From 226c37a8561486888d0231095ac6df379aa46323 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 8 Nov 2013 18:59:36 -0800 Subject: [PATCH 0001/1872] Initial version of symplectic and orthogonal basis for symmetric functions. Currently this does not work correctly because the basis do not give a Hopf structure by converting to the Schur basis and it is only a filtered basis, not a graded basis. --- src/sage/combinat/sf/sf.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 9a627f3288c..38812d261ea 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -952,6 +952,22 @@ def forgotten(self): return self.elementary().dual_basis() f = forgotten + def symplectic(self): + """ + The symplectic basis of the symmetric functions. + """ + import symplectic + return symplectic.SymmetricFunctionAlgebra_symplectic(self) + sp = symplectic + + def orthogonal(self): + """ + The orthogonal basis of the symmetric functions. + """ + import orthogonal + return orthogonal.SymmetricFunctionAlgebra_orthogonal(self) + o = orthogonal + def macdonald(self, q='q', t='t'): r""" Returns the entry point for the various Macdonald bases. From 8864ef14ee83582ce59089fbc059a12ca8a5c710 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 9 Nov 2013 10:40:30 -0800 Subject: [PATCH 0002/1872] Added files. --- src/sage/combinat/sf/orthogonal.py | 222 ++++++++++++++++++++++++++++ src/sage/combinat/sf/symplectic.py | 224 +++++++++++++++++++++++++++++ 2 files changed, 446 insertions(+) create mode 100644 src/sage/combinat/sf/orthogonal.py create mode 100644 src/sage/combinat/sf/symplectic.py diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py new file mode 100644 index 00000000000..36c550af808 --- /dev/null +++ b/src/sage/combinat/sf/orthogonal.py @@ -0,0 +1,222 @@ +""" +Orthogonal Symmetric Functions + +AUTHORS: + +- Travis Scirmshaw (2013-11-10): Initial version +""" +#***************************************************************************** +# Copyright (C) 2013 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/ +#***************************************************************************** +import sfa +import sage.combinat.partition as partition +from sage.misc.cachefunc import cached_method +from sage.rings.all import ZZ, QQ, Integer +from sage.matrix.all import matrix + +# TODO: Don't make it into a realization of the symmetric functions since it +# does not preserve the Hopf structure and is a filtered basis +class SymmetricFunctionAlgebra_orthogonal(sfa.SymmetricFunctionAlgebra_generic): + r""" + The orthogonal symmetric function basis (or orthogonal basis, to be short). + + The orthogonal basis `\{ o_{\lambda} \}` where `\lambda` is taken over + all partitions is defined by the following change of basis with the + Schur functions: + + .. MATH:: + + s_{\lambda} = \sum_{\mu} \left( \sum_{\nu \in H} c^{\lambda}_{\mu\nu} + \right) o_{\mu} + + where `V` is the set of all partitions with even-width rows and + `c^{\lambda}_{\mu\nu}` is the usual Littlewood-Richardson (LR) + coefficients. By the properties of LR coefficients, this can be shown to + be a upper unitriangular change of basis. + + .. NOTE:: + + This is only a filtered basis, not a graded basis. + + INPUT: + + - ``Sym`` -- an instance of the ring of the symmetric functions + + REFERENCES: + + - [ChariKleber2000]_ + + EXAMPLES: + + Here are the first few orthogonal symmetric functions, in various bases:: + + sage: Sym = SymmetricFunctions(QQ) + sage: o = Sym.o() + sage: e = Sym.e() + sage: h = Sym.h() + sage: p = Sym.p() + sage: s = Sym.s() + sage: m = Sym.m() + + sage: p(o([1])) + p[1] + sage: m(o([1])) + m[1] + sage: e(o([1])) + e[1] + sage: h(o([1])) + h[1] + sage: s(o([1])) + s[1] + + sage: p(o([2])) + -p[] + 1/2*p[1, 1] + 1/2*p[2] + sage: m(o([2])) + -m[] + m[1, 1] + m[2] + sage: e(o([2])) + -e[] + e[1, 1] - e[2] + sage: h(o([2])) + -h[] + h[2] + sage: s(o([2])) + -s[] + s[2] + + sage: p(o([3])) + -p[1] + 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3] + sage: m(o([3])) + -m[1] + m[1, 1, 1] + m[2, 1] + m[3] + sage: e(o([3])) + -e[1] + e[1, 1, 1] - 2*e[2, 1] + e[3] + sage: h(o([3])) + -h[1] + h[3] + sage: s(o([3])) + -s[1] + s[3] + + sage: Sym = SymmetricFunctions(ZZ) + sage: o = Sym.o() + sage: e = Sym.e() + sage: h = Sym.h() + sage: s = Sym.s() + sage: m = Sym.m() + sage: p = Sym.p() + sage: m(o([4])) + -m[1, 1] + m[1, 1, 1, 1] - m[2] + m[2, 1, 1] + m[2, 2] + m[3, 1] + m[4] + sage: e(o([4])) + -e[1, 1] + e[1, 1, 1, 1] + e[2] - 3*e[2, 1, 1] + e[2, 2] + 2*e[3, 1] - e[4] + sage: h(o([4])) + -h[2] + h[4] + sage: s(o([4])) + -s[2] + s[4] + + Some examples of conversions the other way:: + + sage: o(h[3]) + o[1] + o[3] + sage: o(e[3]) + o[1, 1, 1] + sage: o(m[2,1]) + o[1] - 2*o[1, 1, 1] + o[2, 1] + sage: o(p[3]) + o[1, 1, 1] - o[2, 1] + o[3] + + Some multiplication:: + + sage: o([2,1,1]) * o([2]) + o[1, 1] + o[1, 1, 1, 1] + 2*o[2, 1, 1] + o[2, 2] + o[2, 2, 1, 1] + + o[3, 1] + o[3, 1, 1, 1] + o[3, 2, 1] + o[4, 1, 1] + sage: o([1,1]) * o([2,1]) + o[1] + o[1, 1, 1] + 2*o[2, 1] + o[2, 1, 1, 1] + o[2, 2, 1] + + o[3] + o[3, 1, 1] + o[3, 2] + + Examples of the Hopf algebra structure:: + + sage: o([1]).antipode() + -o[1] + sage: o([2]).antipode() + -o[] + o[1, 1] + sage: o([1]).coproduct() + o[] # o[1] + o[1] # o[] + sage: o([2]).coproduct() + o[] # o[] + o[] # o[2] + o[1] # o[1] + o[2] # o[] + sage: o([1]).counit() + 0 + sage: o.one().counit() + 1 + """ + def __init__(self, Sym): + """ + Initialize ``self``. + + TESTS:: + + sage: o = SymmetricFunctions(QQ).o() + sage: TestSuite(o).run() + """ + sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "orthogonal", 'o') + + # Setup the coercions + s = Sym.schur() + M = s.module_morphism(self._s_to_o_on_basis, codomain=self, + triangular='upper', unitriangular=True) + M.register_as_coercion() + (~M).register_as_coercion() + + def _multiply(self, r, l): + r""" + Return the product of ``r`` and ``l`` by coercing to the Schur + functions and then pulling back. + + EXAMPLES:: + + sage: o = SymmetricFunctions(QQ).o() + sage: o([2]) * o([1,1]) # indirect doctest + o[1, 1] + o[2] + o[2, 1, 1] + o[3, 1] + """ + s = self.realization_of().schur() + return self(s(r) * s(l)) + + @cached_method + def _s_to_o_on_basis(self, lam): + r""" + Return the Schur symmetric function ``s[lam]`` expanded in + the orthogonal basis, where ``lam`` is a partition. + + INPUT: + + - ``lam`` -- a partition + + OUTPUT: + + - the expansion of ``s[lam]`` in the orthogonal basis ``self`` + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ) + sage: s = Sym.schur() + sage: o = Sym.orthogonal() + sage: o._s_to_o_on_basis(Partition([])) + o[] + sage: o._s_to_o_on_basis(Partition([4,2,1])) + o[1] + 2*o[2, 1] + o[2, 2, 1] + o[3] + o[3, 1, 1] + o[3, 2] + o[4, 1] + o[4, 2, 1] + sage: s(o._s_to_o_on_basis(Partition([3,1]))) == s[3,1] + True + """ + import sage.libs.lrcalc.lrcalc as lrcalc + from sage.combinat.partition import Partitions + R = self.base_ring() + # TODO: This is a brute force check and could likely be simplified + return self._from_dict({ mu: R.sum( lrcalc.lrcoef_unsafe(lam, mu, nu) + for j in range(sum(lam)-sum(mu)+1) + for nu in Partitions(j) + if all(x % 2 == 0 for x in nu) ) + for i in range(sum(lam)+1) for mu in Partitions(i) }) diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py new file mode 100644 index 00000000000..a2801da3e08 --- /dev/null +++ b/src/sage/combinat/sf/symplectic.py @@ -0,0 +1,224 @@ +""" +Symplectic Symmetric Functions + +AUTHORS: + +- Travis Scirmshaw (2013-11-10): Initial version +""" +#***************************************************************************** +# Copyright (C) 2013 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/ +#***************************************************************************** +import sfa +import sage.combinat.partition as partition +from sage.misc.cachefunc import cached_method +from sage.rings.all import ZZ, QQ, Integer +from sage.matrix.all import matrix + +# TODO: Don't make it into a realization of the symmetric functions since it +# does not preserve the Hopf structure and is a filtered basis +class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): + r""" + The symplectic symmetric function basis (or symplectic basis, to be short). + + The symplectic basis `\{ sp_{\lambda} \}` where `\lambda` is taken over + all partitions is defined by the following change of basis with the + Schur functions: + + .. MATH:: + + s_{\lambda} = \sum_{\mu} \left( \sum_{\nu \in V} c^{\lambda}_{\mu\nu} + \right) sp_{\mu} + + where `V` is the set of all partitions with even-height columns and + `c^{\lambda}_{\mu\nu}` is the usual Littlewood-Richardson (LR) + coefficients. By the properties of LR coefficients, this can be shown to + be a upper unitriangular change of basis. + + .. NOTE:: + + This is only a filtered basis, not a graded basis. + + INPUT: + + - ``Sym`` -- an instance of the ring of the symmetric functions + + REFERENCES: + + .. [ChariKleber2000] Vyjayanthi Chari and Michael Kleber. + *Symmetric functions and representations of quantum affine algebras*. + :arXiv:`0011161v1` + + EXAMPLES: + + Here are the first few symplectic symmetric functions, in various bases:: + + sage: Sym = SymmetricFunctions(QQ) + sage: sp = Sym.sp() + sage: e = Sym.e() + sage: h = Sym.h() + sage: p = Sym.p() + sage: s = Sym.s() + sage: m = Sym.m() + + sage: p(sp([1])) + p[1] + sage: m(sp([1])) + m[1] + sage: e(sp([1])) + e[1] + sage: h(sp([1])) + h[1] + sage: s(sp([1])) + s[1] + + sage: p(sp([2])) + 1/2*p[1, 1] + 1/2*p[2] + sage: m(sp([2])) + m[1, 1] + m[2] + sage: e(sp([2])) + e[1, 1] - e[2] + sage: h(sp([2])) + h[2] + sage: s(sp([2])) + s[2] + + sage: p(sp([3])) + 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3] + sage: m(sp([3])) + m[1, 1, 1] + m[2, 1] + m[3] + sage: e(sp([3])) + e[1, 1, 1] - 2*e[2, 1] + e[3] + sage: h(sp([3])) + h[3] + sage: s(sp([3])) + s[3] + + sage: Sym = SymmetricFunctions(ZZ) + sage: sp = Sym.sp() + sage: e = Sym.e() + sage: h = Sym.h() + sage: s = Sym.s() + sage: m = Sym.m() + sage: p = Sym.p() + sage: m(sp([4])) + m[1, 1, 1, 1] + m[2, 1, 1] + m[2, 2] + m[3, 1] + m[4] + sage: e(sp([4])) + e[1, 1, 1, 1] - 3*e[2, 1, 1] + e[2, 2] + 2*e[3, 1] - e[4] + sage: h(sp([4])) + h[4] + sage: s(sp([4])) + s[4] + + Some examples of conversions the other way:: + + sage: sp(h[3]) + sp[3] + sage: sp(e[3]) + sp[1] + sp[1, 1, 1] + sage: sp(m[2,1]) + -sp[1] - 2*sp[1, 1, 1] + sp[2, 1] + sage: sp(p[3]) + sp[1, 1, 1] - sp[2, 1] + sp[3] + + Some multiplication:: + + sage: sp([2,1,1]) * sp([2]) + sp[1, 1] + sp[1, 1, 1, 1] + 2*sp[2, 1, 1] + sp[2, 2] + sp[2, 2, 1, 1] + + sp[3, 1] + sp[3, 1, 1, 1] + sp[3, 2, 1] + sp[4, 1, 1] + sage: sp([1,1]) * sp([2,1]) + sp[1] + sp[1, 1, 1] + 2*sp[2, 1] + sp[2, 1, 1, 1] + sp[2, 2, 1] + + sp[3] + sp[3, 1, 1] + sp[3, 2] + + Examples of the Hopf algebra structure:: + + sage: sp([1]).antipode() + -sp[1] + sage: sp([2]).antipode() + sp[] + sp[1, 1] + sage: sp([1]).coproduct() + sp[] # sp[1] + sp[1] # sp[] + sage: sp([2]).coproduct() + sp[] # sp[2] + sp[1] # sp[1] + sp[2] # sp[] + sage: sp([1]).counit() + 0 + sage: sp.one().counit() + 1 + """ + def __init__(self, Sym): + """ + Initialize ``self``. + + TESTS:: + + sage: sp = SymmetricFunctions(QQ).sp() + sage: TestSuite(sp).run() + """ + sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "symplectic", 'sp') + + # Setup the coercions + s = Sym.schur() + M = s.module_morphism(self._s_to_sp_on_basis, codomain=self, + triangular='upper', unitriangular=True) + M.register_as_coercion() + (~M).register_as_coercion() + + def _multiply(self, r, l): + r""" + Return the product of ``r`` and ``l`` by coercing to the Schur + functions and then pulling back. + + EXAMPLES:: + + sage: sp = SymmetricFunctions(QQ).sp() + sage: sp([2]) * sp([1,1]) # indirect doctest + sp[1, 1] + sp[2] + sp[2, 1, 1] + sp[3, 1] + """ + s = self.realization_of().schur() + return self(s(r) * s(l)) + + @cached_method + def _s_to_sp_on_basis(self, lam): + r""" + Return the Schur symmetric function ``s[lam]`` expanded in + the symplectic basis, where ``lam`` is a partition. + + INPUT: + + - ``lam`` -- a partition + + OUTPUT: + + - the expansion of ``s[lam]`` in the symplectic basis ``self`` + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ) + sage: s = Sym.schur() + sage: sp = Sym.symplectic() + sage: sp._s_to_sp_on_basis(Partition([])) + sp[] + sage: sp._s_to_sp_on_basis(Partition([4,2,1])) + sp[2, 1] + sp[3] + sp[3, 1, 1] + sp[3, 2] + sp[4, 1] + sp[4, 2, 1] + sage: s(sp._s_to_sp_on_basis(Partition([3,1]))) == s[3,1] + True + """ + import sage.libs.lrcalc.lrcalc as lrcalc + from sage.combinat.partition import Partitions + R = self.base_ring() + # TODO: This is a brute force check and could likely be simplified + return self._from_dict({ mu: R.sum( lrcalc.lrcoef_unsafe(lam, mu, nu) + for j in range(sum(lam)-sum(mu)+1) + for nu in Partitions(j) + if all(x % 2 == 0 for x in nu.conjugate()) ) + for i in range(sum(lam)+1) for mu in Partitions(i) }) From 7982d3ad9815b6313ac93880467aaf71ddb096ca Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 15 Dec 2013 22:46:17 -0800 Subject: [PATCH 0003/1872] Iniital fix and added regular partitions. --- src/sage/combinat/partition.py | 288 ++++++++++++++++++++++++++++++++- 1 file changed, 283 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 138b66f68ea..d49f3f05a26 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -4216,8 +4216,8 @@ class Partitions(UniqueRepresentation, Parent): Valid keywords are: ``starting``, ``ending``, ``min_part``, ``max_part``, ``max_length``, ``min_length``, ``length``, - ``max_slope``, ``min_slope``, ``inner``, ``outer``, and - ``parts_in``. They have the following meanings: + ``max_slope``, ``min_slope``, ``inner``, ``outer``, ``parts_in`` + and ``regular``. They have the following meanings: - ``starting=p`` specifies that the partitions should all be less than or equal to `p` in lex order. @@ -4247,6 +4247,10 @@ class Partitions(UniqueRepresentation, Parent): `S`, which can be any sequence of pairwise distinct positive integers. + - ``regular=ell`` specifies that the partitions are `\ell`-regular, + and can only be combined with the ``max_part`` keyword if `n` is + not specified + The ``max_*`` versions, along with ``inner`` and ``ending``, work analogously. @@ -4454,6 +4458,10 @@ def __classcall_private__(cls, n=None, **kwargs): if len(kwargs) == 1: if 'max_part' in kwargs: return Partitions_all_bounded(kwargs['max_part']) + if 'regular' in kwargs: + return RegularPartitions_all(kwargs['regular']) + elif len(kwargs) == 2 and 'max_part' in kwargs and 'regular' in kwargs: + return RegularPartitions_all_bounded(kwargs['regular'], kwargs['max_part']) raise ValueError("the size must be specified with any keyword argument") return Partitions_all() else: @@ -4473,6 +4481,8 @@ def __classcall_private__(cls, n=None, **kwargs): return Partitions_starting(n, kwargs['starting']) elif 'ending' in kwargs: return Partitions_ending(n, kwargs['ending']) + elif 'regular' in kwargs: + return RegularPartitions_n(n, kwargs['regular']) if 'min_part' not in kwargs: kwargs['min_part'] = 1 @@ -4500,9 +4510,7 @@ def __classcall_private__(cls, n=None, **kwargs): else: kwargs['min_length'] = len(inner) del kwargs['inner'] - kwargs['element_class'] = Partition - kwargs['global_options'] = Partitions.global_options - return IntegerListsLex(n, **kwargs) + return Partitions_with_constraints(n, **kwargs) def __init__(self, is_infinite=False): """ @@ -5908,6 +5916,276 @@ def __setstate__(self, data): constraints.update(data['constraints']) self.__init__(n, **constraints) +class Partitions_with_constraints(IntegerListsLex): + """ + Partitions which satisfy a set of constraints. + + EXAMPLES:: + + sage: P = Partitions(6, inner=[1,1], max_slope=-1) + sage: list(P) + [[5, 1], [4, 2], [3, 2, 1]] + """ + def __init__(self, n, **kwargs): + """ + Initialize ``self``. + + TESTS:: + + sage: P = Partitions(6, min_part=2, max_slope=-1) + sage: TestSuite(P).run() + + Test that :trac:`-1` is fixed:: + + sage: loads(dumps(P)) == P + True + """ + IntegerListsLex.__init__(self, n, **kwargs) + + Element = Partition + global_options = PartitionOptions + +###################### +# Regular Partitions # +###################### + +class RegularPartitions(Partitions): + r""" + Base class for `\ell`-regular partitions. + + A partition is `\ell`-regular if `m_i < \ell` for all `i`. + """ + def __init__(self, ell, is_infinte=False): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: P = Partitions(regular=2) + sage: TestSuite(P).run() + """ + self.ell = ell + Partitions.__init__(self, is_infinte) + + def __contains__(self, x): + """ + TESTS:: + + sage: P = Partitions(regular=3) + sage: [5] in P + True + sage: [] in P + True + sage: [3, 3, 2, 2] in P + True + sage: [3, 3, 3, 1] in P + False + sage: [4, 0, 0, 0, 0, 0] in P + True + sage: Partition([4,2,2,1]) in P + True + sage: Partition([4,2,2,2]) in P + False + """ + if not Partitions.__contains__(self, x): + return False + if isinstance(x, Partition): + return max(x.to_exp(1)) < self.ell + return all(x.count(i) < self.ell for i in set(x) if i > 0) + + def _fast_iterator(self, n, max_part): + """ + A fast (recursive) iterator which returns a list. + + EXAMPLES:: + + sage: P = Partitions(regular=3) + sage: list(P._fast_iterator(5, 5)) + [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1]] + sage: list(P._fast_iterator(5, 3)) + [[3, 2], [3, 1, 1], [2, 2, 1]] + sage: list(P._fast_iterator(5, 6)) + [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1]] + """ + if n == 0: + yield [] + return + + if n < max_part: + max_part = n + bdry = self.ell - 1 + + for i in reversed(range(1, max_part+1)): + for p in self._fast_iterator(n-i, i): + if p.count(i) < bdry: + yield [i] + p + +class RegularPartitions_all(RegularPartitions): + r""" + The class of all `\ell`-regular partitions. + """ + def __init__(self, ell): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: P = Partitions(regular=4) + sage: TestSuite(P).run() + """ + RegularPartitions.__init__(self, ell, True) + + def _repr_(self): + """ + TESTS:: + + sage: from sage.combinat.partition import RegularPartitions_all + sage: RegularPartitions_all(3) + 3-Regular Partitions + """ + return "{}-Regular Partitions".format(self.ell) + + def __iter__(self): + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: P = Partitions(regular=3) + sage: it = P.__iter__() + sage: [it.next() for x in range(10)] + [[], [1], [2], [1, 1], [3], [2, 1], [4], [3, 1], [2, 2], [2, 1, 1]] + """ + n = 0 + while True: + for p in self._fast_iterator(n, n): + yield self.element_class(self, p) + n += 1 + +class RegularPartitions_all_bounded(RegularPartitions): + r""" + The class of `\ell`-regular partitions bounded by `k`. + """ + def __init__(self, ell, k): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: P = Partitions(regular=4, max_part=3) + sage: TestSuite(P).run() + """ + self.k = k + RegularPartitions.__init__(self, ell, False) + + def __contains__(self, x): + """ + TESTS:: + + sage: P = Partitions(regular=4, max_part=3) + sage: [3, 3, 3] in P + True + sage: [] in P + True + sage: [4, 2, 1] in P + False + """ + return len(x) == 0 or (x[0] <= self.k and RegularPartitions.__contains__(self, x)) + + def _repr_(self): + """ + TESTS:: + + sage: from sage.combinat.partition import RegularPartitions_all_bounded + sage: RegularPartitions_all_bounded(4, 3) + 3-Bounded 4-Regular Partitions + """ + return "{}-Bounded {}-Regular Partitions".format(self.k, self.ell) + + def __iter__(self): + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: P = Partitions(regular=2, max_part=3) + sage: list(P) + [[3, 2, 1], [3, 2], [3, 1], [3], [2, 1], [2], [1], []] + """ + k = self.k + for n in reversed(range(k*(k+1)/2 * self.ell)): + for p in self._fast_iterator(n, k): + yield self.element_class(self, p) + +class RegularPartitions_n(RegularPartitions, Partitions_n): + r""" + The class of `\ell`-regular partitions of `n`. + """ + def __init__(self, n, ell): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: P = Partitions(5, regular=3) + sage: TestSuite(P).run() + """ + RegularPartitions.__init__(self, ell) + Partitions_n.__init__(self, n) + + def _repr_(self): + """ + TESTS:: + + sage: from sage.combinat.partition import RegularPartitions_n + sage: RegularPartitions_n(3, 5) + 5-Regular Partitions of the integer 3 + """ + return "{}-Regular Partitions of the integer {}".format(self.ell, self.n) + + def __contains__(self, x): + """ + TESTS:: + + sage: P = Partitions(5, regular=3) + sage: [3, 1, 1] in P + True + sage: [3, 2, 1] in P + False + """ + return RegularPartitions.__contains__(self, x) and sum(x) == self.n + + def __iter__(self): + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: P = Partitions(5, regular=3) + sage: list(P) + [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1]] + """ + for p in self._fast_iterator(self.n, self.n): + yield self.element_class(self, p) + + def cardinality(self): + """ + Return the cardinality of ``self``. + + EXAMPLES:: + + sage: P = Partitions(5, regular=3) + sage: P.cardinality() + 5 + sage: P = Partitions(5, regular=6) + sage: P.cardinality() + 7 + sage: P.cardinality() == Partitions(5).cardinality() + True + """ + if self.ell > self.n: + return Partitions_n.cardinality(self) + return ZZ.sum(1 for x in self) ###################### # Ordered Partitions # From da0b7ebe6e596fd92757b32e4849a9eb7238c5e3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 17 Dec 2013 13:06:28 -0800 Subject: [PATCH 0004/1872] Removed TODO messages. --- src/sage/combinat/sf/orthogonal.py | 3 +-- src/sage/combinat/sf/symplectic.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 36c550af808..1e51ce70488 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -25,8 +25,6 @@ from sage.rings.all import ZZ, QQ, Integer from sage.matrix.all import matrix -# TODO: Don't make it into a realization of the symmetric functions since it -# does not preserve the Hopf structure and is a filtered basis class SymmetricFunctionAlgebra_orthogonal(sfa.SymmetricFunctionAlgebra_generic): r""" The orthogonal symmetric function basis (or orthogonal basis, to be short). @@ -220,3 +218,4 @@ def _s_to_o_on_basis(self, lam): for nu in Partitions(j) if all(x % 2 == 0 for x in nu) ) for i in range(sum(lam)+1) for mu in Partitions(i) }) + diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index a2801da3e08..3dfd27c0269 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -25,8 +25,6 @@ from sage.rings.all import ZZ, QQ, Integer from sage.matrix.all import matrix -# TODO: Don't make it into a realization of the symmetric functions since it -# does not preserve the Hopf structure and is a filtered basis class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): r""" The symplectic symmetric function basis (or symplectic basis, to be short). @@ -222,3 +220,4 @@ def _s_to_sp_on_basis(self, lam): for nu in Partitions(j) if all(x % 2 == 0 for x in nu.conjugate()) ) for i in range(sum(lam)+1) for mu in Partitions(i) }) + From 9536f54a96401a5bdabdaa56dc65640f8bb1bfda Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 17 Dec 2013 13:10:25 -0800 Subject: [PATCH 0005/1872] Added files to documentation. --- src/doc/en/reference/combinat/symmetric_functions.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/en/reference/combinat/symmetric_functions.rst b/src/doc/en/reference/combinat/symmetric_functions.rst index 4a25c4c0f45..8e3f121b69d 100644 --- a/src/doc/en/reference/combinat/symmetric_functions.rst +++ b/src/doc/en/reference/combinat/symmetric_functions.rst @@ -23,4 +23,6 @@ Symmetric Functions ../sage/combinat/sf/llt ../sage/combinat/sf/macdonald ../sage/combinat/sf/ns_macdonald + ../sage/combinat/sf/orthogonal + ../sage/combinat/sf/symplectic ../sage/combinat/sf/witt From 1adb368c00b4b8e1eb49186af47ee1e86dafd94f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Dec 2013 19:02:15 -0800 Subject: [PATCH 0006/1872] Added deprecation to IntegerListLex global_options arg. Fixed doctests. --- src/sage/combinat/integer_list.py | 9 ++ src/sage/combinat/partition.py | 234 ++++++++++++++++++++++++------ 2 files changed, 198 insertions(+), 45 deletions(-) diff --git a/src/sage/combinat/integer_list.py b/src/sage/combinat/integer_list.py index 2b2297990e1..fa8ad089abe 100644 --- a/src/sage/combinat/integer_list.py +++ b/src/sage/combinat/integer_list.py @@ -931,6 +931,10 @@ def __init__(self, sage: C.cardinality().parent() is ZZ True sage: TestSuite(C).run() + sage: C = IntegerListsLex(2, global_options=Partitions.global_options) + doctest:...: DeprecationWarning: the global_options argument is deprecated + since, in general, pickling is broken; create your own class instead + See http://trac.sagemath.org/15525 for details. """ # Convert to float infinity from sage.rings.infinity import infinity @@ -943,6 +947,11 @@ def __init__(self, if max_part == infinity: max_part = float('+inf') + if global_options is not None: + from sage.misc.superseded import deprecation + deprecation(15525, 'the global_options argument is deprecated since, in general,' + ' pickling is broken; create your own class instead') + if floor is None: self.floor_list = [] elif isinstance(floor, __builtin__.list): diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 5390be626e7..c1ae1536d0c 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -3747,7 +3747,8 @@ def remove_horizontal_border_strip(self, k): sage: Partition([5,3,1]).remove_horizontal_border_strip(6).list() [] - The result is returned as an instance of :class:`IntegerListsLex`:: + The result is returned as an instance of + :class:`Partitions_with_constraints`:: sage: Partition([5,3,1]).remove_horizontal_border_strip(5) The subpartitions of [5, 3, 1] obtained by removing an horizontal border strip of length 5 @@ -3763,15 +3764,13 @@ def remove_horizontal_border_strip(self, k): sage: Partition([]).remove_horizontal_border_strip(6).list() [] """ - return IntegerListsLex(n = self.size()-k, - min_length = len(self)-1, - max_length = len(self), - floor = self[1:]+[0], - ceiling = self[:], - max_slope = 0, - element_class = Partition, - global_options = Partitions.global_options, - name = "The subpartitions of %s obtained by removing an horizontal border strip of length %s"%(self,k)) + return Partitions_with_constraints(n = self.size()-k, + min_length = len(self)-1, + max_length = len(self), + floor = self[1:]+[0], + ceiling = self[:], + max_slope = 0, + name = "The subpartitions of {} obtained by removing an horizontal border strip of length {}".format(self,k)) def k_conjugate(self, k): r""" @@ -4251,17 +4250,17 @@ class Partitions(UniqueRepresentation, Parent): (see :trac:`15467`). - ``regular=ell`` specifies that the partitions are `\ell`-regular, - and can only be combined with the ``max_part`` keyword if `n` is - not specified + and can only be combined with the ``max_length`` or ``max_part``, but + not both, keywords if `n` is not specified The ``max_*`` versions, along with ``inner`` and ``ending``, work analogously. - Right now, the ``parts_in``, ``starting``, and ``ending`` keyword - arguments are mutually exclusive, both of each other and of other + Right now, the ``parts_in``, ``starting``, ``ending``, and ``regular`` + keyword arguments are mutually exclusive, both of each other and of other keyword arguments. If you specify, say, ``parts_in``, all other - keyword arguments will be ignored; ``starting`` and ``ending`` work - the same way. + keyword arguments will be ignored; ``starting``, ``ending``, and + ``regular`` work the same way. EXAMPLES: @@ -4339,6 +4338,16 @@ class Partitions(UniqueRepresentation, Parent): sage: Partitions(10, min_part=2, length=3).list() [[6, 2, 2], [5, 3, 2], [4, 4, 2], [4, 3, 3]] + Some examples using the ``regular`` keyword:: + + sage: Partitions(regular=4) + 4-Regular Partitions + sage: Partitions(regular=4, max_length=3) + 4-Regular Partitions with max length 3 + sage: Partitions(regular=4, max_part=3) + 4-Regular 3-Bounded Partitions + sage: Partitions(3, regular=4) + 4-Regular Partitions of the integer 3 Here are some further examples using various constraints:: @@ -4396,7 +4405,7 @@ class Partitions(UniqueRepresentation, Parent): sage: TestSuite(Partitions(0)).run() sage: TestSuite(Partitions(5)).run() - sage: TestSuite(Partitions(5, min_part=2)).run() # Not tested: todo - IntegerListsLex needs to pickle properly + sage: TestSuite(Partitions(5, min_part=2)).run() sage: repr( Partitions(5, min_part=2) ) 'Partitions of the integer 5 satisfying constraints min_part=2' @@ -4472,10 +4481,6 @@ def __classcall_private__(cls, n=None, **kwargs): sage: P2 = Partitions(int(4)) sage: P is P2 True - sage: P = Partitions(4, length=2, parts_in=[3,1,1]) - sage: P2 = Partitions(4, length=2, parts_in=(3,1,1)) - sage: P is P2 - True """ if n == infinity: raise ValueError("n cannot be infinite") @@ -4486,8 +4491,14 @@ def __classcall_private__(cls, n=None, **kwargs): return Partitions_all_bounded(kwargs['max_part']) if 'regular' in kwargs: return RegularPartitions_all(kwargs['regular']) - elif len(kwargs) == 2 and 'max_part' in kwargs and 'regular' in kwargs: - return RegularPartitions_all_bounded(kwargs['regular'], kwargs['max_part']) + elif len(kwargs) == 2: + if 'regular' in kwargs: + if kwargs['regular'] < 2: + raise ValueError("the regularity must be at least 2") + if 'max_part' in kwargs: + return RegularPartitions_bounded(kwargs['regular'], kwargs['max_part']) + if 'max_length' in kwargs: + return RegularPartitions_truncated(kwargs['regular'], kwargs['max_length']) raise ValueError("the size must be specified with any keyword argument") return Partitions_all() elif isinstance(n, (int,Integer)): @@ -4541,6 +4552,9 @@ def __classcall_private__(cls, n=None, **kwargs): del kwargs['inner'] return Partitions_with_constraints(n, **kwargs) + raise ValueError("n must be an integer or be equal to one of " + "None, NN, NonNegativeIntegers()") + def __init__(self, is_infinite=False): """ Initialize ``self``. @@ -5937,11 +5951,9 @@ def __setstate__(self, data): [[2, 1], [1, 1, 1]] """ n = data['n'] - self.__class__ = IntegerListsLex + self.__class__ = Partitions_with_constraints constraints = {'max_slope' : 0, - 'min_part' : 1, - 'element_class' : Partition, - 'global_options' : Partitions.global_options} + 'min_part' : 1} constraints.update(data['constraints']) self.__init__(n, **constraints) @@ -5954,22 +5966,22 @@ class Partitions_with_constraints(IntegerListsLex): sage: P = Partitions(6, inner=[1,1], max_slope=-1) sage: list(P) [[5, 1], [4, 2], [3, 2, 1]] - """ - def __init__(self, n, **kwargs): - """ - Initialize ``self``. - TESTS:: + TESTS:: - sage: P = Partitions(6, min_part=2, max_slope=-1) - sage: TestSuite(P).run() + sage: P = Partitions(6, min_part=2, max_slope=-1) + sage: TestSuite(P).run() - Test that :trac:`-1` is fixed:: + Test that :trac:`15525` is fixed:: - sage: loads(dumps(P)) == P - True - """ - IntegerListsLex.__init__(self, n, **kwargs) + sage: loads(dumps(P)) == P + True + """ +# def __init__(self, n, **kwargs): +# """ +# Initialize ``self``. +# """ +# IntegerListsLex.__init__(self, n, **kwargs) Element = Partition global_options = PartitionOptions @@ -5983,6 +5995,11 @@ class RegularPartitions(Partitions): Base class for `\ell`-regular partitions. A partition is `\ell`-regular if `m_i < \ell` for all `i`. + + INPUT: + + - ``ell`` -- the value `\ell` + - ``is_infinite`` -- if the subset of `\ell`-regular partitions is infinite """ def __init__(self, ell, is_infinte=False): """ @@ -6015,6 +6032,8 @@ def __contains__(self, x): True sage: Partition([4,2,2,2]) in P False + sage: Partition([10,1]) in P + True """ if not Partitions.__contains__(self, x): return False @@ -6052,6 +6071,14 @@ def _fast_iterator(self, n, max_part): class RegularPartitions_all(RegularPartitions): r""" The class of all `\ell`-regular partitions. + + INPUT: + + - ``ell`` -- the value `\ell` + + .. SEEALSO:: + + :class:`~sage.combinat.partition.RegularPartitions` """ def __init__(self, ell): """ @@ -6091,9 +6118,117 @@ def __iter__(self): yield self.element_class(self, p) n += 1 -class RegularPartitions_all_bounded(RegularPartitions): +class RegularPartitions_truncated(RegularPartitions): r""" - The class of `\ell`-regular partitions bounded by `k`. + The class of `\ell`-regular partitions with max length `k`. + + INPUT: + + - ``ell`` -- the value `\ell` + - ``max_len`` -- the maximum length + + .. SEEALSO:: + + :class:`~sage.combinat.partition.RegularPartitions` + """ + def __init__(self, ell, max_len): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: P = Partitions(regular=4, max_length=3) + sage: TestSuite(P).run() + """ + self.max_len = max_len + RegularPartitions.__init__(self, ell) + + def __contains__(self, x): + """ + TESTS:: + + sage: P = Partitions(regular=4, max_length=3) + sage: [3, 3, 3] in P + True + sage: [] in P + True + sage: [4, 2, 1, 1] in P + False + """ + return len(x) <= self.max_len and RegularPartitions.__contains__(self, x) + + def _repr_(self): + """ + TESTS:: + + sage: from sage.combinat.partition import RegularPartitions_truncated + sage: RegularPartitions_truncated(4, 3) + 4-Regular Partitions with max length 3 + """ + return "{}-Regular Partitions with max length {}".format(self.ell, self.max_len) + + def __iter__(self): + """ + Iterate over ``self``. + + EXAMPLES:: + + sage: P = Partitions(regular=3, max_length=2) + sage: it = P.__iter__() + sage: [it.next() for x in range(10)] + [[], [1], [2], [1, 1], [3], [2, 1], [4], [3, 1], [2, 2], [5]] + """ + n = 0 + while True: + for p in self._fast_iterator(n, n): + yield self.element_class(self, p) + n += 1 + + def _fast_iterator(self, n, max_part, depth=0): + """ + A fast (recursive) iterator which returns a list. + + EXAMPLES:: + + sage: P = Partitions(regular=2, max_length=2) + sage: list(P._fast_iterator(5, 5)) + [[5], [4, 1], [3, 2]] + sage: list(P._fast_iterator(5, 3)) + [[3, 2]] + sage: list(P._fast_iterator(5, 6)) + [[5], [4, 1], [3, 2]] + """ + if n == 0 or depth >= self.max_len: + yield [] + return + + # Special case + if depth + 1 == self.max_len: + if max_part >= n: + yield [n] + return + + if n < max_part: + max_part = n + bdry = self.ell - 1 + + for i in reversed(range(1, max_part+1)): + for p in self._fast_iterator(n-i, i, depth+1): + if p.count(i) < bdry: + yield [i] + p + +class RegularPartitions_bounded(RegularPartitions): + r""" + The class of `\ell`-regular `k`-bounded partitions. + + INPUT: + + - ``ell`` -- the value `\ell` + - ``k`` -- the value `k` + + .. SEEALSO:: + + :class:`~sage.combinat.partition.RegularPartitions` """ def __init__(self, ell, k): """ @@ -6125,11 +6260,11 @@ def _repr_(self): """ TESTS:: - sage: from sage.combinat.partition import RegularPartitions_all_bounded - sage: RegularPartitions_all_bounded(4, 3) - 3-Bounded 4-Regular Partitions + sage: from sage.combinat.partition import RegularPartitions_bounded + sage: RegularPartitions_bounded(4, 3) + 4-Regular 3-Bounded Partitions """ - return "{}-Bounded {}-Regular Partitions".format(self.k, self.ell) + return "{}-Regular {}-Bounded Partitions".format(self.ell, self.k) def __iter__(self): """ @@ -6149,6 +6284,15 @@ def __iter__(self): class RegularPartitions_n(RegularPartitions, Partitions_n): r""" The class of `\ell`-regular partitions of `n`. + + INPUT: + + - ``n`` -- the integer `n` to partition + - ``ell`` -- the value `\ell` + + .. SEEALSO:: + + :class:`~sage.combinat.partition.RegularPartitions` """ def __init__(self, n, ell): """ From 223b11b19d050597267d29150fa1e2cb12a3861b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Dec 2013 22:22:15 -0800 Subject: [PATCH 0007/1872] Fix the counit in sp/o bases. --- src/sage/combinat/sf/orthogonal.py | 15 +++++++++++++++ src/sage/combinat/sf/symplectic.py | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 1e51ce70488..dca14e3479c 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -183,6 +183,21 @@ def _multiply(self, r, l): s = self.realization_of().schur() return self(s(r) * s(l)) + def counit(self, x): + """ + Return the counit of ``x`` in ``self``. + + EXAMPLES:: + + sage: o = SymmetricFunctions(QQ).o() + sage: o.an_element() + 2*o[] + 2*o[1] + 3*o[2] + sage: o.counit(o.an_element()) + -1 + """ + s = self.realization_of().schur() + return s.counit(s(x)) + @cached_method def _s_to_o_on_basis(self, lam): r""" diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index 3dfd27c0269..31ae2a519d0 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -185,6 +185,21 @@ def _multiply(self, r, l): s = self.realization_of().schur() return self(s(r) * s(l)) + def counit(self, x): + """ + Return the counit of ``x`` in ``self``. + + EXAMPLES:: + + sage: sp = SymmetricFunctions(QQ).sp() + sage: sp.an_element() + 2*sp[] + 2*sp[1] + 3*sp[2] + sage: sp.counit(sp.an_element()) + 2 + """ + s = self.realization_of().schur() + return s.counit(s(x)) + @cached_method def _s_to_sp_on_basis(self, lam): r""" From 9ea2a2c1eafde6abc39d819002cff6ea43984108 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Dec 2013 22:26:11 -0800 Subject: [PATCH 0008/1872] Added comment about ZZ / 2ZZ grading. --- src/sage/combinat/sf/orthogonal.py | 3 ++- src/sage/combinat/sf/symplectic.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index dca14e3479c..250dcce878d 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -45,7 +45,8 @@ class SymmetricFunctionAlgebra_orthogonal(sfa.SymmetricFunctionAlgebra_generic): .. NOTE:: - This is only a filtered basis, not a graded basis. + This is only a filtered basis, not a `\ZZ`-graded basis. However this + does respect the induced `(\ZZ/2\ZZ)`-grading. INPUT: diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index 31ae2a519d0..7b5c14f08d5 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -45,7 +45,8 @@ class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): .. NOTE:: - This is only a filtered basis, not a graded basis. + This is only a filtered basis, not a `\ZZ`-graded basis. However this + does respect the induced `(\ZZ/2\ZZ)`-grading. INPUT: From fd17c25145d136e2fc342b450d38f6441ff09d24 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 27 Dec 2013 07:51:08 -0800 Subject: [PATCH 0009/1872] Documentation tweaks/typo fixes. --- src/sage/combinat/sf/orthogonal.py | 4 ++-- src/sage/combinat/sf/symplectic.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 250dcce878d..5ce0835c912 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -38,7 +38,7 @@ class SymmetricFunctionAlgebra_orthogonal(sfa.SymmetricFunctionAlgebra_generic): s_{\lambda} = \sum_{\mu} \left( \sum_{\nu \in H} c^{\lambda}_{\mu\nu} \right) o_{\mu} - where `V` is the set of all partitions with even-width rows and + where `H` is the set of all partitions with even-width rows and `c^{\lambda}_{\mu\nu}` is the usual Littlewood-Richardson (LR) coefficients. By the properties of LR coefficients, this can be shown to be a upper unitriangular change of basis. @@ -185,7 +185,7 @@ def _multiply(self, r, l): return self(s(r) * s(l)) def counit(self, x): - """ + r""" Return the counit of ``x`` in ``self``. EXAMPLES:: diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index 7b5c14f08d5..668822b714c 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -56,7 +56,7 @@ class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): .. [ChariKleber2000] Vyjayanthi Chari and Michael Kleber. *Symmetric functions and representations of quantum affine algebras*. - :arXiv:`0011161v1` + :arXiv:`math/0011161v1` EXAMPLES: @@ -187,7 +187,7 @@ def _multiply(self, r, l): return self(s(r) * s(l)) def counit(self, x): - """ + r""" Return the counit of ``x`` in ``self``. EXAMPLES:: From db8a17c1fbe046c00ddfcb4b477ef22642ae6a37 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 18 Apr 2014 22:43:52 -0700 Subject: [PATCH 0010/1872] Learning to spell my name... --- src/sage/combinat/sf/orthogonal.py | 2 +- src/sage/combinat/sf/symplectic.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 5ce0835c912..2c3763958c9 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -3,7 +3,7 @@ AUTHORS: -- Travis Scirmshaw (2013-11-10): Initial version +- Travis Scrimshaw (2013-11-10): Initial version """ #***************************************************************************** # Copyright (C) 2013 Travis Scrimshaw diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index 668822b714c..4a975a6ed2c 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -3,7 +3,7 @@ AUTHORS: -- Travis Scirmshaw (2013-11-10): Initial version +- Travis Scrimshaw (2013-11-10): Initial version """ #***************************************************************************** # Copyright (C) 2013 Travis Scrimshaw From fa0d60186cf7f9bf73b8eb1ad70ab6bc5a862330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 3 Jun 2014 16:54:38 +0200 Subject: [PATCH 0011/1872] trac #16209 first sketch of a working version (rough) --- .../cluster_algebra_quiver/cluster_seed.py | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index eeecc7a37f2..e56ac86b7a4 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -29,7 +29,8 @@ from sage.rings.all import FractionField, PolynomialRing from sage.rings.fraction_field_element import FractionFieldElement from sage.sets.all import Set -from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType_Irreducible, QuiverMutationType_Reducible +from sage.graphs.digraph import DiGraph +from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType_Irreducible, QuiverMutationType_Reducible from sage.combinat.cluster_algebra_quiver.mutation_type import is_mutation_finite class ClusterSeed(SageObject): @@ -2037,6 +2038,79 @@ def greedy(self, a1, a2, method='by_recursion'): raise ValueError("Greedy elements are only currently " "defined for cluster seeds of rank two.") + def oriented_exchange_graph(self): + """ + Return the oriented exchange graph of ``self`` as a directed + graph + + The seed must be a cluster seed for a cluster algebra of + finite type with principal coefficients (the corresponding + quiver must have mutable vertices 0,1,...,n-1). + + EXAMPLES:: + + sage: S = ClusterSeed(['A', 2]).principal_extension() + sage: G = S.oriented_exchange_graph(); G + Digraph on 5 vertices + sage: G.out_degree_sequence() + [2, 1, 1, 1, 0] + + sage: S = ClusterSeed(['B', 2]).principal_extension() + sage: G = S.oriented_exchange_graph(); G + Digraph on 6 vertices + sage: G.out_degree_sequence() + [2, 1, 1, 1, 1, 0] + + TESTS:: + + sage: S = ClusterSeed(['A',[2,2],1]) + sage: S.oriented_exchange_graph() + Traceback (most recent call last): + ... + TypeError: only works for finite mutation type + + sage: S = ClusterSeed(['A', 2]) + sage: S.oriented_exchange_graph() + Traceback (most recent call last): + ... + TypeError: only works for principal coefficients + """ + if not self._mutation_type.is_finite(): + raise TypeError('only works for finite mutation type') + + if not self._is_principal: + raise TypeError('only works for principal coefficients') + + mut_class = self.mutation_class() + covers = [] + + n = self.n() + pairs = [(i, j) for i in mut_class for j in mut_class if i != j] + for (i, j) in pairs: + for k in range(n): + B = i.b_matrix() + count = 0 + green = False + for i2 in range(n, 2 * n): + if B[i2][k] <= 0: + count += 1 + green = (count == n) + S1 = i + NewS1 = S1.mutate(k, inplace=False) + Var1 = [NewS1.cluster_variable(k) for k in range(n)] + Var1.sort() + Var2 = [j.cluster_variable(k) for k in range(n)] + Var2.sort() + P_Res_NewS1 = NewS1.exchangeable_part() + P_Res_S2 = j.exchangeable_part() + New_P_Res_NewS1 = P_Res_NewS1.quiver().digraph() + New_P_Res_s2 = P_Res_S2.quiver().digraph() + if Var1 == Var2 and green and (i, j) not in covers: + covers.append((i, j)) + + return DiGraph(covers) + + def _bino(n, k): """ Binomial coefficient which we define as zero for negative n. From 3f66020116363b17de6d5a68c6ec21554c567f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 3 Jun 2014 17:07:16 +0200 Subject: [PATCH 0012/1872] trac #16209 a little bit smoother --- .../cluster_algebra_quiver/cluster_seed.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index e56ac86b7a4..164c16e2935 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -2087,24 +2087,15 @@ def oriented_exchange_graph(self): n = self.n() pairs = [(i, j) for i in mut_class for j in mut_class if i != j] for (i, j) in pairs: + B = i.b_matrix() for k in range(n): - B = i.b_matrix() - count = 0 - green = False - for i2 in range(n, 2 * n): - if B[i2][k] <= 0: - count += 1 + count = len([i2 for i2 in range(n, 2 * n) if B[i2][k] <= 0]) green = (count == n) - S1 = i - NewS1 = S1.mutate(k, inplace=False) + NewS1 = i.mutate(k, inplace=False) Var1 = [NewS1.cluster_variable(k) for k in range(n)] Var1.sort() Var2 = [j.cluster_variable(k) for k in range(n)] Var2.sort() - P_Res_NewS1 = NewS1.exchangeable_part() - P_Res_S2 = j.exchangeable_part() - New_P_Res_NewS1 = P_Res_NewS1.quiver().digraph() - New_P_Res_s2 = P_Res_S2.quiver().digraph() if Var1 == Var2 and green and (i, j) not in covers: covers.append((i, j)) From e49a4c7bf169f37133cd7c5118ec225406318ed4 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Mon, 11 Aug 2014 21:36:41 +0200 Subject: [PATCH 0013/1872] trac #16627: base ring in polytope doc --- src/sage/geometry/polyhedron/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index d5eddb6aa8d..ab50f9edc24 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1919,7 +1919,7 @@ def base_ring(self): OUTPUT: - Either ``QQ`` (exact arithmetic using gmp, default) or ``RDF`` + Either ``ZZ`` (the ring of integers), ``QQ`` (exact arithmetic using gmp) or ``RDF`` (double precision floating-point arithmetic) EXAMPLES:: From c743ad66ef4f8b48ec1882a00664b808d029ac2f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 11 Sep 2014 17:22:56 -0700 Subject: [PATCH 0014/1872] Implemented RC -> KRT bijection and KR tableaux in type D_4^(3). --- .../rigged_configurations/bij_type_D_tri.py | 415 ++++++++++++++++++ .../rigged_configurations/bijection.py | 12 +- .../rigged_configurations/kr_tableaux.py | 44 +- 3 files changed, 465 insertions(+), 6 deletions(-) create mode 100644 src/sage/combinat/rigged_configurations/bij_type_D_tri.py diff --git a/src/sage/combinat/rigged_configurations/bij_type_D_tri.py b/src/sage/combinat/rigged_configurations/bij_type_D_tri.py new file mode 100644 index 00000000000..3a942ba939e --- /dev/null +++ b/src/sage/combinat/rigged_configurations/bij_type_D_tri.py @@ -0,0 +1,415 @@ +r""" +Bijection classes for type `D_4^{(3)}`. + +Part of the (internal) classes which runs the bijection between rigged +configurations and KR tableaux of type `D_4^{(3)}`. + +AUTHORS: + +- Travis Scrimshaw (2014-09-10): Initial version + +TESTS:: + + sage: KRT = crystals.TensorProductOfKirillovReshetikhinTableaux(['D', 4, 3], [[2,1]]) + sage: from sage.combinat.rigged_configurations.bij_type_D_tri import KRTToRCBijectionTypeDTri + sage: bijection = KRTToRCBijectionTypeDTri(KRT(pathlist=[[-1,2]])) + sage: TestSuite(bijection).run() + sage: RC = RiggedConfigurations(['D', 4, 3], [[2, 1]]) + sage: from sage.combinat.rigged_configurations.bij_type_D_tri import RCToKRTBijectionTypeDTri + sage: bijection = RCToKRTBijectionTypeDTri(RC(partition_list=[[],[],[]])) + sage: TestSuite(bijection).run() +""" + +#***************************************************************************** +# 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.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA +from sage.combinat.rigged_configurations.bij_type_A import RCToKRTBijectionTypeA + +class KRTToRCBijectionTypeDTri(KRTToRCBijectionTypeA): + r""" + Specific implementation of the bijection from KR tableaux to rigged + configurations for type `D_4^{(3)}`. + + This inherits from type `A_n^{(1)}` because we use the same methods in + some places. + """ + + def next_state(self, val): + r""" + Build the next state for type `D_4^{(3)}`. + + TESTS:: + + sage: KRT = crystals.TensorProductOfKirillovReshetikhinTableaux(['D', 4, 3], [[2,1]]) + sage: from sage.combinat.rigged_configurations.bij_type_D_tri import KRTToRCBijectionTypeDTri + sage: bijection = KRTToRCBijectionTypeDTri(KRT(pathlist=[[-1,2]])) + sage: bijection.cur_path.insert(0, []) + sage: bijection.cur_dims.insert(0, [0, 1]) + sage: bijection.cur_path[0].insert(0, [2]) + sage: bijection.next_state(2) + """ + + n = self.n + tableau_height = len(self.cur_path[0]) - 1 + + if val == 'E': + self.ret_rig_con[0].insert_cell(max_width) + self.ret_rig_con[1].insert_cell(max_width) + if tableau_height == 0: + self.ret_rig_con[0].insert_cell(max_width) + self._update_vacancy_nums(0) + self._update_vacancy_nums(1) + self._update_partition_values(0) + self._update_partition_values(1) + return + + if val > 0: + # If it is a regular value, we follow the A_n rules + KRTToRCBijectionTypeA.next_state(self, val) + return + + pos_val = -val + + if pos_val == 0: + if len(self.ret_rig_con[pos_val - 1]) > 0: + max_width = self.ret_rig_con[0][0] + else: + max_width = 1 + max_width = self.ret_rig_con[0].insert_cell(max_width) + width_n = max_width + 1 + + # Follow regular A_n rules + for a in reversed(range(tableau_height, 1)): + max_width = self.ret_rig_con[a].insert_cell(max_width) + self._update_vacancy_nums(a + 1) + self._update_partition_values(a + 1) + self._update_vacancy_nums(tableau_height) + self._update_partition_values(tableau_height) + if tableau_height > 0: + self._update_vacancy_nums(tableau_height-1) + self._update_partition_values(tableau_height-1) + + # Make the largest string at \nu^{(1)} quasi-singular + p = self.ret_rig_con[0] + num_rows = len(p) + for i in range(num_rows): + if p._list[i] == width_n: + j = i+1 + while j < num_rows and p._list[j] == width_n \ + and p.vacancy_numbers[j] == p.rigging[j]: + j += 1 + p.rigging[j-1] -= 1 + break + return + + case_S = [None] * n + pos_val = -val + + if pos_val > 3: + # Always add a cell to the first singular value in the first + # tableau we are updating. + if len(self.ret_rig_con[pos_val - 1]) > 0: + max_width = self.ret_rig_con[pos_val - 1][0] + else: + max_width = 1 + + # Add cells similar to type A_n but we move to the right + for a in range(pos_val - 1, 2): + max_width = self.ret_rig_con[a].insert_cell(max_width) + case_S[a] = max_width + else: + if len(self.ret_rig_con[0]) > 0: + max_width = self.ret_rig_con[0][0] + else: + max_width = 1 + + # Special case for going through 0 + # If we find a quasi-singular string first, then we are in case (Q, S) + # otherwise we will find a singular string and insert 2 cells + P = self.ret_rig_con[0] + num_rows = len(P) + case_QS = False + for i in range(num_rows + 1): + if i == num_rows: + max_width = 0 + if case_QS: + P._list.append(1) + P.vacancy_numbers.append(None) + # Go through our partition until we find a length of greater than 1 + j = len(P._list) - 1 + while j >= 0 and P._list[j] == 1: + j -= 1 + P.rigging.insert(j + 1, None) + width_n = 1 + else: + # Go through our partition until we find a length of greater than 2 + j = len(P._list) - 1 + while j >= 0 and P._list[j] <= 2: + j -= 1 + P._list.insert(j+1, 2) + P.vacancy_numbers.insert(j+1, None) + P.rigging.insert(j+1, None) + break + elif P._list[i] <= max_width: + if P.vacancy_numbers[i] == P.rigging[i]: + max_width = P._list[i] + if case_QS: + P._list[i] += 1 + width_n = P._list[i] + P.rigging[i] = None + else: + j = i - 1 + while j >= 0 and P._list[j] <= max_width + 2: + P.rigging[j+1] = P.rigging[j] # Shuffle it along + j -= 1 + P._list.pop(i) + P._list.insert(j+1, max_width + 2) + P.rigging[j+1] = None + break + elif P.vacancy_numbers[i] - 1 == P.rigging[i] and not case_QS: + case_QS = True + P._list[i] += 1 + P.rigging[i] = None + # No need to set max_width here since we will find a singular string + + # Now go back following the regular C_n (ish) rules + for a in reversed(range(tableau_height, 2)): + if case_S[a] == max_width: + self._insert_cell_case_S(self.ret_rig_con[a]) + else: + max_width = self.ret_rig_con[a].insert_cell(max_width) + self._update_vacancy_nums(a + 1) + self._update_partition_values(a + 1) + + # Update the final rigged partitions + self._update_vacancy_nums(tableau_height) + if tableau_height >= n - 1: + self._correct_vacancy_nums() + self._update_partition_values(tableau_height) + + if pos_val <= tableau_height: + for a in range(pos_val-1, tableau_height): + self._update_vacancy_nums(a) + self._update_partition_values(a) + if pos_val > 1: + self._update_vacancy_nums(pos_val - 2) + self._update_partition_values(pos_val - 2) + elif tableau_height > 0: + self._update_vacancy_nums(tableau_height - 1) + self._update_partition_values(tableau_height - 1) + + if case_QS: + # Make the new string quasi-singular + num_rows = len(partition) + for i in range(num_rows): + if partition._list[i] == width_n: + j = i+1 + while j < num_rows and partition._list[j] == width_n \ + and partition.vacancy_numbers[j] == partition.rigging[j]: + j += 1 + partition.rigging[j-1] -= 1 + break + + def _insert_cell_case_S(self, partition): + """ + Insert a cell when case `(S)` holds. + + TESTS:: + + sage: RC = RiggedConfigurations(['C', 2, 1], [[2, 2]]) + sage: RP = RC(partition_list=[[2],[2,2]])[1] + sage: RP + -4[ ][ ]-4 + -4[ ][ ]-4 + + sage: RP.rigging[0] = None + sage: from sage.combinat.rigged_configurations.bij_type_D_tri import KRTToRCBijectionTypeDTri + sage: KRT = crystals.TensorProductOfKirillovReshetikhinTableaux(['D', 4, 3], [[2,1]]) + sage: bijection = KRTToRCBijectionTypeDTri(KRT(pathlist=[[-1,2]])) + sage: bijection._insert_cell_case_S(RP) + sage: RP + -4[ ][ ][ ]None + -4[ ][ ]-4 + + """ + # Special case when adding twice to the first row + if partition.rigging[0] is None: + partition._list[0] += 1 + return + + num_rows = len(partition) + for i in reversed(range(1, num_rows)): + if partition.rigging[i] is None: + j = i - 1 + while j >= 0 and partition._list[j] == partition._list[i]: + partition.rigging[j+1] = partition.rigging[j] # Shuffle it along + j -= 1 + partition._list[j+1] += 1 + partition.rigging[j+1] = None + return + +class RCToKRTBijectionTypeDTri(RCToKRTBijectionTypeA): + r""" + Specific implementation of the bijection from rigged configurations to + tensor products of KR tableaux for type `D_4^{(3)}`. + """ + + def next_state(self, height): + r""" + Build the next state for type `D_4^{(3)}`. + + TESTS:: + + sage: RC = RiggedConfigurations(['D', 4, 3], [[2, 1]]) + sage: from sage.combinat.rigged_configurations.bij_type_D_tri import RCToKRTBijectionTypeDTri + sage: bijection = RCToKRTBijectionTypeDTri(RC(partition_list=[[2],[2],[1]])) + sage: bijection.next_state(0) + -1 + """ + ell = [None] * 6 + case_S = [False] * 3 + case_Q = False + b = None + + # Calculate the rank and ell values + + last_size = 0 + for a in range(height, 2): + ell[a] = self._find_singular_string(self.cur_partitions[a], last_size) + + if ell[a] is None: + b = a + 1 + break + else: + last_size = self.cur_partitions[a][ell[a]] + + if b is None: + partition = self.cur_partitions[0] + # Modified version of _find_singular_string() + for i in reversed(range(len(partition))): + if partition[i] >= last_size: + if partition.vacancy_numbers[i] == partition.rigging[i] and i != ell[0]: + if partition[i] == 1: + b = 'E' + else: + last_size = partition[i] + case_S[2] = True + ell[3] = i + break + elif partition.vacancy_numbers[i] - 1 == partition.rigging[i] and not case_Q: + case_Q = True + # Check if the block is singular + block_size = partition[i] + for j in reversed(range(i)): + if partition[j] != block_size: + break + elif partition.vacancy_numbers[j] == partition.rigging[j] and j != ell[0]: + case_Q = False + break + if case_Q: + last_size = partition[i] + 1 + ell[2] = i + + if ell[3] is None: + if not case_Q: + b = 3 + else: + b = 0 + + if b is None: # Going back + if self.cur_partitions[1][ell[1]] == last_size: + ell[4] = ell[1] + case_S[1] = True + else: + ell[4] = self._find_singular_string(self.cur_partitions[1], last_size) + + if ell[4] is None: + b = -3 + else: + last_size = self.cur_partitions[1][ell[4]] + + if b is None: # Final partition + P = self.cur_partitions[0] + if ell[0] is not None and P[ell[0]] == last_size: + ell[5] = ell[0] + case_S[0] = True + else: + # Modified form of _find_singular_string + end = ell[3] + for i in reversed(range(end)): + if P[i] >= last_size and P.vacancy_numbers[i] == P.rigging[i]: + ell[5] = i + break + + if ell[5] is None: + b = -2 + + if b is None: + b = -1 + + # Determine the new rigged configuration by removing boxes from the + # selected string and then making the new string singular + if case_S[1]: + row1 = [self.cur_partitions[1].remove_cell(ell[4], 2)] + else: + row1 = [self.cur_partitions[1].remove_cell(ell[1]), + self.cur_partitions[1].remove_cell(ell[4])] + + if case_S[0]: + row0 = [self.cur_partitions[0].remove_cell(ell[5], 2)] + row0.append( self.cur_partitions[0].remove_cell(ell[3], 2) ) + else: + if case_Q: + if ell[0] < ell[2]: + row0 = [self.cur_partitions[0].remove_cell(ell[2]), + self.cur_partitions[0].remove_cell(ell[0])] + else: + row0 = [self.cur_partitions[0].remove_cell(ell[0]), + self.cur_partitions[0].remove_cell(ell[2])] + if case_S[2]: + quasi = self.cur_partitions[0].remove_cell(ell[3]) + else: + row0 = [self.cur_partitions[0].remove_cell(ell[0])] + if case_S[2]: + row0.append( self.cur_partitions[0].remove_cell(ell[3], 2) ) + + row0.append( self.cur_partitions[0].remove_cell(ell[5]) ) + + self._update_vacancy_numbers(0) + self._update_vacancy_numbers(1) + + for l in row1: + if l is not None: + self.cur_partitions[1].rigging[l] = self.cur_partitions[1].vacancy_numbers[l] + for l in row0: + if l is not None: + self.cur_partitions[0].rigging[l] = self.cur_partitions[0].vacancy_numbers[l] + + # If case (Q,S) holds, then we must make the larger string quasisingular + if case_Q and case_S[2]: + P = self.cur_partitions[0] + vac_num = P.vacancy_numbers[quasi] + P.rigging[quasi] = vac_num + block_len = P[quasi] + j = quasi + 1 + length = len(P) + # Find the place for the quasisingular rigging + while j < length and P[j] == block_len and P.rigging[j] == vac_num: + j += 1 + P.rigging[j-1] = vac_num - 1 + + return(b) + diff --git a/src/sage/combinat/rigged_configurations/bijection.py b/src/sage/combinat/rigged_configurations/bijection.py index 4711be4be84..1fd93fe40ac 100644 --- a/src/sage/combinat/rigged_configurations/bijection.py +++ b/src/sage/combinat/rigged_configurations/bijection.py @@ -8,10 +8,11 @@ - Travis Scrimshaw (2011-04-15): Initial version - Travis Scrimshaw (2012-12-21): Added all non-exceptional bijection types +- Travis Scrimshaw (2014-09-10): Added type `D_4^{(3)}` """ #***************************************************************************** -# Copyright (C) 2011, 2012 Travis Scrimshaw +# Copyright (C) 2011-2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # @@ -49,6 +50,9 @@ from sage.combinat.rigged_configurations.bij_type_A2_odd import KRTToRCBijectionTypeA2Odd from sage.combinat.rigged_configurations.bij_type_A2_odd import RCToKRTBijectionTypeA2Odd +from sage.combinat.rigged_configurations.bij_type_D_tri import KRTToRCBijectionTypeDTri +from sage.combinat.rigged_configurations.bij_type_D_tri import RCToKRTBijectionTypeDTri + def KRTToRCBijection(tp_krt): r""" Return the correct KR tableaux to rigged configuration bijection helper class. @@ -83,7 +87,8 @@ def KRTToRCBijection(tp_krt): if ct.dual().type() == 'C': # D_{n+1}^{(2)} return KRTToRCBijectionTypeDTwisted(tp_krt) #if ct.dual().type() == 'F': # E_6^{(2)} - #if ct.dual().type() == 'G': # D_4^{(3)} + if ct.dual().type() == 'G': # D_4^{(3)} + return KRTToRCBijectionTypeDTri(tp_krt) raise NotImplementedError def RCToKRTBijection(rigged_configuration_elt): @@ -120,6 +125,7 @@ def RCToKRTBijection(rigged_configuration_elt): if ct.dual().type() == 'C': # D_{n+1}^{(2)} return RCToKRTBijectionTypeDTwisted(rigged_configuration_elt) #if ct.dual().type() == 'F': # E_6^{(2)} - #if ct.dual().type() == 'G': # D_4^{(3)} + if ct.dual().type() == 'G': # D_4^{(3)} + return RCToKRTBijectionTypeDTri(rigged_configuration_elt) raise NotImplementedError diff --git a/src/sage/combinat/rigged_configurations/kr_tableaux.py b/src/sage/combinat/rigged_configurations/kr_tableaux.py index 60358bcc367..074fa5f0f99 100644 --- a/src/sage/combinat/rigged_configurations/kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/kr_tableaux.py @@ -38,6 +38,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.abstract_method import abstract_method +from sage.misc.lazy_attribute import lazy_attribute from sage.misc.flatten import flatten from sage.structure.parent import Parent @@ -107,6 +108,7 @@ class KirillovReshetikhinTableaux(CrystalOfWords): - type `A_{2n}^{(2)}` for all `r`, - type `D_{n+1}^{(2)}` when `r < n`, + - type `D_4^{(3)}` when `r = 1`, the filling map is the same as given in [OSS2011]_ except for the rightmost column which is given by the column `[1, 2, \ldots, k, @@ -255,8 +257,11 @@ def __classcall_private__(cls, cartan_type, r, s): if r == ct.dual().classical().rank(): return KRTableauxDTwistedSpin(ct, r, s) return KRTableauxTypeBox(ct, r, s) - #if ct.dual().letter == 'F': # E_6^{(2)} - #if ct.dual().letter == 'G': # D_4^{(3)} + #if ct.dual().type() == 'F': # E_6^{(2)} + if ct.dual().type() == 'G': # D_4^{(3)} + if r == 1: + return KRTableauxTypeBox(ct, r, s) + return KRTableauxTypeDTri2(ct, r, s) raise NotImplementedError #return super(KirillovReshetikhinTableaux, cls).__classcall__(cls, ct, r, s) @@ -774,7 +779,8 @@ class KRTableauxTypeBox(KRTableauxTypeVertical): Kirillov-Reshetikhin tableaux `B^{r,s}` of type: - `A_{2n}^{(2)}` for all `r \leq n`, - - `D_{n+1}^{(2)}` for all `r < n`. + - `D_{n+1}^{(2)}` for all `r < n`, + - `D_4^{(3)}` for `r = 1`. TESTS:: @@ -782,6 +788,8 @@ class KRTableauxTypeBox(KRTableauxTypeVertical): sage: TestSuite(KRT).run() sage: KRT = crystals.KirillovReshetikhin(['D', 4, 2], 2, 2, model='KR') sage: TestSuite(KRT).run() # long time + sage: KRT = crystals.KirillovReshetikhin(['D', 4, 3], 1, 2, model='KR') + sage: TestSuite(KRT).run() # long time """ def _fill(self, weight): r""" @@ -1570,3 +1578,33 @@ class KRTableauxDTwistedSpin(KRTableauxRectangle): """ Element = KRTableauxSpinElement +class KRTableauxTypeDTri2(KirillovReshetikhinTableaux): + r""" + Kirillov-Reshetikhin tableaux `B^{2,s}` of type `D_4^{(3)}`. + """ + def __init__(self, cartan_type, r, s): + r""" + Initialize ``self``. + """ + self._r = r + self._s = s + self._cartan_type = cartan_type + Parent.__init__(self, category=(RegularCrystals(), FiniteCrystals())) + self.letters = CrystalOfLetters(cartan_type.classical()) + + @lazy_attribute + def module_generators(self): + """ + The module generators of ``self``. + """ + return self._build_module_generators() + + def _build_module_generators(self): + r""" + Return the module generators of ``self``. + """ + from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + RC = RiggedConfigurations(self._cartan_type, [[self._r, self._s]]) + return tuple(mg.to_tensor_product_of_kirillov_reshetikhin_tableaux()[0] + for mg in RC.module_generators) + From 027c9c0888b313eaf43fb901df92f0a2e281b282 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 14 Sep 2014 23:21:44 -0700 Subject: [PATCH 0015/1872] Finished bijection KRT -> RC and KR tableaux B^{2,s}. --- .../en/reference/combinat/rc_bijections.rst | 1 + .../rigged_configurations/bij_type_D_tri.py | 149 +++++++----------- .../rigged_configurations/kr_tableaux.py | 134 +++++++++++++++- 3 files changed, 194 insertions(+), 90 deletions(-) diff --git a/src/doc/en/reference/combinat/rc_bijections.rst b/src/doc/en/reference/combinat/rc_bijections.rst index f20901e3382..0f97bb354a6 100644 --- a/src/doc/en/reference/combinat/rc_bijections.rst +++ b/src/doc/en/reference/combinat/rc_bijections.rst @@ -14,4 +14,5 @@ Rigged Configuration Bijections ../sage/combinat/rigged_configurations/bij_type_A2_even ../sage/combinat/rigged_configurations/bij_type_A2_dual ../sage/combinat/rigged_configurations/bij_type_D_twisted + ../sage/combinat/rigged_configurations/bij_type_D_tri diff --git a/src/sage/combinat/rigged_configurations/bij_type_D_tri.py b/src/sage/combinat/rigged_configurations/bij_type_D_tri.py index 3a942ba939e..57069640e5f 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D_tri.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D_tri.py @@ -10,13 +10,13 @@ TESTS:: - sage: KRT = crystals.TensorProductOfKirillovReshetikhinTableaux(['D', 4, 3], [[2,1]]) + sage: KRT = crystals.TensorProductOfKirillovReshetikhinTableaux(['D', 4, 3], [[2, 1]]) sage: from sage.combinat.rigged_configurations.bij_type_D_tri import KRTToRCBijectionTypeDTri sage: bijection = KRTToRCBijectionTypeDTri(KRT(pathlist=[[-1,2]])) sage: TestSuite(bijection).run() sage: RC = RiggedConfigurations(['D', 4, 3], [[2, 1]]) sage: from sage.combinat.rigged_configurations.bij_type_D_tri import RCToKRTBijectionTypeDTri - sage: bijection = RCToKRTBijectionTypeDTri(RC(partition_list=[[],[],[]])) + sage: bijection = RCToKRTBijectionTypeDTri(RC(partition_list=[[],[]])) sage: TestSuite(bijection).run() """ @@ -46,7 +46,6 @@ class KRTToRCBijectionTypeDTri(KRTToRCBijectionTypeA): This inherits from type `A_n^{(1)}` because we use the same methods in some places. """ - def next_state(self, val): r""" Build the next state for type `D_4^{(3)}`. @@ -61,15 +60,13 @@ def next_state(self, val): sage: bijection.cur_path[0].insert(0, [2]) sage: bijection.next_state(2) """ - - n = self.n tableau_height = len(self.cur_path[0]) - 1 if val == 'E': - self.ret_rig_con[0].insert_cell(max_width) - self.ret_rig_con[1].insert_cell(max_width) + self.ret_rig_con[0].insert_cell(0) + self.ret_rig_con[1].insert_cell(0) if tableau_height == 0: - self.ret_rig_con[0].insert_cell(max_width) + self.ret_rig_con[0].insert_cell(0) self._update_vacancy_nums(0) self._update_vacancy_nums(1) self._update_partition_values(0) @@ -84,7 +81,7 @@ def next_state(self, val): pos_val = -val if pos_val == 0: - if len(self.ret_rig_con[pos_val - 1]) > 0: + if len(self.ret_rig_con[0]) > 0: max_width = self.ret_rig_con[0][0] else: max_width = 1 @@ -92,15 +89,12 @@ def next_state(self, val): width_n = max_width + 1 # Follow regular A_n rules - for a in reversed(range(tableau_height, 1)): + for a in reversed(range(tableau_height, 2)): max_width = self.ret_rig_con[a].insert_cell(max_width) - self._update_vacancy_nums(a + 1) - self._update_partition_values(a + 1) - self._update_vacancy_nums(tableau_height) - self._update_partition_values(tableau_height) - if tableau_height > 0: - self._update_vacancy_nums(tableau_height-1) - self._update_partition_values(tableau_height-1) + self._update_vacancy_nums(0) + self._update_partition_values(0) + self._update_vacancy_nums(1) + self._update_partition_values(1) # Make the largest string at \nu^{(1)} quasi-singular p = self.ret_rig_con[0] @@ -115,10 +109,10 @@ def next_state(self, val): break return - case_S = [None] * n + case_S = [None] * 2 pos_val = -val - if pos_val > 3: + if pos_val < 3: # Always add a cell to the first singular value in the first # tableau we are updating. if len(self.ret_rig_con[pos_val - 1]) > 0: @@ -186,87 +180,64 @@ def next_state(self, val): # No need to set max_width here since we will find a singular string # Now go back following the regular C_n (ish) rules - for a in reversed(range(tableau_height, 2)): - if case_S[a] == max_width: - self._insert_cell_case_S(self.ret_rig_con[a]) + if case_S[1] == max_width: + P = self.ret_rig_con[1] + + # Special case when adding twice to the first row + if P.rigging[0] is None: + P._list[0] += 1 else: - max_width = self.ret_rig_con[a].insert_cell(max_width) - self._update_vacancy_nums(a + 1) - self._update_partition_values(a + 1) - - # Update the final rigged partitions - self._update_vacancy_nums(tableau_height) - if tableau_height >= n - 1: - self._correct_vacancy_nums() - self._update_partition_values(tableau_height) - - if pos_val <= tableau_height: - for a in range(pos_val-1, tableau_height): - self._update_vacancy_nums(a) - self._update_partition_values(a) - if pos_val > 1: - self._update_vacancy_nums(pos_val - 2) - self._update_partition_values(pos_val - 2) - elif tableau_height > 0: - self._update_vacancy_nums(tableau_height - 1) - self._update_partition_values(tableau_height - 1) + for i in reversed(range(1, len(P))): + if P.rigging[i] is None: + j = i - 1 + while j >= 0 and P._list[j] == P._list[i]: + P.rigging[j+1] = P.rigging[j] # Shuffle it along + j -= 1 + P._list[j+1] += 1 + P.rigging[j+1] = None + break + else: + max_width = self.ret_rig_con[1].insert_cell(max_width) + + if tableau_height == 0: + if case_S[0] == max_width: + P = self.ret_rig_con[0] + # Since this is on the way back, the added string we want + # to bump will never be the first (largest) string + for i in reversed(range(1, len(P))): + if P.rigging[i] is None: + j = i - 1 + while j >= 0 and P._list[j] == P._list[i]: + P.rigging[j+1] = P.rigging[j] # Shuffle it along + j -= 1 + P._list[j+1] += 1 + P.rigging[j+1] = None + break + else: + max_width = self.ret_rig_con[0].insert_cell(max_width) + + self._update_vacancy_nums(0) + self._update_partition_values(0) + self._update_vacancy_nums(1) + self._update_partition_values(1) if case_QS: # Make the new string quasi-singular - num_rows = len(partition) + num_rows = len(P) for i in range(num_rows): - if partition._list[i] == width_n: + if P._list[i] == width_n: j = i+1 - while j < num_rows and partition._list[j] == width_n \ - and partition.vacancy_numbers[j] == partition.rigging[j]: + while j < num_rows and P._list[j] == width_n \ + and P.vacancy_numbers[j] == P.rigging[j]: j += 1 - partition.rigging[j-1] -= 1 + P.rigging[j-1] -= 1 break - def _insert_cell_case_S(self, partition): - """ - Insert a cell when case `(S)` holds. - - TESTS:: - - sage: RC = RiggedConfigurations(['C', 2, 1], [[2, 2]]) - sage: RP = RC(partition_list=[[2],[2,2]])[1] - sage: RP - -4[ ][ ]-4 - -4[ ][ ]-4 - - sage: RP.rigging[0] = None - sage: from sage.combinat.rigged_configurations.bij_type_D_tri import KRTToRCBijectionTypeDTri - sage: KRT = crystals.TensorProductOfKirillovReshetikhinTableaux(['D', 4, 3], [[2,1]]) - sage: bijection = KRTToRCBijectionTypeDTri(KRT(pathlist=[[-1,2]])) - sage: bijection._insert_cell_case_S(RP) - sage: RP - -4[ ][ ][ ]None - -4[ ][ ]-4 - - """ - # Special case when adding twice to the first row - if partition.rigging[0] is None: - partition._list[0] += 1 - return - - num_rows = len(partition) - for i in reversed(range(1, num_rows)): - if partition.rigging[i] is None: - j = i - 1 - while j >= 0 and partition._list[j] == partition._list[i]: - partition.rigging[j+1] = partition.rigging[j] # Shuffle it along - j -= 1 - partition._list[j+1] += 1 - partition.rigging[j+1] = None - return - class RCToKRTBijectionTypeDTri(RCToKRTBijectionTypeA): r""" Specific implementation of the bijection from rigged configurations to tensor products of KR tableaux for type `D_4^{(3)}`. """ - def next_state(self, height): r""" Build the next state for type `D_4^{(3)}`. @@ -275,9 +246,9 @@ def next_state(self, height): sage: RC = RiggedConfigurations(['D', 4, 3], [[2, 1]]) sage: from sage.combinat.rigged_configurations.bij_type_D_tri import RCToKRTBijectionTypeDTri - sage: bijection = RCToKRTBijectionTypeDTri(RC(partition_list=[[2],[2],[1]])) - sage: bijection.next_state(0) - -1 + sage: bijection = RCToKRTBijectionTypeDTri(RC(partition_list=[[3],[2]])) + sage: bijection.next_state(1) + -3 """ ell = [None] * 6 case_S = [False] * 3 diff --git a/src/sage/combinat/rigged_configurations/kr_tableaux.py b/src/sage/combinat/rigged_configurations/kr_tableaux.py index 074fa5f0f99..f053e7e9992 100644 --- a/src/sage/combinat/rigged_configurations/kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/kr_tableaux.py @@ -406,7 +406,7 @@ def _build_module_generators(self): ([[1, 1, 1], [2, 2, 2]],) """ - @abstract_method + @abstract_method(optional=True) def from_kirillov_reshetikhin_crystal(self, krc): """ Construct an element of ``self`` from the Kirillov-Reshetikhin @@ -1578,14 +1578,132 @@ class KRTableauxDTwistedSpin(KRTableauxRectangle): """ Element = KRTableauxSpinElement +class KRTableauxTypeDTri2Element(KirillovReshetikhinTableauxElement): + r""" + A Kirillov-Reshetikhin tableau in `B^{2,s}` of type `D_4^{(3)}`. + """ + def e(self, i): + """ + Perform the action of `e_i` on ``self``. + + .. TODO:: + + Implement a direct action of `e_0` without moving to + rigged configurations. + + EXAMPLES:: + + sage: KRT = crystals.KirillovReshetikhin(['D',4,3], 2, 1, model='KR') + sage: KRT.module_generators[0].e(0) + [[2], [E]] + """ + if i == self.parent().cartan_type().special_node(): + P = self.parent() + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + K = TensorProductOfKirillovReshetikhinTableaux(P.cartan_type(), [[2, P.s()]]) + ret = K(self).to_rigged_configuration() + RC = ret.parent() + ret = ret.to_virtual_configuration().e(0) + if ret is None: + return None + ret = RC.from_virtual(ret) + return ret.to_tensor_product_of_kirillov_reshetikhin_tableaux()[0] + return TensorProductOfRegularCrystalsElement.e(self, i) + + def f(self, i): + """ + Perform the action of `f_i` on ``self``. + + .. TODO:: + + Implement a direct action of `f_0` without moving to + rigged configurations. + + EXAMPLES:: + + sage: KRT = crystals.KirillovReshetikhin(['D',4,3], 2, 1, model='KR') + sage: KRT.module_generators[0].f(0) + sage: KRT.module_generators[3].f(0) + [[1], [0]] + """ + if i == self.parent().cartan_type().special_node(): + P = self.parent() + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + K = TensorProductOfKirillovReshetikhinTableaux(P.cartan_type(), [[2, P.s()]]) + ret = K(self).to_rigged_configuration() + RC = ret.parent() + ret = ret.to_virtual_configuration().f(0) + if ret is None: + return None + ret = RC.from_virtual(ret) + return ret.to_tensor_product_of_kirillov_reshetikhin_tableaux()[0] + return TensorProductOfRegularCrystalsElement.f(self, i) + + def epsilon(self, i): + r""" + Compute `\epsilon_i` of ``self``. + + .. TODO:: + + Implement a direct action of `\epsilon_0` without moving to + KR crystals. + + EXAMPLES:: + + sage: KRT = crystals.KirillovReshetikhin(['D',4,3], 2, 2, model='KR') + sage: KRT.module_generators[0].epsilon(0) + 6 + """ + if i == self.parent().cartan_type().special_node(): + P = self.parent() + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + K = TensorProductOfKirillovReshetikhinTableaux(P.cartan_type(), [[2, P.s()]]) + rc = K(self).to_rigged_configuration().to_virtual_configuration() + return rc.epsilon(0) + return TensorProductOfRegularCrystalsElement.epsilon(self, i) + + def phi(self, i): + r""" + Compute `\phi_i` of ``self``. + + .. TODO:: + + Compute `\phi_0` without moving to KR crystals. + + EXAMPLES:: + + sage: KRT = crystals.KirillovReshetikhin(['D',4,3], 2, 2, model='KR') + sage: KRT.module_generators[0].phi(0) + 0 + """ + if i == self.parent().cartan_type().special_node(): + P = self.parent() + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + K = TensorProductOfKirillovReshetikhinTableaux(P.cartan_type(), [[2, P.s()]]) + rc = K(self).to_rigged_configuration().to_virtual_configuration() + return rc.phi(0) + return TensorProductOfRegularCrystalsElement.phi(self, i) + class KRTableauxTypeDTri2(KirillovReshetikhinTableaux): r""" Kirillov-Reshetikhin tableaux `B^{2,s}` of type `D_4^{(3)}`. + + .. WARNING:: + + The Kashiwara-Nakashima version is not implemented due to the + non-trivial multiplicities of classical components, so + :meth:`classical_decomposition` does not work. """ def __init__(self, cartan_type, r, s): r""" Initialize ``self``. + + EXAMPLES:: + + sage: KRT = crystals.KirillovReshetikhin(['D', 4, 3], 2, 1, model='KR') + sage: TestSuite(KRT).run() # long time """ + # We must modify the constructor of KirillovReshetikhinTableaux self._r = r self._s = s self._cartan_type = cartan_type @@ -1596,15 +1714,29 @@ def __init__(self, cartan_type, r, s): def module_generators(self): """ The module generators of ``self``. + + EXAMPLES:: + + sage: KRT = crystals.KirillovReshetikhin(['D',4,3], 2, 1, model='KR') + sage: KRT.module_generators + ([[1], [2]], [[1], [0]], [[1], [E]], [[E], [E]]) """ return self._build_module_generators() def _build_module_generators(self): r""" Return the module generators of ``self``. + + EXAMPLES:: + + sage: KRT = crystals.KirillovReshetikhin(['D',4,3], 2, 1, model='KR') + sage: KRT._build_module_generators() + ([[1], [2]], [[1], [0]], [[1], [E]], [[E], [E]]) """ from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations RC = RiggedConfigurations(self._cartan_type, [[self._r, self._s]]) return tuple(mg.to_tensor_product_of_kirillov_reshetikhin_tableaux()[0] for mg in RC.module_generators) + Element = KRTableauxTypeDTri2Element + From f94c3f89ec7f126155d7d76752dfd66504ec532b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 23 Sep 2014 01:40:39 -0700 Subject: [PATCH 0016/1872] Another optio for indexed generators. --- src/sage/structure/indexed_generators.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index ff5465e0d4d..28953eb7bdf 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -74,6 +74,9 @@ class IndexedGenerators(object): - ``generator_cmp`` -- a comparison function (default: ``cmp``), to use for sorting elements in the output of elements + - ``string_quotes`` -- bool (default: ``True``), if ``True`` then + display string indices with quotes + .. NOTE:: These print options may also be accessed and modified using the @@ -130,7 +133,8 @@ def __init__(self, indices, prefix="x", **kwds): 'scalar_mult': "*", 'latex_scalar_mult': None, 'tensor_symbol': None, - 'generator_cmp': cmp} + 'generator_cmp': cmp, + 'string_quotes': True} # 'bracket': its default value here is None, meaning that # the value of self._repr_option_bracket is used; the default # value of that attribute is True -- see immediately before @@ -186,8 +190,9 @@ def print_options(self, **kwds): - ``latex_scalar_mult`` - ``tensor_symbol`` - ``generator_cmp`` + - ``string_quotes`` - See the documentation for :class:`CombinatorialFreeModule` for + See the documentation for :class:`IndexedGenerators` for descriptions of the effects of setting each of these options. OUTPUT: if the user provides any input, set the appropriate @@ -209,7 +214,8 @@ def print_options(self, **kwds): [('bracket', '('), ('generator_cmp', ), ('latex_bracket', False), ('latex_prefix', None), ('latex_scalar_mult', None), ('prefix', 'x'), - ('scalar_mult', '*'), ('tensor_symbol', None)] + ('scalar_mult', '*'), ('string_quotes', True), + ('tensor_symbol', None)] sage: F.print_options(bracket='[') # reset """ # don't just use kwds.get(...) because I want to distinguish @@ -220,7 +226,7 @@ def print_options(self, **kwds): # TODO: make this into a set and put it in a global variable? if option in ['prefix', 'latex_prefix', 'bracket', 'latex_bracket', 'scalar_mult', 'latex_scalar_mult', 'tensor_symbol', - 'generator_cmp' + 'generator_cmp', 'string_quotes' ]: self._print_options[option] = kwds[option] else: @@ -262,6 +268,9 @@ def _repr_generator(self, m): sage: e = F.basis() sage: e['a'] + 2*e['b'] # indirect doctest F['a'] + 2*F['b'] + sage: F.print_options(string_quotes=False) + sage: e['a'] + 2*e['b'] + F[a] + 2*F[b] sage: QS3 = CombinatorialFreeModule(QQ, Permutations(3), prefix="") sage: original_print_options = QS3.print_options() @@ -309,6 +318,9 @@ def _repr_generator(self, m): else: left = bracket right = bracket + quotes = self._print_options.get('string_quotes', True) + if not quotes and isinstance(m, str): + return self.prefix() + left + m + right return self.prefix() + left + repr(m) + right # mind the (m), to accept a tuple for m def _ascii_art_generator(self, m): From 5b546c2b28c52e72785c5e52016321804e249b6b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 23 Sep 2014 01:41:56 -0700 Subject: [PATCH 0017/1872] Fixed failing doctest. --- src/sage/combinat/free_module.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index e3be0f2c9ac..6e4d9830711 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1108,7 +1108,8 @@ class CombinatorialFreeModule(UniqueRepresentation, Module, IndexedGenerators): [('bracket', None), ('generator_cmp', ), ('latex_bracket', False), ('latex_prefix', None), ('latex_scalar_mult', None), ('prefix', 'x'), - ('scalar_mult', '*'), ('tensor_symbol', None)] + ('scalar_mult', '*'), ('string_quotes', True), + ('tensor_symbol', None)] sage: e = F.basis() sage: e['a'] - 3 * e['b'] From ad184efacc9ceabfb1179ccd4d677786f4713b01 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 19 Oct 2014 14:56:30 -0700 Subject: [PATCH 0018/1872] Implemented filtered modules/algebras and associated graded algebras. --- src/sage/algebras/associated_graded.py | 178 +++++++++++++++ src/sage/categories/algebras.py | 1 + src/sage/categories/algebras_with_basis.py | 1 + src/sage/categories/category_with_axiom.py | 7 +- .../examples/filtered_algebras_with_basis.py | 169 ++++++++++++++ .../examples/filtered_modules_with_basis.py | 151 +++++++++++++ .../examples/graded_modules_with_basis.py | 5 +- src/sage/categories/filtered_algebras.py | 47 ++++ .../filtered_algebras_with_basis.py | 143 ++++++++++++ src/sage/categories/filtered_modules.py | 208 ++++++++++++++++++ .../categories/filtered_modules_with_basis.py | 193 ++++++++++++++++ src/sage/categories/graded_algebras.py | 27 ++- .../categories/graded_algebras_with_basis.py | 117 ++-------- src/sage/categories/graded_modules.py | 88 ++------ .../categories/graded_modules_with_basis.py | 173 ++------------- src/sage/categories/modules.py | 38 ++++ src/sage/categories/modules_with_basis.py | 1 + 17 files changed, 1223 insertions(+), 324 deletions(-) create mode 100644 src/sage/algebras/associated_graded.py create mode 100644 src/sage/categories/examples/filtered_algebras_with_basis.py create mode 100644 src/sage/categories/examples/filtered_modules_with_basis.py create mode 100644 src/sage/categories/filtered_algebras.py create mode 100644 src/sage/categories/filtered_algebras_with_basis.py create mode 100644 src/sage/categories/filtered_modules.py create mode 100644 src/sage/categories/filtered_modules_with_basis.py diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py new file mode 100644 index 00000000000..4f9e6e925d2 --- /dev/null +++ b/src/sage/algebras/associated_graded.py @@ -0,0 +1,178 @@ +r""" +Associated Graded Algebras + +AUTHORS: + +- Travis Scrimshaw (2014-10-08): Initial version +""" + +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# 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.misc.misc_c import prod + +from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis +from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis +from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis +from sage.rings.all import ZZ +from sage.rings.infinity import infinity +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.sets.family import Family +from sage.sets.positive_integers import PositiveIntegers +from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid +from sage.combinat.cartesian_product import CartesianProduct +from sage.combinat.free_module import CombinatorialFreeModule + +class AssociatedGradedAlgebra(CombinatorialFreeModule): + """ + The associated graded algebra `\mathrm{gr} A` corresponding to + a filtered algebra `A`. + + INPUT: + + - ``A`` -- a filtered algebra + """ + def __init__(self, A, category=None): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: TestSuite(grA).run(elements=[prod(grA.algebra_generators())]) + """ + if A not in AlgebrasWithBasis(A.base_ring()).Filtered(): + raise ValueError("the base algebra must be filtered") + self._A = A + if category is None: + category = A.category().Graded() + from copy import copy + opts = copy(A.print_options()) + if not opts['prefix'] and not opts['bracket']: + opts['bracket'] = '(' + opts['prefix'] = opts['prefix'] + 'bar' + CombinatorialFreeModule.__init__(self, A.base_ring(), A.indices(), + category=category, **opts) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: A.graded_algebra() + Graded Algebra of An example of a filtered module with basis: + the universal enveloping algebra of Lie algebra of RR^3 + with cross product over Rational Field + """ + return "Graded Algebra of {}".format(self._A) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: latex(A.graded_algebra()) + \mathrm{gr}\; ... + """ + from sage.misc.latex import latex + return "\\mathrm{gr}\; " + latex(self._A) + + def _element_constructor_(self, x): + """ + Construct an element of ``self`` from ``x``. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: grA(A.an_element()) + bar(U['x']^2*U['y']^2*U['z']^3) + sage: grA(A.an_element() + A.algebra_generators()['x'] + 2) + bar(U['x']^2*U['y']^2*U['z']^3) + bar(U['x']) + 2*bar(1) + """ + if isinstance(x, CombinatorialFreeModule.Element): + if x.parent() is self._A: + return self._from_dict(dict(x)) + return super(AssociatedGradedAlgebra, self)._element_constructor_(x) + + def gen(self, *args, **kwds): + """ + Return a generator of ``self``. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: grA.gen('x') + bar(U['x']) + """ + try: + x = self._A.gen(*args, **kwds) + except AttributeError: + x = self._A.algebra_generators()[args[0]] + return self(x) + + @cached_method + def algebra_generators(self): + """ + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: grA.algebra_generators() + Finite family {'y': bar(U['y']), 'x': bar(U['x']), 'z': bar(U['z'])} + """ + G = self._A.algebra_generators() + return Family(G.keys(), lambda x: self(G[x]), name="generator") + + @cached_method + def one_basis(self): + """ + Return the basis index of the element `1`. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: grA.one_basis() + 1 + """ + return self._A.one_basis() + + def product_on_basis(self, x, y): + """ + Return the product on basis elements given by the + indices ``x`` and ``y``. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: G = grA.algebra_generators() + sage: x,y,z = G['x'], G['y'], G['z'] + sage: x * y # indirect doctest + bar(U['x']*U['y']) + sage: y * x + bar(U['x']*U['y']) + sage: z * y * x + bar(U['x']*U['y']*U['z']) + """ + ret = self._A.product_on_basis(x, y) + deg = self._A.degree_on_basis(x) + self._A.degree_on_basis(y) + return self.sum_of_terms([(i,c) for i,c in ret + if self._A.degree_on_basis(i) == deg], + distinct=True) + diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 4d921dffe59..e24f16e2e4b 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -87,6 +87,7 @@ def __contains__(self, x): # return [Rings()] # TODO: won't be needed when Rings() will be Rngs().Unital() Commutative = LazyImport('sage.categories.commutative_algebras', 'CommutativeAlgebras', at_startup=True) + Filtered = LazyImport('sage.categories.filtered_algebras', 'FilteredAlgebras') Graded = LazyImport('sage.categories.graded_algebras', 'GradedAlgebras') WithBasis = LazyImport('sage.categories.algebras_with_basis', 'AlgebrasWithBasis') diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index 8a4668edf1e..339ca9de605 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -116,6 +116,7 @@ def example(self, alphabet = ('a','b','c')): from sage.categories.examples.algebras_with_basis import Example return Example(self.base_ring(), alphabet) + Filtered = LazyImport('sage.categories.filtered_algebras_with_basis', 'FilteredAlgebrasWithBasis') FiniteDimensional = LazyImport('sage.categories.finite_dimensional_algebras_with_basis', 'FiniteDimensionalAlgebrasWithBasis') Graded = LazyImport('sage.categories.graded_algebras_with_basis', 'GradedAlgebrasWithBasis') diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index caf3a32f391..f62598efa6d 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -2208,8 +2208,11 @@ def _repr_object_names_static(category, axioms): continue if axiom == "WithBasis": result = result.replace(" over ", " with basis over ", 1) - elif axiom == "Connected" and "graded " in result: - result = result.replace("graded ", "graded connected ", 1) + elif axiom == "Connected": + if "graded " in result: + result = result.replace("graded ", "graded connected ", 1) + elif "filtered " in result: + result = result.replace("filtered ", "filtered connected ", 1) else: result = uncamelcase(axiom) + " " + result return result diff --git a/src/sage/categories/examples/filtered_algebras_with_basis.py b/src/sage/categories/examples/filtered_algebras_with_basis.py new file mode 100644 index 00000000000..0b864fe3aa4 --- /dev/null +++ b/src/sage/categories/examples/filtered_algebras_with_basis.py @@ -0,0 +1,169 @@ +r""" +Examples of filtered algebra with basis +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.categories.filtered_algebras_with_basis import FilteredAlgebrasWithBasis +from sage.combinat.free_module import CombinatorialFreeModule +from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid +from sage.sets.family import Family +from sage.misc.misc import powerset + +class IntersectionFilteredAlgebra(CombinatorialFreeModule): + r""" + This class illustrates an implementation of a filtered algebra + with basis: the universal enveloping algebra of the Lie algebra + of `\RR^3` under the cross product. + + The Lie algebra is generated by `x,y,z` with brackets defined by + `[x, y] = z`, `[y, z] = x`, and `[x, z] = -y`. The universal enveloping + algebra has a (PBW) basis consisting of monomials `x^i y^j z^k`. + + INPUT: + + - ``R`` -- base ring + + The implementation involves the following: + + - A set of algebra generators -- the set of generators `x,y,z`. + + - A product -- this is given on basis elements by using + :meth:`product_on_basis`. + + - A degree function -- this is determined on the basis elements + by using :meth:`degree_on_basis` which returns the sum of exponents + of the monomial. + """ + def __init__(self, base_ring): + """ + EXAMPLES:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: x,y,z = A.algebra_generators() + sage: TestSuite(A).run(elements=[x*y+z]) + """ + I = IndexedFreeAbelianMonoid(['x', 'y', 'z'], prefix='U') + gen_cmp = lambda x,y: cmp((-len(x), x.to_word_list()), (-len(y), y.to_word_list())) + CombinatorialFreeModule.__init__(self, base_ring, I, bracket=False, prefix='', + generator_cmp=gen_cmp, + category=FilteredAlgebrasWithBasis(base_ring)) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: AlgebrasWithBasis(QQ).Filtered().example() + An example of a filtered module with basis: + the universal enveloping algebra of + Lie algebra of RR^3 with cross product over Rational Field + """ + return "An example of a filtered module with basis: the universal enveloping algebra of Lie algebra of RR^3 with cross product over {}".format(self.base_ring()) + + def algebra_generators(self): + """ + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: key = lambda x: x.leading_support().to_word_list() + sage: sorted(A.algebra_generators(), key=key) + [U['x'], U['y'], U['z']] + """ + G = self._indices.monoid_generators() + return Family({x: self.monomial(G[x]) for x in G.keys()}) + + def one_basis(self): + """ + Return the index of the unit of ``self``. + + EXAMPLES:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: A.one_basis() + 1 + """ + return self._indices.one() + + def degree_on_basis(self, m): + """ + The degree of the element determined by ``m`` in ``self``. + + INPUT: + + - ``m`` -- an element of the free monoid + + OUTPUT: an integer, the degree of the corresponding basis element + + EXAMPLES:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: x = A.algebra_generators()['x'] + sage: A.degree_on_basis((x^4).leading_support()) + 4 + sage: a = A.an_element(); a + U['x']^2*U['y']^2*U['z']^3 + sage: A.degree_on_basis(a.leading_support()) + 7 + """ + return len(m) + + def product_on_basis(self, s, t): + """ + Return the product of two basis elements indexed by ``s`` and ``t``. + + EXAMPLES:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: G = A.algebra_generators() + sage: x,y,z = G['x'], G['y'], G['z'] + sage: A.product_on_basis(x.leading_support(), y.leading_support()) + U['x']*U['y'] + sage: y*x + U['x']*U['y'] - U['z'] + sage: x*y*x + U['x']^2*U['y'] - U['x']*U['z'] + sage: z*y*x + U['x']*U['y']*U['z'] - U['x']^2 + U['y']^2 - U['z']^2 + """ + if len(s) == 0: + return self.monomial(t) + if len(t) == 0: + return self.monomial(s) + if s.trailing_support() <= t.leading_support(): + return self.monomial(s*t) + + if len(t) == 1: + if len(s) == 1: + a = s.leading_support() + b = t.leading_support() + cur = self.monomial(s*t) + if a <= b: + return cur + if a == 'z': + if b == 'y': + return cur - self.monomial(self._indices.gen('x')) + # b == 'x' + return cur + self.monomial(self._indices.gen('y')) + # a == 'y' and b == 'x' + return cur - self.monomial(self._indices.gen('z')) + + cur = self.monomial(t) + for a in reversed(s.to_word_list()): + cur = self.monomial(self._indices.gen(a)) * cur + return cur + + cur = self.monomial(s) + for a in t.to_word_list(): + cur = cur * self.monomial(self._indices.gen(a)) + return cur + +Example = IntersectionFilteredAlgebra + diff --git a/src/sage/categories/examples/filtered_modules_with_basis.py b/src/sage/categories/examples/filtered_modules_with_basis.py new file mode 100644 index 00000000000..4af2f427e45 --- /dev/null +++ b/src/sage/categories/examples/filtered_modules_with_basis.py @@ -0,0 +1,151 @@ +r""" +Examples of filtered modules with basis +""" +#***************************************************************************** +# Copyright (C) 2013 Frederic Chapoton +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.categories.filtered_modules_with_basis import FilteredModulesWithBasis +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.partition import Partitions + + +class FilteredPartitionModule(CombinatorialFreeModule): + r""" + This class illustrates an implementation of a filtered module + with basis: the free module over partitions. + + INPUT: + + - ``R`` -- base ring + + The implementation involves the following: + + - A choice of how to represent elements. In this case, the basis + elements are partitions. The algebra is constructed as a + :class:`CombinatorialFreeModule + ` on the + set of partitions, so it inherits all of the methods for such + objects, and has operations like addition already defined. + + :: + + sage: A = ModulesWithBasis(QQ).Filtered().example() + + - If the algebra is called ``A``, then its basis function is + stored as ``A.basis``. Thus the function can be used to + find a basis for the degree `d` piece: essentially, just call + ``A.basis(d)``. More precisely, call ``x`` for + each ``x`` in ``A.basis(d)``. + + :: + + sage: [m for m in A.basis(4)] + [P[4], P[3, 1], P[2, 2], P[2, 1, 1], P[1, 1, 1, 1]] + + - For dealing with basis elements: :meth:`degree_on_basis`, and + :meth:`_repr_term`. The first of these defines the degree of any + monomial, and then the :meth:`degree + ` method for elements -- + see the next item -- uses it to compute the degree for a linear + combination of monomials. The last of these determines the + print representation for monomials, which automatically produces + the print representation for general elements. + + :: + + sage: A.degree_on_basis(Partition([4,3])) + 7 + sage: A._repr_term(Partition([4,3])) + 'P[4, 3]' + + - There is a class for elements, which inherits from + :class:`CombinatorialFreeModuleElement + `. An + element is determined by a dictionary whose keys are partitions and whose + corresponding values are the coefficients. The class implements + two things: an :meth:`is_homogeneous + ` method and a + :meth:`degree ` method. + + :: + + sage: p = A.monomial(Partition([3,2,1])); p + P[3, 2, 1] + sage: p.is_homogeneous() + True + sage: p.degree() + 6 + """ + def __init__(self, base_ring): + """ + EXAMPLES:: + + sage: A = ModulesWithBasis(QQ).Filtered().example(); A + An example of a filtered module with basis: the free module on partitions over Rational Field + sage: TestSuite(A).run() + """ + CombinatorialFreeModule.__init__(self, base_ring, Partitions(), + category=FilteredModulesWithBasis(base_ring)) + + # FIXME: this is currently required, because the implementation of ``basis`` + # in CombinatorialFreeModule overrides that of GradedModulesWithBasis + basis = FilteredModulesWithBasis.ParentMethods.__dict__['basis'] + + # This could be a default implementation + def degree_on_basis(self, t): + """ + The degree of the element determined by the partition ``t`` in + this filtered module. + + INPUT: + + - ``t`` -- the index of an element of the basis of this module, + i.e. a partition + + OUTPUT: an integer, the degree of the corresponding basis element + + EXAMPLES:: + + sage: A = ModulesWithBasis(QQ).Filtered().example() + sage: A.degree_on_basis(Partition((2,1))) + 3 + sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) + 10 + sage: type(A.degree_on_basis(Partition((1,1)))) + + """ + return t.size() + + def _repr_(self): + """ + Print representation + + EXAMPLES:: + + sage: ModulesWithBasis(QQ).Filtered().example() # indirect doctest + An example of a filtered module with basis: the free module on partitions over Rational Field + """ + return "An example of a filtered module with basis: the free module on partitions over %s" % self.base_ring() + + def _repr_term(self, t): + """ + Print representation for the basis element represented by the + partition ``t``. + + This governs the behavior of the print representation of all elements + of the algebra. + + EXAMPLES:: + + sage: A = ModulesWithBasis(QQ).Filtered().example() + sage: A._repr_term(Partition((4,2,1))) + 'P[4, 2, 1]' + """ + return 'P' + t._repr_() + +Example = FilteredPartitionModule + diff --git a/src/sage/categories/examples/graded_modules_with_basis.py b/src/sage/categories/examples/graded_modules_with_basis.py index ebd05587f55..e0f95880199 100644 --- a/src/sage/categories/examples/graded_modules_with_basis.py +++ b/src/sage/categories/examples/graded_modules_with_basis.py @@ -9,6 +9,7 @@ #***************************************************************************** from sage.categories.graded_modules_with_basis import GradedModulesWithBasis +from sage.categories.filtered_modules_with_basis import FilteredModulesWithBasis from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.partition import Partitions @@ -20,7 +21,7 @@ class GradedPartitionModule(CombinatorialFreeModule): INPUT: - - ``R`` - base ring + - ``R`` -- base ring The implementation involves the following: @@ -106,7 +107,7 @@ def __init__(self, base_ring): # FIXME: this is currently required, because the implementation of ``basis`` # in CombinatorialFreeModule overrides that of GradedModulesWithBasis - basis = GradedModulesWithBasis.ParentMethods.__dict__['basis'] + basis = FilteredModulesWithBasis.ParentMethods.__dict__['basis'] # This could be a default implementation def degree_on_basis(self, t): diff --git a/src/sage/categories/filtered_algebras.py b/src/sage/categories/filtered_algebras.py new file mode 100644 index 00000000000..f03b2fb5877 --- /dev/null +++ b/src/sage/categories/filtered_algebras.py @@ -0,0 +1,47 @@ +r""" +Filtered Algebras +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.categories.filtered_modules import FilteredModulesCategory + +class FilteredAlgebras(FilteredModulesCategory): + """ + The category of filtered algebras. + + EXAMPLES:: + + sage: Algebras(ZZ).Filtered() + Category of filtered algebras over Integer Ring + sage: Algebras(ZZ).Filtered().super_categories() + [Category of algebras over Integer Ring, + Category of filtered modules over Integer Ring] + + TESTS:: + + sage: TestSuite(Algebras(ZZ).Filtered()).run() + """ + class ParentMethods: + @abstract_method(optional=True) + def graded_algebra(self): + """ + Return the associated graded algebra to ``self``. + + EXAMPLES:: + + sage: A = AlgebrasWithBasis(ZZ).Filtered().example() + sage: A.graded_algebra() + Graded Algebra of An example of a filtered module with basis: + the universal enveloping algebra of + Lie algebra of RR^3 with cross product over Integer Ring + """ + + class ElementMethods: + pass + diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py new file mode 100644 index 00000000000..d9d3fe61a96 --- /dev/null +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -0,0 +1,143 @@ +r""" +Filtered algebras with basis +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.categories.filtered_modules import FilteredModulesCategory + +class FilteredAlgebrasWithBasis(FilteredModulesCategory): + """ + The category of filtered algebras with a distinguished basis. + + EXAMPLES:: + + sage: C = AlgebrasWithBasis(ZZ).Filtered(); C + Category of filtered algebras with basis over Integer Ring + sage: sorted(C.super_categories(), key=str) + [Category of algebras with basis over Integer Ring, + Category of filtered algebras over Integer Ring, + Category of filtered modules with basis over Integer Ring] + + TESTS:: + + sage: TestSuite(C).run() + """ + class ParentMethods: + def graded_algebra(self): + """ + Return the associated graded algebra to ``self``. + + EXAMPLES:: + + sage: A = AlgebrasWithBasis(ZZ).Filtered().example() + sage: A.graded_algebra() + Graded Algebra of An example of a filtered module with basis: + the universal enveloping algebra of + Lie algebra of RR^3 with cross product over Integer Ring + """ + from sage.algebras.associated_graded import AssociatedGradedAlgebra + return AssociatedGradedAlgebra(self) + + class ElementMethods: + def is_homogeneous(self): + """ + Return whether this element is homogeneous. + + EXAMPLES:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: (x, y) = (S[2], S[3]) + sage: (3*x).is_homogeneous() + True + sage: (x^3 - y^2).is_homogeneous() + True + sage: ((x + y)^2).is_homogeneous() + False + """ + degree_on_basis = self.parent().degree_on_basis + degree = None + for m in self.support(): + if degree is None: + degree = degree_on_basis(m) + else: + if degree != degree_on_basis(m): + return False + return True + + def homogeneous_degree(self): + """ + The degree of this element. + + .. NOTE:: + + This raises an error if the element is not homogeneous. + To obtain the maximum of the degrees of the homogeneous + summands, use :meth:`maximal_degree` + + .. SEEALSO:: :meth:`maximal_degree` + + EXAMPLES:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: (x, y) = (S[2], S[3]) + sage: x.homogeneous_degree() + 2 + sage: (x^3 + 4*y^2).homogeneous_degree() + 6 + sage: ((1 + x)^3).homogeneous_degree() + Traceback (most recent call last): + ... + ValueError: element is not homogeneous + + TESTS:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S.zero().degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + """ + if self.is_zero(): + raise ValueError("the zero element does not have a well-defined degree") + if not self.is_homogeneous(): + raise ValueError("element is not homogeneous") + return self.parent().degree_on_basis(self.leading_support()) + + # default choice for degree; will be overridden as necessary + degree = homogeneous_degree + + def maximal_degree(self): + """ + The maximum of the degrees of the homogeneous summands. + + .. SEEALSO:: :meth:`homogeneous_degree` + + EXAMPLES:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: (x, y) = (S[2], S[3]) + sage: x.maximal_degree() + 2 + sage: (x^3 + 4*y^2).maximal_degree() + 6 + sage: ((1 + x)^3).maximal_degree() + 6 + + TESTS:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S.zero().degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + """ + if self.is_zero(): + raise ValueError("the zero element does not have a well-defined degree") + degree_on_basis = self.parent().degree_on_basis + return max(degree_on_basis(m) for m in self.support()) + diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py new file mode 100644 index 00000000000..bb7e4998e20 --- /dev/null +++ b/src/sage/categories/filtered_modules.py @@ -0,0 +1,208 @@ +r""" +Filtered modules +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# 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.misc.lazy_attribute import lazy_class_attribute +from sage.categories.category_types import Category_over_base_ring +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory + +class FilteredModulesCategory(RegressiveCovariantConstructionCategory, Category_over_base_ring): + def __init__(self, base_category): + """ + EXAMPLES:: + + sage: C = Algebras(QQ).Filtered() + sage: C + Category of filtered algebras over Rational Field + sage: C.base_category() + Category of algebras over Rational Field + sage: sorted(C.super_categories(), key=str) + [Category of algebras over Rational Field, + Category of filtered modules over Rational Field] + + sage: AlgebrasWithBasis(QQ).Filtered().base_ring() + Rational Field + sage: HopfAlgebrasWithBasis(QQ).Filtered().base_ring() + Rational Field + """ + super(FilteredModulesCategory, self).__init__(base_category, base_category.base_ring()) + + _functor_category = "Filtered" + + @lazy_class_attribute + def _base_category_class(cls): + """ + Recover the class of the base category. + + OUTPUT: + + A *tuple* whose first entry is the base category class. + + .. WARNING:: + + This is only used for filtered categories that are not + implemented as nested classes, and won't work otherwise. + + .. SEEALSO:: :meth:`__classcall__` + + EXAMPLES:: + + sage: from sage.categories.filtered_modules import FilteredModules + sage: FilteredModules._base_category_class + (,) + sage: from sage.categories.filtered_algebras_with_basis import FilteredAlgebrasWithBasis + sage: FilteredAlgebrasWithBasis._base_category_class + (,) + + The reason for wrapping the base category class in a tuple is + that, often, the base category class implements a + :meth:`__classget__` method which would get in the way upon + attribute access:: + + sage: F = FilteredAlgebrasWithBasis + sage: F._foo = F._base_category_class[0] + sage: F._foo + Traceback (most recent call last): + ... + AssertionError: base category class for <...AlgebrasWithBasis'> mismatch; + expected <...Algebras'>, got <...FilteredAlgebrasWithBasis'> + """ + module_name = cls.__module__.replace("filtered_","") + import sys + name = cls.__name__.replace("Filtered","") + __import__(module_name) + module = sys.modules[module_name] + return (module.__dict__[name],) + + @staticmethod + def __classcall__(cls, category, *args): + """ + Magic support for putting Filtered categories in their own file. + + EXAMPLES:: + + sage: from sage.categories.filtered_modules import FilteredModules + sage: FilteredModules(ZZ) # indirect doctest + Category of filtered modules over Integer Ring + sage: Modules(ZZ).Filtered() + Category of filtered modules over Integer Ring + sage: FilteredModules(ZZ) is Modules(ZZ).Filtered() + True + + .. TODO:: + + Generalize this support for all other functorial + constructions if at some point we have a category ``Blah`` for + which we want to implement the construction ``Blah.Foo`` in a + separate file like we do for e.g. :class:`FilteredModules`, + :class:`FilteredAlgebras`, ... + + .. SEEALSO:: :meth:`_base_category_class` + """ + base_category_class = cls._base_category_class[0] + if isinstance(category, base_category_class): + return super(FilteredModulesCategory, cls).__classcall__(cls, category, *args) + else: + return base_category_class(category, *args).Filtered() + + def _repr_object_names(self): + """ + EXAMPLES:: + + sage: AlgebrasWithBasis(QQ).Filtered() # indirect doctest + Category of filtered algebras with basis over Rational Field + """ + return "filtered {}".format(self.base_category()._repr_object_names()) + +class FilteredModules(FilteredModulesCategory): + """ + The category of filtered modules. + + EXAMPLES:: + + sage: Modules(ZZ).Filtered() + Category of filtered modules over Integer Ring + sage: Modules(ZZ).Filtered().super_categories() + [Category of modules over Integer Ring] + + TESTS:: + + sage: TestSuite(Modules(ZZ).Filtered()).run() + """ + + def extra_super_categories(self): + r""" + Adds :class:`VectorSpaces` to the super categories of ``self`` if + the base ring is a field. + + EXAMPLES:: + + sage: Modules(QQ).Filtered().extra_super_categories() + [Category of vector spaces over Rational Field] + sage: Modules(ZZ).Filtered().extra_super_categories() + [] + + This makes sure that ``Modules(QQ).Filtered()`` returns an + instance of :class:`FilteredModules` and not a join category of + an instance of this class and of ``VectorSpaces(QQ)``:: + + sage: type(Modules(QQ).Filtered()) + + + .. TODO:: + + Get rid of this workaround once there is a more systematic + approach for the alias ``Modules(QQ)`` -> ``VectorSpaces(QQ)``. + Probably the later should be a category with axiom, and + covariant constructions should play well with axioms. + """ + from sage.categories.modules import Modules + from sage.categories.fields import Fields + base_ring = self.base_ring() + if base_ring in Fields: + return [Modules(base_ring)] + else: + return [] + + class SubcategoryMethods: + + @cached_method + def Connected(self): + r""" + Return the full subcategory of the connected objects of ``self``. + + EXAMPLES:: + + sage: Modules(ZZ).Filtered().Connected() + Category of filtered connected modules over Integer Ring + sage: Coalgebras(QQ).Filtered().Connected() + Join of Category of filtered connected modules over Rational Field + and Category of coalgebras over Rational Field + sage: AlgebrasWithBasis(QQ).Filtered().Connected() + Category of filtered connected algebras with basis over Rational Field + + TESTS:: + + sage: TestSuite(Modules(ZZ).Filtered().Connected()).run() + sage: Coalgebras(QQ).Filtered().Connected.__module__ + 'sage.categories.filtered_modules' + """ + return self._with_axiom("Connected") + + class Connected(CategoryWithAxiom_over_base_ring): + pass + + class ParentMethods: + pass + + class ElementMethods: + pass + diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py new file mode 100644 index 00000000000..8db42471566 --- /dev/null +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -0,0 +1,193 @@ +r""" +Filtered modules with basis +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.categories.filtered_modules import FilteredModulesCategory + +class FilteredModulesWithBasis(FilteredModulesCategory): + """ + The category of filtered modules with a distinguished basis. + + EXAMPLES:: + + sage: C = ModulesWithBasis(ZZ).Filtered(); C + Category of filtered modules with basis over Integer Ring + sage: sorted(C.super_categories(), key=str) + [Category of filtered modules over Integer Ring, + Category of modules with basis over Integer Ring] + sage: C is ModulesWithBasis(ZZ).Filtered() + True + + TESTS:: + + sage: TestSuite(C).run() + """ + class ParentMethods: + + # TODO: which syntax do we prefer? + # A.basis(degree = 3) + # A.basis().subset(degree=3) + + # This is related to the following design question: + # If F = (f_i)_{i\in I} is a family, should ``F.subset(degree = 3)`` + # be the elements of F of degree 3 or those whose index is of degree 3? + + def basis(self, d=None): + """ + Return the basis for (an homogeneous component of) ``self``. + + INPUT: + + - `d` -- non negative integer or ``None``, optional (default: ``None``) + + If `d` is None, returns a basis of the module. + Otherwise, returns the basis of the homogeneous component of degree `d`. + + EXAMPLES:: + + sage: A = ModulesWithBasis(ZZ).Filtered().example() + sage: A.basis(4) + Lazy family (Term map from Partitions to An example of a filtered module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions of the integer 4} + + Without arguments, the full basis is returned:: + + sage: A.basis() + Lazy family (Term map from Partitions to An example of a filtered module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions} + sage: A.basis() + Lazy family (Term map from Partitions to An example of a filtered module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions} + """ + from sage.sets.family import Family + if d is None: + return Family(self._indices, self.monomial) + else: + return Family(self._indices.subset(size=d), self.monomial) + + class ElementMethods: + + def is_homogeneous(self): + """ + Return whether ``self`` is homogeneous. + + EXAMPLES:: + + sage: A = ModulesWithBasis(ZZ).Filtered().example() + sage: x=A(Partition((3,2,1))) + sage: y=A(Partition((4,4,1))) + sage: z=A(Partition((2,2,2))) + sage: (3*x).is_homogeneous() + True + sage: (x - y).is_homogeneous() + False + sage: (x+2*z).is_homogeneous() + True + """ + degree_on_basis = self.parent().degree_on_basis + degree = None + for m in self.support(): + if degree is None: + degree = degree_on_basis(m) + else: + if degree != degree_on_basis(m): + return False + return True + + def degree(self): + """ + The degree of this element in the filtered module. + + .. NOTE:: + + This raises an error if the element is not homogeneous. + Another implementation option would be to return the + maximum of the degrees of the homogeneous summands. + + EXAMPLES:: + + sage: A = ModulesWithBasis(ZZ).Filtered().example() + sage: x = A(Partition((3,2,1))) + sage: y = A(Partition((4,4,1))) + sage: z = A(Partition((2,2,2))) + sage: x.degree() + 6 + sage: (x + 2*z).degree() + 6 + sage: (y - x).degree() + Traceback (most recent call last): + ... + ValueError: element is not homogeneous + """ + if not self.support(): + raise ValueError("the zero element does not have a well-defined degree") + if not self.is_homogeneous(): + raise ValueError("element is not homogeneous") + return self.parent().degree_on_basis(self.leading_support()) + + def homogeneous_component(self, n): + """ + Return the homogeneous component of degree ``n`` of this + element. + + EXAMPLES:: + + sage: A = ModulesWithBasis(ZZ).Filtered().example() + sage: x = A.an_element(); x + 2*P[] + 2*P[1] + 3*P[2] + sage: x.homogeneous_component(-1) + 0 + sage: x.homogeneous_component(0) + 2*P[] + sage: x.homogeneous_component(1) + 2*P[1] + sage: x.homogeneous_component(2) + 3*P[2] + sage: x.homogeneous_component(3) + 0 + + TESTS: + + Check that this really return ``A.zero()`` and not a plain ``0``:: + + sage: x.homogeneous_component(3).parent() is A + True + """ + degree_on_basis = self.parent().degree_on_basis + return self.parent().sum_of_terms((i, c) + for (i, c) in self + if degree_on_basis(i) == n) + + def truncate(self, n): + """ + Return the sum of the homogeneous components of degree + strictly less than ``n`` of this element. + + EXAMPLES:: + + sage: A = ModulesWithBasis(ZZ).Filtered().example() + sage: x = A.an_element(); x + 2*P[] + 2*P[1] + 3*P[2] + sage: x.truncate(0) + 0 + sage: x.truncate(1) + 2*P[] + sage: x.truncate(2) + 2*P[] + 2*P[1] + sage: x.truncate(3) + 2*P[] + 2*P[1] + 3*P[2] + + TESTS: + + Check that this really return ``A.zero()`` and not a plain ``0``:: + + sage: x.truncate(0).parent() is A + True + """ + degree_on_basis = self.parent().degree_on_basis + return self.parent().sum_of_terms((i, c) for (i, c) in self + if degree_on_basis(i) < n) + diff --git a/src/sage/categories/graded_algebras.py b/src/sage/categories/graded_algebras.py index 98e89f81993..f9e59a137e1 100644 --- a/src/sage/categories/graded_algebras.py +++ b/src/sage/categories/graded_algebras.py @@ -20,16 +20,39 @@ class GradedAlgebras(GradedModulesCategory): sage: GradedAlgebras(ZZ) Category of graded algebras over Integer Ring sage: GradedAlgebras(ZZ).super_categories() - [Category of algebras over Integer Ring, + [Category of filtered algebras over Integer Ring, Category of graded modules over Integer Ring] TESTS:: sage: TestSuite(GradedAlgebras(ZZ)).run() """ + def extra_super_categories(self): + r""" + Adds :class:`FilteredAlgebras` to the super categories of ``self`` + since every graded algebra admits a filtraion. + + EXAMPLES:: + + sage: GradedAlgebras(ZZ).extra_super_categories() + [Category of filtered algebras over Integer Ring] + """ + from sage.categories.filtered_algebras import FilteredAlgebras + return [FilteredAlgebras(self.base_ring())] class ParentMethods: - pass + def graded_algebra(self): + """ + Return the associated graded algebra to ``self``. + + EXAMPLES:: + + sage: m = SymmetricFunctions(QQ).m() + sage: m.graded_algebra() is m + True + """ + return self class ElementMethods: pass + diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index 66a608fad2e..e45ece1de8e 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -20,7 +20,7 @@ class GradedAlgebrasWithBasis(GradedModulesCategory): sage: C = GradedAlgebrasWithBasis(ZZ); C Category of graded algebras with basis over Integer Ring sage: sorted(C.super_categories(), key=str) - [Category of algebras with basis over Integer Ring, + [Category of filtered algebras with basis over Integer Ring, Category of graded algebras over Integer Ring, Category of graded modules with basis over Integer Ring] @@ -28,107 +28,34 @@ class GradedAlgebrasWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ + def extra_super_categories(self): + r""" + Adds :class:`FilteredAlgebras` to the super categories of ``self`` + since every graded algebra admits a filtraion. - class ParentMethods: - pass - - class ElementMethods: - def is_homogeneous(self): - """ - Return whether this element is homogeneous. - - EXAMPLES:: + EXAMPLES:: - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: (x, y) = (S[2], S[3]) - sage: (3*x).is_homogeneous() - True - sage: (x^3 - y^2).is_homogeneous() - True - sage: ((x + y)^2).is_homogeneous() - False - """ - degree_on_basis = self.parent().degree_on_basis - degree = None - for m in self.support(): - if degree is None: - degree = degree_on_basis(m) - else: - if degree != degree_on_basis(m): - return False - return True + sage: GradedAlgebras(ZZ).extra_super_categories() + [Category of filtered algebras over Integer Ring] + """ + from sage.categories.filtered_algebras_with_basis import FilteredAlgebrasWithBasis + return [FilteredAlgebrasWithBasis(self.base_ring())] - def homogeneous_degree(self): + class ParentMethods: + # This needs to be copied in GradedAlgebras because we need to have + # FilteredAlgebrasWithBasis as an extra super category + def graded_algebra(self): """ - The degree of this element. - - .. note:: - - This raises an error if the element is not homogeneous. - To obtain the maximum of the degrees of the homogeneous - summands, use :meth:`maximal_degree` - - .. seealso: :meth:`maximal_degree` + Return the associated graded algebra to ``self``. EXAMPLES:: - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: (x, y) = (S[2], S[3]) - sage: x.homogeneous_degree() - 2 - sage: (x^3 + 4*y^2).homogeneous_degree() - 6 - sage: ((1 + x)^3).homogeneous_degree() - Traceback (most recent call last): - ... - ValueError: Element is not homogeneous. - - TESTS:: - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S.zero().degree() - Traceback (most recent call last): - ... - ValueError: The zero element does not have a well-defined degree. - """ - if self.is_zero(): - raise ValueError("The zero element does not have a well-defined degree.") - try: - assert self.is_homogeneous() - return self.parent().degree_on_basis(self.leading_support()) - except AssertionError: - raise ValueError("Element is not homogeneous.") - - # default choice for degree; will be overridden as necessary - degree = homogeneous_degree - - def maximal_degree(self): + sage: m = SymmetricFunctions(QQ).m() + sage: m.graded_algebra() is m + True """ - The maximum of the degrees of the homogeneous summands. - - .. seealso: :meth:`homogeneous_degree` + return self - EXAMPLES:: - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: (x, y) = (S[2], S[3]) - sage: x.maximal_degree() - 2 - sage: (x^3 + 4*y^2).maximal_degree() - 6 - sage: ((1 + x)^3).maximal_degree() - 6 - - TESTS:: + class ElementMethods: + pass - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S.zero().degree() - Traceback (most recent call last): - ... - ValueError: The zero element does not have a well-defined degree. - """ - if self.is_zero(): - raise ValueError("The zero element does not have a well-defined degree.") - else: - degree_on_basis = self.parent().degree_on_basis - return max(degree_on_basis(m) for m in self.support()) diff --git a/src/sage/categories/graded_modules.py b/src/sage/categories/graded_modules.py index 99c005c8052..73d9136783c 100644 --- a/src/sage/categories/graded_modules.py +++ b/src/sage/categories/graded_modules.py @@ -26,7 +26,7 @@ def __init__(self, base_category): sage: C.base_category() Category of algebras over Rational Field sage: sorted(C.super_categories(), key=str) - [Category of algebras over Rational Field, + [Category of filtered algebras over Rational Field, Category of graded modules over Rational Field] sage: AlgebrasWithBasis(QQ).Graded().base_ring() @@ -120,86 +120,44 @@ def _repr_object_names(self): """ return "graded {}".format(self.base_category()._repr_object_names()) -class GradedModules(GradedModulesCategory): - """ - The category of graded modules. - - EXAMPLES:: - - sage: GradedModules(ZZ) - Category of graded modules over Integer Ring - sage: GradedModules(ZZ).super_categories() - [Category of modules over Integer Ring] - - TESTS:: - - sage: TestSuite(GradedModules(ZZ)).run() - """ - def extra_super_categories(self): r""" - Adds :class:`VectorSpaces` to the super categories of ``self`` if - the base ring is a field. + Adds :class:`FilteredModules` to the super categories of ``self`` + since every graded module admits a filtraion. EXAMPLES:: - sage: Modules(QQ).Graded().extra_super_categories() - [Category of vector spaces over Rational Field] - sage: Modules(ZZ).Graded().extra_super_categories() - [] - - This makes sure that ``Modules(QQ).Graded()`` returns an - instance of :class:`GradedModules` and not a join category of - an instance of this class and of ``VectorSpaces(QQ)``:: - - sage: type(Modules(QQ).Graded()) - - - .. TODO:: - - Get rid of this workaround once there is a more systematic - approach for the alias ``Modules(QQ)`` -> ``VectorSpaces(QQ)``. - Probably the later should be a category with axiom, and - covariant constructions should play well with axioms. + sage: GradedModules(ZZ).extra_super_categories() + [Category of filtered modules over Integer Ring] """ - from sage.categories.modules import Modules - from sage.categories.fields import Fields - base_ring = self.base_ring() - if base_ring in Fields: - return [Modules(base_ring)] - else: - return [] + from sage.categories.filtered_modules import FilteredModules + return [FilteredModules(self.base_ring())] - class SubcategoryMethods: +class GradedModules(GradedModulesCategory): + r""" + The category of graded modules. - @cached_method - def Connected(self): - r""" - Return the full subcategory of the connected objects of ``self``. + We consider every graded module `M = \bigoplus_i M_i` as a + filtered module under the (natural) filtration of - EXAMPLES:: + .. MATH:: - sage: Modules(ZZ).Graded().Connected() - Category of graded connected modules over Integer Ring - sage: Coalgebras(QQ).Graded().Connected() - Join of Category of graded connected modules over Rational Field - and Category of coalgebras over Rational Field - sage: GradedAlgebrasWithBasis(QQ).Connected() - Category of graded connected algebras with basis over Rational Field + F_i = \bigoplus_{j < i} M_j. - TESTS:: + EXAMPLES:: - sage: TestSuite(Modules(ZZ).Graded().Connected()).run() - sage: Coalgebras(QQ).Graded().Connected.__module__ - 'sage.categories.graded_modules' - """ - return self._with_axiom("Connected") + sage: GradedModules(ZZ) + Category of graded modules over Integer Ring + sage: GradedModules(ZZ).super_categories() + [Category of filtered modules over Integer Ring] - class Connected(CategoryWithAxiom_over_base_ring): - pass + TESTS:: + sage: TestSuite(GradedModules(ZZ)).run() + """ class ParentMethods: pass class ElementMethods: pass + diff --git a/src/sage/categories/graded_modules_with_basis.py b/src/sage/categories/graded_modules_with_basis.py index 9bb99fc5a95..10671e3b307 100644 --- a/src/sage/categories/graded_modules_with_basis.py +++ b/src/sage/categories/graded_modules_with_basis.py @@ -20,8 +20,8 @@ class GradedModulesWithBasis(GradedModulesCategory): sage: C = GradedModulesWithBasis(ZZ); C Category of graded modules with basis over Integer Ring sage: sorted(C.super_categories(), key=str) - [Category of graded modules over Integer Ring, - Category of modules with basis over Integer Ring] + [Category of filtered modules with basis over Integer Ring, + Category of graded modules over Integer Ring] sage: C is ModulesWithBasis(ZZ).Graded() True @@ -29,165 +29,22 @@ class GradedModulesWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ - class ParentMethods: - - # TODO: which syntax do we prefer? - # A.basis(degree = 3) - # A.basis().subset(degree=3) - - # This is related to the following design question: - # If F = (f_i)_{i\in I} is a family, should ``F.subset(degree = 3)`` - # be the elements of F of degree 3 or those whose index is of degree 3? - - def basis(self, d=None): - """ - Returns the basis for (an homogeneous component of) this graded module - - INPUT: - - - `d` -- non negative integer or ``None``, optional (default: ``None``) - - If `d` is None, returns a basis of the module. - Otherwise, returns the basis of the homogeneous component of degree `d`. + def extra_super_categories(self): + r""" + Adds :class:`FilteredModulesWithBasis` to the super categories + of ``self`` since every graded module admits a filtraion. - EXAMPLES:: + EXAMPLES:: - sage: A = GradedModulesWithBasis(ZZ).example() - sage: A.basis(4) - Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions of the integer 4} + sage: GradedModulesWithBasis(ZZ).extra_super_categories() + [Category of filtered modules with basis over Integer Ring] + """ + from sage.categories.filtered_modules_with_basis import FilteredModulesWithBasis + return [FilteredModulesWithBasis(self.base_ring())] - Without arguments, the full basis is returned:: - - sage: A.basis() - Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions} - sage: A.basis() - Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions} - """ - from sage.sets.family import Family - if d is None: - return Family(self._indices, self.monomial) - else: - return Family(self._indices.subset(size=d), self.monomial) + class ParentMethods: + pass class ElementMethods: + pass - def is_homogeneous(self): - """ - Return whether this element is homogeneous. - - EXAMPLES:: - - sage: A = GradedModulesWithBasis(ZZ).example() - sage: x=A(Partition((3,2,1))) - sage: y=A(Partition((4,4,1))) - sage: z=A(Partition((2,2,2))) - sage: (3*x).is_homogeneous() - True - sage: (x - y).is_homogeneous() - False - sage: (x+2*z).is_homogeneous() - True - """ - degree_on_basis = self.parent().degree_on_basis - degree = None - for m in self.support(): - if degree is None: - degree = degree_on_basis(m) - else: - if degree != degree_on_basis(m): - return False - return True - - def degree(self): - """ - The degree of this element in the graded module. - - .. note:: - - This raises an error if the element is not homogeneous. - Another implementation option would be to return the - maximum of the degrees of the homogeneous summands. - - EXAMPLES:: - - sage: A = GradedModulesWithBasis(ZZ).example() - sage: x = A(Partition((3,2,1))) - sage: y = A(Partition((4,4,1))) - sage: z = A(Partition((2,2,2))) - sage: x.degree() - 6 - sage: (x + 2*z).degree() - 6 - sage: (y - x).degree() - Traceback (most recent call last): - ... - ValueError: Element is not homogeneous. - """ - if not self.support(): - raise ValueError("The zero element does not have a well-defined degree.") - if self.is_homogeneous(): - return self.parent().degree_on_basis(self.leading_support()) - else: - raise ValueError("Element is not homogeneous.") - - def homogeneous_component(self, n): - """ - Return the homogeneous component of degree ``n`` of this - element. - - EXAMPLES:: - - sage: A = GradedModulesWithBasis(ZZ).example() - sage: x = A.an_element(); x - 2*P[] + 2*P[1] + 3*P[2] - sage: x.homogeneous_component(-1) - 0 - sage: x.homogeneous_component(0) - 2*P[] - sage: x.homogeneous_component(1) - 2*P[1] - sage: x.homogeneous_component(2) - 3*P[2] - sage: x.homogeneous_component(3) - 0 - - TESTS: - - Check that this really return ``A.zero()`` and not a plain ``0``:: - - sage: x.homogeneous_component(3).parent() is A - True - """ - degree_on_basis = self.parent().degree_on_basis - return self.parent().sum_of_terms((i, c) - for (i, c) in self - if degree_on_basis(i) == n) - - def truncate(self, n): - """ - Return the sum of the homogeneous components of degree ``< n`` of this element - - EXAMPLES:: - - sage: A = GradedModulesWithBasis(ZZ).example() - sage: x = A.an_element(); x - 2*P[] + 2*P[1] + 3*P[2] - sage: x.truncate(0) - 0 - sage: x.truncate(1) - 2*P[] - sage: x.truncate(2) - 2*P[] + 2*P[1] - sage: x.truncate(3) - 2*P[] + 2*P[1] + 3*P[2] - - TESTS: - - Check that this really return ``A.zero()`` and not a plain ``0``:: - - sage: x.truncate(0).parent() is A - True - """ - degree_on_basis = self.parent().degree_on_basis - return self.parent().sum_of_terms((i, c) for (i, c) in self - if degree_on_basis(i) < n) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 8bb11ba4129..e10f241e364 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -325,6 +325,43 @@ def FiniteDimensional(self): """ return self._with_axiom("FiniteDimensional") + @cached_method + def Filtered(self, base_ring=None): + r""" + Return the subcategory of the filtered objects of ``self``. + + INPUT:: + + - ``base_ring`` -- this is ignored + + EXAMPLES:: + + sage: Modules(ZZ).Filtered() + Category of filtered modules over Integer Ring + + sage: Coalgebras(QQ).Filtered() + Join of Category of filtered modules over Rational Field + and Category of coalgebras over Rational Field + + sage: AlgebrasWithBasis(QQ).Filtered() + Category of filtered algebras with basis over Rational Field + + .. TODO:: + + - Explain why this does not commute with :meth:`WithBasis` + - Improve the support for covariant functorial + constructions categories over a base ring so as to + get rid of the ``base_ring`` argument. + + TESTS:: + + sage: Coalgebras(QQ).Graded.__module__ + 'sage.categories.modules' + """ + assert base_ring is None or base_ring is self.base_ring() + from sage.categories.filtered_modules import FilteredModulesCategory + return FilteredModulesCategory.category_of(self) + @cached_method def Graded(self, base_ring=None): r""" @@ -407,6 +444,7 @@ def extra_super_categories(self): else: return [] + Filtered = LazyImport('sage.categories.filtered_modules', 'FilteredModules') Graded = LazyImport('sage.categories.graded_modules', 'GradedModules') WithBasis = LazyImport('sage.categories.modules_with_basis', 'ModulesWithBasis') diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index aac486b3931..93a1ced2c8b 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -179,6 +179,7 @@ def is_abelian(self): return self.base_ring().is_field() FiniteDimensional = LazyImport('sage.categories.finite_dimensional_modules_with_basis', 'FiniteDimensionalModulesWithBasis') + Filtered = LazyImport('sage.categories.filtered_modules_with_basis', 'FilteredModulesWithBasis') Graded = LazyImport('sage.categories.graded_modules_with_basis', 'GradedModulesWithBasis') class ParentMethods: From bb234ec71d1276c6cc14320074b3de6fdc606192 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 20 Oct 2014 08:09:20 -0700 Subject: [PATCH 0019/1872] Use default_super_categories instead of extra_super_categories. --- src/sage/categories/graded_algebras.py | 13 ------ .../categories/graded_algebras_with_basis.py | 13 ------ src/sage/categories/graded_modules.py | 45 +++++++++++++++---- .../categories/graded_modules_with_basis.py | 13 ------ 4 files changed, 37 insertions(+), 47 deletions(-) diff --git a/src/sage/categories/graded_algebras.py b/src/sage/categories/graded_algebras.py index f9e59a137e1..48f47f4068b 100644 --- a/src/sage/categories/graded_algebras.py +++ b/src/sage/categories/graded_algebras.py @@ -27,19 +27,6 @@ class GradedAlgebras(GradedModulesCategory): sage: TestSuite(GradedAlgebras(ZZ)).run() """ - def extra_super_categories(self): - r""" - Adds :class:`FilteredAlgebras` to the super categories of ``self`` - since every graded algebra admits a filtraion. - - EXAMPLES:: - - sage: GradedAlgebras(ZZ).extra_super_categories() - [Category of filtered algebras over Integer Ring] - """ - from sage.categories.filtered_algebras import FilteredAlgebras - return [FilteredAlgebras(self.base_ring())] - class ParentMethods: def graded_algebra(self): """ diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index e45ece1de8e..d0ff3160643 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -28,19 +28,6 @@ class GradedAlgebrasWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ - def extra_super_categories(self): - r""" - Adds :class:`FilteredAlgebras` to the super categories of ``self`` - since every graded algebra admits a filtraion. - - EXAMPLES:: - - sage: GradedAlgebras(ZZ).extra_super_categories() - [Category of filtered algebras over Integer Ring] - """ - from sage.categories.filtered_algebras_with_basis import FilteredAlgebrasWithBasis - return [FilteredAlgebrasWithBasis(self.base_ring())] - class ParentMethods: # This needs to be copied in GradedAlgebras because we need to have # FilteredAlgebrasWithBasis as an extra super category diff --git a/src/sage/categories/graded_modules.py b/src/sage/categories/graded_modules.py index 73d9136783c..02caab1ddcd 100644 --- a/src/sage/categories/graded_modules.py +++ b/src/sage/categories/graded_modules.py @@ -11,6 +11,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_class_attribute +from sage.categories.category import Category from sage.categories.category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory @@ -120,18 +121,46 @@ def _repr_object_names(self): """ return "graded {}".format(self.base_category()._repr_object_names()) - def extra_super_categories(self): + @classmethod + def default_super_categories(cls, category, *args): r""" - Adds :class:`FilteredModules` to the super categories of ``self`` - since every graded module admits a filtraion. + Return the default super categories of ``category.Graded()`` - EXAMPLES:: + Mathematical meaning: every graded category is a filtered category + with the (implicit) filtration of `F_i = \bigoplus_{j \leq i} G_j`. + + INPUT: + + - ``cls`` -- the class ``QuotientsCategory`` + - ``category`` -- a category `Cat` + + OUTPUT: a (join) category + + In practice, this returns ``category.Filtered()``, joined + together with the result of the method + :meth:`RegressiveCovariantConstructionCategory.default_super_categories() ` + (that is the join of ``category`` and ``cat.Filtered()`` for + each ``cat`` in the super categories of ``category``). + + EXAMPLES: + + Consider ``category=Algebras()``, which has ``cat=Modules()`` + as super category. Then, a grading of an algebra `G` + is also a filtration of `G`:: + + sage: Algebras(QQ).Graded().super_categories() + [Category of filtered algebras over Rational Field, + Category of graded modules over Rational Field] + + This resulted from the following call:: - sage: GradedModules(ZZ).extra_super_categories() - [Category of filtered modules over Integer Ring] + sage: sage.categories.graded_modules.GradedModulesCategory.default_super_categories(Algebras(QQ)) + Join of Category of filtered algebras over Rational Field + and Category of graded modules over Rational Field """ - from sage.categories.filtered_modules import FilteredModules - return [FilteredModules(self.base_ring())] + cat = super(GradedModulesCategory, cls).default_super_categories(category, *args) + return Category.join([category.Filtered(), + cat]) class GradedModules(GradedModulesCategory): r""" diff --git a/src/sage/categories/graded_modules_with_basis.py b/src/sage/categories/graded_modules_with_basis.py index 10671e3b307..a1c4a5d5c2e 100644 --- a/src/sage/categories/graded_modules_with_basis.py +++ b/src/sage/categories/graded_modules_with_basis.py @@ -29,19 +29,6 @@ class GradedModulesWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ - def extra_super_categories(self): - r""" - Adds :class:`FilteredModulesWithBasis` to the super categories - of ``self`` since every graded module admits a filtraion. - - EXAMPLES:: - - sage: GradedModulesWithBasis(ZZ).extra_super_categories() - [Category of filtered modules with basis over Integer Ring] - """ - from sage.categories.filtered_modules_with_basis import FilteredModulesWithBasis - return [FilteredModulesWithBasis(self.base_ring())] - class ParentMethods: pass From 5f6337908a43200ef3283e6dd24f4f6c6da66ee9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 29 Oct 2014 15:46:50 -0700 Subject: [PATCH 0020/1872] Addressing Darij's comments. --- src/sage/algebras/associated_graded.py | 42 ++++++++++++++++++- .../examples/filtered_algebras_with_basis.py | 11 ++++- src/sage/categories/filtered_algebras.py | 6 ++- .../filtered_algebras_with_basis.py | 7 +++- src/sage/categories/filtered_modules.py | 9 +++- .../categories/filtered_modules_with_basis.py | 18 +++++--- 6 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 4f9e6e925d2..8df63023460 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -15,6 +15,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod +from copy import copy from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis @@ -37,6 +38,35 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): INPUT: - ``A`` -- a filtered algebra + + EXAMPLES: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: x,y,z = map(lambda s: grA.algebra_generators()[s], ['x','y','z']) + sage: x + bar(U['x']) + sage: y * x + z + bar(U['x']*U['y']) + bar(U['z']) + sage: A(y) * A(x) + A(z) + U['x']*U['y'] + + We note that the conversion between ``A`` and ``grA`` is the canonical + ``QQ``-module isomorphism:: + + sage: grA(A.an_element()) + bar(U['x']^2*U['y']^2*U['z']^3) + sage: elt = A.an_element() + A.algebra_generators()['x'] + 2 + sage: grelt = grA(elt); grelt + bar(U['x']^2*U['y']^2*U['z']^3) + bar(U['x']) + 2*bar(1) + sage: A(grelt) == elt + True + + .. TODO:: + + The algebra ``A`` must currently be an instance of (a subclass of) + :class:`CombinatorialFreeModule`. This should work with any algebra + with a basis. """ def __init__(self, A, category=None): """ @@ -51,16 +81,21 @@ def __init__(self, A, category=None): if A not in AlgebrasWithBasis(A.base_ring()).Filtered(): raise ValueError("the base algebra must be filtered") self._A = A + if category is None: category = A.category().Graded() - from copy import copy opts = copy(A.print_options()) if not opts['prefix'] and not opts['bracket']: opts['bracket'] = '(' opts['prefix'] = opts['prefix'] + 'bar' + CombinatorialFreeModule.__init__(self, A.base_ring(), A.indices(), category=category, **opts) + # Setup the conversion back + phi = self.module_morphism(lambda x: A.monomial(x), codomain=A) + self._A.register_conversion(phi) + def _repr_(self): """ Return a string representation of ``self``. @@ -92,6 +127,11 @@ def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. + .. NOTE:: + + This constructs an element from the filtered algebra ``A`` + by the canonical module isomorphism. + EXAMPLES:: sage: A = Algebras(QQ).WithBasis().Filtered().example() diff --git a/src/sage/categories/examples/filtered_algebras_with_basis.py b/src/sage/categories/examples/filtered_algebras_with_basis.py index 0b864fe3aa4..df4e7bcfa95 100644 --- a/src/sage/categories/examples/filtered_algebras_with_basis.py +++ b/src/sage/categories/examples/filtered_algebras_with_basis.py @@ -14,7 +14,7 @@ from sage.sets.family import Family from sage.misc.misc import powerset -class IntersectionFilteredAlgebra(CombinatorialFreeModule): +class PBWBasisCrossProduct(CombinatorialFreeModule): r""" This class illustrates an implementation of a filtered algebra with basis: the universal enveloping algebra of the Lie algebra @@ -32,6 +32,9 @@ class IntersectionFilteredAlgebra(CombinatorialFreeModule): - A set of algebra generators -- the set of generators `x,y,z`. + - The index of the unit element -- the unit element in the monoid + of monomials. + - A product -- this is given on basis elements by using :meth:`product_on_basis`. @@ -115,6 +118,9 @@ def degree_on_basis(self, m): """ return len(m) + # TODO: This is a general procedure of expanding multiplication defined + # on generators to arbitrary monomials and could likely be factored out + # and be useful elsewhere. def product_on_basis(self, s, t): """ Return the product of two basis elements indexed by ``s`` and ``t``. @@ -142,6 +148,7 @@ def product_on_basis(self, s, t): if len(t) == 1: if len(s) == 1: + # Do the product of the generators a = s.leading_support() b = t.leading_support() cur = self.monomial(s*t) @@ -165,5 +172,5 @@ def product_on_basis(self, s, t): cur = cur * self.monomial(self._indices.gen(a)) return cur -Example = IntersectionFilteredAlgebra +Example = PBWBasisCrossProduct diff --git a/src/sage/categories/filtered_algebras.py b/src/sage/categories/filtered_algebras.py index f03b2fb5877..ccb050a7ae9 100644 --- a/src/sage/categories/filtered_algebras.py +++ b/src/sage/categories/filtered_algebras.py @@ -12,9 +12,13 @@ from sage.categories.filtered_modules import FilteredModulesCategory class FilteredAlgebras(FilteredModulesCategory): - """ + r""" The category of filtered algebras. + An algebra `A` over `R` is *filtered* if `A` is a filtered `R`-module + such that `F_i \cdot F_j \subseteq F_{i+j}` for all `i, j` in the + filteration group. + EXAMPLES:: sage: Algebras(ZZ).Filtered() diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index d9d3fe61a96..6a1ea5ef1e7 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -46,7 +46,10 @@ def graded_algebra(self): class ElementMethods: def is_homogeneous(self): """ - Return whether this element is homogeneous. + Return whether ``self`` is homogeneous. + + An element `x` is homogeneous if `x \in F_i \setminus F_{i-1}` + for some `i`. EXAMPLES:: @@ -71,7 +74,7 @@ def is_homogeneous(self): def homogeneous_degree(self): """ - The degree of this element. + The degree of ``self``. .. NOTE:: diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index bb7e4998e20..655a1b1dc53 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -1,5 +1,7 @@ r""" Filtered modules + +We require all `F_i \setminus F_{i-1}` to be modules for all `i`. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -123,9 +125,14 @@ def _repr_object_names(self): return "filtered {}".format(self.base_category()._repr_object_names()) class FilteredModules(FilteredModulesCategory): - """ + r""" The category of filtered modules. + A `R`-module `M` is *filtered* if there exists a `R`-module + isomorphism `A = \bigoplus_{i \in I} F_i`, where `I` is a + totally ordered additive abelian group, such that + `F_{i-1} \subseteq F_i` for all `i \in I`. + EXAMPLES:: sage: Modules(ZZ).Filtered() diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 8db42471566..0be47d2c722 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -44,10 +44,12 @@ def basis(self, d=None): INPUT: - - `d` -- non negative integer or ``None``, optional (default: ``None``) + - ``d`` -- (optional, default ``None``) non negative integer + or ``None`` - If `d` is None, returns a basis of the module. - Otherwise, returns the basis of the homogeneous component of degree `d`. + If ``d`` is ``None``, returns a basis of the module. + Otherwise, returns the basis of the homogeneous component + of degree ``d`` (i.e., of ``F_d \setminus F_{d-1}``). EXAMPLES:: @@ -74,6 +76,9 @@ def is_homogeneous(self): """ Return whether ``self`` is homogeneous. + An element `x` is homogeneous if `x \in F_i \setminus F_{i-1}` + for some `i`. + EXAMPLES:: sage: A = ModulesWithBasis(ZZ).Filtered().example() @@ -99,7 +104,10 @@ def is_homogeneous(self): def degree(self): """ - The degree of this element in the filtered module. + The degree of ``self`` in the filtered module. + + The degree of an element `x` is the value `i` such that + `x \in F_i \setminus F_{i-1}`. .. NOTE:: @@ -164,7 +172,7 @@ def homogeneous_component(self, n): def truncate(self, n): """ Return the sum of the homogeneous components of degree - strictly less than ``n`` of this element. + strictly less than ``n`` of ``self``. EXAMPLES:: From 2aec8bdaeba3c34478807342b5659b8e8ceca2f4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 29 Oct 2014 15:50:49 -0700 Subject: [PATCH 0021/1872] Fixing some typos. --- src/sage/categories/filtered_algebras.py | 2 +- src/sage/categories/filtered_modules.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/filtered_algebras.py b/src/sage/categories/filtered_algebras.py index ccb050a7ae9..7a91de609ba 100644 --- a/src/sage/categories/filtered_algebras.py +++ b/src/sage/categories/filtered_algebras.py @@ -17,7 +17,7 @@ class FilteredAlgebras(FilteredModulesCategory): An algebra `A` over `R` is *filtered* if `A` is a filtered `R`-module such that `F_i \cdot F_j \subseteq F_{i+j}` for all `i, j` in the - filteration group. + filtration group. EXAMPLES:: diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index 655a1b1dc53..caf248febea 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -129,7 +129,7 @@ class FilteredModules(FilteredModulesCategory): The category of filtered modules. A `R`-module `M` is *filtered* if there exists a `R`-module - isomorphism `A = \bigoplus_{i \in I} F_i`, where `I` is a + isomorphism `A = \bigcup_{i \in I} F_i`, where `I` is a totally ordered additive abelian group, such that `F_{i-1} \subseteq F_i` for all `i \in I`. From 592ba1176ae7a337c40792c0da3d439831ea3dc0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 31 Oct 2014 14:57:59 -0700 Subject: [PATCH 0022/1872] Some minor doc tweaks. --- src/sage/categories/filtered_algebras_with_basis.py | 2 +- src/sage/categories/filtered_modules.py | 4 ++-- src/sage/categories/filtered_modules_with_basis.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 6a1ea5ef1e7..f5dbdef0406 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -45,7 +45,7 @@ def graded_algebra(self): class ElementMethods: def is_homogeneous(self): - """ + r""" Return whether ``self`` is homogeneous. An element `x` is homogeneous if `x \in F_i \setminus F_{i-1}` diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index caf248febea..02762f2d3c8 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -1,7 +1,7 @@ r""" Filtered modules -We require all `F_i \setminus F_{i-1}` to be modules for all `i`. +We require all `F_i / F_{i-1}` to be modules for all `i`. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -168,7 +168,7 @@ def extra_super_categories(self): Get rid of this workaround once there is a more systematic approach for the alias ``Modules(QQ)`` -> ``VectorSpaces(QQ)``. - Probably the later should be a category with axiom, and + Probably the latter should be a category with axiom, and covariant constructions should play well with axioms. """ from sage.categories.modules import Modules diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 0be47d2c722..21f02012141 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -39,7 +39,7 @@ class ParentMethods: # be the elements of F of degree 3 or those whose index is of degree 3? def basis(self, d=None): - """ + r""" Return the basis for (an homogeneous component of) ``self``. INPUT: @@ -49,7 +49,7 @@ def basis(self, d=None): If ``d`` is ``None``, returns a basis of the module. Otherwise, returns the basis of the homogeneous component - of degree ``d`` (i.e., of ``F_d \setminus F_{d-1}``). + of degree ``d`` (i.e., of `F_d \setminus F_{d-1}`). EXAMPLES:: @@ -73,7 +73,7 @@ def basis(self, d=None): class ElementMethods: def is_homogeneous(self): - """ + r""" Return whether ``self`` is homogeneous. An element `x` is homogeneous if `x \in F_i \setminus F_{i-1}` @@ -103,7 +103,7 @@ def is_homogeneous(self): return True def degree(self): - """ + r""" The degree of ``self`` in the filtered module. The degree of an element `x` is the value `i` such that From 60beb17df13f5399d9ce13f21984e903f77d3ea9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 31 Oct 2014 15:00:09 -0700 Subject: [PATCH 0023/1872] More explicit documentation. --- src/sage/categories/filtered_modules.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index 02762f2d3c8..caa2b271ea5 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -1,7 +1,8 @@ r""" Filtered modules -We require all `F_i / F_{i-1}` to be modules for all `i`. +Consider a filtered module `M = \cup_{i \in I} F_i`. We require +all `F_i / F_{i-1}` to be modules for all `i`. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw From 9d567ea2aaa030f51dbf2e966c8584bd2d8489ee Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 9 Nov 2014 11:26:12 -0800 Subject: [PATCH 0024/1872] clarifying doc, or maybe obscuring it -- needs to be proofread --- src/sage/algebras/associated_graded.py | 76 +++++++++++++++--- .../examples/filtered_algebras_with_basis.py | 5 +- .../examples/filtered_modules_with_basis.py | 2 +- src/sage/categories/filtered_algebras.py | 19 ++++- .../filtered_algebras_with_basis.py | 15 ++-- src/sage/categories/filtered_modules.py | 44 +++++++---- .../categories/filtered_modules_with_basis.py | 77 ++++++++++++++++--- 7 files changed, 188 insertions(+), 50 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 8df63023460..66f5692db52 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -31,9 +31,57 @@ from sage.combinat.free_module import CombinatorialFreeModule class AssociatedGradedAlgebra(CombinatorialFreeModule): - """ - The associated graded algebra `\mathrm{gr} A` corresponding to - a filtered algebra `A`. + r""" + The associated graded algebra `\operatorname{gr} A` + of a filtered-algebra-with-basis `A`. + + Let `A` be a filtered algebra with basis over a + commutative ring `R`. Let `(F_0, F_1, F_2, \ldots)` be + its filtration, let `(b_i)_{i \in I}` be its basis, + and consider the partition of the set `I` into subsets + `I_0, I_1, I_2, \ldots` which is part of the data of + a filtered algebra with basis. The *associated graded + algebra* (or, for short, just *graded algebra*) of + `A` is a graded algebra with basis defined as follows: + + We know (see :class:`FilteredModulesWithBasis`) that + `A` (being a filtered `R`-module with basis) canonically + becomes a graded `R`-module with basis. (Its `n`-th + graded component, for every `n \in \NN`, is the + `R`-submodule of `A` spanned by `(b_i)_{i \in I_n}`.) + We define a multiplication `*` on this graded `R`-module + `A` (not to be mistaken for the multiplication of the + original algebra `A`) by requiring that + + .. MATH:: + + b_i * b_j = \left( \text{the } + (n+m)\text{-th homogeneous component of } + b_i b_j \right) + \qquad \text{for all } n, m \in \NN \text{ and } + i \in I_n \text{ and } j \in I_m + + (or, equivalently, + + .. MATH:: + + u * v = \left( \text{the } + (n+m)\text{-th homogeneous component of } + uv \right) + \qquad \text{for all } n, m \in \NN + \text{ and any homogeneous elements } u + \text{ and } v \text{ of respective degrees } + n \text{ and } m + + ). + + Thus, `(A, *)` is a graded `R`-algebra with basis. + This is called the associated graded algebra of `A`, + and denoted by `\operatorname{gr} A`. + + Notice that the multiplication `*` of this associated + graded algebra depends not only on the filtered algebra + `A`, but also on its basis. INPUT: @@ -43,6 +91,8 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): sage: A = Algebras(QQ).WithBasis().Filtered().example() sage: grA = A.graded_algebra() + sage: grA.category() + Category of graded algebras with basis over Rational Field sage: x,y,z = map(lambda s: grA.algebra_generators()[s], ['x','y','z']) sage: x bar(U['x']) @@ -51,8 +101,10 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): sage: A(y) * A(x) + A(z) U['x']*U['y'] - We note that the conversion between ``A`` and ``grA`` is the canonical - ``QQ``-module isomorphism:: + We note that the conversion between ``A`` and ``grA`` is + the canonical ``QQ``-module isomorphism stemming from the + fact that the underlying ``QQ``-modules of ``A`` and + ``grA`` are the same:: sage: grA(A.an_element()) bar(U['x']^2*U['y']^2*U['z']^3) @@ -104,7 +156,7 @@ def _repr_(self): sage: A = Algebras(QQ).WithBasis().Filtered().example() sage: A.graded_algebra() - Graded Algebra of An example of a filtered module with basis: + Graded Algebra of An example of a filtered algebra with basis: the universal enveloping algebra of Lie algebra of RR^3 with cross product over Rational Field """ @@ -118,19 +170,19 @@ def _latex_(self): sage: A = Algebras(QQ).WithBasis().Filtered().example() sage: latex(A.graded_algebra()) - \mathrm{gr}\; ... + \operatorname{gr} ... """ from sage.misc.latex import latex - return "\\mathrm{gr}\; " + latex(self._A) + return "\\operatorname{gr} " + latex(self._A) def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. - .. NOTE:: - - This constructs an element from the filtered algebra ``A`` - by the canonical module isomorphism. + This constructs an element from the filtered algebra `A` + by the canonical module isomorphism (stemming from the + fact that `A` and the associated graded algebra `A` + have the same underlying `R`-module). EXAMPLES:: diff --git a/src/sage/categories/examples/filtered_algebras_with_basis.py b/src/sage/categories/examples/filtered_algebras_with_basis.py index df4e7bcfa95..1f9bd7bd9bb 100644 --- a/src/sage/categories/examples/filtered_algebras_with_basis.py +++ b/src/sage/categories/examples/filtered_algebras_with_basis.py @@ -12,7 +12,6 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid from sage.sets.family import Family -from sage.misc.misc import powerset class PBWBasisCrossProduct(CombinatorialFreeModule): r""" @@ -63,11 +62,11 @@ def _repr_(self): EXAMPLES:: sage: AlgebrasWithBasis(QQ).Filtered().example() - An example of a filtered module with basis: + An example of a filtered algebra with basis: the universal enveloping algebra of Lie algebra of RR^3 with cross product over Rational Field """ - return "An example of a filtered module with basis: the universal enveloping algebra of Lie algebra of RR^3 with cross product over {}".format(self.base_ring()) + return "An example of a filtered algebra with basis: the universal enveloping algebra of Lie algebra of RR^3 with cross product over {}".format(self.base_ring()) def algebra_generators(self): """ diff --git a/src/sage/categories/examples/filtered_modules_with_basis.py b/src/sage/categories/examples/filtered_modules_with_basis.py index 4af2f427e45..d2c8b5d4ef5 100644 --- a/src/sage/categories/examples/filtered_modules_with_basis.py +++ b/src/sage/categories/examples/filtered_modules_with_basis.py @@ -16,7 +16,7 @@ class FilteredPartitionModule(CombinatorialFreeModule): r""" This class illustrates an implementation of a filtered module - with basis: the free module over partitions. + with basis: the free module on the set of all partitions. INPUT: diff --git a/src/sage/categories/filtered_algebras.py b/src/sage/categories/filtered_algebras.py index 7a91de609ba..3252c215b69 100644 --- a/src/sage/categories/filtered_algebras.py +++ b/src/sage/categories/filtered_algebras.py @@ -15,9 +15,11 @@ class FilteredAlgebras(FilteredModulesCategory): r""" The category of filtered algebras. - An algebra `A` over `R` is *filtered* if `A` is a filtered `R`-module - such that `F_i \cdot F_j \subseteq F_{i+j}` for all `i, j` in the - filtration group. + An algebra `A` over a commutative ring `R` is *filtered* if + `A` is endowed with a structure of a filtered `R`-module + (whose underlying `R`-module structure is identical with + that of the `R`-algebra `A`) such that + `F_i \cdot F_j \subseteq F_{i+j}` for all `i, j \in \NN`. EXAMPLES:: @@ -37,11 +39,20 @@ def graded_algebra(self): """ Return the associated graded algebra to ``self``. + .. TODO:: + + Should this really be here and not in the + ``_with_basis`` class? The notion of an associated + graded algebra of a filtered algebra (without + basis) exists, but are we ever going to get it into + Sage, and, more importantly: will it cooperate with + the with-basis version? + EXAMPLES:: sage: A = AlgebrasWithBasis(ZZ).Filtered().example() sage: A.graded_algebra() - Graded Algebra of An example of a filtered module with basis: + Graded Algebra of An example of a filtered algebra with basis: the universal enveloping algebra of Lie algebra of RR^3 with cross product over Integer Ring """ diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index f5dbdef0406..481c6245818 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -1,5 +1,12 @@ r""" Filtered algebras with basis + +A filtered algebra with basis over a commutative ring `R` +is a filtered algebra over `R` endowed with the structure +of a filtered module with basis (with the same underlying +filtered-module structure). See +:class:`FilteredAlgebras` and +:class:`FilteredModulesWithBasis` for these two notions. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -36,7 +43,7 @@ def graded_algebra(self): sage: A = AlgebrasWithBasis(ZZ).Filtered().example() sage: A.graded_algebra() - Graded Algebra of An example of a filtered module with basis: + Graded Algebra of An example of a filtered algebra with basis: the universal enveloping algebra of Lie algebra of RR^3 with cross product over Integer Ring """ @@ -48,9 +55,6 @@ def is_homogeneous(self): r""" Return whether ``self`` is homogeneous. - An element `x` is homogeneous if `x \in F_i \setminus F_{i-1}` - for some `i`. - EXAMPLES:: sage: S = NonCommutativeSymmetricFunctions(QQ).S() @@ -74,7 +78,8 @@ def is_homogeneous(self): def homogeneous_degree(self): """ - The degree of ``self``. + The degree of a nonzero homogeneous element ``self`` in the + filtered module. .. NOTE:: diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index caa2b271ea5..2a1c2d126e4 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -1,8 +1,15 @@ r""" Filtered modules -Consider a filtered module `M = \cup_{i \in I} F_i`. We require -all `F_i / F_{i-1}` to be modules for all `i`. +A *filtered module* over a commutative ring `R` is an +`R`-module `M` equipped with a sequence `(F_0, F_1, F_2, \ldots)` +of `R`-submodules satisfying +`F_0 \subseteq F_1 \subseteq F_2 \subseteq \cdots` and +`M = \cup_{i \geq 0} F_i`. This sequence is called the +*filtration* of the given module `M`. + +(More general notions of filtered modules exist, but are not +currently implemented in Sage.) """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -70,13 +77,13 @@ def _base_category_class(cls): :meth:`__classget__` method which would get in the way upon attribute access:: - sage: F = FilteredAlgebrasWithBasis - sage: F._foo = F._base_category_class[0] - sage: F._foo - Traceback (most recent call last): - ... - AssertionError: base category class for <...AlgebrasWithBasis'> mismatch; - expected <...Algebras'>, got <...FilteredAlgebrasWithBasis'> + sage: F = FilteredAlgebrasWithBasis + sage: F._foo = F._base_category_class[0] + sage: F._foo + Traceback (most recent call last): + ... + AssertionError: base category class for <...AlgebrasWithBasis'> mismatch; + expected <...Algebras'>, got <...FilteredAlgebrasWithBasis'> """ module_name = cls.__module__.replace("filtered_","") import sys @@ -129,10 +136,15 @@ class FilteredModules(FilteredModulesCategory): r""" The category of filtered modules. - A `R`-module `M` is *filtered* if there exists a `R`-module - isomorphism `A = \bigcup_{i \in I} F_i`, where `I` is a - totally ordered additive abelian group, such that - `F_{i-1} \subseteq F_i` for all `i \in I`. + A *filtered module* over a commutative ring `R` is an + `R`-module `M` equipped with a sequence `(F_0, F_1, F_2, \ldots)` + of `R`-submodules satisfying + `F_0 \subseteq F_1 \subseteq F_2 \subseteq \cdots` and + `M = \cup_{i \geq 0} F_i`. This sequence is called the + *filtration* of the given module `M`. + + (More general notions of filtered modules exist, but are not + currently implemented in Sage.) EXAMPLES:: @@ -148,7 +160,7 @@ class FilteredModules(FilteredModulesCategory): def extra_super_categories(self): r""" - Adds :class:`VectorSpaces` to the super categories of ``self`` if + Add :class:`VectorSpaces` to the super categories of ``self`` if the base ring is a field. EXAMPLES:: @@ -187,6 +199,10 @@ def Connected(self): r""" Return the full subcategory of the connected objects of ``self``. + A filtered `R`-module `M` with filtration + `(F_0, F_1, F_2, \ldots)` is said to be + *connected* if `F_0` is isomorphic to `R`. + EXAMPLES:: sage: Modules(ZZ).Filtered().Connected() diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 21f02012141..ce331e13355 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -1,5 +1,37 @@ r""" Filtered modules with basis + +A *filtered module with basis* over a commutative ring `R` +means (for the purpose of this code) a filtered `R`-module +`M` with filtration `(F_0, F_1, F_2, \ldots)` endowed with a +basis `(b_i)_{i \in I}` of `M` and a partition of the set +`I` into subsets `I_0, I_1, I_2, \ldots` (which can be +empty) such that for every `n \in \NN`, the subfamily +`(b_i)_{i \in I_0 \cup I_1 \cup \cdots \cup I_n}` is a basis +of the `R`-submodule `F_n`. + +For every `n \in \NN`, the `R`-submodule of `M` spanned by +`(b_i)_{i \in I_n}` is called the `*n*-th graded component* +of the filtered-module-with-basis `M`; the elements of +this submodule are referred to as *homogeneous elements of +degree `n`*. The `R`-module `M` is the direct sum of its +`n`-th graded components over all `n \in \NN`, and thus +becomes a graded `R`-module with basis. Conversely, any +graded `R`-module with basis canonically becomes a filtered +`R`-module with basis (by defining `F_n` as the direct sum +of the `0`-th, `1`-st, ..., `n`-th graded components, and +`I_n` as the indexing set of the basis of the `n`-th graded +component). Hence, the notion of a filtered `R`-module with +basis is equivalent to the notion of a graded `R`-module +with basis. However, the *category* of filtered `R`-modules +with basis is not the category of graded `R`-modules with +basis. Indeed, the *morphisms* of filtered `R`-modules with +basis are defined to be morphisms of `R`-modules which send +each `F_n` of the domain to the corresponding `F_n` of the +target; in contrast, the morphisms of graded `R`-modules +with basis must preserve each homogeneous component. Also, +the notion of a filtered algebra with basis differs from +that of a graded algebra with basis. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -14,6 +46,21 @@ class FilteredModulesWithBasis(FilteredModulesCategory): """ The category of filtered modules with a distinguished basis. + A *filtered module with basis* over a commutative ring `R` + means (for the purpose of this code) a filtered `R`-module + `M` with filtration `(F_0, F_1, F_2, \ldots)` endowed with a + basis `(b_i)_{i \in I}` of `M` and a partition of the set + `I` into subsets `I_0, I_1, I_2, \ldots` (which can be + empty) such that for every `n \in \NN`, the subfamily + `(b_i)_{i \in I_0 \cup I_1 \cup \cdots \cup I_n}` is a basis + of the `R`-submodule `F_n`. + + For every `n \in \NN`, the `R`-submodule of `M` spanned by + `(b_i)_{i \in I_n}` is called the `*n*-th graded component* + of the filtered-module-with-basis `M`; the elements of + this submodule are referred to as *homogeneous elements of + degree `n`*. + EXAMPLES:: sage: C = ModulesWithBasis(ZZ).Filtered(); C @@ -40,16 +87,19 @@ class ParentMethods: def basis(self, d=None): r""" - Return the basis for (an homogeneous component of) ``self``. + Return the basis for (the ``d``-th homogeneous component + of) ``self``. INPUT: - - ``d`` -- (optional, default ``None``) non negative integer + - ``d`` -- (optional, default ``None``) nonnegative integer or ``None`` If ``d`` is ``None``, returns a basis of the module. Otherwise, returns the basis of the homogeneous component - of degree ``d`` (i.e., of `F_d \setminus F_{d-1}`). + of degree ``d`` (i.e., the subfamily of the basis of the + whole module which consists only of the basis vectors + lying in `F_d \setminus F_{d-1}`). EXAMPLES:: @@ -76,9 +126,6 @@ def is_homogeneous(self): r""" Return whether ``self`` is homogeneous. - An element `x` is homogeneous if `x \in F_i \setminus F_{i-1}` - for some `i`. - EXAMPLES:: sage: A = ModulesWithBasis(ZZ).Filtered().example() @@ -104,10 +151,8 @@ def is_homogeneous(self): def degree(self): r""" - The degree of ``self`` in the filtered module. - - The degree of an element `x` is the value `i` such that - `x \in F_i \setminus F_{i-1}`. + The degree of a nonzero homogeneous element ``self`` in the + filtered module. .. NOTE:: @@ -141,6 +186,13 @@ def homogeneous_component(self, n): Return the homogeneous component of degree ``n`` of this element. + Let `m` be an element of a filtered `R`-module `M` with + basis. Then, `m` can be uniquely written in the form + `m = m_0 + m_1 + m_2 + \ldots`, where each `m_i` is a + homogeneous element of degree `i`. For `n \in \NN`, we + define the homogeneous component of degree `n` of the + element `m` to be `m_n`. + EXAMPLES:: sage: A = ModulesWithBasis(ZZ).Filtered().example() @@ -159,7 +211,7 @@ def homogeneous_component(self, n): TESTS: - Check that this really return ``A.zero()`` and not a plain ``0``:: + Check that this really returns ``A.zero()`` and not a plain ``0``:: sage: x.homogeneous_component(3).parent() is A True @@ -174,6 +226,9 @@ def truncate(self, n): Return the sum of the homogeneous components of degree strictly less than ``n`` of ``self``. + See :meth:`homogeneous_component` for the notion of a + homogeneous component. + EXAMPLES:: sage: A = ModulesWithBasis(ZZ).Filtered().example() From f1aa77ee1f5c71e03b490d760f22b6810e94501e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 9 Nov 2014 11:58:42 -0800 Subject: [PATCH 0025/1872] Initial implementation of colored permutations. --- src/sage/combinat/all.py | 1 + src/sage/combinat/colored_permutations.py | 384 ++++++++++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 src/sage/combinat/colored_permutations.py diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 1d0aa066dda..13eb4f7747d 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -33,6 +33,7 @@ #Permutations from permutation import Permutation, Permutations, Arrangements, PermutationOptions, CyclicPermutations, CyclicPermutationsOfPartition from affine_permutation import AffinePermutationGroup +from colored_permutations import ColoredPermutations, SignedPermutations from derangements import Derangements #RSK diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py new file mode 100644 index 00000000000..0a767ebe7b6 --- /dev/null +++ b/src/sage/combinat/colored_permutations.py @@ -0,0 +1,384 @@ +r""" +Colored Permutations +""" +from sage.categories.groups import Groups +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.structure.element import Element +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.misc.cachefunc import cached_method + +from sage.combinat.permutation import Permutations +from sage.combinat.cartesian_product import CartesianProduct +from sage.matrix.constructor import diagonal_matrix +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.number_field.number_field import CyclotomicField + +class ColoredPermutation(Element): + """ + A colored permutation. + """ + def __init__(self, parent, colors, perm): + """ + Initialize ``self``. + """ + self._colors = tuple(colors) + self._perm = perm + Element.__init__(self, parent=parent) + + def _repr_(self): + """ + Return a string representation of ``self``. + """ + return repr([list(self._colors), self._perm]) + + def _mul_(self, other): + """ + Multiply ``self`` and ``other``. + """ + colors = tuple(self._colors[i] + other._colors[val-1] + for i,val in enumerate(~self._perm)) + return self.__class__(self.parent(), colors, self._perm * other._perm) + + def __eq__(self, other): + """ + Check equality. + """ + if not isinstance(other, ColoredPermutation): + return False + return (self.parent() is other.parent() + and self._colors == other._colors + and self._perm == other._perm) + + def __ne__(self, other): + """ + Check inequality. + """ + return not self.__eq__(other) + + def __iter__(self): + """ + Iterate over ``self``. + """ + for i,p in enumerate(self._perm): + yield (self._colors[i], p) + + def one_line_form(self): + """ + Return the one line form of ``self``. + """ + return list(self) + + def colors(self): + """ + Return the colors of ``self``. + """ + return list(self._colors) + + def permutation(self): + """ + Return the permutation of ``self``. + """ + return self._perm + + def to_matrix(self): + """ + Return a matrix of ``self``. + """ + Cp = CyclotomicField(self.parent()._m) + g = Cp.gen() + return diagonal_matrix(Cp, [g**i for i in self._colors]) * self._perm.to_matrix() + +class ColoredPermutations(Parent, UniqueRepresentation): + r""" + The group of `m`-colored permutations on `\{1, 2, \ldots, n\}`. + + Let `S_n` be the symmetric group on `n` letters and `C_m` be the cyclic + group of order `m`. The `m`-colored permutation group on `n` letters + is given by `P_n^m = C_m \wr S_n`. This is also the complex reflection + group `G(m, 1, n)`. + + We define our multiplication by + + .. MATH:: + + ((s_1, \ldots s_n), \sigma) \cdot ((t_1, \ldots, t_n), \tau) + = ((s_1 t_{\sigma^{-1}(1)}, \ldots, s_n t_{\sigma^{-1}(n)}), + \sigma \tau). + + REFERENCES: + + - :wikipedia:`Generalized_symmetric_group` + - :wikipedia:`Complex_reflection_group` + """ + def __init__(self, m, n): + """ + Initialize ``self``. + + EXAMPLES:: + """ + self._m = m + self._n = n + self._C = IntegerModRing(self._m) + self._P = Permutations(self._n) + Parent.__init__(self, category=(Groups(), FiniteEnumeratedSets())) + + def _repr_(self): + """ + Return a string representation of ``self``. + """ + return "{}-colored permutations of size {}".format(self._m, self._n) + + def one(self): + """ + Return the identity element of ``self``. + """ + return self.element_class(self, [self._C.zero()]*self._n, self._P.identity()) + + @cached_method + def gens(self): + """ + Return the generators of ``self``. + """ + zero = [self._C.zero()]*self._n + g = [] + for i in range(self._n-1): + p = range(1, self._n+1) + p[i] = i+2 + p[i+1] = i+1 + g.append( self.element_class(self, zero, self._P(p)) ) + zero[-1] = self._C.one() + g.append( self.element_class(self, zero, self._P.identity()) ) + return tuple(g) + + def matrix_group(self): + """ + Return the matrix group corresponding to ``self``. + """ + from sage.groups.matrix_gps.finitely_generated import MatrixGroup + return MatrixGroup([g.to_matrix() for g in self.gens()]) + + def _element_constructor_(self, x): + """ + Construct an element of ``self`` from ``x``. + """ + if isinstance(x, list): + if isinstance(x[0], tuple): + c = [] + p = [] + for k in x: + if len(k) != 2: + raise ValueError("input must be pairs (color, element)") + c.append( self._C(k[0]) ) + p.append(k[1]) + return self.element_class(self, c, self._P(p)) + + if len(x) != 2: + raise ValueError("input must be a pair of a list of colors and a permutation") + return self.element_class(self, map(self._C, x[0]), self._P(x[1])) + + def __iter__(self): + """ + Iterate over ``self``. + """ + C = CartesianProduct(*[self._C]*self._n) + for p in self._P: + for c in C: + yield self.element_class(self, c, p) + + def cardinality(self): + """ + Return the cardinality of ``self``. + """ + return self._m**self._n * self._P.cardinality() + + def rank(self): + """ + Return the rank of ``self``. + + The rank of a complex reflection group is equal to the dimension + of the complex vector space the group acts on. + """ + if self._m == 1: + return self._n - 1 + return self._n + + def degrees(self): + """ + Return the degrees of ``self``. + + The degrees of a complex reflection group are the degrees of + the fundamental invariants of the ring of polynomial invariants. + + If `m = 1`, then we are in the special case of the symmetric group + and the degrees are `(2, 3, \ldots, n, n+1)`. Otherwise the degrees + are `(m, 2m, \ldots, nm)`. + + EXAMPLES:: + + sage: CP = ColoredPermutations(4, 3) + sage: CP.degrees() + [4, 8, 12] + sage: S = ColoredPermutations(1, 3) + sage: S.degrees() + [2, 3] + + We now check that the product of the degrees is equal to the + cardinality of ``self``:: + + sage: prod(CP.degrees()) == CP.cardinality() + True + sage: prod(S.degrees()) == S.cardinality() + True + """ + if self._m == 1: # Special case for the usual symmetric group + return range(2, self._n+1) + return [self._m * i for i in range(1, self._n+1)] + + def codegrees(self): + """ + Return the codegrees of ``self``. + + Let `G` be a complex reflection group. The codegrees + `d_1^* \leq d_2^* \leq \cdots \leq d_{\ell}^*` of `G` can be + defined in terms of the fixed point polynomial: + + f_G(q) = \prod_{i=1}^{\ell} (q - d_i^* - 1). + + If `m = 1`, then we are in the special case of the symmetric group + and the codegrees are `(n-2, n-3, \ldots 1, 0)`. Otherwise the degrees + are `((n-1)m, (n-2)m, \ldots, m, 0)`. + """ + if self._m == 1: # Special case for the usual symmetric group + return list(reversed(range(self._n-1))) + return [self._m * i for i in reversed(range(self._n))] + + def number_reflection_hyperplanes(self): + """ + Return the number of reflection hyperplanes of ``self``. + + The number of reflection hyperplanes of a complex reflection + group is equal to the sume of the codegrees plus the rank. + """ + return sum(self.codegrees()) + self.rank() + + def fixed_point_polynomial(self, q): + r""" + The fixed point polynomial of ``self``. + + The fixed point polynomial `f_G` of a complex reflection group `G` is + counting the dimesions fixed points subspaces: + + .. MATH:: + + f_G(q) = \sum_{w \in W} q^{\dim V^w}. + + Furthermore, let `d_1, d_2, \ldots, d_{\ell}` be the degrees of `G`, + then the fixed point polynomial is given by + + .. MATH:: + + f_G(q) = \prod_{i=1}^{\ell} (q + d_i - 1). + """ + return prod(q + d - 1 for d in self.degrees()) + + def is_well_generated(self): + """ + Return if ``self`` is a well-generated complex reflection group. + + A complex reflection group `G` is well-generated if it is + generated by `\ell` reflections. Equivalently, `G` is well-generated + if `d_i + d_i^* = d_{\ell}` for all `1 \leq i \leq \ell` + """ + deg = self.degrees() + dstar = self.codegrees() + return all(deg[-1] == d + dstar[i] for i,d in enumerate(deg)) + + Element = ColoredPermutation + +##################################################################### +## Signed permutations + +class SignedPermutation(ColoredPermutation): + """ + A signed permutation. + """ + def _mul_(self, other): + """ + Multiply ``self`` and ``other``. + """ + colors = tuple(self._colors[i] * other._colors[val-1] + for i,val in enumerate(~self._perm)) + return self.__class__(self.parent(), colors, self._perm * other._perm) + + def __iter__(self): + """ + Iterate over ``self``. + """ + for i,p in enumerate(self._perm): + yield self._colors[i] * p + + def to_matrix(self): + """ + Return a matrix of ``self``. + """ + return identity_matrix(self._colors) * self._perm.to_matrix() + +class SignedPermutations(ColoredPermutations): + r""" + Group of signed permutations. + + The group of signed permutations is also known as the hyperoctahedral + group and the 2-colored permutation group. Thus it can be constructed + as the wreath product `S_2 \wr S_n`. + + REFERENCES: + + - :wikipedia:`Hyperoctahedral_group` + """ + def __init__(self, n): + """ + Initialize ``self``. + """ + ColoredPermutations.__init__(self, 2, n) + + def _repr_(self): + """ + Return a string representation of ``self``. + """ + return "Signed permutations of {}".format(self._n) + + def __iter__(self): + """ + Iterate over ``self``. + """ + C = CartesianProduct(*[[-1,1]]*self._n) + for p in self._P: + for c in C: + yield self.element_class(self, c, p) + + Element = SignedPermutation + +class EvenSignedPermutations(SignedPermutations): + """ + Group of even signed permutations. + """ + def _repr_(self): + """ + Return a string representation of ``self``. + """ + return "Even signed permtuations of {}".format(self._n) + + def __iter__(self): + """ + Iterate over ``self``. + """ + for s in SignedPermutations.__iter__(self): + total = 0 + for pm in s._colors: + if pm == -1: + total += 1 + + if total % 2 == 0: + yield s + From a4bc65cc8e1915f9e80c55d07509cf8be569f2ae Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 15 Nov 2014 00:44:22 -0800 Subject: [PATCH 0026/1872] Fix failing doctests. --- src/sage/categories/category.py | 2 +- src/sage/categories/category_with_axiom.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 8fd57986f9e..8dbf0f045c3 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -2625,7 +2625,7 @@ def category_graph(categories = None): Graphics object consisting of 20 graphics primitives sage: sage.categories.category.category_graph().plot() - Graphics object consisting of 312 graphics primitives + Graphics object consisting of 324 graphics primitives """ from sage import graphs if categories is None: diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 70c091a25ba..000f96bd8bd 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -2249,10 +2249,9 @@ def _repr_object_names_static(category, axioms): base_category = base_category._with_axiom(axiom) if axiom == "WithBasis": result = result.replace(" over ", " with basis over ", 1) - elif axiom == "Connected": - if "graded " in result: - result = result.replace("graded ", "graded connected ", 1) - elif "filtered " in result: + elif axiom == "Connected" and "graded " in result: + result = result.replace("graded ", "graded connected ", 1) + elif axiom == "Connected" and "filtered " in result: result = result.replace("filtered ", "filtered connected ", 1) elif axiom == "Endset" and "homsets" in result: # Without the space at the end to handle Homsets().Endset() From a15a170e64ec10b4c57215029c9239ee9805bc07 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 15 Nov 2014 18:08:39 -0800 Subject: [PATCH 0027/1872] Made CliffordAlgebra into a filtered algebra. --- src/sage/algebras/clifford_algebra.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 53403eb8425..af6ce5a280f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -18,7 +18,6 @@ from copy import copy from sage.categories.algebras_with_basis import AlgebrasWithBasis -from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis from sage.categories.modules_with_basis import ModuleMorphismByLinearity from sage.categories.poor_man_map import PoorManMap @@ -536,7 +535,7 @@ def __init__(self, Q, names, category=None): self._quadratic_form = Q R = Q.base_ring() if category is None: - category = GradedAlgebrasWithBasis(R) + category = AlgebrasWithBasis(R).Filtered() indices = SubsetsSorted(range(Q.dim())) CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) @@ -1049,8 +1048,8 @@ def lift_module_morphism(self, m, names=None): f = lambda x: self.prod(self._from_dict( {(j,): m[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - return Cl.module_morphism(on_basis=f, codomain=self, - category=GradedAlgebrasWithBasis(self.base_ring())) + cat = AlgebrasWithBasis(self.base_ring()).Filtered() + return Cl.module_morphism(on_basis=f, codomain=self, category=cat) def lift_isometry(self, m, names=None): r""" @@ -1114,8 +1113,9 @@ def lift_isometry(self, m, names=None): f = lambda x: Cl.prod(Cl._from_dict( {(j,): m[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - return self.module_morphism(on_basis=f, codomain=Cl, - category=GradedAlgebrasWithBasis(self.base_ring())) + + cat = AlgebrasWithBasis(self.base_ring()).Filtered() + return self.module_morphism(on_basis=f, codomain=Cl, category=cat) # This is a general method for finite dimensional algebras with bases # and should be moved to the corresponding category once there is @@ -1562,7 +1562,7 @@ def lift_morphism(self, phi, names=None): f = lambda x: E.prod(E._from_dict( {(j,): phi[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - return self.module_morphism(on_basis=f, codomain=E, category=GradedAlgebrasWithBasis(R)) + return self.module_morphism(on_basis=f, codomain=E, category=GradedHopfAlgebrasWithBasis(R)) def volume_form(self): """ From 41fbe5c6b1f8be6619f68529fa847ef9bf6c9c33 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 16 Nov 2014 11:08:18 -0800 Subject: [PATCH 0028/1872] Made Weyl algebra into a filtered algebra. --- src/sage/algebras/weyl_algebra.py | 40 ++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index a85c0c91629..a2a1050a00e 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -436,6 +436,23 @@ def list(self): return sorted(self.__monomials.items(), key=lambda x: (-sum(x[0][1]), x[0][1], -sum(x[0][0]), x[0][0]) ) + def support(self): + """ + Return the support of ``self``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ) + sage: dx,dy,dz = W.differentials() + sage: elt = dy - (3*x - z)*dx + 1 + sage: elt.support() + [((0, 0, 0), (0, 1, 0)), + ((1, 0, 0), (1, 0, 0)), + ((0, 0, 0), (0, 0, 0)), + ((0, 0, 1), (1, 0, 0))] + """ + return self.__monomials.keys() + # This is essentially copied from # sage.combinat.free_module.CombinatorialFreeModuleElement def __div__(self, x, self_on_left=False): @@ -567,9 +584,8 @@ def __init__(self, R, names=None): names = names + tuple('d' + n for n in names) if len(names) != self._n * 2: raise ValueError("variable names cannot differ by a leading 'd'") - # TODO: Make this into a filtered algebra under the natural grading of - # x_i and dx_i have degree 1 - Algebra.__init__(self, R, names, category=AlgebrasWithBasis(R).NoZeroDivisors()) + cat = AlgebrasWithBasis(R).NoZeroDivisors().Filtered() + Algebra.__init__(self, R, names, category=cat) def _repr_(self): r""" @@ -663,6 +679,24 @@ def _coerce_map_from_(self, R): and self.base_ring().has_coerce_map_from(R.base_ring()) ) return super(DifferentialWeylAlgebra, self)._coerce_map_from_(R) + def degree_on_basis(self, i): + """ + Return the degree of the basis element indexed by ``i``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ) + sage: W.degree_on_basis( ((1, 3, 2), (0, 1, 3)) ) + 10 + + sage: W. = DifferentialWeylAlgebra(QQ) + sage: dx,dy,dz = W.differentials() + sage: elt = y*dy - (3*x - z)*dx + sage: elt.degree() + 2 + """ + return sum(i[0]) + sum(i[1]) + def polynomial_ring(self): """ Return the associated polynomial ring of ``self``. From a11c501518c6785db1a99c78c04a1e38c2daff67 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 16 Nov 2014 11:09:23 -0800 Subject: [PATCH 0029/1872] Documentation changes and added to docbuild. --- src/doc/en/reference/algebras/index.rst | 2 + src/doc/en/reference/categories/index.rst | 4 + src/sage/algebras/associated_graded.py | 73 +++++++--------- src/sage/categories/filtered_algebras.py | 18 ++-- .../filtered_algebras_with_basis.py | 10 ++- src/sage/categories/filtered_modules.py | 42 +++++---- .../categories/filtered_modules_with_basis.py | 85 +++++++++---------- 7 files changed, 118 insertions(+), 116 deletions(-) diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 36ed741b169..16be0dd29a3 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -4,6 +4,8 @@ Algebras .. toctree:: :maxdepth: 2 + sage/algebras/associated_graded + sage/algebras/clifford_algebra sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index ef69b30335e..421e0f30aaf 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -75,6 +75,10 @@ Categories sage/categories/enumerated_sets sage/categories/euclidean_domains sage/categories/fields + sage/categories/filtered_algebras + sage/categories/filtered_algebras_with_basis + sage/categories/filtered_modules + sage/categories/filtered_modules_with_basis sage/categories/finite_coxeter_groups sage/categories/finite_crystals sage/categories/finite_dimensional_algebras_with_basis diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 66f5692db52..21cb4108144 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -1,5 +1,5 @@ r""" -Associated Graded Algebras +Associated Graded Algebras To Filtered Algebras AUTHORS: @@ -33,61 +33,41 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): r""" The associated graded algebra `\operatorname{gr} A` - of a filtered-algebra-with-basis `A`. + of a filtered algebra with basis `A`. Let `A` be a filtered algebra with basis over a - commutative ring `R`. Let `(F_0, F_1, F_2, \ldots)` be - its filtration, let `(b_i)_{i \in I}` be its basis, - and consider the partition of the set `I` into subsets - `I_0, I_1, I_2, \ldots` which is part of the data of - a filtered algebra with basis. The *associated graded - algebra* (or, for short, just *graded algebra*) of - `A` is a graded algebra with basis defined as follows: - - We know (see :class:`FilteredModulesWithBasis`) that - `A` (being a filtered `R`-module with basis) canonically - becomes a graded `R`-module with basis. (Its `n`-th - graded component, for every `n \in \NN`, is the - `R`-submodule of `A` spanned by `(b_i)_{i \in I_n}`.) - We define a multiplication `*` on this graded `R`-module - `A` (not to be mistaken for the multiplication of the - original algebra `A`) by requiring that + commutative ring `R`. Let `(F_i)_{i \in I}` be + its filtration, let `(b_x)_{x \in X}` be its basis, + and consider the partition of the set `X = \bigsqcup_{i \in I} X_i`, + which is part of the data of a filtered algebra with basis. The + *associated graded algebra* (or, for short, just *graded algebra*) + of `A` is a graded algebra with basis defined as follows. + + We know (see + :class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis`) + that `A` (being a filtered `R`-module with basis) canonically + becomes a graded `R`-module with basis. (Its `i`-th + graded component, for every `i \in I`, is the + `R`-submodule of `A` spanned by `(b_x)_{x \in X_i}`.) + Let `u \in F_i` and `v \in F_j` and suppose + `u v = \sum_{k \leq i + j} m_k` where `m_k` is in the `k`-th + homogeneous component. We define a multiplication `*` on this + graded `R`-module `A` (not to be mistaken for the multiplication + of the original algebra `A`) by requiring that .. MATH:: - b_i * b_j = \left( \text{the } - (n+m)\text{-th homogeneous component of } - b_i b_j \right) - \qquad \text{for all } n, m \in \NN \text{ and } - i \in I_n \text{ and } j \in I_m - - (or, equivalently, - - .. MATH:: - - u * v = \left( \text{the } - (n+m)\text{-th homogeneous component of } - uv \right) - \qquad \text{for all } n, m \in \NN - \text{ and any homogeneous elements } u - \text{ and } v \text{ of respective degrees } - n \text{ and } m - - ). + u * v = m_{i+j}. Thus, `(A, *)` is a graded `R`-algebra with basis. This is called the associated graded algebra of `A`, and denoted by `\operatorname{gr} A`. - Notice that the multiplication `*` of this associated - graded algebra depends not only on the filtered algebra - `A`, but also on its basis. - INPUT: - ``A`` -- a filtered algebra - EXAMPLES: + EXAMPLES:: sage: A = Algebras(QQ).WithBasis().Filtered().example() sage: grA = A.graded_algebra() @@ -119,6 +99,15 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): The algebra ``A`` must currently be an instance of (a subclass of) :class:`CombinatorialFreeModule`. This should work with any algebra with a basis. + + .. TODO:: + + Implement a version of for filtered algebras without a + distinguished basis. + + REFERENCES: + + - :wikipedia:`Filtered_algebra#Associated_graded_algebra` """ def __init__(self, A, category=None): """ diff --git a/src/sage/categories/filtered_algebras.py b/src/sage/categories/filtered_algebras.py index 3252c215b69..536ef505a1a 100644 --- a/src/sage/categories/filtered_algebras.py +++ b/src/sage/categories/filtered_algebras.py @@ -18,8 +18,10 @@ class FilteredAlgebras(FilteredModulesCategory): An algebra `A` over a commutative ring `R` is *filtered* if `A` is endowed with a structure of a filtered `R`-module (whose underlying `R`-module structure is identical with - that of the `R`-algebra `A`) such that - `F_i \cdot F_j \subseteq F_{i+j}` for all `i, j \in \NN`. + that of the `R`-algebra `A`) such that the indexing set `I` + (typically `I = \NN`) is also an additive abelian monoid, + `F_0 = \{ 0 \}`, and `F_i \cdot F_j \subseteq F_{i+j}` + for all `i, j \in I`. EXAMPLES:: @@ -32,6 +34,10 @@ class FilteredAlgebras(FilteredModulesCategory): TESTS:: sage: TestSuite(Algebras(ZZ).Filtered()).run() + + REFERENCES: + + - :wikipedia:`Filtered_algebra` """ class ParentMethods: @abstract_method(optional=True) @@ -41,12 +47,8 @@ def graded_algebra(self): .. TODO:: - Should this really be here and not in the - ``_with_basis`` class? The notion of an associated - graded algebra of a filtered algebra (without - basis) exists, but are we ever going to get it into - Sage, and, more importantly: will it cooperate with - the with-basis version? + Implement a version of the associated graded algebra + without a distinguished basis. EXAMPLES:: diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 481c6245818..c56fb3878e7 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -1,12 +1,13 @@ r""" -Filtered algebras with basis +Filtered Algebras With Basis A filtered algebra with basis over a commutative ring `R` is a filtered algebra over `R` endowed with the structure of a filtered module with basis (with the same underlying filtered-module structure). See -:class:`FilteredAlgebras` and -:class:`FilteredModulesWithBasis` for these two notions. +:class:`~sage.categories.filtered_algebras.FilteredAlgebras` and +:class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis` +for these two notions. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -19,7 +20,8 @@ class FilteredAlgebrasWithBasis(FilteredModulesCategory): """ - The category of filtered algebras with a distinguished basis. + The category of filtered algebras with a distinguished + homogeneous basis. EXAMPLES:: diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index 2a1c2d126e4..8b4bba1bf2e 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -1,15 +1,20 @@ r""" -Filtered modules +Filtered Modules -A *filtered module* over a commutative ring `R` is an -`R`-module `M` equipped with a sequence `(F_0, F_1, F_2, \ldots)` -of `R`-submodules satisfying -`F_0 \subseteq F_1 \subseteq F_2 \subseteq \cdots` and -`M = \cup_{i \geq 0} F_i`. This sequence is called the -*filtration* of the given module `M`. +A *filtered module* over a commutative ring `R` with a totally ordered +indexing set `I` (typically `I = \NN`) is an `R`-module `M` equipped +with a sequence `(F_i)_{i \in I}` of `R`-submodules satisfying +`F_i \subseteq F_j` if `i \leq j` for all `i,j \in I` and +`M = \bigcup_{i \in I} F_i`. This sequence is called a *filtration* +of the given module `M`. -(More general notions of filtered modules exist, but are not -currently implemented in Sage.) +.. TODO:: + + Implement a notion for decreasing filtrations: where `F_j \subseteq F_i`. + +.. TODO:: + + Implement filtrations for all concrete categories. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -136,15 +141,12 @@ class FilteredModules(FilteredModulesCategory): r""" The category of filtered modules. - A *filtered module* over a commutative ring `R` is an - `R`-module `M` equipped with a sequence `(F_0, F_1, F_2, \ldots)` - of `R`-submodules satisfying - `F_0 \subseteq F_1 \subseteq F_2 \subseteq \cdots` and - `M = \cup_{i \geq 0} F_i`. This sequence is called the - *filtration* of the given module `M`. - - (More general notions of filtered modules exist, but are not - currently implemented in Sage.) + A *filtered module* over a commutative ring `R` with a totally ordered + indexing set `I` (typically `I = \NN`) is an `R`-module `M` equipped + with a sequence `(F_i)_{i \in I}` of `R`-submodules satisfying + `F_i \subseteq F_j` if `i \leq j` for all `i, j \in I` and + `M = \bigcup_{i \in I} F_i`. This sequence is called a *filtration* + of the given module `M`. EXAMPLES:: @@ -156,6 +158,10 @@ class FilteredModules(FilteredModulesCategory): TESTS:: sage: TestSuite(Modules(ZZ).Filtered()).run() + + REFERENCES: + + - :wikipedia:`Filtration_(mathematics)` """ def extra_super_categories(self): diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index ce331e13355..5dcf2f34e42 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -1,37 +1,19 @@ r""" -Filtered modules with basis +Filtered Modules With Basis A *filtered module with basis* over a commutative ring `R` means (for the purpose of this code) a filtered `R`-module -`M` with filtration `(F_0, F_1, F_2, \ldots)` endowed with a -basis `(b_i)_{i \in I}` of `M` and a partition of the set -`I` into subsets `I_0, I_1, I_2, \ldots` (which can be -empty) such that for every `n \in \NN`, the subfamily -`(b_i)_{i \in I_0 \cup I_1 \cup \cdots \cup I_n}` is a basis -of the `R`-submodule `F_n`. - -For every `n \in \NN`, the `R`-submodule of `M` spanned by -`(b_i)_{i \in I_n}` is called the `*n*-th graded component* -of the filtered-module-with-basis `M`; the elements of +`M` with filtration `(F_i)_{i \in I}` (typically `I = \NN`) +endowed with a basis `(b_j)_{j \in J}` of `M` and a partition of +the set `J = \bigsqcup_{i \in I} J_i` (which can be empty) such +that for every `n \in I`, the subfamily `(b_j)_{j \in U_n}`, where +`U_n = \bigcup_{i \leq n} J_i`, is a basis of the `R`-submodule `F_n`. + +For every `i \in I`, the `R`-submodule of `M` spanned by +`(b_j)_{j \in J_i}` is called the `i`-*th graded component* +of the filtered module with basis `M`; the elements of this submodule are referred to as *homogeneous elements of -degree `n`*. The `R`-module `M` is the direct sum of its -`n`-th graded components over all `n \in \NN`, and thus -becomes a graded `R`-module with basis. Conversely, any -graded `R`-module with basis canonically becomes a filtered -`R`-module with basis (by defining `F_n` as the direct sum -of the `0`-th, `1`-st, ..., `n`-th graded components, and -`I_n` as the indexing set of the basis of the `n`-th graded -component). Hence, the notion of a filtered `R`-module with -basis is equivalent to the notion of a graded `R`-module -with basis. However, the *category* of filtered `R`-modules -with basis is not the category of graded `R`-modules with -basis. Indeed, the *morphisms* of filtered `R`-modules with -basis are defined to be morphisms of `R`-modules which send -each `F_n` of the domain to the corresponding `F_n` of the -target; in contrast, the morphisms of graded `R`-modules -with basis must preserve each homogeneous component. Also, -the notion of a filtered algebra with basis differs from -that of a graded algebra with basis. +degree* `i`. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -43,23 +25,38 @@ from sage.categories.filtered_modules import FilteredModulesCategory class FilteredModulesWithBasis(FilteredModulesCategory): - """ + r""" The category of filtered modules with a distinguished basis. A *filtered module with basis* over a commutative ring `R` means (for the purpose of this code) a filtered `R`-module - `M` with filtration `(F_0, F_1, F_2, \ldots)` endowed with a - basis `(b_i)_{i \in I}` of `M` and a partition of the set - `I` into subsets `I_0, I_1, I_2, \ldots` (which can be - empty) such that for every `n \in \NN`, the subfamily - `(b_i)_{i \in I_0 \cup I_1 \cup \cdots \cup I_n}` is a basis - of the `R`-submodule `F_n`. - - For every `n \in \NN`, the `R`-submodule of `M` spanned by - `(b_i)_{i \in I_n}` is called the `*n*-th graded component* - of the filtered-module-with-basis `M`; the elements of - this submodule are referred to as *homogeneous elements of - degree `n`*. + `M` with filtration `(F_i)_{i \in I}` (typically `I = \NN`) + endowed with a basis `(b_j)_{j \in J}` of `M` and a partition of + the set `J = \bigsqcup_{i \in I} J_i` (which can be empty) such + that for every `n \in I`, the subfamily `(b_j)_{j \in U_n}`, where + `U_n = \bigcup_{i \leq n} J_i`, is a basis of the `R`-submodule `F_n`. + + For every `i \in I`, the `R`-submodule of `M` spanned by + `(b_j)_{j \in J_i}` is called the `i`-*th graded component* of the + filtered module with basis `M`; the elements of this submodule are + referred to as *homogeneous elements of degree* `i`. The `R`-module + `M` is the direct sum of its `i`-th graded components over + all `i \in I`, and thus becomes a graded `R`-module with basis. + Conversely, any graded `R`-module with basis canonically becomes a filtered + `R`-module with basis (by defining `F_n = \bigoplus_{i \leq n} G_i` + where `G_i` is the `i`-th graded component and `J_i` as the indexing + set of the basis of the `i`-th graded component). Hence, the notion + of a filtered `R`-module with basis is equivalent to the notion of + a graded `R`-module with basis. + + However, the *category* of filtered `R`-modules with basis is not + the category of graded `R`-modules with basis. Indeed, the *morphisms* + of filtered `R`-modules with basis are defined to be morphisms of + `R`-modules which send each `F_n` of the domain to the corresponding + `F_n` of the target; in contrast, the morphisms of graded `R`-modules + with basis must preserve each homogeneous component. Also, + the notion of a filtered algebra with basis differs from + that of a graded algebra with basis. EXAMPLES:: @@ -188,8 +185,8 @@ def homogeneous_component(self, n): Let `m` be an element of a filtered `R`-module `M` with basis. Then, `m` can be uniquely written in the form - `m = m_0 + m_1 + m_2 + \ldots`, where each `m_i` is a - homogeneous element of degree `i`. For `n \in \NN`, we + `m = \sum_{i \in I} m_i`, where each `m_i` is a + homogeneous element of degree `i`. For `n \in I`, we define the homogeneous component of degree `n` of the element `m` to be `m_n`. From 45aca1bb8e9492c4b076532a89c9334eec4dc1d2 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 16 Nov 2014 15:57:52 -0800 Subject: [PATCH 0030/1872] Changed some doc from conversation with Darij. --- src/sage/algebras/associated_graded.py | 62 ++++++++++++------- .../categories/filtered_modules_with_basis.py | 2 +- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 21cb4108144..305c695abc1 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -35,33 +35,51 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): The associated graded algebra `\operatorname{gr} A` of a filtered algebra with basis `A`. - Let `A` be a filtered algebra with basis over a - commutative ring `R`. Let `(F_i)_{i \in I}` be - its filtration, let `(b_x)_{x \in X}` be its basis, - and consider the partition of the set `X = \bigsqcup_{i \in I} X_i`, - which is part of the data of a filtered algebra with basis. The - *associated graded algebra* (or, for short, just *graded algebra*) - of `A` is a graded algebra with basis defined as follows. + Let `A` be a filtered algebra with basis over a commutative + ring `R`. Let `(F_i)_{i \in I}` be the filtration of `A`, and + define - We know (see - :class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis`) - that `A` (being a filtered `R`-module with basis) canonically - becomes a graded `R`-module with basis. (Its `i`-th - graded component, for every `i \in I`, is the - `R`-submodule of `A` spanned by `(b_x)_{x \in X_i}`.) - Let `u \in F_i` and `v \in F_j` and suppose - `u v = \sum_{k \leq i + j} m_k` where `m_k` is in the `k`-th - homogeneous component. We define a multiplication `*` on this - graded `R`-module `A` (not to be mistaken for the multiplication - of the original algebra `A`) by requiring that + .. MATH:: + + G_i = F_i / \sum_{j < i} F_j + + and then .. MATH:: - u * v = m_{i+j}. + \operatorname{gr} A = \bigoplus_{i \in I} G_i. + + There are canonical projections `p_i : F_i \to G_i` for + every `i \in I`. Moreover `\operatorname{gr} A` is naturally a + graded module with `G_i` being the `i`-th graded component. + + Let `u \in G_i` and `v \in G_j` with lifts `u' \in F_i` + and `v' \in F_j` respectively. Therefore we define + multiplication `*` on `\operatorname{gr} A` (not to be mistaken + for the multiplication of the original algebra `A`) by - Thus, `(A, *)` is a graded `R`-algebra with basis. - This is called the associated graded algebra of `A`, - and denoted by `\operatorname{gr} A`. + .. MATH:: + + u * v = p_{i+j}(u' v'). + + The *associated graded algebra* (or, for short, just *graded algebra*) + of `A` is the graded algebra `\operatorname{gr} A`. + + In particular, let `(b_x)_{x \in X}` be the basis of `A`, + and consider the partition of the set `X = \bigsqcup_{i \in I} X_i`, + which is part of the data of a filtered algebra with basis. + We know (see + :class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis`) + that `A` (being a filtered `R`-module with basis) is canonically + isomorphic to `\operatorname{gr} A` as an `R`-module. Therefore + the `k`-th graded component `G_k` can be identified with + the span of `(b_x)_{x \in X_k}`, or equivalently the + `k`-th homogeneous component of `A`. Suppose + that `u' v' = \sum_{k \leq i+j} m_k` where `m_k \in G_k` (which + has been identified with the `k`-th homogeneous component of `A`). + Then `u * v = m_{i+j}`. We also note that the choice of + identification of `G_k` with the `k`-th homogeneous component + depends on the given basis. INPUT: diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 5dcf2f34e42..efe84a1416b 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -96,7 +96,7 @@ def basis(self, d=None): Otherwise, returns the basis of the homogeneous component of degree ``d`` (i.e., the subfamily of the basis of the whole module which consists only of the basis vectors - lying in `F_d \setminus F_{d-1}`). + lying in `F_d \setminus \bigcup_{i Date: Sun, 16 Nov 2014 20:52:48 -0800 Subject: [PATCH 0031/1872] fixes to associated_graded.py --- src/doc/en/reference/algebras/index.rst | 2 + src/sage/algebras/associated_graded.py | 156 ++++++++++++++++++++---- 2 files changed, 133 insertions(+), 25 deletions(-) diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 192c6e39eb8..af0254920c4 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -33,6 +33,8 @@ Algebras sage/algebras/hall_algebra + sage/algebras/quatalg/quaternion_algebra + sage/algebras/shuffle_algebra sage/algebras/steenrod/steenrod_algebra diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 305c695abc1..36f62a1081c 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -36,14 +36,14 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): of a filtered algebra with basis `A`. Let `A` be a filtered algebra with basis over a commutative - ring `R`. Let `(F_i)_{i \in I}` be the filtration of `A`, and - define + ring `R`. Let `(F_i)_{i \in I}` be the filtration of `A`, with + `I` being a totally ordered set. Define .. MATH:: G_i = F_i / \sum_{j < i} F_j - and then + for every `i \in I`, and then .. MATH:: @@ -51,26 +51,29 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): There are canonical projections `p_i : F_i \to G_i` for every `i \in I`. Moreover `\operatorname{gr} A` is naturally a - graded module with `G_i` being the `i`-th graded component. + graded `R`-module with `G_i` being the `i`-th graded component. - Let `u \in G_i` and `v \in G_j` with lifts `u' \in F_i` - and `v' \in F_j` respectively. Therefore we define + Let `u \in G_i` and `v \in G_j`, and let `u' \in F_i` and + `v' \in F_j` be lifts of `u` and `v`, respectively (so that + `u = p_i(u')` and `v = p_j(v')`). Then, we define a multiplication `*` on `\operatorname{gr} A` (not to be mistaken for the multiplication of the original algebra `A`) by .. MATH:: - u * v = p_{i+j}(u' v'). + u * v = p_{i+j} (u' v'). - The *associated graded algebra* (or, for short, just *graded algebra*) - of `A` is the graded algebra `\operatorname{gr} A`. + The *associated graded algebra* (or, for short, just + *graded algebra*) of `A` is the graded algebra + `\operatorname{gr} A` (endowed with this multiplication). In particular, let `(b_x)_{x \in X}` be the basis of `A`, - and consider the partition of the set `X = \bigsqcup_{i \in I} X_i`, - which is part of the data of a filtered algebra with basis. - We know (see + and consider the partition `X = \bigsqcup_{i \in I} X_i` of + the set `X`, which is part of the data of a filtered + algebra with basis. We know (see :class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis`) that `A` (being a filtered `R`-module with basis) is canonically + (when the basis is considered to be part of the data) isomorphic to `\operatorname{gr} A` as an `R`-module. Therefore the `k`-th graded component `G_k` can be identified with the span of `(b_x)_{x \in X_k}`, or equivalently the @@ -79,11 +82,20 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): has been identified with the `k`-th homogeneous component of `A`). Then `u * v = m_{i+j}`. We also note that the choice of identification of `G_k` with the `k`-th homogeneous component - depends on the given basis. + of `A` depends on the given basis. + + In this class, the `R`-module isomorphism from `A` to + `\operatorname{gr} A` is implemented as + :meth:`to_graded_conversion` and also as the default + conversion from `A` to `\operatorname{gr} A`. Its + inverse map is implemented as + :meth:`from_graded_conversion`. The projection + `p_i : F_i \to G_i` is implemented as + :meth:`projection` ``(i)``. INPUT: - - ``A`` -- a filtered algebra + - ``A`` -- a filtered algebra with basis EXAMPLES:: @@ -102,7 +114,7 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): We note that the conversion between ``A`` and ``grA`` is the canonical ``QQ``-module isomorphism stemming from the fact that the underlying ``QQ``-modules of ``A`` and - ``grA`` are the same:: + ``grA`` are isomorphic:: sage: grA(A.an_element()) bar(U['x']^2*U['y']^2*U['z']^3) @@ -120,8 +132,8 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): .. TODO:: - Implement a version of for filtered algebras without a - distinguished basis. + Implement a version of associated graded algebra for + filtered algebras without a distinguished basis. REFERENCES: @@ -138,9 +150,12 @@ def __init__(self, A, category=None): sage: TestSuite(grA).run(elements=[prod(grA.algebra_generators())]) """ if A not in AlgebrasWithBasis(A.base_ring()).Filtered(): - raise ValueError("the base algebra must be filtered") + raise ValueError("the base algebra must be filtered and with basis") self._A = A + base_ring = A.base_ring() + self.base_one = base_ring.one() + if category is None: category = A.category().Graded() opts = copy(A.print_options()) @@ -148,11 +163,11 @@ def __init__(self, A, category=None): opts['bracket'] = '(' opts['prefix'] = opts['prefix'] + 'bar' - CombinatorialFreeModule.__init__(self, A.base_ring(), A.indices(), + CombinatorialFreeModule.__init__(self, base_ring, A.indices(), category=category, **opts) # Setup the conversion back - phi = self.module_morphism(lambda x: A.monomial(x), codomain=A) + phi = self.module_morphism(diagonal=lambda x: self.base_one, codomain=A) self._A.register_conversion(phi) def _repr_(self): @@ -183,13 +198,15 @@ def _latex_(self): return "\\operatorname{gr} " + latex(self._A) def _element_constructor_(self, x): - """ + r""" Construct an element of ``self`` from ``x``. - This constructs an element from the filtered algebra `A` - by the canonical module isomorphism (stemming from the - fact that `A` and the associated graded algebra `A` - have the same underlying `R`-module). + If ``self`` `= \operatorname{gr} A` for a filtered algebra + `A`, and if ``x`` is an element of `A`, then this returns + the image of `x` under the canonical `R`-module + isomorphism `A \to \operatorname{gr} A`. (In this case, + this is equivalent to calling + ``self.to_graded_conversion()(x)``.) EXAMPLES:: @@ -205,6 +222,90 @@ def _element_constructor_(self, x): return self._from_dict(dict(x)) return super(AssociatedGradedAlgebra, self)._element_constructor_(x) + # Maps + + def to_graded_conversion(self): + r""" + Return the canonical `R`-module isomorphism + `A \to \operatorname{gr} A` induced by the basis of `A`. + + This is an isomorphism of `R`-modules, not of algebras. See + the class-wide documentation :class:`AssociatedGradedAlgebra`. + + .. SEEALSO:: + + :meth:`from_graded_conversion`. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p + U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 + sage: grA.to_graded_conversion()(p) + bar(U['x']^2*U['y']^2*U['z']^3) + bar(U['x']) + 2*bar(1) + """ + return self._A.module_morphism(diagonal=lambda x: self.base_one, + codomain=self) + + def from_graded_conversion(self): + r""" + Return the inverse of the canonical `R`-module isomorphism + `A \to \operatorname{gr} A` induced by the basis of `A`. + + This is an isomorphism of `R`-modules, not of algebras. See + the class-wide documentation :class:`AssociatedGradedAlgebra`. + + .. SEEALSO:: + + :meth:`to_graded_conversion`. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p + U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 + sage: q = grA.to_graded_conversion()(p) + sage: grA.from_graded_conversion()(q) == p + True + """ + return self.module_morphism(diagonal=lambda x: self.base_one, + codomain=self._A) + + def projection(self, i): + r""" + Return the `i`-th projection `p_i : F_i \to G_i` (in the + notations of the class-wide documentation + :class:`AssociatedGradedAlgebra`). + + This method actually does not return the map `p_i` itself, + but an extension of `p_i` to the whole `R`-module `A`. + This extension is the composition of the `R`-module + isomorphism `A \to \operatorname{gr} A` with the canonical + projection of the graded `R`-module `\operatorname{gr} A` + onto its `i`-th graded component `G_i`. The codomain of + this map is `\operatorname{gr} A`, although its actual + image is `G_i`. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p + U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 + sage: grA.projection(7)(p) + bar(U['x']^2*U['y']^2*U['z']^3) + sage: grA.projection(8)(p) + 0 + """ + base_zero = self.base_ring().zero() + return self._A.module_morphism(diagonal=lambda x: + (self.base_one if + self._A.degree_on_basis(x) == i + else base_zero), + codomain=self) + def gen(self, *args, **kwds): """ Return a generator of ``self``. @@ -227,6 +328,9 @@ def algebra_generators(self): """ Return the algebra generators of ``self``. + This assumes that the algebra generators of `A` provided by + its ``algebra_generators`` method are homogeneous. + EXAMPLES:: sage: A = Algebras(QQ).WithBasis().Filtered().example() @@ -242,6 +346,8 @@ def one_basis(self): """ Return the basis index of the element `1`. + This assumes that the unity `1` of `A` belongs to `F_0`. + EXAMPLES:: sage: A = Algebras(QQ).WithBasis().Filtered().example() From b2bc6f59a7daf29f2e55fe0db40a241c06066b6e Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 16 Nov 2014 20:57:07 -0800 Subject: [PATCH 0032/1872] self.base_one removed --- src/sage/algebras/associated_graded.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 36f62a1081c..d372e301048 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -154,7 +154,7 @@ def __init__(self, A, category=None): self._A = A base_ring = A.base_ring() - self.base_one = base_ring.one() + base_one = base_ring.one() if category is None: category = A.category().Graded() @@ -167,7 +167,7 @@ def __init__(self, A, category=None): category=category, **opts) # Setup the conversion back - phi = self.module_morphism(diagonal=lambda x: self.base_one, codomain=A) + phi = self.module_morphism(diagonal=lambda x: base_one, codomain=A) self._A.register_conversion(phi) def _repr_(self): @@ -245,7 +245,8 @@ def to_graded_conversion(self): sage: grA.to_graded_conversion()(p) bar(U['x']^2*U['y']^2*U['z']^3) + bar(U['x']) + 2*bar(1) """ - return self._A.module_morphism(diagonal=lambda x: self.base_one, + base_one = self.base_ring().one() + return self._A.module_morphism(diagonal=lambda x: base_one, codomain=self) def from_graded_conversion(self): @@ -270,7 +271,8 @@ def from_graded_conversion(self): sage: grA.from_graded_conversion()(q) == p True """ - return self.module_morphism(diagonal=lambda x: self.base_one, + base_one = self.base_ring().one() + return self.module_morphism(diagonal=lambda x: base_one, codomain=self._A) def projection(self, i): @@ -300,8 +302,9 @@ def projection(self, i): 0 """ base_zero = self.base_ring().zero() + base_one = self.base_ring().one() return self._A.module_morphism(diagonal=lambda x: - (self.base_one if + (base_one if self._A.degree_on_basis(x) == i else base_zero), codomain=self) From b32aaf289e6a152a8938a87a6865d510d818bfb6 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 16 Nov 2014 22:31:31 -0800 Subject: [PATCH 0033/1872] further review changes --- src/sage/algebras/associated_graded.py | 46 +++++++++---------- src/sage/categories/category_with_axiom.py | 2 +- .../examples/filtered_algebras_with_basis.py | 9 ++-- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index d372e301048..1fddb176f6b 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -14,20 +14,10 @@ #***************************************************************************** from sage.misc.cachefunc import cached_method -from sage.misc.misc_c import prod from copy import copy from sage.categories.algebras_with_basis import AlgebrasWithBasis -from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis -from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis -from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis -from sage.rings.all import ZZ -from sage.rings.infinity import infinity -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.sets.family import Family -from sage.sets.positive_integers import PositiveIntegers -from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid -from sage.combinat.cartesian_product import CartesianProduct from sage.combinat.free_module import CombinatorialFreeModule class AssociatedGradedAlgebra(CombinatorialFreeModule): @@ -35,9 +25,9 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): The associated graded algebra `\operatorname{gr} A` of a filtered algebra with basis `A`. - Let `A` be a filtered algebra with basis over a commutative - ring `R`. Let `(F_i)_{i \in I}` be the filtration of `A`, with - `I` being a totally ordered set. Define + Let `A` be a filtered algebra over a commutative ring `R`. + Let `(F_i)_{i \in I}` be the filtration of `A`, with `I` being + a totally ordered set. Define .. MATH:: @@ -67,7 +57,8 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): *graded algebra*) of `A` is the graded algebra `\operatorname{gr} A` (endowed with this multiplication). - In particular, let `(b_x)_{x \in X}` be the basis of `A`, + Now, assume that `A` is a filtered `R`-algebra with basis. + Let `(b_x)_{x \in X}` be the basis of `A`, and consider the partition `X = \bigsqcup_{i \in I} X_i` of the set `X`, which is part of the data of a filtered algebra with basis. We know (see @@ -84,13 +75,20 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): identification of `G_k` with the `k`-th homogeneous component of `A` depends on the given basis. + The basis `(b_x)_{x \in X}` of `A` gives rise to a basis + of `\operatorname{gr} A`. This latter basis is still indexed + by the elements of `X`, and consists of the images of the + `b_x` under the `R`-module isomorphism from `A` to + `\operatorname{gr} A`. It makes `\operatorname{gr} A` into + a graded `R`-algebra with basis. + In this class, the `R`-module isomorphism from `A` to `\operatorname{gr} A` is implemented as :meth:`to_graded_conversion` and also as the default conversion from `A` to `\operatorname{gr} A`. Its inverse map is implemented as - :meth:`from_graded_conversion`. The projection - `p_i : F_i \to G_i` is implemented as + :meth:`from_graded_conversion`. + The projection `p_i : F_i \to G_i` is implemented as :meth:`projection` ``(i)``. INPUT: @@ -127,8 +125,8 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): .. TODO:: The algebra ``A`` must currently be an instance of (a subclass of) - :class:`CombinatorialFreeModule`. This should work with any algebra - with a basis. + :class:`CombinatorialFreeModule`. This should work with any + filtered algebra with a basis. .. TODO:: @@ -202,8 +200,8 @@ def _element_constructor_(self, x): Construct an element of ``self`` from ``x``. If ``self`` `= \operatorname{gr} A` for a filtered algebra - `A`, and if ``x`` is an element of `A`, then this returns - the image of `x` under the canonical `R`-module + `A` with basis, and if ``x`` is an element of `A`, then + this returns the image of `x` under the canonical `R`-module isomorphism `A \to \operatorname{gr} A`. (In this case, this is equivalent to calling ``self.to_graded_conversion()(x)``.) @@ -301,8 +299,9 @@ def projection(self, i): sage: grA.projection(8)(p) 0 """ - base_zero = self.base_ring().zero() - base_one = self.base_ring().one() + base_ring = self.base_ring() + base_zero = base_ring.zero() + base_one = base_ring.one() return self._A.module_morphism(diagonal=lambda x: (base_one if self._A.degree_on_basis(x) == i @@ -347,7 +346,8 @@ def algebra_generators(self): @cached_method def one_basis(self): """ - Return the basis index of the element `1`. + Return the basis index of the element `1` of + `\operatorname{gr} A`. This assumes that the unity `1` of `A` belongs to `F_0`. diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 000f96bd8bd..c262783a7ab 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -2252,7 +2252,7 @@ def _repr_object_names_static(category, axioms): elif axiom == "Connected" and "graded " in result: result = result.replace("graded ", "graded connected ", 1) elif axiom == "Connected" and "filtered " in result: - result = result.replace("filtered ", "filtered connected ", 1) + result = result.replace("filtered ", "filtered connected ", 1) elif axiom == "Endset" and "homsets" in result: # Without the space at the end to handle Homsets().Endset() result = result.replace("homsets", "endsets", 1) diff --git a/src/sage/categories/examples/filtered_algebras_with_basis.py b/src/sage/categories/examples/filtered_algebras_with_basis.py index 1f9bd7bd9bb..9cf0e8d07db 100644 --- a/src/sage/categories/examples/filtered_algebras_with_basis.py +++ b/src/sage/categories/examples/filtered_algebras_with_basis.py @@ -22,6 +22,9 @@ class PBWBasisCrossProduct(CombinatorialFreeModule): The Lie algebra is generated by `x,y,z` with brackets defined by `[x, y] = z`, `[y, z] = x`, and `[x, z] = -y`. The universal enveloping algebra has a (PBW) basis consisting of monomials `x^i y^j z^k`. + Despite these monomials not commuting with each other, we + nevertheless label them by the elements of the free abelian monoid + on three generators. INPUT: @@ -46,7 +49,7 @@ def __init__(self, base_ring): EXAMPLES:: sage: A = AlgebrasWithBasis(QQ).Filtered().example() - sage: x,y,z = A.algebra_generators() + sage: x,y,z = [A.algebra_generators()[i] for i in ['x','y','z']] sage: TestSuite(A).run(elements=[x*y+z]) """ I = IndexedFreeAbelianMonoid(['x', 'y', 'z'], prefix='U') @@ -96,11 +99,11 @@ def one_basis(self): def degree_on_basis(self, m): """ - The degree of the element determined by ``m`` in ``self``. + The degree of the basis element of ``self`` labelled by ``m``. INPUT: - - ``m`` -- an element of the free monoid + - ``m`` -- an element of the free abelian monoid OUTPUT: an integer, the degree of the corresponding basis element From 68b47a88d9a650d3633f1b4ba3492b8a7bc3dabe Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 17 Nov 2014 00:05:55 -0800 Subject: [PATCH 0034/1872] Better return of algebra_generators for filtered alg w/ basis example. --- .../categories/examples/filtered_algebras_with_basis.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/examples/filtered_algebras_with_basis.py b/src/sage/categories/examples/filtered_algebras_with_basis.py index 9cf0e8d07db..9e7765aefa8 100644 --- a/src/sage/categories/examples/filtered_algebras_with_basis.py +++ b/src/sage/categories/examples/filtered_algebras_with_basis.py @@ -49,7 +49,7 @@ def __init__(self, base_ring): EXAMPLES:: sage: A = AlgebrasWithBasis(QQ).Filtered().example() - sage: x,y,z = [A.algebra_generators()[i] for i in ['x','y','z']] + sage: x,y,z = A.algebra_generators() sage: TestSuite(A).run(elements=[x*y+z]) """ I = IndexedFreeAbelianMonoid(['x', 'y', 'z'], prefix='U') @@ -78,12 +78,12 @@ def algebra_generators(self): EXAMPLES:: sage: A = AlgebrasWithBasis(QQ).Filtered().example() - sage: key = lambda x: x.leading_support().to_word_list() - sage: sorted(A.algebra_generators(), key=key) + sage: list(A.algebra_generators()) [U['x'], U['y'], U['z']] """ G = self._indices.monoid_generators() - return Family({x: self.monomial(G[x]) for x in G.keys()}) + I = sorted(G.keys()) + return Family(I, lambda x: self.monomial(G[x])) def one_basis(self): """ From c3b29504eb8ec28ec0fe47b82ef59079f8f494c4 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 17 Nov 2014 00:25:44 -0800 Subject: [PATCH 0035/1872] enough for today --- .../examples/filtered_modules_with_basis.py | 6 +- src/sage/categories/filtered_algebras.py | 7 +- .../filtered_algebras_with_basis.py | 74 ++++++++++++++++-- src/sage/categories/filtered_modules.py | 19 ++--- .../categories/filtered_modules_with_basis.py | 77 +++++++++++++------ 5 files changed, 140 insertions(+), 43 deletions(-) diff --git a/src/sage/categories/examples/filtered_modules_with_basis.py b/src/sage/categories/examples/filtered_modules_with_basis.py index d2c8b5d4ef5..9954d6a2ff5 100644 --- a/src/sage/categories/examples/filtered_modules_with_basis.py +++ b/src/sage/categories/examples/filtered_modules_with_basis.py @@ -98,8 +98,8 @@ def __init__(self, base_ring): # This could be a default implementation def degree_on_basis(self, t): """ - The degree of the element determined by the partition ``t`` in - this filtered module. + The degree of the basis element indexed by the partition ``t`` + in this filtered module. INPUT: @@ -122,7 +122,7 @@ def degree_on_basis(self, t): def _repr_(self): """ - Print representation + Print representation of ``self``. EXAMPLES:: diff --git a/src/sage/categories/filtered_algebras.py b/src/sage/categories/filtered_algebras.py index 536ef505a1a..c9444680f0a 100644 --- a/src/sage/categories/filtered_algebras.py +++ b/src/sage/categories/filtered_algebras.py @@ -20,8 +20,8 @@ class FilteredAlgebras(FilteredModulesCategory): (whose underlying `R`-module structure is identical with that of the `R`-algebra `A`) such that the indexing set `I` (typically `I = \NN`) is also an additive abelian monoid, - `F_0 = \{ 0 \}`, and `F_i \cdot F_j \subseteq F_{i+j}` - for all `i, j \in I`. + the unity `1` of `A` belongs to `F_0`, and we have + `F_i \cdot F_j \subseteq F_{i+j}` for all `i, j \in I`. EXAMPLES:: @@ -48,7 +48,8 @@ def graded_algebra(self): .. TODO:: Implement a version of the associated graded algebra - without a distinguished basis. + which does not require ``self`` to have a + distinguished basis. EXAMPLES:: diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index c56fb3878e7..68badc0e2fc 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -41,6 +41,9 @@ def graded_algebra(self): """ Return the associated graded algebra to ``self``. + See :class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra` + for the definition and the properties of this. + EXAMPLES:: sage: A = AlgebrasWithBasis(ZZ).Filtered().example() @@ -53,11 +56,14 @@ def graded_algebra(self): return AssociatedGradedAlgebra(self) class ElementMethods: + def is_homogeneous(self): r""" Return whether ``self`` is homogeneous. - EXAMPLES:: + EXAMPLES: + + Here is a case where the algebra is graded:: sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: (x, y) = (S[2], S[3]) @@ -67,6 +73,23 @@ def is_homogeneous(self): True sage: ((x + y)^2).is_homogeneous() False + + Let us now test a filtered algebra (but remember that the + notion of homogeneity now depends on the choice of a + basis):: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: x,y,z = A.algebra_generators() + sage: (x*y).is_homogeneous() + True + sage: (y*x).is_homogeneous() + False + sage: A.one().is_homogeneous() + True + sage: A.zero().is_homogeneous() + True + sage: (A.one()+x).is_homogeneous() + False """ degree_on_basis = self.parent().degree_on_basis degree = None @@ -87,11 +110,13 @@ def homogeneous_degree(self): This raises an error if the element is not homogeneous. To obtain the maximum of the degrees of the homogeneous - summands, use :meth:`maximal_degree` + summands, use :meth:`maximal_degree`. .. SEEALSO:: :meth:`maximal_degree` - EXAMPLES:: + EXAMPLES: + + First, an example where the algebra is graded:: sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: (x, y) = (S[2], S[3]) @@ -104,6 +129,21 @@ def homogeneous_degree(self): ... ValueError: element is not homogeneous + Let us now test a filtered algebra (but remember that the + notion of homogeneity now depends on the choice of a + basis):: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: x,y,z = A.algebra_generators() + sage: (x*y).homogeneous_degree() + 2 + sage: (y*x).homogeneous_degree() + Traceback (most recent call last): + ... + ValueError: element is not homogeneous + sage: A.one().homogeneous_degree() + 0 + TESTS:: sage: S = NonCommutativeSymmetricFunctions(QQ).S() @@ -123,11 +163,18 @@ def homogeneous_degree(self): def maximal_degree(self): """ - The maximum of the degrees of the homogeneous summands. + The maximum of the degrees of the homogeneous components + of ``self``. + + This is also the smallest `i` such that ``self`` belongs + to `F_i`. Hence, it does not depend on the basis of the + parent of ``self``. .. SEEALSO:: :meth:`homogeneous_degree` - EXAMPLES:: + EXAMPLES: + + First, we test this on a graded algebra:: sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: (x, y) = (S[2], S[3]) @@ -138,6 +185,23 @@ def maximal_degree(self): sage: ((1 + x)^3).maximal_degree() 6 + Let us now test a filtered algebra:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: x,y,z = A.algebra_generators() + sage: (x*y).maximal_degree() + 2 + sage: (y*x).maximal_degree() + 2 + sage: A.one().maximal_degree() + 0 + sage: A.zero().maximal_degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + sage: (A.one()+x).maximal_degree() + 1 + TESTS:: sage: S = NonCommutativeSymmetricFunctions(QQ).S() diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index 8b4bba1bf2e..af5f0f83fc4 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -3,9 +3,9 @@ A *filtered module* over a commutative ring `R` with a totally ordered indexing set `I` (typically `I = \NN`) is an `R`-module `M` equipped -with a sequence `(F_i)_{i \in I}` of `R`-submodules satisfying -`F_i \subseteq F_j` if `i \leq j` for all `i,j \in I` and -`M = \bigcup_{i \in I} F_i`. This sequence is called a *filtration* +with a family `(F_i)_{i \in I}` of `R`-submodules satisfying +`F_i \subseteq F_j` for all `i,j \in I` having `i \leq j`, and +`M = \bigcup_{i \in I} F_i`. This family is called a *filtration* of the given module `M`. .. TODO:: @@ -139,13 +139,13 @@ def _repr_object_names(self): class FilteredModules(FilteredModulesCategory): r""" - The category of filtered modules. + The category of filtered modules over a given commutative ring `R`. A *filtered module* over a commutative ring `R` with a totally ordered indexing set `I` (typically `I = \NN`) is an `R`-module `M` equipped - with a sequence `(F_i)_{i \in I}` of `R`-submodules satisfying - `F_i \subseteq F_j` if `i \leq j` for all `i, j \in I` and - `M = \bigcup_{i \in I} F_i`. This sequence is called a *filtration* + with a family `(F_i)_{i \in I}` of `R`-submodules satisfying + `F_i \subseteq F_j` for all `i,j \in I` having `i \leq j`, and + `M = \bigcup_{i \in I} F_i`. This family is called a *filtration* of the given module `M`. EXAMPLES:: @@ -206,8 +206,9 @@ def Connected(self): Return the full subcategory of the connected objects of ``self``. A filtered `R`-module `M` with filtration - `(F_0, F_1, F_2, \ldots)` is said to be - *connected* if `F_0` is isomorphic to `R`. + `(F_0, F_1, F_2, \ldots)` (indexed by `\NN`) + is said to be *connected* if `F_0` is isomorphic + to `R`. EXAMPLES:: diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index efe84a1416b..cee97aabcef 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -4,16 +4,18 @@ A *filtered module with basis* over a commutative ring `R` means (for the purpose of this code) a filtered `R`-module `M` with filtration `(F_i)_{i \in I}` (typically `I = \NN`) -endowed with a basis `(b_j)_{j \in J}` of `M` and a partition of -the set `J = \bigsqcup_{i \in I} J_i` (which can be empty) such -that for every `n \in I`, the subfamily `(b_j)_{j \in U_n}`, where -`U_n = \bigcup_{i \leq n} J_i`, is a basis of the `R`-submodule `F_n`. +endowed with a basis `(b_j)_{j \in J}` of `M` and a partition +`J = \bigsqcup_{i \in I} J_i` of the set `J` (it is allowed +that some `J_i` are empty) such that for every `n \in I`, +the subfamily `(b_j)_{j \in U_n}`, where +`U_n = \bigcup_{i \leq n} J_i`, is a basis of the +`R`-submodule `F_n`. For every `i \in I`, the `R`-submodule of `M` spanned by `(b_j)_{j \in J_i}` is called the `i`-*th graded component* -of the filtered module with basis `M`; the elements of -this submodule are referred to as *homogeneous elements of -degree* `i`. +(aka the `i`-*th homogeneous component*) of the filtered +module with basis `M`; the elements of this submodule are +referred to as *homogeneous elements of degree* `i`. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -31,23 +33,28 @@ class FilteredModulesWithBasis(FilteredModulesCategory): A *filtered module with basis* over a commutative ring `R` means (for the purpose of this code) a filtered `R`-module `M` with filtration `(F_i)_{i \in I}` (typically `I = \NN`) - endowed with a basis `(b_j)_{j \in J}` of `M` and a partition of - the set `J = \bigsqcup_{i \in I} J_i` (which can be empty) such - that for every `n \in I`, the subfamily `(b_j)_{j \in U_n}`, where - `U_n = \bigcup_{i \leq n} J_i`, is a basis of the `R`-submodule `F_n`. + endowed with a basis `(b_j)_{j \in J}` of `M` and a partition + `J = \bigsqcup_{i \in I} J_i` of the set `J` (it is allowed + that some `J_i` are empty) such that for every `n \in I`, + the subfamily `(b_j)_{j \in U_n}`, where + `U_n = \bigcup_{i \leq n} J_i`, is a basis of the + `R`-submodule `F_n`. For every `i \in I`, the `R`-submodule of `M` spanned by - `(b_j)_{j \in J_i}` is called the `i`-*th graded component* of the - filtered module with basis `M`; the elements of this submodule are - referred to as *homogeneous elements of degree* `i`. The `R`-module - `M` is the direct sum of its `i`-th graded components over - all `i \in I`, and thus becomes a graded `R`-module with basis. - Conversely, any graded `R`-module with basis canonically becomes a filtered - `R`-module with basis (by defining `F_n = \bigoplus_{i \leq n} G_i` - where `G_i` is the `i`-th graded component and `J_i` as the indexing - set of the basis of the `i`-th graded component). Hence, the notion - of a filtered `R`-module with basis is equivalent to the notion of - a graded `R`-module with basis. + `(b_j)_{j \in J_i}` is called the `i`-*th graded component* + (aka the `i`-*th homogeneous component*) of the filtered + module with basis `M`; the elements of this submodule are + referred to as *homogeneous elements of degree* `i`. + The `R`-module `M` is the direct sum of its `i`-th graded + components over all `i \in I`, and thus becomes a graded + `R`-module with basis. + Conversely, any graded `R`-module with basis canonically + becomes a filtered `R`-module with basis (by defining + `F_n = \bigoplus_{i \leq n} G_i` where `G_i` is the `i`-th + graded component, and defining `J_i` as the indexing set + of the basis of the `i`-th graded component). Hence, the + notion of a filtered `R`-module with basis is equivalent + to the notion of a graded `R`-module with basis. However, the *category* of filtered `R`-modules with basis is not the category of graded `R`-modules with basis. Indeed, the *morphisms* @@ -58,6 +65,22 @@ class FilteredModulesWithBasis(FilteredModulesCategory): the notion of a filtered algebra with basis differs from that of a graded algebra with basis. + .. NOTE:: + + Currently, to make use of the functionality of this class, + an instance of ``FilteredModulesWithBasis`` should fulfill + the contract of a :class:`CombinatorialFreeModule` (most + likely by inheriting from it). It should also have the + indexing set `J` encoded as its ``_indices`` attribute, + and ``_indices.subset(basis=i)`` should yield the subset + `J_i` (as an iterable). If the latter conditions are not + satisfied, then :meth:`basis` must be overridden. + + .. TODO:: + + This deserves to be handled better, and the contracts + involved might also profit from some explicit writing-up. + EXAMPLES:: sage: C = ModulesWithBasis(ZZ).Filtered(); C @@ -92,7 +115,9 @@ def basis(self, d=None): - ``d`` -- (optional, default ``None``) nonnegative integer or ``None`` - If ``d`` is ``None``, returns a basis of the module. + OUTPUT: + + If ``d`` is ``None``, returns the basis of the module. Otherwise, returns the basis of the homogeneous component of degree ``d`` (i.e., the subfamily of the basis of the whole module which consists only of the basis vectors @@ -178,6 +203,12 @@ def degree(self): raise ValueError("element is not homogeneous") return self.parent().degree_on_basis(self.leading_support()) +# .. TODO:: +# +# maximal_degree. This actually does not depend on the basis +# and can probably be copied, up to doctests, from +# filtered_algebras_with_basis.py. + def homogeneous_component(self, n): """ Return the homogeneous component of degree ``n`` of this From 2d2929600e9e94b54cd4f9af0c19f6cd465fea2d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 17 Nov 2014 08:11:03 -0800 Subject: [PATCH 0036/1872] Added option to consider the clifford algebra as filtered or graded. --- src/sage/algebras/clifford_algebra.py | 93 +++++++++++++++++++++------ 1 file changed, 74 insertions(+), 19 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index af6ce5a280f..c22b1581ad2 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -454,6 +454,8 @@ class CliffordAlgebra(CombinatorialFreeModule): - ``Q`` -- a quadratic form - ``names`` -- (default: ``'e'``) the generator names + - ``graded`` -- (default: ``True``) if ``True``, then use the `\ZZ / 2\ZZ` + grading, otherwise use the `\ZZ` filtration EXAMPLES: @@ -463,7 +465,8 @@ class CliffordAlgebra(CombinatorialFreeModule): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl = CliffordAlgebra(Q) sage: Cl - The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: + The graded Clifford algebra of the Quadratic form in 3 variables + over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] @@ -485,7 +488,7 @@ class CliffordAlgebra(CombinatorialFreeModule): will be changed once :trac:`17096` is finished. """ @staticmethod - def __classcall_private__(cls, Q, names=None): + def __classcall_private__(cls, Q, names=None, graded=True): """ Normalize arguments to ensure a unique representation. @@ -508,9 +511,9 @@ def __classcall_private__(cls, Q, names=None): names = tuple( '{}{}'.format(names[0], i) for i in range(Q.dim()) ) else: raise ValueError("the number of variables does not match the number of generators") - return super(CliffordAlgebra, cls).__classcall__(cls, Q, names) + return super(CliffordAlgebra, cls).__classcall__(cls, Q, names, graded=bool(graded)) - def __init__(self, Q, names, category=None): + def __init__(self, Q, names, category=None, graded=True): r""" Initialize ``self``. @@ -519,6 +522,8 @@ def __init__(self, Q, names, category=None): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl = CliffordAlgebra(Q) sage: TestSuite(Cl).run() + sage: Cl = CliffordAlgebra(Q, graded=False) + sage: TestSuite(Cl).run() TESTS: @@ -533,9 +538,13 @@ def __init__(self, Q, names, category=None): True """ self._quadratic_form = Q + self._graded = graded R = Q.base_ring() if category is None: - category = AlgebrasWithBasis(R).Filtered() + if graded: + category = AlgebrasWithBasis(R).Graded() + else: + category = AlgebrasWithBasis(R).Filtered() indices = SubsetsSorted(range(Q.dim())) CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) @@ -548,12 +557,20 @@ def _repr_(self): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: CliffordAlgebra(Q) - The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: + The graded Clifford algebra of the Quadratic form in 3 variables + over Integer Ring with coefficients: + [ 1 2 3 ] + [ * 4 5 ] + [ * * 6 ] + sage: CliffordAlgebra(Q, graded=False) + The filtered Clifford algebra of the Quadratic form in 3 variables + over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] """ - return "The Clifford algebra of the {}".format(self._quadratic_form) + gr = "graded" if self._graded else "filtered" + return "The {} Clifford algebra of the {}".format(gr, self._quadratic_form) def _repr_term(self, m): """ @@ -667,12 +684,24 @@ def _coerce_map_from_(self, V): sage: b = Cl.basis()[(0,2)] sage: Clp(3*a-4*b) 2*e0*e2 + + The filtered Clifford algebra coerces into the graded Clifford + algebra, but not the other way around:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl = CliffordAlgebra(Q) + sage: ClF = CliffordAlgebra(Q, graded=False) + sage: Cl.has_coerce_map_from(ClF) + True + sage: ClF.has_coerce_map_from(Cl) + False """ if isinstance(V, CliffordAlgebra): Q = self._quadratic_form try: return (V.variable_names() == self.variable_names() and - V._quadratic_form.base_change_to(self.base_ring()) == Q) + V._quadratic_form.base_change_to(self.base_ring()) == Q + and (self._graded or not V._graded)) except Exception: return False @@ -835,19 +864,22 @@ def degree_on_basis(self, m): r""" Return the degree of the monomial indexed by ``m``. - This degree is a nonnegative integer, and should be interpreted - as a residue class modulo `2`, since we consider ``self`` to be - `\ZZ_2`-graded (not `\ZZ`-graded, although there is a natural - *filtration* by the length of ``m``). The degree of the monomial - ``m`` in this `\ZZ_2`-grading is defined to be the length of ``m`` - taken mod `2`. + If we consider the Clifford algebra to be `\ZZ_2`-graded, this + degree is a nonnegative integer, and should be interpreted as a + residue class modulo `2`. The degree of the monomial ``m`` in this + `\ZZ_2`-grading is defined to be the length of ``m`` taken mod `2`. + + Otherwise we are considering the Clifford algebra to be + `\NN`-filtered, and the degree of the monomial ``m`` is the + length of ``m``. .. WARNING: On the :class:`ExteriorAlgebra` class (which inherits from :class:`CliffordAlgebra`), the :meth:`degree_on_basis` - method is overridden to return an actual `\NN`-degree. So - don't count on this method always returning `0` or `1` !! + method is overridden to always return an actual `\NN`-degree + since it is `\NN`-graded. So don't count on this method + always returning `0` or `1` !! EXAMPLES:: @@ -857,8 +889,31 @@ def degree_on_basis(self, m): 1 sage: Cl.degree_on_basis((0,1)) 0 + sage: Cl. = CliffordAlgebra(Q, graded=False) + sage: Cl.degree_on_basis((0,1)) + 2 + """ + if self._graded: + return len(m) % ZZ(2) + return ZZ(len(m)) + + def graded_algebra(self): + """ + Return the associated graded algebra of ``self``. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: Cl.graded_algebra() is Cl + True + sage: Cl. = CliffordAlgebra(Q, graded=False) + sage: Cl.graded_algebra() + The exterior algebra of rank 3 over Integer Ring """ - return len(m) % ZZ(2) + if self._graded: + return self + return ExteriorAlgebra(self.base_ring(), self.variable_names()) @cached_method def free_module(self): @@ -956,11 +1011,11 @@ def lift_module_morphism(self, m, names=None): sage: phi = Cl.lift_module_morphism(m, 'abc') sage: phi Generic morphism: - From: The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: + From: The graded Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: [ 10 17 3 ] [ * 11 0 ] [ * * 5 ] - To: The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: + To: The graded Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] From 096538121130679a55b971d3d3a5626e94b157a5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 19 Nov 2014 15:54:34 -0800 Subject: [PATCH 0037/1872] Changes from discussion on trac. --- src/sage/algebras/associated_graded.py | 104 ++------- src/sage/algebras/clifford_algebra.py | 7 +- src/sage/algebras/weyl_algebra.py | 7 +- .../filtered_algebras_with_basis.py | 211 ++++++------------ src/sage/categories/filtered_modules.py | 9 +- .../categories/filtered_modules_with_basis.py | 135 ++++++++++- 6 files changed, 225 insertions(+), 248 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 1fddb176f6b..bc75474a798 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -147,7 +147,7 @@ def __init__(self, A, category=None): sage: grA = A.graded_algebra() sage: TestSuite(grA).run(elements=[prod(grA.algebra_generators())]) """ - if A not in AlgebrasWithBasis(A.base_ring()).Filtered(): + if A not in AlgebrasWithBasis(A.base_ring().category()).Filtered(): raise ValueError("the base algebra must be filtered and with basis") self._A = A @@ -220,94 +220,6 @@ def _element_constructor_(self, x): return self._from_dict(dict(x)) return super(AssociatedGradedAlgebra, self)._element_constructor_(x) - # Maps - - def to_graded_conversion(self): - r""" - Return the canonical `R`-module isomorphism - `A \to \operatorname{gr} A` induced by the basis of `A`. - - This is an isomorphism of `R`-modules, not of algebras. See - the class-wide documentation :class:`AssociatedGradedAlgebra`. - - .. SEEALSO:: - - :meth:`from_graded_conversion`. - - EXAMPLES:: - - sage: A = Algebras(QQ).WithBasis().Filtered().example() - sage: grA = A.graded_algebra() - sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p - U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 - sage: grA.to_graded_conversion()(p) - bar(U['x']^2*U['y']^2*U['z']^3) + bar(U['x']) + 2*bar(1) - """ - base_one = self.base_ring().one() - return self._A.module_morphism(diagonal=lambda x: base_one, - codomain=self) - - def from_graded_conversion(self): - r""" - Return the inverse of the canonical `R`-module isomorphism - `A \to \operatorname{gr} A` induced by the basis of `A`. - - This is an isomorphism of `R`-modules, not of algebras. See - the class-wide documentation :class:`AssociatedGradedAlgebra`. - - .. SEEALSO:: - - :meth:`to_graded_conversion`. - - EXAMPLES:: - - sage: A = Algebras(QQ).WithBasis().Filtered().example() - sage: grA = A.graded_algebra() - sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p - U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 - sage: q = grA.to_graded_conversion()(p) - sage: grA.from_graded_conversion()(q) == p - True - """ - base_one = self.base_ring().one() - return self.module_morphism(diagonal=lambda x: base_one, - codomain=self._A) - - def projection(self, i): - r""" - Return the `i`-th projection `p_i : F_i \to G_i` (in the - notations of the class-wide documentation - :class:`AssociatedGradedAlgebra`). - - This method actually does not return the map `p_i` itself, - but an extension of `p_i` to the whole `R`-module `A`. - This extension is the composition of the `R`-module - isomorphism `A \to \operatorname{gr} A` with the canonical - projection of the graded `R`-module `\operatorname{gr} A` - onto its `i`-th graded component `G_i`. The codomain of - this map is `\operatorname{gr} A`, although its actual - image is `G_i`. - - EXAMPLES:: - - sage: A = Algebras(QQ).WithBasis().Filtered().example() - sage: grA = A.graded_algebra() - sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p - U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 - sage: grA.projection(7)(p) - bar(U['x']^2*U['y']^2*U['z']^3) - sage: grA.projection(8)(p) - 0 - """ - base_ring = self.base_ring() - base_zero = base_ring.zero() - base_one = base_ring.one() - return self._A.module_morphism(diagonal=lambda x: - (base_one if - self._A.degree_on_basis(x) == i - else base_zero), - codomain=self) - def gen(self, *args, **kwds): """ Return a generator of ``self``. @@ -343,6 +255,20 @@ def algebra_generators(self): G = self._A.algebra_generators() return Family(G.keys(), lambda x: self(G[x]), name="generator") + def degree_on_basis(self, x): + """ + Return the degree on the basis element indexed by ``x``. + + EXAMPLES:: + + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: all(A.degree_on_basis(x) == grA.degree_on_basis(x) + ....: for g in grA.algebra_generators() for x in g.support()) + True + """ + return self._A.degree_on_basis(x) + @cached_method def one_basis(self): """ diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index c22b1581ad2..40170457e55 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -542,9 +542,9 @@ def __init__(self, Q, names, category=None, graded=True): R = Q.base_ring() if category is None: if graded: - category = AlgebrasWithBasis(R).Graded() + category = AlgebrasWithBasis(R.category()).Graded() else: - category = AlgebrasWithBasis(R).Filtered() + category = AlgebrasWithBasis(R.category()).Filtered() indices = SubsetsSorted(range(Q.dim())) CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) @@ -1473,7 +1473,8 @@ def __init__(self, R, names): sage: E. = ExteriorAlgebra(QQ) sage: TestSuite(E).run() """ - CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, GradedHopfAlgebrasWithBasis(R)) + cat = GradedHopfAlgebrasWithBasis(R.category()) + CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, cat) # TestSuite will fail if the HopfAlgebra classes will ever have tests for # the coproduct being an algebra morphism -- since this is really a # Hopf superalgebra, not a Hopf algebra. diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index a2a1050a00e..1727f8e8377 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -546,6 +546,11 @@ class DifferentialWeylAlgebra(Algebra, UniqueRepresentation): sage: W. = DifferentialWeylAlgebra(QQ); W Differential Weyl algebra of polynomials in a, b over Rational Field + + .. TODO:: + + Implement the :meth:`graded_algebra` as a polynomial ring once + they are considered to be graded rings (algebras). """ @staticmethod def __classcall__(cls, R, names=None): @@ -584,7 +589,7 @@ def __init__(self, R, names=None): names = names + tuple('d' + n for n in names) if len(names) != self._n * 2: raise ValueError("variable names cannot differ by a leading 'd'") - cat = AlgebrasWithBasis(R).NoZeroDivisors().Filtered() + cat = AlgebrasWithBasis(R.category()).NoZeroDivisors().Filtered() Algebra.__init__(self, R, names, category=cat) def _repr_(self): diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 68badc0e2fc..7756d5a3a52 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -55,163 +55,96 @@ def graded_algebra(self): from sage.algebras.associated_graded import AssociatedGradedAlgebra return AssociatedGradedAlgebra(self) - class ElementMethods: + # Maps - def is_homogeneous(self): + def to_graded_conversion(self): r""" - Return whether ``self`` is homogeneous. + Return the canonical `R`-module isomorphism + `A \to \operatorname{gr} A` induced by the basis of `A`. - EXAMPLES: + This is an isomorphism of `R`-modules, not of algebras. See + the class documentation :class:`AssociatedGradedAlgebra`. - Here is a case where the algebra is graded:: + .. SEEALSO:: - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: (x, y) = (S[2], S[3]) - sage: (3*x).is_homogeneous() - True - sage: (x^3 - y^2).is_homogeneous() - True - sage: ((x + y)^2).is_homogeneous() - False + :meth:`from_graded_conversion` - Let us now test a filtered algebra (but remember that the - notion of homogeneity now depends on the choice of a - basis):: + EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).Filtered().example() - sage: x,y,z = A.algebra_generators() - sage: (x*y).is_homogeneous() - True - sage: (y*x).is_homogeneous() - False - sage: A.one().is_homogeneous() - True - sage: A.zero().is_homogeneous() + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p + U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 + sage: q = A.to_graded_conversion()(p); q + bar(U['x']^2*U['y']^2*U['z']^3) + bar(U['x']) + 2*bar(1) + sage: q.parent() is A.graded_algebra() True - sage: (A.one()+x).is_homogeneous() - False - """ - degree_on_basis = self.parent().degree_on_basis - degree = None - for m in self.support(): - if degree is None: - degree = degree_on_basis(m) - else: - if degree != degree_on_basis(m): - return False - return True - - def homogeneous_degree(self): - """ - The degree of a nonzero homogeneous element ``self`` in the - filtered module. - - .. NOTE:: - - This raises an error if the element is not homogeneous. - To obtain the maximum of the degrees of the homogeneous - summands, use :meth:`maximal_degree`. - - .. SEEALSO:: :meth:`maximal_degree` - - EXAMPLES: - - First, an example where the algebra is graded:: - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: (x, y) = (S[2], S[3]) - sage: x.homogeneous_degree() - 2 - sage: (x^3 + 4*y^2).homogeneous_degree() - 6 - sage: ((1 + x)^3).homogeneous_degree() - Traceback (most recent call last): - ... - ValueError: element is not homogeneous - - Let us now test a filtered algebra (but remember that the - notion of homogeneity now depends on the choice of a - basis):: - - sage: A = AlgebrasWithBasis(QQ).Filtered().example() - sage: x,y,z = A.algebra_generators() - sage: (x*y).homogeneous_degree() - 2 - sage: (y*x).homogeneous_degree() - Traceback (most recent call last): - ... - ValueError: element is not homogeneous - sage: A.one().homogeneous_degree() - 0 - - TESTS:: - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S.zero().degree() - Traceback (most recent call last): - ... - ValueError: the zero element does not have a well-defined degree """ - if self.is_zero(): - raise ValueError("the zero element does not have a well-defined degree") - if not self.is_homogeneous(): - raise ValueError("element is not homogeneous") - return self.parent().degree_on_basis(self.leading_support()) + base_one = self.base_ring().one() + return self.module_morphism(diagonal=lambda x: base_one, + codomain=self.graded_algebra()) - # default choice for degree; will be overridden as necessary - degree = homogeneous_degree + def from_graded_conversion(self): + r""" + Return the inverse of the canonical `R`-module isomorphism + `A \to \operatorname{gr} A` induced by the basis of `A` + (that is a map `\operatorname{gr} A \to A`). - def maximal_degree(self): - """ - The maximum of the degrees of the homogeneous components - of ``self``. + This is an isomorphism of `R`-modules, not of algebras. See + the class documentation :class:`AssociatedGradedAlgebra`. - This is also the smallest `i` such that ``self`` belongs - to `F_i`. Hence, it does not depend on the basis of the - parent of ``self``. + .. SEEALSO:: - .. SEEALSO:: :meth:`homogeneous_degree` + :meth:`to_graded_conversion` - EXAMPLES: + EXAMPLES:: - First, we test this on a graded algebra:: + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p + U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 + sage: q = A.to_graded_conversion()(p) + sage: A.from_graded_conversion()(q) == p + True + sage: q.parent() is A.graded_algebra() + True + """ + base_one = self.base_ring().one() + return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, + codomain=self) - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: (x, y) = (S[2], S[3]) - sage: x.maximal_degree() - 2 - sage: (x^3 + 4*y^2).maximal_degree() - 6 - sage: ((1 + x)^3).maximal_degree() - 6 + def projection(self, i): + r""" + Return the `i`-th projection `p_i : F_i \to G_i` (in the + notations of the class documentation + :class:`AssociatedGradedAlgebra`). + + This method actually does not return the map `p_i` itself, + but an extension of `p_i` to the whole `R`-module `A`. + This extension is the composition of the `R`-module + isomorphism `A \to \operatorname{gr} A` with the canonical + projection of the graded `R`-module `\operatorname{gr} A` + onto its `i`-th graded component `G_i`. The codomain of + this map is `\operatorname{gr} A`, although its actual + image is `G_i`. - Let us now test a filtered algebra:: + EXAMPLES:: - sage: A = AlgebrasWithBasis(QQ).Filtered().example() - sage: x,y,z = A.algebra_generators() - sage: (x*y).maximal_degree() - 2 - sage: (y*x).maximal_degree() - 2 - sage: A.one().maximal_degree() + sage: A = Algebras(QQ).WithBasis().Filtered().example() + sage: p = A.an_element() + A.algebra_generators()['x'] + 2; p + U['x']^2*U['y']^2*U['z']^3 + U['x'] + 2 + sage: q = A.projection(7)(p); q + bar(U['x']^2*U['y']^2*U['z']^3) + sage: q.parent() is A.graded_algebra() + True + sage: A.projection(8)(p) 0 - sage: A.zero().maximal_degree() - Traceback (most recent call last): - ... - ValueError: the zero element does not have a well-defined degree - sage: (A.one()+x).maximal_degree() - 1 - - TESTS:: - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S.zero().degree() - Traceback (most recent call last): - ... - ValueError: the zero element does not have a well-defined degree """ - if self.is_zero(): - raise ValueError("the zero element does not have a well-defined degree") - degree_on_basis = self.parent().degree_on_basis - return max(degree_on_basis(m) for m in self.support()) + base_zero = self.base_ring().zero() + base_one = self.base_ring().one() + grA = self.graded_algebra() + proj = lambda x: (base_one if grA.degree_on_basis(x) == i + else base_zero) + return self.module_morphism(diagonal=proj, codomain=grA) + + class ElementMethods: + pass diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index af5f0f83fc4..784b0faaf59 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -1,7 +1,7 @@ r""" Filtered Modules -A *filtered module* over a commutative ring `R` with a totally ordered +A *filtered module* over a ring `R` with a totally ordered indexing set `I` (typically `I = \NN`) is an `R`-module `M` equipped with a family `(F_i)_{i \in I}` of `R`-submodules satisfying `F_i \subseteq F_j` for all `i,j \in I` having `i \leq j`, and @@ -10,7 +10,8 @@ .. TODO:: - Implement a notion for decreasing filtrations: where `F_j \subseteq F_i`. + Implement a notion for decreasing filtrations: where `F_j \subseteq F_i` + when `i \leq j`. .. TODO:: @@ -139,9 +140,9 @@ def _repr_object_names(self): class FilteredModules(FilteredModulesCategory): r""" - The category of filtered modules over a given commutative ring `R`. + The category of filtered modules over a given ring `R`. - A *filtered module* over a commutative ring `R` with a totally ordered + A *filtered module* over a ring `R` with a totally ordered indexing set `I` (typically `I = \NN`) is an `R`-module `M` equipped with a family `(F_i)_{i \in I}` of `R`-submodules satisfying `F_i \subseteq F_j` for all `i,j \in I` having `i \leq j`, and diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index cee97aabcef..6feee58383e 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -1,9 +1,9 @@ r""" Filtered Modules With Basis -A *filtered module with basis* over a commutative ring `R` -means (for the purpose of this code) a filtered `R`-module -`M` with filtration `(F_i)_{i \in I}` (typically `I = \NN`) +A *filtered module with basis* over a ring `R` means +(for the purpose of this code) a filtered `R`-module `M` +with filtration `(F_i)_{i \in I}` (typically `I = \NN`) endowed with a basis `(b_j)_{j \in J}` of `M` and a partition `J = \bigsqcup_{i \in I} J_i` of the set `J` (it is allowed that some `J_i` are empty) such that for every `n \in I`, @@ -30,9 +30,9 @@ class FilteredModulesWithBasis(FilteredModulesCategory): r""" The category of filtered modules with a distinguished basis. - A *filtered module with basis* over a commutative ring `R` - means (for the purpose of this code) a filtered `R`-module - `M` with filtration `(F_i)_{i \in I}` (typically `I = \NN`) + A *filtered module with basis* over a ring `R` means + (for the purpose of this code) a filtered `R`-module `M` + with filtration `(F_i)_{i \in I}` (typically `I = \NN`) endowed with a basis `(b_j)_{j \in J}` of `M` and a partition `J = \bigsqcup_{i \in I} J_i` of the set `J` (it is allowed that some `J_i` are empty) such that for every `n \in I`, @@ -160,6 +160,32 @@ def is_homogeneous(self): False sage: (x+2*z).is_homogeneous() True + + Here is a case where the algebra is graded:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: (x, y) = (S[2], S[3]) + sage: (3*x).is_homogeneous() + True + sage: (x^3 - y^2).is_homogeneous() + True + sage: ((x + y)^2).is_homogeneous() + False + + Let us now test a filtered algebra:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: x,y,z = A.algebra_generators() + sage: (x*y).is_homogeneous() + True + sage: (y*x).is_homogeneous() + False + sage: A.one().is_homogeneous() + True + sage: A.zero().is_homogeneous() + True + sage: (A.one()+x).is_homogeneous() + False """ degree_on_basis = self.parent().degree_on_basis degree = None @@ -171,7 +197,7 @@ def is_homogeneous(self): return False return True - def degree(self): + def homogeneous_degree(self): r""" The degree of a nonzero homogeneous element ``self`` in the filtered module. @@ -196,6 +222,40 @@ def degree(self): Traceback (most recent call last): ... ValueError: element is not homogeneous + + An example where the algebra is graded:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: (x, y) = (S[2], S[3]) + sage: x.homogeneous_degree() + 2 + sage: (x^3 + 4*y^2).homogeneous_degree() + 6 + sage: ((1 + x)^3).homogeneous_degree() + Traceback (most recent call last): + ... + ValueError: element is not homogeneous + + Let us now test a filtered algebra:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: x,y,z = A.algebra_generators() + sage: (x*y).homogeneous_degree() + 2 + sage: (y*x).homogeneous_degree() + Traceback (most recent call last): + ... + ValueError: element is not homogeneous + sage: A.one().homogeneous_degree() + 0 + + TESTS:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S.zero().degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree """ if not self.support(): raise ValueError("the zero element does not have a well-defined degree") @@ -203,11 +263,62 @@ def degree(self): raise ValueError("element is not homogeneous") return self.parent().degree_on_basis(self.leading_support()) -# .. TODO:: -# -# maximal_degree. This actually does not depend on the basis -# and can probably be copied, up to doctests, from -# filtered_algebras_with_basis.py. + # default choice for degree; will be overridden as necessary + degree = homogeneous_degree + + def maximal_degree(self): + """ + The maximum of the degrees of the homogeneous components + of ``self``. + + This is also the smallest `i` such that ``self`` belongs + to `F_i`. Hence, it does not depend on the basis of the + parent of ``self``. + + .. SEEALSO:: :meth:`homogeneous_degree` + + EXAMPLES: + + First, we test this on a graded algebra:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: (x, y) = (S[2], S[3]) + sage: x.maximal_degree() + 2 + sage: (x^3 + 4*y^2).maximal_degree() + 6 + sage: ((1 + x)^3).maximal_degree() + 6 + + Let us now test a filtered algebra:: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example() + sage: x,y,z = A.algebra_generators() + sage: (x*y).maximal_degree() + 2 + sage: (y*x).maximal_degree() + 2 + sage: A.one().maximal_degree() + 0 + sage: A.zero().maximal_degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + sage: (A.one()+x).maximal_degree() + 1 + + TESTS:: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S.zero().degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + """ + if self.is_zero(): + raise ValueError("the zero element does not have a well-defined degree") + degree_on_basis = self.parent().degree_on_basis + return max(degree_on_basis(m) for m in self.support()) def homogeneous_component(self, n): """ From 79894b4c5b248281fbba1b932171b18a59e5b137 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 23 Nov 2014 17:55:25 -0800 Subject: [PATCH 0038/1872] filtered_modules(_with_basis).py reviewed -- see TODOs --- src/sage/algebras/associated_graded.py | 2 +- .../categories/filtered_modules_with_basis.py | 159 ++++++++++++++++-- 2 files changed, 146 insertions(+), 15 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index bc75474a798..f286964aa95 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -257,7 +257,7 @@ def algebra_generators(self): def degree_on_basis(self, x): """ - Return the degree on the basis element indexed by ``x``. + Return the degree of the basis element indexed by ``x``. EXAMPLES:: diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 6feee58383e..326a099fcfb 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -16,6 +16,10 @@ (aka the `i`-*th homogeneous component*) of the filtered module with basis `M`; the elements of this submodule are referred to as *homogeneous elements of degree* `i`. + +See the class documentation +:class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis` +for further details. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw @@ -72,7 +76,7 @@ class FilteredModulesWithBasis(FilteredModulesCategory): the contract of a :class:`CombinatorialFreeModule` (most likely by inheriting from it). It should also have the indexing set `J` encoded as its ``_indices`` attribute, - and ``_indices.subset(basis=i)`` should yield the subset + and ``_indices.subset(size=i)`` should yield the subset `J_i` (as an iterable). If the latter conditions are not satisfied, then :meth:`basis` must be overridden. @@ -81,6 +85,11 @@ class FilteredModulesWithBasis(FilteredModulesCategory): This deserves to be handled better, and the contracts involved might also profit from some explicit writing-up. + What else should be part of the requirements for + inheriting from :class:`FilteredModulesWithBasis`? + At least having a ``degree_on_basis`` method? Is that + enough? + EXAMPLES:: sage: C = ModulesWithBasis(ZZ).Filtered(); C @@ -123,18 +132,57 @@ def basis(self, d=None): whole module which consists only of the basis vectors lying in `F_d \setminus \bigcup_{i Date: Sun, 23 Nov 2014 19:55:05 -0800 Subject: [PATCH 0039/1872] looked through clifford_algebra and filtered_algebras*; many TODOs left --- src/sage/algebras/clifford_algebra.py | 60 +++++++- .../filtered_algebras_with_basis.py | 128 +++++++++++++++++- .../categories/graded_algebras_with_basis.py | 12 ++ 3 files changed, 189 insertions(+), 11 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 40170457e55..8eebd21df6e 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -421,6 +421,17 @@ class CliffordAlgebra(CombinatorialFreeModule): canonical isomorphism. The inclusion `i` is commonly used to identify `V` with a vector subspace of `Cl(V)`. + The Clifford algebra `Cl(V, Q)` is a `\ZZ_2`-graded algebra + (where `\ZZ_2 = \ZZ / 2 \ZZ`); this grading is determined by + placing all elements of `V` in degree `1`. It is also an + `\NN`-filtered algebra, with the filtration too being defined + by placing all elements of `V` in degree `1`. Due to current + limitations of the category framework, Sage can consider + either the grading or the filtration but not both at the same + time (though one can introduce two equal Clifford algebras, + one filtered and the other graded); the ``graded`` parameter + determines which of them is to be used. + The Clifford algebra also can be considered as a covariant functor from the category of vector spaces equipped with quadratic forms to the category of algebras. In fact, if `(V, Q)` and `(W, R)` @@ -481,11 +492,6 @@ class CliffordAlgebra(CombinatorialFreeModule): a*d sage: d*c*b*a + a + 4*b*c a*b*c*d + 4*b*c + a - - .. WARNING:: - - The Clifford algebra is not graded, but instead filtered. This - will be changed once :trac:`17096` is finished. """ @staticmethod def __classcall_private__(cls, Q, names=None, graded=True): @@ -740,6 +746,38 @@ def _element_constructor_(self, x): sage: Cl3 = CliffordAlgebra(Q3, names='xyz') # different syntax for a change sage: Cl3( M((1,-3,2)) ) x + 2*z + + Conversions work between the filtered and the graded Clifford + algebra for the same form: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,4,3,5,6]) + sage: Cl = CliffordAlgebra(Q); Cl + The graded Clifford algebra of the Quadratic form in 3 variables + over Integer Ring with coefficients: + [ 1 2 4 ] + [ * 3 5 ] + [ * * 6 ] + sage: Cl2 = CliffordAlgebra(Q, graded=False); Cl2 + The filtered Clifford algebra of the Quadratic form in 3 variables + over Integer Ring with coefficients: + [ 1 2 4 ] + [ * 3 5 ] + [ * * 6 ] + sage: Cl == Cl2 + False + sage: x,y,z = Cl.gens() + sage: a = (x+y)*(x+z) - 2*x + 3; a + -e0*e1 + e0*e2 + e1*e2 - 2*e0 + 6 + sage: Cl2(a) + -e0*e1 + e0*e2 + e1*e2 - 2*e0 + 6 + sage: Cl(Cl2(a)) == a + True + + .. TODO:: + + These conversions don't work. You might not want a coercion + from the graded Cl into the filtered Cl (although I don't + see why not), but a conversion should exist! """ # This is the natural lift morphism of the underlying free module if x in self.free_module(): @@ -910,6 +948,10 @@ def graded_algebra(self): sage: Cl. = CliffordAlgebra(Q, graded=False) sage: Cl.graded_algebra() The exterior algebra of rank 3 over Integer Ring + + .. TODO:: + + Doctest that the three methods do what they should. """ if self._graded: return self @@ -1104,6 +1146,9 @@ def lift_module_morphism(self, m, names=None): remove_zeros=True ) for i in x) cat = AlgebrasWithBasis(self.base_ring()).Filtered() + # .. TODO:: + # And if the Clifford is graded, we don't use .Graded()? + # Also, why self.base_ring() and not self.base_ring().category()? return Cl.module_morphism(on_basis=f, codomain=self, category=cat) def lift_isometry(self, m, names=None): @@ -1170,6 +1215,9 @@ def lift_isometry(self, m, names=None): for i in x) cat = AlgebrasWithBasis(self.base_ring()).Filtered() + # .. TODO:: + # And if the Clifford is graded, we don't use .Graded()? + # Also, why self.base_ring() and not self.base_ring().category()? return self.module_morphism(on_basis=f, codomain=Cl, category=cat) # This is a general method for finite dimensional algebras with bases @@ -1619,6 +1667,8 @@ def lift_morphism(self, phi, names=None): remove_zeros=True ) for i in x) return self.module_morphism(on_basis=f, codomain=E, category=GradedHopfAlgebrasWithBasis(R)) + # .. TODO:: + # not R.category()? def volume_form(self): """ diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 7756d5a3a52..7acfb205a1c 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -23,6 +23,14 @@ class FilteredAlgebrasWithBasis(FilteredModulesCategory): The category of filtered algebras with a distinguished homogeneous basis. + A filtered algebra with basis over a commutative ring `R` + is a filtered algebra over `R` endowed with the structure + of a filtered module with basis (with the same underlying + filtered-module structure). See + :class:`~sage.categories.filtered_algebras.FilteredAlgebras` and + :class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis` + for these two notions. + EXAMPLES:: sage: C = AlgebrasWithBasis(ZZ).Filtered(); C @@ -38,12 +46,48 @@ class FilteredAlgebrasWithBasis(FilteredModulesCategory): """ class ParentMethods: def graded_algebra(self): - """ + r""" Return the associated graded algebra to ``self``. See :class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra` for the definition and the properties of this. + If the filtered algebra ``self`` with basis is called `A`, + then this method returns `\operatorname{gr} A`. The method + :meth:`to_graded_conversion` returns the canonical + `R`-module isomorphism `A \to \operatorname{gr} A` induced + by the basis of `A`, and the method + :meth:`from_graded_conversion` returns the inverse of this + isomorphism. The method :meth:`projection` projects + elements of `A` onto `\operatorname{gr} A` according to + their place in the filtration on `A`. + + .. WARNING:: + + When not overridden, this method returns the default + implementation of an associated graded algebra -- + namely, ``AssociatedGradedAlgebra(self)``, where + ``AssociatedGradedAlgebra`` is + :class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra`. + But many instances of :class:`FilteredAlgebrasWithBasis` + override this method, as the associated graded algebra + often is (isomorphic) to a simpler object (for instance, + the associated graded algebra of a graded algebra can be + identified with the graded algebra itself). Generic code + that uses associated graded algebras (such as the code + of the :meth:`induced_graded_map` method below) should + make sure to only communicate with them via the + :meth:`to_graded_conversion`, + :meth:`from_graded_conversion` and + :meth:`from_graded_conversion` methods. Similarly, when + overriding :meth:`graded_algebra`, make sure to + accordingly redefine these three methods, unless their + definitions below still apply to your case (this will + happen whenever the basis of your :meth:`graded_algebra` + has the same indexing set as ``self``, and the partition + of this indexing set according to degree is the same as + for ``self``). + EXAMPLES:: sage: A = AlgebrasWithBasis(ZZ).Filtered().example() @@ -60,7 +104,8 @@ def graded_algebra(self): def to_graded_conversion(self): r""" Return the canonical `R`-module isomorphism - `A \to \operatorname{gr} A` induced by the basis of `A`. + `A \to \operatorname{gr} A` induced by the basis of `A` + (where `A = ` ``self``). This is an isomorphism of `R`-modules, not of algebras. See the class documentation :class:`AssociatedGradedAlgebra`. @@ -87,7 +132,8 @@ def from_graded_conversion(self): r""" Return the inverse of the canonical `R`-module isomorphism `A \to \operatorname{gr} A` induced by the basis of `A` - (that is a map `\operatorname{gr} A \to A`). + (where `A = ` ``self``). This inverse is an isomorphism + `\operatorname{gr} A \to A`. This is an isomorphism of `R`-modules, not of algebras. See the class documentation :class:`AssociatedGradedAlgebra`. @@ -115,7 +161,7 @@ def projection(self, i): r""" Return the `i`-th projection `p_i : F_i \to G_i` (in the notations of the class documentation - :class:`AssociatedGradedAlgebra`). + :class:`AssociatedGradedAlgebra`, where `A = ` ``self``). This method actually does not return the map `p_i` itself, but an extension of `p_i` to the whole `R`-module `A`. @@ -124,7 +170,8 @@ def projection(self, i): projection of the graded `R`-module `\operatorname{gr} A` onto its `i`-th graded component `G_i`. The codomain of this map is `\operatorname{gr} A`, although its actual - image is `G_i`. + image is `G_i`. The map `p_i` is obtained from this map + by restricting its domain to `F_i` and its image to `G_i`. EXAMPLES:: @@ -141,10 +188,79 @@ def projection(self, i): base_zero = self.base_ring().zero() base_one = self.base_ring().one() grA = self.graded_algebra() - proj = lambda x: (base_one if grA.degree_on_basis(x) == i + proj = lambda x: (base_one if self.degree_on_basis(x) == i else base_zero) return self.module_morphism(diagonal=proj, codomain=grA) + def induced_graded_map(self, other, f): + r""" + Return the graded linear map between the associated graded + algebras of ``self`` and ``other`` canonically induced by + the filtration-preserving map ``f : self -> other``. + + Let `A` and `B` be two filtered algebras with basis, and let + `(F_i)_{i \in I}` and `(G_i)_{i \in I}` be their + filtrations. Let `f : A \to B` be a linear map which + preserves the filtration (i.e., satisfies `f(F_i) \subseteq + G_i` for all `i \in I`). Then, there is a canonically + defined graded linear map + `\operatorname{gr} f : \operatorname{gr} A \to + \operatorname{gr} B` which satisfies + + .. MATH:: + + (\operatorname{gr} f) (p_i(a)) = p_i(f(a)) + \qquad \text{for all } i \in I \text{ and } a \in F_i , + + where the `p_i` on the left hand side is the canonical + projection from `F_i` onto the `i`-th graded component + of `\operatorname{gr} A`, while the `p_i` on the right + hand side is the canonical projection from `G_i` onto + the `i`-th graded component of `\operatorname{gr} B`. + + INPUT: + + - ``other`` -- a filtered algebra with basis + + - ``f`` -- a filtration-preserving linear map from ``self`` + to ``other`` (can be given as a morphism or as a function) + + OUTPUT: + + The graded linear map `\operatorname{gr} f`. + + EXAMPLES: + + .. TODO:: + + doctests. Currently, Clifford algebras seem the most + appropriate. But need also trivial test with graded + algebra. + """ + grA = self.graded_algebra() + grB = other.graded_algebra() + from sage.categories.graded_modules_with_basis import GradedModulesWithBasis + cat = GradedModulesWithBasis(self.base_ring()) + from_gr = self.from_graded_conversion() + def on_basis(m): + i = grA.degree_on_basis(m) + return grB.projection(i)(f(from_gr(grA.monomial(m)))) + return grA.module_morphism(on_basis=on_basis, + codomain=grB, category=cat) + # If we could assume that the projection of the basis + # element of ``self`` indexed by an index ``m`` is the + # basis element of ``grA`` indexed by ``m``, then this + # could go faster: + # + # def on_basis(m): + # i = grA.degree_on_basis(m) + # return grB.projection(i)(f(self.monomial(m))) + # return grA.module_morphism(on_basis=on_basis, + # codomain=grB, category=cat) + # + # But this assumption might come back to bite us in the + # ass one day. What do you think? + class ElementMethods: pass diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index d0ff3160643..b43ba1416c4 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -35,11 +35,23 @@ def graded_algebra(self): """ Return the associated graded algebra to ``self``. + This is ``self``, because ``self`` is already graded. + See :meth:`~sage.categories.filtered_algebras_with_basis.FilteredAlgebrasWithBasis.graded_algebra` + for the general behavior of this method, and see + :class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra` + for the definition and properties of associated graded + algebras. + EXAMPLES:: sage: m = SymmetricFunctions(QQ).m() sage: m.graded_algebra() is m True + + .. TODO:: + + Add examples showing that the three methods are + overridden correctly. """ return self From 2a62c3b093a2a991422f8c4f261d1a9d5ac6e059 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 23 Nov 2014 20:10:20 -0800 Subject: [PATCH 0040/1872] lift_* methods in algebras/clifford_algebra.py should remember the graded-filtered choice --- src/sage/algebras/clifford_algebra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 8eebd21df6e..e96f98ec7a0 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1139,7 +1139,7 @@ def lift_module_morphism(self, m, names=None): if Q == self._quadratic_form and names is None: Cl = self else: - Cl = CliffordAlgebra(Q, names) + Cl = CliffordAlgebra(Q, names, graded=self._graded) n = self._quadratic_form.dim() f = lambda x: self.prod(self._from_dict( {(j,): m[j,i] for j in range(n)}, @@ -1207,7 +1207,7 @@ def lift_isometry(self, m, names=None): else: if names is None: names = 'e' - Cl = CliffordAlgebra(Q, names) + Cl = CliffordAlgebra(Q, names, graded=self._graded) n = Q.dim() f = lambda x: Cl.prod(Cl._from_dict( {(j,): m[j,i] for j in range(n)}, From 15cf0dce22ece06760fdd270257f98757625f0a9 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 23 Nov 2014 20:25:26 -0800 Subject: [PATCH 0041/1872] fix and a first doctest for induced_graded_map --- .../filtered_algebras_with_basis.py | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 7acfb205a1c..68455fd1054 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -231,11 +231,67 @@ def induced_graded_map(self, other, f): EXAMPLES: + Let us compute `\operatorname{gr} f` for a map `f` between + two Clifford algebras:: + + sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) + sage: B = CliffordAlgebra(Q, names=['u','v'], graded=False); B + The filtered Clifford algebra of the Quadratic form in 2 + variables over Integer Ring with coefficients: + [ 1 2 ] + [ * 3 ] + sage: m = Matrix(ZZ, [[1, 2], [1, -1]]) + sage: f = B.lift_module_morphism(m, names=['x','y']) + sage: A = f.domain(); A + The filtered Clifford algebra of the Quadratic form in 2 + variables over Integer Ring with coefficients: + [ 6 0 ] + [ * 3 ] + sage: x, y = A.gens() + sage: f(x) + u + v + sage: f(y) + 2*u - v + sage: f(x**2) + 6 + sage: f(x*y) + -3*u*v + 3 + sage: grA = A.graded_algebra(); grA + The exterior algebra of rank 2 over Integer Ring + sage: A.to_graded_conversion()(x) + x + sage: A.to_graded_conversion()(y) + y + sage: A.to_graded_conversion()(x*y) + x^y + sage: u = A.to_graded_conversion()(x*y+1); u + x^y + 1 + sage: A.from_graded_conversion()(u) + x*y + 1 + sage: A.projection(2)(x*y+1) + x^y + sage: A.projection(1)(x+2*y-2) + x + 2*y + sage: grf = A.induced_graded_map(B, f); grf + Generic morphism: + From: The exterior algebra of rank 2 over Integer Ring + To: The exterior algebra of rank 2 over Integer Ring + sage: grf(A.to_graded_conversion()(x)) + u + v + sage: grf(A.to_graded_conversion()(y)) + 2*u - v + sage: grf(A.to_graded_conversion()(x**2)) + 6 + sage: grf(A.to_graded_conversion()(x*y)) + -3*u^v + sage: grf(grA.one()) + 1 + .. TODO:: - doctests. Currently, Clifford algebras seem the most + more doctests. Currently, Clifford algebras seem the most appropriate. But need also trivial test with graded - algebra. + algebra. (Maybe not the Clifford one, though.) """ grA = self.graded_algebra() grB = other.graded_algebra() @@ -244,7 +300,8 @@ def induced_graded_map(self, other, f): from_gr = self.from_graded_conversion() def on_basis(m): i = grA.degree_on_basis(m) - return grB.projection(i)(f(from_gr(grA.monomial(m)))) + lifted_img_of_m = f(from_gr(grA.monomial(m))) + return other.projection(i)(lifted_img_of_m) return grA.module_morphism(on_basis=on_basis, codomain=grB, category=cat) # If we could assume that the projection of the basis From 50299560bf500b649aa5bdc3e7c7690fa09e2fb1 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 23 Nov 2014 20:28:47 -0800 Subject: [PATCH 0042/1872] another pitfall documented --- src/sage/categories/filtered_algebras_with_basis.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 68455fd1054..0759a7e8fd0 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -79,7 +79,10 @@ def graded_algebra(self): make sure to only communicate with them via the :meth:`to_graded_conversion`, :meth:`from_graded_conversion` and - :meth:`from_graded_conversion` methods. Similarly, when + :meth:`from_graded_conversion` methods (in particular, + do not expect there to be a conversion from ``self`` + to ``self.graded_algebra()``; this currently does not + work for Clifford algebras). Similarly, when overriding :meth:`graded_algebra`, make sure to accordingly redefine these three methods, unless their definitions below still apply to your case (this will @@ -88,6 +91,13 @@ def graded_algebra(self): of this indexing set according to degree is the same as for ``self``). + .. TODO:: + + Maybe the thing about the conversion from ``self`` + to ``self.graded_algebra()`` at least could be made to + work? (I would still warn the user against ASSUMING + that it must work.) + EXAMPLES:: sage: A = AlgebrasWithBasis(ZZ).Filtered().example() From 292ef5f2a26bff5302a5d97ebf22d34240c78f72 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 23 Nov 2014 21:50:18 -0800 Subject: [PATCH 0043/1872] another doctest --- .../filtered_algebras_with_basis.py | 80 +++++++++++++++++-- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 0759a7e8fd0..a4c753ff99e 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -94,9 +94,12 @@ def graded_algebra(self): .. TODO:: Maybe the thing about the conversion from ``self`` - to ``self.graded_algebra()`` at least could be made to - work? (I would still warn the user against ASSUMING - that it must work.) + to ``self.graded_algebra()`` on the Clifford at least + could be made to work? (I would still warn the user + against ASSUMING that it must work -- as there is + probably no way to guarantee it in all cases, and + we shouldn't require users to mess with + element constructors.) EXAMPLES:: @@ -241,8 +244,75 @@ def induced_graded_map(self, other, f): EXAMPLES: - Let us compute `\operatorname{gr} f` for a map `f` between - two Clifford algebras:: + We start with the universal enveloping algebra of the + Lie algebra `\RR^3` (with the cross product serving as + Lie bracket):: + + sage: A = AlgebrasWithBasis(QQ).Filtered().example(); A + An example of a filtered algebra with basis: the + universal enveloping algebra of Lie algebra of RR^3 + with cross product over Rational Field + sage: M = A.indices(); M + Free abelian monoid indexed by {'x', 'y', 'z'} + sage: x,y,z = [A.basis()[M.gens()[i]] for i in "xyz"] + + Let us define a stupid filtered map from ``A`` to + itself:: + + sage: def map_on_basis(m): + ....: d = m.dict() + ....: i = d.get('x', 0); j = d.get('y', 0); k = d.get('z', 0) + ....: g = (y ** (i+j)) * (z ** k) + ....: if i > 0: + ....: g += i * (x ** (i-1)) * (y ** j) * (z ** k) + ....: return g + sage: f = A.module_morphism(on_basis=map_on_basis, + ....: codomain=A) + sage: f(x) + U['y'] + 1 + sage: f(x*y*z) + U['y']^2*U['z'] + U['y']*U['z'] + sage: f(x*x*y*z) + U['y']^3*U['z'] + 2*U['x']*U['y']*U['z'] + sage: f(A.one()) + 1 + sage: f(y*z) + U['y']*U['z'] + + (There is nothing here that is peculiar to this + universal enveloping algebra; we are only using its + module structure, and we could just as well be using + a polynomial algebra in its stead.) + + We now compute `\operatorname{gr} f` :: + + sage: grA = A.graded_algebra(); grA + Graded Algebra of An example of a filtered algebra with + basis: the universal enveloping algebra of Lie algebra + of RR^3 with cross product over Rational Field + sage: xx, yy, zz = [A.to_graded_conversion()(i) for i in [x, y, z]] + sage: xx+yy*zz + bar(U['y']*U['z']) + bar(U['x']) + sage: grf = A.induced_graded_map(A, f); grf + Generic endomorphism of Graded Algebra of An example + of a filtered algebra with basis: the universal + enveloping algebra of Lie algebra of RR^3 with cross + product over Rational Field + sage: grf(xx) + bar(U['y']) + sage: grf(xx*yy*zz) + bar(U['y']^2*U['z']) + sage: grf(xx*xx*yy*zz) + bar(U['y']^3*U['z']) + sage: grf(grA.one()) + bar(1) + sage: grf(yy*zz) + bar(U['y']*U['z']) + sage: grf(yy*zz-2*yy) + bar(U['y']*U['z']) - 2*bar(U['y']) + + For another example, let us compute `\operatorname{gr} f` for a + map `f` between two Clifford algebras:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: B = CliffordAlgebra(Q, names=['u','v'], graded=False); B From c2e84e1367cbfc47eb7104de654e2ee55caea95d Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 24 Nov 2014 08:04:09 -0800 Subject: [PATCH 0044/1872] remaining doctests for induced_graded_map --- .../filtered_algebras_with_basis.py | 150 +++++++++++++++++- 1 file changed, 144 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index a4c753ff99e..a33d941172a 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -244,6 +244,8 @@ def induced_graded_map(self, other, f): EXAMPLES: + **Example 1.** + We start with the universal enveloping algebra of the Lie algebra `\RR^3` (with the cross product serving as Lie bracket):: @@ -311,6 +313,148 @@ def induced_graded_map(self, other, f): sage: grf(yy*zz-2*yy) bar(U['y']*U['z']) - 2*bar(U['y']) + **Example 2.** + + We shall now construct `\operatorname{gr} f` for a + different map `f` out of the same ``A``; the new map + `f` will lead into a graded algebra already, namely into + the algebra of symmetric functions:: + + sage: h = SymmetricFunctions(QQ).h() + sage: def map_on_basis(m): # redefining map_on_basis + ....: d = m.dict() + ....: i = d.get('x', 0); j = d.get('y', 0); k = d.get('z', 0) + ....: g = (h[1] ** i) * (h[2] ** (floor(j/2))) * (h[3] ** (floor(k/3))) + ....: g += i * (h[1] ** (i+j+k)) + ....: return g + sage: f = A.module_morphism(on_basis=map_on_basis, + ....: codomain=h) # redefining f + sage: f(x) + 2*h[1] + sage: f(y) + h[] + sage: f(z) + h[] + sage: f(y**2) + h[2] + sage: f(x**2) + 3*h[1, 1] + sage: f(x*y*z) + h[1] + h[1, 1, 1] + sage: f(x*x*y*y*z) + 2*h[1, 1, 1, 1, 1] + h[2, 1, 1] + sage: f(A.one()) + h[] + + The algebra ``h`` of symmetric functions in the `h`-basis + is already graded, so its associated graded algebra is + implemented as itself:: + + sage: grh = h.graded_algebra(); grh is h + True + sage: grf = A.induced_graded_map(h, f); grf + Generic morphism: + From: Graded Algebra of An example of a filtered + algebra with basis: the universal enveloping + algebra of Lie algebra of RR^3 with cross + product over Rational Field + To: Symmetric Functions over Rational Field + in the homogeneous basis + sage: grf(xx) + 2*h[1] + sage: grf(yy) + 0 + sage: grf(zz) + 0 + sage: grf(yy**2) + h[2] + sage: grf(xx**2) + 3*h[1, 1] + sage: grf(xx*yy*zz) + h[1, 1, 1] + sage: grf(xx*xx*yy*yy*zz) + 2*h[1, 1, 1, 1, 1] + sage: grf(grA.one()) + h[] + + **Example 3.** + + After having had a graded algebra as the codomain, let us try to + have one as the domain instead. Our new ``f`` will go from ``h`` + to ``A``:: + + sage: def map_on_basis(lam): # redefining map_on_basis + ....: return x ** (sum(lam)) + y ** (len(lam)) + sage: f = h.module_morphism(on_basis=map_on_basis, + ....: codomain=A) # redefining f + sage: f(h[1]) + U['x'] + U['y'] + sage: f(h[2]) + U['x']^2 + U['y'] + sage: f(h[1, 1]) + U['x']^2 + U['y']^2 + sage: f(h[2, 2]) + U['x']^4 + U['y']^2 + sage: f(h[3, 2, 1]) + U['x']^6 + U['y']^3 + sage: f(h.one()) + 2 + sage: grf = h.induced_graded_map(A, f); grf + Generic morphism: + From: Symmetric Functions over Rational Field + in the homogeneous basis + To: Graded Algebra of An example of a filtered + algebra with basis: the universal enveloping + algebra of Lie algebra of RR^3 with cross + product over Rational Field + sage: grf(h[1]) + bar(U['x']) + bar(U['y']) + sage: grf(h[2]) + bar(U['x']^2) + sage: grf(h[1, 1]) + bar(U['x']^2) + bar(U['y']^2) + sage: grf(h[2, 2]) + bar(U['x']^4) + sage: grf(h[3, 2, 1]) + bar(U['x']^6) + sage: grf(h.one()) + 2*bar(1) + + **Example 4.** + + The construct `\operatorname{gr} f` also makes sense when `f` + is a filtration-preserving map between graded algebras. + + sage: def map_on_basis(lam): # redefining map_on_basis + ....: return h[lam] + h[len(lam)] + sage: f = h.module_morphism(on_basis=map_on_basis, + ....: codomain=h) # redefining f + sage: f(h[1]) + 2*h[1] + sage: f(h[2]) + h[1] + h[2] + sage: f(h[1, 1]) + h[1, 1] + h[2] + sage: f(h[2, 1]) + h[2] + h[2, 1] + sage: f(h.one()) + 2*h[] + sage: grf = h.induced_graded_map(h, f); grf + Generic endomorphism of Symmetric Functions over Rational + Field in the homogeneous basis + sage: grf(h[1]) + 2*h[1] + sage: grf(h[2]) + h[2] + sage: grf(h[1, 1]) + h[1, 1] + h[2] + sage: grf(h[2, 1]) + h[2, 1] + sage: grf(h.one()) + 2*h[] + + **Example 5.** + For another example, let us compute `\operatorname{gr} f` for a map `f` between two Clifford algebras:: @@ -366,12 +510,6 @@ def induced_graded_map(self, other, f): -3*u^v sage: grf(grA.one()) 1 - - .. TODO:: - - more doctests. Currently, Clifford algebras seem the most - appropriate. But need also trivial test with graded - algebra. (Maybe not the Clifford one, though.) """ grA = self.graded_algebra() grB = other.graded_algebra() From 03bd4cfb53e24b24c65aada21f08850b40fb5c5c Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 24 Nov 2014 08:13:53 -0800 Subject: [PATCH 0045/1872] possibly controversial: graded_algebra and the three methods forming its interface are now cached_methods --- src/sage/categories/filtered_algebras_with_basis.py | 5 +++++ src/sage/categories/graded_algebras_with_basis.py | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index a33d941172a..4930de1a6d6 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -17,6 +17,7 @@ #****************************************************************************** from sage.categories.filtered_modules import FilteredModulesCategory +from sage.misc.cachefunc import cached_method class FilteredAlgebrasWithBasis(FilteredModulesCategory): """ @@ -45,6 +46,7 @@ class FilteredAlgebrasWithBasis(FilteredModulesCategory): sage: TestSuite(C).run() """ class ParentMethods: + @cached_method def graded_algebra(self): r""" Return the associated graded algebra to ``self``. @@ -114,6 +116,7 @@ def graded_algebra(self): # Maps + @cached_method def to_graded_conversion(self): r""" Return the canonical `R`-module isomorphism @@ -141,6 +144,7 @@ def to_graded_conversion(self): return self.module_morphism(diagonal=lambda x: base_one, codomain=self.graded_algebra()) + @cached_method def from_graded_conversion(self): r""" Return the inverse of the canonical `R`-module isomorphism @@ -170,6 +174,7 @@ def from_graded_conversion(self): return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, codomain=self) + @cached_method def projection(self, i): r""" Return the `i`-th projection `p_i : F_i \to G_i` (in the diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index b43ba1416c4..c55c3671261 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -10,6 +10,7 @@ #****************************************************************************** from sage.categories.graded_modules import GradedModulesCategory +from sage.misc.cachefunc import cached_method class GradedAlgebrasWithBasis(GradedModulesCategory): """ @@ -31,6 +32,7 @@ class GradedAlgebrasWithBasis(GradedModulesCategory): class ParentMethods: # This needs to be copied in GradedAlgebras because we need to have # FilteredAlgebrasWithBasis as an extra super category + @cached_method def graded_algebra(self): """ Return the associated graded algebra to ``self``. @@ -55,6 +57,14 @@ def graded_algebra(self): """ return self + # .. TODO:: + # Possibly override ``to_graded_conversion`` and + # ``from_graded_conversion`` with identity morphisms? + # I have to admit I don't know the right way to construct + # identity morphisms other than using the identity matrix. + # Also, ``projection`` could be overridden by, well, a + # projection. + class ElementMethods: pass From 8a747c073e706950d1b14e77458539e126ff0550 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 24 Nov 2014 08:37:21 -0800 Subject: [PATCH 0046/1872] further edits --- .../filtered_algebras_with_basis.py | 4 +-- src/sage/categories/graded_algebras.py | 3 +++ .../categories/graded_algebras_with_basis.py | 25 ++++++++++++++++--- src/sage/categories/graded_modules.py | 15 +++++------ 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 4930de1a6d6..22832812521 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -81,7 +81,7 @@ def graded_algebra(self): make sure to only communicate with them via the :meth:`to_graded_conversion`, :meth:`from_graded_conversion` and - :meth:`from_graded_conversion` methods (in particular, + :meth:`projection` methods (in particular, do not expect there to be a conversion from ``self`` to ``self.graded_algebra()``; this currently does not work for Clifford algebras). Similarly, when @@ -428,7 +428,7 @@ def induced_graded_map(self, other, f): **Example 4.** The construct `\operatorname{gr} f` also makes sense when `f` - is a filtration-preserving map between graded algebras. + is a filtration-preserving map between graded algebras. :: sage: def map_on_basis(lam): # redefining map_on_basis ....: return h[lam] + h[len(lam)] diff --git a/src/sage/categories/graded_algebras.py b/src/sage/categories/graded_algebras.py index 48f47f4068b..d03f648d499 100644 --- a/src/sage/categories/graded_algebras.py +++ b/src/sage/categories/graded_algebras.py @@ -32,6 +32,9 @@ def graded_algebra(self): """ Return the associated graded algebra to ``self``. + Since ``self`` is already graded, this just returns + ``self``. + EXAMPLES:: sage: m = SymmetricFunctions(QQ).m() diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index c55c3671261..f6b8dce4513 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -50,10 +50,29 @@ def graded_algebra(self): sage: m.graded_algebra() is m True - .. TODO:: + TESTS: - Add examples showing that the three methods are - overridden correctly. + Let us check that the three methods + :meth:`to_graded_conversion`, :meth:`from_graded_conversion` + and :meth:`projection` (which form the interface of the + associated graded algebra) work correctly here:: + + sage: to_gr = m.to_graded_conversion() + sage: from_gr = m.from_graded_conversion() + sage: m[2] == to_gr(m[2]) == from_gr(m[2]) + True + sage: u = 3*m[1] - (1/2)*m[3] + sage: u == to_gr(u) == from_gr(u) + True + sage: m.zero() == to_gr(m.zero()) == from_gr(m.zero()) + True + sage: p2 = m.projection(2) + sage: p2(m[2] - 4*m[1,1] + 3*m[1] - 2*m[[]]) + -4*m[1, 1] + m[2] + sage: p2(4*m[1]) + 0 + sage: p2(m.zero()) == m.zero() + True """ return self diff --git a/src/sage/categories/graded_modules.py b/src/sage/categories/graded_modules.py index 5c34438260b..7a843eb3dc5 100644 --- a/src/sage/categories/graded_modules.py +++ b/src/sage/categories/graded_modules.py @@ -124,22 +124,23 @@ def _repr_object_names(self): @classmethod def default_super_categories(cls, category, *args): r""" - Return the default super categories of ``category.Graded()`` + Return the default super categories of ``category.Graded()``. - Mathematical meaning: every graded category is a filtered category - with the (implicit) filtration of `F_i = \bigoplus_{j \leq i} G_j`. + Mathematical meaning: every graded object (module, algebra, + etc.) is a filtered object with the (implicit) filtration + defined by `F_i = \bigoplus_{j \leq i} G_j`. INPUT: - - ``cls`` -- the class ``QuotientsCategory`` - - ``category`` -- a category `Cat` + - ``cls`` -- the class ``GradedModulesCategory`` + - ``category`` -- a category OUTPUT: a (join) category In practice, this returns ``category.Filtered()``, joined together with the result of the method :meth:`RegressiveCovariantConstructionCategory.default_super_categories() ` - (that is the join of ``category`` and ``cat.Filtered()`` for + (that is the join of ``category.Filtered()`` and ``cat`` for each ``cat`` in the super categories of ``category``). EXAMPLES: @@ -167,7 +168,7 @@ class GradedModules(GradedModulesCategory): The category of graded modules. We consider every graded module `M = \bigoplus_i M_i` as a - filtered module under the (natural) filtration of + filtered module under the (natural) filtration given by .. MATH:: From 7525680af6c574932b8a1323e3fb544fa8ab3bb3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 27 Nov 2014 12:36:40 -0800 Subject: [PATCH 0047/1872] Fixing things and added full coverage. --- src/sage/combinat/colored_permutations.py | 635 ++++++++++++++++++++-- 1 file changed, 591 insertions(+), 44 deletions(-) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 0a767ebe7b6..c2b9d6c8e84 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -3,46 +3,116 @@ """ from sage.categories.groups import Groups from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.structure.element import Element +from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups +from sage.structure.element import MultiplicativeGroupElement from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method +from sage.misc.misc_c import prod from sage.combinat.permutation import Permutations from sage.combinat.cartesian_product import CartesianProduct from sage.matrix.constructor import diagonal_matrix from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.number_field.number_field import CyclotomicField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.all import ZZ -class ColoredPermutation(Element): +class ColoredPermutation(MultiplicativeGroupElement): """ A colored permutation. """ def __init__(self, parent, colors, perm): """ Initialize ``self``. + + TESTS:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: TestSuite(s1*s2*t).run() """ self._colors = tuple(colors) self._perm = perm - Element.__init__(self, parent=parent) + MultiplicativeGroupElement.__init__(self, parent=parent) def _repr_(self): """ Return a string representation of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: s1*s2*t + [[1, 0, 0], [3, 1, 2]] """ return repr([list(self._colors), self._perm]) + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: latex(s1*s2*t) + [3_{1}, 1_{0}, 2_{0}] + """ + ret = "[" + ret += ", ".join("{}_{{{}}}".format(x, self._colors[i]) + for i,x in enumerate(self._perm)) + return ret + "]" + def _mul_(self, other): """ Multiply ``self`` and ``other``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: s1*s2*s1 == s2*s1*s2 + True + """ + colors = tuple(self._colors[i] + other._colors[val-1] #-1 for indexing + for i,val in enumerate(self._perm)) + p = self._perm._left_to_right_multiply_on_right(other._perm) + return self.__class__(self.parent(), colors, p) + + def __invert__(self): + """ + Return the inverse of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: ~t + [[0, 0, 3], [1, 2, 3]] + sage: all(x * ~x == C.one() for x in C.gens()) + True """ - colors = tuple(self._colors[i] + other._colors[val-1] - for i,val in enumerate(~self._perm)) - return self.__class__(self.parent(), colors, self._perm * other._perm) + ip = ~self._perm + return self.__class__(self.parent(), + tuple([-self._colors[i-1] for i in ip]), #-1 for indexing + ip) def __eq__(self, other): """ Check equality. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: s1*s2*s1 == s2*s1*s2 + True + sage: t^4 == C.one() + True + sage: s1*s2 == s2*s1 + False """ if not isinstance(other, ColoredPermutation): return False @@ -53,12 +123,29 @@ def __eq__(self, other): def __ne__(self, other): """ Check inequality. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: s1*s2*s1 != s2*s1*s2 + False + sage: s1*s2 != s2*s1 + True """ return not self.__eq__(other) def __iter__(self): """ Iterate over ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: x = s1*s2*t + sage: list(x) + [(1, 3), (0, 1), (0, 2)] """ for i,p in enumerate(self._perm): yield (self._colors[i], p) @@ -66,28 +153,71 @@ def __iter__(self): def one_line_form(self): """ Return the one line form of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: x = s1*s2*t + sage: x + [[1, 0, 0], [3, 1, 2]] + sage: x.one_line_form() + [(1, 3), (0, 1), (0, 2)] """ return list(self) def colors(self): """ Return the colors of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: x = s1*s2*t + sage: x.colors() + [1, 0, 0] """ return list(self._colors) def permutation(self): """ Return the permutation of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: x = s1*s2*t + sage: x.permutation() + [3, 1, 2] """ return self._perm def to_matrix(self): """ Return a matrix of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: x = s1*s2*t*s2; x.one_line_form() + [(1, 2), (0, 1), (0, 3)] + sage: M = x.to_matrix(); M + [ 0 1 0] + [zeta4 0 0] + [ 0 0 1] + + The matrix multiplication is in the *opposite* order:: + + sage: M == s2.to_matrix()*t.to_matrix()*s2.to_matrix()*s1.to_matrix() + True """ Cp = CyclotomicField(self.parent()._m) g = Cp.gen() - return diagonal_matrix(Cp, [g**i for i in self._colors]) * self._perm.to_matrix() + D = diagonal_matrix(Cp, [g**i for i in self._colors]) + return self._perm.to_matrix() * D class ColoredPermutations(Parent, UniqueRepresentation): r""" @@ -103,35 +233,73 @@ class ColoredPermutations(Parent, UniqueRepresentation): .. MATH:: ((s_1, \ldots s_n), \sigma) \cdot ((t_1, \ldots, t_n), \tau) - = ((s_1 t_{\sigma^{-1}(1)}, \ldots, s_n t_{\sigma^{-1}(n)}), - \sigma \tau). + = ((s_1 t_{\sigma(1)}, \ldots, s_n t_{\sigma(n)}), \tau \sigma). + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3); C + 4-colored permutations of size 3 + sage: s1,s2,t = C.gens() + sage: (s1, s2, t) + ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]]) + sage: s1*s2 + [[0, 0, 0], [3, 1, 2]] + sage: s1*s2*s1 == s2*s1*s2 + True + sage: t^4 == C.one() + True + sage: s2*t*s2 + [[0, 1, 0], [1, 2, 3]] REFERENCES: - :wikipedia:`Generalized_symmetric_group` - :wikipedia:`Complex_reflection_group` """ - def __init__(self, m, n): + def __init__(self, m, n, category=None): """ Initialize ``self``. EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: TestSuite(C).run() + sage: C = ColoredPermutations(2, 3) + sage: TestSuite(C).run() + sage: C = ColoredPermutations(1, 3) + sage: TestSuite(C).run() """ + if m <= 0: + raise ValueError("m must be a positive integer") self._m = m self._n = n self._C = IntegerModRing(self._m) self._P = Permutations(self._n) - Parent.__init__(self, category=(Groups(), FiniteEnumeratedSets())) + if category is None: + category = (Groups(), FiniteEnumeratedSets()) + Parent.__init__(self, category=category) def _repr_(self): """ Return a string representation of ``self``. + + EXAMPLES:: + + sage: ColoredPermutations(4, 3) + 4-colored permutations of size 3 """ return "{}-colored permutations of size {}".format(self._m, self._n) + @cached_method def one(self): """ Return the identity element of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: C.one() + [[0, 0, 0], [1, 2, 3]] """ return self.element_class(self, [self._C.zero()]*self._n, self._P.identity()) @@ -139,6 +307,14 @@ def one(self): def gens(self): """ Return the generators of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: C.gens() + ([[0, 0, 0], [2, 1, 3]], + [[0, 0, 0], [1, 3, 2]], + [[0, 0, 1], [1, 2, 3]]) """ zero = [self._C.zero()]*self._n g = [] @@ -154,6 +330,16 @@ def gens(self): def matrix_group(self): """ Return the matrix group corresponding to ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: C.matrix_group() + Matrix group over Cyclotomic Field of order 4 and degree 2 with 3 generators ( + [0 1 0] [1 0 0] [ 1 0 0] + [1 0 0] [0 0 1] [ 0 1 0] + [0 0 1], [0 1 0], [ 0 0 zeta4] + ) """ from sage.groups.matrix_gps.finitely_generated import MatrixGroup return MatrixGroup([g.to_matrix() for g in self.gens()]) @@ -161,6 +347,14 @@ def matrix_group(self): def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. + + TESTS:: + + sage: C = ColoredPermutations(4, 3) + sage: x = C([(2,1), (3,3), (3,2)]); x + [[2, 3, 3], [1, 3, 2]] + sage: x == C([[2,3,3], [1,3,2]]) + True """ if isinstance(x, list): if isinstance(x[0], tuple): @@ -180,6 +374,19 @@ def _element_constructor_(self, x): def __iter__(self): """ Iterate over ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(2, 2) + sage: [x for x in C] + [[[0, 0], [1, 2]], + [[0, 1], [1, 2]], + [[1, 0], [1, 2]], + [[1, 1], [1, 2]], + [[0, 0], [2, 1]], + [[0, 1], [2, 1]], + [[1, 0], [2, 1]], + [[1, 1], [2, 1]]] """ C = CartesianProduct(*[self._C]*self._n) for p in self._P: @@ -189,6 +396,14 @@ def __iter__(self): def cardinality(self): """ Return the cardinality of ``self``. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: C.cardinality() + 384 + sage: C.cardinality() == 4**3 * factorial(3) + True """ return self._m**self._n * self._P.cardinality() @@ -198,6 +413,18 @@ def rank(self): The rank of a complex reflection group is equal to the dimension of the complex vector space the group acts on. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 12) + sage: C.rank() + 12 + sage: C = ColoredPermutations(7, 4) + sage: C.rank() + 4 + sage: C = ColoredPermutations(1, 4) + sage: C.rank() + 3 """ if self._m == 1: return self._n - 1 @@ -216,8 +443,8 @@ def degrees(self): EXAMPLES:: - sage: CP = ColoredPermutations(4, 3) - sage: CP.degrees() + sage: C = ColoredPermutations(4, 3) + sage: C.degrees() [4, 8, 12] sage: S = ColoredPermutations(1, 3) sage: S.degrees() @@ -226,7 +453,7 @@ def degrees(self): We now check that the product of the degrees is equal to the cardinality of ``self``:: - sage: prod(CP.degrees()) == CP.cardinality() + sage: prod(C.degrees()) == C.cardinality() True sage: prod(S.degrees()) == S.cardinality() True @@ -241,13 +468,37 @@ def codegrees(self): Let `G` be a complex reflection group. The codegrees `d_1^* \leq d_2^* \leq \cdots \leq d_{\ell}^*` of `G` can be - defined in terms of the fixed point polynomial: + defined by: + + \prod_{i=1}^{\ell} (q - d_i^* - 1) + = \sum_{g \in G} \det(g) q^{\dim(V^g)}, - f_G(q) = \prod_{i=1}^{\ell} (q - d_i^* - 1). + where `V` is the natural complex vector space that `G` acts on. If `m = 1`, then we are in the special case of the symmetric group and the codegrees are `(n-2, n-3, \ldots 1, 0)`. Otherwise the degrees are `((n-1)m, (n-2)m, \ldots, m, 0)`. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: C.codegrees() + [8, 4, 0] + sage: S = ColoredPermutations(1, 3) + sage: S.codegrees() + [1, 0] + + TESTS: + + We check the polynomial identity:: + + sage: R. = ZZ[] + sage: C = ColoredPermutations(3, 2) + sage: f = prod(q - ds - 1 for ds in C.codegrees()) + sage: d = lambda x: sum(1 for e in x.to_matrix().eigenvalues() if e == 1) + sage: g = sum(det(x.to_matrix()) * q**d(x) for x in C) + sage: f == g + True """ if self._m == 1: # Special case for the usual symmetric group return list(reversed(range(self._n-1))) @@ -259,10 +510,22 @@ def number_reflection_hyperplanes(self): The number of reflection hyperplanes of a complex reflection group is equal to the sume of the codegrees plus the rank. + + EXAMPLES:: + + sage: C = ColoredPermutations(1, 2) + sage: C.number_reflection_hyperplanes() + 1 + sage: C = ColoredPermutations(1, 3) + sage: C.number_reflection_hyperplanes() + 3 + sage: C = ColoredPermutations(4, 12) + sage: C.number_reflection_hyperplanes() + 276 """ return sum(self.codegrees()) + self.rank() - def fixed_point_polynomial(self, q): + def fixed_point_polynomial(self, q=None): r""" The fixed point polynomial of ``self``. @@ -279,7 +542,32 @@ def fixed_point_polynomial(self, q): .. MATH:: f_G(q) = \prod_{i=1}^{\ell} (q + d_i - 1). + + INPUT: + + - ``q`` -- (default: the generator of ``ZZ['q']``) the parameter `q` + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: C.fixed_point_polynomial() + q^3 + 21*q^2 + 131*q + 231 + + sage: S = ColoredPermutations(1, 3) + sage: S.fixed_point_polynomial() + q^2 + 3*q + 2 + + TESTS: + + We check the against the degrees and codegrees:: + + sage: R. = ZZ[] + sage: C = ColoredPermutations(4, 3) + sage: C.fixed_point_polynomial(q) == prod(q + d - 1 for d in C.degrees()) + True """ + if q is None: + q = PolynomialRing(ZZ, 'q').gen(0) return prod(q + d - 1 for d in self.degrees()) def is_well_generated(self): @@ -288,7 +576,19 @@ def is_well_generated(self): A complex reflection group `G` is well-generated if it is generated by `\ell` reflections. Equivalently, `G` is well-generated - if `d_i + d_i^* = d_{\ell}` for all `1 \leq i \leq \ell` + if `d_i + d_i^* = d_{\ell}` for all `1 \leq i \leq \ell`. + + EXAMPLES:: + + sage: C = ColoredPermutations(4, 3) + sage: C.is_well_generated() + True + sage: C = ColoredPermutations(2, 8) + sage: C.is_well_generated() + True + sage: C = ColoredPermutations(1, 4) + sage: C.is_well_generated() + True """ deg = self.degrees() dstar = self.codegrees() @@ -303,17 +603,78 @@ class SignedPermutation(ColoredPermutation): """ A signed permutation. """ + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: s1,s2,s3,s4 = S.gens() + sage: s4*s1*s2*s3*s4 + [-4, 1, 2, -3] + """ + return repr(list(self)) + + _latex_ = _repr_ + def _mul_(self, other): """ Multiply ``self`` and ``other``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: s1,s2,s3,s4 = S.gens() + sage: x = s4*s1*s2*s3*s4; x + [-4, 1, 2, -3] + sage: x * x + [3, -4, 1, -2] + + :: + + sage: s1*s2*s1 == s1*s2*s1 + True + sage: s3*s4*s3*s4 == s4*s3*s4*s3 + True + """ + colors = tuple(self._colors[i] * other._colors[val-1] #-1 for indexing + for i,val in enumerate(self._perm)) + p = self._perm._left_to_right_multiply_on_right(other._perm) + return self.__class__(self.parent(), colors, p) + + def inverse(self): + """ + Return the inverse of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: s1,s2,s3,s4 = S.gens() + sage: x = s4*s1*s2*s3*s4 + sage: ~x + [2, 3, -4, -1] + sage: x * ~x == S.one() + True """ - colors = tuple(self._colors[i] * other._colors[val-1] - for i,val in enumerate(~self._perm)) - return self.__class__(self.parent(), colors, self._perm * other._perm) + ip = ~self._perm + return self.__class__(self.parent(), + tuple([self._colors[i-1] for i in ip]), #-1 for indexing + ip) + + __invert__ = inverse def __iter__(self): """ Iterate over ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: s1,s2,s3,s4 = S.gens() + sage: x = s4*s1*s2*s3*s4 + sage: [a for a in x] + [-4, 1, 2, -3] """ for i,p in enumerate(self._perm): yield self._colors[i] * p @@ -321,16 +682,52 @@ def __iter__(self): def to_matrix(self): """ Return a matrix of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: s1,s2,s3,s4 = S.gens() + sage: x = s4*s1*s2*s3*s4 + sage: M = x.to_matrix(); M + [ 0 1 0 0] + [ 0 0 1 0] + [ 0 0 0 -1] + [-1 0 0 0] + + The matrix multiplication is in the *opposite* order:: + + sage: m1,m2,m3,m4 = [g.to_matrix() for g in S.gens()] + sage: M == m4 * m3 * m2 * m1 * m4 + True + """ + return self._perm.to_matrix() * diagonal_matrix(self._colors) + + def has_left_descent(self, i): """ - return identity_matrix(self._colors) * self._perm.to_matrix() + Return ``True`` if ``i`` is a left descent of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: s1,s2,s3,s4 = S.gens() + sage: x = s4*s1*s2*s3*s4 + sage: [x.has_left_descent(i) for i in S.index_set()] + [True, False, False, True] + """ + n = self.parent()._n + if i == n: + return self._colors[-1] == -1 + if self._colors[i-1] == -1: + return self._colors[i] == 1 or self._perm[i-1] < self._perm[i] + return self._colors[i] == 1 and self._perm[i-1] > self._perm[i] class SignedPermutations(ColoredPermutations): r""" Group of signed permutations. The group of signed permutations is also known as the hyperoctahedral - group and the 2-colored permutation group. Thus it can be constructed - as the wreath product `S_2 \wr S_n`. + group, the Coxeter group of type `B_n`, and the 2-colored permutation + group. Thus it can be constructed as the wreath product `S_2 \wr S_n`. REFERENCES: @@ -339,46 +736,196 @@ class SignedPermutations(ColoredPermutations): def __init__(self, n): """ Initialize ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: TestSuite(S).run() """ - ColoredPermutations.__init__(self, 2, n) + ColoredPermutations.__init__(self, 2, n, FiniteCoxeterGroups()) def _repr_(self): """ Return a string representation of ``self``. + + EXAMPLES:: + + sage: SignedPermutations(4) + Signed permutations of 4 """ return "Signed permutations of {}".format(self._n) + @cached_method + def one(self): + """ + Return the identity element of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: S.one() + [1, 2, 3, 4] + """ + return self.element_class(self, [ZZ.one()]*self._n, self._P.identity()) + + def simple_reflection(self, i): + r""" + Return the ``i``-th simple refection of ``self``. + + Return the generators of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: S.simple_reflection(1) + [2, 1, 3, 4] + sage: S.simple_reflection(4) + [1, 2, 3, -4] + """ + if i not in self.index_set(): + raise ValueError("i must be in the index set") + if i < self._n: + p = range(1, self._n+1) + p[i-1] = i+1 + p[i] = i + return self.element_class(self, [ZZ.one()]*self._n, self._P(p)) + temp = [ZZ.one()]*self._n + temp[-1] = -ZZ.one() + return self.element_class(self, temp, self._P.identity()) + + @cached_method + def gens(self): + """ + Return the generators of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: S.gens() + ([2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3], [1, 2, 3, -4]) + """ + return tuple(self.simple_reflection(i) for i in self.index_set()) + + def _element_constructor_(self, x): + """ + Construct an element of ``self`` from ``x``. + + TESTS:: + + sage: S = SignedPermutations(3) + sage: x = S([(+1,1), (-1,3), (-1,2)]); x + [1, -3, -2] + sage: x == S([[+1,-1,-1], [1,3,2]]) + True + sage: x == S([1, -3, -2]) + True + """ + if isinstance(x, list): + if isinstance(x[0], tuple): + c = [] + p = [] + for k in x: + if len(k) != 2: + raise ValueError("input must be pairs (sign, element)") + if k[0] != 1 and k[0] != -1: + raise ValueError("the sign must be +1 or -1") + c.append( ZZ(k[0]) ) + p.append(k[1]) + return self.element_class(self, c, self._P(p)) + + if len(x) == self._n: + c = [] + p = [] + one = ZZ.one() + for v in x: + if v > 0: + c.append(one) + p.append(v) + else: + c.append(-one) + p.append(-v) + return self.element_class(self, c, self._P(p)) + + if len(x) != 2: + raise ValueError("input must be a pair of a list of signs and a permutation") + if any(s != 1 and s != -1 for s in x[0]): + raise ValueError("the sign must be +1 or -1") + return self.element_class(self, map(ZZ, x[0]), self._P(x[1])) + def __iter__(self): """ Iterate over ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(2) + sage: [x for x in S] + [[1, 2], [1, -2], [-1, 2], [-1, -2], + [2, 1], [2, -1], [-2, 1], [-2, -1]] """ - C = CartesianProduct(*[[-1,1]]*self._n) + one = ZZ.one() + C = CartesianProduct(*[[one,-one]]*self._n) for p in self._P: for c in C: yield self.element_class(self, c, p) - Element = SignedPermutation - -class EvenSignedPermutations(SignedPermutations): - """ - Group of even signed permutations. - """ - def _repr_(self): + @cached_method + def index_set(self): """ - Return a string representation of ``self``. + Return the index set of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: S.index_set() + (1, 2, 3, 4) """ - return "Even signed permtuations of {}".format(self._n) + return tuple(range(1, self._n+1)) - def __iter__(self): + def long_element(self, index_set=None): """ - Iterate over ``self``. + Return the longest element of ``self``, or of the + parabolic subgroup corresponding to the given ``index_set``. + + INPUT: + + - ``index_set`` -- (optioal) a subset (as a list or iterable) + of the nodes of the indexing set + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: S.long_element() + [-4, -3, -2, -1] """ - for s in SignedPermutations.__iter__(self): - total = 0 - for pm in s._colors: - if pm == -1: - total += 1 + if index_set is not None: + return super(SignedPermutations, self).long_element() + p = range(self._n, 0, -1) + return self.element_class(self, [-ZZ.one()]*self._n, self._P(p)) + + Element = SignedPermutation - if total % 2 == 0: - yield s +# TODO: Make this a subgroup +#class EvenSignedPermutations(SignedPermutations): +# """ +# Group of even signed permutations. +# """ +# def _repr_(self): +# """ +# Return a string representation of ``self``. +# """ +# return "Even signed permtuations of {}".format(self._n) +# +# def __iter__(self): +# """ +# Iterate over ``self``. +# """ +# for s in SignedPermutations.__iter__(self): +# total = 0 +# for pm in s._colors: +# if pm == -1: +# total += 1 +# +# if total % 2 == 0: +# yield s From 184b4f9403b613e357db74d9074c3e95e8370ce3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 27 Nov 2014 12:53:26 -0800 Subject: [PATCH 0048/1872] Added some more methods and some comments. --- src/sage/combinat/colored_permutations.py | 41 +++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index c2b9d6c8e84..0d3699b947d 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -18,6 +18,8 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.all import ZZ +# TODO: Much of the colored permutations (and element) class can be +# generalized to `G \wr S_n` class ColoredPermutation(MultiplicativeGroupElement): """ A colored permutation. @@ -219,6 +221,7 @@ def to_matrix(self): D = diagonal_matrix(Cp, [g**i for i in self._colors]) return self._perm.to_matrix() * D +# TODO: Parts of this should be put in the category of complex reflection groups class ColoredPermutations(Parent, UniqueRepresentation): r""" The group of `m`-colored permutations on `\{1, 2, \ldots, n\}`. @@ -729,6 +732,28 @@ class SignedPermutations(ColoredPermutations): group, the Coxeter group of type `B_n`, and the 2-colored permutation group. Thus it can be constructed as the wreath product `S_2 \wr S_n`. + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: s1,s2,s3,s4 = S.group_generators() + sage: x = s4*s1*s2*s3*s4; x + [-4, 1, 2, -3] + sage: x^4 == S.one() + True + + This is a finite Coxeter group of type `B_n`:: + + sage: S.canonical_representation() + Coxeter group over Universal Cyclotomic Field with Coxeter matrix: + [1 3 2 2] + [3 1 3 2] + [2 3 1 4] + [2 2 4 1] + sage: S.long_element() + [-4, -3, -2, -1] + sage: S.long_element().reduced_word() + [4, 3, 4, 2, 3, 4, 1, 2, 3, 4] + REFERENCES: - :wikipedia:`Hyperoctahedral_group` @@ -882,6 +907,22 @@ def index_set(self): """ return tuple(range(1, self._n+1)) + def coxeter_matrix(self): + """ + Return the Coxeter matrix of ``self``. + + EXAMPLES:: + + sage: S = SignedPermutations(4) + sage: S.coxeter_matrix() + [1 3 2 2] + [3 1 3 2] + [2 3 1 4] + [2 2 4 1] + """ + from sage.combinat.root_system.cartan_type import CartanType + return CartanType(['B', self._n]).coxeter_matrix() + def long_element(self, index_set=None): """ Return the longest element of ``self``, or of the From a8667eb3725f0156cc3936dd770e8a3e04852cf1 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Wed, 3 Dec 2014 08:47:40 +0000 Subject: [PATCH 0049/1872] Fix base_ring docstring --- src/sage/geometry/polyhedron/base.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index ab50f9edc24..8c64258df0f 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1919,8 +1919,17 @@ def base_ring(self): OUTPUT: - Either ``ZZ`` (the ring of integers), ``QQ`` (exact arithmetic using gmp) or ``RDF`` - (double precision floating-point arithmetic) + The ring over which the polyhedron is defined. Must be a + sub-ring of the reals to define a polyhedron, in particular + comparison must be defined. Popular choices are + + * ``ZZ`` (the ring of integers, lattice polytope), + + * ``QQ`` (exact arithmetic using gmp), + + * ``RDF`` (double precision floating-point arithmetic), or + + * ``AA`` (real algebraic field). EXAMPLES:: From fbc0d3d12a77f1d619c7a981f00001c41b450082 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Sun, 7 Dec 2014 15:46:20 +0100 Subject: [PATCH 0050/1872] added doctest for cdd_Hrepresentation --- src/sage/geometry/polyhedron/base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 03087e2b75c..e49c4a70d6a 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -748,6 +748,14 @@ def cdd_Hrepresentation(self): 1 -1 0 1 0 -1 end + + sage: triangle = Polyhedron(vertices = [[1,0],[0,1],[1,1]],base_ring=AA) + sage: triangle.base_ring() + Algebraic Real Field + sage: triangle.cdd_Hrepresentation() + Traceback (most recent call last): + ... + TypeError: The base ring must be ZZ, QQ, or RDF """ from cdd_file_format import cdd_Hrepresentation try: From 924d341abe2f85b95031ee9c6169cea69cad39e4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 13 Dec 2014 17:49:14 -0800 Subject: [PATCH 0051/1872] Added check for formality, k-generated, and matroid methods. --- .../hyperplane_arrangement/arrangement.py | 112 +++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index adddb797bb9..cd642dfb5f3 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -23,7 +23,9 @@ sage: -2*h Hyperplane -6*x - 4*y + 10*z + 14 sage: x, y, z - (Hyperplane x + 0*y + 0*z + 0, Hyperplane 0*x + y + 0*z + 0, Hyperplane 0*x + 0*y + z + 0) + (Hyperplane x + 0*y + 0*z + 0, + Hyperplane 0*x + y + 0*z + 0, + Hyperplane 0*x + 0*y + z + 0) See :mod:`sage.geometry.hyperplane_arrangement.hyperplane` for more functionality of the individual hyperplanes. @@ -340,9 +342,12 @@ from sage.misc.cachefunc import cached_method from sage.misc.misc import uniq from sage.matrix.constructor import matrix, vector +from sage.modules.free_module import VectorSpace +from sage.matroids.constructor import Matroid from sage.geometry.hyperplane_arrangement.hyperplane import AmbientVectorSpace, Hyperplane +from copy import copy class HyperplaneArrangementElement(Element): @@ -1481,7 +1486,7 @@ def regions(self): return tuple(regions) def region_containing_point(self, p): - r""" + r"""def region The region in the hyperplane arrangement containing a given point. The base field must have characteristic zero. @@ -1928,7 +1933,110 @@ def varchenko_matrix(self, names='h'): v.set_immutable() return v + @cached_method + def matroid(self): + r""" + Return the matroid assoicated to ``self``. + + Let `A` denote a central hyperplane arrangement and `n_H` the + normal vector of some hyperplane `H \in A`. We define a matroid + `M_A` as the linear matoid spanned by `\{ n_H | H \in A \}`. + The matroid `M_A` is such that the lattice of flats of `M` is + isomorphic to the intersection lattice of `A` + (Proposition 3.6 in [RS]_). + + EXAMPLES:: + + sage: P. = HyperplaneArrangements(QQ) + sage: A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z) + sage: M = A.matroid(); M + Linear matroid of rank 3 on 7 elements represented over the Rational Field + + We check the lattice of flats is isomorphic to the + intersection lattice:: + + sage: f = sum([list(M.flats(i)) for i in range(M.rank()+1)], []) + sage: PF = Poset([f, lambda x,y: x < y]) + sage: PF.is_isomorphic(A.intersection_poset()) + True + """ + if not self.is_central(): + raise ValueError("the hyperplane arrangement must be central") + norms = [p.normal() for p in self] + return Matroid(matrix=matrix(norms).transpose()) + + @cached_method + def minimal_generated_number(self): + r""" + Return the minimum `k` such that ``self`` is `k`-generated. + Let `A` be a central hyperplane arrangement. Let `W_k` denote + the solution space of the linear system corresponding to the + linear dependencies among the hyperplanes of `A` of length at + most `k`. We say `A` is `k`-*generated* if `\dim W_k = \rank A`. + Equivalently this says all dependencies forming the Orlik-Terao + ideal are generated by at most `k` hyperplanes. + + EXAMPLES: + + We construct Example 2.2 from [Vuz93]_:: + + sage: P. = HyperplaneArrangements(QQ) + sage: A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z, 3*x+5*z, 3*x+4*y+5*z) + sage: B = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z, x+3*z, x+2*y+3*z) + sage: A.minimal_generated_number() + 3 + sage: B.minimal_generated_number() + 4 + + REFERENCES: + + .. [Vuz93] Sergey Yuzvinksy, + *The first two obstructions to the freeness of arrangements*, + Transactions of the American Mathematical Society, + Vol. 335, **1** (1993) pp. 231--244. + """ + V = VectorSpace(self.base_ring(), self.dimension()) + W = VectorSpace(self.base_ring(), self.n_hyperplanes()) + r = self.rank() + D = [] + M = self.matroid() + norms = M.representation().columns() + circuits = M.circuits() + for i in range(2, self.n_hyperplanes()): + sol = [] + for d in circuits: + if len(d) > i: + continue + d = list(d) + dep = V.linear_dependence([norms[j] for j in d]) + w = copy(W.zero()) + for j,k in enumerate(d): + w[k] = dep[0][j] + sol.append(w) + mat = matrix(sol) + if mat.right_kernel().dimension() == r: + return i + return self.n_hyperplanes() + + def is_formal(self): + """ + Return if ``self`` is formal. + + A hyperplane arrangement is *formal* if it is 3-generated as + defined in :meth:`minimal_generated_number`. + + EXAMPLES:: + + sage: P. = HyperplaneArrangements(QQ) + sage: A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z, 3*x+5*z, 3*x+4*y+5*z) + sage: B = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z, x+3*z, x+2*y+3*z) + sage: A.is_formal() + True + sage: B.is_formal() + False + """ + return self.minimal_generated_number() <= 3 class HyperplaneArrangements(Parent, UniqueRepresentation): """ From 56d27553989dc42a9563628e545f08eb874ac15f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 13 Dec 2014 17:51:16 -0800 Subject: [PATCH 0052/1872] Some cleanup. --- src/sage/geometry/hyperplane_arrangement/arrangement.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index cd642dfb5f3..ccd728066c6 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -343,7 +343,6 @@ from sage.misc.misc import uniq from sage.matrix.constructor import matrix, vector from sage.modules.free_module import VectorSpace -from sage.matroids.constructor import Matroid from sage.geometry.hyperplane_arrangement.hyperplane import AmbientVectorSpace, Hyperplane @@ -700,7 +699,6 @@ def intersection_poset(self): """ K = self.base_ring() from sage.geometry.hyperplane_arrangement.affine_subspace import AffineSubspace - from sage.modules.all import VectorSpace whole_space = AffineSubspace(0, VectorSpace(K, self.dimension())) L = [[whole_space]] active = True @@ -1963,6 +1961,7 @@ def matroid(self): if not self.is_central(): raise ValueError("the hyperplane arrangement must be central") norms = [p.normal() for p in self] + from sage.matroids.constructor import Matroid return Matroid(matrix=matrix(norms).transpose()) @cached_method @@ -1999,7 +1998,6 @@ def minimal_generated_number(self): V = VectorSpace(self.base_ring(), self.dimension()) W = VectorSpace(self.base_ring(), self.n_hyperplanes()) r = self.rank() - D = [] M = self.matroid() norms = M.representation().columns() circuits = M.circuits() From 65af64ebcf0012a5cb5dfdb2bdacff93464deccc Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 27 Dec 2014 18:41:16 -0800 Subject: [PATCH 0053/1872] Added (quantum) Mobius algebras and KL polynomials of posets. --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/posets/__init__.py | 2 + src/sage/combinat/posets/lattices.py | 32 + src/sage/combinat/posets/mobius_algebra.py | 729 ++++++++++++++++++ src/sage/combinat/posets/posets.py | 133 ++++ 5 files changed, 897 insertions(+) create mode 100644 src/sage/combinat/posets/mobius_algebra.py diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index e84dc84733e..e6603763e14 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -155,6 +155,7 @@ Comprehensive Module list sage/combinat/posets/hasse_diagram sage/combinat/posets/lattices sage/combinat/posets/linear_extensions + sage/combinat/posets/mobius_algebra sage/combinat/posets/poset_examples sage/combinat/posets/posets sage/combinat/q_analogues diff --git a/src/sage/combinat/posets/__init__.py b/src/sage/combinat/posets/__init__.py index 8b6b80ea2eb..15767a01964 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.mobius_algebra` + - :ref:`sage.combinat.tamari_lattices` - :ref:`sage.combinat.interval_posets` diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index 2e637c71b9f..2635c368da4 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -16,6 +16,7 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** + from sage.categories.finite_lattice_posets import FiniteLatticePosets from sage.combinat.posets.posets import Poset, FinitePoset from sage.combinat.posets.elements import (LatticePosetElement, @@ -722,6 +723,37 @@ def is_lower_semimodular(self): for a in range(n) for b in range(a+1, n)) return True + def mobius_algebra(self, R): + """ + Return the Mobius algebra of ``self`` over ``R``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: L.mobius_algebra(QQ) + Mobius algebra of Finite lattice containing 16 elements over Rational Field + """ + from sage.combinat.posets.mobius_algebra import MobiusAlgebra + return MobiusAlgebra(R, self) + + def quantum_mobius_algebra(self, q=None): + """ + Return the quantum Mobius algebra of ``self`` with parameter ``q``. + + INPUT: + + - ``q`` -- (optional) the deformation parameter `q` + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: L.quantum_mobius_algebra() + Quantum Mobius algebra of Finite lattice containing 16 elements + with q=q over Univariate Laurent Polynomial Ring in q over Integer Ring + """ + from sage.combinat.posets.mobius_algebra import QuantumMobiusAlgebra + return QuantumMobiusAlgebra(self, q) + #################################################################################### FiniteMeetSemilattice._dual_class = FiniteJoinSemilattice diff --git a/src/sage/combinat/posets/mobius_algebra.py b/src/sage/combinat/posets/mobius_algebra.py new file mode 100644 index 00000000000..7d49dd2e4c7 --- /dev/null +++ b/src/sage/combinat/posets/mobius_algebra.py @@ -0,0 +1,729 @@ +r""" +Mobius 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.bindable_class import BindableClass +from sage.misc.lazy_attribute import lazy_attribute +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.categories.algebras import Algebras +from sage.categories.realizations import Realizations, Category_realization_of_parent +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.combinat.posets.lattices import LatticePoset +from sage.combinat.free_module import CombinatorialFreeModule +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.all import ZZ + +class BasisAbstract(CombinatorialFreeModule, BindableClass): + """ + Abstract base class for a basis. + """ + def __getitem__(self, x): + """ + Return the basis element indexed by ``x``. + + INPUT: + + - ``x`` -- an element of the lattice + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: E = L.mobius_algebra(QQ).E() + sage: E[5] + E[5] + sage: C = L.quantum_mobius_algebra().C() + sage: C[5] + C[5] + """ + L = self.realization_of()._lattice + return self.monomial(L(x)) + +class MobiusAlgebra(Parent, UniqueRepresentation): + r""" + The Mobius algebra of a lattice. + + Let `L` be a lattice. The *Mobius algebra* `M_L` was originally + constructed by Solomon and has a natural basis + `\{ E_x \mid x \in L \}` with multiplication given by + `E_x \cdot E_y = E_{x \vee y}`. Moreover this has a basis given by + orthogonal idempotents `\{ I_x \mid x \in L \}` (so + `I_x I_y = \delta_{xy} I_x` where `\delta` is the Kronecker delta) + related to the natural basis by + + .. MATH:: + + I_x = \sum_{y \leq x} \mu_L(y, x) E_x, + + where `\mu_L` is the Mobius function of `L`. + + REFERENCES: + + .. [Greene73] Curtis Greene. + *On the Mobius algebra of a partially ordered set*. + Advances in Mathematics, **10**, 1973. + :doi:`10.1016/0001-8708(73)90106-0`. + + .. [Etienne98] Gwihen Etienne. + *On the Mobius algebra of geometric lattices*. + European Journal of Combinatorics, **19**, 1998. + :doi:`10.1006/eujc.1998.0227`. + """ + def __init__(self, R, L): + """ + Initialize ``self``. + + TESTS:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.mobius_algebra(QQ) + sage: TestSuite(M).run() + """ + if not L.is_lattice(): + raise ValueError("L must be a lattice") + cat = Algebras(R).Commutative().WithBasis() + if L in FiniteEnumeratedSets(): + cat = cat.FiniteDimensional() + self._lattice = L + self._category = cat + Parent.__init__(self, base=R, category=self._category.WithRealizations()) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: L.mobius_algebra(QQ) + Mobius algebra of Finite lattice containing 16 elements over Rational Field + """ + return "Mobius algebra of {} over {}".format(self._lattice, self.base_ring()) + + def a_realization(self): + r""" + Return a particular realization of ``self`` (the `B`-basis). + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.mobius_algebra(QQ) + sage: M.a_realization() + Mobius algebra of Finite lattice containing 16 elements + over Rational Field in the natural basis + """ + return self.E() + + def lattice(self): + """ + Return the defining lattice of ``self``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.mobius_algebra(QQ) + sage: M.lattice() + Finite lattice containing 16 elements + sage: M.lattice() == L + True + """ + return self._lattice + + class E(BasisAbstract): + r""" + The natural basis of a Mobius algebra. + + Let `E_x` and `E_y` be basis elements of `M_L` for some lattice `L`. + Multiplication is given by `E_x E_y = E_{x \vee y}`. + """ + def __init__(self, M, prefix='E'): + """ + Initialize ``self``. + + TESTS:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.mobius_algebra(QQ) + sage: TestSuite(M.E()).run() + """ + self._basis_name = "natural" + CombinatorialFreeModule.__init__(self, M.base_ring(), + tuple(M._lattice), + prefix=prefix, + category=MobiusAlgebraBases(M)) + + @cached_method + def _to_idempotent_basis(self, x): + """ + Convert the element indexed by ``x`` to the idempotent basis. + + EXAMPLES:: + + sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: E = M.E() + sage: all(E(E._to_idempotent_basis(x)) == E.monomial(x) + ....: for x in E.basis().keys()) + True + """ + M = self.realization_of() + I = M.idempotent() + return I.sum_of_monomials(M._lattice.order_ideal([x])) + + def product_on_basis(self, x, y): + """ + Return the product of basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: E = L.mobius_algebra(QQ).E() + sage: E.product_on_basis(5, 14) + E[15] + sage: E.product_on_basis(2, 8) + E[10] + """ + return self.monomial(self.realization_of()._lattice.join(x, y)) + + @cached_method + def one(self): + """ + Return the element ``1`` of ``self``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: E = L.mobius_algebra(QQ).E() + sage: E.one() + E[0] + """ + elts = self.realization_of()._lattice.minimal_elements() + return self.sum_of_monomials(elts) + + natural = E + + class I(BasisAbstract): + """ + The (orthogonal) idempotent basis of a Mobius algebra. + + Let `I_x` and `I_y` be basis elements of `M_L` for some lattice `L`. + Multiplication is given by `I_x I_y = \delta_{xy} I_x` where + `\delta_{xy}` is the Kronecker delta. + """ + def __init__(self, M, prefix='I'): + """ + Initialize ``self``. + + TESTS:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.mobius_algebra(QQ) + sage: TestSuite(M.I()).run() + """ + self._basis_name = "idempotent" + CombinatorialFreeModule.__init__(self, M.base_ring(), + tuple(M._lattice), + prefix=prefix, + category=MobiusAlgebraBases(M)) + + ## Change of basis: + E = M.E() + self.module_morphism(self._to_natural_basis, + codomain=E, category=self.category(), + triangular='upper', unitriangular=True + ).register_as_coercion() + + E.module_morphism(E._to_idempotent_basis, + codomain=self, category=self.category(), + triangular='upper', unitriangular=True + ).register_as_coercion() + + + @cached_method + def _to_natural_basis(self, x): + """ + Convert the element indexed by ``x`` to the natural basis. + + EXAMPLES:: + + sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: I = M.I() + sage: all(I(I._to_natural_basis(x)) == I.monomial(x) + ....: for x in I.basis().keys()) + True + """ + M = self.realization_of() + N = M.natural() + mobius = M._lattice.mobius_function + return N.sum_of_terms((y, mobius(y,x)) for y in M._lattice.order_ideal([x])) + + def product_on_basis(self, x, y): + """ + Return the product of basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: I = L.mobius_algebra(QQ).I() + sage: I.product_on_basis(5, 14) + 0 + sage: I.product_on_basis(2, 2) + I[2] + """ + if x == y: + return self.monomial(x) + return self.zero() + + @cached_method + def one(self): + """ + Return the element ``1`` of ``self``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: I = L.mobius_algebra(QQ).I() + sage: I.one() + I[0] + I[1] + I[2] + I[3] + I[4] + I[5] + I[6] + I[7] + I[8] + + I[9] + I[10] + I[11] + I[12] + I[13] + I[14] + I[15] + """ + return self.sum_of_monomials(self.realization_of()._lattice) + + def __getitem__(self, x): + """ + Return the basis element indexed by ``x``. + + INPUT: + + - ``x`` -- an element of the lattice + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: I = L.mobius_algebra(QQ).I() + sage: I[5] + I[5] + """ + L = self.realization_of()._lattice + return self.monomial(L(x)) + + idempotent = I + +class QuantumMobiusAlgebra(Parent, UniqueRepresentation): + r""" + The quantum Mobius algebra of a lattice. + + Let `L` be a lattice, and we define the *quantum Mobius algebra* `M_L(q)` + as the algebra with basis `\{ E_x \mid x \in L \}` with + multiplication given by + + .. MATH:: + + E_x E_y = \sum_{z \geq a \geq x \vee y} \mu_L(a, z) + q^{\operatorname{crk} a} E_z, + + where `\mu_L` is the Mobius function of `L` and `\operatorname{crk}` + is the corank function (i.e., `\operatorname{crk} a = + \operatorname{rank} L - \operatorname{rank}` a). At `q = 1`, this + reduces to the multiplication formula originally given by Solomon. + """ + def __init__(self, L, q=None): + """ + Initialize ``self``. + + TESTS:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.quantum_mobius_algebra() + sage: TestSuite(M).run() # long time + """ + if not L.is_lattice(): + raise ValueError("L must be a lattice") + if q is None: + q = LaurentPolynomialRing(ZZ, 'q').gen() + self._q = q + R = q.parent() + cat = Algebras(R).WithBasis() + if L in FiniteEnumeratedSets(): + cat = cat.Commutative().FiniteDimensional() + self._lattice = L + self._category = cat + Parent.__init__(self, base=R, category=self._category.WithRealizations()) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: L.quantum_mobius_algebra() + Quantum Mobius algebra of Finite lattice containing 16 elements + with q=q over Univariate Laurent Polynomial Ring in q over Integer Ring + """ + return "Quantum Mobius algebra of {} with q={} over {}".format( + self._lattice, self._q, self.base_ring()) + + def a_realization(self): + r""" + Return a particular realization of ``self`` (the `B`-basis). + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.quantum_mobius_algebra() + sage: M.a_realization() + Quantum Mobius algebra of Finite lattice containing 16 elements + with q=q over Univariate Laurent Polynomial Ring in q + over Integer Ring in the natural basis + """ + return self.E() + + def lattice(self): + """ + Return the defining lattice of ``self``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.quantum_mobius_algebra() + sage: M.lattice() + Finite lattice containing 16 elements + sage: M.lattice() == L + True + """ + return self._lattice + + class E(BasisAbstract): + r""" + The natural basis of a Mobius algebra. + + Let `E_x` and `E_y` be basis elements of `M_L` for some lattice `L`. + Multiplication is given by + + .. MATH:: + + E_x E_y = \sum_{z \geq a \geq x \vee y} \mu_L(a, z) + q^{\operatorname{crk} a} E_z, + + where `\mu_L` is the Mobius function of `L` and `\operatorname{crk}` + is the corank function (i.e., `\operatorname{crk} a = + \operatorname{rank} L - \operatorname{rank}` a). + """ + def __init__(self, M, prefix='E'): + """ + Initialize ``self``. + + TESTS:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.quantum_mobius_algebra() + sage: TestSuite(M.E()).run() # long time + """ + self._basis_name = "natural" + CombinatorialFreeModule.__init__(self, M.base_ring(), + tuple(M._lattice), + prefix=prefix, + category=MobiusAlgebraBases(M)) + + def product_on_basis(self, x, y): + """ + Return the product of basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: E = L.quantum_mobius_algebra().E() + sage: E.product_on_basis(5, 14) + E[15] + sage: E.product_on_basis(2, 8) + q^2*E[10] + (q-q^2)*E[11] + (q-q^2)*E[14] + (1-2*q+q^2)*E[15] + """ + L = self.realization_of()._lattice + q = self.realization_of()._q + mobius = L.mobius_function + rank = L.rank_function() + R = L.rank() + j = L.join(x,y) + return self.sum_of_terms(( z, mobius(a,z) * q**(R - rank(a)) ) + for z in L.order_filter([j]) + for a in L.closed_interval(j, z)) + + @cached_method + def one(self): + """ + Return the element ``1`` of ``self``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: E = L.quantum_mobius_algebra().E() + sage: all(E.one() * b == b for b in E.basis()) + True + """ + L = self.realization_of()._lattice + q = self.realization_of()._q + mobius = L.mobius_function + rank = L.rank_function() + R = L.rank() + return self.sum_of_terms((x, mobius(y,x) * q**(rank(y) - R)) + for x in L for y in L.order_ideal([x])) + + natural = E + + class C(BasisAbstract): + r""" + The characteristic basis of a Mobius algebra. + + The characteristic basis `\{ C_x \mid x \in L \}` of `M_L` + for some lattice `L` is defined by + + .. MATH:: + + C_x = \sum_{a \geq x} P(I^x; q) E_a, + + where `I^x = \{ y \in L \mid y \geq x \}` is the order filter and + `P(I^x; q)` is the characteristic polynomial of the (sub)poset `I^x`. + """ + def __init__(self, M, prefix='C'): + """ + Initialize ``self``. + + TESTS:: + + sage: L = posets.BooleanLattice(3) + sage: M = L.quantum_mobius_algebra() + sage: TestSuite(M.C()).run() # long time + """ + self._basis_name = "characteristic" + CombinatorialFreeModule.__init__(self, M.base_ring(), + tuple(M._lattice), + prefix=prefix, + category=MobiusAlgebraBases(M)) + + ## Change of basis: + E = M.E() + phi = self.module_morphism(self._to_natural_basis, + codomain=E, category=self.category(), + triangular='lower', unitriangular=True) + + phi.register_as_coercion() + (~phi).register_as_coercion() + + @cached_method + def _to_natural_basis(self, x): + """ + Convert the element indexed by ``x`` to the natural basis. + + EXAMPLES:: + + sage: M = posets.BooleanLattice(4).quantum_mobius_algebra() + sage: C = M.C() + sage: all(C(C._to_natural_basis(x)) == C.monomial(x) + ....: for x in C.basis().keys()) + True + """ + M = self.realization_of() + N = M.natural() + q = M._q + R = M.base_ring() + L = M._lattice + poly = lambda x,y: L.subposet(L.closed_interval(x, y)).characteristic_polynomial() + # This is a workaround until #17554 is fixed... + subs = lambda p,q: R.sum( c * q**e for e,c in enumerate(p.list()) ) + # ...at which point, we can do poly(x,y)(q=q) + return N.sum_of_terms((y, subs(poly(x,y), q)) + for y in L.order_filter([x])) + + characteristic_basis = C + + class KL(BasisAbstract): + """ + The Kazhdan-Lusztig basis of a quantum Mobius algebra. + + The Kazhdan-Lusztig basis `\{ B_x \mid x \in L \}` of `M_L` + for some lattice `L` is defined by + + .. MATH:: + + B_x = \sum_{y \geq x} P_{x,y}(q) E_a, + + where `P_{x,y}(q)` is the Kazhdan-Lusztig polynomial of `L`, + following the definition given in [EPW14]_. + + EXAMPLES: + + We construct some examples of Proposition 4.5 of [EPW14]_:: + + sage: M = posets.BooleanLattice(4).quantum_mobius_algebra() + sage: KL = M.KL() + sage: KL[4] * KL[5] + (q^2+q^3)*KL[5] + (q+2*q^2+q^3)*KL[7] + (q+2*q^2+q^3)*KL[13] + (1+3*q+3*q^2+q^3)*KL[15] + sage: KL[4] * KL[15] + (1+3*q+3*q^2+q^3)*KL[15] + sage: KL[4] * KL[10] + (q+3*q^2+3*q^3+q^4)*KL[14] + (1+4*q+6*q^2+4*q^3+q^4)*KL[15] + """ + def __init__(self, M, prefix='KL'): + """ + Initialize ``self``. + + TESTS:: + + sage: L = posets.BooleanLattice(4) + sage: M = L.quantum_mobius_algebra() + sage: TestSuite(M.KL()).run() # long time + """ + self._basis_name = "Kazhdan-Lusztig" + CombinatorialFreeModule.__init__(self, M.base_ring(), + tuple(M._lattice), + prefix=prefix, + category=MobiusAlgebraBases(M)) + + ## Change of basis: + E = M.E() + phi = self.module_morphism(self._to_natural_basis, + codomain=E, category=self.category(), + triangular='lower', unitriangular=True) + + phi.register_as_coercion() + (~phi).register_as_coercion() + + @cached_method + def _to_natural_basis(self, x): + """ + Convert the element indexed by ``x`` to the natural basis. + + EXAMPLES:: + + sage: M = posets.BooleanLattice(4).quantum_mobius_algebra() + sage: KL = M.KL() + sage: all(KL(KL._to_natural_basis(x)) == KL.monomial(x) # long time + ....: for x in KL.basis().keys()) + True + """ + M = self.realization_of() + L = M._lattice + E = M.E() + q = M._q + R = M.base_ring() + rank = L.rank_function() + # This is a workaround until #17554 is fixed... + subs = lambda p,q: R.sum( c * q**e for e,c in enumerate(p.list()) ) + return E.sum_of_terms((y, q**(rank(y) - rank(x)) * + subs(L.kazhdan_lusztig_polynomial(x, y), q**-2)) + for y in L.order_filter([x])) + + kazhdan_lusztig = KL + +class MobiusAlgebraBases(Category_realization_of_parent): + r""" + The category of bases of a Mobius algebra. + + INPUT: + + - ``base`` -- a Mobius algebra + + TESTS:: + + sage: from sage.combinat.posets.mobius_algebra import MobiusAlgebraBases + sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: bases = MobiusAlgebraBases(M) + sage: M.E() in bases + True + """ + def _repr_(self): + r""" + Return the representation of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.posets.mobius_algebra import MobiusAlgebraBases + sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: MobiusAlgebraBases(M) + Category of bases of Mobius algebra of Finite lattice + containing 16 elements over Rational Field + """ + return "Category of bases of {}".format(self.base()) + + def super_categories(self): + r""" + The super categories of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.posets.mobius_algebra import MobiusAlgebraBases + sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: bases = MobiusAlgebraBases(M) + sage: bases.super_categories() + [Category of finite dimensional commutative algebras with basis over Rational Field, + Category of realizations of Mobius algebra of Finite lattice + containing 16 elements over Rational Field] + """ + return [self.base()._category, Realizations(self.base())] + + class ParentMethods: + def _repr_(self): + """ + Text representation of this basis of a Mobius algebra. + + EXAMPLES:: + + sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: M.E() + Mobius algebra of Finite lattice containing 16 elements + over Rational Field in the natural basis + sage: M.I() + Mobius algebra of Finite lattice containing 16 elements + over Rational Field in the idempotent basis + """ + return "{} in the {} basis".format(self.realization_of(), self._basis_name) + + def product_on_basis(self, x, y): + """ + Return the product of basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: C = L.quantum_mobius_algebra().C() + sage: C.product_on_basis(5, 14) + q^3*C[15] + sage: C.product_on_basis(2, 8) + q^4*C[10] + """ + R = self.realization_of().a_realization() + return self(R(self.monomial(x)) * R(self.monomial(y))) + + @cached_method + def one(self): + """ + Return the element ``1`` of ``self``. + + EXAMPLES:: + + sage: L = posets.BooleanLattice(4) + sage: C = L.quantum_mobius_algebra().C() + sage: all(C.one() * b == b for b in C.basis()) + True + """ + R = self.realization_of().a_realization() + return self(R.one()) + + class ElementMethods: + pass + diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index e0a21339b58..445872cd53f 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -139,6 +139,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod +from sage.functions.other import floor from sage.categories.category import Category from sage.categories.sets_cat import Sets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -150,6 +151,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.graphs.digraph import DiGraph from sage.graphs.digraph_generators import digraphs from sage.combinat.posets.hasse_diagram import HasseDiagram @@ -5003,6 +5005,137 @@ def p_partition_enumerator(self, tup, R, check=False): res += QR.Fundamental()(Composition(from_subset=(descents, n))) return res + @cached_method(key=lambda self,x,y,l: (x,y)) + def _kl_poly(self, x=None, y=None, canonical_labels=None): + r""" + Cached Kazhdan-Lusztig polynomial of ``self`` for generic `q`. + + .. SEEALSO:: + + :meth:`kazhdan_lusztig_polynomial` + + EXAMPLES:: + + sage: L = posets.SymmetricGroupWeakOrderPoset(4) + sage: L._kl_poly() + 1 + sage: x = '2314' + sage: y = '3421' + sage: L._kl_poly(x, y) + -q + 1 + + AUTHORS: + + - Travis Scrimshaw (27-12-2014) + """ + R = PolynomialRing(ZZ, 'q') + q = R.gen(0) + + # Handle some special cases + if self.cardinality() == 0: + return q.parent().zero() + if not self.rank(): + return q.parent().one() + + if canonical_labels is None: + canonical_labels = x is None and y is None + + if x is not None or y is not None: + if x == y: + return q.parent().one() + if x is None: + x = self.minimal_elements()[0] + if y is None: + y = self.maximal_elements()[0] + if not self.le(x, y): + return q.parent().zero() + P = self.subposet(self.interval(x, y)) + return P.kazhdan_lusztig_polynomial(q=q, canonical_labels=canonical_labels) + + min_elt = self.minimal_elements()[0] + if canonical_labels: + sublat = lambda P: self.subposet(P).canonical_label() + else: + sublat = lambda P: self.subposet(P) + poly = -sum(sublat(self.order_ideal([x])).characteristic_polynomial() + * sublat(self.order_filter([x])).kazhdan_lusztig_polynomial() + for x in self if x != min_elt) + tr = floor(self.rank()/2) + 1 + ret = poly.truncate(tr) + return ret(q=q) + + def kazhdan_lusztig_polynomial(self, x=None, y=None, q=None, canonical_labels=None): + r""" + Return the Kazhdan-Lusztig polynomial `P_{x,y}(q)` of ``self``. + + We follow the definition given in [EPW14]_. Let `G` denote a + graded poset with unique minimal and maximal elements and `\chi_G` + denote the characteristic polynomial of `G`. Let `I_x` and `F^x` + denote the order ideal and filter of `x` respectively. Define the + *Kazhdan-Lusztig polynomial* of `G` as the unique polynomial + `P_G(q)` satisfying the following: + + 1. If `\operatorname{rank} G = 0`, then `P_G(q) = 1`. + 2. If `\operatorname{rank} G > 0`, then `\deg P_G(q) < + \frac{1}{2} \operatorname{rank} G`. + 3. We have + + .. MATH:: + + q^{\operatorname{rank} G} P_G(q^{-1}) + = \sum_{x \in G} \chi_{I_x}(q) P_{F^x}(q). + + We then extend this to `P_{x,y}(q)` by considering the subposet + corresponding to the (closed) interval `[x, y]`. We also + define `P_{\emptyset}(q) = 0` (so if `x \not\leq y`, + then `P_{x,y}(q) = 0`). + + INPUT: + + - ``q`` -- (default: `q \in \ZZ[q]`) the indeterminate `q` + - ``x`` -- (default: the minimal element) the element `x` + - ``y`` -- (default: the maximal element) the element `y` + - ``canonical_labels`` -- (optional) for subposets, use the + canonical labeling (this can limit recursive calls for posets + with large amounts of symmetry, but producing the labeling + takes time); if not specified, this is ``True`` if ``x`` + and ``y`` are both not specified and ``False`` otherwise + + EXAMPLES:: + + sage: L = posets.BooleanLattice(3) + sage: L.kazhdan_lusztig_polynomial() + 1 + + :: + + sage: L = posets.SymmetricGroupWeakOrderPoset(4) + sage: L.kazhdan_lusztig_polynomial() + 1 + sage: x = '2314' + sage: y = '3421' + sage: L.kazhdan_lusztig_polynomial(x, y) + -q + 1 + sage: L.kazhdan_lusztig_polynomial(x, y, var('t')) + -t + 1 + + REFERENCES: + + .. [EPW14] Ben Elias, Nicholas Proudfoot, and Max Wakefield. + *The Kazhdan-Lusztig polynomial of a matroid*. 2014. + :arxiv:`1412.7408`. + + AUTHORS: + + - Travis Scrimshaw (27-12-2014) + """ + if not self.is_ranked(): + raise ValueError("poset is not ranked") + if q is None: + q = PolynomialRing(ZZ, 'q').gen(0) + poly = self._kl_poly(x, y, canonical_labels) + return poly(q=q) + FinitePoset._dual_class = FinitePoset ##### Posets ##### From b41248b13e18744ab9902adde9b7740832bb1724 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Thu, 8 Jan 2015 14:47:28 -0800 Subject: [PATCH 0054/1872] trac 17447: Deprecation of function('f',x) in favour of function('f')(x) rationale: function('f') returns a "NewSymbolicFunction" object, whereas function('f')(x) returns a SymbolicExpression obtained by evaluating the function at x. It is confusing that function('f',x) doesn't return a function, so we are better off not providing it. --- src/sage/symbolic/function_factory.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/symbolic/function_factory.py b/src/sage/symbolic/function_factory.py index aac429816dc..75db644c3de 100644 --- a/src/sage/symbolic/function_factory.py +++ b/src/sage/symbolic/function_factory.py @@ -135,7 +135,7 @@ def function(s, *args, **kwds): INPUT: - ``args`` - arguments to the function, if specified returns the new - function evaluated at the given arguments + function evaluated at the given arguments (deprecated as of :trac:`17447`) - ``nargs=0`` - number of arguments the function accepts, defaults to variable number of arguments, or 0 - ``latex_name`` - name used when printing in latex mode @@ -168,9 +168,11 @@ def function(s, *args, **kwds): EXAMPLES:: + sage: from sage.symbolic.function_factory import function sage: var('a, b') (a, b) - sage: f = function('cr', a) + sage: cr = function('cr') + sage: f = cr(a) sage: g = f.diff(a).integral(b) sage: g b*D[0](cr)(a) @@ -303,10 +305,6 @@ def function(s, *args, **kwds): Make sure that :trac:`15860` is fixed and whitespaces are removed:: - sage: function('A, B') - (A, B) - sage: B - B sage: C, D, E = function(' C D E') sage: C(D(x)) C(D(x)) @@ -328,6 +326,8 @@ def function(s, *args, **kwds): funcs = [function_factory(name, **kwds) for name in names] if len(args) > 0: + from sage.misc.superseded import deprecation + deprecation(17447, "Calling function('f',x) is deprecated. Use function('f')(x) instead.") res = [f(*args) for f in funcs] else: res = funcs From fa3ebd6645eb2cae45c2218628eaa1d984f16506 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Thu, 8 Jan 2015 14:51:04 -0800 Subject: [PATCH 0055/1872] trac 17447: Doctest changes to reflect deprecation of function('f',x) WARNING: these are probably not all doctests that need to be changed yet, so this branch will probably be rewritten. --- src/sage/calculus/calculus.py | 24 ++++++------- src/sage/calculus/desolvers.py | 42 +++++++++++------------ src/sage/calculus/var.pyx | 30 +++++++++++----- src/sage/symbolic/expression.pyx | 6 ++-- src/sage/symbolic/function.pyx | 2 +- src/sage/symbolic/integration/external.py | 2 +- src/sage/symbolic/ring.pyx | 2 +- 7 files changed, 60 insertions(+), 48 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 6f37bbac1ee..b6509f6d049 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -357,7 +357,7 @@ Check to see that the problem with the variables method mentioned in :trac:`3779` is actually fixed:: - sage: f = function('F',x) + sage: f = function('F')(x) sage: diff(f*SR(1),x) D[0](F)(x) @@ -1282,7 +1282,7 @@ def laplace(ex, t, s): We do a formal calculation:: - sage: f = function('f', x) + sage: f = function('f')(x) sage: g = f.diff(x); g D[0](f)(x) sage: g.laplace(x, s) @@ -1308,8 +1308,8 @@ def laplace(ex, t, s): sage: var('t') t sage: t = var('t') - sage: x = function('x', t) - sage: y = function('y', t) + sage: x = function('x')(t) + sage: y = function('y')(t) sage: de1 = x.diff(t) + 16*y sage: de2 = y.diff(t) + x - 1 sage: de1.laplace(t, s) @@ -1435,7 +1435,7 @@ def at(ex, *args, **kwds): sage: var('s,t') (s, t) - sage: f=function('f', t) + sage: f=function('f')(t) sage: f.diff(t,2) D[0, 0](f)(t) sage: f.diff(t,2).laplace(t,s) @@ -1531,7 +1531,7 @@ def dummy_diff(*args): Here the function is used implicitly:: sage: a = var('a') - sage: f = function('cr', a) + sage: f = function('cr')(a) sage: g = f.diff(a); g D[0](cr)(a) """ @@ -1549,7 +1549,7 @@ def dummy_integrate(*args): EXAMPLES:: sage: from sage.calculus.calculus import dummy_integrate - sage: f(x) = function('f',x) + sage: f = function('f') sage: dummy_integrate(f(x), x) integrate(f(x), x) sage: a,b = var('a,b') @@ -1570,7 +1570,7 @@ def dummy_laplace(*args): sage: from sage.calculus.calculus import dummy_laplace sage: s,t = var('s,t') - sage: f(t) = function('f',t) + sage: f = function('f') sage: dummy_laplace(f(t),t,s) laplace(f(t), t, s) """ @@ -1585,7 +1585,7 @@ def dummy_inverse_laplace(*args): sage: from sage.calculus.calculus import dummy_inverse_laplace sage: s,t = var('s,t') - sage: F(s) = function('F',s) + sage: F = function('F') sage: dummy_inverse_laplace(F(s),s,t) ilt(F(s), s, t) """ @@ -1659,7 +1659,7 @@ def _laplace_latex_(self, *args): sage: from sage.calculus.calculus import _laplace_latex_ sage: var('s,t') (s, t) - sage: f = function('f',t) + sage: f = function('f')(t) sage: _laplace_latex_(0,f,t,s) '\\mathcal{L}\\left(f\\left(t\\right), t, s\\right)' sage: latex(laplace(f, t, s)) @@ -1678,7 +1678,7 @@ def _inverse_laplace_latex_(self, *args): sage: from sage.calculus.calculus import _inverse_laplace_latex_ sage: var('s,t') (s, t) - sage: F = function('F',s) + sage: F = function('F')(s) sage: _inverse_laplace_latex_(0,F,s,t) '\\mathcal{L}^{-1}\\left(F\\left(s\\right), s, t\\right)' sage: latex(inverse_laplace(F,s,t)) @@ -1741,7 +1741,7 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): sage: from sage.calculus.calculus import symbolic_expression_from_maxima_string as sefms sage: sefms('x^%e + %e^%pi + %i + sin(0)') x^e + e^pi + I - sage: f = function('f',x) + sage: f = function('f')(x) sage: sefms('?%at(f(x),x=2)#1') f(2) != 1 sage: a = sage.calculus.calculus.maxima("x#0"); a diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index ac28e833249..6e3977380ed 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -135,7 +135,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) EXAMPLES:: sage: x = var('x') - sage: y = function('y', x) + sage: y = function('y')(x) sage: desolve(diff(y,x) + y - 1, y) (_C + e^x)*e^(-x) @@ -152,7 +152,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) We can also solve second-order differential equations.:: sage: x = var('x') - sage: y = function('y', x) + sage: y = function('y')(x) sage: de = diff(y,x,2) - y == x sage: desolve(de, y) _K2*e^(-x) + _K1*e^x - x @@ -368,7 +368,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) Trac #9961 fixed (allow assumptions on the dependent variable in desolve):: - sage: y=function('y',x); assume(x>0); assume(y>0) + sage: y=function('y')(x); assume(x>0); assume(y>0) sage: sage.calculus.calculus.maxima('domain:real') # needed since Maxima 5.26.0 to get the answer as below real sage: desolve(x*diff(y,x)-x*sqrt(y^2+x^2)-y == 0, y, contrib_ode=True) @@ -388,7 +388,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) Trac #6479 fixed:: sage: x = var('x') - sage: y = function('y', x) + sage: y = function('y')(x) sage: desolve( diff(y,x,x) == 0, y, [0,0,1]) x @@ -400,7 +400,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) Trac #9835 fixed:: sage: x = var('x') - sage: y = function('y', x) + sage: y = function('y')(x) sage: desolve(diff(y,x,2)+y*(1-y^2)==0,y,[0,-1,1,1]) Traceback (most recent call last): ... @@ -408,7 +408,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) Trac #8931 fixed:: - sage: x=var('x'); f=function('f',x); k=var('k'); assume(k>0) + sage: x=var('x'); f=function('f')(x); k=var('k'); assume(k>0) sage: desolve(diff(f,x,2)/f==k,f,ivar=x) _K1*e^(sqrt(k)*x) + _K2*e^(-sqrt(k)*x) @@ -425,7 +425,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) if is_SymbolicEquation(de): de = de.lhs() - de.rhs() if is_SymbolicVariable(dvar): - raise ValueError("You have to declare dependent variable as a function, eg. y=function('y',x)") + raise ValueError("You have to declare dependent variable as a function evaluated at the independent variable, eg. y=function('y')(x)") # for backwards compatibility if isinstance(dvar, list): dvar, ivar = dvar @@ -543,7 +543,7 @@ def sanitize_var(exprs): ## EXAMPLES: ## sage: from sage.calculus.desolvers import desolve_laplace ## sage: x = var('x') -## sage: f = function('f', x) +## sage: f = function('f')(x) ## sage: de = lambda y: diff(y,x,x) - 2*diff(y,x) + y ## sage: desolve_laplace(de(f(x)),[f,x]) ## #x*%e^x*(?%at('diff('f(x),x,1),x=0))-'f(0)*x*%e^x+'f(0)*%e^x @@ -591,7 +591,7 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): EXAMPLES:: - sage: u=function('u',x) + sage: u=function('u')(x) sage: eq = diff(u,x) - exp(-x) - u == 0 sage: desolve_laplace(eq,u) 1/2*(2*u(0) + 1)*e^x - 1/2*e^(-x) @@ -609,7 +609,7 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): :: - sage: f=function('f', x) + sage: f=function('f')(x) sage: eq = diff(f,x) + f == 0 sage: desolve_laplace(eq,f,[0,1]) e^(-x) @@ -617,7 +617,7 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): :: sage: x = var('x') - sage: f = function('f', x) + sage: f = function('f')(x) sage: de = diff(f,x,x) - 2*diff(f,x) + f sage: desolve_laplace(de,f) -x*e^x*f(0) + x*e^x*D[0](f)(0) + e^x*f(0) @@ -632,7 +632,7 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): Trac #4839 fixed:: sage: t=var('t') - sage: x=function('x', t) + sage: x=function('x')(t) sage: soln=desolve_laplace(diff(x,t)+x==1, x, ics=[0,2]) sage: soln e^(-t) + 1 @@ -663,7 +663,7 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): if is_SymbolicEquation(de): de = de.lhs() - de.rhs() if is_SymbolicVariable(dvar): - raise ValueError("You have to declare dependent variable as a function, eg. y=function('y',x)") + raise ValueError("You have to declare dependent variable as a function evaluated at the independent variable, eg. y=function('y')(x)") # for backwards compatibility if isinstance(dvar, list): dvar, ivar = dvar @@ -717,8 +717,8 @@ def desolve_system(des, vars, ics=None, ivar=None): EXAMPLES:: sage: t = var('t') - sage: x = function('x', t) - sage: y = function('y', t) + sage: x = function('x')(t) + sage: y = function('y')(t) sage: de1 = diff(x,t) + y - 1 == 0 sage: de2 = diff(y,t) - x + 1 == 0 sage: desolve_system([de1, de2], [x,y]) @@ -741,7 +741,7 @@ def desolve_system(des, vars, ics=None, ivar=None): Check that :trac:`9823` is fixed:: sage: t = var('t') - sage: x = function('x', t) + sage: x = function('x')(t) sage: de1 = diff(x,t) + 1 == 0 sage: desolve_system([de1], [x]) -t + x(0) @@ -749,8 +749,8 @@ def desolve_system(des, vars, ics=None, ivar=None): Check that :trac:`16568` is fixed:: sage: t = var('t') - sage: x = function('x', t) - sage: y = function('y', t) + sage: x = function('x')(t) + sage: y = function('y')(t) sage: de1 = diff(x,t) + y - 1 == 0 sage: de2 = diff(y,t) - x + 1 == 0 sage: des = [de1,de2] @@ -776,8 +776,8 @@ def desolve_system(des, vars, ics=None, ivar=None): sage: t = var('t') sage: epsilon = var('epsilon') - sage: x1 = function('x1', t) - sage: x2 = function('x2', t) + sage: x1 = function('x1')(t) + sage: x2 = function('x2')(t) sage: de1 = diff(x1,t) == epsilon sage: de2 = diff(x2,t) == -2 sage: desolve_system([de1, de2], [x1, x2], ivar=t) @@ -1149,7 +1149,7 @@ def desolve_rk4(de, dvar, ics=None, ivar=None, end_points=None, step=0.1, output desolve function In this example we integrate bakwards, since ``end_points < ics[0]``:: - sage: y=function('y',x) + sage: y=function('y')(x) sage: desolve_rk4(diff(y,x)+y*(y-1) == x-2,y,ics=[1,1],step=0.5, end_points=0) [[0.0, 8.904257108962112], [0.5, 1.909327945361535], [1, 1]] diff --git a/src/sage/calculus/var.pyx b/src/sage/calculus/var.pyx index 98592f51979..458edc7d3c3 100644 --- a/src/sage/calculus/var.pyx +++ b/src/sage/calculus/var.pyx @@ -159,13 +159,13 @@ def function(s, *args, **kwds): (1) latex_name=LaTeX where ``LaTeX`` is any valid latex expression. - Ex: f = function('f', x, latex_name="\\mathcal{F}") + Ex: f = function('f', latex_name="\\mathcal{F}") See EXAMPLES for more. (2) print_latex_func=my_latex_print where ``my_latex_print`` is any callable function that returns a valid latex expression. - Ex: f = function('f', x, print_latex_func=my_latex_print) + Ex: f = function('f', print_latex_func=my_latex_print) See EXAMPLES for an explicit usage. .. note:: @@ -175,13 +175,12 @@ def function(s, *args, **kwds): code, it is better to use sage.symbolic.function_factory.function, since it won't touch the global namespace. - EXAMPLES:: + EXAMPLES: - We create a formal function called supersin:: + We create a formal function called supersin :: - sage: f = function('supersin', x) - sage: f - supersin(x) + sage: function('supersin') + supersin We can immediately use supersin in symbolic expressions:: @@ -203,7 +202,8 @@ def function(s, *args, **kwds): (1) Either using latex_name keyword:: - sage: riemann(x) = function('riemann', x, latex_name="\\mathcal{R}") + sage: function('riemann', latex_name="\\mathcal{R}") + riemann sage: latex(riemann(x)) \mathcal{R}\left(x\right) @@ -212,7 +212,8 @@ def function(s, *args, **kwds): sage: mu,nu = var('mu,nu') sage: def my_latex_print(self, *args): return "\\psi_{%s}"%(', '.join(map(latex, args))) - sage: psi(mu,nu) = function('psi', mu, nu, print_latex_func=my_latex_print) + sage: function('psi', print_latex_func=my_latex_print) + psi sage: latex(psi(mu,nu)) \psi_{\mu, \nu} @@ -221,8 +222,19 @@ def function(s, *args, **kwds): sage: k.substitute_function(supersin, sin) 2*cos(x)*sin(x) + + TESTS: + + Make sure that :trac:`15860` is fixed and whitespaces are removed:: + + sage: function('A, B') + (A, B) + sage: B + B """ if len(args) > 0: + from sage.misc.superseded import deprecation + deprecation(17447, "Calling function('f',x) is deprecated. Use function('f')(x) instead.") return function(s, **kwds)(*args) G = globals() # this is the reason the code must be in Cython. diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index ee7ab44d604..16b27a75aed 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1310,7 +1310,7 @@ cdef class Expression(CommutativeRingElement): sage: num_vars = 10; max_order=7 sage: X = var(' '.join(['x'+str(i) for i in range(num_vars)])) - sage: f = function('f',*X) + sage: f = function('f')(*X) sage: hashes=set() sage: for length in range(1,max_order+1): # long time (4s on sage.math, 2012) ... for s in UnorderedTuples(X, length): @@ -1586,7 +1586,7 @@ cdef class Expression(CommutativeRingElement): sage: x = var('x') sage: x._assume_str() '_SAGE_VAR_x' - sage: y = function('y', x) + sage: y = function('y')(x) sage: y._assume_str() 'y' sage: abs(x)._assume_str() @@ -1866,7 +1866,7 @@ cdef class Expression(CommutativeRingElement): Check if we can handle derivatives. :trac:`6523`:: - sage: f(x) = function('f',x) + sage: f(x) = function('f')(x) sage: f(x).diff(x).is_zero() False diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 53616f7098b..6f486ca714e 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -134,7 +134,7 @@ cdef class Function(SageObject): functions was broken. We check here that this is fixed (:trac:`11919`):: - sage: f = function('f', x) + sage: f = function('f')(x) sage: s = dumps(f) sage: loads(s) f(x) diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 600b91da2c5..1202368447e 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -8,7 +8,7 @@ def maxima_integrator(expression, v, a=None, b=None): -cos(x) sage: maxima_integrator(cos(x), x) sin(x) - sage: f(x) = function('f', x) + sage: f(x) = function('f')(x) sage: maxima_integrator(f(x), x) integrate(f(x), x) """ diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 13b9318afce..39836943f32 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -736,7 +736,7 @@ cdef class SymbolicRing(CommutativeRing): Note that you make get unexpected results when calling symbolic expressions and not explicitly giving the variables:: - sage: f = function('Gamma', var('z'), var('w')); f + sage: f = function('Gamma')(var('z'), var('w')); f Gamma(z, w) sage: f(2) Gamma(z, 2) From 6d27fbc78b76c41254d3f87da3cac0c1b1529b14 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 21 Jan 2015 19:19:29 +0100 Subject: [PATCH 0056/1872] create data_structures/mutual_poset.py --- src/sage/data_structures/mutable_poset.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/sage/data_structures/mutable_poset.py diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py new file mode 100644 index 00000000000..8d7112abe21 --- /dev/null +++ b/src/sage/data_structures/mutable_poset.py @@ -0,0 +1,17 @@ +r""" +Asymptotic Ring +""" +#***************************************************************************** +# Copyright (C) 2015 Daniel Krenn +# +# 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 sage + + +# ***************************************************************************** + From dcdc59a075651b589df89dca2d683786c3ff043b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 21 Jan 2015 19:22:16 +0100 Subject: [PATCH 0057/1872] create datastructure MutablePoset --- src/sage/data_structures/mutable_poset.py | 240 ++++++++++++++++++++++ 1 file changed, 240 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8d7112abe21..e1b80ca4ac8 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -15,3 +15,243 @@ # ***************************************************************************** + +class MutablePosetElement(sage.structure.sage_object.SageObject): + r""" + An element of a mutable poset. + """ + def __init__(self, poset, value): + r""" + See :class:`MutablePosetElement` for details. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: MutablePosetElement(P, (1, 2)) + (1, 2) + """ + self._poset_ = poset + self._value_ = value + self.predecessors = set() + self.successors = set() + + + @property + def poset(self): + r""" + The poset to which the element belongs. + + INPUT: + + Nothing. + + OUTPUT: + + A poset. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: e = MutablePosetElement(P, (1, 2)) + sage: e.poset is P + True + """ + return self._poset_ + + + @property + def value(self): + r""" + The value of the element. + + INPUT: + + Nothing. + + OUTPUT: + + An object. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: e = MutablePosetElement(P, (1, 2)) + sage: e.value + (1, 2) + """ + return self._value_ + + + def __repr__(self): + r""" + Return the representation of the element. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + This methods usually returns the representation string of its + :meth:`value`. The only exception is if this value is + ``None``. In this case either ``'zero'`` or ``'oo'`` is + returned depending in the nonexistence of predecessors and + sucessors respectively. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: repr(MutablePosetElement(P, (1, 2))) # indirect doctest + '(1, 2)' + sage: repr(P._zero_) # indirect doctest + 'zero' + sage: repr(P._oo_) # indirect doctest + 'oo' + """ + if self.value is None: + if not self.predecessors: + return 'zero' + if not self.successors: + return 'oo' + return repr(self.value) + + + def __hash__(self): + r""" + Return the hash of the element. + + INPUT: + + Nothing. + + OUTPUT: + + A hash value. + + This returns the hash value of the element. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: hash(MutablePosetElement(P, (1, 2))) == hash((1, 2)) + True + """ + return hash(self.value) + + +# ***************************************************************************** + + +class MutablePoset(sage.structure.sage_object.SageObject): + r""" + A mutable poset. + """ + def __init__(self, data=None): + r""" + See :class:`MutablePoset` for details. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: MP() + poset() + """ + + if data is not None: + raise NotImplementedError + + self._zero_ = MutablePosetElement(self, None) + self._oo_ = MutablePosetElement(self, None) + self._zero_.successors.add(self._oo_) + self._oo_.predecessors.add(self._zero_) + self._elements_ = {} + + + def iter_elements(self): + r""" + Return an iterator over all elements. + + INPUT: + + Nothing. + + OUTPUT: + + An iterator. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: tuple(P.iter_elements()) + () + """ + return self._elements_.itervalues() + + + def iter_all(self): + r""" + Return an iterator over all elements including a smallest + element (`0`) and a largest element (`\infty`). + + INPUT: + + Nothing. + + OUTPUT: + + An iterator. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: tuple(P.iter_all()) + (oo, zero) + """ + yield self._oo_ + for e in self._elements_.itervalues(): + yield e + yield self._zero_ + + + def repr(self): + r""" + Return a representation of the poset. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: print MP().repr() + poset() + """ + s = 'poset(' + s += ', '.join(repr(element) for element in self.iter_elements()) + s += ')' + return s + + + __repr__ = repr + + +# ***************************************************************************** From fd10e6b8863b20c03897ba0a86c4bb4fb00b79f6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 21 Jan 2015 19:22:53 +0100 Subject: [PATCH 0058/1872] implement element.__le__ --- src/sage/data_structures/mutable_poset.py | 74 +++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index e1b80ca4ac8..ed612669fa4 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -151,6 +151,80 @@ def __hash__(self): return hash(self.value) + def __le__(left, right): + r""" + Return if ``left`` is less or equal to ``right``. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + ``True`` or ``False``. + + This methods usually returns if the values of the given + elements are less or equal. The only exception is if this + value is ``None``. In this case the elements are considered as + special elements: If it has no predecessors, then it is + interpreted as an element smaller than any other, if it has no + successors, then as larger than any other. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: e = MutablePosetElement(P, (1, 2)) + sage: z = P._zero_ + sage: oo = P._oo_ + sage: z <= e + True + sage: e <= oo + True + sage: z <= oo + True + sage: oo <= z + False + sage: oo <= e + False + sage: e <= z + False + sage: z <= z + True + sage: oo <= oo + True + sage: e <= e + True + """ + if left.value is None: + if not left.predecessors: + # zero on the left + return True + else: + # oo on the left + if right.value is None: + # zero or oo on the right + return not right.successors + else: + # not zero, not oo on the right + return False + if right.value is None: + if not right.successors: + # oo on the right + return True + else: + # zero on the right + if left.value is None: + # zero or oo on the left + return not left.predecessors + else: + # not zero, not oo on the right + return False + return left.value <= right.value + # ***************************************************************************** From 103b63f5f55898b72801267337b443c393d6a201 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 21 Jan 2015 19:23:49 +0100 Subject: [PATCH 0059/1872] helper-function "sort set" --- src/sage/data_structures/mutable_poset.py | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ed612669fa4..3c0cb48d93d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -225,6 +225,36 @@ def __le__(left, right): return False return left.value <= right.value + +# ***************************************************************************** + + +def _sort_set_by_tuple_iter_(S, T): + r""" + Return an iterator over ``S`` respecting the order given by ``T``. + + INPUT: + + - ``S`` -- a set (or something which supports containment test). + + - ``T`` -- a tuple (or other iterable). + + OUTPUT: + + An iterator. + + In the iterator all elements of ``T``, which are also in ``S`` + appear. The order given by ``T`` is kept. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import _sort_set_by_tuple_iter_ + sage: tuple(_sort_set_by_tuple_iter_({3, 4, 6}, (5, 4, 1, 2, 3, 6))) + (4, 3, 6) + """ + return iter(ell for ell in T if ell in S) + + # ***************************************************************************** From 60d7d194f5ee0067e92ab3bb45d8b12319435504 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 21 Jan 2015 19:24:17 +0100 Subject: [PATCH 0060/1872] implement repr_full to show details --- src/sage/data_structures/mutable_poset.py | 47 +++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3c0cb48d93d..098dcc1438e 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -355,6 +355,53 @@ def repr(self): return s + def repr_full(self): + r""" + Return a representation with ordering details of the poset. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: print MP().repr_full() + poset() + +-- oo + | +-- no successors + | +-- predecessors: zero + +-- zero + | +-- successors: oo + | +-- no predecessors + """ + sortedelements = tuple(self.iter_all()) + strings = [self.repr()] + for element in sortedelements: + s = '+-- ' + repr(element) + '\n' + if element.successors: + s += '| +-- successors: ' + s += ', '.join(repr(e) for e in + _sort_set_by_tuple_iter_(element.successors, + sortedelements)) + else: + s += '| +-- no successors' + s += '\n' + if element.predecessors: + s += '| +-- predecessors: ' + s += ', '.join(repr(e) for e in + _sort_set_by_tuple_iter_(element.predecessors, + sortedelements)) + else: + s += '| +-- no predecessors' + strings.append(s) + return '\n'.join(strings) + + __repr__ = repr From 889ac2d30c6d23a9b8f53c453327f1132c2d5b8c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 10:20:41 +0100 Subject: [PATCH 0061/1872] add getter-function for successors/predecessors --- src/sage/data_structures/mutable_poset.py | 82 +++++++++++++++++++---- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 098dcc1438e..b91422b8c51 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -34,8 +34,8 @@ def __init__(self, poset, value): """ self._poset_ = poset self._value_ = value - self.predecessors = set() - self.successors = set() + self._predecessors_ = set() + self._successors_ = set() @property @@ -88,6 +88,60 @@ def value(self): return self._value_ + def predecessors(self, reverse=False): + r""" + Return the predecessors of the element. + + INPUT: + + - ``reverse`` -- (default: ``False``) if set, then returns + successors instead. + + OUTPUT: + + A set. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: e = MutablePosetElement(P, (1, 2)) + sage: e.predecessors() + set() + """ + if reverse: + return self._successors_ + return self._predecessors_ + + + def successors(self, reverse=False): + r""" + Return the successors of the element. + + INPUT: + + - ``reverse`` -- (default: ``False``) if set, then returns + predecessors instead. + + OUTPUT: + + A set. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: e = MutablePosetElement(P, (1, 2)) + sage: e.successors() + set() + """ + if reverse: + return self._predecessors_ + return self._successors_ + + def __repr__(self): r""" Return the representation of the element. @@ -119,9 +173,9 @@ def __repr__(self): 'oo' """ if self.value is None: - if not self.predecessors: + if not self.predecessors(): return 'zero' - if not self.successors: + if not self.successors(): return 'oo' return repr(self.value) @@ -200,26 +254,26 @@ def __le__(left, right): True """ if left.value is None: - if not left.predecessors: + if not left.predecessors(): # zero on the left return True else: # oo on the left if right.value is None: # zero or oo on the right - return not right.successors + return not right.successors() else: # not zero, not oo on the right return False if right.value is None: - if not right.successors: + if not right.successors(): # oo on the right return True else: # zero on the right if left.value is None: # zero or oo on the left - return not left.predecessors + return not left.predecessors() else: # not zero, not oo on the right return False @@ -278,8 +332,8 @@ def __init__(self, data=None): self._zero_ = MutablePosetElement(self, None) self._oo_ = MutablePosetElement(self, None) - self._zero_.successors.add(self._oo_) - self._oo_.predecessors.add(self._zero_) + self._zero_.successors().add(self._oo_) + self._oo_.predecessors().add(self._zero_) self._elements_ = {} @@ -383,18 +437,18 @@ def repr_full(self): strings = [self.repr()] for element in sortedelements: s = '+-- ' + repr(element) + '\n' - if element.successors: + if element.successors(): s += '| +-- successors: ' s += ', '.join(repr(e) for e in - _sort_set_by_tuple_iter_(element.successors, + _sort_set_by_tuple_iter_(element.successors(), sortedelements)) else: s += '| +-- no successors' s += '\n' - if element.predecessors: + if element.predecessors(): s += '| +-- predecessors: ' s += ', '.join(repr(e) for e in - _sort_set_by_tuple_iter_(element.predecessors, + _sort_set_by_tuple_iter_(element.predecessors(), sortedelements)) else: s += '| +-- no predecessors' From 9c84d7bd2d6bd033ec40d3cc83d66bf80a52fcc5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 10:21:29 +0100 Subject: [PATCH 0062/1872] reverse for iter_all --- src/sage/data_structures/mutable_poset.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index b91422b8c51..1e9bde2588b 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -359,7 +359,7 @@ def iter_elements(self): return self._elements_.itervalues() - def iter_all(self): + def iter_all(self, reverse=False): r""" Return an iterator over all elements including a smallest element (`0`) and a largest element (`\infty`). @@ -377,12 +377,13 @@ def iter_all(self): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() sage: tuple(P.iter_all()) - (oo, zero) + (zero, oo) """ - yield self._oo_ + yield self._oo_ if reverse else self._zero_ for e in self._elements_.itervalues(): yield e - yield self._zero_ + yield self._zero_ if reverse else self._oo_ + def repr(self): @@ -433,7 +434,7 @@ def repr_full(self): | +-- successors: oo | +-- no predecessors """ - sortedelements = tuple(self.iter_all()) + sortedelements = tuple(self.iter_all(reverse=True)) strings = [self.repr()] for element in sortedelements: s = '+-- ' + repr(element) + '\n' From 7ad391373da43cf9d19cd34b2be803c760183f2c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 10:28:47 +0100 Subject: [PATCH 0063/1872] reverse for le --- src/sage/data_structures/mutable_poset.py | 31 ++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 1e9bde2588b..ade008c36a0 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -205,7 +205,7 @@ def __hash__(self): return hash(self.value) - def __le__(left, right): + def le(left, right, reverse=False): r""" Return if ``left`` is less or equal to ``right``. @@ -215,6 +215,9 @@ def __le__(left, right): - ``right`` -- an element. + - ``reverse`` -- (default: ``False``) if set, then return + ``right <= left`` instead. + OUTPUT: ``True`` or ``False``. @@ -252,7 +255,31 @@ def __le__(left, right): True sage: e <= e True + + :: + + sage: z.le(e, reverse=True) + False + sage: e.le(oo, reverse=True) + False + sage: z.le(oo, reverse=True) + False + sage: oo.le(z, reverse=True) + True + sage: oo.le(e, reverse=True) + True + sage: e.le(z, reverse=True) + True + sage: z.le(z, reverse=True) + True + sage: oo.le(oo, reverse=True) + True + sage: e.le(e, reverse=True) + True """ + if reverse: + left, right = (right, left) + if left.value is None: if not left.predecessors(): # zero on the left @@ -280,6 +307,8 @@ def __le__(left, right): return left.value <= right.value + __le__ = le + # ***************************************************************************** From 533df6d58eddb46dd5ed4944170573e4450a35aa Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 11:11:51 +0100 Subject: [PATCH 0064/1872] rename iterators, add reverse-flag --- src/sage/data_structures/mutable_poset.py | 55 +++++++++-------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ade008c36a0..878215daaac 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -366,53 +366,41 @@ def __init__(self, data=None): self._elements_ = {} - def iter_elements(self): + + def elements(self, include_special=False, reverse=False): r""" Return an iterator over all elements. INPUT: - Nothing. - - OUTPUT: - - An iterator. - - TESTS:: - - sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: tuple(P.iter_elements()) - () - """ - return self._elements_.itervalues() - + - ``include_special`` -- (default: ``False``) if set, then + including a smallest element (`0`) and a largest element + (`\infty`). - def iter_all(self, reverse=False): - r""" - Return an iterator over all elements including a smallest - element (`0`) and a largest element (`\infty`). - - INPUT: - - Nothing. + - ``reverse`` -- (default: ``False``) if set, the order is + reversed. This only affects the elements `0` and `\infty`. OUTPUT: An iterator. - TESTS:: + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: tuple(P.iter_all()) + sage: tuple(P.elements()) + () + sage: tuple(P.elements(include_special=True)) (zero, oo) + sage: tuple(P.elements(include_special=True, reverse=True)) + (oo, zero) """ - yield self._oo_ if reverse else self._zero_ + if include_special: + yield self._zero_ if not reverse else self._oo_ for e in self._elements_.itervalues(): yield e - yield self._zero_ if reverse else self._oo_ - + if include_special: + yield self._oo_ if not reverse else self._zero_ def repr(self): @@ -434,12 +422,12 @@ def repr(self): poset() """ s = 'poset(' - s += ', '.join(repr(element) for element in self.iter_elements()) + s += ', '.join(repr(element) for element in self.elements()) s += ')' return s - def repr_full(self): + def repr_full(self, reverse=False): r""" Return a representation with ordering details of the poset. @@ -454,7 +442,7 @@ def repr_full(self): TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: print MP().repr_full() + sage: print MP().repr_full(reverse=True) poset() +-- oo | +-- no successors @@ -463,7 +451,8 @@ def repr_full(self): | +-- successors: oo | +-- no predecessors """ - sortedelements = tuple(self.iter_all(reverse=True)) + sortedelements = tuple( + self.elements(include_special=True, reverse=reverse)) strings = [self.repr()] for element in sortedelements: s = '+-- ' + repr(element) + '\n' From 1ae07a2b1089e1ea69165c20961d790fb4c3ccaf Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 12:36:20 +0100 Subject: [PATCH 0065/1872] implement is_zero, is_oo --- src/sage/data_structures/mutable_poset.py | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 878215daaac..2e2cf410d3e 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -142,6 +142,58 @@ def successors(self, reverse=False): return self._successors_ + def is_zero(self, reverse=False): + r""" + Return if the element is the zero-element, i.e., the element + smaller than any possible other element. + + INPUT: + + - ``reverse`` -- (default: ``False``) if set, then returns + if the element is the largest possible. + + OUTPUT: + + ``True`` or ``False``. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P._zero_.is_zero() + True + sage: P._oo_.is_zero() + False + """ + return self.value is None and not self.predecessors(reverse) + + + def is_oo(self, reverse=False): + r""" + Return if the element is the infinity-element, i.e., the element + larger than any possible other element. + + INPUT: + + - ``reverse`` -- (default: ``False``) if set, then returns + if the element is the smallest possible. + + OUTPUT: + + ``True`` or ``False``. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P._zero_.is_oo() + False + sage: P._oo_.is_oo() + True + """ + return self.value is None and not self.successors(reverse) + + def __repr__(self): r""" Return the representation of the element. From 9b0f8fb80663db276bdad4303bca806b7da2e537 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 12:39:39 +0100 Subject: [PATCH 0066/1872] implement equality testing for elements --- src/sage/data_structures/mutable_poset.py | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 2e2cf410d3e..ea27cde36cf 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -361,6 +361,49 @@ def le(left, right, reverse=False): __le__ = le + + def eq(left, right): + r""" + Return if ``left`` is equal to ``right``. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + ``True`` or ``False``. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: e = MutablePosetElement(P, (1, 2)) + sage: z = P._zero_ + sage: oo = P._oo_ + sage: z == z + True + sage: oo == oo + True + sage: e == e + True + sage: z == e + False + sage: e == oo + False + sage: oo == z + False + """ + if left.value is None and right.value is None: + return left.is_zero() == right.is_zero() + return left.value == right.value + + + __eq__ = eq + # ***************************************************************************** From c46abb0e809f29db5761bc813bbf9a959db07e6f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 13:32:40 +0100 Subject: [PATCH 0067/1872] method for adding element to poset; methods for finding covers --- src/sage/data_structures/mutable_poset.py | 225 ++++++++++++++++++++++ 1 file changed, 225 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ea27cde36cf..c7e9036c556 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -404,6 +404,114 @@ def eq(left, right): __eq__ = eq + + def _search_covers_(self, covers, element, reverse=False): + r""" + Helper function for :meth:`covers`. + + INPUT: + + - ``covers`` -- a set which finally contains all covers. + + - ``element`` -- the element for which to find the covering elements. + + - ``reverse`` -- (default: ``False``) if not set, then find + the lower covers, otherwise find the upper covers. + + OUTPUT: + + ``True`` or ``False``. + + Note that ``False`` is returned if we do not have + ``self <= element``. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1, 1))) + (1, 1, 1) + sage: P.add_element(T((1, 3, 1))) + (1, 3, 1) + sage: P.add_element(T((2, 1, 2))) + (2, 1, 2) + sage: P.add_element(T((4, 4, 2))) + (4, 4, 2) + sage: P.add_element(T((1, 2, 2))) + (1, 2, 2) + sage: e = P.add_element(T((2, 2, 2))); e + (2, 2, 2) + sage: covers = set() + sage: P._zero_._search_covers_(covers, e) + True + sage: covers + {(2, 1, 2), (1, 2, 2)} + """ + if not self.le(element, reverse) or self == element: + return False + if not any([e._search_covers_(covers, element, reverse) + for e in self.successors(reverse)]): + covers.add(self) + return True + + + def covers(self, element, reverse=False): + r""" + Return the covers of the given element (considering only + elements which originate from ``self``). + + INPUT: + + - ``element`` -- the element for which to find the covering elements. + + - ``reverse`` -- (default: ``False``) if not set, then find + the lower covers, otherwise find the upper covers. + + OUTPUT: + + A set of the covers. + + Suppose ``reverse`` is ``False``. This method returns all the + lower covers of the given ``element``, i.e., elements in the + poset, which are at most the given element and maximal with + this property. Only elements which are (not necessarily + direct) successors of ``self`` are considered. + + If ``reverse`` is ``True``, then the reverse direction is + taken, i.e., in the text above replace lower covers by upper + covers, maximal by minimal, and successors by predecessors. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1))) + (1, 1) + sage: P.add_element(T((1, 3))) + (1, 3) + sage: P.add_element(T((2, 1))) + (2, 1) + sage: P.add_element(T((4, 4))) + (4, 4) + sage: P.add_element(T((1, 2))) + (1, 2) + sage: e = P.add_element(T((2, 2))); e + (2, 2) + sage: P._zero_.covers(e) + {(2, 1), (1, 2)} + sage: P._oo_.covers(e, reverse=True) + {(4, 4)} + """ + covers = set() + self._search_covers_(covers, element, reverse) + return covers + # ***************************************************************************** @@ -573,4 +681,121 @@ def repr_full(self, reverse=False): __repr__ = repr + + def add_element(self, value): + r""" + Add the given object as element to the poset. + + INPUT: + + - ``value`` -- an object (hashable and supporting comparison + with the operator ``<=``. + + OUTPUT: + + The created (or already existing) element. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1))) + (1, 1) + sage: P.add_element(T((1, 3))) + (1, 3) + sage: P.add_element(T((2, 1))) + (2, 1) + sage: P.add_element(T((4, 4))) + (4, 4) + sage: P.add_element(T((1, 2))) + (1, 2) + sage: print P.repr_full(reverse=True) + poset((1, 2), (1, 3), (1, 1), (2, 1), (4, 4)) + +-- oo + | +-- no successors + | +-- predecessors: (4, 4) + +-- (1, 2) + | +-- successors: (1, 3) + | +-- predecessors: (1, 1) + +-- (1, 3) + | +-- successors: (4, 4) + | +-- predecessors: (1, 2) + +-- (1, 1) + | +-- successors: (1, 2), (2, 1) + | +-- predecessors: zero + +-- (2, 1) + | +-- successors: (4, 4) + | +-- predecessors: (1, 1) + +-- (4, 4) + | +-- successors: oo + | +-- predecessors: (1, 3), (2, 1) + +-- zero + | +-- successors: (1, 1) + | +-- no predecessors + sage: P.add_element(T((2, 2))) + (2, 2) + sage: print P.repr_full(reverse=True) + poset((1, 2), (1, 3), (4, 4), (2, 1), (2, 2), (1, 1)) + +-- oo + | +-- no successors + | +-- predecessors: (4, 4) + +-- (1, 2) + | +-- successors: (1, 3), (2, 2) + | +-- predecessors: (1, 1) + +-- (1, 3) + | +-- successors: (4, 4) + | +-- predecessors: (1, 2) + +-- (4, 4) + | +-- successors: oo + | +-- predecessors: (1, 3), (2, 2) + +-- (2, 1) + | +-- successors: (2, 2) + | +-- predecessors: (1, 1) + +-- (2, 2) + | +-- successors: (4, 4) + | +-- predecessors: (1, 2), (2, 1) + +-- (1, 1) + | +-- successors: (1, 2), (2, 1) + | +-- predecessors: zero + +-- zero + | +-- successors: (1, 1) + | +-- no predecessors + + When adding an element which is already in the poset, the + existing one is returned:: + + sage: e = T((2, 2)) + sage: f = P.add_element(e).value; f + (2, 2) + sage: e == f, e is f + (True, False) + """ + try: + return self._elements_[value] + except KeyError: + pass + if value is None: + raise ValueError('None is not allowed as value.') + + new = MutablePosetElement(self, value) + smaller = self._zero_.covers(new, reverse=False) + larger = self._oo_.covers(new, reverse=True) + + for reverse in (False, True): + sm = smaller if not reverse else larger + la = larger if not reverse else smaller + for element in sm: + for e in element.successors(reverse).intersection(la): + e.predecessors(reverse).remove(element) + element.successors(reverse).remove(e) + new.predecessors(reverse).add(element) + element.successors(reverse).add(new) + + self._elements_[value] = new + return new + + # ***************************************************************************** From ab2fe6d37d9ffb9f324271d552f40a61a2dcc30e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 13:39:31 +0100 Subject: [PATCH 0068/1872] implement iterator topological --- src/sage/data_structures/mutable_poset.py | 179 ++++++++++++++++++++++ 1 file changed, 179 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index c7e9036c556..e13f1cd3c63 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -512,6 +512,153 @@ def covers(self, element, reverse=False): self._search_covers_(covers, element, reverse) return covers + + def _iter_topological_visit_(self, marked, reverse=False, key=None): + r""" + Helper function for :meth:`iter_topological`. + + INPUT: + + - ``marked`` -- a set in which marked elements are stored. + + - ``reverse`` -- (default: ``False``) -- if set, reverses the order. + + - ``key`` -- (default: ``None``) a function used for sorting + the successors. If this is ``None``, no sorting occurrs. + + OUTPUT: + + An iterator. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add_element(42) + 42 + sage: P.add_element(5) + 5 + sage: marked = set() + sage: list(P._zero_._iter_topological_visit_( + ....: marked, True)) + [oo, 42, 5, zero] + """ + if self in marked: + return + marked.add(self) + S = self.predecessors(reverse) + if key is not None: + S = sorted(S, key=key) + for element in S: + for e in element._iter_topological_visit_(marked, reverse, key): + yield e + yield self + + + def iter_topological(self, reverse=False, key=None): + r""" + Iterates over all elements in topological order. + + INPUT: + + - ``reverse`` -- (default: ``False``) -- if set, reverses the + order, i.e., ``False`` gives smallest elements first, + ``True`` gives largest first. + + - ``key`` -- (default: ``None``) a function used for sorting + the direct successors of an element (used in case of a + tie). If this is ``None``, no sorting occurrs. + + OUTPUT: + + An iterator. + + ALGORITHM: + + Here a simplified version of the algorithm found in [T1976]_ + and [CLRS]_ is used. See also + :wikipedia:`Topological_sorting`. + + .. [T1976] Robert E. Tarjan, *Edge-disjoint spanning trees and + depth-first search*, Acta Informatica 6 (2), 1976, 171-185, + :doi:`10.1007/BF00268499`. + + .. [CLRS2001] Thomas H. Cormen, Charles E. Leiserson, Ronald + L. Rivest and Clifford Stein, *Section 22.4: Topological + sort*, Introduction to Algorithms (2nd ed.), MIT Press and + McGraw-Hill, 2001, 549-552, ISBN 0-262-03293-7. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1))) + (1, 1) + sage: P.add_element(T((1, 3))) + (1, 3) + sage: P.add_element(T((2, 1))) + (2, 1) + sage: P.add_element(T((4, 4))) + (4, 4) + sage: P.add_element(T((1, 2))) + (1, 2) + sage: P.add_element(T((2, 2))) + (2, 2) + + :: + + sage: for e in P.elements_topological(reverse=True): + ....: print e + ....: print list(e.iter_topological(reverse=True, + ....: key=lambda c: repr(c))) + oo + [oo] + (4, 4) + [oo, (4, 4)] + (1, 3) + [oo, (4, 4), (1, 3)] + (2, 2) + [oo, (4, 4), (2, 2)] + (1, 2) + [oo, (4, 4), (1, 3), (2, 2), (1, 2)] + (2, 1) + [oo, (4, 4), (2, 2), (2, 1)] + (1, 1) + [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)] + zero + [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), zero] + + :: + + sage: for e in P.elements_topological(reverse=True): + ....: print e + ....: print list(e.iter_topological(reverse=False, + ....: key=lambda c: repr(c))) + oo + [zero, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] + (4, 4) + [zero, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] + (1, 3) + [zero, (1, 1), (1, 2), (1, 3)] + (2, 2) + [zero, (1, 1), (1, 2), (2, 1), (2, 2)] + (1, 2) + [zero, (1, 1), (1, 2)] + (2, 1) + [zero, (1, 1), (2, 1)] + (1, 1) + [zero, (1, 1)] + zero + [zero] + """ + marked = set() + return self._iter_topological_visit_( + marked, reverse, key) + + # ***************************************************************************** @@ -606,6 +753,38 @@ def elements(self, include_special=False, reverse=False): yield self._oo_ if not reverse else self._zero_ + def elements_topological(self, reverse=False, key=None): + r""" + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1))) + (1, 1) + sage: P.add_element(T((1, 3))) + (1, 3) + sage: P.add_element(T((2, 1))) + (2, 1) + sage: P.add_element(T((4, 4))) + (4, 4) + sage: P.add_element(T((1, 2))) + (1, 2) + sage: P.add_element(T((2, 2))) + (2, 2) + sage: list(P.elements_topological()) + [zero, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] + sage: list(P.elements_topological(reverse=True)) + [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), zero] + """ + if key is None: + key = lambda c: repr(c) + element = self._oo_ if not reverse else self._zero_ + return element.iter_topological(reverse, key) + + def repr(self): r""" Return a representation of the poset. From 4ba5b77c42b86dd4cd7ac190aaa339b9f55e2197 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 15:42:38 +0100 Subject: [PATCH 0069/1872] depth first search for elements --- src/sage/data_structures/mutable_poset.py | 93 +++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index e13f1cd3c63..45c2c915414 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -513,6 +513,99 @@ def covers(self, element, reverse=False): return covers + def _iter_depth_first_visit_(self, marked, reverse=False, key=None): + r""" + Helper function for :meth:`iter_depth_first`. + + INPUT: + + - ``marked`` -- a set in which marked elements are stored. + + - ``reverse`` -- (default: ``False``) -- if set, reverses the order. + + - ``key`` -- (default: ``None``) a function used for sorting + the successors. If this is ``None``, no sorting occurrs. + + OUTPUT: + + An iterator. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add_element(42) + 42 + sage: P.add_element(5) + 5 + sage: marked = set() + sage: list(P._oo_._iter_depth_first_visit_(marked, True)) + [oo, 42, 5, zero] + """ + if self in marked: + return + marked.add(self) + yield self + S = self.successors(reverse) + if key is not None: + S = sorted(S, key=key) + for element in S: + for e in element._iter_depth_first_visit_(marked, reverse, key): + yield e + + + def iter_depth_first(self, reverse=False, key=None): + r""" + Iterates over all elements in depth first order. + + INPUT: + + - ``reverse`` -- (default: ``False``) -- if set, reverses the + order, i.e., ``False`` starts at bottom (`0`), + ``True`` starts at top (`\infty`). + + - ``key`` -- (default: ``None``) a function used for sorting + the direct successors of an element (used in case of a + tie). If this is ``None``, no sorting occurrs. + + OUTPUT: + + An iterator. + + ALGORITHM: + + See :wikipedia:`Depth-first_search`. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1))) + (1, 1) + sage: P.add_element(T((1, 3))) + (1, 3) + sage: P.add_element(T((2, 1))) + (2, 1) + sage: P.add_element(T((4, 4))) + (4, 4) + sage: P.add_element(T((1, 2))) + (1, 2) + sage: P.add_element(T((2, 2))) + (2, 2) + sage: list(P._zero_.iter_depth_first(reverse=False, + ....: key=lambda c: repr(c))) + [zero, (1, 1), (1, 2), (1, 3), (4, 4), oo, (2, 2), (2, 1)] + sage: list(P._oo_.iter_depth_first(reverse=True, + ....: key=lambda c: repr(c))) + [oo, (4, 4), (1, 3), (1, 2), (1, 1), zero, (2, 2), (2, 1)] + """ + marked = set() + return self._iter_depth_first_visit_(marked, reverse, key) + + def _iter_topological_visit_(self, marked, reverse=False, key=None): r""" Helper function for :meth:`iter_topological`. From abf45a26c2b0574cf096e43f71f0ffd187f19267 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 15:43:18 +0100 Subject: [PATCH 0070/1872] element.is_special --- src/sage/data_structures/mutable_poset.py | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 45c2c915414..ecb98e21faf 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -142,6 +142,34 @@ def successors(self, reverse=False): return self._successors_ + def is_special(self): + r""" + + Return if the element is either the zero-element, i.e., the + element smaller than any possible other element or the + infinity-element, i.e., the element larger than any possible + other element. + + INPUT: + + Nothing. + + OUTPUT: + + ``True`` or ``False``. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P._zero_.is_special() + True + sage: P._oo_.is_special() + True + """ + return self.value is None + + def is_zero(self, reverse=False): r""" Return if the element is the zero-element, i.e., the element From d23eba988c856f26f115af00de8bd5f4b09a65ad Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 15:46:25 +0100 Subject: [PATCH 0071/1872] remove unnecessary line breaks --- src/sage/data_structures/mutable_poset.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ecb98e21faf..6a168b00dd3 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -660,8 +660,7 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): sage: P.add_element(5) 5 sage: marked = set() - sage: list(P._zero_._iter_topological_visit_( - ....: marked, True)) + sage: list(P._zero_._iter_topological_visit_(marked, True)) [oo, 42, 5, zero] """ if self in marked: @@ -776,8 +775,7 @@ def iter_topological(self, reverse=False, key=None): [zero] """ marked = set() - return self._iter_topological_visit_( - marked, reverse, key) + return self._iter_topological_visit_(marked, reverse, key) # ***************************************************************************** From 505a88d5bd1fb1e06c24fe6a60c84b532f2fd7f1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 15:47:48 +0100 Subject: [PATCH 0072/1872] use topological search in repr (thereby including include_special-flag) --- src/sage/data_structures/mutable_poset.py | 66 +++++++++++++---------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 6a168b00dd3..bfe906ee619 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -730,7 +730,8 @@ def iter_topological(self, reverse=False, key=None): :: - sage: for e in P.elements_topological(reverse=True): + sage: for e in P.elements_topological(include_special=True, + ....: reverse=True): ....: print e ....: print list(e.iter_topological(reverse=True, ....: key=lambda c: repr(c))) @@ -753,7 +754,8 @@ def iter_topological(self, reverse=False, key=None): :: - sage: for e in P.elements_topological(reverse=True): + sage: for e in P.elements_topological(include_special=True, + ....: reverse=True): ....: print e ....: print list(e.iter_topological(reverse=False, ....: key=lambda c: repr(c))) @@ -872,7 +874,8 @@ def elements(self, include_special=False, reverse=False): yield self._oo_ if not reverse else self._zero_ - def elements_topological(self, reverse=False, key=None): + def elements_topological(self, include_special=False, + reverse=False, key=None): r""" EXAMPLES:: @@ -894,17 +897,23 @@ def elements_topological(self, reverse=False, key=None): sage: P.add_element(T((2, 2))) (2, 2) sage: list(P.elements_topological()) - [zero, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] + [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] sage: list(P.elements_topological(reverse=True)) + [(4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)] + sage: list(P.elements_topological(include_special=True)) + [zero, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] + sage: list(P.elements_topological( + ....: include_special=True, reverse=True)) [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), zero] """ if key is None: key = lambda c: repr(c) element = self._oo_ if not reverse else self._zero_ - return element.iter_topological(reverse, key) + return iter(e for e in element.iter_topological(reverse, key) + if include_special or not e.is_special()) - def repr(self): + def repr(self, include_special=False): r""" Return a representation of the poset. @@ -923,7 +932,8 @@ def repr(self): poset() """ s = 'poset(' - s += ', '.join(repr(element) for element in self.elements()) + s += ', '.join(repr(element) for element in + self.elements_topological(include_special, reverse=True)) s += ')' return s @@ -953,8 +963,8 @@ def repr_full(self, reverse=False): | +-- no predecessors """ sortedelements = tuple( - self.elements(include_special=True, reverse=reverse)) - strings = [self.repr()] + self.elements_topological(include_special=True, reverse=reverse)) + strings = [self.repr(include_special=False)] for element in sortedelements: s = '+-- ' + repr(element) + '\n' if element.successors(): @@ -1011,50 +1021,50 @@ def add_element(self, value): sage: P.add_element(T((1, 2))) (1, 2) sage: print P.repr_full(reverse=True) - poset((1, 2), (1, 3), (1, 1), (2, 1), (4, 4)) + poset((4, 4), (1, 3), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors | +-- predecessors: (4, 4) + +-- (4, 4) + | +-- successors: oo + | +-- predecessors: (1, 3), (2, 1) + +-- (1, 3) + | +-- successors: (4, 4) + | +-- predecessors: (1, 2) +-- (1, 2) | +-- successors: (1, 3) | +-- predecessors: (1, 1) - +-- (1, 3) + +-- (2, 1) | +-- successors: (4, 4) - | +-- predecessors: (1, 2) + | +-- predecessors: (1, 1) +-- (1, 1) | +-- successors: (1, 2), (2, 1) | +-- predecessors: zero - +-- (2, 1) - | +-- successors: (4, 4) - | +-- predecessors: (1, 1) - +-- (4, 4) - | +-- successors: oo - | +-- predecessors: (1, 3), (2, 1) +-- zero | +-- successors: (1, 1) | +-- no predecessors sage: P.add_element(T((2, 2))) (2, 2) sage: print P.repr_full(reverse=True) - poset((1, 2), (1, 3), (4, 4), (2, 1), (2, 2), (1, 1)) + poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors | +-- predecessors: (4, 4) - +-- (1, 2) - | +-- successors: (1, 3), (2, 2) - | +-- predecessors: (1, 1) - +-- (1, 3) - | +-- successors: (4, 4) - | +-- predecessors: (1, 2) +-- (4, 4) | +-- successors: oo | +-- predecessors: (1, 3), (2, 2) - +-- (2, 1) - | +-- successors: (2, 2) - | +-- predecessors: (1, 1) + +-- (1, 3) + | +-- successors: (4, 4) + | +-- predecessors: (1, 2) +-- (2, 2) | +-- successors: (4, 4) | +-- predecessors: (1, 2), (2, 1) + +-- (1, 2) + | +-- successors: (1, 3), (2, 2) + | +-- predecessors: (1, 1) + +-- (2, 1) + | +-- successors: (2, 2) + | +-- predecessors: (1, 1) +-- (1, 1) | +-- successors: (1, 2), (2, 1) | +-- predecessors: zero From 4734a83bc833968d525d6941c93e8107fce851c2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 15:48:09 +0100 Subject: [PATCH 0073/1872] implement remove_element --- src/sage/data_structures/mutable_poset.py | 112 ++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index bfe906ee619..8392a7adc84 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1106,4 +1106,116 @@ def add_element(self, value): return new + def remove_element(self, value): + r""" + Remove the given object from the poset. + + INPUT: + + - ``value`` -- an object. + + OUTPUT: + + Nothing. + + If the element is not a member, raise a ``KeyError``. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1))) + (1, 1) + sage: P.add_element(T((1, 3))) + (1, 3) + sage: P.add_element(T((2, 1))) + (2, 1) + sage: P.add_element(T((4, 4))) + (4, 4) + sage: P.add_element(T((1, 2))) + (1, 2) + sage: P.add_element(T((2, 2))) + (2, 2) + sage: print P.repr_full(reverse=True) + poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) + +-- oo + | +-- no successors + | +-- predecessors: (4, 4) + +-- (4, 4) + | +-- successors: oo + | +-- predecessors: (1, 3), (2, 2) + +-- (1, 3) + | +-- successors: (4, 4) + | +-- predecessors: (1, 2) + +-- (2, 2) + | +-- successors: (4, 4) + | +-- predecessors: (1, 2), (2, 1) + +-- (1, 2) + | +-- successors: (1, 3), (2, 2) + | +-- predecessors: (1, 1) + +-- (2, 1) + | +-- successors: (2, 2) + | +-- predecessors: (1, 1) + +-- (1, 1) + | +-- successors: (1, 2), (2, 1) + | +-- predecessors: zero + +-- zero + | +-- successors: (1, 1) + | +-- no predecessors + sage: P.remove_element(T((1, 2))) + sage: print P.repr_full(reverse=True) + poset((4, 4), (1, 3), (2, 2), (2, 1), (1, 1)) + +-- oo + | +-- no successors + | +-- predecessors: (4, 4) + +-- (4, 4) + | +-- successors: oo + | +-- predecessors: (1, 3), (2, 2) + +-- (1, 3) + | +-- successors: (4, 4) + | +-- predecessors: (1, 1) + +-- (2, 2) + | +-- successors: (4, 4) + | +-- predecessors: (2, 1) + +-- (2, 1) + | +-- successors: (2, 2) + | +-- predecessors: (1, 1) + +-- (1, 1) + | +-- successors: (1, 3), (2, 1) + | +-- predecessors: zero + +-- zero + | +-- successors: (1, 1) + | +-- no predecessors + + When adding an element which is already in the poset, the + existing one is returned:: + + sage: e = T((2, 2)) + sage: f = P.add_element(e).value; f + (2, 2) + sage: e == f, e is f + (True, False) + """ + if value is None: + raise ValueError('None is not allowed as value.') + + try: + element = self._elements_[value] + except KeyError: + raise KeyError('%s is not contained in this poset.' % (value,)) + + for reverse in (False, True): + for p in element.predecessors(reverse): + S = p.successors(reverse) + S.remove(element) + D = set(s for s in p.iter_depth_first(reverse) + if s in element.successors(reverse)) + S.update(element.successors(reverse)) + S.difference_update(D) + del self._elements_[value] + + # ***************************************************************************** From 2874696d68773afa1deac5723995de67e224c9cd Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 16:01:07 +0100 Subject: [PATCH 0074/1872] implement __contains__ --- src/sage/data_structures/mutable_poset.py | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8392a7adc84..abd59396c3d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -989,6 +989,34 @@ def repr_full(self, reverse=False): __repr__ = repr + def __contains__(self, value): + r""" + Tests if ``value`` is encapsulated by one of the poset's elements. + + INPUT: + + - ``value`` -- an object. + + OUTPUT: + + ``True`` or ``False``. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1))) + (1, 1) + sage: T((1, 1)) in P + True + sage: T((1, 2)) in P + False + """ + return value in self._elements_ + def add_element(self, value): r""" From e57d47b461c9181f71cabe7ea52bf2c8cf065445 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 16:14:26 +0100 Subject: [PATCH 0075/1872] fix machine-dependent doctest (containing a set) --- src/sage/data_structures/mutable_poset.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index abd59396c3d..2e723ed66ce 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -531,10 +531,12 @@ def covers(self, element, reverse=False): (1, 2) sage: e = P.add_element(T((2, 2))); e (2, 2) - sage: P._zero_.covers(e) - {(2, 1), (1, 2)} - sage: P._oo_.covers(e, reverse=True) - {(4, 4)} + sage: sorted(P._zero_.covers(e), + ....: key=lambda c: tuple(c.value)) + [(1, 2), (2, 1)] + sage: sorted(P._oo_.covers(e, reverse=True), + ....: key=lambda c: tuple(c.value)) + [(4, 4)] """ covers = set() self._search_covers_(covers, element, reverse) From f4b5240b3ab369e4e60d9bf222638b28626186fe Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 16:26:51 +0100 Subject: [PATCH 0076/1872] implement copy-method of poset --- src/sage/data_structures/mutable_poset.py | 88 +++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 2e723ed66ce..ec19d0b18fd 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -433,6 +433,49 @@ def eq(left, right): __eq__ = eq + def _copy_all_linked_(self, memo, poset): + r""" + Helper function for :meth:`MutablePoset.copy`. + + INPUT: + + - ``memo`` -- a dictionary which assigns to the id of ``self`` + a copy of ``self``. + + - ``poset`` -- the poset to which the newly created element belongs. + + OUTPUT: + + A new element. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: Q = MP() + sage: memo = {} + sage: z = P._zero_._copy_all_linked_(memo, Q) + sage: z.poset is Q + True + sage: oo = z.successors().pop() + sage: oo == P._oo_ + True + """ + try: + return memo[id(self)] + except KeyError: + pass + + new = self.__class__(poset, self.value) + memo[id(self)] = new + + for reverse in (False, True): + for e in self.successors(reverse): + new.successors(reverse).add(e._copy_all_linked_(memo, poset)) + + return new + + def _search_covers_(self, covers, element, reverse=False): r""" Helper function for :meth:`covers`. @@ -839,6 +882,51 @@ def __init__(self, data=None): self._elements_ = {} + def copy(self): + r""" + Creates a shallow copy. + + INPUT: + + Nothing. + + OUTPUT: + + A poset with the same content as ``self``. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add_element(T((1, 1))) + (1, 1) + sage: P.add_element(T((1, 3))) + (1, 3) + sage: P.add_element(T((2, 1))) + (2, 1) + sage: P.add_element(T((4, 4))) + (4, 4) + sage: P.add_element(T((1, 2))) + (1, 2) + sage: Q = P.copy() + sage: P.repr_full() == Q.repr_full() + True + """ + new = self.__class__() + memo = {} + new._zero_ = self._zero_._copy_all_linked_(memo, new) + new._oo_ = memo[id(self._oo_)] + new._elements_ = dict((f.value, f) for f in + iter(memo[id(e)] + for e in self._elements_.itervalues())) + return new + + + __copy__ = copy + def elements(self, include_special=False, reverse=False): r""" From 1288f99740de15b32043b4bef99b09ce3bfae7eb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 16:32:29 +0100 Subject: [PATCH 0077/1872] delete INPUT and OUTPUT of getter since useless --- src/sage/data_structures/mutable_poset.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ec19d0b18fd..e77f56b11aa 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -43,14 +43,6 @@ def poset(self): r""" The poset to which the element belongs. - INPUT: - - Nothing. - - OUTPUT: - - A poset. - TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -68,14 +60,6 @@ def value(self): r""" The value of the element. - INPUT: - - Nothing. - - OUTPUT: - - An object. - TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 0c2f235e880390da31b2d6587f50d9a83e893a6e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 16:35:39 +0100 Subject: [PATCH 0078/1872] getters for zero and oo --- src/sage/data_structures/mutable_poset.py | 86 ++++++++++++++++------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index e77f56b11aa..1ff290a988a 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -146,9 +146,9 @@ def is_special(self): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: P._zero_.is_special() + sage: P.zero.is_special() True - sage: P._oo_.is_special() + sage: P.oo.is_special() True """ return self.value is None @@ -172,9 +172,9 @@ def is_zero(self, reverse=False): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: P._zero_.is_zero() + sage: P.zero.is_zero() True - sage: P._oo_.is_zero() + sage: P.oo.is_zero() False """ return self.value is None and not self.predecessors(reverse) @@ -198,9 +198,9 @@ def is_oo(self, reverse=False): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: P._zero_.is_oo() + sage: P.zero.is_oo() False - sage: P._oo_.is_oo() + sage: P.oo.is_oo() True """ return self.value is None and not self.successors(reverse) @@ -231,9 +231,9 @@ def __repr__(self): sage: from sage.data_structures.mutable_poset import MutablePosetElement sage: repr(MutablePosetElement(P, (1, 2))) # indirect doctest '(1, 2)' - sage: repr(P._zero_) # indirect doctest + sage: repr(P.zero) # indirect doctest 'zero' - sage: repr(P._oo_) # indirect doctest + sage: repr(P.oo) # indirect doctest 'oo' """ if self.value is None: @@ -299,8 +299,8 @@ def le(left, right, reverse=False): sage: P = MP() sage: from sage.data_structures.mutable_poset import MutablePosetElement sage: e = MutablePosetElement(P, (1, 2)) - sage: z = P._zero_ - sage: oo = P._oo_ + sage: z = P.zero + sage: oo = P.oo sage: z <= e True sage: e <= oo @@ -394,8 +394,8 @@ def eq(left, right): sage: P = MP() sage: from sage.data_structures.mutable_poset import MutablePosetElement sage: e = MutablePosetElement(P, (1, 2)) - sage: z = P._zero_ - sage: oo = P._oo_ + sage: z = P.zero + sage: oo = P.oo sage: z == z True sage: oo == oo @@ -438,11 +438,11 @@ def _copy_all_linked_(self, memo, poset): sage: P = MP() sage: Q = MP() sage: memo = {} - sage: z = P._zero_._copy_all_linked_(memo, Q) + sage: z = P.zero._copy_all_linked_(memo, Q) sage: z.poset is Q True sage: oo = z.successors().pop() - sage: oo == P._oo_ + sage: oo == P.oo True """ try: @@ -500,7 +500,7 @@ def _search_covers_(self, covers, element, reverse=False): sage: e = P.add_element(T((2, 2, 2))); e (2, 2, 2) sage: covers = set() - sage: P._zero_._search_covers_(covers, e) + sage: P.zero._search_covers_(covers, e) True sage: covers {(2, 1, 2), (1, 2, 2)} @@ -558,10 +558,10 @@ def covers(self, element, reverse=False): (1, 2) sage: e = P.add_element(T((2, 2))); e (2, 2) - sage: sorted(P._zero_.covers(e), + sage: sorted(P.zero.covers(e), ....: key=lambda c: tuple(c.value)) [(1, 2), (2, 1)] - sage: sorted(P._oo_.covers(e, reverse=True), + sage: sorted(P.oo.covers(e, reverse=True), ....: key=lambda c: tuple(c.value)) [(4, 4)] """ @@ -596,7 +596,7 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): sage: P.add_element(5) 5 sage: marked = set() - sage: list(P._oo_._iter_depth_first_visit_(marked, True)) + sage: list(P.oo._iter_depth_first_visit_(marked, True)) [oo, 42, 5, zero] """ if self in marked: @@ -652,10 +652,10 @@ def iter_depth_first(self, reverse=False, key=None): (1, 2) sage: P.add_element(T((2, 2))) (2, 2) - sage: list(P._zero_.iter_depth_first(reverse=False, + sage: list(P.zero.iter_depth_first(reverse=False, ....: key=lambda c: repr(c))) [zero, (1, 1), (1, 2), (1, 3), (4, 4), oo, (2, 2), (2, 1)] - sage: list(P._oo_.iter_depth_first(reverse=True, + sage: list(P.oo.iter_depth_first(reverse=True, ....: key=lambda c: repr(c))) [oo, (4, 4), (1, 3), (1, 2), (1, 1), zero, (2, 2), (2, 1)] """ @@ -689,7 +689,7 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): sage: P.add_element(5) 5 sage: marked = set() - sage: list(P._zero_._iter_topological_visit_(marked, True)) + sage: list(P.zero._iter_topological_visit_(marked, True)) [oo, 42, 5, zero] """ if self in marked: @@ -866,6 +866,40 @@ def __init__(self, data=None): self._elements_ = {} + @property + def zero(self): + r""" + The element `0` which is smaller than any other element. + + EXAMPLES: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: z = P.zero; z + zero + sage: z.is_zero() + True + """ + return self._zero_ + + + @property + def oo(self): + r""" + The element `\infty` which is larger than any other element. + + EXAMPLES: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: oo = P.oo; oo + oo + sage: oo.is_oo() + True + """ + return self._oo_ + + def copy(self): r""" Creates a shallow copy. @@ -941,11 +975,11 @@ def elements(self, include_special=False, reverse=False): (oo, zero) """ if include_special: - yield self._zero_ if not reverse else self._oo_ + yield self.zero if not reverse else self.oo for e in self._elements_.itervalues(): yield e if include_special: - yield self._oo_ if not reverse else self._zero_ + yield self.oo if not reverse else self.zero def elements_topological(self, include_special=False, @@ -982,7 +1016,7 @@ def elements_topological(self, include_special=False, """ if key is None: key = lambda c: repr(c) - element = self._oo_ if not reverse else self._zero_ + element = self.oo if not reverse else self.zero return iter(e for e in element.iter_topological(reverse, key) if include_special or not e.is_special()) @@ -1191,8 +1225,8 @@ def add_element(self, value): raise ValueError('None is not allowed as value.') new = MutablePosetElement(self, value) - smaller = self._zero_.covers(new, reverse=False) - larger = self._oo_.covers(new, reverse=True) + smaller = self.zero.covers(new, reverse=False) + larger = self.oo.covers(new, reverse=True) for reverse in (False, True): sm = smaller if not reverse else larger From a6a275e2b7b5e64e1f9ee598feac4b7a31eb6d02 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 17:07:05 +0100 Subject: [PATCH 0079/1872] fixed another machine depended doctest --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 1ff290a988a..13692148f9d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -502,8 +502,8 @@ def _search_covers_(self, covers, element, reverse=False): sage: covers = set() sage: P.zero._search_covers_(covers, e) True - sage: covers - {(2, 1, 2), (1, 2, 2)} + sage: sorted(covers, key=lambda c: tuple(c.value)) + [(1, 2, 2), (2, 1, 2)] """ if not self.le(element, reverse) or self == element: return False From a331373f342d193b5fd56e2670a74c0de383a6b7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 17:18:19 +0100 Subject: [PATCH 0080/1872] replace zero by null --- src/sage/data_structures/mutable_poset.py | 142 +++++++++++----------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 13692148f9d..d6e6edf4361 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -129,7 +129,7 @@ def successors(self, reverse=False): def is_special(self): r""" - Return if the element is either the zero-element, i.e., the + Return if the element is either the null-element, i.e., the element smaller than any possible other element or the infinity-element, i.e., the element larger than any possible other element. @@ -146,7 +146,7 @@ def is_special(self): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: P.zero.is_special() + sage: P.null.is_special() True sage: P.oo.is_special() True @@ -154,9 +154,9 @@ def is_special(self): return self.value is None - def is_zero(self, reverse=False): + def is_null(self, reverse=False): r""" - Return if the element is the zero-element, i.e., the element + Return if the element is the null-element, i.e., the element smaller than any possible other element. INPUT: @@ -172,9 +172,9 @@ def is_zero(self, reverse=False): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: P.zero.is_zero() + sage: P.null.is_null() True - sage: P.oo.is_zero() + sage: P.oo.is_null() False """ return self.value is None and not self.predecessors(reverse) @@ -198,7 +198,7 @@ def is_oo(self, reverse=False): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: P.zero.is_oo() + sage: P.null.is_oo() False sage: P.oo.is_oo() True @@ -220,7 +220,7 @@ def __repr__(self): This methods usually returns the representation string of its :meth:`value`. The only exception is if this value is - ``None``. In this case either ``'zero'`` or ``'oo'`` is + ``None``. In this case either ``'null'`` or ``'oo'`` is returned depending in the nonexistence of predecessors and sucessors respectively. @@ -231,14 +231,14 @@ def __repr__(self): sage: from sage.data_structures.mutable_poset import MutablePosetElement sage: repr(MutablePosetElement(P, (1, 2))) # indirect doctest '(1, 2)' - sage: repr(P.zero) # indirect doctest - 'zero' + sage: repr(P.null) # indirect doctest + 'null' sage: repr(P.oo) # indirect doctest 'oo' """ if self.value is None: if not self.predecessors(): - return 'zero' + return 'null' if not self.successors(): return 'oo' return repr(self.value) @@ -299,7 +299,7 @@ def le(left, right, reverse=False): sage: P = MP() sage: from sage.data_structures.mutable_poset import MutablePosetElement sage: e = MutablePosetElement(P, (1, 2)) - sage: z = P.zero + sage: z = P.null sage: oo = P.oo sage: z <= e True @@ -346,27 +346,27 @@ def le(left, right, reverse=False): if left.value is None: if not left.predecessors(): - # zero on the left + # null on the left return True else: # oo on the left if right.value is None: - # zero or oo on the right + # null or oo on the right return not right.successors() else: - # not zero, not oo on the right + # not null, not oo on the right return False if right.value is None: if not right.successors(): # oo on the right return True else: - # zero on the right + # null on the right if left.value is None: - # zero or oo on the left + # null or oo on the left return not left.predecessors() else: - # not zero, not oo on the right + # not null, not oo on the right return False return left.value <= right.value @@ -394,7 +394,7 @@ def eq(left, right): sage: P = MP() sage: from sage.data_structures.mutable_poset import MutablePosetElement sage: e = MutablePosetElement(P, (1, 2)) - sage: z = P.zero + sage: z = P.null sage: oo = P.oo sage: z == z True @@ -410,7 +410,7 @@ def eq(left, right): False """ if left.value is None and right.value is None: - return left.is_zero() == right.is_zero() + return left.is_null() == right.is_null() return left.value == right.value @@ -438,7 +438,7 @@ def _copy_all_linked_(self, memo, poset): sage: P = MP() sage: Q = MP() sage: memo = {} - sage: z = P.zero._copy_all_linked_(memo, Q) + sage: z = P.null._copy_all_linked_(memo, Q) sage: z.poset is Q True sage: oo = z.successors().pop() @@ -500,7 +500,7 @@ def _search_covers_(self, covers, element, reverse=False): sage: e = P.add_element(T((2, 2, 2))); e (2, 2, 2) sage: covers = set() - sage: P.zero._search_covers_(covers, e) + sage: P.null._search_covers_(covers, e) True sage: sorted(covers, key=lambda c: tuple(c.value)) [(1, 2, 2), (2, 1, 2)] @@ -558,7 +558,7 @@ def covers(self, element, reverse=False): (1, 2) sage: e = P.add_element(T((2, 2))); e (2, 2) - sage: sorted(P.zero.covers(e), + sage: sorted(P.null.covers(e), ....: key=lambda c: tuple(c.value)) [(1, 2), (2, 1)] sage: sorted(P.oo.covers(e, reverse=True), @@ -597,7 +597,7 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): 5 sage: marked = set() sage: list(P.oo._iter_depth_first_visit_(marked, True)) - [oo, 42, 5, zero] + [oo, 42, 5, null] """ if self in marked: return @@ -618,7 +618,7 @@ def iter_depth_first(self, reverse=False, key=None): INPUT: - ``reverse`` -- (default: ``False``) -- if set, reverses the - order, i.e., ``False`` starts at bottom (`0`), + order, i.e., ``False`` starts at bottom (`\emptyset`), ``True`` starts at top (`\infty`). - ``key`` -- (default: ``None``) a function used for sorting @@ -652,12 +652,12 @@ def iter_depth_first(self, reverse=False, key=None): (1, 2) sage: P.add_element(T((2, 2))) (2, 2) - sage: list(P.zero.iter_depth_first(reverse=False, + sage: list(P.null.iter_depth_first(reverse=False, ....: key=lambda c: repr(c))) - [zero, (1, 1), (1, 2), (1, 3), (4, 4), oo, (2, 2), (2, 1)] + [null, (1, 1), (1, 2), (1, 3), (4, 4), oo, (2, 2), (2, 1)] sage: list(P.oo.iter_depth_first(reverse=True, ....: key=lambda c: repr(c))) - [oo, (4, 4), (1, 3), (1, 2), (1, 1), zero, (2, 2), (2, 1)] + [oo, (4, 4), (1, 3), (1, 2), (1, 1), null, (2, 2), (2, 1)] """ marked = set() return self._iter_depth_first_visit_(marked, reverse, key) @@ -689,8 +689,8 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): sage: P.add_element(5) 5 sage: marked = set() - sage: list(P.zero._iter_topological_visit_(marked, True)) - [oo, 42, 5, zero] + sage: list(P.null._iter_topological_visit_(marked, True)) + [oo, 42, 5, null] """ if self in marked: return @@ -778,8 +778,8 @@ def iter_topological(self, reverse=False, key=None): [oo, (4, 4), (2, 2), (2, 1)] (1, 1) [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)] - zero - [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), zero] + null + [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), null] :: @@ -789,21 +789,21 @@ def iter_topological(self, reverse=False, key=None): ....: print list(e.iter_topological(reverse=False, ....: key=lambda c: repr(c))) oo - [zero, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] + [null, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] (4, 4) - [zero, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] + [null, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] (1, 3) - [zero, (1, 1), (1, 2), (1, 3)] + [null, (1, 1), (1, 2), (1, 3)] (2, 2) - [zero, (1, 1), (1, 2), (2, 1), (2, 2)] + [null, (1, 1), (1, 2), (2, 1), (2, 2)] (1, 2) - [zero, (1, 1), (1, 2)] + [null, (1, 1), (1, 2)] (2, 1) - [zero, (1, 1), (2, 1)] + [null, (1, 1), (2, 1)] (1, 1) - [zero, (1, 1)] - zero - [zero] + [null, (1, 1)] + null + [null] """ marked = set() return self._iter_topological_visit_(marked, reverse, key) @@ -859,28 +859,28 @@ def __init__(self, data=None): if data is not None: raise NotImplementedError - self._zero_ = MutablePosetElement(self, None) + self._null_ = MutablePosetElement(self, None) self._oo_ = MutablePosetElement(self, None) - self._zero_.successors().add(self._oo_) - self._oo_.predecessors().add(self._zero_) + self._null_.successors().add(self._oo_) + self._oo_.predecessors().add(self._null_) self._elements_ = {} @property - def zero(self): + def null(self): r""" - The element `0` which is smaller than any other element. + The element `\emptyset` which is smaller than any other element. EXAMPLES: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: z = P.zero; z - zero - sage: z.is_zero() + sage: z = P.null; z + null + sage: z.is_null() True """ - return self._zero_ + return self._null_ @property @@ -935,7 +935,7 @@ def copy(self): """ new = self.__class__() memo = {} - new._zero_ = self._zero_._copy_all_linked_(memo, new) + new._null_ = self._null_._copy_all_linked_(memo, new) new._oo_ = memo[id(self._oo_)] new._elements_ = dict((f.value, f) for f in iter(memo[id(e)] @@ -953,11 +953,11 @@ def elements(self, include_special=False, reverse=False): INPUT: - ``include_special`` -- (default: ``False``) if set, then - including a smallest element (`0`) and a largest element + including a smallest element (`\emptyset`) and a largest element (`\infty`). - ``reverse`` -- (default: ``False``) if set, the order is - reversed. This only affects the elements `0` and `\infty`. + reversed. This only affects the elements `\emptyset` and `\infty`. OUTPUT: @@ -970,16 +970,16 @@ def elements(self, include_special=False, reverse=False): sage: tuple(P.elements()) () sage: tuple(P.elements(include_special=True)) - (zero, oo) + (null, oo) sage: tuple(P.elements(include_special=True, reverse=True)) - (oo, zero) + (oo, null) """ if include_special: - yield self.zero if not reverse else self.oo + yield self.null if not reverse else self.oo for e in self._elements_.itervalues(): yield e if include_special: - yield self.oo if not reverse else self.zero + yield self.oo if not reverse else self.null def elements_topological(self, include_special=False, @@ -1009,14 +1009,14 @@ def elements_topological(self, include_special=False, sage: list(P.elements_topological(reverse=True)) [(4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)] sage: list(P.elements_topological(include_special=True)) - [zero, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] + [null, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] sage: list(P.elements_topological( ....: include_special=True, reverse=True)) - [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), zero] + [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), null] """ if key is None: key = lambda c: repr(c) - element = self.oo if not reverse else self.zero + element = self.oo if not reverse else self.null return iter(e for e in element.iter_topological(reverse, key) if include_special or not e.is_special()) @@ -1065,8 +1065,8 @@ def repr_full(self, reverse=False): poset() +-- oo | +-- no successors - | +-- predecessors: zero - +-- zero + | +-- predecessors: null + +-- null | +-- successors: oo | +-- no predecessors """ @@ -1175,8 +1175,8 @@ def add_element(self, value): | +-- predecessors: (1, 1) +-- (1, 1) | +-- successors: (1, 2), (2, 1) - | +-- predecessors: zero - +-- zero + | +-- predecessors: null + +-- null | +-- successors: (1, 1) | +-- no predecessors sage: P.add_element(T((2, 2))) @@ -1203,8 +1203,8 @@ def add_element(self, value): | +-- predecessors: (1, 1) +-- (1, 1) | +-- successors: (1, 2), (2, 1) - | +-- predecessors: zero - +-- zero + | +-- predecessors: null + +-- null | +-- successors: (1, 1) | +-- no predecessors @@ -1225,7 +1225,7 @@ def add_element(self, value): raise ValueError('None is not allowed as value.') new = MutablePosetElement(self, value) - smaller = self.zero.covers(new, reverse=False) + smaller = self.null.covers(new, reverse=False) larger = self.oo.covers(new, reverse=True) for reverse in (False, True): @@ -1297,8 +1297,8 @@ def remove_element(self, value): | +-- predecessors: (1, 1) +-- (1, 1) | +-- successors: (1, 2), (2, 1) - | +-- predecessors: zero - +-- zero + | +-- predecessors: null + +-- null | +-- successors: (1, 1) | +-- no predecessors sage: P.remove_element(T((1, 2))) @@ -1321,8 +1321,8 @@ def remove_element(self, value): | +-- predecessors: (1, 1) +-- (1, 1) | +-- successors: (1, 3), (2, 1) - | +-- predecessors: zero - +-- zero + | +-- predecessors: null + +-- null | +-- successors: (1, 1) | +-- no predecessors From cbf3bffcf272068dcf9844d95b36f38af8d07f92 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 22 Jan 2015 19:19:26 +0100 Subject: [PATCH 0081/1872] introduce keys --- src/sage/data_structures/mutable_poset.py | 214 ++++++++++++++++++---- 1 file changed, 182 insertions(+), 32 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d6e6edf4361..8fb8d11f292 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -72,6 +72,29 @@ def value(self): return self._value_ + @property + def key(self): + r""" + The key of the element. + + The value of the element is converted by the poset to the key. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: P = MP() + sage: e = MutablePosetElement(P, (1, 2)) + sage: e.key + (1, 2) + sage: Q = MP(key=lambda k: k[0]) + sage: f = MutablePosetElement(Q, (1, 2)) + sage: f.key + 1 + """ + return self.poset.get_key(self._value_) + + def predecessors(self, reverse=False): r""" Return the predecessors of the element. @@ -256,7 +279,7 @@ def __hash__(self): A hash value. - This returns the hash value of the element. + This returns the hash value of the key of this element. TESTS:: @@ -266,7 +289,7 @@ def __hash__(self): sage: hash(MutablePosetElement(P, (1, 2))) == hash((1, 2)) True """ - return hash(self.value) + return hash(self.key) def le(left, right, reverse=False): @@ -286,8 +309,8 @@ def le(left, right, reverse=False): ``True`` or ``False``. - This methods usually returns if the values of the given - elements are less or equal. The only exception is if this + This methods usually returns if the keys of the given + elements are less or equal. The only exception is if the value is ``None``. In this case the elements are considered as special elements: If it has no predecessors, then it is interpreted as an element smaller than any other, if it has no @@ -368,7 +391,7 @@ def le(left, right, reverse=False): else: # not null, not oo on the right return False - return left.value <= right.value + return left.key <= right.key __le__ = le @@ -388,6 +411,8 @@ def eq(left, right): ``True`` or ``False``. + This method compares the keys of the elements. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -411,7 +436,7 @@ def eq(left, right): """ if left.value is None and right.value is None: return left.is_null() == right.is_null() - return left.value == right.value + return left.key == right.key __eq__ = eq @@ -502,7 +527,7 @@ def _search_covers_(self, covers, element, reverse=False): sage: covers = set() sage: P.null._search_covers_(covers, e) True - sage: sorted(covers, key=lambda c: tuple(c.value)) + sage: sorted(covers, key=lambda c: repr(c.value)) [(1, 2, 2), (2, 1, 2)] """ if not self.le(element, reverse) or self == element: @@ -559,10 +584,10 @@ def covers(self, element, reverse=False): sage: e = P.add_element(T((2, 2))); e (2, 2) sage: sorted(P.null.covers(e), - ....: key=lambda c: tuple(c.value)) + ....: key=lambda c: repr(c.value)) [(1, 2), (2, 1)] sage: sorted(P.oo.covers(e, reverse=True), - ....: key=lambda c: tuple(c.value)) + ....: key=lambda c: repr(c.value)) [(4, 4)] """ covers = set() @@ -845,7 +870,7 @@ class MutablePoset(sage.structure.sage_object.SageObject): r""" A mutable poset. """ - def __init__(self, data=None): + def __init__(self, data=None, key=None): r""" See :class:`MutablePoset` for details. @@ -865,6 +890,11 @@ def __init__(self, data=None): self._oo_.predecessors().add(self._null_) self._elements_ = {} + if key is None: + self._key_ = lambda k: k + else: + self._key_ = key + @property def null(self): @@ -900,6 +930,36 @@ def oo(self): return self._oo_ + def get_key(self, value): + r""" + Return the key corresponding to ``value``. + + INPUT: + + - ``value`` -- an object. + + OUTPUT: + + An object (the key of ``value``). + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: P = MP() + sage: P.get_key(None) is None + True + sage: P.get_key((1, 2)) + (1, 2) + sage: Q = MP(key=lambda k: k[0]) + sage: Q.get_key((1, 2)) + 1 + """ + if value is None: + return None + return self._key_(value) + + def copy(self): r""" Creates a shallow copy. @@ -937,7 +997,7 @@ def copy(self): memo = {} new._null_ = self._null_._copy_all_linked_(memo, new) new._oo_ = memo[id(self._oo_)] - new._elements_ = dict((f.value, f) for f in + new._elements_ = dict((f.key, f) for f in iter(memo[id(e)] for e in self._elements_.itervalues())) return new @@ -1097,13 +1157,13 @@ def repr_full(self, reverse=False): __repr__ = repr - def __contains__(self, value): + def __contains__(self, key): r""" - Tests if ``value`` is encapsulated by one of the poset's elements. + Tests if ``key`` is encapsulated by one of the poset's elements. INPUT: - - ``value`` -- an object. + - ``key`` -- an object. OUTPUT: @@ -1123,7 +1183,7 @@ def __contains__(self, value): sage: T((1, 2)) in P False """ - return value in self._elements_ + return key in self._elements_ def add_element(self, value): @@ -1216,13 +1276,45 @@ def add_element(self, value): (2, 2) sage: e == f, e is f (True, False) + + TESTS:: + + sage: R = MP(key=lambda k: T(k[2:3])) + sage: R.add_element(T((1, 1, 42))) + (1, 1, 42) + sage: R.add_element(T((1, 3, 42))) + (1, 1, 42) + sage: R.add_element(T((2, 1, 7))) + (2, 1, 7) + sage: R.add_element(T((4, 4, 42))) + (1, 1, 42) + sage: R.add_element(T((1, 2, 7))) + (2, 1, 7) + sage: R.add_element(T((2, 2, 7))) + (2, 1, 7) + sage: print R.repr_full(reverse=True) + poset((1, 1, 42), (2, 1, 7)) + +-- oo + | +-- no successors + | +-- predecessors: (1, 1, 42) + +-- (1, 1, 42) + | +-- successors: oo + | +-- predecessors: (2, 1, 7) + +-- (2, 1, 7) + | +-- successors: (1, 1, 42) + | +-- predecessors: null + +-- null + | +-- successors: (2, 1, 7) + | +-- no predecessors """ + if value is None: + raise ValueError('None is not allowed as value.') + key = self.get_key(value) + try: - return self._elements_[value] + return self._elements_[key] except KeyError: pass - if value is None: - raise ValueError('None is not allowed as value.') new = MutablePosetElement(self, value) smaller = self.null.covers(new, reverse=False) @@ -1238,11 +1330,11 @@ def add_element(self, value): new.predecessors(reverse).add(element) element.successors(reverse).add(new) - self._elements_[value] = new + self._elements_[key] = new return new - def remove_element(self, value): + def remove_element(self, key): r""" Remove the given object from the poset. @@ -1326,22 +1418,80 @@ def remove_element(self, value): | +-- successors: (1, 1) | +-- no predecessors - When adding an element which is already in the poset, the - existing one is returned:: + TESTS:: - sage: e = T((2, 2)) - sage: f = P.add_element(e).value; f - (2, 2) - sage: e == f, e is f - (True, False) + sage: Q = MP(key=lambda k: T(k[0:2])) + sage: Q.add_element(T((1, 1, 42))) + (1, 1, 42) + sage: Q.add_element(T((1, 3, 42))) + (1, 3, 42) + sage: Q.add_element(T((2, 1, 7))) + (2, 1, 7) + sage: Q.add_element(T((4, 4, 42))) + (4, 4, 42) + sage: Q.add_element(T((1, 2, 7))) + (1, 2, 7) + sage: Q.add_element(T((2, 2, 7))) + (2, 2, 7) + sage: print Q.repr_full(reverse=True) + poset((4, 4, 42), (1, 3, 42), (2, 2, 7), + (1, 2, 7), (2, 1, 7), (1, 1, 42)) + +-- oo + | +-- no successors + | +-- predecessors: (4, 4, 42) + +-- (4, 4, 42) + | +-- successors: oo + | +-- predecessors: (1, 3, 42), (2, 2, 7) + +-- (1, 3, 42) + | +-- successors: (4, 4, 42) + | +-- predecessors: (1, 2, 7) + +-- (2, 2, 7) + | +-- successors: (4, 4, 42) + | +-- predecessors: (1, 2, 7), (2, 1, 7) + +-- (1, 2, 7) + | +-- successors: (1, 3, 42), (2, 2, 7) + | +-- predecessors: (1, 1, 42) + +-- (2, 1, 7) + | +-- successors: (2, 2, 7) + | +-- predecessors: (1, 1, 42) + +-- (1, 1, 42) + | +-- successors: (1, 2, 7), (2, 1, 7) + | +-- predecessors: null + +-- null + | +-- successors: (1, 1, 42) + | +-- no predecessors + sage: Q.remove_element((1,1)) + sage: print Q.repr_full(reverse=True) + poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7)) + +-- oo + | +-- no successors + | +-- predecessors: (4, 4, 42) + +-- (4, 4, 42) + | +-- successors: oo + | +-- predecessors: (1, 3, 42), (2, 2, 7) + +-- (1, 3, 42) + | +-- successors: (4, 4, 42) + | +-- predecessors: (1, 2, 7) + +-- (2, 2, 7) + | +-- successors: (4, 4, 42) + | +-- predecessors: (1, 2, 7), (2, 1, 7) + +-- (1, 2, 7) + | +-- successors: (1, 3, 42), (2, 2, 7) + | +-- predecessors: null + +-- (2, 1, 7) + | +-- successors: (2, 2, 7) + | +-- predecessors: null + +-- null + | +-- successors: (1, 2, 7), (2, 1, 7) + | +-- no predecessors """ - if value is None: - raise ValueError('None is not allowed as value.') + if key is None: + raise ValueError('None is not allowed as key.') try: - element = self._elements_[value] + element = self._elements_[key] except KeyError: - raise KeyError('%s is not contained in this poset.' % (value,)) + raise KeyError('Key %s is not contained in this poset.' % (key,)) for reverse in (False, True): for p in element.predecessors(reverse): @@ -1351,7 +1501,7 @@ def remove_element(self, value): if s in element.successors(reverse)) S.update(element.successors(reverse)) S.difference_update(D) - del self._elements_[value] + del self._elements_[key] # ***************************************************************************** From 49bd53c142f321f67b988f91a5a378da116268de Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 23 Jan 2015 09:27:13 +0100 Subject: [PATCH 0082/1872] make reference-doc build --- src/doc/en/reference/data_structures/index.rst | 1 + src/sage/data_structures/mutable_poset.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/en/reference/data_structures/index.rst b/src/doc/en/reference/data_structures/index.rst index 52e3280b17d..90bf85efdf2 100644 --- a/src/doc/en/reference/data_structures/index.rst +++ b/src/doc/en/reference/data_structures/index.rst @@ -7,5 +7,6 @@ Data Structures sage/misc/binary_tree sage/data_structures/bitset sage/data_structures/bounded_integer_sequences + sage/data_structures/mutable_poset .. include:: ../footer.txt diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8fb8d11f292..d61214b20bb 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1,5 +1,5 @@ r""" -Asymptotic Ring +Mutable Poset """ #***************************************************************************** # Copyright (C) 2015 Daniel Krenn @@ -750,7 +750,7 @@ def iter_topological(self, reverse=False, key=None): ALGORITHM: Here a simplified version of the algorithm found in [T1976]_ - and [CLRS]_ is used. See also + and [CLRS2001]_ is used. See also :wikipedia:`Topological_sorting`. .. [T1976] Robert E. Tarjan, *Edge-disjoint spanning trees and From c7d01874651070940d95e043e028009918f3eba5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 23 Jan 2015 14:54:15 +0100 Subject: [PATCH 0083/1872] rename helper to sorted_set_by_tuple --- src/sage/data_structures/mutable_poset.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d61214b20bb..f192edcd84a 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -837,7 +837,7 @@ def iter_topological(self, reverse=False, key=None): # ***************************************************************************** -def _sort_set_by_tuple_iter_(S, T): +def sorted_set_by_tuple(S, T): r""" Return an iterator over ``S`` respecting the order given by ``T``. @@ -856,8 +856,8 @@ def _sort_set_by_tuple_iter_(S, T): EXAMPLES:: - sage: from sage.data_structures.mutable_poset import _sort_set_by_tuple_iter_ - sage: tuple(_sort_set_by_tuple_iter_({3, 4, 6}, (5, 4, 1, 2, 3, 6))) + sage: from sage.data_structures.mutable_poset import sorted_set_by_tuple + sage: tuple(sorted_set_by_tuple({3, 4, 6}, (5, 4, 1, 2, 3, 6))) (4, 3, 6) """ return iter(ell for ell in T if ell in S) @@ -1138,16 +1138,16 @@ def repr_full(self, reverse=False): if element.successors(): s += '| +-- successors: ' s += ', '.join(repr(e) for e in - _sort_set_by_tuple_iter_(element.successors(), - sortedelements)) + sorted_set_by_tuple(element.successors(), + sortedelements)) else: s += '| +-- no successors' s += '\n' if element.predecessors(): s += '| +-- predecessors: ' s += ', '.join(repr(e) for e in - _sort_set_by_tuple_iter_(element.predecessors(), - sortedelements)) + sorted_set_by_tuple(element.predecessors(), + sortedelements)) else: s += '| +-- no predecessors' strings.append(s) From de511f70b84878e81044ecd3f9c0de600e4be5a6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 23 Jan 2015 16:17:02 +0100 Subject: [PATCH 0084/1872] introduce toset --- src/sage/data_structures/mutable_poset.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index f192edcd84a..3ad339c1d2e 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1505,3 +1505,20 @@ def remove_element(self, key): # ***************************************************************************** + + +class MutableTosetElement(MutablePosetElement): + pass + + +# ***************************************************************************** + + +class MutableToset(MutablePoset): + r""" + A mutable toset (totally ordered set) as data structure. + """ + pass + + +# ***************************************************************************** From b9a65ce3a66b450f4cc153315d20f7a3e22d0926 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 23 Jan 2015 16:17:35 +0100 Subject: [PATCH 0085/1872] some code rewriting (w.r.t. repr and reverse) --- src/sage/data_structures/mutable_poset.py | 34 ++++++++++------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3ad339c1d2e..5944145ca3f 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1081,7 +1081,7 @@ def elements_topological(self, include_special=False, if include_special or not e.is_special()) - def repr(self, include_special=False): + def repr(self, include_special=False, reverse=False): r""" Return a representation of the poset. @@ -1101,7 +1101,7 @@ def repr(self, include_special=False): """ s = 'poset(' s += ', '.join(repr(element) for element in - self.elements_topological(include_special, reverse=True)) + self.elements_topological(include_special, reverse)) s += ')' return s @@ -1132,25 +1132,19 @@ def repr_full(self, reverse=False): """ sortedelements = tuple( self.elements_topological(include_special=True, reverse=reverse)) - strings = [self.repr(include_special=False)] + strings = [self.repr(include_special=False, reverse=reverse)] for element in sortedelements: - s = '+-- ' + repr(element) + '\n' - if element.successors(): - s += '| +-- successors: ' - s += ', '.join(repr(e) for e in - sorted_set_by_tuple(element.successors(), - sortedelements)) - else: - s += '| +-- no successors' - s += '\n' - if element.predecessors(): - s += '| +-- predecessors: ' - s += ', '.join(repr(e) for e in - sorted_set_by_tuple(element.predecessors(), - sortedelements)) - else: - s += '| +-- no predecessors' - strings.append(s) + strings.append('+-- ' + repr(element)) + for rev in (not reverse, reverse): + what = 'successors' if not rev else 'predecessors' + if element.successors(rev): + s = '| +-- ' + what + ': ' + s += ', '.join(repr(e) for e in + sorted_set_by_tuple(element.successors(rev), + sortedelements)) + else: + s = '| +-- no ' + what + strings.append(s) return '\n'.join(strings) From 7774e9b940020671f658c35637f97637ea888dc5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 23 Jan 2015 19:51:11 +0100 Subject: [PATCH 0086/1872] started writing top-level documentation --- src/sage/data_structures/mutable_poset.py | 146 +++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 5944145ca3f..6343b67bde2 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1,5 +1,149 @@ r""" Mutable Poset + +This module provides a class representing a finite partially ordered +set (poset) for the purpose of being used as a data structure. Thus +the here introduced posets are mutable, i.e., elements can be added and +removed from a poset at any time. + +To get in touch with Sage's "usual" posets, start with the page +:mod:`Posets ` in the reference manual. + + +.. _mutable_poset_intro: + +Introduction +============ + + +.. _mutable_poset_examples: + +Examples +======== + +First Steps +----------- + +We start by creating an empty poset. This is simply done by + +:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P + poset() + +A poset should contain elements, thus let us add them with + +:: + + sage: P.add_element(42) + sage: P.add_element(7) + sage: P.add_element(13) + sage: P.add_element(3) + +Let us look at the poset again:: + + sage: P + poset(3, 7, 13, 42) + +We see that they elements are sorted using `\leq` which exists on the +integers `\ZZ`. Since this is even a total order, we could have used +the more efficient :class:`MutableToset`. (Note that also other data +structures are suitable for totally ordered sets.) + + +A less boring Example +--------------------- + +Let us continue with a less boring example. We define the class + +:: + + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + +It is equipped with a `\leq`-operation which makes `a \leq b` if all +entries of `a` are at most `b`. For example, we have + +:: + + sage: a = T((1,1)) + sage: b = T((2,1)) + sage: c = T((1,2)) + sage: a <= b, a <= c, b <= c + (True, True, False) + +The last comparison gives ``False``, since the first entries give `2 \leq 1`. + +Now, let us add such elements to a poset:: + + sage: Q = MP() + sage: Q.add_element(T((1, 1))) + sage: Q.add_element(T((3, 3))) + sage: Q.add_element(T((4, 1))) + sage: Q.add_element(T((3, 2))) + sage: Q.add_element(T((2, 3))) + sage: Q.add_element(T((2, 2))) + sage: Q + poset((1, 1), (2, 2), (2, 3), (3, 2), (3, 3), (4, 1)) + +In the representation above, the elements are sorted topologically, +smallest first. This does not show (directly) more structural +information. We can overcome this and display a "wiring layout" by +typing:: + + sage: print Q.repr_full(reverse=True) + poset((3, 3), (2, 3), (3, 2), (2, 2), (4, 1), (1, 1)) + +-- oo + | +-- no successors + | +-- predecessors: (3, 3), (4, 1) + +-- (3, 3) + | +-- successors: oo + | +-- predecessors: (2, 3), (3, 2) + +-- (2, 3) + | +-- successors: (3, 3) + | +-- predecessors: (2, 2) + +-- (3, 2) + | +-- successors: (3, 3) + | +-- predecessors: (2, 2) + +-- (2, 2) + | +-- successors: (2, 3), (3, 2) + | +-- predecessors: (1, 1) + +-- (4, 1) + | +-- successors: oo + | +-- predecessors: (1, 1) + +-- (1, 1) + | +-- successors: (2, 2), (4, 1) + | +-- predecessors: null + +-- null + | +-- successors: (1, 1) + | +-- no predecessors + +Note that we use ``reverse=True`` to let the elements appear from +largest (on the top) to smallest (on the bottom). + +If you look at the output above, you'll see two additional elements, +namely ``oo`` (`\infty`) and ``null`` (`\emptyset`). So what are these +strange animals? The answer is simple and maybe you can guess it +already. The `\infty`-element is larger than every other element, +therefore a successor of the maximal elements in the poset. Similarly, +the `\emptyset`-element is smaller than any other element, therefore a +predecessor of the poset's minimal elements. Both do not have to scare +us; they are just there and sometimes useful. + + +AUTHORS: + +- Daniel Krenn (2015-01-21): initial version + +ACKNOWLEDGEMENT: + +- Daniel Krenn is supported by the Austrian Science Fund (FWF): P 24644-N26. + +Classes and their Methods +========================= """ #***************************************************************************** # Copyright (C) 2015 Daniel Krenn @@ -868,7 +1012,7 @@ def sorted_set_by_tuple(S, T): class MutablePoset(sage.structure.sage_object.SageObject): r""" - A mutable poset. + A mutable poset (partially ordered set) as data structure. """ def __init__(self, data=None, key=None): r""" From 1b8d48a4105725ea15e4b6172fccece12fb8c34d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 14:47:20 +0100 Subject: [PATCH 0087/1872] rename add_element to add, remove_element to remove to make it consistent with Python's set --- src/sage/data_structures/mutable_poset.py | 158 +++++++++++----------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 6343b67bde2..1b7df47bca1 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -37,10 +37,10 @@ :: - sage: P.add_element(42) - sage: P.add_element(7) - sage: P.add_element(13) - sage: P.add_element(3) + sage: P.add(42) + sage: P.add(7) + sage: P.add(13) + sage: P.add(3) Let us look at the poset again:: @@ -80,12 +80,12 @@ Now, let us add such elements to a poset:: sage: Q = MP() - sage: Q.add_element(T((1, 1))) - sage: Q.add_element(T((3, 3))) - sage: Q.add_element(T((4, 1))) - sage: Q.add_element(T((3, 2))) - sage: Q.add_element(T((2, 3))) - sage: Q.add_element(T((2, 2))) + sage: Q.add(T((1, 1))) + sage: Q.add(T((3, 3))) + sage: Q.add(T((4, 1))) + sage: Q.add(T((3, 2))) + sage: Q.add(T((2, 3))) + sage: Q.add(T((2, 2))) sage: Q poset((1, 1), (2, 2), (2, 3), (3, 2), (3, 3), (4, 1)) @@ -656,17 +656,17 @@ def _search_covers_(self, covers, element, reverse=False): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1, 1))) + sage: P.add(T((1, 1, 1))) (1, 1, 1) - sage: P.add_element(T((1, 3, 1))) + sage: P.add(T((1, 3, 1))) (1, 3, 1) - sage: P.add_element(T((2, 1, 2))) + sage: P.add(T((2, 1, 2))) (2, 1, 2) - sage: P.add_element(T((4, 4, 2))) + sage: P.add(T((4, 4, 2))) (4, 4, 2) - sage: P.add_element(T((1, 2, 2))) + sage: P.add(T((1, 2, 2))) (1, 2, 2) - sage: e = P.add_element(T((2, 2, 2))); e + sage: e = P.add(T((2, 2, 2))); e (2, 2, 2) sage: covers = set() sage: P.null._search_covers_(covers, e) @@ -715,17 +715,17 @@ def covers(self, element, reverse=False): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1))) + sage: P.add(T((1, 1))) (1, 1) - sage: P.add_element(T((1, 3))) + sage: P.add(T((1, 3))) (1, 3) - sage: P.add_element(T((2, 1))) + sage: P.add(T((2, 1))) (2, 1) - sage: P.add_element(T((4, 4))) + sage: P.add(T((4, 4))) (4, 4) - sage: P.add_element(T((1, 2))) + sage: P.add(T((1, 2))) (1, 2) - sage: e = P.add_element(T((2, 2))); e + sage: e = P.add(T((2, 2))); e (2, 2) sage: sorted(P.null.covers(e), ....: key=lambda c: repr(c.value)) @@ -760,9 +760,9 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: P.add_element(42) + sage: P.add(42) 42 - sage: P.add_element(5) + sage: P.add(5) 5 sage: marked = set() sage: list(P.oo._iter_depth_first_visit_(marked, True)) @@ -809,17 +809,17 @@ def iter_depth_first(self, reverse=False, key=None): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1))) + sage: P.add(T((1, 1))) (1, 1) - sage: P.add_element(T((1, 3))) + sage: P.add(T((1, 3))) (1, 3) - sage: P.add_element(T((2, 1))) + sage: P.add(T((2, 1))) (2, 1) - sage: P.add_element(T((4, 4))) + sage: P.add(T((4, 4))) (4, 4) - sage: P.add_element(T((1, 2))) + sage: P.add(T((1, 2))) (1, 2) - sage: P.add_element(T((2, 2))) + sage: P.add(T((2, 2))) (2, 2) sage: list(P.null.iter_depth_first(reverse=False, ....: key=lambda c: repr(c))) @@ -853,9 +853,9 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: P.add_element(42) + sage: P.add(42) 42 - sage: P.add_element(5) + sage: P.add(5) 5 sage: marked = set() sage: list(P.null._iter_topological_visit_(marked, True)) @@ -913,17 +913,17 @@ def iter_topological(self, reverse=False, key=None): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1))) + sage: P.add(T((1, 1))) (1, 1) - sage: P.add_element(T((1, 3))) + sage: P.add(T((1, 3))) (1, 3) - sage: P.add_element(T((2, 1))) + sage: P.add(T((2, 1))) (2, 1) - sage: P.add_element(T((4, 4))) + sage: P.add(T((4, 4))) (4, 4) - sage: P.add_element(T((1, 2))) + sage: P.add(T((1, 2))) (1, 2) - sage: P.add_element(T((2, 2))) + sage: P.add(T((2, 2))) (2, 2) :: @@ -1123,15 +1123,15 @@ def copy(self): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1))) + sage: P.add(T((1, 1))) (1, 1) - sage: P.add_element(T((1, 3))) + sage: P.add(T((1, 3))) (1, 3) - sage: P.add_element(T((2, 1))) + sage: P.add(T((2, 1))) (2, 1) - sage: P.add_element(T((4, 4))) + sage: P.add(T((4, 4))) (4, 4) - sage: P.add_element(T((1, 2))) + sage: P.add(T((1, 2))) (1, 2) sage: Q = P.copy() sage: P.repr_full() == Q.repr_full() @@ -1196,17 +1196,17 @@ def elements_topological(self, include_special=False, ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1))) + sage: P.add(T((1, 1))) (1, 1) - sage: P.add_element(T((1, 3))) + sage: P.add(T((1, 3))) (1, 3) - sage: P.add_element(T((2, 1))) + sage: P.add(T((2, 1))) (2, 1) - sage: P.add_element(T((4, 4))) + sage: P.add(T((4, 4))) (4, 4) - sage: P.add_element(T((1, 2))) + sage: P.add(T((1, 2))) (1, 2) - sage: P.add_element(T((2, 2))) + sage: P.add(T((2, 2))) (2, 2) sage: list(P.elements_topological()) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] @@ -1314,7 +1314,7 @@ def __contains__(self, key): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1))) + sage: P.add(T((1, 1))) (1, 1) sage: T((1, 1)) in P True @@ -1324,7 +1324,7 @@ def __contains__(self, key): return key in self._elements_ - def add_element(self, value): + def add(self, value): r""" Add the given object as element to the poset. @@ -1344,15 +1344,15 @@ def add_element(self, value): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1))) + sage: P.add(T((1, 1))) (1, 1) - sage: P.add_element(T((1, 3))) + sage: P.add(T((1, 3))) (1, 3) - sage: P.add_element(T((2, 1))) + sage: P.add(T((2, 1))) (2, 1) - sage: P.add_element(T((4, 4))) + sage: P.add(T((4, 4))) (4, 4) - sage: P.add_element(T((1, 2))) + sage: P.add(T((1, 2))) (1, 2) sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (1, 2), (2, 1), (1, 1)) @@ -1377,7 +1377,7 @@ def add_element(self, value): +-- null | +-- successors: (1, 1) | +-- no predecessors - sage: P.add_element(T((2, 2))) + sage: P.add(T((2, 2))) (2, 2) sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) @@ -1410,7 +1410,7 @@ def add_element(self, value): existing one is returned:: sage: e = T((2, 2)) - sage: f = P.add_element(e).value; f + sage: f = P.add(e).value; f (2, 2) sage: e == f, e is f (True, False) @@ -1418,17 +1418,17 @@ def add_element(self, value): TESTS:: sage: R = MP(key=lambda k: T(k[2:3])) - sage: R.add_element(T((1, 1, 42))) + sage: R.add(T((1, 1, 42))) (1, 1, 42) - sage: R.add_element(T((1, 3, 42))) + sage: R.add(T((1, 3, 42))) (1, 1, 42) - sage: R.add_element(T((2, 1, 7))) + sage: R.add(T((2, 1, 7))) (2, 1, 7) - sage: R.add_element(T((4, 4, 42))) + sage: R.add(T((4, 4, 42))) (1, 1, 42) - sage: R.add_element(T((1, 2, 7))) + sage: R.add(T((1, 2, 7))) (2, 1, 7) - sage: R.add_element(T((2, 2, 7))) + sage: R.add(T((2, 2, 7))) (2, 1, 7) sage: print R.repr_full(reverse=True) poset((1, 1, 42), (2, 1, 7)) @@ -1472,7 +1472,7 @@ def add_element(self, value): return new - def remove_element(self, key): + def remove(self, key): r""" Remove the given object from the poset. @@ -1493,17 +1493,17 @@ def remove_element(self, key): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add_element(T((1, 1))) + sage: P.add(T((1, 1))) (1, 1) - sage: P.add_element(T((1, 3))) + sage: P.add(T((1, 3))) (1, 3) - sage: P.add_element(T((2, 1))) + sage: P.add(T((2, 1))) (2, 1) - sage: P.add_element(T((4, 4))) + sage: P.add(T((4, 4))) (4, 4) - sage: P.add_element(T((1, 2))) + sage: P.add(T((1, 2))) (1, 2) - sage: P.add_element(T((2, 2))) + sage: P.add(T((2, 2))) (2, 2) sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) @@ -1531,7 +1531,7 @@ def remove_element(self, key): +-- null | +-- successors: (1, 1) | +-- no predecessors - sage: P.remove_element(T((1, 2))) + sage: P.remove(T((1, 2))) sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (2, 2), (2, 1), (1, 1)) +-- oo @@ -1559,17 +1559,17 @@ def remove_element(self, key): TESTS:: sage: Q = MP(key=lambda k: T(k[0:2])) - sage: Q.add_element(T((1, 1, 42))) + sage: Q.add(T((1, 1, 42))) (1, 1, 42) - sage: Q.add_element(T((1, 3, 42))) + sage: Q.add(T((1, 3, 42))) (1, 3, 42) - sage: Q.add_element(T((2, 1, 7))) + sage: Q.add(T((2, 1, 7))) (2, 1, 7) - sage: Q.add_element(T((4, 4, 42))) + sage: Q.add(T((4, 4, 42))) (4, 4, 42) - sage: Q.add_element(T((1, 2, 7))) + sage: Q.add(T((1, 2, 7))) (1, 2, 7) - sage: Q.add_element(T((2, 2, 7))) + sage: Q.add(T((2, 2, 7))) (2, 2, 7) sage: print Q.repr_full(reverse=True) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), @@ -1598,7 +1598,7 @@ def remove_element(self, key): +-- null | +-- successors: (1, 1, 42) | +-- no predecessors - sage: Q.remove_element((1,1)) + sage: Q.remove((1,1)) sage: print Q.repr_full(reverse=True) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7)) +-- oo From a02d9968a5e3aebb93444c83c46ea88bd78e8ade Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 16:51:13 +0100 Subject: [PATCH 0088/1872] implement method for returning the element from given key --- src/sage/data_structures/mutable_poset.py | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 1b7df47bca1..102cc13ba22 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1074,6 +1074,31 @@ def oo(self): return self._oo_ + def element(self, key): + r""" + Return the element corresponding to ``key``. + + INPUT: + + ``key`` -- the key of an object. + + OUTPUT: + + An instance of :class:`MutablePosetElement`. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(42) + sage: e = P.element(42); e + 42 + sage: type(e) + + """ + return self._elements_[key] + + def get_key(self, value): r""" Return the key corresponding to ``value``. From e4b1047546b65c88fcb9c2c878d53e4014965779 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 16:54:58 +0100 Subject: [PATCH 0089/1872] remove return value from add --- src/sage/data_structures/mutable_poset.py | 87 +++-------------------- 1 file changed, 11 insertions(+), 76 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 102cc13ba22..d869f8607cb 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -657,16 +657,12 @@ def _search_covers_(self, covers, element, reverse=False): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1, 1))) - (1, 1, 1) sage: P.add(T((1, 3, 1))) - (1, 3, 1) sage: P.add(T((2, 1, 2))) - (2, 1, 2) sage: P.add(T((4, 4, 2))) - (4, 4, 2) sage: P.add(T((1, 2, 2))) - (1, 2, 2) - sage: e = P.add(T((2, 2, 2))); e + sage: P.add(T((2, 2, 2))) + sage: e = P.element(T((2, 2, 2))); e (2, 2, 2) sage: covers = set() sage: P.null._search_covers_(covers, e) @@ -716,16 +712,12 @@ def covers(self, element, reverse=False): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - (1, 1) sage: P.add(T((1, 3))) - (1, 3) sage: P.add(T((2, 1))) - (2, 1) sage: P.add(T((4, 4))) - (4, 4) sage: P.add(T((1, 2))) - (1, 2) - sage: e = P.add(T((2, 2))); e + sage: P.add(T((2, 2))) + sage: e = P.element(T((2, 2))); e (2, 2) sage: sorted(P.null.covers(e), ....: key=lambda c: repr(c.value)) @@ -761,9 +753,7 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() sage: P.add(42) - 42 sage: P.add(5) - 5 sage: marked = set() sage: list(P.oo._iter_depth_first_visit_(marked, True)) [oo, 42, 5, null] @@ -810,17 +800,11 @@ def iter_depth_first(self, reverse=False, key=None): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - (1, 1) sage: P.add(T((1, 3))) - (1, 3) sage: P.add(T((2, 1))) - (2, 1) sage: P.add(T((4, 4))) - (4, 4) sage: P.add(T((1, 2))) - (1, 2) sage: P.add(T((2, 2))) - (2, 2) sage: list(P.null.iter_depth_first(reverse=False, ....: key=lambda c: repr(c))) [null, (1, 1), (1, 2), (1, 3), (4, 4), oo, (2, 2), (2, 1)] @@ -854,9 +838,7 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() sage: P.add(42) - 42 sage: P.add(5) - 5 sage: marked = set() sage: list(P.null._iter_topological_visit_(marked, True)) [oo, 42, 5, null] @@ -914,17 +896,11 @@ def iter_topological(self, reverse=False, key=None): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - (1, 1) sage: P.add(T((1, 3))) - (1, 3) sage: P.add(T((2, 1))) - (2, 1) sage: P.add(T((4, 4))) - (4, 4) sage: P.add(T((1, 2))) - (1, 2) sage: P.add(T((2, 2))) - (2, 2) :: @@ -1149,15 +1125,10 @@ def copy(self): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - (1, 1) sage: P.add(T((1, 3))) - (1, 3) sage: P.add(T((2, 1))) - (2, 1) sage: P.add(T((4, 4))) - (4, 4) sage: P.add(T((1, 2))) - (1, 2) sage: Q = P.copy() sage: P.repr_full() == Q.repr_full() True @@ -1222,17 +1193,11 @@ def elements_topological(self, include_special=False, ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - (1, 1) sage: P.add(T((1, 3))) - (1, 3) sage: P.add(T((2, 1))) - (2, 1) sage: P.add(T((4, 4))) - (4, 4) sage: P.add(T((1, 2))) - (1, 2) sage: P.add(T((2, 2))) - (2, 2) sage: list(P.elements_topological()) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] sage: list(P.elements_topological(reverse=True)) @@ -1340,7 +1305,6 @@ def __contains__(self, key): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - (1, 1) sage: T((1, 1)) in P True sage: T((1, 2)) in P @@ -1370,15 +1334,10 @@ def add(self, value): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - (1, 1) sage: P.add(T((1, 3))) - (1, 3) sage: P.add(T((2, 1))) - (2, 1) sage: P.add(T((4, 4))) - (4, 4) sage: P.add(T((1, 2))) - (1, 2) sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (1, 2), (2, 1), (1, 1)) +-- oo @@ -1403,8 +1362,7 @@ def add(self, value): | +-- successors: (1, 1) | +-- no predecessors sage: P.add(T((2, 2))) - (2, 2) - sage: print P.repr_full(reverse=True) + sage: reprP = P.repr_full(reverse=True); print reprP poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -1431,30 +1389,22 @@ def add(self, value): | +-- successors: (1, 1) | +-- no predecessors - When adding an element which is already in the poset, the - existing one is returned:: + When adding an element which is already in the poset, nothing happens:: sage: e = T((2, 2)) - sage: f = P.add(e).value; f - (2, 2) - sage: e == f, e is f - (True, False) + sage: P.add(e) + sage: P.repr_full(reverse=True) == reprP + True TESTS:: sage: R = MP(key=lambda k: T(k[2:3])) sage: R.add(T((1, 1, 42))) - (1, 1, 42) sage: R.add(T((1, 3, 42))) - (1, 1, 42) sage: R.add(T((2, 1, 7))) - (2, 1, 7) sage: R.add(T((4, 4, 42))) - (1, 1, 42) sage: R.add(T((1, 2, 7))) - (2, 1, 7) sage: R.add(T((2, 2, 7))) - (2, 1, 7) sage: print R.repr_full(reverse=True) poset((1, 1, 42), (2, 1, 7)) +-- oo @@ -1474,10 +1424,8 @@ def add(self, value): raise ValueError('None is not allowed as value.') key = self.get_key(value) - try: - return self._elements_[key] - except KeyError: - pass + if key in self._elements_: + return new = MutablePosetElement(self, value) smaller = self.null.covers(new, reverse=False) @@ -1494,7 +1442,6 @@ def add(self, value): element.successors(reverse).add(new) self._elements_[key] = new - return new def remove(self, key): @@ -1519,17 +1466,11 @@ def remove(self, key): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - (1, 1) sage: P.add(T((1, 3))) - (1, 3) sage: P.add(T((2, 1))) - (2, 1) sage: P.add(T((4, 4))) - (4, 4) sage: P.add(T((1, 2))) - (1, 2) sage: P.add(T((2, 2))) - (2, 2) sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) +-- oo @@ -1585,17 +1526,11 @@ def remove(self, key): sage: Q = MP(key=lambda k: T(k[0:2])) sage: Q.add(T((1, 1, 42))) - (1, 1, 42) sage: Q.add(T((1, 3, 42))) - (1, 3, 42) sage: Q.add(T((2, 1, 7))) - (2, 1, 7) sage: Q.add(T((4, 4, 42))) - (4, 4, 42) sage: Q.add(T((1, 2, 7))) - (1, 2, 7) sage: Q.add(T((2, 2, 7))) - (2, 2, 7) sage: print Q.repr_full(reverse=True) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7), (1, 1, 42)) From 356d4a9ba2d5146e6c00685b46ec3e4a9410a2be Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 16:55:24 +0100 Subject: [PATCH 0090/1872] implement clear() --- src/sage/data_structures/mutable_poset.py | 41 ++++++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d869f8607cb..d7c241000e9 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1004,11 +1004,7 @@ def __init__(self, data=None, key=None): if data is not None: raise NotImplementedError - self._null_ = MutablePosetElement(self, None) - self._oo_ = MutablePosetElement(self, None) - self._null_.successors().add(self._oo_) - self._oo_.predecessors().add(self._null_) - self._elements_ = {} + self.clear() if key is None: self._key_ = lambda k: k @@ -1016,6 +1012,41 @@ def __init__(self, data=None, key=None): self._key_ = key + def clear(self): + r""" + Remove all elements from this poset. + + INPUT: + + Nothing. + + OUTPUT: + + Nothing. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(42); P + poset(42) + sage: P.clear() + sage: print P.repr_full() + poset() + +-- null + | +-- no predecessors + | +-- successors: oo + +-- oo + | +-- predecessors: null + | +-- no successors + """ + self._null_ = MutablePosetElement(self, None) + self._oo_ = MutablePosetElement(self, None) + self._null_.successors().add(self._oo_) + self._oo_.predecessors().add(self._null_) + self._elements_ = {} + + @property def null(self): r""" From 06e5c4968be4a40a3cbb1b3a44b9d5be71161e18 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 16:56:59 +0100 Subject: [PATCH 0091/1872] simplfied codes and doctests --- src/sage/data_structures/mutable_poset.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d7c241000e9..6cbd35fc98a 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -805,11 +805,9 @@ def iter_depth_first(self, reverse=False, key=None): sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: P.add(T((2, 2))) - sage: list(P.null.iter_depth_first(reverse=False, - ....: key=lambda c: repr(c))) + sage: list(P.null.iter_depth_first(reverse=False, key=repr)) [null, (1, 1), (1, 2), (1, 3), (4, 4), oo, (2, 2), (2, 1)] - sage: list(P.oo.iter_depth_first(reverse=True, - ....: key=lambda c: repr(c))) + sage: list(P.oo.iter_depth_first(reverse=True, key=repr)) [oo, (4, 4), (1, 3), (1, 2), (1, 1), null, (2, 2), (2, 1)] """ marked = set() @@ -907,8 +905,7 @@ def iter_topological(self, reverse=False, key=None): sage: for e in P.elements_topological(include_special=True, ....: reverse=True): ....: print e - ....: print list(e.iter_topological(reverse=True, - ....: key=lambda c: repr(c))) + ....: print list(e.iter_topological(reverse=True, key=repr)) oo [oo] (4, 4) @@ -931,8 +928,7 @@ def iter_topological(self, reverse=False, key=None): sage: for e in P.elements_topological(include_special=True, ....: reverse=True): ....: print e - ....: print list(e.iter_topological(reverse=False, - ....: key=lambda c: repr(c))) + ....: print list(e.iter_topological(reverse=False, key=repr)) oo [null, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] (4, 4) @@ -1240,7 +1236,7 @@ def elements_topological(self, include_special=False, [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), null] """ if key is None: - key = lambda c: repr(c) + key = repr element = self.oo if not reverse else self.null return iter(e for e in element.iter_topological(reverse, key) if include_special or not e.is_special()) From c45af6acd620d0810d4c6712b33103b15ecfc2c5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 16:59:56 +0100 Subject: [PATCH 0092/1872] write a couple of docs and improve existing --- src/sage/data_structures/mutable_poset.py | 30 ++++++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 6cbd35fc98a..23a4b7c8d8c 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -742,7 +742,7 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): - ``reverse`` -- (default: ``False``) -- if set, reverses the order. - ``key`` -- (default: ``None``) a function used for sorting - the successors. If this is ``None``, no sorting occurrs. + the successors. If this is ``None``, no sorting occurs. OUTPUT: @@ -782,7 +782,7 @@ def iter_depth_first(self, reverse=False, key=None): - ``key`` -- (default: ``None``) a function used for sorting the direct successors of an element (used in case of a - tie). If this is ``None``, no sorting occurrs. + tie). If this is ``None``, no sorting occurs. OUTPUT: @@ -825,7 +825,8 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): - ``reverse`` -- (default: ``False``) -- if set, reverses the order. - ``key`` -- (default: ``None``) a function used for sorting - the successors. If this is ``None``, no sorting occurrs. + the direct successors of an element (used in case of a + tie). If this is ``None``, no sorting occurs. OUTPUT: @@ -865,7 +866,7 @@ def iter_topological(self, reverse=False, key=None): - ``key`` -- (default: ``None``) a function used for sorting the direct successors of an element (used in case of a - tie). If this is ``None``, no sorting occurrs. + tie). If this is ``None``, no sorting occurs. OUTPUT: @@ -1212,6 +1213,27 @@ def elements(self, include_special=False, reverse=False): def elements_topological(self, include_special=False, reverse=False, key=None): r""" + Return an iterator over all elements in topological order. + + INPUT: + + - ``include_special`` -- (default: ``False``) if set, then + including a smallest element (`\emptyset`) and a largest element + (`\infty`). + + - ``reverse`` -- (default: ``False``) -- if set, reverses the + order, i.e., ``False`` gives smallest elements first, + ``True`` gives largest first. + + - ``key`` -- (default: ``None``) a function used for sorting + the direct successors of an element (used in case of a + tie). If this is ``None``, no sorting according to the reprsentation + string occurs. + + OUTPUT: + + An iterator. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 59276fb4cd6ac44ad9e56750ad6654515b7f6a34 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 17:01:02 +0100 Subject: [PATCH 0093/1872] method contains() --- src/sage/data_structures/mutable_poset.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 23a4b7c8d8c..8026b0cd54c 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1334,7 +1334,7 @@ def repr_full(self, reverse=False): __repr__ = repr - def __contains__(self, key): + def contains(self, key): r""" Tests if ``key`` is encapsulated by one of the poset's elements. @@ -1354,14 +1354,17 @@ def __contains__(self, key): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() sage: P.add(T((1, 1))) - sage: T((1, 1)) in P + sage: T((1, 1)) in P # indirect doctest True - sage: T((1, 2)) in P + sage: T((1, 2)) in P # indirect doctest False """ return key in self._elements_ + __contains__ = contains + + def add(self, value): r""" Add the given object as element to the poset. From 0998a609ea633cf7c69f49793b04ed678fe5dcce Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 17:01:33 +0100 Subject: [PATCH 0094/1872] iterators for keys and values --- src/sage/data_structures/mutable_poset.py | 161 ++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8026b0cd54c..d08e51b143d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1264,6 +1264,167 @@ def elements_topological(self, include_special=False, if include_special or not e.is_special()) + def values(self, **kwargs): + r""" + Return an iterator over all values of the elements. + + INPUT: + + - ``kwargs`` -- arguments are passed to :meth:`elements`. + + OUTPUT: + + An iterator. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3) + sage: P.add(42) + sage: P.add(7) + sage: [(v, type(v)) for v in sorted(P.values())] + [(3, ), + (7, ), + (42, )] + + Note that + + :: + + sage: it = iter(P) + sage: sorted(it) + [3, 7, 42] + + returns all values as well. + """ + for element in self.elements(**kwargs): + yield element.value + + + __iter__ = values + + + def values_topological(self, **kwargs): + r""" + Return an iterator over all values of the elements in + topological order. + + INPUT: + + - ``kwargs`` -- arguments are passed to :meth:`elements_topological`. + + OUTPUT: + + An iterator. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 1))) + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: [(v, type(v)) for v in P.values_topological()] + [((1, 1), ), + ((1, 2), ), + ((1, 3), ), + ((2, 1), ), + ((2, 2), ), + ((4, 4), )] + """ + for element in self.elements_topological(**kwargs): + yield element.value + + + def keys(self, **kwargs): + r""" + Return an iterator over all keys of the elements. + + INPUT: + + - ``kwargs`` -- arguments are passed to :meth:`elements`. + + OUTPUT: + + An iterator. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP(key=lambda c: -c) + sage: P.add(3) + sage: P.add(42) + sage: P.add(7) + sage: [(v, type(v)) for v in sorted(P.keys())] + [(-42, ), + (-7, ), + (-3, )] + + sage: [(v, type(v)) for v in sorted(P.values())] + [(3, ), + (7, ), + (42, )] + + sage: [(v, type(v)) for v in sorted(P.elements(), + ....: key=lambda c: c.value)] + [(3, ), + (7, ), + (42, )] + """ + for element in self.elements(**kwargs): + yield element.key + + + def keys_topological(self, **kwargs): + r""" + Return an iterator over all keys of the elements in + topological order. + + INPUT: + + - ``kwargs`` -- arguments are passed to :meth:`elements_topological`. + + OUTPUT: + + An iterator. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP(key=lambda c: c[0]) + sage: P.add(T((1, 1))) + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: [(v, type(v)) for v in P.keys_topological()] + [(1, ), + (2, ), + (4, )] + sage: [(v, type(v)) for v in P.values_topological()] + [((1, 1), ), + ((2, 1), ), + ((4, 4), )] + sage: [(v, type(v)) for v in P.elements_topological()] + [((1, 1), ), + ((2, 1), ), + ((4, 4), )] + """ + for element in self.elements_topological(**kwargs): + yield element.key + + def repr(self, include_special=False, reverse=False): r""" Return a representation of the poset. From 00e545785bc3fea541909e5a9e22ad0063ca648e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 17:00:21 +0100 Subject: [PATCH 0095/1872] prepare remove() for discard() --- src/sage/data_structures/mutable_poset.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d08e51b143d..c1ebd4bd864 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1657,13 +1657,13 @@ def add(self, value): self._elements_[key] = new - def remove(self, key): + def remove(self, key, raise_key_error=True): r""" Remove the given object from the poset. INPUT: - - ``value`` -- an object. + - ``key`` -- the key of an object. OUTPUT: @@ -1802,7 +1802,9 @@ def remove(self, key): try: element = self._elements_[key] except KeyError: - raise KeyError('Key %s is not contained in this poset.' % (key,)) + if raise_key_error: + raise KeyError('Key %s is not contained ' + 'in this poset.' % (key,)) for reverse in (False, True): for p in element.predecessors(reverse): From 6a51cca61b2469fb3e6d240a3c7921e5186c8166 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 17:02:02 +0100 Subject: [PATCH 0096/1872] implement discard and pop --- src/sage/data_structures/mutable_poset.py | 89 ++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index c1ebd4bd864..730a6d45dd0 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1665,11 +1665,15 @@ def remove(self, key, raise_key_error=True): - ``key`` -- the key of an object. + - ``raise_key_error`` -- (default: ``True``) switch raising + ``KeyError``on and off. + OUTPUT: Nothing. - If the element is not a member, raise a ``KeyError``. + If the element is not a member and ``raise_key_error`` is set + (default), raise a ``KeyError``. EXAMPLES:: @@ -1817,6 +1821,89 @@ def remove(self, key, raise_key_error=True): del self._elements_[key] + def discard(self, key, raise_key_error=False): + r""" + Remove the given object from the poset. + + INPUT: + + - ``key`` -- the key of an object. + + - ``raise_key_error`` -- (default: ``False``) switch raising + ``KeyError``on and off. + + OUTPUT: + + Nothing. + + If the element is not a member and ``raise_key_error`` is set + (not default), raise a ``KeyError``. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 1))) + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: P.discard(T((1, 2))) + sage: P.remove(T((1, 2))) + Traceback (most recent call last): + ... + KeyError: 'Key (1, 2) is not contained in this poset.' + sage: P.discard(T((1, 2))) + """ + return self.remove(key, raise_key_error) + + + def pop(self, **kwargs): + r""" + Remove and return an arbitrary poset element. + + INPUT: + + - ``kwargs`` -- arguments are passed to :meth:`elements_topological`. + + OUTPUT: + + An object. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP(key=lambda c: -c) + sage: P.add(3) + sage: P + poset(3) + sage: P.pop() + 3 + sage: P + poset() + sage: P.pop() + Traceback (most recent call last): + ... + KeyError: 'pop from an empty poset' + """ + try: + del kwargs['include_special'] + except KeyError: + pass + kwargs['include_special'] = False + + try: + element = next(self.elements_topological(**kwargs)) + except StopIteration: + raise KeyError('pop from an empty poset') + self.remove(element.key) + return element.value + + # ***************************************************************************** From a852bcbbf243d396a9f228ffaa215cffddef8bfa Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 17:02:41 +0100 Subject: [PATCH 0097/1872] implement union, intersection, difference --- src/sage/data_structures/mutable_poset.py | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 730a6d45dd0..13e317e5ca3 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1904,6 +1904,63 @@ def pop(self, **kwargs): return element.value + def union(left, right): + r""" + """ + new = left.copy() + new.update(right) + return new + + + def update(self, other): + r""" + """ + try: + it = other.values() + except AttributeError: + it = iter(other) + for value in it: + self.add(value) + + + def difference(left, right): + r""" + """ + new = left.copy() + new.difference_update(right) + return new + + + def difference_update(self, other): + r""" + """ + try: + it = other.keys() + except AttributeError: + it = iter(other) + for key in it: + self.discard(key) + + + def intersection(left, right): + r""" + """ + new = left.copy() + new.intersection_update(right) + return new + + + def intersection_update(self, other): + r""" + """ + try: + it = other.keys() + except AttributeError: + it = iter(other) + for key in it: + if key not in other: + self.discard(key) + # ***************************************************************************** From 195e235ec5d7b68b65ceb7f3345a0d5ca4833a3e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 26 Jan 2015 17:39:34 +0100 Subject: [PATCH 0098/1872] fix bug in return value of add --- src/sage/data_structures/mutable_poset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 13e317e5ca3..383decdc16c 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1806,9 +1806,9 @@ def remove(self, key, raise_key_error=True): try: element = self._elements_[key] except KeyError: - if raise_key_error: - raise KeyError('Key %s is not contained ' - 'in this poset.' % (key,)) + if not raise_key_error: + return + raise KeyError('Key %s is not contained in this poset.' % (key,)) for reverse in (False, True): for p in element.predecessors(reverse): From 861243eafd30c541aac608687872d32999ef9cf8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 11:41:18 +0100 Subject: [PATCH 0099/1872] minor rewording of some docstrings --- src/sage/data_structures/mutable_poset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 383decdc16c..cfbe7636ecb 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -592,8 +592,8 @@ def _copy_all_linked_(self, memo, poset): INPUT: - - ``memo`` -- a dictionary which assigns to the id of ``self`` - a copy of ``self``. + - ``memo`` -- a dictionary which assigns to the id of the + calling element to a copy of it. - ``poset`` -- the poset to which the newly created element belongs. @@ -681,7 +681,7 @@ def _search_covers_(self, covers, element, reverse=False): def covers(self, element, reverse=False): r""" Return the covers of the given element (considering only - elements which originate from ``self``). + elements which originate from itself). INPUT: @@ -698,7 +698,7 @@ def covers(self, element, reverse=False): lower covers of the given ``element``, i.e., elements in the poset, which are at most the given element and maximal with this property. Only elements which are (not necessarily - direct) successors of ``self`` are considered. + direct) successors of the calling element are considered. If ``reverse`` is ``True``, then the reverse direction is taken, i.e., in the text above replace lower covers by upper From f7e98af288f76cc4b3722020849ad29e01df1a9f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 11:43:03 +0100 Subject: [PATCH 0100/1872] finish union, intersection, (symmetric_)difference: small code rewriting; docstrings --- src/sage/data_structures/mutable_poset.py | 263 +++++++++++++++++++++- 1 file changed, 252 insertions(+), 11 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index cfbe7636ecb..02b1773563d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1904,16 +1904,81 @@ def pop(self, **kwargs): return element.value - def union(left, right): + def union(left, *right): r""" - """ + Return the union of the given posets as a new poset + + INPUT: + + - ``left`` -- a poset. + + - ``right`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + A poset. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.union(Q) + poset(3, 4, 7, 8, 42) + + TESTS:: + + sage: P.union(P, Q, Q, P) + poset(3, 4, 7, 8, 42) + """ new = left.copy() - new.update(right) + for r in right: + new.update(r) return new - def update(self, other): + def union_update(self, other): r""" + Update the poset with the union of itself and another poset. + + INPUT: + + - ``other`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + Nothing. + + .. TODO:: + + Use the already existing information in the other poset to speed + up this function. (At the moment each element of the other poset + is inserted one by one and without using this information.) + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.union_update(Q) + sage: P + poset(3, 4, 7, 8, 42) + + TESTS:: + + sage: Q.update(P) + sage: Q + poset(3, 4, 7, 8, 42) """ try: it = other.values() @@ -1923,16 +1988,77 @@ def update(self, other): self.add(value) - def difference(left, right): + update = union_update # as in a Python set + + + def difference(left, *right): r""" + Return a new poset where all elements of this poset, which are + contained in one of the other given posets, are removed. + + INPUT: + + - ``left`` -- a poset. + + - ``right`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + A poset. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.difference(Q) + poset(3, 7) + + TESTS:: + + sage: P.difference(Q, Q) + poset(3, 7) + sage: P.difference(P) + poset() + sage: P.difference(Q, P) + poset() """ new = left.copy() - new.difference_update(right) + for r in right: + new.difference_update(r) return new def difference_update(self, other): r""" + Remove all elements of another poset from this poset. + + INPUT: + + - ``other`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.difference_update(Q) + sage: P + poset(3, 7) """ try: it = other.keys() @@ -1942,25 +2068,140 @@ def difference_update(self, other): self.discard(key) - def intersection(left, right): + def intersection(left, *right): r""" + Return the intersection of the given posets as a new poset + + INPUT: + + - ``left`` -- a poset. + + - ``right`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + A poset. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.intersection(Q) + poset(42) + + TESTS:: + + sage: P.intersection(P, Q, Q, P) + poset(42) """ new = left.copy() - new.intersection_update(right) + for r in right: + new.intersection_update(r) return new def intersection_update(self, other): r""" + Update the poset with the intersection of itself and another poset. + + INPUT: + + - ``other`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.intersection_update(Q) + sage: P + poset(42) """ try: - it = other.keys() + keys = tuple(self.keys()) except AttributeError: - it = iter(other) - for key in it: + keys = tuple(iter(self)) + for key in keys: if key not in other: self.discard(key) + + def symmetric_difference(left, right): + r""" + Return the symmetric difference of two posets as a new poset. + + INPUT: + + - ``left`` -- a poset. + + - ``right`` -- a poset. + + OUTPUT: + + A poset. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.symmetric_difference(Q) + poset(3, 4, 7, 8) + """ + new = left.copy() + new.symmetric_difference_update(right) + return new + + + def symmetric_difference_update(self, other): + r""" + Update the poset with the symmetric difference of itself and + another poset. + + INPUT: + + - ``other`` -- a poset. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.symmetric_difference_update(Q) + sage: P + poset(3, 4, 7, 8) + """ + T = other.difference(self) + self.difference_update(other) + self.union_update(T) + # ***************************************************************************** From 69828f04e16a3c3c71e64730539ca1cc7d9fa356 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 11:44:46 +0100 Subject: [PATCH 0101/1872] implement is_disjoint, is_subset, is_superset --- src/sage/data_structures/mutable_poset.py | 114 ++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 02b1773563d..74c7648b7a8 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2202,6 +2202,120 @@ def symmetric_difference_update(self, other): self.difference_update(other) self.union_update(T) + + def is_disjoint(self, other): + r""" + Return if another poset is disjoint to this poset. + + INPUT: + + - ``other`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.is_disjoint(Q) + False + sage: P.is_disjoint(Q.difference(P)) + True + """ + return all(key not in other for key in self.keys()) + + + isdisjoint = is_disjoint # as in a Python set + + + def is_subset(self, other): + r""" + Return if another poset contains this poset, i.e., if this poset + is a subset of the other poset. + + INPUT: + + - ``other`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.is_subset(Q) + False + sage: Q.is_subset(P) + False + sage: P.is_subset(P) + True + sage: P.is_subset(P.union(Q)) + True + """ + return all(key in other for key in self.keys()) + + + issubset = is_subset # as in a Python set + + + def is_superset(self, other): + r""" + Return if this poset contains another poset, i.e., if this poset + is a superset of the other poset. + + INPUT: + + - ``other`` -- a poset or an iterable. In the latter case the + iterated objects are seen as values of a poset. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(3); P.add(42); P.add(7); P + poset(3, 7, 42) + sage: Q = MP() + sage: Q.add(4); Q.add(8); Q.add(42); Q + poset(4, 8, 42) + sage: P.is_superset(Q) + False + sage: Q.is_superset(P) + False + sage: P.is_superset(P) + True + sage: P.union(Q).is_superset(P) + True + """ + try: + it = other.keys() + except AttributeError: + it = iter(other) + return all(key in self for key in it) + + + issuperset = is_superset # as in a Python set + + # ***************************************************************************** From 7ca9da3b379dc0fa45d9f02fccca6e0661692e3a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 12:02:25 +0100 Subject: [PATCH 0102/1872] docstring fixup and improvement (and a couple of TODOs added as well) --- src/sage/data_structures/mutable_poset.py | 46 +++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 74c7648b7a8..288ff9d2253 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -162,7 +162,7 @@ class MutablePosetElement(sage.structure.sage_object.SageObject): r""" - An element of a mutable poset. + An element of a :class:`mutable poset `. """ def __init__(self, poset, value): r""" @@ -986,6 +986,35 @@ def sorted_set_by_tuple(S, T): class MutablePoset(sage.structure.sage_object.SageObject): r""" A mutable poset (partially ordered set) as data structure. + + .. TODO:: + + Implement the following methods of + :class:`~sage.combinat.posets.posets.FinitePoset`: + + - :meth:`~sage.combinat.posets.posets.FinitePoset.bottom`: Returns the bottom element of the poset, if it exists. + - :meth:`~sage.combinat.posets.posets.FinitePoset.cardinality`: Returns the number of elements in the poset. + - :meth:`~sage.combinat.posets.posets.FinitePoset.compare_elements`: Compares x and y in the poset. + - :meth:`~sage.combinat.posets.posets.FinitePoset.covers`: Returns True if y covers x and False otherwise. + - :meth:`~sage.combinat.posets.posets.FinitePoset.has_bottom`: Returns True if the poset has a unique minimal element. + - :meth:`~sage.combinat.posets.posets.FinitePoset.has_top`: Returns True if the poset contains a unique maximal element, and False otherwise. + - :meth:`~sage.combinat.posets.posets.FinitePoset.is_bounded`: Returns True if the poset contains a unique maximal element and a unique minimal element, and False otherwise. + - :meth:`~sage.combinat.posets.posets.FinitePoset.is_chain`: Returns True if the poset is totally ordered, and False otherwise. + - :meth:`~sage.combinat.posets.posets.FinitePoset.is_gequal`: Returns True if x is greater than or equal to y in the poset, and False otherwise. + - :meth:`~sage.combinat.posets.posets.FinitePoset.is_greater_than`: Returns True if x is greater than but not equal to y in the poset, and False otherwise. + - :meth:`~sage.combinat.posets.posets.FinitePoset.is_lequal`: Returns True if x is less than or equal to y in the poset, and False otherwise. + - :meth:`~sage.combinat.posets.posets.FinitePoset.is_less_than`: Returns True if x is less than but not equal to y in the poset, and False otherwise. + - :meth:`~sage.combinat.posets.posets.FinitePoset.linear_extension`: Returns a linear extension of this poset. + - :meth:`~sage.combinat.posets.posets.FinitePoset.list`: List the elements of the poset. This just returns the result of linear_extension(). + - :meth:`~sage.combinat.posets.posets.FinitePoset.lower_covers_iterator`: Returns an iterator for the lower covers of the element y. An lower cover of y is an element x such that y x is a cover relation. + - :meth:`~sage.combinat.posets.posets.FinitePoset.lower_covers`: Returns a list of lower covers of the element y. An lower cover of y is an element x such that y x is a cover relation. + - :meth:`~sage.combinat.posets.posets.FinitePoset.maximal_elements`: Returns a list of the maximal elements of the poset. + - :meth:`~sage.combinat.posets.posets.FinitePoset.minimal_elements`: Returns a list of the minimal elements of the poset. + - :meth:`~sage.combinat.posets.posets.FinitePoset.relations_iterator`: Returns an iterator for all the relations of the poset. + - :meth:`~sage.combinat.posets.posets.FinitePoset.relations`: Returns a list of all relations of the poset. + - :meth:`~sage.combinat.posets.posets.FinitePoset.top`: Returns the top element of the poset, if it exists. + - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers_iterator`: Returns an iterator for the upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. + - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers`: Returns a list of upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. """ def __init__(self, data=None, key=None): r""" @@ -1666,7 +1695,7 @@ def remove(self, key, raise_key_error=True): - ``key`` -- the key of an object. - ``raise_key_error`` -- (default: ``True``) switch raising - ``KeyError``on and off. + ``KeyError`` on and off. OUTPUT: @@ -1830,7 +1859,7 @@ def discard(self, key, raise_key_error=False): - ``key`` -- the key of an object. - ``raise_key_error`` -- (default: ``False``) switch raising - ``KeyError``on and off. + ``KeyError`` on and off. OUTPUT: @@ -2320,6 +2349,13 @@ def is_superset(self, other): class MutableTosetElement(MutablePosetElement): + r""" + An element of a mutable toset (totally ordered set). + + .. TODO:: + + Implement this class. + """ pass @@ -2329,6 +2365,10 @@ class MutableTosetElement(MutablePosetElement): class MutableToset(MutablePoset): r""" A mutable toset (totally ordered set) as data structure. + + .. TODO:: + + Implement this class. """ pass From fd87ef1b68fd3aa6fe5bf0bfc9246624e9657362 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 13:52:57 +0100 Subject: [PATCH 0103/1872] introduce copy-helper function --- src/sage/data_structures/mutable_poset.py | 49 +++++++++++++++++++---- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 288ff9d2253..f231e769f00 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1162,6 +1162,46 @@ def get_key(self, value): return self._key_(value) + def _copy_elements_(self, other): + r""" + Helper function for copying elements. + + INPUT: + + - ``other`` -- the mutable poset from which the elements + should be copied this poset. + + OUTPUT: + + Nothing. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 1))) + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: Q = MP() + sage: Q._copy_elements_(P) + sage: P.repr_full() == Q.repr_full() + True + """ + from copy import copy + self._key_ = copy(other._key_) + memo = {} + self._null_ = other._null_._copy_all_linked_(memo, self) + self._oo_ = memo[id(other._oo_)] + self._elements_ = dict((f.key, f) for f in + iter(memo[id(e)] + for e in other._elements_.itervalues())) + + def copy(self): r""" Creates a shallow copy. @@ -1186,17 +1226,12 @@ def copy(self): sage: P.add(T((2, 1))) sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) - sage: Q = P.copy() + sage: Q = copy(P) # indirect doctest sage: P.repr_full() == Q.repr_full() True """ new = self.__class__() - memo = {} - new._null_ = self._null_._copy_all_linked_(memo, new) - new._oo_ = memo[id(self._oo_)] - new._elements_ = dict((f.key, f) for f in - iter(memo[id(e)] - for e in self._elements_.itervalues())) + new._copy_elements_(self) return new From 72962b7ff0c22d7ffaa6eaed72c4d08259246242 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 13:53:13 +0100 Subject: [PATCH 0104/1872] implement is_MutablePoset --- src/sage/data_structures/mutable_poset.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index f231e769f00..3a4ed2c64ae 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -983,6 +983,21 @@ def sorted_set_by_tuple(S, T): # ***************************************************************************** +def is_MutablePoset(P): + r""" + Tests if ``P`` inherits from :class:`MutablePoset`. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: from sage.data_structures.mutable_poset import is_MutablePoset + sage: P = MP() + sage: is_MutablePoset(P) + True + """ + return isinstance(P, MutablePoset) + + class MutablePoset(sage.structure.sage_object.SageObject): r""" A mutable poset (partially ordered set) as data structure. From 8092b9da0c242d82c8c04c7a9281d05e7f0a3004 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 13:53:51 +0100 Subject: [PATCH 0105/1872] implement construction from iterable and from other mutable poset --- src/sage/data_structures/mutable_poset.py | 43 +++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3a4ed2c64ae..371be902bc6 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1040,17 +1040,46 @@ def __init__(self, data=None, key=None): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: MP() poset() - """ - if data is not None: - raise NotImplementedError + :: - self.clear() + sage: P = MP() + sage: P.add(42) + sage: MP(P) + poset(42) + + :: + + sage: MP([3, 5, 7]) + poset(3, 5, 7) + + :: + + sage: MP(33) + Traceback (most recent call last): + ... + TypeError: 33 is not iterable; do not know what to do with it. + """ + if is_MutablePoset(data): + if key is not None: + raise TypeError('Cannot use key when data is a poset.') + self._copy_elements_(data) - if key is None: - self._key_ = lambda k: k else: - self._key_ = key + self.clear() + + if key is None: + self._key_ = lambda k: k + else: + self._key_ = key + + if data is not None: + try: + it = iter(data) + except TypeError: + raise TypeError('%s is not iterable; do not know what to ' + 'do with it.' % (data,)) + self.union_update(it) def clear(self): From cf44c63f03fe304bfc1b2adcafb400e83f2d5152 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 14:50:47 +0100 Subject: [PATCH 0106/1872] Docstring for aliases --- src/sage/data_structures/mutable_poset.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 371be902bc6..04a30b6ee44 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2097,6 +2097,9 @@ def union_update(self, other): update = union_update # as in a Python set + r""" + Alias of :meth:`union_update`. + """ def difference(left, *right): @@ -2342,6 +2345,9 @@ def is_disjoint(self, other): isdisjoint = is_disjoint # as in a Python set + r""" + Alias of :meth:`is_disjoint`. + """ def is_subset(self, other): @@ -2380,6 +2386,9 @@ def is_subset(self, other): issubset = is_subset # as in a Python set + r""" + Alias of :meth:`is_subset`. + """ def is_superset(self, other): @@ -2422,6 +2431,9 @@ def is_superset(self, other): issuperset = is_superset # as in a Python set + r""" + Alias of :meth:`is_superset`. + """ # ***************************************************************************** From 992803b14ac10bcbf2f0924b3368c09fc91b865a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 27 Jan 2015 15:12:19 +0100 Subject: [PATCH 0107/1872] element_exists_hook for add-method --- src/sage/data_structures/mutable_poset.py | 30 +++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 04a30b6ee44..42c133dc4cc 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1634,7 +1634,7 @@ def contains(self, key): __contains__ = contains - def add(self, value): + def add(self, value, element_exists_hook=None): r""" Add the given object as element to the poset. @@ -1643,9 +1643,19 @@ def add(self, value): - ``value`` -- an object (hashable and supporting comparison with the operator ``<=``. + - ``element_exists_hook`` -- a function. It is called when + value is already in this poset. The function gets as a first + parameter this existing value and as a second parameter + ``value``, and it should return the value which to put in + the poset. If this is ``None`` (default) the value is not + changed, i.e., this is equivalent to ``element_exists_hook`` + returns the first parameter. Note that it is not allowed + that the key of this new element differs from the key of + existing. + OUTPUT: - The created (or already existing) element. + Nothing. EXAMPLES:: @@ -1717,6 +1727,18 @@ def add(self, value): sage: P.repr_full(reverse=True) == reprP True + :: + + sage: S = MP(key=lambda k: k[0]) + sage: S.add((3, 'a')) + sage: S + poset((3, 'a')) + sage: def add_existing(existing, other): + ....: return (existing[0], existing[1] + other[1]) + sage: S.add((3, 'b'), element_exists_hook=add_existing) + sage: S + poset((3, 'ab')) + TESTS:: sage: R = MP(key=lambda k: T(k[2:3])) @@ -1746,6 +1768,10 @@ def add(self, value): key = self.get_key(value) if key in self._elements_: + if element_exists_hook is not None: + existing = self.element(key) + new = element_exists_hook(existing.value, value) + existing._value_ = new return new = MutablePosetElement(self, value) From 6e75dc2f941447da86853b258458a66ee22ce56f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 28 Jan 2015 10:40:06 +0100 Subject: [PATCH 0108/1872] add-method: allow cancellation of elements --- src/sage/data_structures/mutable_poset.py | 58 +++++++++++++++++------ 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 42c133dc4cc..57b42799a35 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1644,14 +1644,22 @@ def add(self, value, element_exists_hook=None): with the operator ``<=``. - ``element_exists_hook`` -- a function. It is called when - value is already in this poset. The function gets as a first - parameter this existing value and as a second parameter - ``value``, and it should return the value which to put in - the poset. If this is ``None`` (default) the value is not - changed, i.e., this is equivalent to ``element_exists_hook`` - returns the first parameter. Note that it is not allowed - that the key of this new element differs from the key of - existing. + ``value`` (more precisely its key) is already in this + poset. This function has the following properties: + + - It gets as a first parameter the existing value mentioned above. + + - As a second parameter it gets ``value``. + + - It should return the value which to put in the poset + instead of the existing one. If this return value is ``None``, + the existing element is removed out of the poset. + + If ``element_exists_hook`` is ``None`` (default) the value + (existing element) is not changed, i.e., this is equivalent + to ``element_exists_hook`` returns the first parameter. Note + that it is not allowed that the key of this new element + differs from the key of existing. OUTPUT: @@ -1727,18 +1735,35 @@ def add(self, value, element_exists_hook=None): sage: P.repr_full(reverse=True) == reprP True - :: + We can influence the behavior when an value with existing key + is to be inserted in the poset. For example, we can perform an + addition on some argument of the values:: - sage: S = MP(key=lambda k: k[0]) - sage: S.add((3, 'a')) - sage: S + sage: A = MP(key=lambda k: k[0]) + sage: A.add((3, 'a')) + sage: A poset((3, 'a')) sage: def add_existing(existing, other): ....: return (existing[0], existing[1] + other[1]) - sage: S.add((3, 'b'), element_exists_hook=add_existing) - sage: S + sage: A.add((3, 'b'), element_exists_hook=add_existing) + sage: A poset((3, 'ab')) + We can also deal with cancellations. If the return value of + our hook-function is ``None``, then the element is removed out of + the poset:: + + sage: B = MP(key=lambda k: k[0]) + sage: def add_existing_None(existing, other): + ....: s = existing[1] + other[1] + ....: if s == 0: + ....: return None + ....: return (existing[0], s) + sage: B.add((7, 42)) + sage: B.add((7, -42), element_exists_hook=add_existing_None) + sage: B + poset() + TESTS:: sage: R = MP(key=lambda k: T(k[2:3])) @@ -1771,7 +1796,10 @@ def add(self, value, element_exists_hook=None): if element_exists_hook is not None: existing = self.element(key) new = element_exists_hook(existing.value, value) - existing._value_ = new + if new is None: + self.remove(key) + else: + existing._value_ = new return new = MutablePosetElement(self, value) From 49c9e174ddb4f743ded9ee1fb99285883380c322 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 29 Jan 2015 14:42:30 +0100 Subject: [PATCH 0109/1872] moved hook from add to __init__ --- src/sage/data_structures/mutable_poset.py | 62 +++++++++++++---------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 57b42799a35..996e0bc4f9d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1002,6 +1002,27 @@ class MutablePoset(sage.structure.sage_object.SageObject): r""" A mutable poset (partially ordered set) as data structure. + INPUT: + + - ``element_exists_hook`` -- a function. It is called during + :meth:`add` when ``value`` (more precisely its key) is already + in this poset. This function has the following properties: + + - It gets as a first parameter the existing value mentioned above. + + - As a second parameter it gets ``value``. + + - It should return the value which to put in the poset + instead of the existing one. If this return value is ``None``, + the existing element is removed out of the poset. + + If ``element_exists_hook`` is ``None`` (default) the value + (existing element) is not changed, i.e., this is equivalent + to ``element_exists_hook`` returns the first parameter. Note + that it is not allowed that the key of this new element + differs from the key of existing. + + .. TODO:: Implement the following methods of @@ -1031,7 +1052,7 @@ class MutablePoset(sage.structure.sage_object.SageObject): - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers_iterator`: Returns an iterator for the upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers`: Returns a list of upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. """ - def __init__(self, data=None, key=None): + def __init__(self, data=None, key=None, element_exists_hook=None): r""" See :class:`MutablePoset` for details. @@ -1073,6 +1094,8 @@ def __init__(self, data=None, key=None): else: self._key_ = key + self._element_exists_hook_ = element_exists_hook + if data is not None: try: it = iter(data) @@ -1634,7 +1657,7 @@ def contains(self, key): __contains__ = contains - def add(self, value, element_exists_hook=None): + def add(self, value): r""" Add the given object as element to the poset. @@ -1643,24 +1666,6 @@ def add(self, value, element_exists_hook=None): - ``value`` -- an object (hashable and supporting comparison with the operator ``<=``. - - ``element_exists_hook`` -- a function. It is called when - ``value`` (more precisely its key) is already in this - poset. This function has the following properties: - - - It gets as a first parameter the existing value mentioned above. - - - As a second parameter it gets ``value``. - - - It should return the value which to put in the poset - instead of the existing one. If this return value is ``None``, - the existing element is removed out of the poset. - - If ``element_exists_hook`` is ``None`` (default) the value - (existing element) is not changed, i.e., this is equivalent - to ``element_exists_hook`` returns the first parameter. Note - that it is not allowed that the key of this new element - differs from the key of existing. - OUTPUT: Nothing. @@ -1739,13 +1744,13 @@ def add(self, value, element_exists_hook=None): is to be inserted in the poset. For example, we can perform an addition on some argument of the values:: - sage: A = MP(key=lambda k: k[0]) + sage: def add_existing(existing, other): + ....: return (existing[0], existing[1] + other[1]) + sage: A = MP(key=lambda k: k[0], element_exists_hook=add_existing) sage: A.add((3, 'a')) sage: A poset((3, 'a')) - sage: def add_existing(existing, other): - ....: return (existing[0], existing[1] + other[1]) - sage: A.add((3, 'b'), element_exists_hook=add_existing) + sage: A.add((3, 'b')) sage: A poset((3, 'ab')) @@ -1753,14 +1758,15 @@ def add(self, value, element_exists_hook=None): our hook-function is ``None``, then the element is removed out of the poset:: - sage: B = MP(key=lambda k: k[0]) sage: def add_existing_None(existing, other): ....: s = existing[1] + other[1] ....: if s == 0: ....: return None ....: return (existing[0], s) + sage: B = MP(key=lambda k: k[0], + ....: element_exists_hook=add_existing_None) sage: B.add((7, 42)) - sage: B.add((7, -42), element_exists_hook=add_existing_None) + sage: B.add((7, -42)) sage: B poset() @@ -1793,9 +1799,9 @@ def add(self, value, element_exists_hook=None): key = self.get_key(value) if key in self._elements_: - if element_exists_hook is not None: + if self._element_exists_hook_ is not None: existing = self.element(key) - new = element_exists_hook(existing.value, value) + new = self._element_exists_hook_(existing.value, value) if new is None: self.remove(key) else: From 886f4952bc39292552b962fda1d0b361bd2e21d5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 29 Jan 2015 15:18:56 +0100 Subject: [PATCH 0110/1872] rename: value --> element --> shell --- src/sage/data_structures/mutable_poset.py | 477 +++++++++++----------- 1 file changed, 238 insertions(+), 239 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 996e0bc4f9d..d81260ded5c 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -160,24 +160,24 @@ # ***************************************************************************** -class MutablePosetElement(sage.structure.sage_object.SageObject): +class MutablePosetShell(sage.structure.sage_object.SageObject): r""" - An element of a :class:`mutable poset `. + A shell for an element of a :class:`mutable poset `. """ - def __init__(self, poset, value): + def __init__(self, poset, element): r""" - See :class:`MutablePosetElement` for details. + See :class:`MutablePosetShell` for details. TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: MutablePosetElement(P, (1, 2)) + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: MutablePosetShell(P, (1, 2)) (1, 2) """ self._poset_ = poset - self._value_ = value + self._element_ = element self._predecessors_ = set() self._successors_ = set() @@ -185,14 +185,14 @@ def __init__(self, poset, value): @property def poset(self): r""" - The poset to which the element belongs. + The poset to which this shell belongs. TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: e = MutablePosetElement(P, (1, 2)) + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: e = MutablePosetShell(P, (1, 2)) sage: e.poset is P True """ @@ -200,48 +200,48 @@ def poset(self): @property - def value(self): + def element(self): r""" - The value of the element. + The element contained in this shell. TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: e = MutablePosetElement(P, (1, 2)) - sage: e.value + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: e = MutablePosetShell(P, (1, 2)) + sage: e.element (1, 2) """ - return self._value_ + return self._element_ @property def key(self): r""" - The key of the element. + The key of the element contained in this shell. - The value of the element is converted by the poset to the key. + The element is converted by the poset to the key. TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: from sage.data_structures.mutable_poset import MutablePosetShell sage: P = MP() - sage: e = MutablePosetElement(P, (1, 2)) + sage: e = MutablePosetShell(P, (1, 2)) sage: e.key (1, 2) sage: Q = MP(key=lambda k: k[0]) - sage: f = MutablePosetElement(Q, (1, 2)) + sage: f = MutablePosetShell(Q, (1, 2)) sage: f.key 1 """ - return self.poset.get_key(self._value_) + return self.poset.get_key(self._element_) def predecessors(self, reverse=False): r""" - Return the predecessors of the element. + Return the predecessors of this shell. INPUT: @@ -256,8 +256,8 @@ def predecessors(self, reverse=False): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: e = MutablePosetElement(P, (1, 2)) + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: e = MutablePosetShell(P, (1, 2)) sage: e.predecessors() set() """ @@ -268,7 +268,7 @@ def predecessors(self, reverse=False): def successors(self, reverse=False): r""" - Return the successors of the element. + Return the successors of this shell. INPUT: @@ -283,8 +283,8 @@ def successors(self, reverse=False): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: e = MutablePosetElement(P, (1, 2)) + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: e = MutablePosetShell(P, (1, 2)) sage: e.successors() set() """ @@ -295,8 +295,7 @@ def successors(self, reverse=False): def is_special(self): r""" - - Return if the element is either the null-element, i.e., the + Return if this shell contains either the null-element, i.e., the element smaller than any possible other element or the infinity-element, i.e., the element larger than any possible other element. @@ -318,12 +317,12 @@ def is_special(self): sage: P.oo.is_special() True """ - return self.value is None + return self.element is None def is_null(self, reverse=False): r""" - Return if the element is the null-element, i.e., the element + Return if this shell contains the null-element, i.e., the element smaller than any possible other element. INPUT: @@ -344,12 +343,12 @@ def is_null(self, reverse=False): sage: P.oo.is_null() False """ - return self.value is None and not self.predecessors(reverse) + return self.element is None and not self.predecessors(reverse) def is_oo(self, reverse=False): r""" - Return if the element is the infinity-element, i.e., the element + Return if this shell contains the infinity-element, i.e., the element larger than any possible other element. INPUT: @@ -370,12 +369,12 @@ def is_oo(self, reverse=False): sage: P.oo.is_oo() True """ - return self.value is None and not self.successors(reverse) + return self.element is None and not self.successors(reverse) def __repr__(self): r""" - Return the representation of the element. + Return the representation of this shell. INPUT: @@ -386,7 +385,7 @@ def __repr__(self): A string. This methods usually returns the representation string of its - :meth:`value`. The only exception is if this value is + :meth:`element`. The only exception is if this element is ``None``. In this case either ``'null'`` or ``'oo'`` is returned depending in the nonexistence of predecessors and sucessors respectively. @@ -395,25 +394,25 @@ def __repr__(self): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: repr(MutablePosetElement(P, (1, 2))) # indirect doctest + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: repr(MutablePosetShell(P, (1, 2))) # indirect doctest '(1, 2)' sage: repr(P.null) # indirect doctest 'null' sage: repr(P.oo) # indirect doctest 'oo' """ - if self.value is None: + if self.element is None: if not self.predecessors(): return 'null' if not self.successors(): return 'oo' - return repr(self.value) + return repr(self.element) def __hash__(self): r""" - Return the hash of the element. + Return the hash of this shell. INPUT: @@ -423,14 +422,15 @@ def __hash__(self): A hash value. - This returns the hash value of the key of this element. + This returns the hash value of the key of the element + contained in this shell. TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: hash(MutablePosetElement(P, (1, 2))) == hash((1, 2)) + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: hash(MutablePosetShell(P, (1, 2))) == hash((1, 2)) True """ return hash(self.key) @@ -442,9 +442,9 @@ def le(left, right, reverse=False): INPUT: - - ``left`` -- an element. + - ``left`` -- a shell. - - ``right`` -- an element. + - ``right`` -- a shell. - ``reverse`` -- (default: ``False``) if set, then return ``right <= left`` instead. @@ -453,19 +453,19 @@ def le(left, right, reverse=False): ``True`` or ``False``. - This methods usually returns if the keys of the given - elements are less or equal. The only exception is if the - value is ``None``. In this case the elements are considered as - special elements: If it has no predecessors, then it is - interpreted as an element smaller than any other, if it has no - successors, then as larger than any other. + This methods usually returns if the keys of the given elements + (in the shells) are less or equal. The only exception is if + the element is ``None``. In this case the shell contains special + elements: If it has no predecessors, then it is interpreted as + an element smaller than any other, if it has no successors, + then as larger than any other. TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: e = MutablePosetElement(P, (1, 2)) + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: e = MutablePosetShell(P, (1, 2)) sage: z = P.null sage: oo = P.oo sage: z <= e @@ -511,25 +511,25 @@ def le(left, right, reverse=False): if reverse: left, right = (right, left) - if left.value is None: + if left.element is None: if not left.predecessors(): # null on the left return True else: # oo on the left - if right.value is None: + if right.element is None: # null or oo on the right return not right.successors() else: # not null, not oo on the right return False - if right.value is None: + if right.element is None: if not right.successors(): # oo on the right return True else: # null on the right - if left.value is None: + if left.element is None: # null or oo on the left return not left.predecessors() else: @@ -547,22 +547,22 @@ def eq(left, right): INPUT: - - ``left`` -- an element. + - ``left`` -- a shell. - - ``right`` -- an element. + - ``right`` -- a shell. OUTPUT: ``True`` or ``False``. - This method compares the keys of the elements. + This method compares the keys of the elements contained in the shells. TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: from sage.data_structures.mutable_poset import MutablePosetElement - sage: e = MutablePosetElement(P, (1, 2)) + sage: from sage.data_structures.mutable_poset import MutablePosetShell + sage: e = MutablePosetShell(P, (1, 2)) sage: z = P.null sage: oo = P.oo sage: z == z @@ -578,7 +578,7 @@ def eq(left, right): sage: oo == z False """ - if left.value is None and right.value is None: + if left.element is None and right.element is None: return left.is_null() == right.is_null() return left.key == right.key @@ -593,13 +593,13 @@ def _copy_all_linked_(self, memo, poset): INPUT: - ``memo`` -- a dictionary which assigns to the id of the - calling element to a copy of it. + calling shell to a copy of it. - - ``poset`` -- the poset to which the newly created element belongs. + - ``poset`` -- the poset to which the newly created shells belongs. OUTPUT: - A new element. + A new shell. TESTS:: @@ -619,7 +619,7 @@ def _copy_all_linked_(self, memo, poset): except KeyError: pass - new = self.__class__(poset, self.value) + new = self.__class__(poset, self.element) memo[id(self)] = new for reverse in (False, True): @@ -629,7 +629,7 @@ def _copy_all_linked_(self, memo, poset): return new - def _search_covers_(self, covers, element, reverse=False): + def _search_covers_(self, covers, shell, reverse=False): r""" Helper function for :meth:`covers`. @@ -637,7 +637,7 @@ def _search_covers_(self, covers, element, reverse=False): - ``covers`` -- a set which finally contains all covers. - - ``element`` -- the element for which to find the covering elements. + - ``shell`` -- the shell for which to find the covering shells. - ``reverse`` -- (default: ``False``) if not set, then find the lower covers, otherwise find the upper covers. @@ -647,7 +647,7 @@ def _search_covers_(self, covers, element, reverse=False): ``True`` or ``False``. Note that ``False`` is returned if we do not have - ``self <= element``. + ``self <= shell``. TESTS:: @@ -662,30 +662,30 @@ def _search_covers_(self, covers, element, reverse=False): sage: P.add(T((4, 4, 2))) sage: P.add(T((1, 2, 2))) sage: P.add(T((2, 2, 2))) - sage: e = P.element(T((2, 2, 2))); e + sage: e = P.shell(T((2, 2, 2))); e (2, 2, 2) sage: covers = set() sage: P.null._search_covers_(covers, e) True - sage: sorted(covers, key=lambda c: repr(c.value)) + sage: sorted(covers, key=lambda c: repr(c.element)) [(1, 2, 2), (2, 1, 2)] """ - if not self.le(element, reverse) or self == element: + if not self.le(shell, reverse) or self == shell: return False - if not any([e._search_covers_(covers, element, reverse) + if not any([e._search_covers_(covers, shell, reverse) for e in self.successors(reverse)]): covers.add(self) return True - def covers(self, element, reverse=False): + def covers(self, shell, reverse=False): r""" - Return the covers of the given element (considering only - elements which originate from itself). + Return the covers of the given shell (considering only + shells which originate from itself). INPUT: - - ``element`` -- the element for which to find the covering elements. + - ``shell`` -- the shell for which to find the covering shells. - ``reverse`` -- (default: ``False``) if not set, then find the lower covers, otherwise find the upper covers. @@ -695,10 +695,10 @@ def covers(self, element, reverse=False): A set of the covers. Suppose ``reverse`` is ``False``. This method returns all the - lower covers of the given ``element``, i.e., elements in the - poset, which are at most the given element and maximal with - this property. Only elements which are (not necessarily - direct) successors of the calling element are considered. + lower covers of the given ``shell``, i.e., shells in the + poset, which are at most the given shell and maximal with + this property. Only shells which are (not necessarily + direct) successors of the calling shell are considered. If ``reverse`` is ``True``, then the reverse direction is taken, i.e., in the text above replace lower covers by upper @@ -717,17 +717,17 @@ def covers(self, element, reverse=False): sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: P.add(T((2, 2))) - sage: e = P.element(T((2, 2))); e + sage: e = P.shell(T((2, 2))); e (2, 2) sage: sorted(P.null.covers(e), - ....: key=lambda c: repr(c.value)) + ....: key=lambda c: repr(c.element)) [(1, 2), (2, 1)] sage: sorted(P.oo.covers(e, reverse=True), - ....: key=lambda c: repr(c.value)) + ....: key=lambda c: repr(c.element)) [(4, 4)] """ covers = set() - self._search_covers_(covers, element, reverse) + self._search_covers_(covers, shell, reverse) return covers @@ -737,7 +737,7 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): INPUT: - - ``marked`` -- a set in which marked elements are stored. + - ``marked`` -- a set in which marked shells are stored. - ``reverse`` -- (default: ``False``) -- if set, reverses the order. @@ -765,14 +765,14 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): S = self.successors(reverse) if key is not None: S = sorted(S, key=key) - for element in S: - for e in element._iter_depth_first_visit_(marked, reverse, key): + for shell in S: + for e in shell._iter_depth_first_visit_(marked, reverse, key): yield e def iter_depth_first(self, reverse=False, key=None): r""" - Iterates over all elements in depth first order. + Iterates over all shells in depth first order. INPUT: @@ -781,7 +781,7 @@ def iter_depth_first(self, reverse=False, key=None): ``True`` starts at top (`\infty`). - ``key`` -- (default: ``None``) a function used for sorting - the direct successors of an element (used in case of a + the direct successors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. OUTPUT: @@ -820,12 +820,12 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): INPUT: - - ``marked`` -- a set in which marked elements are stored. + - ``marked`` -- a set in which marked shells are stored. - ``reverse`` -- (default: ``False``) -- if set, reverses the order. - ``key`` -- (default: ``None``) a function used for sorting - the direct successors of an element (used in case of a + the direct successors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. OUTPUT: @@ -848,24 +848,24 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): S = self.predecessors(reverse) if key is not None: S = sorted(S, key=key) - for element in S: - for e in element._iter_topological_visit_(marked, reverse, key): + for shell in S: + for e in shell._iter_topological_visit_(marked, reverse, key): yield e yield self def iter_topological(self, reverse=False, key=None): r""" - Iterates over all elements in topological order. + Iterates over all shells in topological order. INPUT: - ``reverse`` -- (default: ``False``) -- if set, reverses the - order, i.e., ``False`` gives smallest elements first, + order, i.e., ``False`` gives smallest shells first, ``True`` gives largest first. - ``key`` -- (default: ``None``) a function used for sorting - the direct successors of an element (used in case of a + the direct successors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. OUTPUT: @@ -903,7 +903,7 @@ def iter_topological(self, reverse=False, key=None): :: - sage: for e in P.elements_topological(include_special=True, + sage: for e in P.shells_topological(include_special=True, ....: reverse=True): ....: print e ....: print list(e.iter_topological(reverse=True, key=repr)) @@ -926,7 +926,7 @@ def iter_topological(self, reverse=False, key=None): :: - sage: for e in P.elements_topological(include_special=True, + sage: for e in P.shells_topological(include_special=True, ....: reverse=True): ....: print e ....: print list(e.iter_topological(reverse=False, key=repr)) @@ -1005,18 +1005,18 @@ class MutablePoset(sage.structure.sage_object.SageObject): INPUT: - ``element_exists_hook`` -- a function. It is called during - :meth:`add` when ``value`` (more precisely its key) is already + :meth:`add` when an element (more precisely its key) is already in this poset. This function has the following properties: - - It gets as a first parameter the existing value mentioned above. + - It gets as a first parameter the existing element mentioned above. - - As a second parameter it gets ``value``. + - As a second parameter it gets the element from :meth:`add`. - - It should return the value which to put in the poset + - It should return the element which to put in the poset instead of the existing one. If this return value is ``None``, the existing element is removed out of the poset. - If ``element_exists_hook`` is ``None`` (default) the value + If ``element_exists_hook`` is ``None`` (default) the (existing element) is not changed, i.e., this is equivalent to ``element_exists_hook`` returns the first parameter. Note that it is not allowed that the key of this new element @@ -1084,7 +1084,7 @@ def __init__(self, data=None, key=None, element_exists_hook=None): if is_MutablePoset(data): if key is not None: raise TypeError('Cannot use key when data is a poset.') - self._copy_elements_(data) + self._copy_shells_(data) else: self.clear() @@ -1133,17 +1133,17 @@ def clear(self): | +-- predecessors: null | +-- no successors """ - self._null_ = MutablePosetElement(self, None) - self._oo_ = MutablePosetElement(self, None) + self._null_ = MutablePosetShell(self, None) + self._oo_ = MutablePosetShell(self, None) self._null_.successors().add(self._oo_) self._oo_.predecessors().add(self._null_) - self._elements_ = {} + self._shells_ = {} @property def null(self): r""" - The element `\emptyset` which is smaller than any other element. + The shell `\emptyset` whose element is smaller than any other element. EXAMPLES: @@ -1160,7 +1160,7 @@ def null(self): @property def oo(self): r""" - The element `\infty` which is larger than any other element. + The shell `\infty` whose element is larger than any other element. EXAMPLES: @@ -1174,9 +1174,9 @@ def oo(self): return self._oo_ - def element(self, key): + def shell(self, key): r""" - Return the element corresponding to ``key``. + Return the shell of the element corresponding to ``key``. INPUT: @@ -1184,37 +1184,37 @@ def element(self, key): OUTPUT: - An instance of :class:`MutablePosetElement`. + An instance of :class:`MutablePosetShell`. EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() sage: P.add(42) - sage: e = P.element(42); e + sage: e = P.shell(42); e 42 sage: type(e) - + """ - return self._elements_[key] + return self._shells_[key] - def get_key(self, value): + def get_key(self, element): r""" - Return the key corresponding to ``value``. + Return the key corresponding to the given element. INPUT: - - ``value`` -- an object. + - ``element`` -- an object. OUTPUT: - An object (the key of ``value``). + An object (the key of ``element``). TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: from sage.data_structures.mutable_poset import MutablePosetElement + sage: from sage.data_structures.mutable_poset import MutablePosetShell sage: P = MP() sage: P.get_key(None) is None True @@ -1224,18 +1224,18 @@ def get_key(self, value): sage: Q.get_key((1, 2)) 1 """ - if value is None: + if element is None: return None - return self._key_(value) + return self._key_(element) - def _copy_elements_(self, other): + def _copy_shells_(self, other): r""" - Helper function for copying elements. + Helper function for copying shells. INPUT: - - ``other`` -- the mutable poset from which the elements + - ``other`` -- the mutable poset from which the shells should be copied this poset. OUTPUT: @@ -1255,7 +1255,7 @@ def _copy_elements_(self, other): sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: Q = MP() - sage: Q._copy_elements_(P) + sage: Q._copy_shells_(P) sage: P.repr_full() == Q.repr_full() True """ @@ -1264,9 +1264,9 @@ def _copy_elements_(self, other): memo = {} self._null_ = other._null_._copy_all_linked_(memo, self) self._oo_ = memo[id(other._oo_)] - self._elements_ = dict((f.key, f) for f in + self._shells_ = dict((f.key, f) for f in iter(memo[id(e)] - for e in other._elements_.itervalues())) + for e in other._shells_.itervalues())) def copy(self): @@ -1298,25 +1298,25 @@ def copy(self): True """ new = self.__class__() - new._copy_elements_(self) + new._copy_shells_(self) return new __copy__ = copy - def elements(self, include_special=False, reverse=False): + def shells(self, include_special=False, reverse=False): r""" - Return an iterator over all elements. + Return an iterator over all shells. INPUT: - ``include_special`` -- (default: ``False``) if set, then - including a smallest element (`\emptyset`) and a largest element - (`\infty`). + including shells containing a smallest element (`\emptyset`) + and a largest element (`\infty`). - ``reverse`` -- (default: ``False``) if set, the order is - reversed. This only affects the elements `\emptyset` and `\infty`. + reversed. This only affects the shells `\emptyset` and `\infty`. OUTPUT: @@ -1326,38 +1326,38 @@ def elements(self, include_special=False, reverse=False): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() - sage: tuple(P.elements()) + sage: tuple(P.shells()) () - sage: tuple(P.elements(include_special=True)) + sage: tuple(P.shells(include_special=True)) (null, oo) - sage: tuple(P.elements(include_special=True, reverse=True)) + sage: tuple(P.shells(include_special=True, reverse=True)) (oo, null) """ if include_special: yield self.null if not reverse else self.oo - for e in self._elements_.itervalues(): + for e in self._shells_.itervalues(): yield e if include_special: yield self.oo if not reverse else self.null - def elements_topological(self, include_special=False, + def shells_topological(self, include_special=False, reverse=False, key=None): r""" - Return an iterator over all elements in topological order. + Return an iterator over all shells in topological order. INPUT: - ``include_special`` -- (default: ``False``) if set, then - including a smallest element (`\emptyset`) and a largest element - (`\infty`). - + including shells containing a smallest element (`\emptyset`) + and a largest element (`\infty`). + - ``reverse`` -- (default: ``False``) -- if set, reverses the order, i.e., ``False`` gives smallest elements first, ``True`` gives largest first. - ``key`` -- (default: ``None``) a function used for sorting - the direct successors of an element (used in case of a + the direct successors of a shell (used in case of a tie). If this is ``None``, no sorting according to the reprsentation string occurs. @@ -1378,30 +1378,30 @@ def elements_topological(self, include_special=False, sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: P.add(T((2, 2))) - sage: list(P.elements_topological()) + sage: list(P.shells_topological()) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] - sage: list(P.elements_topological(reverse=True)) + sage: list(P.shells_topological(reverse=True)) [(4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)] - sage: list(P.elements_topological(include_special=True)) + sage: list(P.shells_topological(include_special=True)) [null, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] - sage: list(P.elements_topological( + sage: list(P.shells_topological( ....: include_special=True, reverse=True)) [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), null] """ if key is None: key = repr - element = self.oo if not reverse else self.null - return iter(e for e in element.iter_topological(reverse, key) + shell = self.oo if not reverse else self.null + return iter(e for e in shell.iter_topological(reverse, key) if include_special or not e.is_special()) - def values(self, **kwargs): + def elements(self, **kwargs): r""" - Return an iterator over all values of the elements. + Return an iterator over all elements. INPUT: - - ``kwargs`` -- arguments are passed to :meth:`elements`. + - ``kwargs`` -- arguments are passed to :meth:`shells`. OUTPUT: @@ -1414,7 +1414,7 @@ def values(self, **kwargs): sage: P.add(3) sage: P.add(42) sage: P.add(7) - sage: [(v, type(v)) for v in sorted(P.values())] + sage: [(v, type(v)) for v in sorted(P.elements())] [(3, ), (7, ), (42, )] @@ -1427,23 +1427,22 @@ def values(self, **kwargs): sage: sorted(it) [3, 7, 42] - returns all values as well. + returns all elements as well. """ - for element in self.elements(**kwargs): - yield element.value + for shell in self.shells(**kwargs): + yield shell.element - __iter__ = values + __iter__ = elements - def values_topological(self, **kwargs): + def elements_topological(self, **kwargs): r""" - Return an iterator over all values of the elements in - topological order. + Return an iterator over all elements in topological order. INPUT: - - ``kwargs`` -- arguments are passed to :meth:`elements_topological`. + - ``kwargs`` -- arguments are passed to :meth:`shells_topological`. OUTPUT: @@ -1462,7 +1461,7 @@ def values_topological(self, **kwargs): sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: P.add(T((2, 2))) - sage: [(v, type(v)) for v in P.values_topological()] + sage: [(v, type(v)) for v in P.elements_topological()] [((1, 1), ), ((1, 2), ), ((1, 3), ), @@ -1470,8 +1469,8 @@ def values_topological(self, **kwargs): ((2, 2), ), ((4, 4), )] """ - for element in self.elements_topological(**kwargs): - yield element.value + for shell in self.shells_topological(**kwargs): + yield shell.element def keys(self, **kwargs): @@ -1480,7 +1479,7 @@ def keys(self, **kwargs): INPUT: - - ``kwargs`` -- arguments are passed to :meth:`elements`. + - ``kwargs`` -- arguments are passed to :meth:`shells`. OUTPUT: @@ -1498,19 +1497,19 @@ def keys(self, **kwargs): (-7, ), (-3, )] - sage: [(v, type(v)) for v in sorted(P.values())] + sage: [(v, type(v)) for v in sorted(P.elements())] [(3, ), (7, ), (42, )] - sage: [(v, type(v)) for v in sorted(P.elements(), - ....: key=lambda c: c.value)] - [(3, ), - (7, ), - (42, )] + sage: [(v, type(v)) for v in sorted(P.shells(), + ....: key=lambda c: c.element)] + [(3, ), + (7, ), + (42, )] """ - for element in self.elements(**kwargs): - yield element.key + for shell in self.shells(**kwargs): + yield shell.key def keys_topological(self, **kwargs): @@ -1520,7 +1519,7 @@ def keys_topological(self, **kwargs): INPUT: - - ``kwargs`` -- arguments are passed to :meth:`elements_topological`. + - ``kwargs`` -- arguments are passed to :meth:`shells_topological`. OUTPUT: @@ -1543,17 +1542,17 @@ def keys_topological(self, **kwargs): [(1, ), (2, ), (4, )] - sage: [(v, type(v)) for v in P.values_topological()] + sage: [(v, type(v)) for v in P.elements_topological()] [((1, 1), ), ((2, 1), ), ((4, 4), )] - sage: [(v, type(v)) for v in P.elements_topological()] - [((1, 1), ), - ((2, 1), ), - ((4, 4), )] + sage: [(v, type(v)) for v in P.shells_topological()] + [((1, 1), ), + ((2, 1), ), + ((4, 4), )] """ - for element in self.elements_topological(**kwargs): - yield element.key + for shell in self.shells_topological(**kwargs): + yield shell.key def repr(self, include_special=False, reverse=False): @@ -1575,8 +1574,8 @@ def repr(self, include_special=False, reverse=False): poset() """ s = 'poset(' - s += ', '.join(repr(element) for element in - self.elements_topological(include_special, reverse)) + s += ', '.join(repr(shell) for shell in + self.shells_topological(include_special, reverse)) s += ')' return s @@ -1605,18 +1604,18 @@ def repr_full(self, reverse=False): | +-- successors: oo | +-- no predecessors """ - sortedelements = tuple( - self.elements_topological(include_special=True, reverse=reverse)) + sortedshells = tuple( + self.shells_topological(include_special=True, reverse=reverse)) strings = [self.repr(include_special=False, reverse=reverse)] - for element in sortedelements: - strings.append('+-- ' + repr(element)) + for shell in sortedshells: + strings.append('+-- ' + repr(shell)) for rev in (not reverse, reverse): what = 'successors' if not rev else 'predecessors' - if element.successors(rev): + if shell.successors(rev): s = '| +-- ' + what + ': ' s += ', '.join(repr(e) for e in - sorted_set_by_tuple(element.successors(rev), - sortedelements)) + sorted_set_by_tuple(shell.successors(rev), + sortedshells)) else: s = '| +-- no ' + what strings.append(s) @@ -1651,19 +1650,19 @@ def contains(self, key): sage: T((1, 2)) in P # indirect doctest False """ - return key in self._elements_ + return key in self._shells_ __contains__ = contains - def add(self, value): + def add(self, element): r""" Add the given object as element to the poset. INPUT: - - ``value`` -- an object (hashable and supporting comparison + - ``element`` -- an object (hashable and supporting comparison with the operator ``<=``. OUTPUT: @@ -1740,9 +1739,9 @@ def add(self, value): sage: P.repr_full(reverse=True) == reprP True - We can influence the behavior when an value with existing key + We can influence the behavior when an element with existing key is to be inserted in the poset. For example, we can perform an - addition on some argument of the values:: + addition on some argument of the elements:: sage: def add_existing(existing, other): ....: return (existing[0], existing[1] + other[1]) @@ -1794,35 +1793,35 @@ def add(self, value): | +-- successors: (2, 1, 7) | +-- no predecessors """ - if value is None: - raise ValueError('None is not allowed as value.') - key = self.get_key(value) + if element is None: + raise ValueError('None is not allowed as element.') + key = self.get_key(element) - if key in self._elements_: + if key in self._shells_: if self._element_exists_hook_ is not None: - existing = self.element(key) - new = self._element_exists_hook_(existing.value, value) + existing = self.shell(key) + new = self._element_exists_hook_(existing.element, element) if new is None: self.remove(key) else: - existing._value_ = new + existing._element_ = new return - new = MutablePosetElement(self, value) + new = MutablePosetShell(self, element) smaller = self.null.covers(new, reverse=False) larger = self.oo.covers(new, reverse=True) for reverse in (False, True): sm = smaller if not reverse else larger la = larger if not reverse else smaller - for element in sm: - for e in element.successors(reverse).intersection(la): - e.predecessors(reverse).remove(element) - element.successors(reverse).remove(e) - new.predecessors(reverse).add(element) - element.successors(reverse).add(new) + for shell in sm: + for e in shell.successors(reverse).intersection(la): + e.predecessors(reverse).remove(shell) + shell.successors(reverse).remove(e) + new.predecessors(reverse).add(shell) + shell.successors(reverse).add(new) - self._elements_[key] = new + self._shells_[key] = new def remove(self, key, raise_key_error=True): @@ -1972,21 +1971,21 @@ def remove(self, key, raise_key_error=True): raise ValueError('None is not allowed as key.') try: - element = self._elements_[key] + shell = self._shells_[key] except KeyError: if not raise_key_error: return raise KeyError('Key %s is not contained in this poset.' % (key,)) for reverse in (False, True): - for p in element.predecessors(reverse): + for p in shell.predecessors(reverse): S = p.successors(reverse) - S.remove(element) + S.remove(shell) D = set(s for s in p.iter_depth_first(reverse) - if s in element.successors(reverse)) - S.update(element.successors(reverse)) + if s in shell.successors(reverse)) + S.update(shell.successors(reverse)) S.difference_update(D) - del self._elements_[key] + del self._shells_[key] def discard(self, key, raise_key_error=False): @@ -2036,7 +2035,7 @@ def pop(self, **kwargs): INPUT: - - ``kwargs`` -- arguments are passed to :meth:`elements_topological`. + - ``kwargs`` -- arguments are passed to :meth:`shells_topological`. OUTPUT: @@ -2065,11 +2064,11 @@ def pop(self, **kwargs): kwargs['include_special'] = False try: - element = next(self.elements_topological(**kwargs)) + shell = next(self.shells_topological(**kwargs)) except StopIteration: raise KeyError('pop from an empty poset') - self.remove(element.key) - return element.value + self.remove(shell.key) + return shell.element def union(left, *right): @@ -2081,7 +2080,7 @@ def union(left, *right): - ``left`` -- a poset. - ``right`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2117,7 +2116,7 @@ def union_update(self, other): INPUT: - ``other`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2149,11 +2148,11 @@ def union_update(self, other): poset(3, 4, 7, 8, 42) """ try: - it = other.values() + it = other.elements() except AttributeError: it = iter(other) - for value in it: - self.add(value) + for element in it: + self.add(element) update = union_update # as in a Python set @@ -2172,7 +2171,7 @@ def difference(left, *right): - ``left`` -- a poset. - ``right`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2212,7 +2211,7 @@ def difference_update(self, other): INPUT: - ``other`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2248,7 +2247,7 @@ def intersection(left, *right): - ``left`` -- a poset. - ``right`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2284,7 +2283,7 @@ def intersection_update(self, other): INPUT: - ``other`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2381,7 +2380,7 @@ def is_disjoint(self, other): INPUT: - ``other`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2418,7 +2417,7 @@ def is_subset(self, other): INPUT: - ``other`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2459,7 +2458,7 @@ def is_superset(self, other): INPUT: - ``other`` -- a poset or an iterable. In the latter case the - iterated objects are seen as values of a poset. + iterated objects are seen as elements of a poset. OUTPUT: @@ -2499,9 +2498,9 @@ def is_superset(self, other): # ***************************************************************************** -class MutableTosetElement(MutablePosetElement): +class MutableTosetShell(MutablePosetShell): r""" - An element of a mutable toset (totally ordered set). + A shell containing an element of a mutable toset (totally ordered set). .. TODO:: From 143dfeab1089f54057194d4318b4197cd061c9a1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 29 Jan 2015 15:47:47 +0100 Subject: [PATCH 0111/1872] write method element --- src/sage/data_structures/mutable_poset.py | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d81260ded5c..228d3692ad5 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1199,6 +1199,31 @@ def shell(self, key): return self._shells_[key] + def element(self, key): + r""" + Return the element corresponding to ``key``. + + INPUT: + + ``key`` -- the key of an object. + + OUTPUT: + + An object. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(42) + sage: e = P.element(42); e + 42 + sage: type(e) + + """ + return self._shells_[key].element + + def get_key(self, element): r""" Return the key corresponding to the given element. From b348d14284f5dc30170ff05887ca53033b2a541e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 29 Jan 2015 15:48:10 +0100 Subject: [PATCH 0112/1872] improve/extend docstrings --- src/sage/data_structures/mutable_poset.py | 102 +++++++++++++++++++--- 1 file changed, 92 insertions(+), 10 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 228d3692ad5..f010d22b779 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -163,6 +163,28 @@ class MutablePosetShell(sage.structure.sage_object.SageObject): r""" A shell for an element of a :class:`mutable poset `. + + INPUT: + + - ``poset`` -- the poset to which this shell belongs. + + - ``element`` -- the element which should be + contained/encapsulated in this shell. + + OUTPUT: + + A shell for the given element. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: P.add(66) + sage: P + poset(66) + sage: s = P.shell(66) + sage: type(s) + """ def __init__(self, poset, element): r""" @@ -739,10 +761,13 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): - ``marked`` -- a set in which marked shells are stored. - - ``reverse`` -- (default: ``False``) -- if set, reverses the order. + - ``reverse`` -- (default: ``False``) if set, reverses the + order, i.e., ``False`` gives smallest shells first, + ``True`` gives largest first. - ``key`` -- (default: ``None``) a function used for sorting - the successors. If this is ``None``, no sorting occurs. + the direct successors of a shell (used in case of a + tie). If this is ``None``, no sorting occurs. OUTPUT: @@ -776,9 +801,9 @@ def iter_depth_first(self, reverse=False, key=None): INPUT: - - ``reverse`` -- (default: ``False``) -- if set, reverses the - order, i.e., ``False`` starts at bottom (`\emptyset`), - ``True`` starts at top (`\infty`). + - ``reverse`` -- (default: ``False``) if set, reverses the + order, i.e., ``False`` gives smallest shells first, + ``True`` gives largest first. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -822,7 +847,9 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): - ``marked`` -- a set in which marked shells are stored. - - ``reverse`` -- (default: ``False``) -- if set, reverses the order. + - ``reverse`` -- (default: ``False``) if set, reverses the + order, i.e., ``False`` gives smallest shells first, + ``True`` gives largest first. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -860,7 +887,7 @@ def iter_topological(self, reverse=False, key=None): INPUT: - - ``reverse`` -- (default: ``False``) -- if set, reverses the + - ``reverse`` -- (default: ``False``) if set, reverses the order, i.e., ``False`` gives smallest shells first, ``True`` gives largest first. @@ -1004,6 +1031,19 @@ class MutablePoset(sage.structure.sage_object.SageObject): INPUT: + - ``data`` -- data from which to construct the poset. It can be + any of the following: + + #. ``None`` (default), in which case an empty poset is created, + + #. a :class:`MutablePoset`, which will be copied during creation, + + #. an iterable, whose elements will be in the poset. + + - ``key`` -- a function which maps elements to keys. If ``None`` + (default), this is the identity, i.e., keys are equal to their + elements. + - ``element_exists_hook`` -- a function. It is called during :meth:`add` when an element (more precisely its key) is already in this poset. This function has the following properties: @@ -1012,9 +1052,9 @@ class MutablePoset(sage.structure.sage_object.SageObject): - As a second parameter it gets the element from :meth:`add`. - - It should return the element which to put in the poset - instead of the existing one. If this return value is ``None``, - the existing element is removed out of the poset. + - It should return the element which to put in the poset instead + of the existing one. If this return value is ``None``, the + existing element is removed out of the poset. If ``element_exists_hook`` is ``None`` (default) the (existing element) is not changed, i.e., this is equivalent @@ -1022,6 +1062,36 @@ class MutablePoset(sage.structure.sage_object.SageObject): that it is not allowed that the key of this new element differs from the key of existing. + OUTPUT: + + A mutable poset. + + You can find a short introduction and examples + :mod:`here `. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + + We illustrate the different input formats + + #. No input:: + + sage: A = MP(); A + poset() + + #. A :class:`MutablePoset`:: + + sage: B = MP(A); B + poset() + sage: B.add(42) + sage: C = MP(B); C + poset(42) + + #. An iterable:: + + sage: C = MP([5, 3, 11]); C + poset(3, 5, 11) .. TODO:: @@ -1186,6 +1256,10 @@ def shell(self, key): An instance of :class:`MutablePosetShell`. + .. NOTE:: + + Each element is contained/encapusalted in a shell inside the poset. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1347,6 +1421,10 @@ def shells(self, include_special=False, reverse=False): An iterator. + .. NOTE:: + + Each element is contained/encapusalted in a shell inside the poset. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1390,6 +1468,10 @@ def shells_topological(self, include_special=False, An iterator. + .. NOTE:: + + Each element is contained/encapusalted in a shell inside the poset. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 520bb00642983f93ad4e6741b421bfb5cf7eef60 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 29 Jan 2015 17:20:59 +0100 Subject: [PATCH 0113/1872] conditional iterations for shells --- src/sage/data_structures/mutable_poset.py | 63 ++++++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index f010d22b779..f45db2f7b44 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -753,7 +753,9 @@ def covers(self, shell, reverse=False): return covers - def _iter_depth_first_visit_(self, marked, reverse=False, key=None): + def _iter_depth_first_visit_(self, marked, + reverse=False, key=None, + condition=None): r""" Helper function for :meth:`iter_depth_first`. @@ -769,6 +771,12 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): the direct successors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. + - ``condition`` -- (default: ``None``) a function mapping a + shell to ``True`` (include in iteration) or ``False`` (do + not include). ``None`` is equivalent to a function returning + always ``True``. Note that the iteration does not go beyond a + not shell included shell. + OUTPUT: An iterator. @@ -783,6 +791,9 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): sage: list(P.oo._iter_depth_first_visit_(marked, True)) [oo, 42, 5, null] """ + if (condition is not None and + not self.is_special() and not condition(self)): + return if self in marked: return marked.add(self) @@ -791,11 +802,12 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None): if key is not None: S = sorted(S, key=key) for shell in S: - for e in shell._iter_depth_first_visit_(marked, reverse, key): + for e in shell._iter_depth_first_visit_(marked, reverse, + key, condition): yield e - def iter_depth_first(self, reverse=False, key=None): + def iter_depth_first(self, reverse=False, key=None, condition=None): r""" Iterates over all shells in depth first order. @@ -809,6 +821,12 @@ def iter_depth_first(self, reverse=False, key=None): the direct successors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. + - ``condition`` -- (default: ``None``) a function mapping a + shell to ``True`` (include in iteration) or ``False`` (do + not include). ``None`` is equivalent to a function returning + always ``True``. Note that the iteration does not go beyond a + not shell included shell. + OUTPUT: An iterator. @@ -834,12 +852,17 @@ def iter_depth_first(self, reverse=False, key=None): [null, (1, 1), (1, 2), (1, 3), (4, 4), oo, (2, 2), (2, 1)] sage: list(P.oo.iter_depth_first(reverse=True, key=repr)) [oo, (4, 4), (1, 3), (1, 2), (1, 1), null, (2, 2), (2, 1)] + sage: list(P.null.iter_depth_first( + ....: condition=lambda s: s.element[0] == 1)) + [null, (1, 1), (1, 2), (1, 3)] """ marked = set() - return self._iter_depth_first_visit_(marked, reverse, key) + return self._iter_depth_first_visit_(marked, reverse, key, condition) - def _iter_topological_visit_(self, marked, reverse=False, key=None): + def _iter_topological_visit_(self, marked, + reverse=False, key=None, + condition=None): r""" Helper function for :meth:`iter_topological`. @@ -855,6 +878,12 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): the direct successors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. + - ``condition`` -- (default: ``None``) a function mapping a + shell to ``True`` (include in iteration) or ``False`` (do + not include). ``None`` is equivalent to a function returning + always ``True``. Note that the iteration does not go beyond a + not shell included shell. + OUTPUT: An iterator. @@ -869,6 +898,9 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): sage: list(P.null._iter_topological_visit_(marked, True)) [oo, 42, 5, null] """ + if (condition is not None and + not self.is_special() and not condition(self)): + return if self in marked: return marked.add(self) @@ -876,12 +908,13 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None): if key is not None: S = sorted(S, key=key) for shell in S: - for e in shell._iter_topological_visit_(marked, reverse, key): + for e in shell._iter_topological_visit_(marked, reverse, + key, condition): yield e yield self - def iter_topological(self, reverse=False, key=None): + def iter_topological(self, reverse=False, key=None, condition=None): r""" Iterates over all shells in topological order. @@ -895,6 +928,12 @@ def iter_topological(self, reverse=False, key=None): the direct successors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. + - ``condition`` -- (default: ``None``) a function mapping a + shell to ``True`` (include in iteration) or ``False`` (do + not include). ``None`` is equivalent to a function returning + always ``True``. Note that the iteration does not go beyond a + not shell included shell. + OUTPUT: An iterator. @@ -973,9 +1012,17 @@ def iter_topological(self, reverse=False, key=None): [null, (1, 1)] null [null] + + :: + + sage: def C(shell): + ....: return shell.element[0] == 1 + sage: list(P.null.iter_topological( + ....: reverse=True, condition=lambda s: s.element[0] == 1)) + [(1, 3), (1, 2), (1, 1), null] """ marked = set() - return self._iter_topological_visit_(marked, reverse, key) + return self._iter_topological_visit_(marked, reverse, key, condition) # ***************************************************************************** From e443f7e324a2b29f773572bba3588ce1c4b69f4d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 29 Jan 2015 17:32:49 +0100 Subject: [PATCH 0114/1872] rename element_exists_hook to merge_hook --- src/sage/data_structures/mutable_poset.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index f45db2f7b44..c02a1b63425 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1091,7 +1091,7 @@ class MutablePoset(sage.structure.sage_object.SageObject): (default), this is the identity, i.e., keys are equal to their elements. - - ``element_exists_hook`` -- a function. It is called during + - ``merge_hook`` -- a function. It is called during :meth:`add` when an element (more precisely its key) is already in this poset. This function has the following properties: @@ -1103,9 +1103,9 @@ class MutablePoset(sage.structure.sage_object.SageObject): of the existing one. If this return value is ``None``, the existing element is removed out of the poset. - If ``element_exists_hook`` is ``None`` (default) the + If ``merge_hook`` is ``None`` (default) the (existing element) is not changed, i.e., this is equivalent - to ``element_exists_hook`` returns the first parameter. Note + to ``merge_hook`` returns the first parameter. Note that it is not allowed that the key of this new element differs from the key of existing. @@ -1169,7 +1169,7 @@ class MutablePoset(sage.structure.sage_object.SageObject): - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers_iterator`: Returns an iterator for the upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers`: Returns a list of upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. """ - def __init__(self, data=None, key=None, element_exists_hook=None): + def __init__(self, data=None, key=None, merge_hook=None): r""" See :class:`MutablePoset` for details. @@ -1211,7 +1211,7 @@ def __init__(self, data=None, key=None, element_exists_hook=None): else: self._key_ = key - self._element_exists_hook_ = element_exists_hook + self._merge_hook_ = merge_hook if data is not None: try: @@ -1897,9 +1897,9 @@ def add(self, element): is to be inserted in the poset. For example, we can perform an addition on some argument of the elements:: - sage: def add_existing(existing, other): + sage: def add(existing, other): ....: return (existing[0], existing[1] + other[1]) - sage: A = MP(key=lambda k: k[0], element_exists_hook=add_existing) + sage: A = MP(key=lambda k: k[0], merge_hook=add) sage: A.add((3, 'a')) sage: A poset((3, 'a')) @@ -1911,13 +1911,13 @@ def add(self, element): our hook-function is ``None``, then the element is removed out of the poset:: - sage: def add_existing_None(existing, other): + sage: def add_None(existing, other): ....: s = existing[1] + other[1] ....: if s == 0: ....: return None ....: return (existing[0], s) sage: B = MP(key=lambda k: k[0], - ....: element_exists_hook=add_existing_None) + ....: merge_hook=add_None) sage: B.add((7, 42)) sage: B.add((7, -42)) sage: B @@ -1952,9 +1952,9 @@ def add(self, element): key = self.get_key(element) if key in self._shells_: - if self._element_exists_hook_ is not None: + if self._merge_hook_ is not None: existing = self.shell(key) - new = self._element_exists_hook_(existing.element, element) + new = self._merge_hook_(existing.element, element) if new is None: self.remove(key) else: From b79f1bc2e2fb872e1a064e94ce6f7c61d75b4364 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 30 Jan 2015 09:08:54 +0100 Subject: [PATCH 0115/1872] introduce can_merge and rename merge_hook to merge --- src/sage/data_structures/mutable_poset.py | 37 ++++++++++++++--------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index c02a1b63425..7fd4aeb5c60 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1091,23 +1091,29 @@ class MutablePoset(sage.structure.sage_object.SageObject): (default), this is the identity, i.e., keys are equal to their elements. - - ``merge_hook`` -- a function. It is called during + - ``merge`` -- a function which merges its second argument (an + element) to its first (again an element) and returns the result + (as an element). If the return value is ``None``, the element is + removed out of the poset. + + This hook is called by :meth:`merge`. Moreover it is used during :meth:`add` when an element (more precisely its key) is already - in this poset. This function has the following properties: + in this poset. - - It gets as a first parameter the existing element mentioned above. + ``merge`` is ``None`` (default) is equivalent to ``merge`` + returns its first argument. Note that it is not allowed that the + key of the returning element differs from the key of the first + input parameter. - - As a second parameter it gets the element from :meth:`add`. + - ``can_merge`` -- a function which checks if its second argument + can be merged to its first. - - It should return the element which to put in the poset instead - of the existing one. If this return value is ``None``, the - existing element is removed out of the poset. + This hook is called by :meth:`merge`. Moreover it is used during + :meth:`add` when an element (more precisely its key) is already + in this poset. - If ``merge_hook`` is ``None`` (default) the - (existing element) is not changed, i.e., this is equivalent - to ``merge_hook`` returns the first parameter. Note - that it is not allowed that the key of this new element - differs from the key of existing. + ``can_merge`` is ``None`` (default) is equivalent to ``can_merge`` + returns ``True`` in all cases. OUTPUT: @@ -1169,7 +1175,7 @@ class MutablePoset(sage.structure.sage_object.SageObject): - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers_iterator`: Returns an iterator for the upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers`: Returns a list of upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. """ - def __init__(self, data=None, key=None, merge_hook=None): + def __init__(self, data=None, key=None, merge=None, can_merge=None): r""" See :class:`MutablePoset` for details. @@ -1211,7 +1217,8 @@ def __init__(self, data=None, key=None, merge_hook=None): else: self._key_ = key - self._merge_hook_ = merge_hook + self._merge_ = merge + self._can_merge_ = can_merge if data is not None: try: @@ -1407,6 +1414,8 @@ def _copy_shells_(self, other): """ from copy import copy self._key_ = copy(other._key_) + self._merge_ = copy(other._merge_) + self._can_merge_ = copy(other._can_merge_) memo = {} self._null_ = other._null_._copy_all_linked_(memo, self) self._oo_ = memo[id(other._oo_)] From 82ed0f3ef882ffbb590ef4e3e307ee43a10ab67f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 30 Jan 2015 09:11:27 +0100 Subject: [PATCH 0116/1872] a couple of minor rewritings to make the code and doctests nicer --- src/sage/data_structures/mutable_poset.py | 65 +++++++++++------------ 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 7fd4aeb5c60..13e79d700ad 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -791,8 +791,8 @@ def _iter_depth_first_visit_(self, marked, sage: list(P.oo._iter_depth_first_visit_(marked, True)) [oo, 42, 5, null] """ - if (condition is not None and - not self.is_special() and not condition(self)): + if condition is not None and \ + not self.is_special() and not condition(self): return if self in marked: return @@ -1349,7 +1349,7 @@ def element(self, key): sage: type(e) """ - return self._shells_[key].element + return self.shell(key).element def get_key(self, element): @@ -1691,24 +1691,21 @@ def keys_topological(self, **kwargs): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: class T(tuple): - ....: def __le__(left, right): - ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP(key=lambda c: c[0]) - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P.add((1, 1)) + sage: P.add((1, 3)) + sage: P.add((2, 1)) + sage: P.add((4, 4)) + sage: P.add((1, 2)) + sage: P.add((2, 2)) sage: [(v, type(v)) for v in P.keys_topological()] [(1, ), (2, ), (4, )] sage: [(v, type(v)) for v in P.elements_topological()] - [((1, 1), ), - ((2, 1), ), - ((4, 4), )] + [((1, 1), ), + ((2, 1), ), + ((4, 4), )] sage: [(v, type(v)) for v in P.shells_topological()] [((1, 1), ), ((2, 1), ), @@ -1906,9 +1903,9 @@ def add(self, element): is to be inserted in the poset. For example, we can perform an addition on some argument of the elements:: - sage: def add(existing, other): - ....: return (existing[0], existing[1] + other[1]) - sage: A = MP(key=lambda k: k[0], merge_hook=add) + sage: def add(left, right): + ....: return (left[0], ''.join(sorted(left[1] + right[1]))) + sage: A = MP(key=lambda k: k[0], merge=add) sage: A.add((3, 'a')) sage: A poset((3, 'a')) @@ -1920,13 +1917,13 @@ def add(self, element): our hook-function is ``None``, then the element is removed out of the poset:: - sage: def add_None(existing, other): - ....: s = existing[1] + other[1] + sage: def add_None(left, right): + ....: s = left[1] + right[1] ....: if s == 0: ....: return None - ....: return (existing[0], s) + ....: return (left[0], s) sage: B = MP(key=lambda k: k[0], - ....: merge_hook=add_None) + ....: merge=add_None) sage: B.add((7, 42)) sage: B.add((7, -42)) sage: B @@ -1935,12 +1932,12 @@ def add(self, element): TESTS:: sage: R = MP(key=lambda k: T(k[2:3])) - sage: R.add(T((1, 1, 42))) - sage: R.add(T((1, 3, 42))) - sage: R.add(T((2, 1, 7))) - sage: R.add(T((4, 4, 42))) - sage: R.add(T((1, 2, 7))) - sage: R.add(T((2, 2, 7))) + sage: R.add((1, 1, 42)) + sage: R.add((1, 3, 42)) + sage: R.add((2, 1, 7)) + sage: R.add((4, 4, 42)) + sage: R.add((1, 2, 7)) + sage: R.add((2, 2, 7)) sage: print R.repr_full(reverse=True) poset((1, 1, 42), (2, 1, 7)) +-- oo @@ -2072,12 +2069,12 @@ def remove(self, key, raise_key_error=True): TESTS:: sage: Q = MP(key=lambda k: T(k[0:2])) - sage: Q.add(T((1, 1, 42))) - sage: Q.add(T((1, 3, 42))) - sage: Q.add(T((2, 1, 7))) - sage: Q.add(T((4, 4, 42))) - sage: Q.add(T((1, 2, 7))) - sage: Q.add(T((2, 2, 7))) + sage: Q.add((1, 1, 42)) + sage: Q.add((1, 3, 42)) + sage: Q.add((2, 1, 7)) + sage: Q.add((4, 4, 42)) + sage: Q.add((1, 2, 7)) + sage: Q.add((2, 2, 7)) sage: print Q.repr_full(reverse=True) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7), (1, 1, 42)) From 13d4a36de647ed209e0bcd9e90a549befb4ea790 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 30 Jan 2015 09:11:48 +0100 Subject: [PATCH 0117/1872] write merge-methods --- src/sage/data_structures/mutable_poset.py | 151 +++++++++++++++++++++- 1 file changed, 144 insertions(+), 7 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 13e79d700ad..19f26f1ec29 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1025,6 +1025,59 @@ def iter_topological(self, reverse=False, key=None, condition=None): return self._iter_topological_visit_(marked, reverse, key, condition) + def merge(self, element, check=True, delete=True): + r""" + Merge the given element with itself. + + INPUT: + + - ``element`` -- an element (of the poset). + + - ``check`` -- (default: ``True``) if set, then the + ``can_merge``-function of :class:`MutablePoset` is asked + before the merge if the merge is possible. + + - ``delete`` -- (default: ``True``) if set, then given element + is removed out of the poset after the merge. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: def add(left, right): + ....: return (left[0], ''.join(sorted(left[1] + right[1]))) + sage: def can_add(left, right): + ....: return left[0] <= right[0] + sage: P = MP(key=lambda c: c[0], merge=add, can_merge=can_add) + sage: P.add((1, 'a')) + sage: P.add((3, 'b')) + sage: P.add((2, 'c')) + sage: P.add((4, 'd')) + sage: P + poset((1, 'a'), (2, 'c'), (3, 'b'), (4, 'd')) + sage: P.shell(2).merge((3, 'b')) + sage: P + poset((1, 'a'), (2, 'bc'), (4, 'd')) + """ + poset = self.poset + if poset._merge_ is None: + return + self_element = self.element + if check and poset._can_merge_ is not None and \ + not poset._can_merge_(self_element, element): + return + new = poset._merge_(self_element, element) + if new is None: + poset.discard(poset.get_key(self.element)) + else: + self._element_ = new + if delete: + poset.remove(poset.get_key(element)) + + # ***************************************************************************** @@ -1958,13 +2011,8 @@ def add(self, element): key = self.get_key(element) if key in self._shells_: - if self._merge_hook_ is not None: - existing = self.shell(key) - new = self._merge_hook_(existing.element, element) - if new is None: - self.remove(key) - else: - existing._element_ = new + if self._merge_ is not None: + self.shell(key).merge(element, delete=False) return new = MutablePosetShell(self, element) @@ -2655,6 +2703,95 @@ def is_superset(self, other): """ + def merge(self, key): + r""" + Merge the given element with its successors/predecessors. + + INPUT: + + ``key`` -- the key specifying an element. + + OUTPUT: + + Nothing. + + This method tests all (not necessarily direct) successors and + predecessors of the given element if they can be merged with + the element itself. This is done by the ``can_merge``-function + of :class:`MutablePoset`. If this merge is possible, then it + is performed by calling :class:`MutablePoset`'s + ``merge``-function and the corresponding successor/predecessor + is removed from the poset. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: key = lambda t: T(t[0:2]) + sage: def add(left, right): + ....: return (left[0], left[1], + ....: ''.join(sorted(left[2] + right[2]))) + sage: def can_add(left, right): + ....: return key(left) >= key(right) + sage: P = MP(key=key, merge=add, can_merge=can_add) + sage: P.add((1, 1, 'a')) + sage: P.add((1, 3, 'b')) + sage: P.add((2, 1, 'c')) + sage: P.add((4, 4, 'd')) + sage: P.add((1, 2, 'e')) + sage: P.add((2, 2, 'f')) + sage: Q = copy(P) + sage: Q.merge(T((1, 3))) + sage: print Q.repr_full(reverse=True) + poset((4, 4, 'd'), (1, 3, 'abe'), (2, 2, 'f'), (2, 1, 'c')) + +-- oo + | +-- no successors + | +-- predecessors: (4, 4, 'd') + +-- (4, 4, 'd') + | +-- successors: oo + | +-- predecessors: (1, 3, 'abe'), (2, 2, 'f') + +-- (1, 3, 'abe') + | +-- successors: (4, 4, 'd') + | +-- predecessors: null + +-- (2, 2, 'f') + | +-- successors: (4, 4, 'd') + | +-- predecessors: (2, 1, 'c') + +-- (2, 1, 'c') + | +-- successors: (2, 2, 'f') + | +-- predecessors: null + +-- null + | +-- successors: (1, 3, 'abe'), (2, 1, 'c') + | +-- no predecessors + sage: for k in P.keys(): + ....: Q = copy(P) + ....: Q.merge(k) + ....: print 'merging %s: %s' % (k, Q) + merging (1, 2): poset((1, 2, 'ae'), (1, 3, 'b'), + (2, 1, 'c'), (2, 2, 'f'), (4, 4, 'd')) + merging (1, 3): poset((1, 3, 'abe'), (2, 1, 'c'), + (2, 2, 'f'), (4, 4, 'd')) + merging (4, 4): poset((4, 4, 'abcdef')) + merging (2, 1): poset((1, 2, 'e'), (1, 3, 'b'), + (2, 1, 'ac'), (2, 2, 'f'), (4, 4, 'd')) + merging (2, 2): poset((1, 3, 'b'), (2, 2, 'acef'), (4, 4, 'd')) + merging (1, 1): poset((1, 1, 'a'), (1, 2, 'e'), (1, 3, 'b'), + (2, 1, 'c'), (2, 2, 'f'), (4, 4, 'd')) + """ + shell = self.shell(key) + def can_merge(other): + return self._can_merge_(shell.element, other.element) + for reverse in (False, True): + to_merge = shell.iter_depth_first( + reverse=reverse, condition=can_merge) + next(to_merge) + for m in tuple(to_merge): + if m.is_special(): + continue + shell.merge(m.element, delete=True) + + # ***************************************************************************** From e6a35343e5f712b88a5a9a80abd4e9302879c187 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Sun, 1 Feb 2015 17:26:01 +0100 Subject: [PATCH 0118/1872] 17447: reviewer's patch: fix rst doctests --- src/doc/en/constructions/calculus.rst | 4 ++-- src/doc/en/prep/Quickstarts/Differential-Equations.rst | 6 +++--- src/doc/en/tutorial/tour_algebra.rst | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/en/constructions/calculus.rst b/src/doc/en/constructions/calculus.rst index 5798dd67f01..97f7ea3f3b8 100644 --- a/src/doc/en/constructions/calculus.rst +++ b/src/doc/en/constructions/calculus.rst @@ -280,7 +280,7 @@ An example, how to solve ODE's symbolically in Sage using the Maxima interface :: - sage: y=function('y',x); desolve(diff(y,x,2) + 3*x == y, dvar = y, ics = [1,1,1]) + sage: y=function('y')(x); desolve(diff(y,x,2) + 3*x == y, dvar = y, ics = [1,1,1]) 3*x - 2*e^(x - 1) sage: desolve(diff(y,x,2) + 3*x == y, dvar = y) _K2*e^(-x) + _K1*e^x + 3*x @@ -289,7 +289,7 @@ An example, how to solve ODE's symbolically in Sage using the Maxima interface sage: desolve(diff(y,x) + 3*x == y, dvar = y, ics = [1,1]).expand() 3*x - 5*e^(x - 1) + 3 - sage: f=function('f',x); desolve_laplace(diff(f,x,2) == 2*diff(f,x)-f, dvar = f, ics = [0,1,2]) + sage: f=function('f')(x); desolve_laplace(diff(f,x,2) == 2*diff(f,x)-f, dvar = f, ics = [0,1,2]) x*e^x + e^x sage: desolve_laplace(diff(f,x,2) == 2*diff(f,x)-f, dvar = f) diff --git a/src/doc/en/prep/Quickstarts/Differential-Equations.rst b/src/doc/en/prep/Quickstarts/Differential-Equations.rst index a61aa4560c8..539b21344fa 100644 --- a/src/doc/en/prep/Quickstarts/Differential-Equations.rst +++ b/src/doc/en/prep/Quickstarts/Differential-Equations.rst @@ -21,7 +21,7 @@ Basic Symbolic Techniques :: - sage: y = function('y',x) + sage: y = function('y')(x) sage: de = diff(y,x) + y -2 sage: h = desolve(de, y) @@ -102,7 +102,7 @@ gives the last list in the example. :: - sage: f=function('f',x) + sage: f=function('f')(x) sage: desolve_laplace(diff(f,x,2) == 2*diff(f,x)-f, dvar = f, ics = [0,1,2]) x*e^x + e^x @@ -124,7 +124,7 @@ conditions. :: - sage: y = function('y',x) + sage: y = function('y')(x) sage: de = diff(y,x) + y -2 sage: h = desolve_rk4(de, y, step=.05, ics=[0,3]) diff --git a/src/doc/en/tutorial/tour_algebra.rst b/src/doc/en/tutorial/tour_algebra.rst index 1fc1f347617..eff637b19dd 100644 --- a/src/doc/en/tutorial/tour_algebra.rst +++ b/src/doc/en/tutorial/tour_algebra.rst @@ -164,7 +164,7 @@ solve the equation :math:`x'+x-1=0`: :: sage: t = var('t') # define a variable t - sage: x = function('x',t) # define x to be a function of that variable + sage: x = function('x')(t) # define x to be a function of that variable sage: DE = diff(x, t) + x - 1 sage: desolve(DE, [x,t]) (_C + e^t)*e^(-t) From 4585e74063e81a8c332a500d016e837069edf8eb Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Mon, 2 Feb 2015 09:12:50 +0100 Subject: [PATCH 0119/1872] 17447: fix rest of doctests --- src/doc/de/tutorial/tour_algebra.rst | 2 +- src/doc/fr/tutorial/tour_algebra.rst | 2 +- src/doc/ru/tutorial/tour_algebra.rst | 2 +- src/sage/combinat/tutorial.py | 4 +-- src/sage/functions/bessel.py | 4 +-- src/sage/functions/other.py | 6 ++-- src/sage/interfaces/maxima_lib.py | 4 +-- .../tests/french_book/calculus_doctest.py | 6 ++-- .../tests/french_book/nonlinear_doctest.py | 4 +-- src/sage/tests/french_book/recequadiff.py | 32 +++++++++---------- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/doc/de/tutorial/tour_algebra.rst b/src/doc/de/tutorial/tour_algebra.rst index 64df55a4df8..d3a67b56912 100644 --- a/src/doc/de/tutorial/tour_algebra.rst +++ b/src/doc/de/tutorial/tour_algebra.rst @@ -153,7 +153,7 @@ berechnen. Die Gleichung :math:`x'+x-1=0` berechnen Sie wie folgt: :: sage: t = var('t') # definiere die Variable t - sage: x = function('x',t) # definiere x als Funktion dieser Variablen + sage: x = function('x')(t) # definiere x als Funktion dieser Variablen sage: DE = diff(x, t) + x - 1 sage: desolve(DE, [x,t]) (_C + e^t)*e^(-t) diff --git a/src/doc/fr/tutorial/tour_algebra.rst b/src/doc/fr/tutorial/tour_algebra.rst index d0ba28e5d2a..cccdfa2ed1d 100644 --- a/src/doc/fr/tutorial/tour_algebra.rst +++ b/src/doc/fr/tutorial/tour_algebra.rst @@ -129,7 +129,7 @@ ordinaires. Pour résoudre l'équation :math:`x'+x-1=0` : :: sage: t = var('t') # on définit une variable t - sage: function('x',t) # on déclare x fonction de cette variable + sage: function('x')(t) # on déclare x fonction de cette variable x(t) sage: DE = lambda y: diff(y,t) + y - 1 sage: desolve(DE(x(t)), [x(t),t]) diff --git a/src/doc/ru/tutorial/tour_algebra.rst b/src/doc/ru/tutorial/tour_algebra.rst index 73a0bff7a8a..05dd15c7695 100644 --- a/src/doc/ru/tutorial/tour_algebra.rst +++ b/src/doc/ru/tutorial/tour_algebra.rst @@ -147,7 +147,7 @@ Sage может использоваться для решения диффер :: sage: t = var('t') # определение переменной t для символьных вычислений - sage: x = function('x',t) # определение функции x зависящей от t + sage: x = function('x')(t) # определение функции x зависящей от t sage: DE = diff(x, t) + x - 1 sage: desolve(DE, [x,t]) (_C + e^t)*e^(-t) diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index b38a543e527..2af6ec4fa67 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -433,8 +433,8 @@ equation with respect to `z`:: sage: x, y, z = var('x, y, z') - sage: P = function('P', x, y) - sage: C = function('C', z) + sage: P = function('P')(x, y) + sage: C = function('C')(z) sage: equation = P(x=z, y=C) == 0 sage: diff(equation, z) D[0](C)(z)*D[1](P)(z, C(z)) + D[0](P)(z, C(z)) == 0 diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index e0472302827..fea750df7a9 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -132,7 +132,7 @@ Symbolically solve a second order differential equation with initial conditions `y(1) = a` and `y'(1) = b` in terms of Bessel functions:: - sage: y = function('y', x) + sage: y = function('y')(x) sage: a, b = var('a, b') sage: diffeq = x^2*diff(y,x,x) + x*diff(y,x) + x^2*y == 0 sage: f = desolve(diffeq, y, [1, a, b]); f @@ -958,7 +958,7 @@ def Bessel(*args, **kwds): satisfies `y(1) = 1` and `y'(1) = 1`, then verify the initial conditions and plot it:: - sage: y = function('y', x) + sage: y = function('y')(x) sage: diffeq = x^2*diff(y,x,x) + x*diff(y,x) + x^2*y == 0 sage: f = desolve(diffeq, y, [1, 1, 1]); f (bessel_Y(1, 1) + bessel_Y(0, 1))*bessel_J(0, x)/(bessel_J(0, diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index bc6d7925aa6..688cf1aa24a 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -2016,7 +2016,7 @@ def __init__(self): sage: latex(x.real()) \Re \left( x \right) - sage: f(x) = function('f',x) + sage: f(x) = function('f')(x) sage: latex( f(x).real()) \Re \left( f\left(x\right) \right) """ @@ -2086,7 +2086,7 @@ def __init__(self): sage: latex(x.imag()) \Im \left( x \right) - sage: f(x) = function('f',x) + sage: f(x) = function('f')(x) sage: latex( f(x).imag()) \Im \left( f\left(x\right) \right) """ @@ -2151,7 +2151,7 @@ def __init__(self): sage: f = function('f') sage: latex(f(x).conjugate()) \overline{f\left(x\right)} - sage: f = function('psi',x,y) + sage: f = function('psi')(x,y) sage: latex(f.conjugate()) \overline{\psi\left(x, y\right)} sage: x.conjugate().conjugate() diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index c909c14f72a..2577bf2c14e 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -1535,7 +1535,7 @@ def sr_to_max(expr): sage: sr_to_max(cos(x)) - sage: f = function('f',x) + sage: f = function('f')(x) sage: sr_to_max(f.diff()) @@ -1644,7 +1644,7 @@ def max_to_sr(expr): TESTS:: sage: from sage.interfaces.maxima_lib import sr_to_max, max_to_sr - sage: f = function('f',x).diff() + sage: f = function('f')(x).diff() sage: bool(max_to_sr(sr_to_max(f)) == f) True """ diff --git a/src/sage/tests/french_book/calculus_doctest.py b/src/sage/tests/french_book/calculus_doctest.py index ed5186d5acd..70278bbefa3 100644 --- a/src/sage/tests/french_book/calculus_doctest.py +++ b/src/sage/tests/french_book/calculus_doctest.py @@ -46,7 +46,7 @@ Sage example in ./calculus.tex, line 122:: sage: y = var('y'); u = sin(x) + x*cos(y) - sage: v = u.function(x, y); v + sage: v = u.function(x)(y); v (x, y) |--> x*cos(y) + sin(x) sage: w(x, y) = u; w (x, y) |--> x*cos(y) + sin(x) @@ -252,7 +252,7 @@ Sage example in ./calculus.tex, line 706:: - sage: y = function('y', x) + sage: y = function('y')(x) sage: desolve(diff(y,x,x) + x*diff(y,x) + y == 0, y, [0,0,1]) -1/2*I*sqrt(2)*sqrt(pi)*erf(1/2*I*sqrt(2)*x)*e^(-1/2*x^2) @@ -406,7 +406,7 @@ sage: diff(sin(x^2), x) 2*x*cos(x^2) - sage: function('f', x); function('g', x); diff(f(g(x)), x) + sage: function('f')(x); function('g')(x); diff(f(g(x)), x) f(x) g(x) D[0](f)(g(x))*D[0](g)(x) diff --git a/src/sage/tests/french_book/nonlinear_doctest.py b/src/sage/tests/french_book/nonlinear_doctest.py index d61bba5cf20..296f6d83a48 100644 --- a/src/sage/tests/french_book/nonlinear_doctest.py +++ b/src/sage/tests/french_book/nonlinear_doctest.py @@ -118,8 +118,8 @@ Sage example in ./nonlinear.tex, line 424:: sage: alpha, m, x = var('alpha, m, x') - sage: p = function('p', x) - sage: q = function('q', x) + sage: p = function('p')(x) + sage: q = function('q')(x) sage: p = (x - alpha)^m * q sage: p.derivative(x) (-alpha + x)^(m - 1)*m*q(x) + (-alpha + x)^m*D[0](q)(x) diff --git a/src/sage/tests/french_book/recequadiff.py b/src/sage/tests/french_book/recequadiff.py index 6deec70d9e8..b888756d8d7 100755 --- a/src/sage/tests/french_book/recequadiff.py +++ b/src/sage/tests/french_book/recequadiff.py @@ -11,11 +11,11 @@ Sage example in ./recequadiff.tex, line 110:: sage: x = var('x') - sage: y = function('y', x) + sage: y = function('y')(x) Sage example in ./recequadiff.tex, line 179:: - sage: x = var('x'); y = function('y', x) + sage: x = var('x'); y = function('y')(x) Sage example in ./recequadiff.tex, line 182:: @@ -62,7 +62,7 @@ Sage example in ./recequadiff.tex, line 293:: - sage: x = var('x'); y = function('y', x) + sage: x = var('x'); y = function('y')(x) Sage example in ./recequadiff.tex, line 297:: @@ -88,7 +88,7 @@ Sage example in ./recequadiff.tex, line 338:: - sage: x = var('x'); y = function('y', x) + sage: x = var('x'); y = function('y')(x) sage: desolve(diff(y,x)*log(y) == y*sin(x), y, show_method=True) [1/2*log(y(x))^2 == _C - cos(x), 'separable'] @@ -145,7 +145,7 @@ Sage example in ./recequadiff.tex, line 472:: - sage: u = function('u',x) + sage: u = function('u')(x) sage: y = x*u sage: DE = x*diff(y,x) == y + sqrt(x**2 + y**2) @@ -186,7 +186,7 @@ Sage example in ./recequadiff.tex, line 567:: - sage: x = var('x'); y = function('y', x); a, b = var('a, b') + sage: x = var('x'); y = function('y')(x); a, b = var('a, b') sage: DE = diff(y,x) - a*y == -b*y**2 sage: sol(x) = desolve(DE,[y,x]); sol(x) -(log(b*y(x) - a) - log(y(x)))/a == _C + x @@ -207,7 +207,7 @@ Sage example in ./recequadiff.tex, line 602:: - sage: x = var('x'); y = function('y', x) + sage: x = var('x'); y = function('y')(x) sage: DE = diff(y,x,2)+3*y == x^2-7*x+31 sage: desolve(DE, y).expand() 1/3*x^2 + _K2*cos(sqrt(3)*x) + _K1*sin(sqrt(3)*x) - 7/3*x + 91/9 @@ -226,7 +226,7 @@ Sage example in ./recequadiff.tex, line 674:: - sage: x, t = var('x, t'); f = function('f',x); g = function('g',t) + sage: x, t = var('x, t'); f = function('f')(x); g = function('g')(t) sage: z = f*g sage: eq(x,t) = diff(z,x,2) == diff(z,t); eq(x,t) g(t)*D[0, 0](f)(x) == f(x)*D[0](g)(t) @@ -261,7 +261,7 @@ Sage example in ./recequadiff.tex, line 782:: - sage: x, s = var('x, s'); f = function('f',x) + sage: x, s = var('x, s'); f = function('f')(x) sage: f(x) = sin(x); f.laplace(x,s) x |--> 1/(s^2 + 1) @@ -278,7 +278,7 @@ Sage example in ./recequadiff.tex, line 818:: - sage: x = var('x'); y = function('y',x) + sage: x = var('x'); y = function('y')(x) sage: eq = diff(y,x,x) - 3*diff(y,x) - 4*y - sin(x) == 0 sage: desolve_laplace(eq, y) 1/85*(17*y(0) + 17*D[0](y)(0) + 1)*e^(4*x) + 1/10*(8*y(0) @@ -288,8 +288,8 @@ Sage example in ./recequadiff.tex, line 869:: - sage: x = var('x'); y1 = function('y1', x) - sage: y2 = function('y2', x); y3 = function('y3', x) + sage: x = var('x'); y1 = function('y1')(x) + sage: y2 = function('y2')(x); y3 = function('y3')(x) sage: y = vector([y1, y2, y3]) sage: A = matrix([[2,-2,0],[-2,0,2],[0,2,2]]) sage: system = [diff(y[i], x) - (A * y)[i] for i in range(3)] @@ -300,7 +300,7 @@ Sage example in ./recequadiff.tex, line 913:: - sage: x = var('x'); y1 = function('y1', x); y2 = function('y2', x) + sage: x = var('x'); y1 = function('y1')(x); y2 = function('y2')(x) sage: y = vector([y1,y2]) sage: A = matrix([[3,-4],[1,3]]) sage: system = [diff(y[i], x) - (A * y)[i] for i in range(2)] @@ -309,8 +309,8 @@ Sage example in ./recequadiff.tex, line 966:: - sage: x = var('x'); u1 = function('u1', x); u2 = function('u2', x) - sage: u3 = function('u3', x); u4 = function('u4', x) + sage: x = var('x'); u1 = function('u1')(x); u2 = function('u2')(x) + sage: u3 = function('u3')(x); u4 = function('u4')(x) sage: u = vector([u1,u2,u3,u4]) sage: A = matrix([[0,0,1,0],[0,0,0,1],[2,-6,1,3],[-2,6,1,-1]]) sage: system = [diff(u[i], x) - (A*u)[i] for i in range(4)] @@ -330,7 +330,7 @@ Sage example in ./recequadiff.tex, line 1095:: - sage: x = var('x'); f = function('f',x) + sage: x = var('x'); f = function('f')(x) sage: f(x) = 3.83*x*(1 - x/100000) sage: def u(n): ... if n==0: return(20000) From 1dddd2087f0a69a5f0ca874dad5d738316b6293d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 19 Feb 2015 09:09:33 -0800 Subject: [PATCH 0120/1872] Initial creation of the files. --- .../combinat/root_system/coxeter_matrix.py | 178 +++++++++++- src/sage/combinat/root_system/coxeter_type.py | 256 ++++++++++++++++++ 2 files changed, 432 insertions(+), 2 deletions(-) create mode 100644 src/sage/combinat/root_system/coxeter_type.py diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 499f861f5a8..ae3bb9ba59e 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -3,6 +3,7 @@ """ #***************************************************************************** # Copyright (C) 2007 Mike Hansen , +# 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # @@ -15,10 +16,181 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** -from cartan_type import CartanType +from coxeter_type import CartanType from sage.matrix.all import MatrixSpace from sage.rings.all import ZZ +from sage.misc.cachefunc import cached_method +from sage.matrix.constructor import matrix +from sage.matrix.matrix import is_Matrix +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall +from sage.matrix.matrix_integer_dense import Matrix_integer_dense +from sage.rings.all import ZZ +from sage.combinat.root_system.coxeter_type import CoxeterType, CoxeterType_abstract +from sage.combinat.root_system.root_system import RootSystem +from sage.sets.family import Family + +class CoxeterMatrix(Matrix_integer_dense, CoxeterType_abstract): + """ + A Coxeter matrix. + """ + def __init__(self, parent, data, coxeter_type, index_set): + """ + Initialize ``self``. + + TESTS:: + + sage: C = CoxeterMatrix(['A',1,1]) + sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) + """ + Matrix_integer_sparse.__init__(self, parent, data, False, False) + self._coxeter_type = coxeter_type + self._index_set = index_set + self.set_immutable() + + ########################################################################## + # Coxeter type methods + + def index_set(self): + """ + Return the index set of ``self``. + + EXAMPLES:: + + sage: C = CoxeterMatrix(['A',1,1]) + sage: C.index_set() + (0, 1) + sage: C = CoxeterMatrix(['E',6]) + sage: C.index_set() + (1, 2, 3, 4, 5, 6) + """ + return self._index_set + + def coxeter_type(self): + """ + Return the Cartan type of ``self`` or ``self`` if unknown. + + EXAMPLES:: + + sage: C = CoxeterMatrix(['A',4,1]) + sage: C.coxeter_type() + ['A', 4, 1] + + If the Cartan type is unknown:: + + sage: C = CoxeterMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]]) + sage: C.coxeter_type() + [ 2 -1 -2] + [-1 2 -1] + [-2 -1 2] + """ + if self._coxeter_type is None: + return self + return self._coxeter_type + + def rank(self): + r""" + Return the rank of ``self``. + + EXAMPLES:: + + sage: CoxeterMatrix(['C',3]).rank() + 3 + sage: CoxeterMatrix(["A2","B2","F4"]).rank() + 8 + """ + return self.ncols() + + def coxeter_matrix(self): + r""" + Return the Coxeter matrix of ``self``. + + EXAMPLES:: + + sage: CoxeterMatrix(['C',3]).coxeter_matrix() + [ 2 -1 0] + [-1 2 -2] + [ 0 -1 2] + """ + return self + + def is_simply_laced(self): + """ + Return if ``self`` is simply-laced. + + A Coxeter matrix is simply-laced if all non-diagonal entries are + either 2 or 3. + + EXAMPLES:: + + sage: cm = CoxeterMatrix([[2, -1, -1, -1], [-1, 2, -1, -1], [-1, -1, 2, -1], [-1, -1, -1, 2]]) + sage: cm.is_simply_laced() + True + """ + # We include 1 in this list to account for the diagonal + L = [1,2,3] + return all(x in L for row in self for x in row) + + def is_crystallographic(self): + """ + Return if ``self`` is crystallographic. + + A Coxeter matrix is crystallographic if all non-diagonal entries + are either 2, 4, or 6. + + EXAMPLES:: + + sage: CoxeterMatrix(['F',4]).is_crystallographic() + True + """ + # We include 1 in this list to account for the diagonal + L = [1,2,3,4,6] + return all(x in L for row in self for x in row) + + def is_finite(self): + """ + Return if ``self`` is a finite type or ``False`` if unknown. + + EXAMPLES:: + + sage: M = CoxeterMatrix(['C',4]) + sage: M.is_finite() + True + sage: M = CoxeterMatrix(['D',4,1]) + sage: M.is_finite() + False + sage: M = CoxeterMatrix([[2, -4], [-3, 2]]) + sage: M.is_finite() + False + """ + if self._coxeter_type is not None: + return self._coxeter_type.is_finite() + return self.bilinear_form().is_positive_semidefinite() + + def is_affine(self): + """ + Return if ``self`` is an affine type or ``False`` if unknown. + + EXAMPLES:: + + sage: M = CoxeterMatrix(['C',4]) + sage: M.is_affine() + False + sage: M = CoxeterMatrix(['D',4,1]) + sage: M.is_affine() + True + sage: M = CoxeterMatrix([[2, -4], [-3, 2]]) + sage: M.is_affine() + False + """ + if self._coxeter_type is not None: + return self._coxeter_type.is_affine() + return self.bilinear_form().is_positive_semidefinite() + +##################################################################### +## Other methods + def coxeter_matrix_as_function(t): """ Returns the Coxeter matrix, as a function @@ -94,4 +266,6 @@ def coxeter_matrix(t): [1 6] [6 1] """ - return CartanType(t).coxeter_matrix() + # TODO: Deprecate this in favor of CoxeterMatrix + return CoxeterMatrix(t) + diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py new file mode 100644 index 00000000000..6904d0c1602 --- /dev/null +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -0,0 +1,256 @@ +""" +Coxeter Types +""" +#***************************************************************************** +# Copyright (C) 2015 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 cartan_type import CartanType +from sage.matrix.all import MatrixSpace +from sage.rings.all import ZZ + +class CoxeterType_abstract(object): + """ + Abstract class for Coxeter types. + """ + @abstract_method + def rank(self): + """ + Return the rank of ``self``. + + This is the number of nodes of the associated Coxeter diagram. + + EXAMPLES:: + + sage: CartanType(['A', 4]).rank() + 4 + sage: CartanType(['A', 7, 2]).rank() + 5 + sage: CartanType(['I', 8]).rank() + 2 + """ + + @abstract_method + def index_set(self): + """ + Return the index set for ``self``. + + This is the list of the nodes of the associated Coxeter diagram. + + EXAMPLES:: + + sage: CartanType(['A', 3, 1]).index_set() + (0, 1, 2, 3) + sage: CartanType(['D', 4]).index_set() + (1, 2, 3, 4) + sage: CartanType(['A', 7, 2]).index_set() + (0, 1, 2, 3, 4) + sage: CartanType(['A', 7, 2]).index_set() + (0, 1, 2, 3, 4) + sage: CartanType(['A', 6, 2]).index_set() + (0, 1, 2, 3) + sage: CartanType(['D', 6, 2]).index_set() + (0, 1, 2, 3, 4, 5) + sage: CartanType(['E', 6, 1]).index_set() + (0, 1, 2, 3, 4, 5, 6) + sage: CartanType(['E', 6, 2]).index_set() + (0, 1, 2, 3, 4) + sage: CartanType(['A', 2, 2]).index_set() + (0, 1) + sage: CartanType(['G', 2, 1]).index_set() + (0, 1, 2) + sage: CartanType(['F', 4, 1]).index_set() + (0, 1, 2, 3, 4) + """ + + @abstract_method + def coxeter_matrix(self): + """ + Return the Coxeter matrix associated to ``self``. + + EXAMPLES:: + + sage: CartanType(['A', 3]).is_affine() + False + sage: CartanType(['A', 3, 1]).is_affine() + True + """ + + @abstract_method + def coxeter_diagram(self): + """ + Return the Coxeter diagram associated to ``self``. + + EXAMPLES:: + + sage: CartanType(['A', 3]).is_affine() + False + sage: CartanType(['A', 3, 1]).is_affine() + True + """ + + @abstract_method + def is_finite(self): + """ + Return whether ``self`` is finite. + + EXAMPLES:: + + sage: from sage.combinat.root_system.cartan_type import CartanType_abstract + sage: C = CartanType_abstract() + sage: C.is_finite() + Traceback (most recent call last): + ... + NotImplementedError: + + :: + + sage: CartanType(['A',4]).is_finite() + True + sage: CartanType(['A',4, 1]).is_finite() + False + """ + + @abstract_method + def is_affine(self): + """ + Return whether ``self`` is affine. + + EXAMPLES:: + + sage: CartanType(['A', 3]).is_affine() + False + sage: CartanType(['A', 3, 1]).is_affine() + True + """ + + def is_crystallographic(self): + """ + Return whether ``self`` is crystallographic. + + This returns ``False`` by default. Derived class should override this + appropriately. + + EXAMPLES:: + + sage: [ [t, t.is_crystallographic() ] for t in CartanType.samples(finite=True) ] + [[['A', 1], True], [['A', 5], True], + [['B', 1], True], [['B', 5], True], + [['C', 1], True], [['C', 5], True], + [['D', 2], True], [['D', 3], True], [['D', 5], True], + [['E', 6], True], [['E', 7], True], [['E', 8], True], + [['F', 4], True], [['G', 2], True], + [['I', 5], False], [['H', 3], False], [['H', 4], False]] + """ + return False + + def is_simply_laced(self): + """ + Return whether ``self`` is simply laced. + + This returns ``False`` by default. Derived class should override this + appropriately. + + EXAMPLES:: + + sage: [ [t, t.is_simply_laced() ] for t in CartanType.samples() ] + [[['A', 1], True], [['A', 5], True], + [['B', 1], True], [['B', 5], False], + [['C', 1], True], [['C', 5], False], + [['D', 2], True], [['D', 3], True], [['D', 5], True], + [['E', 6], True], [['E', 7], True], [['E', 8], True], + [['F', 4], False], [['G', 2], False], [['I', 5], False], [['H', 3], False], [['H', 4], False], + [['A', 1, 1], False], [['A', 5, 1], True], + [['B', 1, 1], False], [['B', 5, 1], False], + [['C', 1, 1], False], [['C', 5, 1], False], + [['D', 3, 1], True], [['D', 5, 1], True], + [['E', 6, 1], True], [['E', 7, 1], True], [['E', 8, 1], True], + [['F', 4, 1], False], [['G', 2, 1], False], + [['BC', 1, 2], False], [['BC', 5, 2], False], + [['B', 5, 1]^*, False], [['C', 4, 1]^*, False], [['F', 4, 1]^*, False], [['G', 2, 1]^*, False], + [['BC', 1, 2]^*, False], [['BC', 5, 2]^*, False]] + """ + return False + +class CoxeterTypeFromCartanType(CoxeterType_abstract): + """ + A Coxeter type associated to a Cartan type. + """ + def __init__(self, cartan_type): + """ + Initialize ``self``. + """ + self._cartan_type = cartan_type + + def _repr_(self): + """ + Return a string representation of ``self``. + """ + return "Coxeter type of {}".format(self._cartan_type) + + def coxeter_matrix(self): + """ + Return the Coxeter matrix associated to ``self``. + + EXAMPLES:: + """ + return self._cartan_type.coxeter_matrix() + + def coxeter_diagram(self): + """ + Return the Coxeter digramh of ``self``. + """ + return self._cartan_type.coxeter_diagram() + + def cartan_type(self): + """ + Return the Cartan type used to construct ``self``. + """ + return self._cartan_type + + def rank(self): + """ + Return the rank of ``self``. + """ + return self._cartan_type.rank() + + def index_set(self): + """ + Return the index set of ``self``. + """ + return self._cartan_type.index_set() + + def is_finite(self): + """ + Return if ``self`` is a finite type. + """ + return self._cartan_type.is_finite() + + def is_affine(self): + """ + Return if ``self`` is an affine type. + """ + return self._cartan_type.is_affine() + + def is_crystallographic(self): + """ + Return if ``self`` is crystallographic. + """ + return self._cartan_type.is_crystallographic() + + def is_simply_laced(self): + """ + Return if ``self`` is simply-laced. + """ + return self._cartan_type.is_simply_laced() + From 5484c5d6077138d6ed79d5d19af38c1f1da120ea Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Feb 2015 18:47:12 -0800 Subject: [PATCH 0121/1872] Making all doctests pass and removing some deprecated code. --- src/sage/combinat/root_system/all.py | 5 +- .../combinat/root_system/cartan_matrix.py | 26 +- src/sage/combinat/root_system/cartan_type.py | 51 +- .../combinat/root_system/coxeter_matrix.py | 547 +++++++++++++++--- src/sage/combinat/root_system/coxeter_type.py | 241 ++++++-- .../combinat/root_system/dynkin_diagram.py | 7 +- src/sage/combinat/root_system/type_I.py | 7 +- src/sage/groups/matrix_gps/coxeter_group.py | 270 +-------- 8 files changed, 734 insertions(+), 420 deletions(-) diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py index 69271d70073..1c2a6207160 100644 --- a/src/sage/combinat/root_system/all.py +++ b/src/sage/combinat/root_system/all.py @@ -6,8 +6,9 @@ from cartan_type import CartanType from dynkin_diagram import DynkinDiagram -from cartan_matrix import CartanMatrix, cartan_matrix -from coxeter_matrix import coxeter_matrix +from cartan_matrix import CartanMatrix +from coxeter_matrix import CoxeterMatrix, coxeter_matrix +from coxeter_type import CoxeterType from root_system import RootSystem, WeylDim from weyl_group import WeylGroup, WeylGroupElement from coxeter_group import CoxeterGroup diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index fa9ed6f38ea..7e15bddd66c 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -197,7 +197,7 @@ class CartanMatrix(Matrix_integer_sparse, CartanType_abstract): @staticmethod def __classcall_private__(cls, *args, **kwds): """ - Normalize input so we can inherit from spare integer matrix. + Normalize input so we can inherit from sparse integer matrix. .. NOTE:: @@ -761,27 +761,3 @@ def find_cartan_type_from_matrix(CM): return ct return None -def cartan_matrix(t): - """ - Return the Cartan matrix of type `t`. - - .. NOTE:: - - This function is deprecated in favor of - ``CartanMatrix(...)``, to avoid polluting the - global namespace. - - EXAMPLES:: - - sage: cartan_matrix(['A', 4]) - doctest:...: DeprecationWarning: cartan_matrix() is deprecated. Use CartanMatrix() instead - See http://trac.sagemath.org/14137 for details. - [ 2 -1 0 0] - [-1 2 -1 0] - [ 0 -1 2 -1] - [ 0 0 -1 2] - """ - from sage.misc.superseded import deprecation - deprecation(14137, 'cartan_matrix() is deprecated. Use CartanMatrix() instead') - return CartanMatrix(t) - diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index f26a6387344..9dabd120ebf 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -279,9 +279,9 @@ .. rubric:: Affine Cartan types -For affine types, we use the usual conventions for affine Coxeter groups: each affine type -is either untwisted (that is arise from the natural affinisation -of a finite Cartan type):: +For affine types, we use the usual conventions for affine Coxeter +groups: each affine type is either untwisted (that is arise from the +natural affinisation of a finite Cartan type):: sage: CartanType(["A", 4, 1]).dynkin_diagram() 0 @@ -451,7 +451,6 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.global_options import GlobalOptions from sage.sets.family import Family -from sage.misc.superseded import deprecated_function_alias from sage.misc.decorators import rename_keyword # TODO: @@ -1070,7 +1069,6 @@ def coxeter_diagram(self): [(1, 2, 3), (2, 3, 4), (3, 4, 3)] """ - @cached_method def coxeter_matrix(self): """ Return the Coxeter matrix for ``self``. @@ -1083,16 +1081,19 @@ def coxeter_matrix(self): [2 3 1 3] [2 2 3 1] """ - from sage.matrix.constructor import matrix - from sage.rings.all import ZZ - index_set = self.index_set() - reverse = dict((index_set[i], i) for i in range(len(index_set))) - m = matrix(ZZ,len(index_set), lambda i,j: 1 if i==j else 2) - for (i,j,l) in self.coxeter_diagram().edge_iterator(): - m[reverse[i], reverse[j]] = l - m[reverse[j], reverse[i]] = l - m.set_immutable() - return m + from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix + return CoxeterMatrix(self) + + def coxeter_type(self): + """ + Return the Coxeter type for ``self``. + + EXAMPLES:: + + sage: CartanType(['A', 4]).coxeter_type() + """ + from sage.combinat.root_system.coxeter_type import CoxeterType + return CoxeterType(self) def dual(self): """ @@ -1284,20 +1285,9 @@ def is_crystallographic(self): [['E', 6], True], [['E', 7], True], [['E', 8], True], [['F', 4], True], [['G', 2], True], [['I', 5], False], [['H', 3], False], [['H', 4], False]] - - TESTS:: - - sage: all(t.is_crystallographic() for t in CartanType.samples(affine=True)) - True - sage: t = CartanType(['A',3]); t.is_crystalographic() - doctest:...: DeprecationWarning: is_crystalographic is deprecated. Please use is_crystallographic instead. - See http://trac.sagemath.org/14673 for details. - True """ return False - is_crystalographic = deprecated_function_alias(14673, is_crystallographic) - def is_simply_laced(self): """ Return whether this Cartan type is simply laced. @@ -1572,18 +1562,9 @@ def is_crystallographic(self): sage: CartanType(['A', 3, 1]).is_crystallographic() True - - TESTS:: - - sage: t = CartanType(['A',3]); t.is_crystalographic() - doctest:...: DeprecationWarning: is_crystalographic is deprecated. Please use is_crystallographic instead. - See http://trac.sagemath.org/14673 for details. - True """ return True - is_crystalographic = deprecated_function_alias(14673, is_crystallographic) - @cached_method def symmetrizer(self): """ diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index ae3bb9ba59e..048130b6d76 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -16,35 +16,226 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** -from coxeter_type import CartanType -from sage.matrix.all import MatrixSpace -from sage.rings.all import ZZ +from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.matrix.constructor import matrix from sage.matrix.matrix import is_Matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.matrix.matrix_integer_dense import Matrix_integer_dense -from sage.rings.all import ZZ -from sage.combinat.root_system.coxeter_type import CoxeterType, CoxeterType_abstract +from sage.graphs.graph import Graph +from sage.rings.all import ZZ, QQ, RR +from sage.rings.infinity import infinity +from sage.combinat.root_system.cartan_type import CartanType +from sage.combinat.root_system.coxeter_type import CoxeterType from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family -class CoxeterMatrix(Matrix_integer_dense, CoxeterType_abstract): +class CoxeterMatrix(Matrix_integer_dense, CoxeterType): """ A Coxeter matrix. + + .. TODO:: + + Because there is no object `\ZZ \cup \{ \infty \}`, we define `-1` + to represent `\infty`. + + EXAMPLES:: + + sage: CoxeterMatrix(['A', 4]) + [1 3 2 2] + [3 1 3 2] + [2 3 1 3] + [2 2 3 1] + sage: CoxeterMatrix(['B', 4]) + [1 3 2 2] + [3 1 3 2] + [2 3 1 4] + [2 2 4 1] + sage: CoxeterMatrix(['C', 4]) + [1 3 2 2] + [3 1 3 2] + [2 3 1 4] + [2 2 4 1] + sage: CoxeterMatrix(['D', 4]) + [1 3 2 2] + [3 1 3 3] + [2 3 1 2] + [2 3 2 1] + + sage: CoxeterMatrix(['E', 6]) + [1 2 3 2 2 2] + [2 1 2 3 2 2] + [3 2 1 3 2 2] + [2 3 3 1 3 2] + [2 2 2 3 1 3] + [2 2 2 2 3 1] + + sage: CoxeterMatrix(['F', 4]) + [1 3 2 2] + [3 1 4 2] + [2 4 1 3] + [2 2 3 1] + + sage: CoxeterMatrix(['G', 2]) + [1 6] + [6 1] + + Because there currently is no class for `\ZZ \cup \{ \infty \}`, labels + of `\infty` are given by `-1` in the Coxeter matrix:: + + sage: G = Graph([(0,1,None), (1,2,4), (0,2,oo)]) + sage: CoxeterMatrix(G) + [ 1 3 -1] + [ 3 1 4] + [-1 4 1] """ + __metaclass__ = ClasscallMetaclass + + @staticmethod + def __classcall_private__(cls, *args, **kwds): + """ + Normalize input so we can inherit from dense integer matrix. + + .. NOTE:: + + To disable the Coxeter type check, use the optional argument + ``coxeter_type_check = False``. + + EXAMPLES:: + + sage: C = CoxeterMatrix(['A',1,1]) + sage: C2 = CoxeterMatrix([[1, -1], [-1, 1]]) + sage: C3 = CoxeterMatrix(matrix([[1, -1], [-1, 1]]), [0, 1]) + sage: C == C2 and C == C3 + True + + Check with `\infty` because of the hack of using `-1` to represent + `\infty` in the Coxeter matrix:: + + sage: G = Graph([(0, 1, 3), (1, 2, oo)]) + sage: W1 = CoxeterMatrix([[1, 3, 2], [3, 1, -1], [2, -1, 1]]) + sage: W2 = CoxeterMatrix(G) + sage: W1 == W2 + True + sage: CoxeterMatrix(W1.coxeter_diagram()) == W1 + True + """ + # Special cases with 0 args + if not args: + if "coxeter_type" in kwds: # kwds has Coxeter type + args = ( CoxeterType(kwds["coxeter_type"]), ) + elif "cartan_type" in kwds: # kwds has Cartan type + args = ( CoxeterType(CartanType(kwds["cartan_type"])), ) + + if not args: + data = [] + n = 0 + index_set = tuple() + coxeter_type = None + subdivisions = None + + elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling + return typecall(cls, args[0], args[1], args[2], args[3]) + elif isinstance(args[0], CoxeterMatrix): + return args[0] + + else: + coxeter_type = None + subdivisions = None + index_set = None + + from sage.combinat.root_system.cartan_type import CartanType_abstract + if isinstance(args[0], CartanType_abstract): + coxeter_type = args[0].coxeter_type() + elif isinstance(args[0], Graph): + G = args[0] + n = G.num_verts() + + # Setup the basis matrix as all 2 except 1 on the diagonal + data = MatrixSpace(ZZ, n)([2]*(n*n)) + for i in range(n): + data[i, i] = ZZ.one() + + verts = sorted(G.vertices()) + for e in G.edges(): + m = e[2] + if m is None: + m = 3 + elif m == infinity or m == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\} + m = -1 + elif m <= 1: + raise ValueError("invalid Coxeter graph label") + i = verts.index(e[0]) + j = verts.index(e[1]) + data[j, i] = data[i, j] = m + + index_set = tuple(verts) + args = [data] + else: + try: + coxeter_type = CoxeterType(args[0]) + except (TypeError, ValueError, NotImplementedError): + pass + + if coxeter_type: + index_set = coxeter_type.index_set() + n = len(index_set) + reverse = {index_set[i]: i for i in range(n)} + data = [[1 if i == j else 2 for j in range(n)] for i in range(n)] + for (i,j,l) in coxeter_type.coxeter_diagram().edge_iterator(): + if l == infinity: + l = -1 + data[reverse[i]][reverse[j]] = l + data[reverse[j]][reverse[i]] = l + data = [val for row in data for val in row] + else: + M = matrix(args[0]) + check_coxeter_matrix(M) + n = M.ncols() + if "coxeter_type" in kwds: + coxeter_type = CoxeterType(kwds["coxeter_type"]) + elif n == 1: + coxeter_type = CoxeterType(['A', 1]) + elif kwds.get("coxeter_type_check", True): + coxeter_type = find_coxeter_type_from_matrix(M) + data = M.list() + subdivisions = M._subdivisions + + if kwds.get("index_set", None): + index_set = tuple(kwds["index_set"]) + + if len(args) == 1: + if coxeter_type is not None and index_set is None: + index_set = tuple(coxeter_type.index_set()) + elif len(args) == 2: + index_set = tuple(args[1]) + else: + raise ValueError("too many arguments") + + if index_set is None: + index_set = tuple(range(n)) + + if len(set(index_set)) != n: + raise ValueError("the given index set is not valid") + + mat = typecall(cls, MatrixSpace(ZZ, n, sparse=False), data, + coxeter_type, index_set) + mat._subdivisions = subdivisions + return mat + def __init__(self, parent, data, coxeter_type, index_set): """ Initialize ``self``. TESTS:: - sage: C = CoxeterMatrix(['A',1,1]) + sage: C = CoxeterMatrix(['A', 2, 1]) sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) """ - Matrix_integer_sparse.__init__(self, parent, data, False, False) + Matrix_integer_dense.__init__(self, parent, data, False, True) + self._coxeter_type = coxeter_type self._index_set = index_set self.set_immutable() @@ -75,15 +266,15 @@ def coxeter_type(self): sage: C = CoxeterMatrix(['A',4,1]) sage: C.coxeter_type() - ['A', 4, 1] + Coxeter type of ['A', 4, 1] If the Cartan type is unknown:: - sage: C = CoxeterMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]]) + sage: C = CoxeterMatrix([[1,3,4], [3,1,-1], [4,-1,1]]) sage: C.coxeter_type() - [ 2 -1 -2] - [-1 2 -1] - [-2 -1 2] + [ 1 3 4] + [ 3 1 -1] + [ 4 -1 1] """ if self._coxeter_type is None: return self @@ -100,7 +291,7 @@ def rank(self): sage: CoxeterMatrix(["A2","B2","F4"]).rank() 8 """ - return self.ncols() + return len(self._index_set) def coxeter_matrix(self): r""" @@ -109,12 +300,36 @@ def coxeter_matrix(self): EXAMPLES:: sage: CoxeterMatrix(['C',3]).coxeter_matrix() - [ 2 -1 0] - [-1 2 -2] - [ 0 -1 2] + [1 3 2] + [3 1 4] + [2 4 1] """ return self + @cached_method + def coxeter_diagram(self): + """ + Return the Coxeter diagram of ``self``. + + EXAMPLES:: + + sage: C = CoxeterMatrix(['A',3]) + sage: C.coxeter_diagram() + Graph on 3 vertices + + sage: C = CoxeterMatrix([['A',3],['A',1]]) + sage: C.coxeter_diagram() + Graph on 4 vertices + """ + n = self.nrows() + I = self.index_set() + val = lambda x: infinity if x == -1 else x + G = Graph([(I[i], I[j], val(self[i, j])) + for i in range(n) for j in range(i) + if self[i, j] not in [1, 2]]) + G.add_vertices(I) + return G.copy(immutable=True) + def is_simply_laced(self): """ Return if ``self`` is simply-laced. @@ -124,12 +339,12 @@ def is_simply_laced(self): EXAMPLES:: - sage: cm = CoxeterMatrix([[2, -1, -1, -1], [-1, 2, -1, -1], [-1, -1, 2, -1], [-1, -1, -1, 2]]) + sage: cm = CoxeterMatrix([[1,3,3,3], [3,1,3,3], [3,3,1,3], [3,3,3,1]]) sage: cm.is_simply_laced() True """ # We include 1 in this list to account for the diagonal - L = [1,2,3] + L = [1, 2, 3] return all(x in L for row in self for x in row) def is_crystallographic(self): @@ -143,9 +358,11 @@ def is_crystallographic(self): sage: CoxeterMatrix(['F',4]).is_crystallographic() True + sage: CoxeterMatrix(['H',3]).is_crystallographic() + False """ # We include 1 in this list to account for the diagonal - L = [1,2,3,4,6] + L = [1, 2, 3, 4, 6] return all(x in L for row in self for x in row) def is_finite(self): @@ -160,13 +377,17 @@ def is_finite(self): sage: M = CoxeterMatrix(['D',4,1]) sage: M.is_finite() False - sage: M = CoxeterMatrix([[2, -4], [-3, 2]]) + sage: M = CoxeterMatrix([[1, -1], [-1, 1]]) sage: M.is_finite() False """ if self._coxeter_type is not None: return self._coxeter_type.is_finite() - return self.bilinear_form().is_positive_semidefinite() + # The type checker should catch all finite types, and checking for + # positive definiteness is difficult, so we just assume it is + # not finite if the type checker cannot determine the type. + #return self.bilinear_form().is_positive_definite() + return False def is_affine(self): """ @@ -180,16 +401,246 @@ def is_affine(self): sage: M = CoxeterMatrix(['D',4,1]) sage: M.is_affine() True - sage: M = CoxeterMatrix([[2, -4], [-3, 2]]) + sage: M = CoxeterMatrix([[1, 3],[3,1]]) sage: M.is_affine() False + sage: M = CoxeterMatrix([[1, -1, 7], [-1, 1, 3], [7, 3, 1]]) + sage: M.is_affine() + Traceback (most recent call last): + ... + NotImplementedError """ if self._coxeter_type is not None: return self._coxeter_type.is_affine() - return self.bilinear_form().is_positive_semidefinite() + raise NotImplementedError + +##################################################################### +## Type check functions + +def find_coxeter_type_from_matrix(coxeter_matrix): + """ + Return the Coxeter type of ``coxeter_matrix`` if known, + otherwise return ``None``. + + .. TODO:: + + Check for more affine types. + + EXAMPLES: + + Some infinite ones:: + + sage: C = CoxeterMatrix([[1,3,2],[3,1,-1],[2,-1,1]]) + sage: C.is_finite() # indirect doctest + False + sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) + sage: C.is_finite() # indirect doctest + False + + Some finite ones:: + + sage: m = matrix(CoxeterMatrix(['D', 4])) + sage: CoxeterMatrix(m).is_finite() # indirect doctest + True + sage: m = matrix(CoxeterMatrix(['H', 4])) + sage: CoxeterMatrix(m).is_finite() # indirect doctest + True + """ + # First, we build the Coxeter graph of the group without the edge labels + n = ZZ(coxeter_matrix.nrows()) + G = Graph([range(n), lambda i,j: coxeter_matrix[i, j] not in [1,2]]) + # Coxeter graphs of finite Coxeter groups are forests + if not(G.is_forest()): + return None + comps = G.connected_components() + # The group is finite if and only if for every connected + # component ``comp`` of its Coxeter graph, the submatrix of + # the Coxeter matrix corresponding to ``comp`` is one of the + # type-A,B,D,E,F,H,I matrices (up to permutation). So we + # shall check this condition on every ``comp``. + types = [] + for comp in comps: + l = len(comp) + if l == 1: + # Any `1 \times 1` Coxeter matrix gives a finite group. + types.append(['A',1]) + continue # A1 + elif l == 2: + # A finite dihedral group iff there is no `\infty` in its + # Coxeter matrix. Otherwise we consider it type A1~. + c0, c1 = comp + if coxeter_matrix[c0, c1] > 0: + types.append(['I', coxeter_matrix[c0, c1]]) + else: + types.append(['A', 1, 1]) + elif l == 3: + # The `3`-node case. The finite groups to check for + # here are `A_3`, `B_3` and `H_3`. + c0, c1, c2 = comp + s = sorted([coxeter_matrix[c0, c1], + coxeter_matrix[c0, c2], + coxeter_matrix[c1, c2]]) + if s[1] == 3: + if s[2] == 3: + types.append(['A',3]) + elif s[2] == 4: + types.append(['B',3]) + elif s[2] == 5: + types.append(['H',3]) + elif s[2] == 6: + types.append(['G',2,1]) + else: + return None + continue + return None + elif l == 4: + # The `4`-node case. The finite groups to check for + # here are `A_4`, `B_4`, `D_4`, `F_4` and `H_4`. + c0, c1, c2, c3 = comp + u = [coxeter_matrix[c0, c1], + coxeter_matrix[c0, c2], + coxeter_matrix[c0, c3], + coxeter_matrix[c1, c2], + coxeter_matrix[c1, c3], + coxeter_matrix[c2, c3]] + s = sorted(u) + # ``s`` is the list of all off-diagonal entries of + # the ``comp``-submatrix of the Coxeter matrix, + # sorted in increasing order. + if s[3:5] == [3, 3]: + if s[5] == 3: + if max(G.degree()) == 2: + types.append(['A',4]) + else: + types.append(['D',4]) + continue # A4, D4 + if s[5] in [4, 5]: + u0 = u[0] + u[1] + u[2] + u1 = u[0] + u[3] + u[4] + u2 = u[1] + u[3] + u[5] + u3 = u[2] + u[4] + u[5] + ss = sorted([u0, u1, u2, u3]) + if ss == [7, 7, 9, 9]: + types.append(['F',4]) + continue + elif ss == [7, 8, 8, 9]: + types.append(['B',4]) + continue + elif ss == [7, 8, 9, 10]: + types.append(['H',4]) + continue + return None + else: + # The case of `l \geq 5` nodes. The finite + # groups to check for here are `A_l`, `B_l`, `D_l`, + # and `E_l` (for `l = 6, 7, 8`). + + # Checking that the Coxeter matrix of the subgroup + # corresponding to the vertices ``comp`` has all its + # off-diagonal entries equal to 2, 3 or at most once 4 + found_a_4 = False + for j in range(l): + for i in range(j): + coxeter_entry = coxeter_matrix[comp[i], comp[j]] + if coxeter_entry in [2, 3]: + continue + if coxeter_entry == 4 and not found_a_4: + found_a_4 = True + continue + return None + + G0 = G.subgraph(comp) + if found_a_4: + # The case when a `4` has been found in the + # Coxeter matrix. This needs only to be checked + # against `B_l`. We use the observation that + # the group is `B_l` if and only if the Coxeter + # graph is an `l`-path (i.e., has diameter + # `l - 1`) and the `4` corresponds to one of + # its two outermost edges. + diameter = G0.diameter() + if diameter != l - 1: + return None + + ecc = sorted(((u, v) for (v, u) in G0.eccentricity(with_labels=True).items())) + left_end = ecc[-1][1] + right_end = ecc[-2][1] + left_almost_end = G0.neigbors(left_end)[0] + right_almost_end = G0.neigbors(right_end)[0] + if (coxeter_matrix[left_end, left_almost_end] == 4 + or coxeter_matrix[right_end, right_almost_end] == 4): + types.append(['B', l]) + continue # Bl + return None + + # Now, all off-diagonal entries of the Coxeter matrix + # are 2's and 3's. We need to check our group against + # `A_l`, `D_l` and `E_l`. Knowing that the Coxeter + # graph is a tree, we can use its vertex + # eccentricities to check this. + ecc = sorted(G0.eccentricity()) + if ecc[-1] == l - 1: + types.append(['A', l]) + continue # Al + if ecc[-3] == l - 2: + types.append(['D', l]) + continue # Dl + if l <= 8 and ecc[-2] == l - 2 and ecc[-5] == l - 3: + types.append(['E', l]) + continue # El + return None + + if len(types) == 1: + types = types[0] + return CoxeterType(types) ##################################################################### -## Other methods +## Other functions + +def check_coxeter_matrix(m): + """ + Check if ``m`` represents a Coxeter matrix and raise and error if not. + + EXAMPLES:: + + sage: from sage.combinat.root_system.coxeter_matrix import check_coxeter_matrix + sage: m = matrix([[1,3,2],[3,1,-1],[2,-1,1]]) + sage: check_coxeter_matrix(m) + + sage: m = matrix([[1,3],[3,1],[2,-1]]) + sage: check_coxeter_matrix(m) + Traceback (most recent call last): + ... + ValueError: not a square matrix + + sage: m = matrix([[1,3,2],[3,1,-1],[2,-1,2]]) + sage: check_coxeter_matrix(m) + Traceback (most recent call last): + ... + ValueError: the matrix diagonal is not all 1 + + sage: m = matrix([[1,3,3],[3,1,-1],[2,-1,1]]) + sage: check_coxeter_matrix(m) + Traceback (most recent call last): + ... + ValueError: the matrix is not symmetric + + sage: m = matrix([[1,3,2],[3,1,-2],[2,-2,1]]) + sage: check_coxeter_matrix(m) + Traceback (most recent call last): + ... + ValueError: invalid Coxeter label -2 + """ + if not m.is_square(): + raise ValueError("not a square matrix") + for i, row in enumerate(m.rows()): + if m[i,i] != 1: + raise ValueError("the matrix diagonal is not all 1") + for j, val in enumerate(row[i+1:]): + if val != m[j+i+1,i]: + raise ValueError("the matrix is not symmetric") + if val <= 1 and val != -1: + raise ValueError("invalid Coxeter label {}".format(val)) def coxeter_matrix_as_function(t): """ @@ -217,55 +668,19 @@ def coxeter_matrix_as_function(t): def coxeter_matrix(t): """ - Returns the Coxeter matrix of type t. + This was deprecated in :trac:`17798` for :class:`CartanMatrix`. EXAMPLES:: sage: coxeter_matrix(['A', 4]) + doctest:...: DeprecationWarning: coxeter_matrix() is deprecated. Use CoxeterMatrix() instead + See http://trac.sagemath.org/17798 for details. [1 3 2 2] [3 1 3 2] [2 3 1 3] [2 2 3 1] - sage: coxeter_matrix(['B', 4]) - [1 3 2 2] - [3 1 3 2] - [2 3 1 4] - [2 2 4 1] - sage: coxeter_matrix(['C', 4]) - [1 3 2 2] - [3 1 3 2] - [2 3 1 4] - [2 2 4 1] - sage: coxeter_matrix(['D', 4]) - [1 3 2 2] - [3 1 3 3] - [2 3 1 2] - [2 3 2 1] - - :: - - sage: coxeter_matrix(['E', 6]) - [1 2 3 2 2 2] - [2 1 2 3 2 2] - [3 2 1 3 2 2] - [2 3 3 1 3 2] - [2 2 2 3 1 3] - [2 2 2 2 3 1] - - :: - - sage: coxeter_matrix(['F', 4]) - [1 3 2 2] - [3 1 4 2] - [2 4 1 3] - [2 2 3 1] - - :: - - sage: coxeter_matrix(['G', 2]) - [1 6] - [6 1] """ - # TODO: Deprecate this in favor of CoxeterMatrix + from sage.misc.superseded import deprecation + deprecation(17798, 'coxeter_matrix() is deprecated. Use CoxeterMatrix() instead') return CoxeterMatrix(t) diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 6904d0c1602..39ad7446014 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -15,14 +15,44 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** -from cartan_type import CartanType + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.misc.classcall_metaclass import ClasscallMetaclass +from sage.combinat.root_system.cartan_type import CartanType from sage.matrix.all import MatrixSpace from sage.rings.all import ZZ +from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.sage_object import SageObject +from sage.combinat.root_system.cartan_type import CartanType -class CoxeterType_abstract(object): +class CoxeterType(object): """ Abstract class for Coxeter types. """ + __metaclass__ = ClasscallMetaclass + + @staticmethod + def __classcall_private__(cls, x): + """ + Parse input ``x``. + + EXAMPLES:: + + sage: CoxeterType(['A',3]) + Coxeter type of ['A', 3] + """ + if isinstance(x, CoxeterType): + return x + + try: + return CoxeterTypeFromCartanType(CartanType(x)) + except (ValueError, TypeError): + pass + + raise NotImplementedError("Coxeter types not from Cartan types not yet implemented") + @abstract_method def rank(self): """ @@ -32,11 +62,11 @@ def rank(self): EXAMPLES:: - sage: CartanType(['A', 4]).rank() + sage: CoxeterType(['A', 4]).rank() 4 - sage: CartanType(['A', 7, 2]).rank() + sage: CoxeterType(['A', 7, 2]).rank() 5 - sage: CartanType(['I', 8]).rank() + sage: CoxeterType(['I', 8]).rank() 2 """ @@ -49,27 +79,27 @@ def index_set(self): EXAMPLES:: - sage: CartanType(['A', 3, 1]).index_set() + sage: CoxeterType(['A', 3, 1]).index_set() (0, 1, 2, 3) - sage: CartanType(['D', 4]).index_set() + sage: CoxeterType(['D', 4]).index_set() (1, 2, 3, 4) - sage: CartanType(['A', 7, 2]).index_set() + sage: CoxeterType(['A', 7, 2]).index_set() (0, 1, 2, 3, 4) - sage: CartanType(['A', 7, 2]).index_set() + sage: CoxeterType(['A', 7, 2]).index_set() (0, 1, 2, 3, 4) - sage: CartanType(['A', 6, 2]).index_set() + sage: CoxeterType(['A', 6, 2]).index_set() (0, 1, 2, 3) - sage: CartanType(['D', 6, 2]).index_set() + sage: CoxeterType(['D', 6, 2]).index_set() (0, 1, 2, 3, 4, 5) - sage: CartanType(['E', 6, 1]).index_set() + sage: CoxeterType(['E', 6, 1]).index_set() (0, 1, 2, 3, 4, 5, 6) - sage: CartanType(['E', 6, 2]).index_set() + sage: CoxeterType(['E', 6, 2]).index_set() (0, 1, 2, 3, 4) - sage: CartanType(['A', 2, 2]).index_set() + sage: CoxeterType(['A', 2, 2]).index_set() (0, 1) - sage: CartanType(['G', 2, 1]).index_set() + sage: CoxeterType(['G', 2, 1]).index_set() (0, 1, 2) - sage: CartanType(['F', 4, 1]).index_set() + sage: CoxeterType(['F', 4, 1]).index_set() (0, 1, 2, 3, 4) """ @@ -80,10 +110,15 @@ def coxeter_matrix(self): EXAMPLES:: - sage: CartanType(['A', 3]).is_affine() - False - sage: CartanType(['A', 3, 1]).is_affine() - True + sage: CoxeterType(['A', 3]).coxeter_matrix() + [1 3 2] + [3 1 3] + [2 3 1] + sage: CoxeterType(['A', 3, 1]).coxeter_matrix() + [1 3 2 3] + [3 1 3 2] + [2 3 1 3] + [3 2 3 1] """ @abstract_method @@ -93,10 +128,10 @@ def coxeter_diagram(self): EXAMPLES:: - sage: CartanType(['A', 3]).is_affine() - False - sage: CartanType(['A', 3, 1]).is_affine() - True + sage: CoxeterType(['A', 3]).coxeter_diagram() + Graph on 3 vertices + sage: CoxeterType(['A', 3, 1]).coxeter_diagram() + Graph on 4 vertices """ @abstract_method @@ -106,18 +141,9 @@ def is_finite(self): EXAMPLES:: - sage: from sage.combinat.root_system.cartan_type import CartanType_abstract - sage: C = CartanType_abstract() - sage: C.is_finite() - Traceback (most recent call last): - ... - NotImplementedError: - - :: - - sage: CartanType(['A',4]).is_finite() + sage: CoxeterType(['A',4]).is_finite() True - sage: CartanType(['A',4, 1]).is_finite() + sage: CoxeterType(['A',4, 1]).is_finite() False """ @@ -128,9 +154,9 @@ def is_affine(self): EXAMPLES:: - sage: CartanType(['A', 3]).is_affine() + sage: CoxeterType(['A', 3]).is_affine() False - sage: CartanType(['A', 3, 1]).is_affine() + sage: CoxeterType(['A', 3, 1]).is_affine() True """ @@ -182,19 +208,96 @@ def is_simply_laced(self): """ return False -class CoxeterTypeFromCartanType(CoxeterType_abstract): + @cached_method + def bilinear_form(self, R=None): + """ + Return the bilinear form over ``R`` associated to ``self``. + + INPUT: + + - ``R`` -- (default: universal cyclotomic field) a ring used to + compute the bilinear form + + EXAMPLES:: + + sage: CoxeterType(['A', 2, 1]).bilinear_form() + [ 1 -1/2 -1/2] + [-1/2 1 -1/2] + [-1/2 -1/2 1] + sage: CoxeterType(['H', 3]).bilinear_form() + [ 1 -1/2 0] + [ -1/2 1 1/2*E(5)^2 + 1/2*E(5)^3] + [ 0 1/2*E(5)^2 + 1/2*E(5)^3 1] + sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) + sage: C.bilinear_form() + [ 1 -1 -1] + [-1 1 -1] + [-1 -1 1] + """ + if R is None: + R = UniversalCyclotomicField() + # Compute the matrix with entries `- \cos( \pi / m_{ij} )`. + if R is UniversalCyclotomicField(): + val = lambda x: (R.gen(2*x) + ~R.gen(2*x)) / R(-2) if x != -1 else -R.one() + else: + from sage.functions.trig import cos + from sage.symbolic.constants import pi + val = lambda x: -R(cos(pi / x)) if x != -1 else -R.one() + + n = self.rank() + MS = MatrixSpace(R, n, sparse=True) + MC = MS._get_matrix_class() + mat = self.coxeter_matrix() + bilinear = MC(MS, entries={(i, j): val(mat[i, j]) + for i in range(n) for j in range(n) + if mat[i, j] != 2}, + coerce=True, copy=True) + bilinear.set_immutable() + return bilinear + +class CoxeterTypeFromCartanType(SageObject, CoxeterType, UniqueRepresentation): """ A Coxeter type associated to a Cartan type. """ + @staticmethod + def __classcall_private__(cls, cartan_type): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: from sage.combinat.root_system.coxeter_type import CoxeterTypeFromCartanType + sage: C1 = CoxeterTypeFromCartanType(['A',3]) + sage: C2 = CoxeterTypeFromCartanType(CartanType(['A',3])) + sage: C1 is C2 + True + """ + return super(CoxeterTypeFromCartanType, cls).__classcall__(cls, + CartanType(cartan_type)) + def __init__(self, cartan_type): """ Initialize ``self``. + + EXAMPLES:: + + sage: C = CoxeterType(['A',3]) + sage: TestSuite(C).run() + sage: C = CoxeterType(['H',4]) + sage: TestSuite(C).run() + sage: C = CoxeterType(['C',3,1]) + sage: TestSuite(C).run() """ self._cartan_type = cartan_type def _repr_(self): """ Return a string representation of ``self``. + + EXAMPLES:: + + sage: CoxeterType(['A',3]) + Coxeter type of ['A', 3] """ return "Coxeter type of {}".format(self._cartan_type) @@ -203,54 +306,116 @@ def coxeter_matrix(self): Return the Coxeter matrix associated to ``self``. EXAMPLES:: + + sage: C = CoxeterType(['H',3]) + sage: C.coxeter_matrix() + [1 3 2] + [3 1 5] + [2 5 1] """ return self._cartan_type.coxeter_matrix() def coxeter_diagram(self): """ Return the Coxeter digramh of ``self``. + + EXAMPLES:: + + sage: C = CoxeterType(['H',3]) + sage: C.coxeter_diagram().edges() + [(1, 2, 3), (2, 3, 5)] """ return self._cartan_type.coxeter_diagram() def cartan_type(self): """ Return the Cartan type used to construct ``self``. + + EXAMPLES:: + + sage: C = CoxeterType(['C',3]) + sage: C.cartan_type() + ['C', 3] """ return self._cartan_type def rank(self): """ Return the rank of ``self``. + + EXAMPLES:: + + sage: C = CoxeterType(['I', 16]) + sage: C.rank() + 2 """ return self._cartan_type.rank() def index_set(self): """ Return the index set of ``self``. + + EXAMPLES:: + + sage: C = CoxeterType(['A', 4]) + sage: C.index_set() + (1, 2, 3, 4) """ return self._cartan_type.index_set() def is_finite(self): """ Return if ``self`` is a finite type. + + EXAMPLES:: + + sage: C = CoxeterType(['E', 6]) + sage: C.is_finite() + True """ return self._cartan_type.is_finite() def is_affine(self): """ Return if ``self`` is an affine type. + + EXAMPLES:: + + sage: C = CoxeterType(['F', 4, 1]) + sage: C.is_affine() + True """ return self._cartan_type.is_affine() def is_crystallographic(self): """ Return if ``self`` is crystallographic. + + EXAMPLES:: + + sage: C = CoxeterType(['C', 3]) + sage: C.is_crystallographic() + True + + sage: C = CoxeterType(['H', 3]) + sage: C.is_crystallographic() + False """ return self._cartan_type.is_crystallographic() def is_simply_laced(self): """ Return if ``self`` is simply-laced. + + EXAMPLES:: + + sage: C = CoxeterType(['A', 5]) + sage: C.is_simply_laced() + True + + sage: C = CoxeterType(['B', 3]) + sage: C.is_simply_laced() + False """ return self._cartan_type.is_simply_laced() diff --git a/src/sage/combinat/root_system/dynkin_diagram.py b/src/sage/combinat/root_system/dynkin_diagram.py index 80903b54049..44388ff486b 100644 --- a/src/sage/combinat/root_system/dynkin_diagram.py +++ b/src/sage/combinat/root_system/dynkin_diagram.py @@ -32,7 +32,6 @@ from sage.graphs.digraph import DiGraph from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.combinat.root_system.cartan_matrix import CartanMatrix -from sage.misc.superseded import deprecated_function_alias def DynkinDiagram(*args, **kwds): r""" @@ -583,15 +582,11 @@ def is_crystallographic(self): TESTS:: - sage: CartanType(['G',2]).dynkin_diagram().is_crystalographic() - doctest:...: DeprecationWarning: is_crystalographic is deprecated. Please use is_crystallographic instead. - See http://trac.sagemath.org/14673 for details. + sage: CartanType(['G',2]).dynkin_diagram().is_crystallographic() True """ return True - is_crystalographic = deprecated_function_alias(14673, is_crystallographic) - def symmetrizer(self): """ Return the symmetrizer of the corresponding Cartan matrix. diff --git a/src/sage/combinat/root_system/type_I.py b/src/sage/combinat/root_system/type_I.py index ea8a7cdeb6f..fcb071d61f4 100644 --- a/src/sage/combinat/root_system/type_I.py +++ b/src/sage/combinat/root_system/type_I.py @@ -47,6 +47,7 @@ def rank(self): Type `I_p` is of rank 2 EXAMPLES:: + sage: CartanType(['I', 5]).rank() 2 """ @@ -57,10 +58,11 @@ def index_set(self): Type `I_p` is of rank 2 EXAMPLES:: + sage: CartanType(['I', 5]).index_set() - [1, 2] + (1, 2) """ - return [1, 2] + return (1, 2) def coxeter_diagram(self): """ @@ -92,3 +94,4 @@ def coxeter_number(self): 12 """ return self.n + diff --git a/src/sage/groups/matrix_gps/coxeter_group.py b/src/sage/groups/matrix_gps/coxeter_group.py index 318f4020466..d7fc21ff529 100644 --- a/src/sage/groups/matrix_gps/coxeter_group.py +++ b/src/sage/groups/matrix_gps/coxeter_group.py @@ -23,6 +23,7 @@ from sage.categories.coxeter_groups import CoxeterGroups from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract +from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_generic from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic from sage.graphs.graph import Graph @@ -31,7 +32,7 @@ from sage.rings.all import ZZ from sage.rings.infinity import infinity from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField - +from sage.misc.superseded import deprecated_function_alias class CoxeterMatrixGroup(FinitelyGeneratedMatrixGroup_generic, UniqueRepresentation): r""" @@ -151,7 +152,7 @@ class CoxeterMatrixGroup(FinitelyGeneratedMatrixGroup_generic, UniqueRepresentat [ 3 1 2 15] [ 2 2 1 7] [ 3 15 7 1] - sage: G2 = W.coxeter_graph() + sage: G2 = W.coxeter_diagram() sage: CoxeterGroup(G2) is W True @@ -202,67 +203,13 @@ def __classcall_private__(cls, data, base_ring=None, index_set=None): sage: W4 = CoxeterGroup(G2) sage: W1 is W4 True - - Check with `\infty` because of the hack of using `-1` to represent - `\infty` in the Coxeter matrix:: - - sage: G = Graph([(0, 1, 3), (1, 2, oo)]) - sage: W1 = CoxeterGroup(matrix([[1, 3, 2], [3,1,-1], [2,-1,1]])) - sage: W2 = CoxeterGroup(G) - sage: W1 is W2 - True - sage: CoxeterGroup(W1.coxeter_graph()) is W1 - True """ - if isinstance(data, CartanType_abstract): - if index_set is None: - index_set = data.index_set() - data = data.coxeter_matrix() - elif isinstance(data, Graph): - G = data - n = G.num_verts() - - # Setup the basis matrix as all 2 except 1 on the diagonal - data = matrix(ZZ, [[2]*n]*n) - for i in range(n): - data[i, i] = ZZ.one() - - verts = G.vertices() - for e in G.edges(): - m = e[2] - if m is None: - m = 3 - elif m == infinity or m == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\} - m = -1 - elif m <= 1: - raise ValueError("invalid Coxeter graph label") - i = verts.index(e[0]) - j = verts.index(e[1]) - data[j, i] = data[i, j] = m - - if index_set is None: - index_set = G.vertices() - else: - try: - data = matrix(data) - except (ValueError, TypeError): - data = CartanType(data).coxeter_matrix() - if not data.is_symmetric(): - raise ValueError("the Coxeter matrix is not symmetric") - if any(d != 1 for d in data.diagonal()): - raise ValueError("the Coxeter matrix diagonal is not all 1") - if any(val <= 1 and val != -1 for i, row in enumerate(data.rows()) - for val in row[i+1:]): - raise ValueError("invalid Coxeter label") - - if index_set is None: - index_set = range(data.nrows()) + data = CoxeterMatrix(data, index_set=index_set) if base_ring is None: base_ring = UniversalCyclotomicField() - data.set_immutable() return super(CoxeterMatrixGroup, cls).__classcall__(cls, - data, base_ring, tuple(index_set)) + data, base_ring, data.index_set()) def __init__(self, coxeter_matrix, base_ring, index_set): """ @@ -301,8 +248,7 @@ def __init__(self, coxeter_matrix, base_ring, index_set): True """ self._matrix = coxeter_matrix - self._index_set = index_set - n = ZZ(coxeter_matrix.nrows()) + n = coxeter_matrix.rank() # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`. MS = MatrixSpace(base_ring, n, sparse=True) MC = MS._get_matrix_class() @@ -317,177 +263,16 @@ def __init__(self, coxeter_matrix, base_ring, index_set): for j in range(n)}, coerce=True, copy=True) for i in range(n)] - # Compute the matrix with entries `- \cos( \pi / m_{ij} )`. - # This describes the bilinear form corresponding to this - # Coxeter system, and might lead us out of our base ring. - base_field = base_ring.fraction_field() - MS2 = MatrixSpace(base_field, n, sparse=True) - MC2 = MS2._get_matrix_class() - self._bilinear = MC2(MS2, entries={(i, j): val(coxeter_matrix[i, j]) / base_field(-2) - for i in range(n) for j in range(n) - if coxeter_matrix[i, j] != 2}, - coerce=True, copy=True) - self._bilinear.set_immutable() category = CoxeterGroups() # Now we shall see if the group is finite, and, if so, refine # the category to ``category.Finite()``. Otherwise the group is # infinite and we refine the category to ``category.Infinite()``. - is_finite = self._finite_recognition() - if is_finite: + if self._matrix.is_finite(): category = category.Finite() else: category = category.Infinite() - FinitelyGeneratedMatrixGroup_generic.__init__(self, n, base_ring, + FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(n), base_ring, gens, category=category) - - def _finite_recognition(self): - """ - Return ``True`` if and only if the type is finite. - - This is an auxiliary function used during the initialisation. - - EXAMPLES: - - Some infinite ones:: - - sage: F = CoxeterGroups().Finite() - sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]]) - sage: W in F # indirect doctest - False - sage: W = CoxeterGroup([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) - sage: W in F # indirect doctest - False - - Some finite ones:: - - sage: CoxeterGroup(['D',4], base_ring=QQ) in F # indirect doctest - True - sage: CoxeterGroup(['H',4]) in F # indirect doctest - True - """ - # First, we build the Coxeter graph of the group, without the - # edge labels. - coxeter_matrix = self._matrix - n = ZZ(coxeter_matrix.nrows()) - G = Graph([(i, j) for i in range(n) for j in range(i) - if coxeter_matrix[i, j] not in [1, 2]]) - # Coxeter graphs of finite Coxeter groups are forests - if not(G.is_forest()): - return False - comps = G.connected_components() - finite = True - # The group is finite if and only if for every connected - # component ``comp`` of its Coxeter graph, the submatrix of - # the Coxeter matrix corresponding to ``comp`` is one of the - # type-A,B,D,E,F,H,I matrices (up to permutation). So we - # shall check this condition on every ``comp``. - for comp in comps: - l = len(comp) - if l == 1: - # Any `1 \times 1` Coxeter matrix gives a finite group. - continue # A1 - elif l == 2: - # A dihedral group is finite iff there is no `\infty` - # in its Coxeter matrix. - c0, c1 = comp - if coxeter_matrix[c0, c1] > 0: - continue # I2 - return False - elif l == 3: - # The `3`-node case. The finite groups to check for - # here are `A_3`, `B_3` and `H_3`. - c0, c1, c2 = comp - s = sorted([coxeter_matrix[c0, c1], - coxeter_matrix[c0, c2], - coxeter_matrix[c1, c2]]) - if s[1] == 3 and s[2] in [3, 4, 5]: - continue # A3, B3, H3 - return False - elif l == 4: - # The `4`-node case. The finite groups to check for - # here are `A_4`, `B_4`, `D_4`, `F_4` and `H_4`. - c0, c1, c2, c3 = comp - u = [coxeter_matrix[c0, c1], - coxeter_matrix[c0, c2], - coxeter_matrix[c0, c3], - coxeter_matrix[c1, c2], - coxeter_matrix[c1, c3], - coxeter_matrix[c2, c3]] - s = sorted(u) - # ``s`` is the list of all off-diagonal entries of - # the ``comp``-submatrix of the Coxeter matrix, - # sorted in increasing order. - if s[3:5] == [3, 3]: - if s[5] == 3: - continue # A4, D4 - if s[5] in [4, 5]: - u0 = u[0] + u[1] + u[2] - u1 = u[0] + u[3] + u[4] - u2 = u[1] + u[3] + u[5] - u3 = u[2] + u[4] + u[5] - ss = sorted([u0, u1, u2, u3]) - if ss in [[7, 7, 9, 9], [7, 8, 8, 9], - [7, 8, 9, 10]]: - continue # F4, B4, H4 - return False - else: - # The case of `l \geq 5` nodes. The finite - # groups to check for here are `A_l`, `B_l`, `D_l`, - # and `E_l` (for `l = 6, 7, 8`). - - # Checking that the Coxeter matrix of the subgroup - # corresponding to the vertices ``comp`` has all its - # off-diagonal entries equal to 2, 3 or at most once 4 - found_a_4 = False - for j in range(l): - for i in range(j): - coxeter_entry = coxeter_matrix[comp[i], comp[j]] - if coxeter_entry in [2, 3]: - continue - if coxeter_entry == 4 and not found_a_4: - found_a_4 = True - continue - return False - - G0 = G.subgraph(comp) - if found_a_4: - # The case when a `4` has been found in the - # Coxeter matrix. This needs only to be checked - # against `B_l`. We use the observation that - # the group is `B_l` if and only if the Coxeter - # graph is an `l`-path (i.e., has diameter - # `l - 1`) and the `4` corresponds to one of - # its two outermost edges. - diameter = G0.diameter() - if diameter != l - 1: - return False - - ecc = sorted(((u, v) for (v, u) in G0.eccentricity(with_labels=True).items())) - left_end = ecc[-1][1] - right_end = ecc[-2][1] - left_almost_end = G0.neigbors(left_end)[0] - right_almost_end = G0.neigbors(right_end)[0] - if (coxeter_matrix[left_end, left_almost_end] == 4 - or coxeter_matrix[right_end, right_almost_end] == 4): - continue # Bl - return False - - # Now, all off-diagonal entries of the Coxeter matrix - # are 2's and 3's. We need to check our group against - # `A_l`, `D_l` and `E_l`. Knowing that the Coxeter - # graph is a tree, we can use its vertex - # eccentricities to check this. - ecc = sorted(G0.eccentricity()) - if ecc[-1] == l - 1: - continue # Al - if ecc[-3] == l - 2: - continue # Dl - if l <= 8 and ecc[-2] == l - 2 and ecc[-5] == l - 3: - continue # El - return False - - return True - def _repr_(self): """ Return a string representation of ``self``. @@ -512,7 +297,7 @@ def index_set(self): sage: W = CoxeterGroup([[1,3],[3,1]]) sage: W.index_set() - (0, 1) + (1, 2) sage: W = CoxeterGroup([[1,3],[3,1]], index_set=['x', 'y']) sage: W.index_set() ('x', 'y') @@ -520,7 +305,7 @@ def index_set(self): sage: W.index_set() (1, 2, 3) """ - return self._index_set + return self._matrix.index_set() def coxeter_matrix(self): """ @@ -540,37 +325,29 @@ def coxeter_matrix(self): """ return self._matrix - def coxeter_graph(self): + def coxeter_diagram(self): """ - Return the Coxeter graph of ``self``. + Return the Coxeter diagram of ``self``. EXAMPLES:: sage: W = CoxeterGroup(['H',3], implementation="reflection") - sage: G = W.coxeter_graph(); G + sage: G = W.coxeter_diagram(); G Graph on 3 vertices sage: G.edges() - [(1, 2, None), (2, 3, 5)] + [(1, 2, 3), (2, 3, 5)] sage: CoxeterGroup(G) is W True sage: G = Graph([(0, 1, 3), (1, 2, oo)]) sage: W = CoxeterGroup(G) - sage: W.coxeter_graph() == G + sage: W.coxeter_diagram() == G True - sage: CoxeterGroup(W.coxeter_graph()) is W + sage: CoxeterGroup(W.coxeter_diagram()) is W True """ - G = Graph() - G.add_vertices(self.index_set()) - for i, row in enumerate(self._matrix.rows()): - for j, val in enumerate(row[i+1:]): - if val == 3: - G.add_edge(self._index_set[i], self._index_set[i+1+j]) - elif val > 3: - G.add_edge(self._index_set[i], self._index_set[i+1+j], val) - elif val == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\} - G.add_edge(self._index_set[i], self._index_set[i+1+j], infinity) - return G + return self._matrix.coxeter_diagram() + + coxeter_graph = deprecated_function_alias(17798, coxeter_diagram) def bilinear_form(self): r""" @@ -596,7 +373,7 @@ def bilinear_form(self): [ 0 -1/2 1 0] [ 0 -1/2 0 1] """ - return self._bilinear + return self._matrix.bilinear_form(self.base_ring()) def is_finite(self): """ @@ -689,9 +466,9 @@ def simple_reflection(self, i): [ 0 1 0] [ 0 1 -1] """ - if not i in self._index_set: + if not i in self.index_set(): raise ValueError("%s is not in the index set %s" % (i, self.index_set())) - return self.gen(self._index_set.index(i)) + return self.gen(self.index_set().index(i)) class Element(MatrixGroupElement_generic): """ @@ -723,7 +500,7 @@ def has_right_descent(self, i): sage: map(lambda i: elt.has_right_descent(i), [1, 2, 3]) [True, False, True] """ - i = self.parent()._index_set.index(i) + i = self.parent().index_set().index(i) col = self.matrix().column(i) return all(x <= 0 for x in col) @@ -743,3 +520,4 @@ def canonical_matrix(self): [ 0 1 -1] """ return self.matrix() + From 311eb184e6c37b7bfa0090468d79ca13509a63da Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 1 Mar 2015 23:19:44 -0800 Subject: [PATCH 0122/1872] Fixing a pickling issue and some easy doctest failures. --- src/sage/combinat/root_system/cartan_matrix.py | 14 ++++++++++++++ src/sage/combinat/root_system/cartan_type.py | 1 + src/sage/combinat/root_system/coxeter_matrix.py | 14 ++++++++++++++ src/sage/combinat/root_system/type_I.py | 2 +- 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index 7e15bddd66c..2f987b16d9b 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -304,6 +304,20 @@ def __init__(self, parent, data, cartan_type, index_set): self._index_set = index_set self.set_immutable() + def __reduce__(self): + """ + Used for pickling. + + TESTS:: + + sage: CM = CartanMatrix(['A',4]) + sage: x = loads(dumps(CM)) + sage: x._index_set + (1, 2, 3, 4) + """ + return (CartanMatrix, (self.parent(), self.list(), + self._cartan_type, self._index_set)) + def root_system(self): """ Return the root system corresponding to ``self``. diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 9dabd120ebf..1ca4c0851fd 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -1091,6 +1091,7 @@ def coxeter_type(self): EXAMPLES:: sage: CartanType(['A', 4]).coxeter_type() + Coxeter type of ['A', 4] """ from sage.combinat.root_system.coxeter_type import CoxeterType return CoxeterType(self) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 048130b6d76..516e846d17a 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -240,6 +240,20 @@ def __init__(self, parent, data, coxeter_type, index_set): self._index_set = index_set self.set_immutable() + def __reduce__(self): + """ + Used for pickling. + + TESTS:: + + sage: C = CoxeterMatrix(['A',4]) + sage: M = loads(dumps(C)) + sage: M._index_set + (1, 2, 3, 4) + """ + return (CoxeterMatrix, (self.parent(), self.list(), + self._coxeter_type, self._index_set)) + ########################################################################## # Coxeter type methods diff --git a/src/sage/combinat/root_system/type_I.py b/src/sage/combinat/root_system/type_I.py index fcb071d61f4..bcbcb8dbfbf 100644 --- a/src/sage/combinat/root_system/type_I.py +++ b/src/sage/combinat/root_system/type_I.py @@ -22,7 +22,7 @@ def __init__(self, n): sage: ct.rank() 2 sage: ct.index_set() - [1, 2] + (1, 2) sage: ct.is_irreducible() True From 2ef21f0ae15293f7f458aecc209b4ab5419b8db6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 1 Mar 2015 23:25:14 -0800 Subject: [PATCH 0123/1872] Re-enable cache of coxeter_matrix() for CartanType_abstract. --- src/sage/combinat/root_system/cartan_type.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 1ca4c0851fd..7efc2e2c514 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -1069,6 +1069,7 @@ def coxeter_diagram(self): [(1, 2, 3), (2, 3, 4), (3, 4, 3)] """ + @cached_method def coxeter_matrix(self): """ Return the Coxeter matrix for ``self``. From e61a4f3927c1d096f8ece1138ed33abbd928594d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 1 Mar 2015 23:38:34 -0800 Subject: [PATCH 0124/1872] Fixed import of numpy via UCF. --- src/sage/combinat/root_system/coxeter_type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 39ad7446014..a900ddce3a2 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -22,7 +22,6 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.matrix.all import MatrixSpace from sage.rings.all import ZZ -from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject from sage.combinat.root_system.cartan_type import CartanType @@ -234,6 +233,7 @@ def bilinear_form(self, R=None): [-1 1 -1] [-1 -1 1] """ + from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField if R is None: R = UniversalCyclotomicField() # Compute the matrix with entries `- \cos( \pi / m_{ij} )`. From cd37cc6e312d7b028024c6fff4778f73c557636b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 2 Mar 2015 15:05:07 -0800 Subject: [PATCH 0125/1872] Fix a docstring. --- src/sage/geometry/hyperplane_arrangement/arrangement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 4e628b6172f..5efda2a41c5 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -1484,7 +1484,7 @@ def regions(self): return tuple(regions) def region_containing_point(self, p): - r"""def region + r""" The region in the hyperplane arrangement containing a given point. The base field must have characteristic zero. From 67bdd8ce642998e6c9194065e91ff45b9b14e090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 7 Mar 2015 23:15:01 +0100 Subject: [PATCH 0126/1872] trac #16209 another algo, without precomputing the mutation class --- .../cluster_algebra_quiver/cluster_seed.py | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index ae908388440..ed542ace6d4 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -2040,7 +2040,7 @@ def greedy(self, a1, a2, method='by_recursion'): def oriented_exchange_graph(self): """ Return the oriented exchange graph of ``self`` as a directed - graph + graph. The seed must be a cluster seed for a cluster algebra of finite type with principal coefficients (the corresponding @@ -2080,23 +2080,24 @@ def oriented_exchange_graph(self): if not self._is_principal: raise TypeError('only works for principal coefficients') - mut_class = self.mutation_class() covers = [] - n = self.n() - pairs = [(i, j) for i in mut_class for j in mut_class if i != j] - for (i, j) in pairs: + stack = [self] + known_clusters = {} + while stack: + i = stack.pop() B = i.b_matrix() for k in range(n): - count = len([i2 for i2 in range(n, 2 * n) if B[i2][k] <= 0]) - green = (count == n) - NewS1 = i.mutate(k, inplace=False) - Var1 = [NewS1.cluster_variable(k) for k in range(n)] - Var1.sort() - Var2 = [j.cluster_variable(k) for k in range(n)] - Var2.sort() - if Var1 == Var2 and green and (i, j) not in covers: - covers.append((i, j)) + # check if green + if all(B[i2][k] >= 0 for i2 in range(n, 2 * n)): + j = i.mutate(k, inplace=False) + Varj = tuple(sorted(j.cluster())) + if Varj in known_clusters: + covers.append((i, known_clusters[Varj])) + else: + covers.append((i, j)) + known_clusters[Varj] = j + stack.append(j) return DiGraph(covers) From 66173bd0290a13e922a4ca0499f911e0646eb80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 13 Mar 2015 16:19:04 +0100 Subject: [PATCH 0127/1872] trac #17947 implement the cluster fans --- .../combinat/cluster_algebra_quiver/quiver.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 22416a4cec6..d1cb7eb21b0 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -1586,3 +1586,45 @@ def is_mutation_finite( self, nr_of_checks=None, return_path=False ): return is_finite, path else: return is_finite + + def fan(self): + """ + Return the cluster fan associated with the quiver. + + It only makes sense for acyclic quivers of finite type. + + This is defined using the denominator vectors of the cluster + variables. Cones are in correspondance with clusters and + rays with cluster variables. + + EXAMPLES:: + + sage: F = ClusterQuiver(DiGraph({0:[1]})).fan(); F + Rational polyhedral fan in 2-d lattice N + sage: F.ngenerating_cones() + 5 + + sage: F = ClusterQuiver(['A',3]).fan(); F + Rational polyhedral fan in 2-d lattice N + sage: F.ngenerating_cones() + 14 + + TESTS:: + + sage: ClusterQuiver(DiGraph({0:[1],1:[2],2:[0]})).fan() + Traceback (most recent call last): + ... + ValueError: only makes sense for acyclic quivers of finite type + """ + from cluster_seed import ClusterSeed + from sage.geometry.fan import Fan + from sage.geometry.cone import Cone + from sage.modules.free_module_element import vector + + if not(self.is_finite() and self.is_acyclic()): + raise ValueError('only makes sense for acyclic quivers' + ' of finite type') + seed = ClusterSeed(self) + return Fan([Cone([vector(v.almost_positive_root()) + for v in s.cluster()]) + for s in seed.mutation_class()]) From 07cd33c875465cff46f4d46dc3a14691eff85eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 13 Mar 2015 16:35:52 +0100 Subject: [PATCH 0128/1872] trac #17947 details about cluster fan --- src/sage/combinat/cluster_algebra_quiver/quiver.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index d1cb7eb21b0..637d37d83ab 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -1605,9 +1605,11 @@ def fan(self): 5 sage: F = ClusterQuiver(['A',3]).fan(); F - Rational polyhedral fan in 2-d lattice N + Rational polyhedral fan in 3-d lattice N sage: F.ngenerating_cones() 14 + sage: F.is_smooth() + True TESTS:: From 9628ba3adff463a4d57a030bd75a57ae2b7aea44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 16 Mar 2015 17:16:58 +0100 Subject: [PATCH 0129/1872] trac #17947 more doc --- .../combinat/cluster_algebra_quiver/quiver.py | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 637d37d83ab..ddfa2d4c306 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -1591,12 +1591,32 @@ def fan(self): """ Return the cluster fan associated with the quiver. - It only makes sense for acyclic quivers of finite type. + This is a complete simplicial (and even smooth) fan. It only makes + sense for acyclic quivers of finite type. - This is defined using the denominator vectors of the cluster + This fan is defined using the denominator vectors of the cluster variables. Cones are in correspondance with clusters and rays with cluster variables. + More precisely, starting from the seed made of the quiver `Q` + with `n` vertices and variables `x_1, ..., x_n`, one obtains + by iterating mutation a finite set of seeds. Each of these + seeds is made of a quiver and `n` cluster variables (that form + a cluster). + + Each cluster variable is mapped to a vector `d` in `\ZZ^n` by + using its denominator written as + + .. MATH:: + + \prod_{i=1}^{n} x_i^d_i. + + By convention the denominator of each initial variable `x_i` is + `x_i^{-1}`. + + Using this map, every cluster defines a cone in `\ZZ^n`. These + are the maximal cones of the cluster fan. + EXAMPLES:: sage: F = ClusterQuiver(DiGraph({0:[1]})).fan(); F @@ -1627,6 +1647,8 @@ def fan(self): raise ValueError('only makes sense for acyclic quivers' ' of finite type') seed = ClusterSeed(self) + # could maybe use a direct custom "denominator" function + # instead of going through almost_positive_roots return Fan([Cone([vector(v.almost_positive_root()) for v in s.cluster()]) for s in seed.mutation_class()]) From bdcd7a5dbfde7746a3e50a0d6e5d68fbbb05c2de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Fri, 20 Mar 2015 02:48:41 +0200 Subject: [PATCH 0130/1872] Dirty version added possible entry <=-1 and affine types recognition --- .../combinat/root_system/coxeter_matrix.py | 509 ++++++++++++++---- src/sage/combinat/root_system/coxeter_type.py | 22 +- 2 files changed, 406 insertions(+), 125 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 516e846d17a..e472f9e4022 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -24,15 +24,17 @@ from sage.matrix.matrix_space import MatrixSpace from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.matrix.matrix_integer_dense import Matrix_integer_dense +from sage.matrix.matrix_generic_dense import Matrix_generic_dense from sage.graphs.graph import Graph -from sage.rings.all import ZZ, QQ, RR +from sage.graphs.generators.basic import CycleGraph +from sage.rings.all import ZZ, QQ, QQbar, RR from sage.rings.infinity import infinity from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.coxeter_type import CoxeterType from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family -class CoxeterMatrix(Matrix_integer_dense, CoxeterType): +class CoxeterMatrix(Matrix_generic_dense, CoxeterType): """ A Coxeter matrix. @@ -90,13 +92,24 @@ class CoxeterMatrix(Matrix_integer_dense, CoxeterType): [ 1 3 -1] [ 3 1 4] [-1 4 1] + + It is possible to give a number `\leq -1` to represent an infinite label + + sage: CoxeterMatrix([[1,-1],[-1,1]]) + [ 1 -1] + [-1 1] + sage: CoxeterMatrix([[1,-3/2],[-3/2,1]]) + [ 1 -3/2] + [-3/2 1] + """ __metaclass__ = ClasscallMetaclass @staticmethod def __classcall_private__(cls, *args, **kwds): """ - Normalize input so we can inherit from dense integer matrix. + Normalize input so we can inherit from a dense matrix with the + appropriate ring. .. NOTE:: @@ -119,8 +132,18 @@ def __classcall_private__(cls, *args, **kwds): sage: W2 = CoxeterMatrix(G) sage: W1 == W2 True - sage: CoxeterMatrix(W1.coxeter_diagram()) == W1 + sage: CoxeterMatrix(W1.coxeter_graph()) == W1 True + + The base ring of the matrix depends on the entries given:: + + sage: CoxeterMatrix([[1,-1],[-1,1]]).base_ring() + Integer Ring + sage: CoxeterMatrix([[1,-3/2],[-3/2,1]]).base_ring() + Rational Field + sage: CoxeterMatrix([[1,-1.5],[-1.5,1]]).base_ring() + Real Field with 53 bits of precision + """ # Special cases with 0 args if not args: @@ -128,6 +151,7 @@ def __classcall_private__(cls, *args, **kwds): args = ( CoxeterType(kwds["coxeter_type"]), ) elif "cartan_type" in kwds: # kwds has Cartan type args = ( CoxeterType(CartanType(kwds["cartan_type"])), ) + base_ring = ZZ if not args: data = [] @@ -135,6 +159,7 @@ def __classcall_private__(cls, *args, **kwds): index_set = tuple() coxeter_type = None subdivisions = None + base_ring = ZZ elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling return typecall(cls, args[0], args[1], args[2], args[3]) @@ -145,6 +170,7 @@ def __classcall_private__(cls, *args, **kwds): coxeter_type = None subdivisions = None index_set = None + base_ring = ZZ from sage.combinat.root_system.cartan_type import CartanType_abstract if isinstance(args[0], CartanType_abstract): @@ -154,23 +180,37 @@ def __classcall_private__(cls, *args, **kwds): n = G.num_verts() # Setup the basis matrix as all 2 except 1 on the diagonal - data = MatrixSpace(ZZ, n)([2]*(n*n)) + data = [] for i in range(n): - data[i, i] = ZZ.one() - + data += [[]] + for j in range(n): + if i == j: + data[-1] += [ZZ.one()] + else: + data[-1] += [2] + + list_rings = [ZZ, QQ, QQbar, RR] + index_ring = 0 + index_list = [] verts = sorted(G.vertices()) for e in G.edges(): m = e[2] if m is None: m = 3 - elif m == infinity or m == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\} + elif m == infinity: m = -1 - elif m <= 1: + elif m not in ZZ and m > -1: + raise ValueError("invalid Coxeter graph label") + elif m == 0 or m == 1: raise ValueError("invalid Coxeter graph label") i = verts.index(e[0]) j = verts.index(e[1]) - data[j, i] = data[i, j] = m - + data[j][i] = data[i][j] = m + new_index = min(index for index in range(len(list_rings)) if m in list_rings[index]) + if new_index > index_ring: + index_ring = new_index + base_ring = list_rings[index_ring] + data = MatrixSpace(base_ring,n)(data) index_set = tuple(verts) args = [data] else: @@ -184,7 +224,7 @@ def __classcall_private__(cls, *args, **kwds): n = len(index_set) reverse = {index_set[i]: i for i in range(n)} data = [[1 if i == j else 2 for j in range(n)] for i in range(n)] - for (i,j,l) in coxeter_type.coxeter_diagram().edge_iterator(): + for (i,j,l) in coxeter_type.coxeter_graph().edge_iterator(): if l == infinity: l = -1 data[reverse[i]][reverse[j]] = l @@ -192,6 +232,7 @@ def __classcall_private__(cls, *args, **kwds): data = [val for row in data for val in row] else: M = matrix(args[0]) + base_ring = M.base_ring() check_coxeter_matrix(M) n = M.ncols() if "coxeter_type" in kwds: @@ -220,7 +261,7 @@ def __classcall_private__(cls, *args, **kwds): if len(set(index_set)) != n: raise ValueError("the given index set is not valid") - mat = typecall(cls, MatrixSpace(ZZ, n, sparse=False), data, + mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), data, coxeter_type, index_set) mat._subdivisions = subdivisions return mat @@ -234,8 +275,12 @@ def __init__(self, parent, data, coxeter_type, index_set): sage: C = CoxeterMatrix(['A', 2, 1]) sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) """ - Matrix_integer_dense.__init__(self, parent, data, False, True) + Matrix_generic_dense.__init__(self, parent, data, False, True) + if min(data)<-1: + self._is_cyclotomic = False + else: + self._is_cyclotomic = True self._coxeter_type = coxeter_type self._index_set = index_set self.set_immutable() @@ -320,19 +365,32 @@ def coxeter_matrix(self): """ return self + @cached_method # Transferred the caching here from CoxeterType + def bilinear_form(self): + r""" + Return the bilinear form of ``self``. + + EXAMPLES:: + """ + + if self._is_cyclotomic: + return super(CoxeterMatrix, self).bilinear_form() + else: + return super(CoxeterMatrix, self).bilinear_form(R=RR) #FIXME put the right ring + @cached_method - def coxeter_diagram(self): + def coxeter_graph(self): """ - Return the Coxeter diagram of ``self``. + Return the Coxeter graph of ``self``. EXAMPLES:: sage: C = CoxeterMatrix(['A',3]) - sage: C.coxeter_diagram() + sage: C.coxeter_graph() Graph on 3 vertices sage: C = CoxeterMatrix([['A',3],['A',1]]) - sage: C.coxeter_diagram() + sage: C.coxeter_graph() Graph on 4 vertices """ n = self.nrows() @@ -424,9 +482,14 @@ def is_affine(self): ... NotImplementedError """ - if self._coxeter_type is not None: + if self._coxeter_type is not None: return self._coxeter_type.is_affine() - raise NotImplementedError + else: + return False + # if self.bilinear_form().rank() == self.rank() - 1 and self.bilinear_form().determinant() == 0: + # return True + # else: + # return False ##################################################################### ## Type check functions @@ -436,10 +499,6 @@ def find_coxeter_type_from_matrix(coxeter_matrix): Return the Coxeter type of ``coxeter_matrix`` if known, otherwise return ``None``. - .. TODO:: - - Check for more affine types. - EXAMPLES: Some infinite ones:: @@ -459,13 +518,68 @@ def find_coxeter_type_from_matrix(coxeter_matrix): sage: m = matrix(CoxeterMatrix(['H', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True + + sage: CoxeterMatrix(CoxeterType(['A',10]).coxeter_graph()).coxeter_type() + Coxeter type of ['A', 10] + sage: CoxeterMatrix(CoxeterType(['B',10]).coxeter_graph()).coxeter_type() + Coxeter type of ['B', 10] + sage: CoxeterMatrix(CoxeterType(['C',10]).coxeter_graph()).coxeter_type() + Coxeter type of ['B', 10] + sage: CoxeterMatrix(CoxeterType(['D',10]).coxeter_graph()).coxeter_type() + Coxeter type of ['D', 10] + sage: CoxeterMatrix(CoxeterType(['E',6]).coxeter_graph()).coxeter_type() + Coxeter type of ['E', 6] + sage: CoxeterMatrix(CoxeterType(['E',7]).coxeter_graph()).coxeter_type() + Coxeter type of ['E', 7] + sage: CoxeterMatrix(CoxeterType(['E',8]).coxeter_graph()).coxeter_type() + Coxeter type of ['E', 8] + sage: CoxeterMatrix(CoxeterType(['F',4]).coxeter_graph()).coxeter_type() + Coxeter type of ['F', 4] + sage: CoxeterMatrix(CoxeterType(['G',2]).coxeter_graph()).coxeter_type() + Coxeter type of ['G', 2] + sage:CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() + Coxeter type of ['I', 100] + sage: CoxeterMatrix(CoxeterType(['H',3]).coxeter_graph()).coxeter_type() + Coxeter type of ['H', 3] + sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type() + Coxeter type of ['H', 4] + + + Some affine graphs:: + + sage: CoxeterMatrix(CoxeterType(['A',3,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['A', 3, 1] + sage: CoxeterMatrix(CoxeterType(['B',3,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['B', 3, 1] + sage: CoxeterMatrix(CoxeterType(['C',3,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['C', 3, 1] + sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['F', 4, 1] + + + sage: CoxeterMatrix(CoxeterType(['A',10,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['A', 10, 1] + sage: CoxeterMatrix(CoxeterType(['B',10,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['B', 10, 1] + sage: CoxeterMatrix(CoxeterType(['C',10,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['C', 10, 1] + sage: CoxeterMatrix(CoxeterType(['D',10,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['D', 10, 1] + sage: CoxeterMatrix(CoxeterType(['E',6,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['E', 6, 1] + sage: CoxeterMatrix(CoxeterType(['E',7,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['E', 7, 1] + sage: CoxeterMatrix(CoxeterType(['E',8,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['E', 8, 1] + """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) G = Graph([range(n), lambda i,j: coxeter_matrix[i, j] not in [1,2]]) # Coxeter graphs of finite Coxeter groups are forests - if not(G.is_forest()): - return None + # Coxeter graphs of affine Coxeter groups are forests possibly with cycle + # graphs + comps = G.connected_components() # The group is finite if and only if for every connected # component ``comp`` of its Coxeter graph, the submatrix of @@ -475,41 +589,65 @@ def find_coxeter_type_from_matrix(coxeter_matrix): types = [] for comp in comps: l = len(comp) + G0 = G.subgraph(comp) if l == 1: # Any `1 \times 1` Coxeter matrix gives a finite group. types.append(['A',1]) continue # A1 elif l == 2: # A finite dihedral group iff there is no `\infty` in its - # Coxeter matrix. Otherwise we consider it type A1~. + # Coxeter matrix. Otherwise it is affine iff the + # off-diagonal value is -1. c0, c1 = comp if coxeter_matrix[c0, c1] > 0: types.append(['I', coxeter_matrix[c0, c1]]) - else: + continue + elif coxeter_matrix[c0, c1] == -1: types.append(['A', 1, 1]) + continue + else: + return None elif l == 3: # The `3`-node case. The finite groups to check for # here are `A_3`, `B_3` and `H_3`. + # The affine groups to check for here are `A_{2,1}`, `G_{2,1}`, + # `B_{2,1}`. c0, c1, c2 = comp s = sorted([coxeter_matrix[c0, c1], coxeter_matrix[c0, c2], coxeter_matrix[c1, c2]]) - if s[1] == 3: - if s[2] == 3: - types.append(['A',3]) - elif s[2] == 4: - types.append(['B',3]) - elif s[2] == 5: - types.append(['H',3]) - elif s[2] == 6: - types.append(['G',2,1]) + if s[0] == 2: #Have a tree + if s[1] == 3: + if s[2] == 3: + types.append(['A',3]) + continue + elif s[2] == 4: + types.append(['B',3]) + continue + elif s[2] == 5: + types.append(['H',3]) + continue + elif s[2] == 6: + types.append(['G',2,1]) + continue + else: + return None + elif s[1] == 4 and s[2] == 4: + types.append(['B',2,1]) + continue else: return None + elif s[0] == 3 and s[1] == 3 and s[2] == 3: + types.append(['A',2,1]) continue - return None + else: + return None elif l == 4: # The `4`-node case. The finite groups to check for # here are `A_4`, `B_4`, `D_4`, `F_4` and `H_4`. + # The affine groups to check for here are `A_{3,1}`, `B_{3,1}`, + # and `C_{3,1}`. + c0, c1, c2, c3 = comp u = [coxeter_matrix[c0, c1], coxeter_matrix[c0, c2], @@ -521,88 +659,231 @@ def find_coxeter_type_from_matrix(coxeter_matrix): # ``s`` is the list of all off-diagonal entries of # the ``comp``-submatrix of the Coxeter matrix, # sorted in increasing order. - if s[3:5] == [3, 3]: - if s[5] == 3: - if max(G.degree()) == 2: + + if s[:3] == [2, 2, 2]: + if s[3:] == [3, 3, 3]: + if max(G0.degree()) == 2: types.append(['A',4]) + continue else: types.append(['D',4]) - continue # A4, D4 - if s[5] in [4, 5]: - u0 = u[0] + u[1] + u[2] - u1 = u[0] + u[3] + u[4] - u2 = u[1] + u[3] + u[5] - u3 = u[2] + u[4] + u[5] - ss = sorted([u0, u1, u2, u3]) - if ss == [7, 7, 9, 9]: - types.append(['F',4]) - continue - elif ss == [7, 8, 8, 9]: - types.append(['B',4]) - continue - elif ss == [7, 8, 9, 10]: - types.append(['H',4]) continue + elif s[3:] == [3, 3, 4] or s[3:] == [3, 3, 5] or s[3:] == [3, + 4, 4]: + if max(G0.degree()) == 3: + if s[4:] == [3, 4]: + types.append(['B', 3, 1]) + continue + else: + return None + else: # The graph is a path + # Differenciate using sum of edge labels + u0 = u[0] + u[1] + u[2] + u1 = u[0] + u[3] + u[4] + u2 = u[1] + u[3] + u[5] + u3 = u[2] + u[4] + u[5] + ss = sorted([u0, u1, u2, u3]) + if s[5] == 4: + if ss == [7, 7, 9, 9]: + types.append(['F',4]) + continue + elif ss == [7, 8, 8, 9]: + types.append(['B',4]) + continue + elif ss == [8, 8, 9, 9]: + types.append(['C',3,1]) + continue + else: + return None + elif ss == [7, 8, 9, 10]: + types.append(['H',4]) + continue + else: + return None + + else: + return None + + elif s == [2, 2, 3, 3, 3, 3] and max(G0.degree()) == 2: + types.append(['A',3,1]) + continue + else: + return None return None else: # The case of `l \geq 5` nodes. The finite # groups to check for here are `A_l`, `B_l`, `D_l`, # and `E_l` (for `l = 6, 7, 8`). - # Checking that the Coxeter matrix of the subgroup - # corresponding to the vertices ``comp`` has all its - # off-diagonal entries equal to 2, 3 or at most once 4 - found_a_4 = False - for j in range(l): - for i in range(j): - coxeter_entry = coxeter_matrix[comp[i], comp[j]] - if coxeter_entry in [2, 3]: - continue - if coxeter_entry == 4 and not found_a_4: - found_a_4 = True - continue + # The affine groups to check for here are `A_{l-1,1}`, `B_{l-1,1}`, + # `C_{l-1,1}`, `D_{l-1,1}`, `E_{l_1,1}` (for `l = 6, 7, 8`), + # or `F_{4,1}`. + + degrees = G0.degree() + vertices= G0.vertices() + sub_cox_matrix = coxeter_matrix.matrix_from_rows_and_columns(vertices,vertices) + vertices_labels = [set(filter(lambda x: x != 1, r)) for r in + sub_cox_matrix.rows()] + label_list = filter(lambda x: x != 1, sub_cox_matrix.list()) + labels = sorted(set(label_list)) + + vertices_4 = [index for index in range(l) if 4 in + vertices_labels[index]] + occur_4 = label_list.count(4)/2 # Each label appear twice + + if not G0.is_tree(): + if G0.is_isomorphic(CycleGraph(l)): # Type `A_{l-1,1}` + types.append(['A',l-1,1]) + continue + else: return None + + elif max(degrees) == 2: # The component is a path + + + if labels[-1] == 3: # Highest label is 3 + types.append(['A',l]) + continue + elif labels[-1] == 4: # Highest label is 4 + + if occur_4 == 1: # There is 1 edge with label 4 + if not (3 in vertices_labels[vertices_4[0]] and 3 in + vertices_labels[vertices_4[1]]): # The edge is at the end of the path + types.append(['B',l]) + continue + elif l == 5: + types.append(['F',4,1]) + continue + else: + return None + elif occur_4 == 2: # There are 2 edges labeled 4 + if len(filter(lambda x: 2 in x and 3 not in x and 4 in + x, [vertices_labels[i] for i in vertices_4])) == 2: + # The edges with 4 are at the ends of the path + types.append(['C',l-1,1]) + continue + else: + return None + else: + return None + - G0 = G.subgraph(comp) - if found_a_4: - # The case when a `4` has been found in the - # Coxeter matrix. This needs only to be checked - # against `B_l`. We use the observation that - # the group is `B_l` if and only if the Coxeter - # graph is an `l`-path (i.e., has diameter - # `l - 1`) and the `4` corresponds to one of - # its two outermost edges. - diameter = G0.diameter() - if diameter != l - 1: + else: # The graph contains branching vertices + + #Finite D_n,E_6,E_7,E_8 + #Affine B_n,D_n, E_6,E_7,E_8 + + if max(degrees) == 3: # Branching degree is 3 + + highest_label = labels[-1] + + nb_branching = degrees.count(3) + ecc = sorted(G0.eccentricity()) + + if nb_branching == 1: + + if highest_label == 3: + + if ecc[-3] == l - 2: + types.append(['D', l]) + continue # Dl + elif l <= 9 and ecc[-2] == l - 2 and ecc[-5] == l - 3: + if l <= 8: #E_{6,7,8} + types.append(['E', l]) + continue + else: #E_{8,1} + types.append(['E',l-1,1]) + continue + elif l <= 8 and ecc[0] == l-5 and ecc[-3] == l-3: + #TO TEST + types.append(['E',l-1,1]) + continue + else: + return None + + elif highest_label == 4: + if ecc[-3] == l - 2 and occur_4 == 1: # D_n graph + # and 1 occurence of label 4 + if not (3 in vertices_labels[vertices_4[0]] and 3 in vertices_labels[vertices_4[1]]) and 3 not in G0.degree(vertices=vertices_4): + # Edge with label 4 is at the end and not + # on a degree 3 vertex. + types.append(['B',l-1,1]) + continue + else: + return None + + elif nb_branching == 2: + if highest_label == 3: + if ecc[-4] == l - 3: + types.append(['D',l-1,1]) + continue + else: + return None + + else: # Highest label too high + return None + + else: # Nb of branching too high + return None + + else: # Branching degree too high return None - ecc = sorted(((u, v) for (v, u) in G0.eccentricity(with_labels=True).items())) - left_end = ecc[-1][1] - right_end = ecc[-2][1] - left_almost_end = G0.neigbors(left_end)[0] - right_almost_end = G0.neigbors(right_end)[0] - if (coxeter_matrix[left_end, left_almost_end] == 4 - or coxeter_matrix[right_end, right_almost_end] == 4): - types.append(['B', l]) - continue # Bl - return None - # Now, all off-diagonal entries of the Coxeter matrix - # are 2's and 3's. We need to check our group against - # `A_l`, `D_l` and `E_l`. Knowing that the Coxeter - # graph is a tree, we can use its vertex - # eccentricities to check this. - ecc = sorted(G0.eccentricity()) - if ecc[-1] == l - 1: - types.append(['A', l]) - continue # Al - if ecc[-3] == l - 2: - types.append(['D', l]) - continue # Dl - if l <= 8 and ecc[-2] == l - 2 and ecc[-5] == l - 3: - types.append(['E', l]) - continue # El - return None + # # Checking that the Coxeter matrix of the subgroup + # # corresponding to the vertices ``comp`` has all its + # # off-diagonal entries equal to 2, 3 or at most once 4 + # found_a_4 = False + # for j in range(l): + # for i in range(j): + # coxeter_entry = coxeter_matrix[comp[i], comp[j]] + # if coxeter_entry in [2, 3]: + # continue + # if coxeter_entry == 4 and not found_a_4: + # found_a_4 = True + # continue + # return None + # + # G0 = G.subgraph(comp) + # if found_a_4: + # # The case when a `4` has been found in the + # # Coxeter matrix. This needs only to be checked + # # against `B_l`. We use the observation that + # # the group is `B_l` if and only if the Coxeter + # # graph is an `l`-path (i.e., has diameter + # # `l - 1`) and the `4` corresponds to one of + # # its two outermost edges. + # diameter = G0.diameter() + # if diameter != l - 1: + # return None + # + # ecc = sorted(((u, v) for (v, u) in G0.eccentricity(with_labels=True).items())) + # left_end = ecc[-1][1] + # right_end = ecc[-2][1] + # left_almost_end = G0.neigbors(left_end)[0] + # right_almost_end = G0.neigbors(right_end)[0] + # if (coxeter_matrix[left_end, left_almost_end] == 4 + # or coxeter_matrix[right_end, right_almost_end] == 4): + # types.append(['B', l]) + # continue # Bl + # return None + # + # # Now, all off-diagonal entries of the Coxeter matrix + # # are 2's and 3's. We need to check our group against + # # `A_l`, `D_l` and `E_l`. Knowing that the Coxeter + # # graph is a tree, we can use its vertex + # # eccentricities to check this. + # ecc = sorted(G0.eccentricity()) + # if ecc[-1] == l - 1: + # types.append(['A', l]) + # continue # Al + # if ecc[-3] == l - 2: + # types.append(['D', l]) + # continue # Dl + # if l <= 8 and ecc[-2] == l - 2 and ecc[-5] == l - 3: + # types.append(['E', l]) + # continue # El + # return None if len(types) == 1: types = types[0] @@ -613,7 +894,8 @@ def find_coxeter_type_from_matrix(coxeter_matrix): def check_coxeter_matrix(m): """ - Check if ``m`` represents a Coxeter matrix and raise and error if not. + Check if ``m`` represents a generalized Coxeter matrix and raise + and error if not. EXAMPLES:: @@ -639,12 +921,7 @@ def check_coxeter_matrix(m): ... ValueError: the matrix is not symmetric - sage: m = matrix([[1,3,2],[3,1,-2],[2,-2,1]]) - sage: check_coxeter_matrix(m) - Traceback (most recent call last): - ... - ValueError: invalid Coxeter label -2 - """ + """ if not m.is_square(): raise ValueError("not a square matrix") for i, row in enumerate(m.rows()): @@ -653,8 +930,12 @@ def check_coxeter_matrix(m): for j, val in enumerate(row[i+1:]): if val != m[j+i+1,i]: raise ValueError("the matrix is not symmetric") - if val <= 1 and val != -1: - raise ValueError("invalid Coxeter label {}".format(val)) + if val not in ZZ: + if val > -1: + raise ValueError("invalid Coxeter label {}".format(val)) + else: + if val == 1 or val == 0: + raise ValueError("invalid Coxeter label {}".format(val)) def coxeter_matrix_as_function(t): """ diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index a900ddce3a2..9fe35493b28 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -57,7 +57,7 @@ def rank(self): """ Return the rank of ``self``. - This is the number of nodes of the associated Coxeter diagram. + This is the number of nodes of the associated Coxeter graph. EXAMPLES:: @@ -74,7 +74,7 @@ def index_set(self): """ Return the index set for ``self``. - This is the list of the nodes of the associated Coxeter diagram. + This is the list of the nodes of the associated Coxeter graph. EXAMPLES:: @@ -121,15 +121,15 @@ def coxeter_matrix(self): """ @abstract_method - def coxeter_diagram(self): + def coxeter_graph(self): """ - Return the Coxeter diagram associated to ``self``. + Return the Coxeter graph associated to ``self``. EXAMPLES:: - sage: CoxeterType(['A', 3]).coxeter_diagram() + sage: CoxeterType(['A', 3]).coxeter_graph() Graph on 3 vertices - sage: CoxeterType(['A', 3, 1]).coxeter_diagram() + sage: CoxeterType(['A', 3, 1]).coxeter_graph() Graph on 4 vertices """ @@ -207,7 +207,7 @@ def is_simply_laced(self): """ return False - @cached_method +# @cached_method def bilinear_form(self, R=None): """ Return the bilinear form over ``R`` associated to ``self``. @@ -242,7 +242,7 @@ def bilinear_form(self, R=None): else: from sage.functions.trig import cos from sage.symbolic.constants import pi - val = lambda x: -R(cos(pi / x)) if x != -1 else -R.one() + val = lambda x: -R(cos(pi / x)) if x > -1 else x n = self.rank() MS = MatrixSpace(R, n, sparse=True) @@ -315,14 +315,14 @@ def coxeter_matrix(self): """ return self._cartan_type.coxeter_matrix() - def coxeter_diagram(self): + def coxeter_graph(self): """ - Return the Coxeter digramh of ``self``. + Return the Coxeter graph of ``self``. EXAMPLES:: sage: C = CoxeterType(['H',3]) - sage: C.coxeter_diagram().edges() + sage: C.coxeter_graph().edges() [(1, 2, 3), (2, 3, 5)] """ return self._cartan_type.coxeter_diagram() From 77189dda033a4bf2bfec212de8c9f987bd078a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Fri, 20 Mar 2015 23:06:04 +0200 Subject: [PATCH 0131/1872] Corrected base ring of the Coxeter matrix --- src/sage/combinat/root_system/coxeter_matrix.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index e472f9e4022..b9fc008869d 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -4,6 +4,7 @@ #***************************************************************************** # Copyright (C) 2007 Mike Hansen , # 2015 Travis Scrimshaw +# 2015 Jean-Philippe Labbe # # Distributed under the terms of the GNU General Public License (GPL) # @@ -27,7 +28,7 @@ from sage.matrix.matrix_generic_dense import Matrix_generic_dense from sage.graphs.graph import Graph from sage.graphs.generators.basic import CycleGraph -from sage.rings.all import ZZ, QQ, QQbar, RR +from sage.rings.all import ZZ, RR from sage.rings.infinity import infinity from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.coxeter_type import CoxeterType @@ -189,9 +190,6 @@ def __classcall_private__(cls, *args, **kwds): else: data[-1] += [2] - list_rings = [ZZ, QQ, QQbar, RR] - index_ring = 0 - index_list = [] verts = sorted(G.vertices()) for e in G.edges(): m = e[2] @@ -206,10 +204,7 @@ def __classcall_private__(cls, *args, **kwds): i = verts.index(e[0]) j = verts.index(e[1]) data[j][i] = data[i][j] = m - new_index = min(index for index in range(len(list_rings)) if m in list_rings[index]) - if new_index > index_ring: - index_ring = new_index - base_ring = list_rings[index_ring] + base_ring = (base_ring.one()*m).parent() data = MatrixSpace(base_ring,n)(data) index_set = tuple(verts) args = [data] @@ -606,7 +601,7 @@ def find_coxeter_type_from_matrix(coxeter_matrix): types.append(['A', 1, 1]) continue else: - return None + return None #TODO: return hyperbolic type once implemented elif l == 3: # The `3`-node case. The finite groups to check for # here are `A_3`, `B_3` and `H_3`. From f135c2e42d8aaf70385795f480b8f64089243a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Sat, 21 Mar 2015 03:10:06 +0200 Subject: [PATCH 0132/1872] Corrected the bilinear form method --- .../combinat/root_system/coxeter_matrix.py | 28 +++++++++---------- src/sage/combinat/root_system/coxeter_type.py | 21 +++++++++----- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index b9fc008869d..cc826e6e835 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -28,7 +28,7 @@ from sage.matrix.matrix_generic_dense import Matrix_generic_dense from sage.graphs.graph import Graph from sage.graphs.generators.basic import CycleGraph -from sage.rings.all import ZZ, RR +from sage.rings.all import ZZ, QQ, RR from sage.rings.infinity import infinity from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.coxeter_type import CoxeterType @@ -43,6 +43,8 @@ class CoxeterMatrix(Matrix_generic_dense, CoxeterType): Because there is no object `\ZZ \cup \{ \infty \}`, we define `-1` to represent `\infty`. + Make it possible to input algebraic number in the matrix and have the + corresponding base ring EXAMPLES:: @@ -227,8 +229,8 @@ def __classcall_private__(cls, *args, **kwds): data = [val for row in data for val in row] else: M = matrix(args[0]) + check_coxeter_matrix(args[0]) base_ring = M.base_ring() - check_coxeter_matrix(M) n = M.ncols() if "coxeter_type" in kwds: coxeter_type = CoxeterType(kwds["coxeter_type"]) @@ -272,7 +274,7 @@ def __init__(self, parent, data, coxeter_type, index_set): """ Matrix_generic_dense.__init__(self, parent, data, False, True) - if min(data)<-1: + if self.base_ring() not in [ZZ,QQ]: self._is_cyclotomic = False else: self._is_cyclotomic = True @@ -360,7 +362,6 @@ def coxeter_matrix(self): """ return self - @cached_method # Transferred the caching here from CoxeterType def bilinear_form(self): r""" Return the bilinear form of ``self``. @@ -368,10 +369,7 @@ def bilinear_form(self): EXAMPLES:: """ - if self._is_cyclotomic: - return super(CoxeterMatrix, self).bilinear_form() - else: - return super(CoxeterMatrix, self).bilinear_form(R=RR) #FIXME put the right ring + return CoxeterType.bilinear_form(self) @cached_method def coxeter_graph(self): @@ -916,17 +914,19 @@ def check_coxeter_matrix(m): ... ValueError: the matrix is not symmetric - """ - if not m.is_square(): + """ + + mat=matrix(m) + if not mat.is_square(): raise ValueError("not a square matrix") - for i, row in enumerate(m.rows()): - if m[i,i] != 1: + for i, row in enumerate(m): + if mat[i,i] != 1: raise ValueError("the matrix diagonal is not all 1") for j, val in enumerate(row[i+1:]): - if val != m[j+i+1,i]: + if val != m[j+i+1][i]: raise ValueError("the matrix is not symmetric") if val not in ZZ: - if val > -1: + if val > -1 and val in RR: raise ValueError("invalid Coxeter label {}".format(val)) else: if val == 1 or val == 0: diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 9fe35493b28..87b826f78ff 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -21,7 +21,8 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.combinat.root_system.cartan_type import CartanType from sage.matrix.all import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.all import ZZ, QQ +from sage.symbolic.ring import SR from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject from sage.combinat.root_system.cartan_type import CartanType @@ -207,7 +208,7 @@ def is_simply_laced(self): """ return False -# @cached_method + @cached_method def bilinear_form(self, R=None): """ Return the bilinear form over ``R`` associated to ``self``. @@ -233,21 +234,27 @@ def bilinear_form(self, R=None): [-1 1 -1] [-1 -1 1] """ + + n = self.rank() + mat = self.coxeter_matrix() + base_ring = sum(mat.list()).parent() + from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField - if R is None: + if base_ring in [ZZ,QQ]: R = UniversalCyclotomicField() + else: + R = base_ring # Compute the matrix with entries `- \cos( \pi / m_{ij} )`. if R is UniversalCyclotomicField(): - val = lambda x: (R.gen(2*x) + ~R.gen(2*x)) / R(-2) if x != -1 else -R.one() + val = lambda x: (R.gen(2*x) + ~R.gen(2*x)) / R(-2) if x > -1 else R.one()*x else: from sage.functions.trig import cos from sage.symbolic.constants import pi - val = lambda x: -R(cos(pi / x)) if x > -1 else x + val = lambda x: -R(cos(pi / SR(x))) if x > -1 else x - n = self.rank() MS = MatrixSpace(R, n, sparse=True) MC = MS._get_matrix_class() - mat = self.coxeter_matrix() + bilinear = MC(MS, entries={(i, j): val(mat[i, j]) for i in range(n) for j in range(n) if mat[i, j] != 2}, From f44e52fb40292424c439d90e29ddf0d3c0256b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Sat, 21 Mar 2015 03:38:05 +0200 Subject: [PATCH 0133/1872] Now asks for a coercion map from base ring in bilinear form --- src/sage/combinat/root_system/coxeter_type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 87b826f78ff..37b758b2d9c 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -240,7 +240,7 @@ def bilinear_form(self, R=None): base_ring = sum(mat.list()).parent() from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField - if base_ring in [ZZ,QQ]: + if UniversalCyclotomicField.has_coerce_map_from(base_ring): R = UniversalCyclotomicField() else: R = base_ring From ba6d80f844a11b373c09198192272fed6a72de9d Mon Sep 17 00:00:00 2001 From: MariaMonks Date: Fri, 20 Mar 2015 22:06:01 -0400 Subject: [PATCH 0134/1872] skew rectification optimization! --- src/sage/combinat/skew_tableau.py | 36 +++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index e0cd3671649..9fc43cdccff 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -42,7 +42,7 @@ from sage.combinat.combinat import CombinatorialObject from sage.combinat.partition import Partition -from sage.combinat.tableau import TableauOptions +from sage.combinat.tableau import TableauOptions, Tableaux, SemistandardTableau, StandardTableau, Tableau from sage.combinat.skew_partition import SkewPartition, SkewPartitions from sage.combinat.integer_vector import IntegerVectors from sage.combinat.words.words import Words @@ -761,7 +761,7 @@ def slide(self, corner=None): return SkewTableau(new_st) - def rectify(self): + def rectify(self, force=None): """ Return a :class:`Tableau` formed by applying the jeu de taquin process to ``self``. See page 15 of [FW]_. @@ -772,6 +772,11 @@ def rectify(self): *Young Tableaux*, Cambridge University Press 1997. + INPUT: + - ``force`` -- optional: if set to ``'jdt'``, rectifies by jeu de taquin; + if set to ``'schensted'``, rectifies by Schensted insertion of the + reading word; otherwise, guesses which will be faster. + EXAMPLES:: sage: s = SkewTableau([[None,1],[2,3]]) @@ -779,20 +784,33 @@ def rectify(self): [[1, 3], [2]] sage: SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]]).rectify() [[1, 3, 4, 6], [2, 5]] + sage: SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]]).rectify('jdt') + [[1, 3, 4, 6], [2, 5]] + sage: SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]]).rectify('schensted') + [[1, 3, 4, 6], [2, 5]] TESTS:: sage: s [[None, 1], [2, 3]] """ - rect = copy.deepcopy(self) - inner_corners = rect.inner_shape().corners() - - while len(inner_corners) > 0: - rect = rect.slide() + labda = self.outer_shape() + musize = self.inner_shape().size() + labdasize = labda.size() + if force == 'jdt' or (force != 'schensted' and musize < len(labda) * (labdasize - musize)**(1/2)): + rect = self inner_corners = rect.inner_shape().corners() - - return rect.to_tableau() + while len(inner_corners) > 0: + rect = rect.slide() + inner_corners = rect.inner_shape().corners() + else: + w = self.to_word() + rect = Tableau([]).insert_word(w) + if self in SemistandardSkewTableaux(): + return SemistandardTableau(rect[:]) + if self in StandardSkewTableaux(): + return StandardTableau(rect[:]) + return Tableau(rect) def standardization(self, check=True): r""" From 752df7798b2ae6b9afc60528227b4e88c745fae9 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 18:16:36 +0100 Subject: [PATCH 0135/1872] Revert the cached_method decorators from commit "possibly controversial: graded_algebra and the three methods forming its interface are now cached_methods" This reverts most of commit 03bd4cfb53e24b24c65aada21f08850b40fb5c5c. --- .../categories/filtered_algebras_with_basis.py | 5 ----- src/sage/categories/graded_algebras_with_basis.py | 14 ++++++-------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 22832812521..62f24559a0e 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -17,7 +17,6 @@ #****************************************************************************** from sage.categories.filtered_modules import FilteredModulesCategory -from sage.misc.cachefunc import cached_method class FilteredAlgebrasWithBasis(FilteredModulesCategory): """ @@ -46,7 +45,6 @@ class FilteredAlgebrasWithBasis(FilteredModulesCategory): sage: TestSuite(C).run() """ class ParentMethods: - @cached_method def graded_algebra(self): r""" Return the associated graded algebra to ``self``. @@ -116,7 +114,6 @@ def graded_algebra(self): # Maps - @cached_method def to_graded_conversion(self): r""" Return the canonical `R`-module isomorphism @@ -144,7 +141,6 @@ def to_graded_conversion(self): return self.module_morphism(diagonal=lambda x: base_one, codomain=self.graded_algebra()) - @cached_method def from_graded_conversion(self): r""" Return the inverse of the canonical `R`-module isomorphism @@ -174,7 +170,6 @@ def from_graded_conversion(self): return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, codomain=self) - @cached_method def projection(self, i): r""" Return the `i`-th projection `p_i : F_i \to G_i` (in the diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index f6b8dce4513..949fceddfb3 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -10,7 +10,6 @@ #****************************************************************************** from sage.categories.graded_modules import GradedModulesCategory -from sage.misc.cachefunc import cached_method class GradedAlgebrasWithBasis(GradedModulesCategory): """ @@ -32,7 +31,6 @@ class GradedAlgebrasWithBasis(GradedModulesCategory): class ParentMethods: # This needs to be copied in GradedAlgebras because we need to have # FilteredAlgebrasWithBasis as an extra super category - @cached_method def graded_algebra(self): """ Return the associated graded algebra to ``self``. @@ -77,12 +75,12 @@ def graded_algebra(self): return self # .. TODO:: - # Possibly override ``to_graded_conversion`` and - # ``from_graded_conversion`` with identity morphisms? - # I have to admit I don't know the right way to construct - # identity morphisms other than using the identity matrix. - # Also, ``projection`` could be overridden by, well, a - # projection. + # Possibly override ``to_graded_conversion`` and + # ``from_graded_conversion`` with identity morphisms? + # I have to admit I don't know the right way to construct + # identity morphisms other than using the identity matrix. + # Also, ``projection`` could be overridden by, well, a + # projection. class ElementMethods: pass From dfaaaeb6d9652e071ea89c9854da984bc8ada319 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 19:41:08 +0100 Subject: [PATCH 0136/1872] associated-graded now also defined for filtered *modules*, although still named 'graded algebra' in this case --- src/sage/algebras/associated_graded.py | 43 +- .../categories/filtered_modules_with_basis.py | 401 ++++++++++++++++++ 2 files changed, 436 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index f286964aa95..a86df92acbf 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -16,16 +16,16 @@ from sage.misc.cachefunc import cached_method from copy import copy -from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.categories.modules_with_basis import ModulesWithBasis from sage.sets.family import Family from sage.combinat.free_module import CombinatorialFreeModule class AssociatedGradedAlgebra(CombinatorialFreeModule): r""" - The associated graded algebra `\operatorname{gr} A` - of a filtered algebra with basis `A`. + The associated graded algebra/module `\operatorname{gr} A` + of a filtered algebra/module with basis `A`. - Let `A` be a filtered algebra over a commutative ring `R`. + Let `A` be a filtered module over a commutative ring `R`. Let `(F_i)_{i \in I}` be the filtration of `A`, with `I` being a totally ordered set. Define @@ -42,7 +42,12 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): There are canonical projections `p_i : F_i \to G_i` for every `i \in I`. Moreover `\operatorname{gr} A` is naturally a graded `R`-module with `G_i` being the `i`-th graded component. + This graded `R`-module is known as the *associated graded module* + (or, for short, just *graded module*) of `A`. + Now, assume that `A` (endowed with the filtration + `(F_i)_{i \in I}`) is not just a filtered `R`-module, but also + a filtered `R`-algebra. Let `u \in G_i` and `v \in G_j`, and let `u' \in F_i` and `v' \in F_j` be lifts of `u` and `v`, respectively (so that `u = p_i(u')` and `v = p_j(v')`). Then, we define a @@ -93,9 +98,28 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): INPUT: - - ``A`` -- a filtered algebra with basis + - ``A`` -- a filtered module (or algebra) with basis - EXAMPLES:: + OUTPUT: + + The associated graded module of `A`, if `A` is just a filtered + `R`-module. + The associated graded algebra of `A`, if `A` is a filtered + `R`-algebra. + + EXAMPLES: + + Associated graded module of a filtered module:: + + sage: A = Modules(QQ).WithBasis().Filtered().example() + sage: grA = A.graded_algebra() + sage: grA.category() + Category of graded modules with basis over Rational Field + sage: x = A.basis()[Partition([3,2,1])] + sage: grA(x) + Bbar[[3, 2, 1]] + + Associated graded algebra of a filtered algebra:: sage: A = Algebras(QQ).WithBasis().Filtered().example() sage: grA = A.graded_algebra() @@ -147,7 +171,7 @@ def __init__(self, A, category=None): sage: grA = A.graded_algebra() sage: TestSuite(grA).run(elements=[prod(grA.algebra_generators())]) """ - if A not in AlgebrasWithBasis(A.base_ring().category()).Filtered(): + if A not in ModulesWithBasis(A.base_ring().category()).Filtered(): raise ValueError("the base algebra must be filtered and with basis") self._A = A @@ -180,7 +204,10 @@ def _repr_(self): the universal enveloping algebra of Lie algebra of RR^3 with cross product over Rational Field """ - return "Graded Algebra of {}".format(self._A) + from sage.categories.algebras_with_basis import AlgebrasWithBasis + if self in AlgebrasWithBasis: + return "Graded Algebra of {}".format(self._A) + return "Graded Module of {}".format(self._A) def _latex_(self): r""" diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 326a099fcfb..0fefaa12e19 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -190,6 +190,407 @@ def basis(self, d=None): else: return Family(self._indices.subset(size=d), self.monomial) + def graded_algebra(self): + r""" + Return the associated graded module to ``self``. + + See :class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra` + for the definition and the properties of this. + + If the filtered module ``self`` with basis is called `A`, + then this method returns `\operatorname{gr} A`. The method + :meth:`to_graded_conversion` returns the canonical + `R`-module isomorphism `A \to \operatorname{gr} A` induced + by the basis of `A`, and the method + :meth:`from_graded_conversion` returns the inverse of this + isomorphism. The method :meth:`projection` projects + elements of `A` onto `\operatorname{gr} A` according to + their place in the filtration on `A`. + + .. WARNING:: + + When not overridden, this method returns the default + implementation of an associated graded module -- + namely, ``AssociatedGradedAlgebra(self)``, where + ``AssociatedGradedAlgebra`` is + :class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra`. + But some instances of :class:`FilteredModulesWithBasis` + override this method, as the associated graded module + often is (isomorphic) to a simpler object (for instance, + the associated graded module of a graded module can be + identified with the graded module itself). Generic code + that uses associated graded modules (such as the code + of the :meth:`induced_graded_map` method below) should + make sure to only communicate with them via the + :meth:`to_graded_conversion`, + :meth:`from_graded_conversion` and + :meth:`projection` methods (in particular, + do not expect there to be a conversion from ``self`` + to ``self.graded_algebra()``; this currently does not + work for Clifford algebras). Similarly, when + overriding :meth:`graded_algebra`, make sure to + accordingly redefine these three methods, unless their + definitions below still apply to your case (this will + happen whenever the basis of your :meth:`graded_algebra` + has the same indexing set as ``self``, and the partition + of this indexing set according to degree is the same as + for ``self``). + + .. TODO:: + + Maybe the thing about the conversion from ``self`` + to ``self.graded_algebra()`` on the Clifford at least + could be made to work? (I would still warn the user + against ASSUMING that it must work -- as there is + probably no way to guarantee it in all cases, and + we shouldn't require users to mess with + element constructors.) + + EXAMPLES:: + + sage: A = ModulesWithBasis(ZZ).Filtered().example() + sage: A.graded_algebra() + Graded Module of An example of a filtered module with basis: + the free module on partitions over Integer Ring + """ + from sage.algebras.associated_graded import AssociatedGradedAlgebra + return AssociatedGradedAlgebra(self) + + # Maps + + def to_graded_conversion(self): + r""" + Return the canonical `R`-module isomorphism + `A \to \operatorname{gr} A` induced by the basis of `A` + (where `A = ` ``self``). + + This is an isomorphism of `R`-modules. See + the class documentation :class:`AssociatedGradedAlgebra`. + + .. SEEALSO:: + + :meth:`from_graded_conversion` + + EXAMPLES:: + + sage: A = Modules(QQ).WithBasis().Filtered().example() + sage: p = -2 * A.an_element(); p + -4*P[] - 4*P[1] - 6*P[2] + sage: q = A.to_graded_conversion()(p); q + -4*Bbar[[]] - 4*Bbar[[1]] - 6*Bbar[[2]] + sage: q.parent() is A.graded_algebra() + True + """ + base_one = self.base_ring().one() + return self.module_morphism(diagonal=lambda x: base_one, + codomain=self.graded_algebra()) + + def from_graded_conversion(self): + r""" + Return the inverse of the canonical `R`-module isomorphism + `A \to \operatorname{gr} A` induced by the basis of `A` + (where `A = ` ``self``). This inverse is an isomorphism + `\operatorname{gr} A \to A`. + + This is an isomorphism of `R`-modules. See + the class documentation :class:`AssociatedGradedAlgebra`. + + .. SEEALSO:: + + :meth:`to_graded_conversion` + + EXAMPLES:: + + sage: A = Modules(QQ).WithBasis().Filtered().example() + sage: p = -2 * A.an_element(); p + -4*P[] - 4*P[1] - 6*P[2] + sage: q = A.to_graded_conversion()(p); q + -4*Bbar[[]] - 4*Bbar[[1]] - 6*Bbar[[2]] + sage: A.from_graded_conversion()(q) == p + True + sage: q.parent() is A.graded_algebra() + True + """ + base_one = self.base_ring().one() + return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, + codomain=self) + + def projection(self, i): + r""" + Return the `i`-th projection `p_i : F_i \to G_i` (in the + notations of the class documentation + :class:`AssociatedGradedAlgebra`, where `A = ` ``self``). + + This method actually does not return the map `p_i` itself, + but an extension of `p_i` to the whole `R`-module `A`. + This extension is the composition of the `R`-module + isomorphism `A \to \operatorname{gr} A` with the canonical + projection of the graded `R`-module `\operatorname{gr} A` + onto its `i`-th graded component `G_i`. The codomain of + this map is `\operatorname{gr} A`, although its actual + image is `G_i`. The map `p_i` is obtained from this map + by restricting its domain to `F_i` and its image to `G_i`. + + EXAMPLES:: + + sage: A = Modules(QQ).WithBasis().Filtered().example() + sage: p = -2 * A.an_element(); p + -4*P[] - 4*P[1] - 6*P[2] + sage: q = A.projection(2)(p); q + -6*Bbar[[2]] + sage: q.parent() is A.graded_algebra() + True + sage: A.projection(3)(p) + 0 + """ + base_zero = self.base_ring().zero() + base_one = self.base_ring().one() + grA = self.graded_algebra() + proj = lambda x: (base_one if self.degree_on_basis(x) == i + else base_zero) + return self.module_morphism(diagonal=proj, codomain=grA) + + def induced_graded_map(self, other, f): + r""" + Return the graded linear map between the associated graded + modules of ``self`` and ``other`` canonically induced by + the filtration-preserving map ``f : self -> other``. + + Let `A` and `B` be two filtered modules with basis, and let + `(F_i)_{i \in I}` and `(G_i)_{i \in I}` be their + filtrations. Let `f : A \to B` be a linear map which + preserves the filtration (i.e., satisfies `f(F_i) \subseteq + G_i` for all `i \in I`). Then, there is a canonically + defined graded linear map + `\operatorname{gr} f : \operatorname{gr} A \to + \operatorname{gr} B` which satisfies + + .. MATH:: + + (\operatorname{gr} f) (p_i(a)) = p_i(f(a)) + \qquad \text{for all } i \in I \text{ and } a \in F_i , + + where the `p_i` on the left hand side is the canonical + projection from `F_i` onto the `i`-th graded component + of `\operatorname{gr} A`, while the `p_i` on the right + hand side is the canonical projection from `G_i` onto + the `i`-th graded component of `\operatorname{gr} B`. + + INPUT: + + - ``other`` -- a filtered algebra with basis + + - ``f`` -- a filtration-preserving linear map from ``self`` + to ``other`` (can be given as a morphism or as a function) + + OUTPUT: + + The graded linear map `\operatorname{gr} f`. + + EXAMPLES: + + **Example 1.** + + We start with the free `\QQ`-module with basis the set of all + partitions:: + + sage: A = Modules(QQ).WithBasis().Filtered().example(); A + An example of a filtered module with basis: the free module + on partitions over Rational Field + sage: M = A.indices(); M + Partitions + sage: p1, p2, p21, p321 = [A.basis()[Partition(i)] for i in [[1], [2], [2,1], [3,2,1]]] + + Let us define a map from ``A`` to itself which acts on the + basis by sending every partition `\lambda` to the sum of + the conjugates of all partitions `\mu` for which + `\lambda / \mu` is a horizontal strip:: + + sage: def map_on_basis(lam): + ....: return A.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) + ....: for mu in lam.remove_horizontal_border_strip(k)]) + sage: f = A.module_morphism(on_basis=map_on_basis, + ....: codomain=A) + sage: f(p1) + P[] + P[1] + sage: f(p2) + P[] + P[1] + P[1, 1] + sage: f(p21) + P[1] + P[1, 1] + P[2] + P[2, 1] + sage: f(p21 - p1) + -P[] + P[1, 1] + P[2] + P[2, 1] + sage: f(p321) + P[2, 1] + P[2, 1, 1] + P[2, 2] + P[2, 2, 1] + + P[3, 1] + P[3, 1, 1] + P[3, 2] + P[3, 2, 1] + + We now compute `\operatorname{gr} f` :: + + sage: grA = A.graded_algebra(); grA + Graded Module of An example of a filtered module with basis: + the free module on partitions over Rational Field + sage: pp1, pp2, pp21, pp321 = [A.to_graded_conversion()(i) for i in [p1, p2, p21, p321]] + sage: pp2 + 4 * pp21 + Bbar[[2]] + 4*Bbar[[2, 1]] + sage: grf = A.induced_graded_map(A, f); grf + Generic endomorphism of Graded Module of An example of a + filtered module with basis: + the free module on partitions over Rational Field + sage: grf(pp1) + Bbar[[1]] + sage: grf(pp2 + 4 * pp21) + Bbar[[1, 1]] + 4*Bbar[[2, 1]] + + **Example 2.** + + We shall now construct `\operatorname{gr} f` for a + different map `f` out of the same ``A``; the new map + `f` will lead into a graded algebra already, namely into + the algebra of symmetric functions:: + + sage: h = SymmetricFunctions(QQ).h() + sage: def map_on_basis(lam): # redefining map_on_basis + ....: return h.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) + ....: for mu in lam.remove_horizontal_border_strip(k)]) + sage: f = A.module_morphism(on_basis=map_on_basis, + ....: codomain=h) # redefining f + sage: f(p1) + h[] + h[1] + sage: f(p2) + h[] + h[1] + h[1, 1] + sage: f(A.zero()) + 0 + sage: f(p2 - 3*p1) + -2*h[] - 2*h[1] + h[1, 1] + + The algebra ``h`` of symmetric functions in the `h`-basis + is already graded, so its associated graded algebra is + implemented as itself:: + + sage: grh = h.graded_algebra(); grh is h + True + sage: grf = A.induced_graded_map(h, f); grf + Generic morphism: + From: Graded Module of An example of a filtered + module with basis: the free module on partitions + over Rational Field + To: Symmetric Functions over Rational Field + in the homogeneous basis + sage: grf(pp1) + h[1] + sage: grf(pp2) + h[1, 1] + sage: grf(pp321) + h[3, 2, 1] + sage: grf(pp2 - 3*pp1) + -3*h[1] + h[1, 1] + sage: grf(pp21) + h[2, 1] + sage: grf(grA.zero()) + 0 + + **Example 3.** + + After having had a graded module as the codomain, let us try to + have one as the domain instead. Our new ``f`` will go from ``h`` + to ``A``:: + + sage: def map_on_basis(lam): # redefining map_on_basis + ....: return A.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) + ....: for mu in lam.remove_horizontal_border_strip(k)]) + sage: f = h.module_morphism(on_basis=map_on_basis, + ....: codomain=A) # redefining f + sage: f(h[1]) + P[] + P[1] + sage: f(h[2]) + P[] + P[1] + P[1, 1] + sage: f(h[1, 1]) + P[1] + P[2] + sage: f(h[2, 2]) + P[1, 1] + P[2, 1] + P[2, 2] + sage: f(h[3, 2, 1]) + P[2, 1] + P[2, 1, 1] + P[2, 2] + P[2, 2, 1] + + P[3, 1] + P[3, 1, 1] + P[3, 2] + P[3, 2, 1] + sage: f(h.one()) + P[] + sage: grf = h.induced_graded_map(A, f); grf + Generic morphism: + From: Symmetric Functions over Rational Field + in the homogeneous basis + To: Graded Module of An example of a filtered + module with basis: the free module on partitions + over Rational Field + sage: grf(h[1]) + Bbar[[1]] + sage: grf(h[2]) + Bbar[[1, 1]] + sage: grf(h[1, 1]) + Bbar[[2]] + sage: grf(h[2, 2]) + Bbar[[2, 2]] + sage: grf(h[3, 2, 1]) + Bbar[[3, 2, 1]] + sage: grf(h.one()) + Bbar[[]] + + **Example 4.** + + The construct `\operatorname{gr} f` also makes sense when `f` + is a filtration-preserving map between graded modules. :: + + sage: def map_on_basis(lam): # redefining map_on_basis + ....: return h.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) + ....: for mu in lam.remove_horizontal_border_strip(k)]) + sage: f = h.module_morphism(on_basis=map_on_basis, + ....: codomain=h) # redefining f + sage: f(h[1]) + h[] + h[1] + sage: f(h[2]) + h[] + h[1] + h[1, 1] + sage: f(h[1, 1]) + h[1] + h[2] + sage: f(h[2, 1]) + h[1] + h[1, 1] + h[2] + h[2, 1] + sage: f(h.one()) + h[] + sage: grf = h.induced_graded_map(h, f); grf + Generic endomorphism of Symmetric Functions over Rational + Field in the homogeneous basis + sage: grf(h[1]) + h[1] + sage: grf(h[2]) + h[1, 1] + sage: grf(h[1, 1]) + h[2] + sage: grf(h[2, 1]) + h[2, 1] + sage: grf(h.one()) + h[] + """ + grA = self.graded_algebra() + grB = other.graded_algebra() + from sage.categories.graded_modules_with_basis import GradedModulesWithBasis + cat = GradedModulesWithBasis(self.base_ring()) + from_gr = self.from_graded_conversion() + def on_basis(m): + i = grA.degree_on_basis(m) + lifted_img_of_m = f(from_gr(grA.monomial(m))) + return other.projection(i)(lifted_img_of_m) + return grA.module_morphism(on_basis=on_basis, + codomain=grB, category=cat) + # If we could assume that the projection of the basis + # element of ``self`` indexed by an index ``m`` is the + # basis element of ``grA`` indexed by ``m``, then this + # could go faster: + # + # def on_basis(m): + # i = grA.degree_on_basis(m) + # return grB.projection(i)(f(self.monomial(m))) + # return grA.module_morphism(on_basis=on_basis, + # codomain=grB, category=cat) + # + # But this assumption might come back to bite us in the + # ass one day. What do you think? + class ElementMethods: def is_homogeneous(self): From cd6d21aa19660d5b60074d5e5299310e6e27d626 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 23 Mar 2015 19:54:34 -0700 Subject: [PATCH 0137/1872] Created super categories for algebras and modules. --- src/sage/algebras/clifford_algebra.py | 18 +- src/sage/categories/algebras.py | 1 + src/sage/categories/algebras_with_basis.py | 1 + src/sage/categories/modules.py | 34 +++ src/sage/categories/modules_with_basis.py | 1 + src/sage/categories/super_algebras.py | 34 +++ .../categories/super_algebras_with_basis.py | 35 +++ src/sage/categories/super_modules.py | 259 ++++++++++++++++++ .../categories/super_modules_with_basis.py | 160 +++++++++++ 9 files changed, 531 insertions(+), 12 deletions(-) create mode 100644 src/sage/categories/super_algebras.py create mode 100644 src/sage/categories/super_algebras_with_basis.py create mode 100644 src/sage/categories/super_modules.py create mode 100644 src/sage/categories/super_modules_with_basis.py diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 53403eb8425..8225292888f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -18,8 +18,7 @@ from copy import copy from sage.categories.algebras_with_basis import AlgebrasWithBasis -from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis -from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis +from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.modules_with_basis import ModuleMorphismByLinearity from sage.categories.poor_man_map import PoorManMap from sage.rings.all import ZZ @@ -479,11 +478,6 @@ class CliffordAlgebra(CombinatorialFreeModule): a*d sage: d*c*b*a + a + 4*b*c a*b*c*d + 4*b*c + a - - .. WARNING:: - - The Clifford algebra is not graded, but instead filtered. This - will be changed once :trac:`17096` is finished. """ @staticmethod def __classcall_private__(cls, Q, names=None): @@ -536,7 +530,7 @@ def __init__(self, Q, names, category=None): self._quadratic_form = Q R = Q.base_ring() if category is None: - category = GradedAlgebrasWithBasis(R) + category = AlgebrasWithBasis(R).Super() indices = SubsetsSorted(range(Q.dim())) CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) @@ -1050,7 +1044,7 @@ def lift_module_morphism(self, m, names=None): remove_zeros=True ) for i in x) return Cl.module_morphism(on_basis=f, codomain=self, - category=GradedAlgebrasWithBasis(self.base_ring())) + category=AlgebrasWithBasis(self.base_ring()).Graded()) def lift_isometry(self, m, names=None): r""" @@ -1115,7 +1109,7 @@ def lift_isometry(self, m, names=None): remove_zeros=True ) for i in x) return self.module_morphism(on_basis=f, codomain=Cl, - category=GradedAlgebrasWithBasis(self.base_ring())) + category=AlgebrasWithBasis(self.base_ring()).Super()) # This is a general method for finite dimensional algebras with bases # and should be moved to the corresponding category once there is @@ -1418,7 +1412,7 @@ def __init__(self, R, names): sage: E. = ExteriorAlgebra(QQ) sage: TestSuite(E).run() """ - CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, GradedHopfAlgebrasWithBasis(R)) + CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, HopfAlgebrasWithBasis(R).Super()) # TestSuite will fail if the HopfAlgebra classes will ever have tests for # the coproduct being an algebra morphism -- since this is really a # Hopf superalgebra, not a Hopf algebra. @@ -1562,7 +1556,7 @@ def lift_morphism(self, phi, names=None): f = lambda x: E.prod(E._from_dict( {(j,): phi[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - return self.module_morphism(on_basis=f, codomain=E, category=GradedAlgebrasWithBasis(R)) + return self.module_morphism(on_basis=f, codomain=E, category=AlgebrasWithBasis(R).Super()) def volume_form(self): """ diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 3440acaab7c..6fbf51d83c5 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -88,6 +88,7 @@ def __contains__(self, x): Commutative = LazyImport('sage.categories.commutative_algebras', 'CommutativeAlgebras', at_startup=True) Graded = LazyImport('sage.categories.graded_algebras', 'GradedAlgebras') + Super = LazyImport('sage.categories.super_algebras', 'SuperAlgebras') WithBasis = LazyImport('sage.categories.algebras_with_basis', 'AlgebrasWithBasis') class ElementMethods: diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index 8a4668edf1e..e3ae7546129 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -118,6 +118,7 @@ def example(self, alphabet = ('a','b','c')): FiniteDimensional = LazyImport('sage.categories.finite_dimensional_algebras_with_basis', 'FiniteDimensionalAlgebrasWithBasis') Graded = LazyImport('sage.categories.graded_algebras_with_basis', 'GradedAlgebrasWithBasis') + Super = LazyImport('sage.categories.super_algebras_with_basis', 'SuperAlgebrasWithBasis') class ParentMethods: diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 4eaa56726de..5b7325e6e18 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -378,6 +378,39 @@ def Graded(self, base_ring=None): from sage.categories.graded_modules import GradedModulesCategory return GradedModulesCategory.category_of(self) + @cached_method + def Super(self, base_ring=None): + r""" + Return the subcategory of the super objects of ``self``. + + INPUT:: + + - ``base_ring`` -- this is ignored + + EXAMPLES:: + + sage: Modules(ZZ).Super() + Category of graded modules over Integer Ring + + sage: Coalgebras(QQ).Super() + Join of Category of graded modules over Rational Field and Category of coalgebras over Rational Field + + sage: AlgebrasWithBasis(QQ).Super() + Category of graded algebras with basis over Rational Field + + .. TODO:: + + Same as :meth:`Graded`. + + TESTS:: + + sage: Coalgebras(QQ).Super.__module__ + 'sage.categories.modules' + """ + assert base_ring is None or base_ring is self.base_ring() + from sage.categories.super_modules import SuperModulesCategory + return SuperModulesCategory.category_of(self) + @cached_method def WithBasis(self): r""" @@ -425,6 +458,7 @@ def extra_super_categories(self): return [] Graded = LazyImport('sage.categories.graded_modules', 'GradedModules') + Super = LazyImport('sage.categories.super_modules', 'SuperModules') WithBasis = LazyImport('sage.categories.modules_with_basis', 'ModulesWithBasis') class ParentMethods: diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 0f899ca04f4..0c6d9edea69 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -180,6 +180,7 @@ def is_abelian(self): FiniteDimensional = LazyImport('sage.categories.finite_dimensional_modules_with_basis', 'FiniteDimensionalModulesWithBasis') Graded = LazyImport('sage.categories.graded_modules_with_basis', 'GradedModulesWithBasis') + Super = LazyImport('sage.categories.super_modules_with_basis', 'SuperModulesWithBasis') class ParentMethods: @cached_method diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py new file mode 100644 index 00000000000..355bf857758 --- /dev/null +++ b/src/sage/categories/super_algebras.py @@ -0,0 +1,34 @@ +r""" +Super Algebras +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.categories.super_modules import SuperModulesCategory + +class SuperAlgebras(SuperModulesCategory): + """ + The category of super algebras. + + EXAMPLES:: + + sage: Algebras(ZZ).Super() + Category of super algebras over Integer Ring + sage: Algebras(ZZ).Super().super_categories() + [Category of graded algebras over Integer Ring, + Category of super modules over Integer Ring] + + TESTS:: + + sage: TestSuite(Algebras(ZZ).Super()).run() + """ + class ParentMethods: + pass + + class ElementMethods: + pass + diff --git a/src/sage/categories/super_algebras_with_basis.py b/src/sage/categories/super_algebras_with_basis.py new file mode 100644 index 00000000000..9ba242c829f --- /dev/null +++ b/src/sage/categories/super_algebras_with_basis.py @@ -0,0 +1,35 @@ +r""" +Super algebras with basis +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.categories.super_modules import SuperModulesCategory + +class SuperAlgebrasWithBasis(SuperModulesCategory): + """ + The category of super algebras with a distinguished basis + + EXAMPLES:: + + sage: C = Algebras(ZZ).WithBasis().Super(); C + Category of super algebras with basis over Integer Ring + sage: sorted(C.super_categories(), key=str) + [Category of graded algebras with basis over Integer Ring, + Category of super algebras over Integer Ring, + Category of super modules with basis over Integer Ring] + + TESTS:: + + sage: TestSuite(C).run() + """ + class ParentMethods: + pass + + class ElementMethods: + pass + diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py new file mode 100644 index 00000000000..154ca9f6168 --- /dev/null +++ b/src/sage/categories/super_modules.py @@ -0,0 +1,259 @@ +r""" +Super modules +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# 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.misc.lazy_attribute import lazy_class_attribute +from sage.categories.category import Category +from sage.categories.category_types import Category_over_base_ring +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory +from sage.categories.modules import Modules + +class SuperModulesCategory(RegressiveCovariantConstructionCategory, Category_over_base_ring): + def __init__(self, base_category): + """ + EXAMPLES:: + + sage: C = Algebras(QQ).Super() + sage: C + Category of super algebras over Rational Field + sage: C.base_category() + Category of algebras over Rational Field + sage: sorted(C.super_categories(), key=str) + [Category of graded algebras over Rational Field, + Category of super modules over Rational Field] + + sage: AlgebrasWithBasis(QQ).Super().base_ring() + Rational Field + sage: HopfAlgebrasWithBasis(QQ).Super().base_ring() + Rational Field + """ + super(SuperModulesCategory, self).__init__(base_category, base_category.base_ring()) + + _functor_category = "Super" + + @lazy_class_attribute + def _base_category_class(cls): + """ + Recover the class of the base category. + + OUTPUT: + + A *tuple* whose first entry is the base category class. + + .. WARNING:: + + This is only used for super categories that are not + implemented as nested classes, and won't work otherwise. + + .. SEEALSO:: :meth:`__classcall__` + + EXAMPLES:: + + sage: from sage.categories.super_modules import SuperModules + sage: from sage.categories.super_algebras_with_basis import SuperAlgebrasWithBasis + sage: SuperModules._base_category_class + (,) + sage: SuperAlgebrasWithBasis._base_category_class + (,) + + The reason for wrapping the base category class in a tuple is + that, often, the base category class implements a + :meth:`__classget__` method which would get in the way upon + attribute access:: + + sage: F = SuperAlgebrasWithBasis + sage: F._foo = F._base_category_class[0] + sage: F._foo + Traceback (most recent call last): + ... + AssertionError: base category class for <...AlgebrasWithBasis'> mismatch; + expected <...Algebras'>, got <...SuperAlgebrasWithBasis'> + """ + module_name = cls.__module__.replace("super_","") + import sys + name = cls.__name__.replace("Super","") + __import__(module_name) + module = sys.modules[module_name] + return (module.__dict__[name],) + + @staticmethod + def __classcall__(cls, category, *args): + """ + Magic support for putting Super categories in their own file. + + EXAMPLES:: + + sage: from sage.categories.super_modules import SuperModules + sage: SuperModules(ZZ) # indirect doctest + Category of super modules over Integer Ring + sage: Modules(ZZ).Super() + Category of super modules over Integer Ring + sage: SuperModules(ZZ) is Modules(ZZ).Super() + True + + .. TODO:: + + Generalize this support for all other functorial + constructions if at some point we have a category ``Blah`` for + which we want to implement the construction ``Blah.Foo`` in a + separate file like we do for e.g. :class:`SuperModules`, + :class:`SuperAlgebras`, ... + + .. SEEALSO:: :meth:`_base_category_class` + """ + base_category_class = cls._base_category_class[0] + if isinstance(category, base_category_class): + return super(SuperModulesCategory, cls).__classcall__(cls, category, *args) + else: + return base_category_class(category, *args).Super() + + def _repr_object_names(self): + """ + EXAMPLES:: + + sage: AlgebrasWithBasis(QQ).Super() # indirect doctest + Category of super algebras with basis over Rational Field + """ + return "super {}".format(self.base_category()._repr_object_names()) + + @classmethod + def default_super_categories(cls, category, *args): + """ + Returns the default super categories of ``category.Subobjects()`` + + Mathematical meaning: if `A` is a super version of `B`, + then `A` is also a graded version of `B`. + + INPUT: + + - ``cls`` -- the class ``SubobjectsCategory`` + - ``category`` -- a category `Cat` + + OUTPUT: a (join) category + + In practice, this returns ``category.Subquotients()``, joined + together with the result of the method + :meth:`RegressiveCovariantConstructionCategory.default_super_categories() ` + (that is the join of ``category`` and ``cat.Subobjects()`` for + each ``cat`` in the super categories of ``category``). + + EXAMPLES:: + """ + return Category.join([category.Graded(), super(SuperModulesCategory, cls).default_super_categories(category, *args)]) + +class SuperModules(SuperModulesCategory): + """ + The category of super modules. + + EXAMPLES:: + + sage: Modules(ZZ).Super() + Category of super modules over Integer Ring + sage: Modules(ZZ).Super().super_categories() + [Category of graded modules over Integer Ring] + + The category of super modules defines the super structure which + shall be preserved by morphisms:: + + sage: Modules(ZZ).Super().additional_structure() + Category of super modules over Integer Ring + + TESTS:: + + sage: TestSuite(Modules(ZZ).Super()).run() + """ + def extra_super_categories(self): + r""" + Adds :class:`VectorSpaces` to the super categories of ``self`` if + the base ring is a field. + + EXAMPLES:: + + sage: Modules(QQ).Super().extra_super_categories() + [Category of vector spaces over Rational Field] + sage: Modules(ZZ).Super().extra_super_categories() + [] + + This makes sure that ``Modules(QQ).Super()`` returns an + instance of :class:`GradedModules` and not a join category of + an instance of this class and of ``VectorSpaces(QQ)``:: + + sage: type(Modules(QQ).Super()) + + + .. TODO:: + + Get rid of this workaround once there is a more systematic + approach for the alias ``Modules(QQ)`` -> ``VectorSpaces(QQ)``. + Probably the later should be a category with axiom, and + covariant constructions should play well with axioms. + """ + from sage.categories.modules import Modules + from sage.categories.fields import Fields + base_ring = self.base_ring() + if base_ring in Fields: + return [Modules(base_ring)] + else: + return [] + + class ParentMethods: + pass + + class ElementMethods: + def is_even_odd(self): + """ + Return ``0`` if ``self`` is an even element or ``1`` + if an odd element. + + EXAMPLES:: + + sage: cat = Algebras(QQ).WithBasis().Super() + sage: C = CombinatorialFreeModule(QQ, Partitions(), category=cat) + sage: C.degree_on_basis = sum + sage: C.basis()[2,2,1].is_even_odd() + 1 + sage: C.basis()[2,2].is_even_odd() + 0 + """ + return self.degree() % 2 + + def is_even(self): + """ + Return if ``self`` is an even element. + + EXAMPLES:: + + sage: cat = Algebras(QQ).WithBasis().Super() + sage: C = CombinatorialFreeModule(QQ, Partitions(), category=cat) + sage: C.degree_on_basis = sum + sage: C.basis()[2,2,1].is_even() + False + sage: C.basis()[2,2].is_even() + True + """ + return self.is_even_odd() == 0 + + def is_odd(self): + """ + Return if ``self`` is an odd element. + + EXAMPLES:: + + sage: cat = Algebras(QQ).WithBasis().Super() + sage: C = CombinatorialFreeModule(QQ, Partitions(), category=cat) + sage: C.degree_on_basis = sum + sage: C.basis()[2,2,1].is_odd() + True + sage: C.basis()[2,2].is_odd() + False + """ + return self.is_even_odd() == 1 + diff --git a/src/sage/categories/super_modules_with_basis.py b/src/sage/categories/super_modules_with_basis.py new file mode 100644 index 00000000000..64cfcc3da7b --- /dev/null +++ b/src/sage/categories/super_modules_with_basis.py @@ -0,0 +1,160 @@ +r""" +Super modules with basis +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.categories.super_modules import SuperModulesCategory + +class SuperModulesWithBasis(SuperModulesCategory): + """ + The category of super modules with a distinguished basis. + + EXAMPLES:: + + sage: C = GradedModulesWithBasis(ZZ); C + Category of graded modules with basis over Integer Ring + sage: sorted(C.super_categories(), key=str) + [Category of graded modules over Integer Ring, + Category of modules with basis over Integer Ring] + sage: C is ModulesWithBasis(ZZ).Graded() + True + + TESTS:: + + sage: TestSuite(C).run() + """ + class ParentMethods: + def _even_odd_on_basis(self, m): + """ + Return if ``m`` is an index of an even or odd basis element. + + OUTPUT: + + ``0`` if ``m`` is for an even element or ``1`` if ``m`` + is for an odd element. + """ + return self.degree_on_basis(m) % 2 + + class ElementMethods: + def is_super_homogeneous(self): + r""" + Return whether this element is homogeneous, in the sense + of a super module. + + EXAMPLES:: + + sage: Q = QuadraticForm(QQ, 2, [1,2,3]) + sage: C. = CliffordAlgebra(Q) + sage: a = x + y + sage: a.is_super_homogeneous() + True + sage: a = x*y + 4 + sage: a.is_super_homogeneous() + True + sage: a = x*y + x - 3*y + 4 + sage: a.is_super_homogeneous() + False + + The exterior algebra has a `\ZZ` grading, which induces the + `\ZZ / 2\ZZ` grading, however the definition of homogeneous + elements differ because of the different gradings:: + + sage: E. = ExteriorAlgebra(QQ) + sage: a = x*y + 4 + sage: a.is_super_homogeneous() + True + sage: a.is_homogeneous() + False + """ + even_odd = self.parent()._even_odd_on_basis + degree = None + for m in self.support(): + if degree is None: + degree = even_odd(m) + else: + if degree != even_odd(m): + return False + return True + + def is_even_odd(self): + """ + Return ``0`` if ``self`` is an even element and ``1`` if + ``self`` is an odd element. + + EXAMPLES:: + + sage: Q = QuadraticForm(QQ, 2, [1,2,3]) + sage: C. = CliffordAlgebra(Q) + sage: a = x + y + sage: a.is_even_odd() + 1 + sage: a = x*y + 4 + sage: a.is_even_odd() + 0 + sage: a = x + 4 + sage: a.is_even_odd() + Traceback (most recent call last): + ... + ValueError: element is not homogeneous + """ + if not self.support(): + raise ValueError("the zero element does not have a well-defined degree") + if not self.is_super_homogeneous(): + raise ValueError("element is not homogeneous") + return self.parent()._even_odd_on_basis(self.leading_support()) + + def even_component(self): + """ + Return the even component of ``self``. + + EXAMPLES:: + + sage: Q = QuadraticForm(QQ, 2, [1,2,3]) + sage: C. = CliffordAlgebra(Q) + sage: a = x*y + x - 3*y + 4 + sage: a.even_component() + x*y + 4 + + TESTS: + + Check that this really return ``A.zero()`` and not a plain ``0``:: + + sage: a = x + y + sage: a.even_component().parent() is C + True + """ + even_odd = self.parent()._even_odd_on_basis + return self.parent().sum_of_terms((i, c) + for (i, c) in self + if even_odd(i) == 0) + + def odd_component(self): + """ + Return the odd component of ``self``. + + EXAMPLES:: + + sage: Q = QuadraticForm(QQ, 2, [1,2,3]) + sage: C. = CliffordAlgebra(Q) + sage: a = x*y + x - 3*y + 4 + sage: a.odd_component() + x - 3*y + + TESTS: + + Check that this really return ``A.zero()`` and not a plain ``0``:: + + sage: a = x*y + sage: a.odd_component().parent() is C + True + """ + even_odd = self.parent()._even_odd_on_basis + return self.parent().sum_of_terms((i, c) + for (i, c) in self + if even_odd(i) == 1) + From d1d135f03b4bed898ae018b8fec03786c8ca4c1a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 25 Mar 2015 11:58:50 -0700 Subject: [PATCH 0138/1872] Give Weyl/Clifford/Exterior super powers. --- src/sage/algebras/clifford_algebra.py | 139 ++++---------------------- src/sage/algebras/weyl_algebra.py | 2 +- 2 files changed, 20 insertions(+), 121 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index ac915b5a01b..73552f8e651 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -476,7 +476,7 @@ class CliffordAlgebra(CombinatorialFreeModule): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl = CliffordAlgebra(Q) sage: Cl - The graded Clifford algebra of the Quadratic form in 3 variables + The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] @@ -494,7 +494,7 @@ class CliffordAlgebra(CombinatorialFreeModule): a*b*c*d + 4*b*c + a """ @staticmethod - def __classcall_private__(cls, Q, names=None, graded=True): + def __classcall_private__(cls, Q, names=None): """ Normalize arguments to ensure a unique representation. @@ -517,9 +517,9 @@ def __classcall_private__(cls, Q, names=None, graded=True): names = tuple( '{}{}'.format(names[0], i) for i in range(Q.dim()) ) else: raise ValueError("the number of variables does not match the number of generators") - return super(CliffordAlgebra, cls).__classcall__(cls, Q, names, graded=bool(graded)) + return super(CliffordAlgebra, cls).__classcall__(cls, Q, names) - def __init__(self, Q, names, category=None, graded=True): + def __init__(self, Q, names, category=None): r""" Initialize ``self``. @@ -528,8 +528,6 @@ def __init__(self, Q, names, category=None, graded=True): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl = CliffordAlgebra(Q) sage: TestSuite(Cl).run() - sage: Cl = CliffordAlgebra(Q, graded=False) - sage: TestSuite(Cl).run() TESTS: @@ -544,13 +542,8 @@ def __init__(self, Q, names, category=None, graded=True): True """ self._quadratic_form = Q - self._graded = graded R = Q.base_ring() - if category is None: - if graded: - category = AlgebrasWithBasis(R.category()).Graded() - else: - category = AlgebrasWithBasis(R.category()).Filtered() + category = AlgebrasWithBasis(R.category()).Super().Filtered().or_subcategory(category) indices = SubsetsSorted(range(Q.dim())) CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) @@ -563,20 +556,13 @@ def _repr_(self): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: CliffordAlgebra(Q) - The graded Clifford algebra of the Quadratic form in 3 variables - over Integer Ring with coefficients: - [ 1 2 3 ] - [ * 4 5 ] - [ * * 6 ] - sage: CliffordAlgebra(Q, graded=False) - The filtered Clifford algebra of the Quadratic form in 3 variables + The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] """ - gr = "graded" if self._graded else "filtered" - return "The {} Clifford algebra of the {}".format(gr, self._quadratic_form) + return "The Clifford algebra of the {}".format(self._quadratic_form) def _repr_term(self, m): """ @@ -690,24 +676,12 @@ def _coerce_map_from_(self, V): sage: b = Cl.basis()[(0,2)] sage: Clp(3*a-4*b) 2*e0*e2 - - The filtered Clifford algebra coerces into the graded Clifford - algebra, but not the other way around:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl = CliffordAlgebra(Q) - sage: ClF = CliffordAlgebra(Q, graded=False) - sage: Cl.has_coerce_map_from(ClF) - True - sage: ClF.has_coerce_map_from(Cl) - False """ if isinstance(V, CliffordAlgebra): Q = self._quadratic_form try: return (V.variable_names() == self.variable_names() and - V._quadratic_form.base_change_to(self.base_ring()) == Q - and (self._graded or not V._graded)) + V._quadratic_form.base_change_to(self.base_ring()) == Q) except Exception: return False @@ -746,38 +720,6 @@ def _element_constructor_(self, x): sage: Cl3 = CliffordAlgebra(Q3, names='xyz') # different syntax for a change sage: Cl3( M((1,-3,2)) ) x + 2*z - - Conversions work between the filtered and the graded Clifford - algebra for the same form: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,4,3,5,6]) - sage: Cl = CliffordAlgebra(Q); Cl - The graded Clifford algebra of the Quadratic form in 3 variables - over Integer Ring with coefficients: - [ 1 2 4 ] - [ * 3 5 ] - [ * * 6 ] - sage: Cl2 = CliffordAlgebra(Q, graded=False); Cl2 - The filtered Clifford algebra of the Quadratic form in 3 variables - over Integer Ring with coefficients: - [ 1 2 4 ] - [ * 3 5 ] - [ * * 6 ] - sage: Cl == Cl2 - False - sage: x,y,z = Cl.gens() - sage: a = (x+y)*(x+z) - 2*x + 3; a - -e0*e1 + e0*e2 + e1*e2 - 2*e0 + 6 - sage: Cl2(a) - -e0*e1 + e0*e2 + e1*e2 - 2*e0 + 6 - sage: Cl(Cl2(a)) == a - True - - .. TODO:: - - These conversions don't work. You might not want a coercion - from the graded Cl into the filtered Cl (although I don't - see why not), but a conversion should exist! """ # This is the natural lift morphism of the underlying free module if x in self.free_module(): @@ -902,22 +844,8 @@ def degree_on_basis(self, m): r""" Return the degree of the monomial indexed by ``m``. - If we consider the Clifford algebra to be `\ZZ_2`-graded, this - degree is a nonnegative integer, and should be interpreted as a - residue class modulo `2`. The degree of the monomial ``m`` in this - `\ZZ_2`-grading is defined to be the length of ``m`` taken mod `2`. - - Otherwise we are considering the Clifford algebra to be - `\NN`-filtered, and the degree of the monomial ``m`` is the - length of ``m``. - - .. WARNING: - - On the :class:`ExteriorAlgebra` class (which inherits from - :class:`CliffordAlgebra`), the :meth:`degree_on_basis` - method is overridden to always return an actual `\NN`-degree - since it is `\NN`-graded. So don't count on this method - always returning `0` or `1` !! + We are considering the Clifford algebra to be `\NN`-filtered, + and the degree of the monomial ``m`` is the length of ``m``. EXAMPLES:: @@ -926,13 +854,8 @@ def degree_on_basis(self, m): sage: Cl.degree_on_basis((0,)) 1 sage: Cl.degree_on_basis((0,1)) - 0 - sage: Cl. = CliffordAlgebra(Q, graded=False) - sage: Cl.degree_on_basis((0,1)) 2 """ - if self._graded: - return len(m) % ZZ(2) return ZZ(len(m)) def graded_algebra(self): @@ -943,18 +866,9 @@ def graded_algebra(self): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl. = CliffordAlgebra(Q) - sage: Cl.graded_algebra() is Cl - True - sage: Cl. = CliffordAlgebra(Q, graded=False) sage: Cl.graded_algebra() The exterior algebra of rank 3 over Integer Ring - - .. TODO:: - - Doctest that the three methods do what they should. """ - if self._graded: - return self return ExteriorAlgebra(self.base_ring(), self.variable_names()) @cached_method @@ -1053,11 +967,11 @@ def lift_module_morphism(self, m, names=None): sage: phi = Cl.lift_module_morphism(m, 'abc') sage: phi Generic morphism: - From: The graded Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: + From: The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: [ 10 17 3 ] [ * 11 0 ] [ * * 5 ] - To: The graded Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: + To: The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] @@ -1139,17 +1053,13 @@ def lift_module_morphism(self, m, names=None): if Q == self._quadratic_form and names is None: Cl = self else: - Cl = CliffordAlgebra(Q, names, graded=self._graded) + Cl = CliffordAlgebra(Q, names) n = self._quadratic_form.dim() f = lambda x: self.prod(self._from_dict( {(j,): m[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - cat = AlgebrasWithBasis(self.base_ring()).Filtered() - # .. TODO:: - # And if the Clifford is graded, we don't use .Graded()? - # Also, why self.base_ring() and not self.base_ring().category()? - return Cl.module_morphism(on_basis=f, codomain=self, category=cat) + return Cl.module_morphism(on_basis=f, codomain=self) def lift_isometry(self, m, names=None): r""" @@ -1207,18 +1117,13 @@ def lift_isometry(self, m, names=None): else: if names is None: names = 'e' - Cl = CliffordAlgebra(Q, names, graded=self._graded) + Cl = CliffordAlgebra(Q, names) n = Q.dim() f = lambda x: Cl.prod(Cl._from_dict( {(j,): m[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - - cat = AlgebrasWithBasis(self.base_ring()).Filtered() - # .. TODO:: - # And if the Clifford is graded, we don't use .Graded()? - # Also, why self.base_ring() and not self.base_ring().category()? - return self.module_morphism(on_basis=f, codomain=Cl, category=cat) + return self.module_morphism(on_basis=f, codomain=Cl) # This is a general method for finite dimensional algebras with bases # and should be moved to the corresponding category once there is @@ -1441,7 +1346,7 @@ class ExteriorAlgebra(CliffordAlgebra): `Q(v) = 0` for all vectors `v \in V`. See :class:`CliffordAlgebra` for the notion of a Clifford algebra. - The exterior algebra of an `R`-module `V` is a `\ZZ`-graded connected + The exterior algebra of an `R`-module `V` is a super connected Hopf superalgebra. It is commutative in the super sense (i.e., the odd elements anticommute and square to `0`). @@ -1455,10 +1360,6 @@ class ExteriorAlgebra(CliffordAlgebra): Hopf superalgebra with the odd-degree components forming the odd part. So use Hopf-algebraic methods with care! - .. TODO:: - - Add a category for Hopf superalgebras (perhaps part of :trac:`16513`). - INPUT: - ``R`` -- the base ring, *or* the free module whose exterior algebra @@ -1521,7 +1422,7 @@ def __init__(self, R, names): sage: E. = ExteriorAlgebra(QQ) sage: TestSuite(E).run() """ - cat = GradedHopfAlgebrasWithBasis(R.category()) + cat = HopfAlgebrasWithBasis(R.category()).Super().Graded() CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, cat) # TestSuite will fail if the HopfAlgebra classes will ever have tests for # the coproduct being an algebra morphism -- since this is really a @@ -1666,9 +1567,7 @@ def lift_morphism(self, phi, names=None): f = lambda x: E.prod(E._from_dict( {(j,): phi[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - return self.module_morphism(on_basis=f, codomain=E, category=GradedHopfAlgebrasWithBasis(R)) - # .. TODO:: - # not R.category()? + return self.module_morphism(on_basis=f, codomain=E) def volume_form(self): """ diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 445b6ba61ba..d074d1dedfb 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -589,7 +589,7 @@ def __init__(self, R, names=None): names = names + tuple('d' + n for n in names) if len(names) != self._n * 2: raise ValueError("variable names cannot differ by a leading 'd'") - cat = AlgebrasWithBasis(R.category()).NoZeroDivisors().Filtered() + cat = AlgebrasWithBasis(R.category()).NoZeroDivisors().Super().Filtered() Algebra.__init__(self, R, names, category=cat) def _repr_(self): From 14e19ba97f1bb096c7614241c9b09c1d0f699a19 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Mar 2015 13:32:00 -0700 Subject: [PATCH 0139/1872] Fixing doctests and updating documentation. --- .../filtered_algebras_with_basis.py | 8 +-- src/sage/categories/filtered_modules.py | 4 ++ .../categories/filtered_modules_with_basis.py | 65 ++++++++++--------- src/sage/categories/modules_with_basis.py | 14 ++++ .../categories/super_modules_with_basis.py | 4 +- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 62f24559a0e..1179b068b7b 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -78,7 +78,7 @@ def graded_algebra(self): of the :meth:`induced_graded_map` method below) should make sure to only communicate with them via the :meth:`to_graded_conversion`, - :meth:`from_graded_conversion` and + :meth:`from_graded_conversion`, and :meth:`projection` methods (in particular, do not expect there to be a conversion from ``self`` to ``self.graded_algebra()``; this currently does not @@ -459,15 +459,15 @@ def induced_graded_map(self, other, f): map `f` between two Clifford algebras:: sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) - sage: B = CliffordAlgebra(Q, names=['u','v'], graded=False); B - The filtered Clifford algebra of the Quadratic form in 2 + sage: B = CliffordAlgebra(Q, names=['u','v']); B + The Clifford algebra of the Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 2 ] [ * 3 ] sage: m = Matrix(ZZ, [[1, 2], [1, -1]]) sage: f = B.lift_module_morphism(m, names=['x','y']) sage: A = f.domain(); A - The filtered Clifford algebra of the Quadratic form in 2 + The Clifford algebra of the Quadratic form in 2 variables over Integer Ring with coefficients: [ 6 0 ] [ * 3 ] diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index 784b0faaf59..7ba8bd51a7c 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -16,6 +16,10 @@ .. TODO:: Implement filtrations for all concrete categories. + +.. TODO:: + + Implement `\operatorname{gr}` as a functor. """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 0fefaa12e19..bf7642ae79e 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -29,6 +29,7 @@ #****************************************************************************** from sage.categories.filtered_modules import FilteredModulesCategory +from sage.misc.abstract_method import abstract_method class FilteredModulesWithBasis(FilteredModulesCategory): r""" @@ -80,15 +81,11 @@ class FilteredModulesWithBasis(FilteredModulesCategory): `J_i` (as an iterable). If the latter conditions are not satisfied, then :meth:`basis` must be overridden. - .. TODO:: - - This deserves to be handled better, and the contracts - involved might also profit from some explicit writing-up. + .. NOTE:: - What else should be part of the requirements for - inheriting from :class:`FilteredModulesWithBasis`? - At least having a ``degree_on_basis`` method? Is that - enough? + One should implement a ``degree_on_basis`` method in the parent + class in order to fully utilize the methods of this category. + This might become a required abstract method in the future. EXAMPLES:: @@ -102,6 +99,9 @@ class FilteredModulesWithBasis(FilteredModulesCategory): TESTS:: + sage: C = ModulesWithBasis(ZZ).Filtered() + sage: TestSuite(C).run() + sage: C = ModulesWithBasis(QQ).Filtered() sage: TestSuite(C).run() """ class ParentMethods: @@ -153,7 +153,9 @@ def basis(self, d=None): filtered module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions} - Checking this method on a filtered algebra:: + Checking this method on a filtered algebra. Note that this + will typically raise an ``AttributeError`` when this feature + is not implemented. :: sage: A = AlgebrasWithBasis(ZZ).Filtered().example() sage: A.basis(4) @@ -161,15 +163,6 @@ def basis(self, d=None): ... AttributeError: 'IndexedFreeAbelianMonoid_with_category' object has no attribute 'subset' - .. TODO:: - - Oops! This doesn't work. This ``size=d`` thing seems very - frail to me. For how many families does it work, and - (more importantly) how many does it result in wrong - return values? What about leaving it to the instances to - define? (The ``basis`` method without extra parameters - should stay general, of course.) - Without arguments, the full basis is returned:: sage: A.basis() @@ -179,10 +172,13 @@ def basis(self, d=None): of RR^3 with cross product over Integer Ring(i))_{i in Free abelian monoid indexed by {'x', 'y', 'z'}} - .. TODO:: + An example with a graded algebra:: - Add doctests for some graded modules and algebras (which - seem to inherit this method). + sage: E. = ExteriorAlgebra(QQ) + sage: E.basis() + Lazy family (Term map from Subsets of {0, 1} to + The exterior algebra of rank 2 over Rational Field(i))_{i in + Subsets of {0, 1}} """ from sage.sets.family import Family if d is None: @@ -236,16 +232,6 @@ def graded_algebra(self): of this indexing set according to degree is the same as for ``self``). - .. TODO:: - - Maybe the thing about the conversion from ``self`` - to ``self.graded_algebra()`` on the Clifford at least - could be made to work? (I would still warn the user - against ASSUMING that it must work -- as there is - probably no way to guarantee it in all cases, and - we shouldn't require users to mess with - element constructors.) - EXAMPLES:: sage: A = ModulesWithBasis(ZZ).Filtered().example() @@ -333,7 +319,7 @@ def projection(self, i): EXAMPLES:: - sage: A = Modules(QQ).WithBasis().Filtered().example() + sage: A = Modules(ZZ).WithBasis().Filtered().example() sage: p = -2 * A.an_element(); p -4*P[] - 4*P[1] - 6*P[2] sage: q = A.projection(2)(p); q @@ -649,6 +635,21 @@ def is_homogeneous(self): return False return True + @abstract_method(optional=True) + def degree_on_basis(self, m): + r""" + Return the degree of the basis element indexed by ``m`` + in ``self``. + + EXAMPLES:: + + sage: A = GradedModulesWithBasis(QQ).example() + sage: A.degree_on_basis(Partition((2,1))) + 3 + sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) + 10 + """ + def homogeneous_degree(self): r""" The degree of a nonzero homogeneous element ``self`` in the diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 09c9333cefe..76744f1aabc 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -19,6 +19,7 @@ from sage.misc.lazy_import import LazyImport from sage.misc.cachefunc import cached_method from sage.misc.misc import attrcall +from sage.misc.abstract_method import abstract_method from sage.misc.sage_itertools import max_cmp, min_cmp from sage.categories.homsets import HomsetsCategory from sage.categories.cartesian_product import CartesianProductsCategory @@ -463,6 +464,19 @@ class ElementMethods: # """ # return self._lmul_(-self.parent().base_ring().one(), self) + @abstract_method + def support(self): + """ + Return the support of ``self``. + + EXAMPLES:: + + sage: C = CombinatorialFreeModule(QQ, ZZ) + sage: x = C.an_element(); x + 3*B[-1] + B[0] + 3*B[1] + sage: x.support() + [-1, 0, 1] + """ def support_of_term(self): """ diff --git a/src/sage/categories/super_modules_with_basis.py b/src/sage/categories/super_modules_with_basis.py index 64cfcc3da7b..fda2ab4abe5 100644 --- a/src/sage/categories/super_modules_with_basis.py +++ b/src/sage/categories/super_modules_with_basis.py @@ -19,8 +19,8 @@ class SuperModulesWithBasis(SuperModulesCategory): sage: C = GradedModulesWithBasis(ZZ); C Category of graded modules with basis over Integer Ring sage: sorted(C.super_categories(), key=str) - [Category of graded modules over Integer Ring, - Category of modules with basis over Integer Ring] + [Category of filtered modules with basis over Integer Ring, + Category of graded modules over Integer Ring] sage: C is ModulesWithBasis(ZZ).Graded() True From 9bc28fd5fdbcb5463703739a9077886a113596a5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 26 Mar 2015 23:33:19 -0700 Subject: [PATCH 0140/1872] Changing abstract methods and doc based off talking with Nicolas. --- src/sage/categories/modules_with_basis.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 76744f1aabc..e23bdb6b0f5 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -122,6 +122,12 @@ class ModulesWithBasis(CategoryWithAxiom_over_base_ring): .. TODO:: ``End(X)`` is an algebra. + .. NOTE:: + + This category currently requires an implementation of an + element method ``support``. Once :trac:`18066`, an implementation + of an ``items`` method will be required. + TESTS:: sage: TestSuite(ModulesWithBasis(ZZ)).run() @@ -464,20 +470,6 @@ class ElementMethods: # """ # return self._lmul_(-self.parent().base_ring().one(), self) - @abstract_method - def support(self): - """ - Return the support of ``self``. - - EXAMPLES:: - - sage: C = CombinatorialFreeModule(QQ, ZZ) - sage: x = C.an_element(); x - 3*B[-1] + B[0] + 3*B[1] - sage: x.support() - [-1, 0, 1] - """ - def support_of_term(self): """ Return the support of ``self``, where ``self`` is a monomial From 0ce1cad1332ec34909c4baa2761307a3bd205ef8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 28 Mar 2015 16:46:44 -0700 Subject: [PATCH 0141/1872] Changing the wording of the Super method. --- src/sage/categories/modules.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 5b7325e6e18..13ad379c7a2 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -381,7 +381,7 @@ def Graded(self, base_ring=None): @cached_method def Super(self, base_ring=None): r""" - Return the subcategory of the super objects of ``self``. + Return the super-analogue category of ``self``. INPUT:: @@ -393,7 +393,8 @@ def Super(self, base_ring=None): Category of graded modules over Integer Ring sage: Coalgebras(QQ).Super() - Join of Category of graded modules over Rational Field and Category of coalgebras over Rational Field + Join of Category of graded modules over Rational Field + and Category of coalgebras over Rational Field sage: AlgebrasWithBasis(QQ).Super() Category of graded algebras with basis over Rational Field From d0932c325ede70e04db1b659bcfbf86a7b691e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Mon, 30 Mar 2015 15:54:02 +0300 Subject: [PATCH 0142/1872] Removed inheritance from matrix, added methods and attributes --- .../combinat/root_system/coxeter_matrix.py | 72 +++++++++++++------ 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index cc826e6e835..2a18a8ee127 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -35,7 +35,7 @@ from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family -class CoxeterMatrix(Matrix_generic_dense, CoxeterType): +class CoxeterMatrix(CoxeterType): """ A Coxeter matrix. @@ -111,8 +111,7 @@ class CoxeterMatrix(Matrix_generic_dense, CoxeterType): @staticmethod def __classcall_private__(cls, *args, **kwds): """ - Normalize input so we can inherit from a dense matrix with the - appropriate ring. + Normalize input so we can get the appropriate ring. .. NOTE:: @@ -207,7 +206,6 @@ def __classcall_private__(cls, *args, **kwds): j = verts.index(e[1]) data[j][i] = data[i][j] = m base_ring = (base_ring.one()*m).parent() - data = MatrixSpace(base_ring,n)(data) index_set = tuple(verts) args = [data] else: @@ -272,15 +270,21 @@ def __init__(self, parent, data, coxeter_type, index_set): sage: C = CoxeterMatrix(['A', 2, 1]) sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) """ - Matrix_generic_dense.__init__(self, parent, data, False, True) + + self._matrix = Matrix_generic_dense(parent,data,False,True) + self._matrix.set_immutable() + # Matrix_generic_dense.__init__(self, parent, data, False, True) - if self.base_ring() not in [ZZ,QQ]: + if self._matrix.base_ring() not in [ZZ,QQ]: self._is_cyclotomic = False else: self._is_cyclotomic = True self._coxeter_type = coxeter_type self._index_set = index_set - self.set_immutable() + self.rank = self._matrix.nrows() + + self._dict = {(self._index_set[i],self._index_set[j]):self._matrix[i,j] + for i in range(self.rank) for j in range(self.rank)} def __reduce__(self): """ @@ -296,6 +300,27 @@ def __reduce__(self): return (CoxeterMatrix, (self.parent(), self.list(), self._coxeter_type, self._index_set)) + def __repr__(self): + """ + String representation of the Coxeter matrix. + """ + + return self._matrix.__repr__() + + def __getitem__(self, key): + + return self._dict[key] + + def _matrix_(self, R = None): + """ + Return ``self`` as a matrix over the ring ``R``. + """ + + if R != None: + return self._matrix.change_ring(R) + else: + return self._matrix + ########################################################################## # Coxeter type methods @@ -336,18 +361,19 @@ def coxeter_type(self): return self return self._coxeter_type - def rank(self): - r""" - Return the rank of ``self``. - - EXAMPLES:: - - sage: CoxeterMatrix(['C',3]).rank() - 3 - sage: CoxeterMatrix(["A2","B2","F4"]).rank() - 8 - """ - return len(self._index_set) + # It seems that this method should be an attribute + # def rank(self): + # r""" + # Return the rank of ``self``. + # + # EXAMPLES:: + # + # sage: CoxeterMatrix(['C',3]).rank() + # 3 + # sage: CoxeterMatrix(["A2","B2","F4"]).rank() + # 8 + # """ + # return len(self._index_set) def coxeter_matrix(self): r""" @@ -386,14 +412,14 @@ def coxeter_graph(self): sage: C.coxeter_graph() Graph on 4 vertices """ - n = self.nrows() + n = self.rank I = self.index_set() val = lambda x: infinity if x == -1 else x - G = Graph([(I[i], I[j], val(self[i, j])) + G = Graph([(I[i], I[j], val((self._matrix)[i, j])) for i in range(n) for j in range(i) - if self[i, j] not in [1, 2]]) + if (self._matrix)[i, j] not in [1, 2]]) G.add_vertices(I) - return G.copy(immutable=True) + return G.copy(immutable = True) def is_simply_laced(self): """ From 4ca6874b91c8c76966c71cc0bc16a7b4985bb43b Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Wed, 1 Apr 2015 16:20:27 +0200 Subject: [PATCH 0143/1872] merged parallelisation from SageManifold --- src/sage/tensor/modules/parallel_utilities.py | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/sage/tensor/modules/parallel_utilities.py diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py new file mode 100644 index 00000000000..9ace188731e --- /dev/null +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -0,0 +1,63 @@ +r""" +Parallelization utilities + +This module defines a class containing parallelization informations + +AUTHORS: + +- Eric Gourgoulhon, Michal Bejger, Marco Mancini (2014-2015): initial version + +""" + +#****************************************************************************** +# Copyright (C) 2015 Eric Gourgoulhon +# Copyright (C) 2015 Michal Bejger +# +# 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.parallel.ncpus import ncpus + + +class ManifoldParallelism(): + r""" + Class governing SageManifolds Parallelism. + + Contains information about parallelism of SageManifolds: + nproc = Number of processors (nproc) to use. + use_paral = Flag if parallelism is used. + Default is nproc=1 and use_paral=False + + """ + def __init__(self,nproc=1): + r""" + Intializes the parallelism. Normally only an instance of this + class is created in a global (visible) variable. + Default : 1 processor is used, so no parallelism. + """ + self.nproc = nproc + self.use_paral = True if self.nproc!=1 else False + + def __str__(self): + r""" + String to print the number of cores. + """ + return "Number of cpu used = "+str(self.nproc) + + def set(self,nproc=None): + r""" + Changes the status of the parallelism in SageManifolds. + If not argument is given, the number of processors will set + to the maximum of cores found. + """ + self.nproc = ncpus() if nproc is None else nproc + self.use_paral = True if self.nproc!=1 else False + + + +# initialisation of SageManifolds Parallelism +# probably to define in another file +manifoldPara = ManifoldParallelism(1) From 2f9352531d734bad923eb72bb335af843bfed3c8 Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Wed, 1 Apr 2015 16:23:39 +0200 Subject: [PATCH 0144/1872] added paralellization --- src/sage/tensor/modules/all.py | 1 + src/sage/tensor/modules/comp.py | 141 +++++++++++++++++++++++++++----- 2 files changed, 120 insertions(+), 22 deletions(-) diff --git a/src/sage/tensor/modules/all.py b/src/sage/tensor/modules/all.py index a6d8750ae90..f7720e41c37 100644 --- a/src/sage/tensor/modules/all.py +++ b/src/sage/tensor/modules/all.py @@ -1 +1,2 @@ from finite_rank_free_module import FiniteRankFreeModule + diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index ef44f8a7145..80cfc4562fa 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -248,6 +248,9 @@ class :class:`~sage.tensor.differential_form_element.DifferentialForm`) from sage.structure.sage_object import SageObject from sage.rings.integer import Integer +from sage.parallel.all import parallel +from sage.tensor.modules.parallel_utilities import manifoldPara +from operator import itemgetter class Components(SageObject): r""" @@ -1294,9 +1297,39 @@ def __add__(self, other): if other._sindex != self._sindex: raise ValueError("the two sets of components do not have the " + "same starting index") - result = self.copy() - for ind, val in other._comp.iteritems(): - result[[ind]] += val + + + if manifoldPara.use_paral : + # parallel sum + result = self._new_instance() + nproc = manifoldPara.nproc + lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + + ind_list = [ ind for ind, ocomp in other._comp.iteritems()] + ind_step = max(1,int(len(ind_list)/nproc/2)) + local_list = lol(ind_list,ind_step) + + # definition of the list of input parameters + listParalInput = [(self,other,ind_part) for ind_part in local_list] + + @parallel(p_iter='multiprocessing',ncpus=manifoldPara.nproc) + def paral_sum(a,b,local_list_ind): + partial = [] + for ind in local_list_ind: + partial.append([ind,a[[ind]]+b[[ind]]]) + return partial + + for ii,val in paral_sum(listParalInput): + for jj in val: + result[[jj[0]]] = jj[1] + + else: + # sequential + result = self.copy() + + for ind, val in other._comp.iteritems(): + result[[ind]] += val + return result def __radd__(self, other): @@ -1732,9 +1765,31 @@ def contract(self, *args): comp_for_contr = Components(self._ring, self._frame, ncontr, start_index=self._sindex) res = 0 - for ind in comp_for_contr.index_generator(): - res += self[[ind]] * other[[ind]] + + + if manifoldPara.use_paral: + # parallel contraction to scalar + + # parallel multiplication + @parallel(p_iter='multiprocessing',ncpus=manifoldPara.nproc) + def compprod(a,b): + return a*b + + # parallel list of inputs + partial = list(compprod([(other[[ind]],self[[ind]]) for ind in + comp_for_contr.index_generator() + ])) + res = sum(map(itemgetter(1),partial)) + else: + # sequential + res = 0 + for ind in comp_for_contr.index_generator(): + res += self[[ind]] * other[[ind]] + + print 'time contraction scalar: ',time.time()-marco_t0 return res + + # # Positions of self and other indices in the result # (None = the position is involved in a contraction and therefore @@ -1846,23 +1901,65 @@ def contract(self, *args): comp_for_contr = Components(self._ring, self._frame, ncontr, start_index=self._sindex) shift_o = self._nid - ncontr - for ind in res.non_redundant_index_generator(): - ind_s = [None for i in range(self._nid)] # initialization - ind_o = [None for i in range(other._nid)] # initialization - for i, pos in enumerate(rev_s): - ind_s[pos] = ind[i] - for i, pos in enumerate(rev_o): - ind_o[pos] = ind[shift_o+i] - sm = 0 - for ind_c in comp_for_contr.index_generator(): - ic = 0 - for pos_s, pos_o in contractions: - k = ind_c[ic] - ind_s[pos_s] = k - ind_o[pos_o] = k - ic += 1 - sm += self[[ind_s]] * other[[ind_o]] - res[[ind]] = sm + + if manifoldPara.use_paral: + # parallel computation + nproc = manifoldPara.nproc + lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + ind_list = [ind for ind in res.non_redundant_index_generator()] + ind_step = max(1,int(len(ind_list)/nproc/2)) + local_list = lol(ind_list,ind_step) + + listParalInput = [] + for ind_part in local_list: + listParalInput.append((self,other,ind_part,rev_s,rev_o,shift_o,contractions,comp_for_contr)) + + # definition of the parallel function + @parallel(p_iter='multiprocessing',ncpus=nproc) + def make_Contraction(this,other,local_list,rev_s,rev_o,shift_o,contractions,comp_for_contr): + local_res = [] + for ind in local_list: + ind_s = [None for i in range(this._nid)] # initialization + ind_o = [None for i in range(other._nid)] # initialization + for i, pos in enumerate(rev_s): + ind_s[pos] = ind[i] + for i, pos in enumerate(rev_o): + ind_o[pos] = ind[shift_o+i] + sm = 0 + for ind_c in comp_for_contr.index_generator(): + ic = 0 + for pos_s, pos_o in contractions: + k = ind_c[ic] + ind_s[pos_s] = k + ind_o[pos_o] = k + ic += 1 + sm += this[[ind_s]] * other[[ind_o]] + local_res.append([ind,sm]) + return local_res + + for ii, val in make_Contraction(listParalInput): + for jj in val : + res[[jj[0]]] = jj[1] + else: + # sequential + for ind in res.non_redundant_index_generator(): + ind_s = [None for i in range(self._nid)] # initialization + ind_o = [None for i in range(other._nid)] # initialization + for i, pos in enumerate(rev_s): + ind_s[pos] = ind[i] + for i, pos in enumerate(rev_o): + ind_o[pos] = ind[shift_o+i] + sm = 0 + for ind_c in comp_for_contr.index_generator(): + ic = 0 + for pos_s, pos_o in contractions: + k = ind_c[ic] + ind_s[pos_s] = k + ind_o[pos_o] = k + ic += 1 + sm += self[[ind_s]] * other[[ind_o]] + res[[ind]] = sm + return res From fb98b4d01681aa841740eef28ae2f1e3490d3793 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 2 Apr 2015 05:06:54 +0200 Subject: [PATCH 0145/1872] doc improvements to quiver.py: --- .../combinat/cluster_algebra_quiver/quiver.py | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index ddfa2d4c306..a0e6f3f4c95 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -1,12 +1,27 @@ r""" Quiver -A *quiver* is an oriented graphs without loops, two-cycles, or multiple edges. The edges are labelled by pairs `(i,-j)` -such that the matrix `M = (m_{ab})` with `m_{ab} = i, m_{ba} = -j` for an edge `(i,-j)` between vertices `a` and `b` is skew-symmetrizable. +A *quiver* is an oriented graph without loops, two-cycles, or multiple +edges. The edges are labelled by pairs `(i,-j)` (with `i` and `j` being +positive integers) such that the matrix `M = (m_{ab})` with +`m_{ab} = i, m_{ba} = -j` for an edge `(i,-j)` between vertices +`a` and `b` is skew-symmetrizable. + +.. WARNING: + + This is not the standard definition of a quiver. Normally, in + cluster algebra theory, a quiver is defined as an oriented graph + without loops and two-cycles but with multiple edges allowed; the + edges are unlabelled. This notion of quivers, however, can be seen + as a particular case of our notion of quivers. Namely, if we have + a quiver (in the regular sense of this word) with (precisely) + `i` edges from `a` to `b`, then we represent it by a quiver + (in our sense of this word) with an edge from `a` to `b` labelled + by the pair `(i,-i)`. For the compendium on the cluster algebra and quiver package see - http://arxiv.org/abs/1102.4844. + http://arxiv.org/abs/1102.4844. AUTHORS: @@ -24,16 +39,12 @@ #***************************************************************************** from sage.structure.sage_object import SageObject from copy import copy -from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.all import cached_method from sage.rings.all import ZZ, CC, infinity from sage.graphs.all import Graph, DiGraph from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType, QuiverMutationType_Irreducible, QuiverMutationType_Reducible, _edge_list_to_matrix from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part, _digraph_mutate, _matrix_to_digraph, _dg_canonical_form, _mutation_class_iter, _digraph_to_dig6, _dig6_to_matrix from sage.combinat.cluster_algebra_quiver.mutation_type import _connected_mutation_type, _mutation_type_from_data, is_mutation_finite -from sage.groups.perm_gps.permgroup import PermutationGroup - class ClusterQuiver(SageObject): """ The *quiver* associated to an *exchange matrix*. @@ -909,7 +920,8 @@ def m(self): def canonical_label( self, certify=False ): """ - Returns the canonical labelling of ``self``, see sage.graphs.graph.GenericGraph.canonical_label. + Returns the canonical labelling of ``self``, see + :meth:`sage.graphs.graph.GenericGraph.canonical_label`. INPUT: @@ -1604,18 +1616,20 @@ def fan(self): seeds is made of a quiver and `n` cluster variables (that form a cluster). - Each cluster variable is mapped to a vector `d` in `\ZZ^n` by - using its denominator written as + Each cluster variable is mapped to the vector + `d = (d_1, d_2, \ldots, d_n) \in \ZZ^n`, where .. MATH:: - \prod_{i=1}^{n} x_i^d_i. + \prod_{i=1}^{n} x_i^d_i - By convention the denominator of each initial variable `x_i` is - `x_i^{-1}`. + is the denominator of this cluster variable (written in lowest + terms). By convention, the denominator of each initial + variable `x_i` is `x_i^{-1}`. - Using this map, every cluster defines a cone in `\ZZ^n`. These - are the maximal cones of the cluster fan. + Using this map, every cluster defines a cone in `\ZZ^n` -- + the cone spanned by the vectors corresponding to its cluster + variables. These are the maximal cones of the cluster fan. EXAMPLES:: @@ -1652,3 +1666,4 @@ def fan(self): return Fan([Cone([vector(v.almost_positive_root()) for v in s.cluster()]) for s in seed.mutation_class()]) + From 82ed22231efa4aa698097a885b43f5fa07b82422 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 2 Apr 2015 05:08:58 +0200 Subject: [PATCH 0146/1872] trivial doc fix --- src/sage/combinat/cluster_algebra_quiver/quiver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index a0e6f3f4c95..3c9b4a57b56 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -19,7 +19,7 @@ (in our sense of this word) with an edge from `a` to `b` labelled by the pair `(i,-i)`. -For the compendium on the cluster algebra and quiver package see +For the compendium on the cluster algebra and quiver package see :: http://arxiv.org/abs/1102.4844. From b29650b87b103a465d66de189182a0e7dcf4fde9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 1 Apr 2015 23:23:47 -0700 Subject: [PATCH 0147/1872] Made it so you must explicitly designate graded as a super category --- src/sage/algebras/clifford_algebra.py | 3 +- .../categories/hopf_algebras_with_basis.py | 1 + src/sage/categories/super_algebras.py | 17 ++++++-- .../categories/super_algebras_with_basis.py | 15 ++++++- .../super_hopf_algebras_with_basis.py | 35 ++++++++++++++++ src/sage/categories/super_modules.py | 41 ++++++++----------- 6 files changed, 82 insertions(+), 30 deletions(-) create mode 100644 src/sage/categories/super_hopf_algebras_with_basis.py diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 8225292888f..9e02718b022 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1412,7 +1412,8 @@ def __init__(self, R, names): sage: E. = ExteriorAlgebra(QQ) sage: TestSuite(E).run() """ - CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, HopfAlgebrasWithBasis(R).Super()) + cat = HopfAlgebrasWithBasis(R).Super().Graded() + CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, cat) # TestSuite will fail if the HopfAlgebra classes will ever have tests for # the coproduct being an algebra morphism -- since this is really a # Hopf superalgebra, not a Hopf algebra. diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index 005cb59dde6..e14cfe92722 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -146,6 +146,7 @@ def example(self, G = None): FiniteDimensional = LazyImport('sage.categories.finite_dimensional_hopf_algebras_with_basis', 'FiniteDimensionalHopfAlgebrasWithBasis') Graded = LazyImport('sage.categories.graded_hopf_algebras_with_basis', 'GradedHopfAlgebrasWithBasis') + Super = LazyImport('sage.categories.super_hopf_algebras_with_basis', 'SuperHopfAlgebrasWithBasis') class ParentMethods: diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py index 355bf857758..ff6cc9a147e 100644 --- a/src/sage/categories/super_algebras.py +++ b/src/sage/categories/super_algebras.py @@ -9,6 +9,9 @@ #****************************************************************************** from sage.categories.super_modules import SuperModulesCategory +from sage.categories.algebras import Algebras +from sage.categories.modules import Modules +from sage.misc.lazy_import import LazyImport class SuperAlgebras(SuperModulesCategory): """ @@ -18,14 +21,22 @@ class SuperAlgebras(SuperModulesCategory): sage: Algebras(ZZ).Super() Category of super algebras over Integer Ring - sage: Algebras(ZZ).Super().super_categories() - [Category of graded algebras over Integer Ring, - Category of super modules over Integer Ring] TESTS:: sage: TestSuite(Algebras(ZZ).Super()).run() """ + def super_categories(self): + """ + EXAMPLES:: + + sage: Algebras(ZZ).Super().super_categories() + [Category of graded algebras over Integer Ring, + Category of super modules over Integer Ring] + """ + R = self.base_ring() + return [Algebras(R).Graded(), Modules(R).Super()] + class ParentMethods: pass diff --git a/src/sage/categories/super_algebras_with_basis.py b/src/sage/categories/super_algebras_with_basis.py index 9ba242c829f..1996e9aab73 100644 --- a/src/sage/categories/super_algebras_with_basis.py +++ b/src/sage/categories/super_algebras_with_basis.py @@ -9,6 +9,8 @@ #****************************************************************************** from sage.categories.super_modules import SuperModulesCategory +from sage.categories.algebras import Algebras +from sage.categories.modules import Modules class SuperAlgebrasWithBasis(SuperModulesCategory): """ @@ -20,13 +22,24 @@ class SuperAlgebrasWithBasis(SuperModulesCategory): Category of super algebras with basis over Integer Ring sage: sorted(C.super_categories(), key=str) [Category of graded algebras with basis over Integer Ring, - Category of super algebras over Integer Ring, Category of super modules with basis over Integer Ring] TESTS:: sage: TestSuite(C).run() """ + def super_categories(self): + """ + EXAMPLES:: + + sage: Algebras(ZZ).WithBasis().Super().super_categories() + [Category of graded algebras with basis over Integer Ring, + Category of super modules with basis over Integer Ring] + """ + R = self.base_ring() + return [Algebras(R).WithBasis().Graded(), + Modules(R).WithBasis().Super()] + class ParentMethods: pass diff --git a/src/sage/categories/super_hopf_algebras_with_basis.py b/src/sage/categories/super_hopf_algebras_with_basis.py new file mode 100644 index 00000000000..f1f2f1d8773 --- /dev/null +++ b/src/sage/categories/super_hopf_algebras_with_basis.py @@ -0,0 +1,35 @@ +r""" +Super algebras with basis +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.categories.super_modules import SuperModulesCategory + +class SuperHopfAlgebrasWithBasis(SuperModulesCategory): + """ + The category of super algebras with a distinguished basis + + EXAMPLES:: + + sage: C = HopfAlgebras(ZZ).WithBasis().Super(); C + Category of super hopf algebras with basis over Integer Ring + sage: sorted(C.super_categories(), key=str) + [Category of hopf algebras with basis over Integer Ring, + Category of super algebras over Integer Ring, + Category of super algebras with basis over Integer Ring] + + TESTS:: + + sage: TestSuite(C).run() + """ + class ParentMethods: + pass + + class ElementMethods: + pass + diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py index 154ca9f6168..46c170080cb 100644 --- a/src/sage/categories/super_modules.py +++ b/src/sage/categories/super_modules.py @@ -124,31 +124,6 @@ def _repr_object_names(self): """ return "super {}".format(self.base_category()._repr_object_names()) - @classmethod - def default_super_categories(cls, category, *args): - """ - Returns the default super categories of ``category.Subobjects()`` - - Mathematical meaning: if `A` is a super version of `B`, - then `A` is also a graded version of `B`. - - INPUT: - - - ``cls`` -- the class ``SubobjectsCategory`` - - ``category`` -- a category `Cat` - - OUTPUT: a (join) category - - In practice, this returns ``category.Subquotients()``, joined - together with the result of the method - :meth:`RegressiveCovariantConstructionCategory.default_super_categories() ` - (that is the join of ``category`` and ``cat.Subobjects()`` for - each ``cat`` in the super categories of ``category``). - - EXAMPLES:: - """ - return Category.join([category.Graded(), super(SuperModulesCategory, cls).default_super_categories(category, *args)]) - class SuperModules(SuperModulesCategory): """ The category of super modules. @@ -170,6 +145,22 @@ class SuperModules(SuperModulesCategory): sage: TestSuite(Modules(ZZ).Super()).run() """ + def super_categories(self): + """ + EXAMPLES:: + + sage: Modules(ZZ).Super().super_categories() + [Category of graded modules over Integer Ring] + + Nota bene:: + + sage: Modules(QQ).Super() + Category of super modules over Rational Field + sage: Modules(QQ).Super().super_categories() + [Category of graded modules over Rational Field] + """ + return [Modules(self.base_ring()).Graded()] + def extra_super_categories(self): r""" Adds :class:`VectorSpaces` to the super categories of ``self`` if From 208015433bc7538a62c47fb09b27a58def53704d Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Fri, 3 Apr 2015 14:34:02 +0200 Subject: [PATCH 0148/1872] Renamed class for parallelism in the Singleton class TensorParallelism. Added doc/test for TensorParallelism --- .../reference/tensor_free_modules/index.rst | 2 + src/sage/tensor/modules/all.py | 1 + src/sage/tensor/modules/comp.py | 87 ++++++++++++++++--- src/sage/tensor/modules/parallel_utilities.py | 67 +++++++++----- 4 files changed, 125 insertions(+), 32 deletions(-) diff --git a/src/doc/en/reference/tensor_free_modules/index.rst b/src/doc/en/reference/tensor_free_modules/index.rst index c8f0b58b988..63027c4c407 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/parallel_utilities + .. include:: ../footer.txt diff --git a/src/sage/tensor/modules/all.py b/src/sage/tensor/modules/all.py index f7720e41c37..77a1d100900 100644 --- a/src/sage/tensor/modules/all.py +++ b/src/sage/tensor/modules/all.py @@ -1,2 +1,3 @@ from finite_rank_free_module import FiniteRankFreeModule +from parallel_utilities import TensorParallelism diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 80cfc4562fa..320693bc4a4 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -249,7 +249,7 @@ class :class:`~sage.tensor.differential_form_element.DifferentialForm`) from sage.structure.sage_object import SageObject from sage.rings.integer import Integer from sage.parallel.all import parallel -from sage.tensor.modules.parallel_utilities import manifoldPara +from sage.tensor.modules.parallel_utilities import TensorParallelism from operator import itemgetter class Components(SageObject): @@ -283,7 +283,7 @@ class Components(SageObject): EXAMPLES: Set of components with 2 indices on a 3-dimensional vector space, the frame - being some basis of the vector space:: + being some basis of the vector space:: sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) @@ -1280,6 +1280,19 @@ def __add__(self, other): sage: s == a+b True + Parallel computation:: + + sage: TensorParallelism().set(2) + sage: print TensorParallelism() + Number of cpu used = 2 + sage: s = a.__add__(b) ; s + 1-index components w.r.t. [1, 2, 3] + sage: s[:] + [5, 5, 3] + sage: s == a+b + True + sage: TensorParallelism().set(1) + """ if other == 0: return +self @@ -1299,10 +1312,10 @@ def __add__(self, other): "same starting index") - if manifoldPara.use_paral : + if TensorParallelism().use_paral : # parallel sum result = self._new_instance() - nproc = manifoldPara.nproc + nproc = TensorParallelism().nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in other._comp.iteritems()] @@ -1312,7 +1325,7 @@ def __add__(self, other): # definition of the list of input parameters listParalInput = [(self,other,ind_part) for ind_part in local_list] - @parallel(p_iter='multiprocessing',ncpus=manifoldPara.nproc) + @parallel(p_iter='multiprocessing',ncpus=TensorParallelism().nproc) def paral_sum(a,b,local_list_ind): partial = [] for ind in local_list_ind: @@ -1384,6 +1397,19 @@ def __sub__(self, other): sage: s == a - b True + Parallel computation:: + + sage: TensorParallelism().set(2) + sage: print TensorParallelism() + Number of cpu used = 2 + sage: s = a.__sub__(b) ; s + 1-index components w.r.t. [1, 2, 3] + sage: s[:] + [-3, -5, -9] + sage: s == a - b + True + sage: TensorParallelism().set(1) + """ if other == 0: return +self @@ -1686,6 +1712,24 @@ def contract(self, *args): sage: [sum(a[j]*b[i,j] for j in range(3)) for i in range(3)] # check [12, 24, 36] + Parallel computation:: + + sage: TensorParallelism().set(2) + sage: print TensorParallelism() + Number of cpu used = 2 + sage: s = a.contract(0, b, 0) ; s + 1-index components w.r.t. [ + (1, 0, 0), + (0, 1, 0), + (0, 0, 1) + ] + sage: s[:] + [28, 32, 36] + sage: s = a.contract(0, b, 1) ; s[:] + [12, 24, 36] + sage: TensorParallelism().set(1) + + Contraction on 2 indices:: sage: c = a*b ; c @@ -1706,6 +1750,28 @@ def contract(self, *args): ....: for j in range(3)) for i in range(3)] [-285, 570, 855] + Parallel computation:: + + sage: TensorParallelism().set(2) + sage: print TensorParallelism() + Number of cpu used = 2 + sage: c = a*b ; c + 3-indices components w.r.t. [ + (1, 0, 0), + (0, 1, 0), + (0, 0, 1) + ] + sage: s = c.contract(1,2, b, 0,1) ; s + 1-index components w.r.t. [ + (1, 0, 0), + (0, 1, 0), + (0, 0, 1) + ] + sage: s[:] + [-285, 570, 855] + sage: TensorParallelism().set(1) + + Consistency check with :meth:`trace`:: sage: b = a*a ; b # the tensor product of a with itself @@ -1767,11 +1833,11 @@ def contract(self, *args): res = 0 - if manifoldPara.use_paral: + if TensorParallelism().use_paral: # parallel contraction to scalar # parallel multiplication - @parallel(p_iter='multiprocessing',ncpus=manifoldPara.nproc) + @parallel(p_iter='multiprocessing',ncpus=TensorParallelism().nproc) def compprod(a,b): return a*b @@ -1786,7 +1852,6 @@ def compprod(a,b): for ind in comp_for_contr.index_generator(): res += self[[ind]] * other[[ind]] - print 'time contraction scalar: ',time.time()-marco_t0 return res @@ -1902,9 +1967,9 @@ def compprod(a,b): start_index=self._sindex) shift_o = self._nid - ncontr - if manifoldPara.use_paral: + if TensorParallelism().use_paral: # parallel computation - nproc = manifoldPara.nproc + nproc = TensorParallelism().nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in res.non_redundant_index_generator()] ind_step = max(1,int(len(ind_list)/nproc/2)) @@ -1936,7 +2001,7 @@ def make_Contraction(this,other,local_list,rev_s,rev_o,shift_o,contractions,comp sm += this[[ind_s]] * other[[ind_o]] local_res.append([ind,sm]) return local_res - + for ii, val in make_Contraction(listParalInput): for jj in val : res[[jj[0]]] = jj[1] diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py index 9ace188731e..d5f0d71b69d 100644 --- a/src/sage/tensor/modules/parallel_utilities.py +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -1,17 +1,18 @@ r""" Parallelization utilities -This module defines a class containing parallelization informations +This module defines a singleton class containing parallelization +informations when using tensor algebra. + AUTHORS: -- Eric Gourgoulhon, Michal Bejger, Marco Mancini (2014-2015): initial version +- Marco Mancini, Eric Gourgoulhon, Michal Bejger (2015): initial version """ #****************************************************************************** -# Copyright (C) 2015 Eric Gourgoulhon -# Copyright (C) 2015 Michal Bejger +# Copyright (C) 2015 Marco Mancini # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -19,31 +20,51 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.structure.sage_object import SageObject +from sage.misc.fast_methods import Singleton from sage.parallel.ncpus import ncpus -class ManifoldParallelism(): +class TensorParallelism(Singleton, SageObject): r""" - Class governing SageManifolds Parallelism. + Class governing Tensors Parallelism. - Contains information about parallelism of SageManifolds: - nproc = Number of processors (nproc) to use. - use_paral = Flag if parallelism is used. - Default is nproc=1 and use_paral=False + Contains information about parallelism of Tensor algebra: + + * ``nproc`` -- (default: 1) number of processors to use in computations. + * ``use_paral`` -- (default: ``False``) flag, ``True`` if parallelism is used. """ - def __init__(self,nproc=1): + def __init__(self): r""" - Intializes the parallelism. Normally only an instance of this - class is created in a global (visible) variable. + Intializes the parallelism. Only an instance (Singleton) of this + class is created. Default : 1 processor is used, so no parallelism. + + TEST :: + + sage: TP = TensorParallelism() + sage: print TP + Number of cpu used = 1 + + Test of the singleton character:: + + sage: TensorParallelism() is TP + True + """ - self.nproc = nproc - self.use_paral = True if self.nproc!=1 else False + self.nproc = 1 + self.use_paral = False - def __str__(self): + def _repr_(self): r""" String to print the number of cores. + + TEST :: + + sage: TensorParallelism()._repr_() + 'Number of cpu used = 1' + """ return "Number of cpu used = "+str(self.nproc) @@ -52,12 +73,16 @@ def set(self,nproc=None): Changes the status of the parallelism in SageManifolds. If not argument is given, the number of processors will set to the maximum of cores found. + + EXAMPLE :: + + sage: print TensorParallelism() + Number of cpu used = 1 + sage: TensorParallelism().set(4) + sage: print TensorParallelism() + Number of cpu used = 4 + """ self.nproc = ncpus() if nproc is None else nproc self.use_paral = True if self.nproc!=1 else False - - -# initialisation of SageManifolds Parallelism -# probably to define in another file -manifoldPara = ManifoldParallelism(1) From 23e2b43f9f7112d3c4cfe4f22712db883f56b3d2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 3 Apr 2015 22:32:41 +0000 Subject: [PATCH 0149/1872] Fixed bug in guessing code and slightly modified guessing algorithm to favor Schensted --- src/sage/combinat/skew_tableau.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 23de6091f15..849dc2829bb 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -774,8 +774,8 @@ def rectify(self, force=None): INPUT: - ``force`` -- optional: if set to ``'jdt'``, rectifies by jeu de taquin; - if set to ``'schensted'``, rectifies by Schensted insertion of the - reading word; otherwise, guesses which will be faster. + if set to ``'schensted'``, rectifies by Schensted insertion of the + reading word; otherwise, guesses which will be faster. EXAMPLES:: @@ -797,7 +797,7 @@ def rectify(self, force=None): labda = self.outer_shape() musize = self.inner_shape().size() labdasize = labda.size() - if force == 'jdt' or (force != 'schensted' and musize < len(labda) * (labdasize - musize)**(1/2)): + if force == 'jdt' or (force != 'schensted' and musize**2 < len(labda) * (labdasize - musize)): rect = self inner_corners = rect.inner_shape().corners() while len(inner_corners) > 0: From 5659f29c3a1d5a7ae9601cece8198a6e277384fa Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Tue, 7 Apr 2015 16:26:27 +0200 Subject: [PATCH 0150/1872] Added parallelization on tensor product --- src/sage/tensor/modules/all.py | 2 +- src/sage/tensor/modules/comp.py | 170 ++++++++++++++---- src/sage/tensor/modules/parallel_utilities.py | 61 +++++-- 3 files changed, 188 insertions(+), 45 deletions(-) diff --git a/src/sage/tensor/modules/all.py b/src/sage/tensor/modules/all.py index 77a1d100900..0c630e7ef4d 100644 --- a/src/sage/tensor/modules/all.py +++ b/src/sage/tensor/modules/all.py @@ -1,3 +1,3 @@ from finite_rank_free_module import FiniteRankFreeModule -from parallel_utilities import TensorParallelism +from parallel_utilities import TensorParallelism,set_nproc,get_nproc diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 320693bc4a4..c86bb14e0ee 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1282,16 +1282,15 @@ def __add__(self, other): Parallel computation:: - sage: TensorParallelism().set(2) - sage: print TensorParallelism() - Number of cpu used = 2 + sage: set_nproc(2); print get_nproc() + 2 sage: s = a.__add__(b) ; s 1-index components w.r.t. [1, 2, 3] sage: s[:] [5, 5, 3] sage: s == a+b True - sage: TensorParallelism().set(1) + sage: set_nproc(1) """ if other == 0: @@ -1312,10 +1311,10 @@ def __add__(self, other): "same starting index") - if TensorParallelism().use_paral : + if TensorParallelism()._use_paral : # parallel sum result = self._new_instance() - nproc = TensorParallelism().nproc + nproc = TensorParallelism()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in other._comp.iteritems()] @@ -1325,7 +1324,7 @@ def __add__(self, other): # definition of the list of input parameters listParalInput = [(self,other,ind_part) for ind_part in local_list] - @parallel(p_iter='multiprocessing',ncpus=TensorParallelism().nproc) + @parallel(p_iter='multiprocessing',ncpus=nproc) def paral_sum(a,b,local_list_ind): partial = [] for ind in local_list_ind: @@ -1399,16 +1398,15 @@ def __sub__(self, other): Parallel computation:: - sage: TensorParallelism().set(2) - sage: print TensorParallelism() - Number of cpu used = 2 + sage: set_nproc(2); print get_nproc() + 2 sage: s = a.__sub__(b) ; s 1-index components w.r.t. [1, 2, 3] sage: s[:] [-3, -5, -9] sage: s == a - b True - sage: TensorParallelism().set(1) + sage: set_nproc(1) """ if other == 0: @@ -1472,6 +1470,20 @@ def __mul__(self, other): sage: s == a*b True + Parallel computation:: + sage: set_nproc(2);print get_nproc() + 2 + sage: s = a.__mul__(b) ; s + 2-indices components w.r.t. [1, 2, 3] + sage: s[:] + [ 4 5 6] + [ 0 0 0] + [-12 -15 -18] + sage: s == a*b + True + sage: set_nproc(1);print get_nproc() + 1 + """ if not isinstance(other, Components): raise TypeError("the second argument for the tensor product " + @@ -1506,18 +1518,64 @@ def __mul__(self, other): # (it would not deal correctly with redundant indices) # So we use a loop specific to the current case and return the # result: - for ind in result.non_redundant_index_generator(): - result[[ind]] = self[[ind[0]]] * self[[ind[1]]] - return result + + if TensorParallelism()._use_paral : + nproc = TensorParallelism()._nproc + lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + + ind_list = [ ind for ind in result.non_redundant_index_generator()] + ind_step = max(1,int(len(ind_list)/nproc)) + local_list = lol(ind_list,ind_step) + + # definition of the list of input parameters + listParalInput = [(self,ind_part) for ind_part in local_list] + + @parallel(p_iter='multiprocessing',ncpus=nproc) + def paral_mul(a,local_list_ind): + return [[ind,a[[ind[0]]]*a[[ind[1]]]] for ind in local_list_ind] + + for ii,val in paral_mul(listParalInput): + for jj in val: + result[[jj[0]]] = jj[1] + else: + + for ind in result.non_redundant_index_generator(): + result[[ind]] = self[[ind[0]]] * self[[ind[1]]] + return result else: result = Components(self._ring, self._frame, 2, self._sindex, self._output_formatter) else: result = Components(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter) - for ind_s, val_s in self._comp.iteritems(): - for ind_o, val_o in other._comp.iteritems(): - result._comp[ind_s + ind_o] = val_s * val_o + + if TensorParallelism()._use_paral : + nproc = TensorParallelism()._nproc + lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + + ind_list = [ ind for ind, ocomp in self._comp.iteritems()] + ind_step = max(1,int(len(ind_list)/nproc)) + local_list = lol(ind_list,ind_step) + + # definition of the list of input parameters + listParalInput = [(self,other,ind_part) for ind_part in local_list] + + @parallel(p_iter='multiprocessing',ncpus=nproc) + def paral_mul(a,b,local_list_ind): + partial = [] + for ind in local_list_ind: + for ind_o, val_o in b._comp.iteritems(): + partial.append([ind + ind_o,a[ind]*val_o]) + return partial + + for ii,val in paral_mul(listParalInput): + for jj in val: + result._comp[jj[0]] = jj[1] + else: + for ind_s, val_s in self._comp.iteritems(): + for ind_o, val_o in other._comp.iteritems(): + result._comp[ind_s + ind_o] = val_s * val_o + return result @@ -1714,9 +1772,8 @@ def contract(self, *args): Parallel computation:: - sage: TensorParallelism().set(2) - sage: print TensorParallelism() - Number of cpu used = 2 + sage: set_nproc(2); print get_nproc() + 2 sage: s = a.contract(0, b, 0) ; s 1-index components w.r.t. [ (1, 0, 0), @@ -1727,7 +1784,7 @@ def contract(self, *args): [28, 32, 36] sage: s = a.contract(0, b, 1) ; s[:] [12, 24, 36] - sage: TensorParallelism().set(1) + sage: set_nproc(1) Contraction on 2 indices:: @@ -1752,9 +1809,8 @@ def contract(self, *args): Parallel computation:: - sage: TensorParallelism().set(2) - sage: print TensorParallelism() - Number of cpu used = 2 + sage: set_nproc(2); print get_nproc() + 2 sage: c = a*b ; c 3-indices components w.r.t. [ (1, 0, 0), @@ -1769,7 +1825,7 @@ def contract(self, *args): ] sage: s[:] [-285, 570, 855] - sage: TensorParallelism().set(1) + sage: set_nproc(1) Consistency check with :meth:`trace`:: @@ -1833,11 +1889,11 @@ def contract(self, *args): res = 0 - if TensorParallelism().use_paral: + if TensorParallelism()._use_paral: # parallel contraction to scalar # parallel multiplication - @parallel(p_iter='multiprocessing',ncpus=TensorParallelism().nproc) + @parallel(p_iter='multiprocessing',ncpus=TensorParallelism()._nproc) def compprod(a,b): return a*b @@ -1967,9 +2023,9 @@ def compprod(a,b): start_index=self._sindex) shift_o = self._nid - ncontr - if TensorParallelism().use_paral: + if TensorParallelism()._use_paral: # parallel computation - nproc = TensorParallelism().nproc + nproc = TensorParallelism()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in res.non_redundant_index_generator()] ind_step = max(1,int(len(ind_list)/nproc/2)) @@ -3165,6 +3221,28 @@ def __mul__(self, other): sage: s == a*c True + Parallel computation:: + sage: set_nproc(2);print get_nproc() + 2 + sage: s = a.__mul__(b) ; s + 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) + sage: s[1,0,0,1] + 8 + sage: s[1,0,0,1] == a[1,0] * b[0,1] + True + sage: s == a*b + True + sage: s = a.__mul__(c) ; s + 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3) + sage: s[1,0,2,0] + -28 + sage: s[1,0,2,0] == a[1,0] * c[2,0] + True + sage: s == a*c + True + sage: set_nproc(1);print get_nproc() + 1 + """ if not isinstance(other, Components): raise TypeError("the second argument for the tensor product " + @@ -3188,12 +3266,38 @@ def __mul__(self, other): antisym.append(ns) result = CompWithSym(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter, sym, antisym) - for ind_s, val_s in self._comp.iteritems(): - for ind_o, val_o in other._comp.iteritems(): - result._comp[ind_s + ind_o] = val_s * val_o - return result + if TensorParallelism()._use_paral : + nproc = TensorParallelism()._nproc + lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + + ind_list = [ ind for ind, ocomp in self._comp.iteritems()] + ind_step = max(1,int(len(ind_list)/nproc)) + local_list = lol(ind_list,ind_step) + + # definition of the list of input parameters + listParalInput = [(self,other,ind_part) for ind_part in local_list] + + @parallel(p_iter='multiprocessing',ncpus=nproc) + def paral_mul(a,b,local_list_ind): + partial = [] + for ind in local_list_ind: + for ind_o, val_o in b._comp.iteritems(): + partial.append([ind + ind_o,a[ind]*val_o]) + return partial + + for ii,val in paral_mul(listParalInput): + for jj in val: + result._comp[jj[0]] = jj[1] + else: + for ind_s, val_s in self._comp.iteritems(): + for ind_o, val_o in other._comp.iteritems(): + result._comp[ind_s + ind_o] = val_s * val_o + + return result + + def trace(self, pos1, pos2): r""" Index contraction, taking care of the symmetries. diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py index d5f0d71b69d..8ced7b8a59f 100644 --- a/src/sage/tensor/modules/parallel_utilities.py +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -29,11 +29,16 @@ class TensorParallelism(Singleton, SageObject): r""" Class governing Tensors Parallelism. - Contains information about parallelism of Tensor algebra: - - * ``nproc`` -- (default: 1) number of processors to use in computations. - * ``use_paral`` -- (default: ``False``) flag, ``True`` if parallelism is used. - + Contains information about parallelism of Tensor algebra. + + EXAMPLE :: + + sage: print TensorParallelism() + Number of cpu used = 1 + sage: TensorParallelism().set(4) + sage: print TensorParallelism() + Number of cpu used = 4 + """ def __init__(self): r""" @@ -53,8 +58,8 @@ class is created. True """ - self.nproc = 1 - self.use_paral = False + self._nproc = 1 + self._use_paral = False def _repr_(self): r""" @@ -66,11 +71,11 @@ def _repr_(self): 'Number of cpu used = 1' """ - return "Number of cpu used = "+str(self.nproc) + return "Number of cpu used = "+str(self._nproc) def set(self,nproc=None): r""" - Changes the status of the parallelism in SageManifolds. + Changes the status of the parallelism in tensorial computations. If not argument is given, the number of processors will set to the maximum of cores found. @@ -83,6 +88,40 @@ def set(self,nproc=None): Number of cpu used = 4 """ - self.nproc = ncpus() if nproc is None else nproc - self.use_paral = True if self.nproc!=1 else False + self._nproc = ncpus() if nproc is None else nproc + self._use_paral = True if self._nproc!=1 else False + + + + +def set_nproc(nproc=None): + r""" + Changes the status of the parallelism in tensorial computations. + If not argument is given, the number of processors will set + to the maximum of cores found. + + EXAMPLE :: + + sage: get_nproc() + 1 + sage: set_nproc(4) + sage: get_nproc() + 4 + + """ + + TensorParallelism().set(nproc) + +def get_nproc(): + r""" + Return the number of processus used in tensorial computations. + + TEST :: + + sage: set_nproc(4) + sage: get_nproc() + 4 + + """ + return TensorParallelism()._nproc From 325e83284ff3b7e0fcb3cf3b6c196814ffb5874e Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Wed, 8 Apr 2015 16:28:31 +0200 Subject: [PATCH 0151/1872] Corrected error in parallelisation of __mul__. Added parallism for the symmetric __add__ --- src/sage/tensor/modules/comp.py | 54 +++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index c86bb14e0ee..f1412684a57 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1559,13 +1559,13 @@ def paral_mul(a,local_list_ind): # definition of the list of input parameters listParalInput = [(self,other,ind_part) for ind_part in local_list] - + @parallel(p_iter='multiprocessing',ncpus=nproc) def paral_mul(a,b,local_list_ind): partial = [] for ind in local_list_ind: for ind_o, val_o in b._comp.iteritems(): - partial.append([ind + ind_o,a[ind]*val_o]) + partial.append([ind + ind_o,a._comp[ind]*val_o]) return partial for ii,val in paral_mul(listParalInput): @@ -3284,7 +3284,7 @@ def paral_mul(a,b,local_list_ind): partial = [] for ind in local_list_ind: for ind_o, val_o in b._comp.iteritems(): - partial.append([ind + ind_o,a[ind]*val_o]) + partial.append([ind + ind_o,a._comp[ind]*val_o]) return partial for ii,val in paral_mul(listParalInput): @@ -4544,6 +4544,21 @@ def __add__(self, other): sage: s == a + c True + Parallel computation:: + + sage: set_nproc(2); print get_nproc() + 2 + sage: s = a.__add__(c) ; s # the symmetry is lost + 2-indices components w.r.t. (1, 2, 3) + sage: s[:] + [ 0 7 7] + [ 1 0 5] + [-7 5 0] + sage: s == a + c + True + sage: set_nproc(1) + + """ if other == 0: return +self @@ -4560,9 +4575,36 @@ def __add__(self, other): if other._sindex != self._sindex: raise ValueError("the two sets of components do not have the " + "same starting index") - result = self.copy() - for ind, val in other._comp.iteritems(): - result[[ind]] += val + + if TensorParallelism()._use_paral : + # parallel sum + result = self._new_instance() + nproc = TensorParallelism()._nproc + lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + + ind_list = [ ind for ind, ocomp in other._comp.iteritems()] + ind_step = max(1,int(len(ind_list)/nproc/2)) + local_list = lol(ind_list,ind_step) + + # definition of the list of input parameters + listParalInput = [(self,other,ind_part) for ind_part in local_list] + + @parallel(p_iter='multiprocessing',ncpus=nproc) + def paral_sum(a,b,local_list_ind): + partial = [] + for ind in local_list_ind: + partial.append([ind,a[[ind]]+b[[ind]]]) + return partial + + for ii,val in paral_sum(listParalInput): + for jj in val: + result[[jj[0]]] = jj[1] + + else: + # sequential + result = self.copy() + for ind, val in other._comp.iteritems(): + result[[ind]] += val return result else: return CompWithSym.__add__(self, other) From ab4a84d739f7616a89a324c4723b7233cf5beb3c Mon Sep 17 00:00:00 2001 From: Josh Swanson Date: Wed, 8 Apr 2015 21:39:38 -0700 Subject: [PATCH 0152/1872] Renamed 'force' to 'algorithm'; cleaned up code --- src/sage/combinat/skew_tableau.py | 56 ++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 849dc2829bb..81f583281aa 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -685,8 +685,8 @@ def to_chain(self, max_entry=None): def slide(self, corner=None): """ - Apply a jeu-de-taquin slide to ``self`` on the specified corner and - returns the new tableau. If no corner is given an arbitrary corner + Apply a jeu-de-taquin slide to ``self`` on the specified inner corner and + returns the new tableau. If no corner is given an arbitrary inner corner is chosen. See [FW]_ p12-13. @@ -761,9 +761,10 @@ def slide(self, corner=None): return SkewTableau(new_st) - def rectify(self, force=None): + def rectify(self, algorithm=None): """ - Return a :class:`Tableau` formed by applying the jeu de taquin + Return a :class:`StandardTableau`, :class:`SemistandardTableau`, + or just :class:`Tableau` formed by applying the jeu de taquin process to ``self``. See page 15 of [FW]_. REFERENCES: @@ -773,39 +774,54 @@ def rectify(self, force=None): Cambridge University Press 1997. INPUT: - - ``force`` -- optional: if set to ``'jdt'``, rectifies by jeu de taquin; + - ``algorithm`` -- optional: if set to ``'jdt'``, rectifies by jeu de taquin; if set to ``'schensted'``, rectifies by Schensted insertion of the reading word; otherwise, guesses which will be faster. EXAMPLES:: - sage: s = SkewTableau([[None,1],[2,3]]) - sage: s.rectify() + sage: S = SkewTableau([[None,1],[2,3]]) + sage: S.rectify() [[1, 3], [2]] - sage: SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]]).rectify() + sage: T = SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]]) + sage: T.rectify() [[1, 3, 4, 6], [2, 5]] - sage: SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]]).rectify('jdt') + sage: T.rectify(algorithm='jdt') [[1, 3, 4, 6], [2, 5]] - sage: SkewTableau([[None, None, None, 4],[None,None,1,6],[None,None,5],[2,3]]).rectify('schensted') + sage: T.rectify(algorithm='schensted') [[1, 3, 4, 6], [2, 5]] + sage: T.rectify(algorithm='spaghetti') + Traceback (most recent call last): + ... + ValueError: algorithm must be 'jdt', 'schensted', or None TESTS:: - sage: s + sage: S [[None, 1], [2, 3]] + sage: T + [[None, None, None, 4], [None, None, 1, 6], [None, None, 5], [2, 3]] """ - labda = self.outer_shape() - musize = self.inner_shape().size() - labdasize = labda.size() - if force == 'jdt' or (force != 'schensted' and musize**2 < len(labda) * (labdasize - musize)): + la = self.outer_shape() + mu_size = self.inner_shape().size() + la_size = la.size() + + # Roughly, use jdt with a small inner shape, Schensted with a large one + if algorithm is None: + if mu_size^2 < len(la) * (la_size - mu_size): + algorithm = 'jdt' + else: + algorithm = 'schensted' + + if algorithm == 'jdt': rect = self - inner_corners = rect.inner_shape().corners() - while len(inner_corners) > 0: + for i in range(mu_size): rect = rect.slide() - inner_corners = rect.inner_shape().corners() + elif algorithm == 'schensted': + rect = Tableau([]).insert_word(self.to_word()) else: - w = self.to_word() - rect = Tableau([]).insert_word(w) + raise ValueError("algorithm must be 'jdt', 'schensted', or None") + if self in SemistandardSkewTableaux(): return SemistandardTableau(rect[:]) if self in StandardSkewTableaux(): From 9785351a4006977fb21a65f25c6245e77f7acb4a Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 10 Apr 2015 21:09:40 +0000 Subject: [PATCH 0153/1872] moved definitions to where used; reordered type checking --- src/sage/combinat/skew_tableau.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 81f583281aa..05d306980bf 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -802,12 +802,12 @@ def rectify(self, algorithm=None): sage: T [[None, None, None, 4], [None, None, 1, 6], [None, None, 5], [2, 3]] """ - la = self.outer_shape() mu_size = self.inner_shape().size() - la_size = la.size() # Roughly, use jdt with a small inner shape, Schensted with a large one if algorithm is None: + la = self.outer_shape() + la_size = la.size() if mu_size^2 < len(la) * (la_size - mu_size): algorithm = 'jdt' else: @@ -821,11 +821,10 @@ def rectify(self, algorithm=None): rect = Tableau([]).insert_word(self.to_word()) else: raise ValueError("algorithm must be 'jdt', 'schensted', or None") - - if self in SemistandardSkewTableaux(): - return SemistandardTableau(rect[:]) if self in StandardSkewTableaux(): return StandardTableau(rect[:]) + if self in SemistandardSkewTableaux(): + return SemistandardTableau(rect[:]) return Tableau(rect) def standardization(self, check=True): From 77b801c6de17159081eea9a1c3fdc4952bf4288a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 12 Apr 2015 11:36:02 -0400 Subject: [PATCH 0154/1872] Inital stubs --- src/sage/categories/groups.py | 29 +++++ src/sage/categories/lie_groups.py | 73 ++++++++++++ src/sage/categories/manifolds.py | 98 ++++++++++++++++ src/sage/categories/metric_spaces.py | 114 ++++++++++++++++++ src/sage/categories/sets_cat.py | 13 +++ src/sage/categories/topological_spaces.py | 136 ++++++++++++++++++++++ 6 files changed, 463 insertions(+) create mode 100644 src/sage/categories/lie_groups.py create mode 100644 src/sage/categories/manifolds.py create mode 100644 src/sage/categories/metric_spaces.py create mode 100644 src/sage/categories/topological_spaces.py diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 785d81afc12..27bc4a0755a 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -18,6 +18,7 @@ from sage.categories.algebra_functor import AlgebrasCategory from sage.categories.cartesian_product import CartesianProductsCategory, cartesian_product from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.categories.topological_spaces import TopologicalSpacesCategory class Groups(CategoryWithAxiom): """ @@ -479,6 +480,7 @@ def conjugacy_class(self): return self.parent().conjugacy_class(self) Finite = LazyImport('sage.categories.finite_groups', 'FiniteGroups') + Lie = LazyImport('sage.categories.lie_groups', 'LieGroups', 'Lie') #Algebras = LazyImport('sage.categories.group_algebras', 'GroupAlgebras') class Commutative(CategoryWithAxiom): @@ -945,3 +947,30 @@ def lift(i, gen): for i,G in enumerate(F)]) return Family(gens_prod, lift, name="gen") + class Topological(TopologicalSpacesCategory): + """ + Category of topological groups. + + A topological group `G` is a group which has a topology such that + multiplication and taking inverses are continuous functions. + + REFERENCES: + + - :wikipedia:`Topological_group` + """ + def additional_structure(self): + r""" + Return ``None``. + + Indeed, the category of topolgocial groups defines no new + structure: a morphism of groups and of topological spaces + between two topological groups is a topological group morphism. + + .. SEEALSO:: :meth:`Category.additional_structure` + + EXAMPLES:: + + sage: Groups().Topological().additional_structure() + """ + return None + diff --git a/src/sage/categories/lie_groups.py b/src/sage/categories/lie_groups.py new file mode 100644 index 00000000000..2713286cba6 --- /dev/null +++ b/src/sage/categories/lie_groups.py @@ -0,0 +1,73 @@ +r""" +Lie Groups +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import LazyImport +from sage.categories.category import Category +from sage.categories.category_types import Category_over_base_ring +from sage.categories.sets_cat import Sets + +class Manifolds(Category_over_base_ring): + r""" + The category of Lie groups. + + A Lie group is a topological group with a smooth differentiable + manifold structure. + + INPUT: + + - ``k`` -- (default: ``RR``) the field `k` + + EXAMPLES:: + + sage: from sage.categories.lie_groups import LieGroups + sage: C = LieGroups(); C + Category of manifolds over Real Field + sage: C.super_categories() + [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, + Category of modules over Integer Ring] + sage: C = LieGroups(CC); C + Category of manifolds over Complex Field + + TESTS:: + + sage: TestSuite(C).run() + """ + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: from sage.categories.lie_groups import LieGroups + sage: LieGroups().super_categories() + """ + R = self.base_ring() + # TODO: Make this smooth differentiable manifolds + return [Groups().Topological(), Manifolds(R)] + + def additional_structure(self): + r""" + Return ``None``. + + Indeed, the category of Lie groups defines no new + structure: a morphism of topological spaces and of smooth + differentiable manifolds is a morphism as Lie groups. + + .. SEEALSO:: :meth:`Category.additional_structure` + + EXAMPLES:: + + sage: from sage.categories.lie_groups import LieGroups + sage: LieGroups().additional_structure() + """ + return None + diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py new file mode 100644 index 00000000000..56dbde629e9 --- /dev/null +++ b/src/sage/categories/manifolds.py @@ -0,0 +1,98 @@ +r""" +Manifolds +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import LazyImport +from sage.categories.category import Category +from sage.categories.category_types import Category_over_base_ring +from sage.categories.sets_cat import Sets +from sage.categories.fields import Fields +from sage.rings.all import RR + +class Manifolds(Category_over_base_ring): + r""" + The category of maniolds. + + Let `k` be a field. A `d`-dimensional `k`-*manifold* `M` is a + second countable Hausdorff space such that the neighborhood + of any point `x \in M` is homeomorphic to `k^d`. + + INPUT: + + - ``k`` -- (default: ``RR``) the field `k` + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds(); C + Category of manifolds over Real Field + sage: C.super_categories() + [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, + Category of modules over Integer Ring] + sage: C = Manifolds(CC); C + Category of manifolds over Complex Field + + TESTS:: + + sage: TestSuite(C).run() + """ + def __init__(self, k=RR): + """ + Initialize ``self``. + """ + if k not in Fields(): + raise ValueError("must be defined over a field") + Category_over_base_ring.__init__(self, k) + + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: from sage.categories.magmatic_algebras import MagmaticAlgebras + sage: MagmaticAlgebras(ZZ).super_categories() + [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, Category of modules over Integer Ring] + + sage: from sage.categories.additive_semigroups import AdditiveSemigroups + sage: MagmaticAlgebras(ZZ).is_subcategory((AdditiveSemigroups() & Magmas()).Distributive()) + True + """ + return [Sets().Topological()] + + def additional_structure(self): + r""" + Return ``None``. + + Indeed, the category of manifolds defines no new + structure: a morphism of metric spaces between manifolds + is a manifold morphism. + + .. SEEALSO:: :meth:`Category.additional_structure` + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().additional_structure() + """ + return None + + class Connected: + """ + The category of connected manifolds. + """ + class ParentMethods: + @abstract_method + def dimension(self): + """ + Return the dimension of ``self``. + """ + diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py new file mode 100644 index 00000000000..6b4dec93de3 --- /dev/null +++ b/src/sage/categories/metric_spaces.py @@ -0,0 +1,114 @@ +r""" +Topological Spaces +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.categories.category import Category +from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory + +class MetricSpaces(RegressiveCovariantConstructionCategory): + r""" + The category of metric spaces. + + A *metric* on a set `S` is a function `d : S \times S \to \RR` + such that: + + - `d(a, b) \geq 0`, + - `d(a, b) = 0` if and only if `a = b`. + + A metric space is a set `S` with a distinguished metric. + """ + + _functor_category = "Metric" + + @classmethod + def default_super_categories(cls, category): + """ + Return the default super categories of ``category.Metric()``. + + Mathematical meaning: if `A` is a metric space in the + category `C`, then `A` is also a topological space. + + INPUT: + + - ``cls`` -- the class ``MetricSpaces`` + - ``category`` -- a category `Cat` + + OUTPUT: + + A (join) category + + In practice, this returns ``category.Subquotients()``, joined + together with the result of the method + :meth:`RegressiveCovariantConstructionCategory.default_super_categories() + ` + (that is the join of ``category`` and ``cat.Metric()`` for + each ``cat`` in the super categories of ``category``). + + EXAMPLES: + + Consider ``category=Groups()``, which has ``cat=Monoids()`` as + super category. Then, a subgroup of a group `G` is + simultaneously a subquotient of `G`, a group by itself, and a + submonoid of `G`:: + + sage: Groups().Subobjects().super_categories() + [Category of groups, Category of subquotients of monoids, Category of subobjects of sets] + + Mind the last item above: there is indeed currently nothing + implemented about submonoids. + + This resulted from the following call:: + + sage: sage.categories.subobjects.SubobjectsCategory.default_super_categories(Groups()) + Join of Category of groups and Category of subquotients of monoids and Category of subobjects of sets + """ + return Category.join([category.Topological(), + super(MetricSpaces, cls).default_super_categories(category)]) + + class ParentMethods: + def _test_metric(self, **options): + r""" + Test that this metric space has a properly implemented metric. + + INPUT:: + + - ``options`` -- any keyword arguments accepted + by :meth:`_tester` + """ + tester = self._tester(**options) + S = tester.some_elements() + dist = self.metric() + for a in S: + for b in S: + d = dist(a, b) + if a != b: + tester.assertGreater(d, 0) + else: + tester.assertEqual(d, 0) + + def metric(self): + """ + Return the metric of ``self``. + """ + return lambda a,b: self.dist(a, b) + + @abstract_method + def dist(self, a, b): + """ + Return the distance between ``a`` and ``b`` in ``self``. + """ + + class ElementMethods: + def dist(self, b): + """ + Return the distance between ``self`` and ``b``. + """ + return self.parent().dist(self, b) + diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index b773014c8f0..1542235b364 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -649,6 +649,18 @@ def IsomorphicObjects(self): """ return IsomorphicObjectsCategory.category_of(self) + @cached_method + def Topological(self): + """ + Return the subcategory of the topological objects of ``self``. + + TESTS:: + + sage: TestSuite(Sets().Topological()).run() + """ + from sage.categories.topological_spaces import TopologicalSpacesCategory + return TopologicalSpacesCategory.category_of(self) + @cached_method def Algebras(self, base_ring): """ @@ -1555,6 +1567,7 @@ def cartesian_product(*elements): Facade = LazyImport('sage.categories.facade_sets', 'FacadeSets') Finite = LazyImport('sage.categories.finite_sets', 'FiniteSets', at_startup=True) + Topological = LazyImport('sage.categories.topological_spaces', 'TopologicalSpaces') class Infinite(CategoryWithAxiom): diff --git a/src/sage/categories/topological_spaces.py b/src/sage/categories/topological_spaces.py new file mode 100644 index 00000000000..c4ab000dd48 --- /dev/null +++ b/src/sage/categories/topological_spaces.py @@ -0,0 +1,136 @@ +r""" +Topological Spaces +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# 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.misc.lazy_attribute import lazy_class_attribute +from sage.categories.category import Category +from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory +from sage.categories.sets_cat import Sets + +class TopologicalSpacesCategory(RegressiveCovariantConstructionCategory): + + _functor_category = "Topological" + + # Currently no use case for this + @lazy_class_attribute + def _base_category_class(cls): + """ + Recover the class of the base category. + + OUTPUT: + + A *tuple* whose first entry is the base category class. + + .. WARNING:: + + This is only used for graded categories that are not + implemented as nested classes, and won't work otherwise. + + .. SEEALSO:: :meth:`__classcall__` + + EXAMPLES:: + + sage: GradedModules._base_category_class + (,) + sage: GradedAlgebrasWithBasis._base_category_class + (,) + + The reason for wrapping the base category class in a tuple is + that, often, the base category class implements a + :meth:`__classget__` method which would get in the way upon + attribute access:: + + sage: F = GradedAlgebrasWithBasis + sage: F._foo = F._base_category_class[0] + sage: F._foo + Traceback (most recent call last): + ... + AssertionError: base category class for <...AlgebrasWithBasis'> mismatch; + expected <...Algebras'>, got <...GradedAlgebrasWithBasis'> + """ + module_name = cls.__module__.replace("topological_","") + import sys + name = cls.__name__.replace("Topological","") + __import__(module_name) + module = sys.modules[module_name] + return (module.__dict__[name],) + + @staticmethod + def __classcall__(cls, category=None, *args): + """ + Magic support for putting topological categories in their own file. + + EXAMPLES:: + + sage: TopologicalSpaces() # indirect doctest + Category of graded modules over Integer Ring + sage: Sets().Topological() + Category of graded modules over Integer Ring + sage: TopologicalSpaces() is Sets().Topological() + True + + .. TODO:: + + Generalize this support for all other functorial + constructions if at some point we have a category ``Blah`` for + which we want to implement the construction ``Blah.Foo`` in a + separate file like we do for e.g. :class:`GradedModules`, + :class:`GradedAlgebras`, ... + + .. SEEALSO:: :meth:`_base_category_class` + """ + base_category_class = cls._base_category_class[0] + if isinstance(category, base_category_class): + return super(TopologicalSpacesCategory, cls).__classcall__(cls, category, *args) + else: + return base_category_class(category, *args).Topological() + + def _repr_object_names(self): + """ + EXAMPLES:: + + sage: Groups().Topological() # indirect doctest + Category of graded algebras with basis over Rational Field + """ + return "topological {}".format(self.base_category()._repr_object_names()) + +class TopologicalSpaces(TopologicalSpacesCategory): + """ + The category of topological spaces. + + EXAMPLES:: + + sage: Sets().Topological() + Category of topological spaces + sage: Sets().Topological().super_categories() + [Category of modules over Integer Ring] + + The category of topological spaces defines the topological structure, + which shall be preserved by morphisms:: + + sage: Sets().Topological().additional_structure() + Category of topological spaces + + TESTS:: + + sage: TestSuite(Sets().Topological()).run() + """ + # We must override the general object because the names don't match + _base_category_class = (Sets,) + + def _repr_object_names(self): + """ + EXAMPLES:: + + sage: Sets().Topological() # indirect doctest + Category of topological spaces + """ + return "topological spaces" + From bdb08fb0e246e3d9937ca67762dde3baa4d43725 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 12 Apr 2015 12:28:19 -0400 Subject: [PATCH 0155/1872] Some cleanup and getting category stubs ready. --- src/sage/categories/groups.py | 15 ----- src/sage/categories/lie_groups.py | 11 +++- src/sage/categories/topological_spaces.py | 74 ----------------------- 3 files changed, 10 insertions(+), 90 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 27bc4a0755a..1acde422a69 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -958,19 +958,4 @@ class Topological(TopologicalSpacesCategory): - :wikipedia:`Topological_group` """ - def additional_structure(self): - r""" - Return ``None``. - - Indeed, the category of topolgocial groups defines no new - structure: a morphism of groups and of topological spaces - between two topological groups is a topological group morphism. - - .. SEEALSO:: :meth:`Category.additional_structure` - - EXAMPLES:: - - sage: Groups().Topological().additional_structure() - """ - return None diff --git a/src/sage/categories/lie_groups.py b/src/sage/categories/lie_groups.py index 2713286cba6..c2af33196b1 100644 --- a/src/sage/categories/lie_groups.py +++ b/src/sage/categories/lie_groups.py @@ -15,8 +15,11 @@ from sage.categories.category import Category from sage.categories.category_types import Category_over_base_ring from sage.categories.sets_cat import Sets +from sage.categories.groups import Groups +from sage.categories.manifolds import Manifolds +from sage.rings.all import RR -class Manifolds(Category_over_base_ring): +class LieGroups(Category_over_base_ring): r""" The category of Lie groups. @@ -42,6 +45,12 @@ class Manifolds(Category_over_base_ring): sage: TestSuite(C).run() """ + def __init__(self, R=RR): + """ + Initialize ``self``. + """ + Category_over_base_ring.__init__(self, RR) + @cached_method def super_categories(self): """ diff --git a/src/sage/categories/topological_spaces.py b/src/sage/categories/topological_spaces.py index c4ab000dd48..80e31857508 100644 --- a/src/sage/categories/topological_spaces.py +++ b/src/sage/categories/topological_spaces.py @@ -18,80 +18,6 @@ class TopologicalSpacesCategory(RegressiveCovariantConstructionCategory): _functor_category = "Topological" - # Currently no use case for this - @lazy_class_attribute - def _base_category_class(cls): - """ - Recover the class of the base category. - - OUTPUT: - - A *tuple* whose first entry is the base category class. - - .. WARNING:: - - This is only used for graded categories that are not - implemented as nested classes, and won't work otherwise. - - .. SEEALSO:: :meth:`__classcall__` - - EXAMPLES:: - - sage: GradedModules._base_category_class - (,) - sage: GradedAlgebrasWithBasis._base_category_class - (,) - - The reason for wrapping the base category class in a tuple is - that, often, the base category class implements a - :meth:`__classget__` method which would get in the way upon - attribute access:: - - sage: F = GradedAlgebrasWithBasis - sage: F._foo = F._base_category_class[0] - sage: F._foo - Traceback (most recent call last): - ... - AssertionError: base category class for <...AlgebrasWithBasis'> mismatch; - expected <...Algebras'>, got <...GradedAlgebrasWithBasis'> - """ - module_name = cls.__module__.replace("topological_","") - import sys - name = cls.__name__.replace("Topological","") - __import__(module_name) - module = sys.modules[module_name] - return (module.__dict__[name],) - - @staticmethod - def __classcall__(cls, category=None, *args): - """ - Magic support for putting topological categories in their own file. - - EXAMPLES:: - - sage: TopologicalSpaces() # indirect doctest - Category of graded modules over Integer Ring - sage: Sets().Topological() - Category of graded modules over Integer Ring - sage: TopologicalSpaces() is Sets().Topological() - True - - .. TODO:: - - Generalize this support for all other functorial - constructions if at some point we have a category ``Blah`` for - which we want to implement the construction ``Blah.Foo`` in a - separate file like we do for e.g. :class:`GradedModules`, - :class:`GradedAlgebras`, ... - - .. SEEALSO:: :meth:`_base_category_class` - """ - base_category_class = cls._base_category_class[0] - if isinstance(category, base_category_class): - return super(TopologicalSpacesCategory, cls).__classcall__(cls, category, *args) - else: - return base_category_class(category, *args).Topological() - def _repr_object_names(self): """ EXAMPLES:: From 68b85e9898949b1d9707f5d62c467e7fa2467da9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 12 Apr 2015 16:48:58 -0400 Subject: [PATCH 0156/1872] Adding some more stubs for categories. --- src/sage/categories/all.py | 3 +- src/sage/categories/category_types.py | 29 +-- src/sage/categories/category_with_axiom.py | 1 + src/sage/categories/cw_complexes.py | 162 ++++++++++++++++ src/sage/categories/graphs.py | 61 ++++++ src/sage/categories/lie_groups.py | 49 ++--- src/sage/categories/manifolds.py | 179 ++++++++++++++---- src/sage/categories/metric_spaces.py | 44 +++-- src/sage/categories/sets_cat.py | 16 +- src/sage/categories/simplicial_complexes.py | 78 ++++++++ src/sage/categories/topological_spaces.py | 52 ++++- src/sage/homology/simplicial_complex.py | 8 +- .../homology/simplicial_complex_homset.py | 4 +- 13 files changed, 576 insertions(+), 110 deletions(-) create mode 100644 src/sage/categories/cw_complexes.py create mode 100644 src/sage/categories/graphs.py create mode 100644 src/sage/categories/simplicial_complexes.py diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index 233ea32ce9e..e00d5000b7e 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -3,10 +3,11 @@ from category_types import( Elements, Sequences, - SimplicialComplexes, ChainComplexes, ) +from sage.categories.simplicial_complexes import SimplicialComplexes + from tensor import tensor from cartesian_product import cartesian_product diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index 8ef0b0a216e..cca4855a982 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -599,34 +599,7 @@ def __call__(self, v): return v return self.ring().ideal(v) -############################################################# -# TODO: make those two into real categories (with super_category, ...) - -# SimplicialComplex -############################################################# -class SimplicialComplexes(Category): - """ - The category of simplicial complexes. - - EXAMPLES:: - - sage: SimplicialComplexes() - Category of simplicial complexes - - TESTS:: - - sage: TestSuite(SimplicialComplexes()).run() - """ - - def super_categories(self): - """ - EXAMPLES:: - - sage: SimplicialComplexes().super_categories() - [Category of objects] - """ - return [Objects()] # anything better? - +# TODO: make this into a better category ############################################################# # ChainComplex ############################################################# diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 84031ba8f30..aa249c87d49 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1675,6 +1675,7 @@ class ``Sets.Finite``), or in a separate file (typically in a class all_axioms = AxiomContainer() all_axioms += ("Flying", "Blue", + "Compact", "Complex", "Differentiable", "Smooth", "Facade", "Finite", "Infinite", "FiniteDimensional", "Connected", "WithBasis", "Irreducible", diff --git a/src/sage/categories/cw_complexes.py b/src/sage/categories/cw_complexes.py new file mode 100644 index 00000000000..764fac8b896 --- /dev/null +++ b/src/sage/categories/cw_complexes.py @@ -0,0 +1,162 @@ +r""" +CW Complexes +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.categories.category_singleton import Category_singleton +from sage.categories.category_with_axiom import CategoryWithAxiom +from sage.categories.sets_cat import Sets + +class CWComplexes(Category_singleton): + r""" + The category of CW complexes. + + A CW complex is a Closure-finite cell complex in the Weak toplogy. + + REFERENCES: + + - :wikipedia:`CW_complex` + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: C = CWComplexes(); C + Category of CW complexes + + TESTS:: + + sage: TestSuite(C).run() + """ + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: CWComplexes().super_categories() + [Category of topological spaces] + """ + return [Sets().Topological()] + + def _repr_object_names(self): + """ + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: CWComplexes() + Category of CW complexes + """ + return "CW complexes" + + class SubcategoryMethods: + @cached_method + def Connected(self): + """ + Return the full subcategory of the connected objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: CWComplexes().Connected() + Category of connected CW complexes + + TESTS:: + + sage: TestSuite(CWComplexes().Connected()).run() + sage: CWComplexes().Connected.__module__ + 'sage.categories.cw_complexes' + """ + return self._with_axiom('Connected') + + @cached_method + def FiniteDimensional(self): + """ + Return the full subcategory of the finite dimensional + objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: C = CWComplexes().FiniteDimensional(); C + Category of finite dimensional CW complexes + + TESTS:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: C = CWComplexes().FiniteDimensional() + sage: TestSuite(C).run() + sage: CWComplexes().Connected().FiniteDimensional.__module__ + 'sage.categories.cw_complexes' + """ + return self._with_axiom('FiniteDimensional') + + class Connected(CategoryWithAxiom): + """ + The category of connected CW complexes. + """ + + class FiniteDimensional(CategoryWithAxiom): + """ + Category of finite dimensional CW complexes. + """ + + class Finite(CategoryWithAxiom): + """ + Category of finite CW complexes. + """ + def extra_super_categories(self): + """ + Return the extra super categories of ``self``. + + A finite CW complex is a compact finite-dimensional CW complex. + """ + return [CWComplexes().FiniteDimensional(), Sets().Topological().Compact()] + + class ParentMethods: + @cached_method + def dimension(self): + """ + Return the dimension of ``self``. + """ + return max(c.dimension() for c in self.cells()) + + def Compact_extra_super_categories(self): + """ + Return extraneous super categories for ``CWComplexes().Compact()``. + + A compact CW complex is finite, see Proposition A.1 in [Hat]_. + + .. TODO:: + + Fix the name of finite CW complexes. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: CWComplexes().Compact() + Category of finite finite dimensional CW complexes + sage: CWComplexes().Compact() is CWComplexes().Finite() + True + """ + return (Sets().Finite(),) + + class ParentMethods: + @abstract_method + def dimension(self): + """ + Return the dimension of ``self``. + """ + + @abstract_method(optional=True) + def cells(self): + """ + Return the cells of ``self``. + """ + diff --git a/src/sage/categories/graphs.py b/src/sage/categories/graphs.py new file mode 100644 index 00000000000..275bec76808 --- /dev/null +++ b/src/sage/categories/graphs.py @@ -0,0 +1,61 @@ +""" +Graphs +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +#from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.categories.category_singleton import Category_singleton +from sage.categories.simplicial_complexes import SimplicialComplexes + +class Graphs(Category_singleton): + r""" + The category of graphs. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs(); C + Category of graphs + + TESTS:: + + sage: TestSuite(C).run() + """ + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: Graphs().super_categories() + [Category of simplicial complexes] + """ + return [SimplicialComplexes()] + + class ParentMethods: + def dimension(self): + """ + Return the dimension of ``self`` as a CW complex. + """ + if self.edges(): + return 1 + return 0 + + def facets(self): + """ + Return the facets of ``self``. + """ + return self.edges() + + def faces(self): + """ + Return the faces of ``self``. + """ + return set(self.edges()).union(self.vertices()) + diff --git a/src/sage/categories/lie_groups.py b/src/sage/categories/lie_groups.py index c2af33196b1..eb9e31abb2a 100644 --- a/src/sage/categories/lie_groups.py +++ b/src/sage/categories/lie_groups.py @@ -8,49 +8,28 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.misc.abstract_method import abstract_method +#from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method -from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.lazy_import import LazyImport -from sage.categories.category import Category -from sage.categories.category_types import Category_over_base_ring -from sage.categories.sets_cat import Sets +from sage.categories.category_singleton import Category_singleton from sage.categories.groups import Groups from sage.categories.manifolds import Manifolds -from sage.rings.all import RR -class LieGroups(Category_over_base_ring): +class LieGroups(Category_singleton): r""" The category of Lie groups. - A Lie group is a topological group with a smooth differentiable - manifold structure. - - INPUT: - - - ``k`` -- (default: ``RR``) the field `k` + A Lie group is a topological group with a smooth manifold structure. EXAMPLES:: sage: from sage.categories.lie_groups import LieGroups sage: C = LieGroups(); C - Category of manifolds over Real Field - sage: C.super_categories() - [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, - Category of modules over Integer Ring] - sage: C = LieGroups(CC); C - Category of manifolds over Complex Field + Category of Lie groups TESTS:: sage: TestSuite(C).run() """ - def __init__(self, R=RR): - """ - Initialize ``self``. - """ - Category_over_base_ring.__init__(self, RR) - @cached_method def super_categories(self): """ @@ -58,10 +37,9 @@ def super_categories(self): sage: from sage.categories.lie_groups import LieGroups sage: LieGroups().super_categories() + [Category of topological groups, Category of smooth manifolds] """ - R = self.base_ring() - # TODO: Make this smooth differentiable manifolds - return [Groups().Topological(), Manifolds(R)] + return [Groups().Topological(), Manifolds().Smooth()] def additional_structure(self): r""" @@ -69,7 +47,7 @@ def additional_structure(self): Indeed, the category of Lie groups defines no new structure: a morphism of topological spaces and of smooth - differentiable manifolds is a morphism as Lie groups. + manifolds is a morphism as Lie groups. .. SEEALSO:: :meth:`Category.additional_structure` @@ -80,3 +58,14 @@ def additional_structure(self): """ return None + # Because Lie is a name that deserves to be capitalized + def _repr_object_names(self): + """ + EXAMPLES:: + + sage: from sage.categories.lie_groups import LieGroups + sage: LieGroups() # indirect doctest + Category of Lie groups + """ + return "Lie groups" + diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index 56dbde629e9..fa8ce5ff6d0 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -13,58 +13,39 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import LazyImport from sage.categories.category import Category -from sage.categories.category_types import Category_over_base_ring +from sage.categories.category_singleton import Category_singleton +from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.sets_cat import Sets from sage.categories.fields import Fields -from sage.rings.all import RR -class Manifolds(Category_over_base_ring): +class Manifolds(Category_singleton): r""" - The category of maniolds. + The category of manifolds over any field. - Let `k` be a field. A `d`-dimensional `k`-*manifold* `M` is a - second countable Hausdorff space such that the neighborhood - of any point `x \in M` is homeomorphic to `k^d`. - - INPUT: - - - ``k`` -- (default: ``RR``) the field `k` + Let `k` be a field. A `k`-*manifold* `M` is a second countable + Hausdorff space such that the neighborhood of any point `x \in M` + is homeomorphic to `k^d` for some `d`. EXAMPLES:: sage: from sage.categories.manifolds import Manifolds sage: C = Manifolds(); C - Category of manifolds over Real Field + Category of manifolds sage: C.super_categories() - [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, - Category of modules over Integer Ring] - sage: C = Manifolds(CC); C - Category of manifolds over Complex Field + [Category of topological spaces] TESTS:: sage: TestSuite(C).run() """ - def __init__(self, k=RR): - """ - Initialize ``self``. - """ - if k not in Fields(): - raise ValueError("must be defined over a field") - Category_over_base_ring.__init__(self, k) - @cached_method def super_categories(self): """ EXAMPLES:: - sage: from sage.categories.magmatic_algebras import MagmaticAlgebras - sage: MagmaticAlgebras(ZZ).super_categories() - [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, Category of modules over Integer Ring] - - sage: from sage.categories.additive_semigroups import AdditiveSemigroups - sage: MagmaticAlgebras(ZZ).is_subcategory((AdditiveSemigroups() & Magmas()).Distributive()) - True + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().super_categories() + [Category of topological spaces] """ return [Sets().Topological()] @@ -85,7 +66,84 @@ def additional_structure(self): """ return None - class Connected: + class SubcategoryMethods: + @cached_method + def Connected(self): + """ + Return the full subcategory of the connected objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Connected() + Category of connected manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Connected()).run() + sage: Manifolds().Connected.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Connected') + + @cached_method + def Differentiable(self): + """ + Return the subcategory of the differentiable objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Differentiable() + Category of differentiable manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Differentiable()).run() + sage: Manifolds().Differentiable.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Differentiable') + + @cached_method + def Smooth(self): + """ + Return the subcategory of the smooth objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Smooth() + Category of smooth manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Smooth()).run() + sage: Manifolds().Smooth.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Smooth') + + @cached_method + def Complex(self): + """ + Return the full subcategory of the complex objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Complex() + Category of complex manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Complex()).run() + sage: Manifolds().Complex.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Complex') + + class Connected(CategoryWithAxiom): """ The category of connected manifolds. """ @@ -96,3 +154,60 @@ def dimension(self): Return the dimension of ``self``. """ + class SubcategoryMethods: + @cached_method + def FiniteDimensional(self): + """ + Return the full subcategory of the finite dimensional + objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds().Connected().FiniteDimensional(); C + Category of finite dimensional connected manifolds + + TESTS:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds().Connected().FiniteDimensional() + sage: TestSuite(C).run() + sage: Manifolds().Connected().FiniteDimensional.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('FiniteDimensional') + + class FiniteDimensional(CategoryWithAxiom): + """ + Category of finite dimensional (connected) manifolds. + """ + + class Differentiable(CategoryWithAxiom): + """ + The category of differentiable manifolds. + """ + + class Smooth(CategoryWithAxiom): + """ + The category of smooth manifolds. + """ + def extra_super_categories(self): + """ + Return the extra super categories of ``self``. + + A smooth manifold is differentiable. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Smooth().super_categories() # indirect doctest + [Category of differentiable manifolds] + """ + return [Manifolds().Differentiable()] + + class Complex(CategoryWithAxiom): + r""" + The category of complex manifolds, i.e., the underlying vector + space is `\CC^d`. + """ + diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index 6b4dec93de3..d01c992fe4f 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -12,18 +12,7 @@ from sage.categories.category import Category from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory -class MetricSpaces(RegressiveCovariantConstructionCategory): - r""" - The category of metric spaces. - - A *metric* on a set `S` is a function `d : S \times S \to \RR` - such that: - - - `d(a, b) \geq 0`, - - `d(a, b) = 0` if and only if `a = b`. - - A metric space is a set `S` with a distinguished metric. - """ +class MetricSpacesCategory(RegressiveCovariantConstructionCategory): _functor_category = "Metric" @@ -72,6 +61,37 @@ def default_super_categories(cls, category): return Category.join([category.Topological(), super(MetricSpaces, cls).default_super_categories(category)]) + # We currently don't have a use for this, but we probably will + def _repr_object_names(self): + """ + EXAMPLES:: + + sage: Groups().Metric() # indirect doctest + Category of metric groups + """ + return "metric {}".format(self.base_category()._repr_object_names()) + +class MetricSpaces(MetricSpacesCategory): + r""" + The category of metric spaces. + + A *metric* on a set `S` is a function `d : S \times S \to \RR` + such that: + + - `d(a, b) \geq 0`, + - `d(a, b) = 0` if and only if `a = b`. + + A metric space is a set `S` with a distinguished metric. + """ + def _repr_object_names(self): + """ + EXAMPLES:: + + sage: Sets().Metric() # indirect doctest + Category of metric spaces + """ + return "metric spaces" + class ParentMethods: def _test_metric(self, **options): r""" diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 1542235b364..55435b11f80 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -661,6 +661,18 @@ def Topological(self): from sage.categories.topological_spaces import TopologicalSpacesCategory return TopologicalSpacesCategory.category_of(self) + @cached_method + def Metric(self): + """ + Return the subcategory of the metric objects of ``self``. + + TESTS:: + + sage: TestSuite(Sets().Metric()).run() + """ + from sage.categories.metric_spaces import MetricSpaces + return MetricSpaces.category_of(self) + @cached_method def Algebras(self, base_ring): """ @@ -1567,7 +1579,9 @@ def cartesian_product(*elements): Facade = LazyImport('sage.categories.facade_sets', 'FacadeSets') Finite = LazyImport('sage.categories.finite_sets', 'FiniteSets', at_startup=True) - Topological = LazyImport('sage.categories.topological_spaces', 'TopologicalSpaces') + Topological = LazyImport('sage.categories.topological_spaces', + 'TopologicalSpaces', 'Topological') + Metric = LazyImport('sage.categories.metric_spaces', 'MetricSpaces', 'Mertic') class Infinite(CategoryWithAxiom): diff --git a/src/sage/categories/simplicial_complexes.py b/src/sage/categories/simplicial_complexes.py new file mode 100644 index 00000000000..81121e68920 --- /dev/null +++ b/src/sage/categories/simplicial_complexes.py @@ -0,0 +1,78 @@ +""" +Simplicial Complexes +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.categories.category_singleton import Category_singleton +from sage.categories.category_with_axiom import CategoryWithAxiom +#from sage.categories.cw_complexes import CWComplexes +from sage.categories.sets_cat import Sets + +class SimplicialComplexes(Category_singleton): + r""" + The category of abstract simplicial complexes. + + An abstract simplicial complex `A` is a collection of sets `X` + such that: + + - `\emptyset \in A`, + - if `X \subset Y \in A`, then `X \in A`. + + .. TODO:: + + Implement the category of simplicial complexes considered + as :class:`CW complexes `. + + EXAMPLES:: + + sage: from sage.categories.simplicial_complexes import SimplicialComplexes + sage: C = SimplicialComplexes(); C + Category of simplicial complexes + + TESTS:: + + sage: TestSuite(C).run() + """ + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: from sage.categories.simplicial_complexes import SimplicialComplexes + sage: SimplicialComplexes().super_categories() + [Category of sets] + """ + return [Sets()] + + class Finite(CategoryWithAxiom): + """ + Category of finite simplicial complexes. + """ + class ParentMethods: + @cached_method + def dimension(self): + """ + Return the dimension of ``self``. + """ + return max(c.dimension() for c in self.facets()) + + class ParentMethods: + @abstract_method + def facets(self): + """ + Return the facets of ``self``. + """ + + @abstract_method + def faces(self): + """ + Return the faces of ``self``. + """ + diff --git a/src/sage/categories/topological_spaces.py b/src/sage/categories/topological_spaces.py index 80e31857508..f279509fb5b 100644 --- a/src/sage/categories/topological_spaces.py +++ b/src/sage/categories/topological_spaces.py @@ -11,6 +11,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_class_attribute from sage.categories.category import Category +from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory from sage.categories.sets_cat import Sets @@ -23,7 +24,7 @@ def _repr_object_names(self): EXAMPLES:: sage: Groups().Topological() # indirect doctest - Category of graded algebras with basis over Rational Field + Category of topological groups """ return "topological {}".format(self.base_category()._repr_object_names()) @@ -36,7 +37,7 @@ class TopologicalSpaces(TopologicalSpacesCategory): sage: Sets().Topological() Category of topological spaces sage: Sets().Topological().super_categories() - [Category of modules over Integer Ring] + [Category of sets] The category of topological spaces defines the topological structure, which shall be preserved by morphisms:: @@ -60,3 +61,50 @@ def _repr_object_names(self): """ return "topological spaces" + class SubcategoryMethods: + @cached_method + def Connected(self): + """ + Return the full subcategory of the connected objects of ``self``. + + EXAMPLES:: + + sage: Sets().Topological().Connected() + Category of connected topological spaces + + TESTS:: + + sage: TestSuite(Sets().Topological().Connected()).run() + sage: Sets().Topological().Connected.__module__ + 'sage.categories.topological_spaces' + """ + return self._with_axiom('Connected') + + @cached_method + def Compact(self): + """ + Return the subcategory of the compact objects of ``self``. + + EXAMPLES:: + + sage: Sets().Topological().Compact() + Category of compact topological spaces + + TESTS:: + + sage: TestSuite(Sets().Topological().Compact()).run() + sage: Sets().Topological().Compact.__module__ + 'sage.categories.topological_spaces' + """ + return self._with_axiom('Compact') + + class Connected(CategoryWithAxiom): + """ + The category of connected topological spaces. + """ + + class Compact(CategoryWithAxiom): + """ + The category of compact topological spaces. + """ + diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index c8c188552f6..d50f8bc7aa6 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -169,7 +169,7 @@ from sage.homology.chain_complex import ChainComplex from sage.graphs.graph import Graph from functools import reduce -lazy_import('sage.categories.category_types', 'SimplicialComplexes') +from sage.categories.simplicial_complexes import SimplicialComplexes def lattice_paths(t1, t2, length=None): """ @@ -833,7 +833,7 @@ def __init__(self, if (maximal_faces is not None and from_characteristic_function is not None): raise ValueError("maximal_faces and from_characteristic_function cannot be both defined") - CategoryObject.__init__(self, category=SimplicialComplexes()) + CategoryObject.__init__(self, category=SimplicialComplexes().Finite()) from sage.misc.misc import union C = None @@ -3284,7 +3284,9 @@ def _Hom_(self, other, category=None): sage: T = simplicial_complexes.Sphere(2) sage: H = Hom(S,T) # indirect doctest sage: H - Set of Morphisms from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} in Category of simplicial complexes + Set of Morphisms from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + in Category of finite simplicial complexes sage: f = {0:0,1:1,2:3} sage: x = H(f) sage: x diff --git a/src/sage/homology/simplicial_complex_homset.py b/src/sage/homology/simplicial_complex_homset.py index 46d3aed15d4..db00d572733 100644 --- a/src/sage/homology/simplicial_complex_homset.py +++ b/src/sage/homology/simplicial_complex_homset.py @@ -67,7 +67,9 @@ def is_SimplicialComplexHomset(x): sage: T = SimplicialComplex(is_mutable=False) sage: H = Hom(S, T) sage: H - Set of Morphisms from Simplicial complex with vertex set () and facets {()} to Simplicial complex with vertex set () and facets {()} in Category of simplicial complexes + Set of Morphisms from Simplicial complex with vertex set () and facets {()} + to Simplicial complex with vertex set () and facets {()} + in Category of finite simplicial complexes sage: from sage.homology.simplicial_complex_homset import is_SimplicialComplexHomset sage: is_SimplicialComplexHomset(H) True From 710d09e3f75ce2fbc95d2f67ba8dbc12bf666c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Sun, 12 Apr 2015 17:48:06 -0400 Subject: [PATCH 0157/1872] 18174: more doc improvements + uniformization with CategoryWithAxiom --- .../covariant_functorial_construction.py | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/covariant_functorial_construction.py b/src/sage/categories/covariant_functorial_construction.py index 284fd5ca064..cc2ea36216e 100644 --- a/src/sage/categories/covariant_functorial_construction.py +++ b/src/sage/categories/covariant_functorial_construction.py @@ -43,6 +43,7 @@ #****************************************************************************** from sage.misc.cachefunc import cached_function, cached_method from sage.misc.lazy_attribute import lazy_class_attribute +from sage.misc.lazy_import import LazyImport from sage.categories.category import Category from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation @@ -317,22 +318,37 @@ def __classget__(cls, base_category, base_category_class): ``Category``, even if it has been overriden by a ``Subquotients`` class. - TESTS:: + EXAMPLES:: sage: Sets.Subquotients sage: Sets().Subquotients Cached version of + This method also initializes the attribute + ``_base_category_class`` if not already set:: + + sage: Sets.Subquotients._base_category_class + (,) + + It also forces the resolution of lazy imports (see :trac:`15648`):: + + sage: type(Algebras.__dict__["Graded"]) + + sage: Algebras.Graded + + sage: type(Algebras.__dict__["Graded"]) + + .. TODO:: The logic is very similar to that implemented in :class:`CategoryWithAxiom.__classget__`. Find a way to refactor this to avoid the duplication. """ - if base_category is None: - return cls - + if base_category is not None: + assert base_category.__class__ is base_category_class + assert isinstance(base_category_class, DynamicMetaclass) if isinstance(base_category_class, DynamicMetaclass): base_category_class = base_category_class.__base__ if "_base_category_class" not in cls.__dict__: @@ -342,6 +358,13 @@ def __classget__(cls, base_category, base_category_class): "base category class for {} mismatch; expected {}, got {}".format( cls, cls._base_category_class[0], base_category_class) + # Workaround #15648: if Sets.Subquotients is a LazyImport object, + # this forces the substitution of the object back into Sets + # to avoid resolving the lazy import over and over + if isinstance(base_category_class.__dict__[cls._functor_category], LazyImport): + setattr(base_category_class, cls._functor_category, cls) + if base_category is None: + return cls return getattr(super(base_category.__class__.__base__, base_category), cls._functor_category) From 19c3471ffe0277979904e465d6867d31d284d969 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 13 Apr 2015 10:28:41 -0400 Subject: [PATCH 0158/1872] Cleanup from adding #18044. --- src/sage/categories/super_modules.py | 76 ---------------------------- 1 file changed, 76 deletions(-) diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py index 46c170080cb..60f94965d86 100644 --- a/src/sage/categories/super_modules.py +++ b/src/sage/categories/super_modules.py @@ -39,82 +39,6 @@ def __init__(self, base_category): _functor_category = "Super" - @lazy_class_attribute - def _base_category_class(cls): - """ - Recover the class of the base category. - - OUTPUT: - - A *tuple* whose first entry is the base category class. - - .. WARNING:: - - This is only used for super categories that are not - implemented as nested classes, and won't work otherwise. - - .. SEEALSO:: :meth:`__classcall__` - - EXAMPLES:: - - sage: from sage.categories.super_modules import SuperModules - sage: from sage.categories.super_algebras_with_basis import SuperAlgebrasWithBasis - sage: SuperModules._base_category_class - (,) - sage: SuperAlgebrasWithBasis._base_category_class - (,) - - The reason for wrapping the base category class in a tuple is - that, often, the base category class implements a - :meth:`__classget__` method which would get in the way upon - attribute access:: - - sage: F = SuperAlgebrasWithBasis - sage: F._foo = F._base_category_class[0] - sage: F._foo - Traceback (most recent call last): - ... - AssertionError: base category class for <...AlgebrasWithBasis'> mismatch; - expected <...Algebras'>, got <...SuperAlgebrasWithBasis'> - """ - module_name = cls.__module__.replace("super_","") - import sys - name = cls.__name__.replace("Super","") - __import__(module_name) - module = sys.modules[module_name] - return (module.__dict__[name],) - - @staticmethod - def __classcall__(cls, category, *args): - """ - Magic support for putting Super categories in their own file. - - EXAMPLES:: - - sage: from sage.categories.super_modules import SuperModules - sage: SuperModules(ZZ) # indirect doctest - Category of super modules over Integer Ring - sage: Modules(ZZ).Super() - Category of super modules over Integer Ring - sage: SuperModules(ZZ) is Modules(ZZ).Super() - True - - .. TODO:: - - Generalize this support for all other functorial - constructions if at some point we have a category ``Blah`` for - which we want to implement the construction ``Blah.Foo`` in a - separate file like we do for e.g. :class:`SuperModules`, - :class:`SuperAlgebras`, ... - - .. SEEALSO:: :meth:`_base_category_class` - """ - base_category_class = cls._base_category_class[0] - if isinstance(category, base_category_class): - return super(SuperModulesCategory, cls).__classcall__(cls, category, *args) - else: - return base_category_class(category, *args).Super() - def _repr_object_names(self): """ EXAMPLES:: From 4f9d5f11871b73b337eabe7d27111d4f6b39ac98 Mon Sep 17 00:00:00 2001 From: David Roe Date: Tue, 14 Apr 2015 15:48:10 -0400 Subject: [PATCH 0159/1872] Starting to move base_ring from CategoryObject to category framework --- src/sage/structure/category_object.pyx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 0bfa8abf3b4..cca5d3dcad7 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -614,6 +614,10 @@ cdef class CategoryObject(sage_object.SageObject): category) so as not to pollute the namespace of all category objects. """ + try: + return super(CategoryObject, self).base_ring() + except AttributeError: + pass return self._base def base(self): From f91e80ad58d3545bb00e6dcaae99534607ba8de7 Mon Sep 17 00:00:00 2001 From: David Roe Date: Tue, 14 Apr 2015 15:45:43 -0400 Subject: [PATCH 0160/1872] Working on cartesian products Conflicts: src/sage/categories/algebras.py src/sage/categories/cartesian_product.py src/sage/categories/modules.py src/sage/categories/monoids.py src/sage/categories/pushout.py src/sage/categories/sets_cat.py --- src/sage/categories/cartesian_product.py | 33 +++++++++++------- src/sage/categories/modules.py | 29 ++++++++++++++++ src/sage/categories/monoids.py | 2 +- src/sage/categories/pushout.py | 43 +++++++++++++++++++++--- src/sage/categories/sets_cat.py | 7 +++- src/sage/sets/cartesian_product.py | 4 +++ 6 files changed, 100 insertions(+), 18 deletions(-) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index 3e0065247a3..f77f0184904 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -12,9 +12,11 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.misc.lazy_import import lazy_import from sage.categories.covariant_functorial_construction import CovariantFunctorialConstruction, CovariantConstructionCategory +from sage.categories.pushout import MultivariateConstructionFunctor -class CartesianProductFunctor(CovariantFunctorialConstruction): +class CartesianProductFunctor(CovariantFunctorialConstruction, MultivariateConstructionFunctor): """ A singleton class for the Cartesian product functor. @@ -105,17 +107,10 @@ class CartesianProductFunctor(CovariantFunctorialConstruction): _functor_category = "CartesianProducts" symbol = " (+) " -cartesian_product = CartesianProductFunctor() -""" -The cartesian product functorial construction. - -See :class:`CartesianProductFunctor` for more information. - -EXAMPLES:: - - sage: cartesian_product - The cartesian_product functorial construction -""" + def __init__(self): + CovariantFunctorialConstruction.__init__(self) + from sage.categories.sets_cat import Sets + MultivariateConstructionFunctor.__init__(self, Sets(), Sets()) class CartesianProductsCategory(CovariantConstructionCategory): """ @@ -171,3 +166,17 @@ def base_ring(self): Integer Ring """ return self.base_category().base_ring() + +# Moved to avoid circular imports +lazy_import('sage.categories.sets_cat', 'cartesian_product') +""" +The cartesian product functorial construction + +See :class:`CartesianProductFunctor` for more information + +EXAMPLES:: + + sage: cartesian_product + The cartesian_product functorial construction +""" + diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 4eaa56726de..6f97d7ff5d3 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -19,6 +19,7 @@ from category_types import Category_module, Category_over_base_ring from tensor import TensorProductsCategory from dual import DualObjectsCategory +from sage.categories.cartesian_product import CartesianProductsCategory from sage.categories.sets_cat import Sets from sage.categories.bimodules import Bimodules from sage.categories.fields import Fields @@ -571,3 +572,31 @@ def extra_super_categories(self): """ from magmatic_algebras import MagmaticAlgebras return [MagmaticAlgebras(self.base_category().base_ring())] + + class CartesianProducts(CartesianProductsCategory): + """ + The category of modules constructed as cartesian products of modules + + This construction gives the direct product of modules. See + discussion on: + + - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16 + - http://en.wikipedia.org/wiki/Direct_product + """ + def extra_super_categories(self): + """ + A cartesian product of modules is endowed with a natural + module structure. + + EXAMPLES:: + + sage: Modules(ZZ).CartesianProducts().extra_super_categories() + [Category of modules over Integer Ring] + sage: Modules(ZZ).CartesianProducts().super_categories() + [Category of modules over Integer Ring, Category of Cartesian products of monoids] + """ + return [self.base_category()] + + class ParentMethods: + def base_ring(self): + return self._sets[0].base_ring() diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index edb6f181247..0e3cf7dfcb4 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -18,7 +18,7 @@ from sage.categories.semigroups import Semigroups from sage.misc.lazy_import import LazyImport from sage.categories.subquotients import SubquotientsCategory -from sage.categories.cartesian_product import CartesianProductsCategory, cartesian_product +from sage.categories.cartesian_product import CartesianProductsCategory from sage.categories.algebra_functor import AlgebrasCategory from sage.categories.with_realizations import WithRealizationsCategory from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 6dd4ddc8698..7618cbd2837 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1,10 +1,10 @@ """ Coercion via Construction Functors """ -from functor import Functor -from basic import * +from sage.misc.lazy_import import lazy_import +from functor import Functor, IdentityFunctor_generic -from sage.structure.parent import CoercionException +lazy_import('sage.structure.parent', 'CoercionException') # TODO, think through the rankings, and override pushout where necessary. @@ -290,6 +290,15 @@ def expand(self): # See the pushout() function below for explanation. coercion_reversed = False + def common_base(self, other, R_bases, S_bases): + """ + This function is called by :func:`pushout` when no common parent + is found in the construction tower. + + The main use is for multivariate construction functors, which + use this function to implement recursion for :func:`pushout`. + """ + raise CoercionException("No common base") class CompositeConstructionFunctor(ConstructionFunctor): """ @@ -486,6 +495,7 @@ def __init__(self): True """ + from sage.categories.sets_cat import Sets ConstructionFunctor.__init__(self, Sets(), Sets()) def _apply_functor(self, x): @@ -564,6 +574,19 @@ def __mul__(self, other): else: return self +class MultivariateConstructionFunctor(ConstructionFunctor): + """ + An abstract base class for functors that take multiple inputs (e.g. CartesianProduct) + """ + def common_base(self, other_functor, R_bases, S_bases): + """ + """ + if self != other_functor: + raise CoercionException("Incompatible multivariate construction functors") + if len(R_bases) != len(S_bases): + raise CoercionException("Multivariate construction functors need the same number of inputs") + Z_bases = tuple(pushout(R, S) for R, S in zip(R_bases, S_bases)) + return self(Z_bases) class PolynomialFunctor(ConstructionFunctor): """ @@ -3241,6 +3264,15 @@ def pushout(R, S): Rs = [c[1] for c in R_tower] Ss = [c[1] for c in S_tower] + # If there is a multivariate construction functor in the tower, we must chop off the end + # because tuples don't have has_coerce_map_from functions and to align with the + # modification of Rs and Ss below + from sage.structure.parent import Parent + if not isinstance(Rs[-1], Parent): + Rs = Rs[:-1] + if not isinstance(Ss[-1], Parent): + Ss = Ss[:-1] + if R in Ss: if not any(c[0].coercion_reversed for c in S_tower[1:]): return S @@ -3278,7 +3310,7 @@ def pushout(R, S): Z = Rs.pop() else: - raise CoercionException("No common base") + Z = R_tower[-1][0].common_base(S_tower[-1][0], R_tower[-1][1], S_tower[-1][1]) # Rc is a list of functors from Z to R and Sc is a list of functors from Z to S R_tower = expand_tower(R_tower[:len(Rs)+1]) @@ -3563,11 +3595,14 @@ def construction_tower(R): """ tower = [(None, R)] c = R.construction() + from sage.structure.parent import Parent while c is not None: f, R = c if not isinstance(f, ConstructionFunctor): f = BlackBoxConstructionFunctor(f) tower.append((f,R)) + if not isinstance(R, Parent): + break c = R.construction() return tower diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index b773014c8f0..15ee116b8ea 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -27,12 +27,14 @@ from sage.categories.subobjects import SubobjectsCategory from sage.categories.isomorphic_objects import IsomorphicObjectsCategory from sage.categories.algebra_functor import AlgebrasCategory -from sage.categories.cartesian_product import cartesian_product, CartesianProductsCategory +#from sage.categories.cartesian_product import cartesian_product, CartesianProductsCategory from sage.categories.realizations import RealizationsCategory, Category_realization_of_parent from sage.categories.with_realizations import WithRealizationsCategory from sage.categories.category_with_axiom import CategoryWithAxiom lazy_import('sage.sets.cartesian_product', 'CartesianProduct') +#from sage.sets.cartesian_product import CartesianProduct +from sage.categories.cartesian_product import CartesianProductsCategory, CartesianProductFunctor def print_compare(x, y): """ @@ -2363,3 +2365,6 @@ def _repr_(self): The subset algebra of {1, 2, 3} over Rational Field in the realization Blah """ return "{} in the realization {}".format(self.realization_of(), self._realization_name()) + +# Moved from sage.categories.cartesian_product to avoid circular import errors +cartesian_product = CartesianProductFunctor() diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 728931982bb..ca9c87c336e 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -206,6 +206,10 @@ def _cartesian_product_of_elements(self, elements): assert len(elements) == len(self._sets) return self.element_class(self, elements) + def construction(self): + from sage.categories.cartesian_product import cartesian_product + return cartesian_product, self.cartesian_factors() + an_element = Sets.CartesianProducts.ParentMethods.an_element class Element(ElementWrapper): From c41a774958929769172db22c05c2688a1f75677f Mon Sep 17 00:00:00 2001 From: David Roe Date: Tue, 14 Apr 2015 16:59:57 -0400 Subject: [PATCH 0161/1872] Fixes to pushout, add coercions --- src/sage/categories/pushout.py | 15 ++++++++++----- src/sage/sets/cartesian_product.py | 8 ++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 7618cbd2837..ae1b94a9254 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1981,6 +1981,8 @@ def __init__(self): sage: F(ZZ['t']) Fraction Field of Univariate Polynomial Ring in t over Integer Ring """ + from sage.categories.integral_domains import IntegralDomains + from sage.categories.fields import Fields Functor.__init__(self, IntegralDomains(), Fields()) def _apply_functor(self, R): @@ -3285,6 +3287,7 @@ def pushout(R, S): R_tower, S_tower = S_tower, R_tower # look for join + Z = None if Ss[-1] in Rs: if Rs[-1] == Ss[-1]: while Rs and Ss and Rs[-1] == Ss[-1]: @@ -3309,12 +3312,14 @@ def pushout(R, S): Ss.pop() Z = Rs.pop() - else: + if Z is None: Z = R_tower[-1][0].common_base(S_tower[-1][0], R_tower[-1][1], S_tower[-1][1]) - - # Rc is a list of functors from Z to R and Sc is a list of functors from Z to S - R_tower = expand_tower(R_tower[:len(Rs)+1]) - S_tower = expand_tower(S_tower[:len(Ss)+1]) + R_tower = expand_tower(R_tower[:len(Rs)]) + S_tower = expand_tower(S_tower[:len(Ss)]) + else: + # Rc is a list of functors from Z to R and Sc is a list of functors from Z to S + R_tower = expand_tower(R_tower[:len(Rs)+1]) + S_tower = expand_tower(S_tower[:len(Ss)+1]) Rc = [c[0] for c in R_tower[1:]] Sc = [c[0] for c in S_tower[1:]] diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index ca9c87c336e..b38862f7e3a 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -210,6 +210,14 @@ def construction(self): from sage.categories.cartesian_product import cartesian_product return cartesian_product, self.cartesian_factors() + def _coerce_map_from_(self, S): + if isinstance(S, CartesianProduct): + S_factors = S.cartesian_factors() + R_factors = self.cartesian_factors() + if len(S_factors) == len(R_factors): + if all(r.has_coerce_map_from(s) for r,s in zip(R_factors, S_factors)): + return True + an_element = Sets.CartesianProducts.ParentMethods.an_element class Element(ElementWrapper): From d90c6fd488f57d68c1b7be249fe586318d55f351 Mon Sep 17 00:00:00 2001 From: David Roe Date: Tue, 14 Apr 2015 17:07:50 -0400 Subject: [PATCH 0162/1872] Clean up sets_cat changes --- src/sage/categories/sets_cat.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 15ee116b8ea..67ef11cdbd8 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -27,14 +27,11 @@ from sage.categories.subobjects import SubobjectsCategory from sage.categories.isomorphic_objects import IsomorphicObjectsCategory from sage.categories.algebra_functor import AlgebrasCategory -#from sage.categories.cartesian_product import cartesian_product, CartesianProductsCategory +from sage.categories.cartesian_product import CartesianProductsCategory, CartesianProductFunctor from sage.categories.realizations import RealizationsCategory, Category_realization_of_parent from sage.categories.with_realizations import WithRealizationsCategory from sage.categories.category_with_axiom import CategoryWithAxiom - lazy_import('sage.sets.cartesian_product', 'CartesianProduct') -#from sage.sets.cartesian_product import CartesianProduct -from sage.categories.cartesian_product import CartesianProductsCategory, CartesianProductFunctor def print_compare(x, y): """ From 7554dbda3721d66fb582ab3bf22c1d3c577b7934 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 14 Apr 2015 17:19:15 -0400 Subject: [PATCH 0163/1872] 1 step forward, 2 steps back. --- src/sage/algebras/clifford_algebra.py | 9 +++- src/sage/algebras/weyl_algebra.py | 3 +- src/sage/categories/super_algebras.py | 45 ------------------- .../categories/super_algebras_with_basis.py | 12 +---- .../super_hopf_algebras_with_basis.py | 7 +-- src/sage/categories/super_modules.py | 37 +++++++++++++-- 6 files changed, 46 insertions(+), 67 deletions(-) delete mode 100644 src/sage/categories/super_algebras.py diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 9e02718b022..a9dc9318131 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -478,6 +478,11 @@ class CliffordAlgebra(CombinatorialFreeModule): a*d sage: d*c*b*a + a + 4*b*c a*b*c*d + 4*b*c + a + + .. WARNING:: + + The Clifford algebra is not graded, but instead filtered. This + will be changed once :trac:`17096` is finished. """ @staticmethod def __classcall_private__(cls, Q, names=None): @@ -1044,7 +1049,7 @@ def lift_module_morphism(self, m, names=None): remove_zeros=True ) for i in x) return Cl.module_morphism(on_basis=f, codomain=self, - category=AlgebrasWithBasis(self.base_ring()).Graded()) + category=AlgebrasWithBasis(self.base_ring()).Super()) def lift_isometry(self, m, names=None): r""" @@ -1412,7 +1417,7 @@ def __init__(self, R, names): sage: E. = ExteriorAlgebra(QQ) sage: TestSuite(E).run() """ - cat = HopfAlgebrasWithBasis(R).Super().Graded() + cat = HopfAlgebrasWithBasis(R).Super() CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, cat) # TestSuite will fail if the HopfAlgebra classes will ever have tests for # the coproduct being an algebra morphism -- since this is really a diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 1c8705f77d9..99fd7bf7f46 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -569,7 +569,8 @@ def __init__(self, R, names=None): raise ValueError("variable names cannot differ by a leading 'd'") # TODO: Make this into a filtered algebra under the natural grading of # x_i and dx_i have degree 1 - Algebra.__init__(self, R, names, category=AlgebrasWithBasis(R).NoZeroDivisors()) + cat = AlgebrasWithBasis(R).NoZeroDivisors().Super() + Algebra.__init__(self, R, names, category=cat) def _repr_(self): r""" diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py deleted file mode 100644 index ff6cc9a147e..00000000000 --- a/src/sage/categories/super_algebras.py +++ /dev/null @@ -1,45 +0,0 @@ -r""" -Super Algebras -""" -#***************************************************************************** -# Copyright (C) 2015 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** - -from sage.categories.super_modules import SuperModulesCategory -from sage.categories.algebras import Algebras -from sage.categories.modules import Modules -from sage.misc.lazy_import import LazyImport - -class SuperAlgebras(SuperModulesCategory): - """ - The category of super algebras. - - EXAMPLES:: - - sage: Algebras(ZZ).Super() - Category of super algebras over Integer Ring - - TESTS:: - - sage: TestSuite(Algebras(ZZ).Super()).run() - """ - def super_categories(self): - """ - EXAMPLES:: - - sage: Algebras(ZZ).Super().super_categories() - [Category of graded algebras over Integer Ring, - Category of super modules over Integer Ring] - """ - R = self.base_ring() - return [Algebras(R).Graded(), Modules(R).Super()] - - class ParentMethods: - pass - - class ElementMethods: - pass - diff --git a/src/sage/categories/super_algebras_with_basis.py b/src/sage/categories/super_algebras_with_basis.py index 1996e9aab73..ce9a8d266ff 100644 --- a/src/sage/categories/super_algebras_with_basis.py +++ b/src/sage/categories/super_algebras_with_basis.py @@ -28,7 +28,7 @@ class SuperAlgebrasWithBasis(SuperModulesCategory): sage: TestSuite(C).run() """ - def super_categories(self): + def extra_super_categories(self): """ EXAMPLES:: @@ -36,13 +36,5 @@ def super_categories(self): [Category of graded algebras with basis over Integer Ring, Category of super modules with basis over Integer Ring] """ - R = self.base_ring() - return [Algebras(R).WithBasis().Graded(), - Modules(R).WithBasis().Super()] - - class ParentMethods: - pass - - class ElementMethods: - pass + return [self.base_category().Graded()] diff --git a/src/sage/categories/super_hopf_algebras_with_basis.py b/src/sage/categories/super_hopf_algebras_with_basis.py index f1f2f1d8773..2de32bb0890 100644 --- a/src/sage/categories/super_hopf_algebras_with_basis.py +++ b/src/sage/categories/super_hopf_algebras_with_basis.py @@ -1,5 +1,5 @@ r""" -Super algebras with basis +Super Hopf algebras with basis """ #***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw @@ -27,9 +27,4 @@ class SuperHopfAlgebrasWithBasis(SuperModulesCategory): sage: TestSuite(C).run() """ - class ParentMethods: - pass - - class ElementMethods: - pass diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py index 60f94965d86..0165a18adf8 100644 --- a/src/sage/categories/super_modules.py +++ b/src/sage/categories/super_modules.py @@ -13,10 +13,41 @@ from sage.categories.category import Category from sage.categories.category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory +from sage.categories.covariant_functorial_construction import CovariantConstructionCategory from sage.categories.modules import Modules -class SuperModulesCategory(RegressiveCovariantConstructionCategory, Category_over_base_ring): +axiom_whitelist = frozenset(["Facade", "Finite", "Infinite", + "FiniteDimensional", "Connected", "WithBasis", + # "Commutative", + "Associative", "Inverse", "Unital", "Division", + "AdditiveCommutative", "AdditiveAssociative", + "AdditiveInverse", "AdditiveUnital", + "NoZeroDivisors", "Distributive"]) + +class SuperModulesCategory(CovariantConstructionCategory, Category_over_base_ring): + @classmethod + def default_super_categories(cls, category, *args): + """ + Return the default super categories of `F_{Cat}(A,B,...)` for + `A,B,...` parents in `Cat`. + + INPUT: + + - ``cls`` -- the category class for the functor `F` + - ``category`` -- a category `Cat` + - ``*args`` -- further arguments for the functor + + OUTPUT: + + A join category. + + This implements the property that subcategories constructed by + the set of whitelisted axioms is a subcategory. + """ + axioms = axiom_whitelist.intersection(category.axioms()) + C = super(SuperModulesCategory, cls).default_super_categories(category, *args) + return C._with_axioms(axioms) + def __init__(self, base_category): """ EXAMPLES:: @@ -83,7 +114,7 @@ def super_categories(self): sage: Modules(QQ).Super().super_categories() [Category of graded modules over Rational Field] """ - return [Modules(self.base_ring()).Graded()] + return [self.base_category().Graded()] def extra_super_categories(self): r""" From caada136601a6af26a7c66ec417a0180b00b1812 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 14 Apr 2015 17:59:58 -0400 Subject: [PATCH 0164/1872] Going all the way to the finish line like a superstar. --- src/sage/categories/bialgebras.py | 5 +-- src/sage/categories/coalgebras.py | 28 +++++++------- src/sage/categories/coalgebras_with_basis.py | 3 ++ src/sage/categories/hopf_algebras.py | 3 ++ src/sage/categories/modules.py | 22 ++++++++--- src/sage/categories/super_algebras.py | 38 +++++++++++++++++++ .../categories/super_algebras_with_basis.py | 7 ++-- .../super_hopf_algebras_with_basis.py | 6 +-- src/sage/categories/super_modules.py | 5 +++ .../categories/super_modules_with_basis.py | 9 +++++ 10 files changed, 97 insertions(+), 29 deletions(-) create mode 100644 src/sage/categories/super_algebras.py diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index e78f080ef18..e779d8acb08 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -11,6 +11,7 @@ from sage.categories.category_types import Category_over_base_ring from sage.categories.all import Algebras, Coalgebras +from sage.categories.super_modules import SuperModulesCategory class Bialgebras(Category_over_base_ring): """ @@ -56,8 +57,6 @@ def additional_structure(self): """ return None - class ParentMethods: + class Super(SuperModulesCategory): pass - class ElementMethods: - pass diff --git a/src/sage/categories/coalgebras.py b/src/sage/categories/coalgebras.py index 2bd98353394..2b2cc74043a 100644 --- a/src/sage/categories/coalgebras.py +++ b/src/sage/categories/coalgebras.py @@ -13,6 +13,7 @@ from sage.categories.all import Modules from sage.categories.tensor import TensorProductsCategory, tensor from sage.categories.dual import DualObjectsCategory +from sage.categories.super_modules import SuperModulesCategory from sage.categories.realizations import RealizationsCategory from sage.categories.with_realizations import WithRealizationsCategory from sage.misc.abstract_method import abstract_method @@ -50,19 +51,6 @@ class ParentMethods: # # Will declare the coproduct of self to the coercion mechanism when it exists # pass - @cached_method - def tensor_square(self): - """ - Returns the tensor square of ``self`` - - EXAMPLES:: - - sage: A = HopfAlgebrasWithBasis(QQ).example() - sage: A.tensor_square() - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field # An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field - """ - return tensor([self, self]) - @abstract_method def counit(self, x): """ @@ -192,6 +180,20 @@ def extra_super_categories(self): from sage.categories.algebras import Algebras return [Algebras(self.base_category().base_ring())] + class Super(SuperModulesCategory): + def extra_super_categories(self): + """ + EXAMPLES:: + + sage: Coalgebras(ZZ).Super().extra_super_categories() + [Join of Category of graded modules over Integer Ring + and Category of coalgebras over Integer Ring] + sage: Coalgebras(ZZ).Super().super_categories() + [Category of super modules over Integer Ring, + Category of coalgebras over Integer Ring] + """ + return [self.base_category().Graded()] + class WithRealizations(WithRealizationsCategory): class ParentMethods: diff --git a/src/sage/categories/coalgebras_with_basis.py b/src/sage/categories/coalgebras_with_basis.py index 0b9ff24f0ec..ddcaad16d26 100644 --- a/src/sage/categories/coalgebras_with_basis.py +++ b/src/sage/categories/coalgebras_with_basis.py @@ -13,6 +13,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.all import ModulesWithBasis, tensor, Hom +from sage.categories.super_modules import SuperModulesCategory class CoalgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ @@ -129,3 +130,5 @@ def counit(self): class ElementMethods: pass + class Super(SuperModulesCategory): + pass diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index eba5add5d9a..a28911b4448 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -15,6 +15,7 @@ from sage.categories.bialgebras import Bialgebras from sage.categories.tensor import TensorProductsCategory # tensor from sage.categories.realizations import RealizationsCategory +from sage.categories.super_modules import SuperModulesCategory from sage.misc.cachefunc import cached_method #from sage.misc.lazy_attribute import lazy_attribute @@ -104,6 +105,8 @@ class Morphism(Category): """ pass + class Super(SuperModulesCategory): + pass class TensorProducts(TensorProductsCategory): """ diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 13ad379c7a2..4147ea6b622 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -17,7 +17,7 @@ from sage.categories.homsets import HomsetsCategory from category import Category, JoinCategory from category_types import Category_module, Category_over_base_ring -from tensor import TensorProductsCategory +from sage.categories.tensor import TensorProductsCategory, tensor from dual import DualObjectsCategory from sage.categories.sets_cat import Sets from sage.categories.bimodules import Bimodules @@ -390,14 +390,13 @@ def Super(self, base_ring=None): EXAMPLES:: sage: Modules(ZZ).Super() - Category of graded modules over Integer Ring + Category of super modules over Integer Ring sage: Coalgebras(QQ).Super() - Join of Category of graded modules over Rational Field - and Category of coalgebras over Rational Field + Category of super coalgebras over Rational Field sage: AlgebrasWithBasis(QQ).Super() - Category of graded algebras with basis over Rational Field + Category of super algebras with basis over Rational Field .. TODO:: @@ -463,7 +462,18 @@ def extra_super_categories(self): WithBasis = LazyImport('sage.categories.modules_with_basis', 'ModulesWithBasis') class ParentMethods: - pass + @cached_method + def tensor_square(self): + """ + Returns the tensor square of ``self`` + + EXAMPLES:: + + sage: A = HopfAlgebrasWithBasis(QQ).example() + sage: A.tensor_square() + An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field # An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field + """ + return tensor([self, self]) class ElementMethods: diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py new file mode 100644 index 00000000000..4fd9583c206 --- /dev/null +++ b/src/sage/categories/super_algebras.py @@ -0,0 +1,38 @@ +r""" +Super Algebras +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.categories.super_modules import SuperModulesCategory +from sage.categories.algebras import Algebras +from sage.categories.modules import Modules +from sage.misc.lazy_import import LazyImport + +class SuperAlgebras(SuperModulesCategory): + """ + The category of super algebras. + + EXAMPLES:: + + sage: Algebras(ZZ).Super() + Category of super algebras over Integer Ring + + TESTS:: + + sage: TestSuite(Algebras(ZZ).Super()).run() + """ + def extra_super_categories(self): + """ + EXAMPLES:: + + sage: Algebras(ZZ).Super().super_categories() + [Category of graded algebras over Integer Ring, + Category of super modules over Integer Ring] + """ + return [self.base_category().Graded()] + diff --git a/src/sage/categories/super_algebras_with_basis.py b/src/sage/categories/super_algebras_with_basis.py index ce9a8d266ff..51b2b72afe8 100644 --- a/src/sage/categories/super_algebras_with_basis.py +++ b/src/sage/categories/super_algebras_with_basis.py @@ -20,9 +20,6 @@ class SuperAlgebrasWithBasis(SuperModulesCategory): sage: C = Algebras(ZZ).WithBasis().Super(); C Category of super algebras with basis over Integer Ring - sage: sorted(C.super_categories(), key=str) - [Category of graded algebras with basis over Integer Ring, - Category of super modules with basis over Integer Ring] TESTS:: @@ -32,8 +29,10 @@ def extra_super_categories(self): """ EXAMPLES:: - sage: Algebras(ZZ).WithBasis().Super().super_categories() + sage: C = Algebras(ZZ).WithBasis().Super() + sage: sorted(C.super_categories(), key=str) # indirect doctest [Category of graded algebras with basis over Integer Ring, + Category of super algebras over Integer Ring, Category of super modules with basis over Integer Ring] """ return [self.base_category().Graded()] diff --git a/src/sage/categories/super_hopf_algebras_with_basis.py b/src/sage/categories/super_hopf_algebras_with_basis.py index 2de32bb0890..58e133915b6 100644 --- a/src/sage/categories/super_hopf_algebras_with_basis.py +++ b/src/sage/categories/super_hopf_algebras_with_basis.py @@ -19,9 +19,9 @@ class SuperHopfAlgebrasWithBasis(SuperModulesCategory): sage: C = HopfAlgebras(ZZ).WithBasis().Super(); C Category of super hopf algebras with basis over Integer Ring sage: sorted(C.super_categories(), key=str) - [Category of hopf algebras with basis over Integer Ring, - Category of super algebras over Integer Ring, - Category of super algebras with basis over Integer Ring] + [Category of super algebras with basis over Integer Ring, + Category of super coalgebras with basis over Integer Ring, + Category of super hopf algebras over Integer Ring] TESTS:: diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py index 0165a18adf8..b93883e4139 100644 --- a/src/sage/categories/super_modules.py +++ b/src/sage/categories/super_modules.py @@ -43,6 +43,11 @@ def default_super_categories(cls, category, *args): This implements the property that subcategories constructed by the set of whitelisted axioms is a subcategory. + + EXAMPLES:: + + sage: HopfAlgebras(ZZ).WithBasis().FiniteDimensional().Super() # indirect doctest + Category of finite dimensional super hopf algebras with basis over Integer Ring """ axioms = axiom_whitelist.intersection(category.axioms()) C = super(SuperModulesCategory, cls).default_super_categories(category, *args) diff --git a/src/sage/categories/super_modules_with_basis.py b/src/sage/categories/super_modules_with_basis.py index 64cfcc3da7b..e6930e620e9 100644 --- a/src/sage/categories/super_modules_with_basis.py +++ b/src/sage/categories/super_modules_with_basis.py @@ -37,6 +37,15 @@ def _even_odd_on_basis(self, m): ``0`` if ``m`` is for an even element or ``1`` if ``m`` is for an odd element. + + EXAMPLES:: + + sage: Q = QuadraticForm(QQ, 2, [1,2,3]) + sage: C. = CliffordAlgebra(Q) + sage: C._even_odd_on_basis((0,)) + 1 + sage: C._even_odd_on_basis((0,1)) + 0 """ return self.degree_on_basis(m) % 2 From 1404ad0e2336eee05877e3e1a434809d437a998d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 14 Apr 2015 18:10:00 -0400 Subject: [PATCH 0165/1872] Cleanup from merged code. --- src/sage/algebras/weyl_algebra.py | 2 +- src/sage/categories/filtered_algebras.py | 3 - src/sage/categories/filtered_modules.py | 83 ------------------------ src/sage/categories/graded_modules.py | 3 +- 4 files changed, 2 insertions(+), 89 deletions(-) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index d074d1dedfb..0400ba7fc37 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -589,7 +589,7 @@ def __init__(self, R, names=None): names = names + tuple('d' + n for n in names) if len(names) != self._n * 2: raise ValueError("variable names cannot differ by a leading 'd'") - cat = AlgebrasWithBasis(R.category()).NoZeroDivisors().Super().Filtered() + cat = AlgebrasWithBasis(R.category()).NoZeroDivisors().Super() Algebra.__init__(self, R, names, category=cat) def _repr_(self): diff --git a/src/sage/categories/filtered_algebras.py b/src/sage/categories/filtered_algebras.py index c9444680f0a..321dd604ed3 100644 --- a/src/sage/categories/filtered_algebras.py +++ b/src/sage/categories/filtered_algebras.py @@ -60,6 +60,3 @@ def graded_algebra(self): Lie algebra of RR^3 with cross product over Integer Ring """ - class ElementMethods: - pass - diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index 7ba8bd51a7c..8a9a79d6c08 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -57,82 +57,6 @@ def __init__(self, base_category): _functor_category = "Filtered" - @lazy_class_attribute - def _base_category_class(cls): - """ - Recover the class of the base category. - - OUTPUT: - - A *tuple* whose first entry is the base category class. - - .. WARNING:: - - This is only used for filtered categories that are not - implemented as nested classes, and won't work otherwise. - - .. SEEALSO:: :meth:`__classcall__` - - EXAMPLES:: - - sage: from sage.categories.filtered_modules import FilteredModules - sage: FilteredModules._base_category_class - (,) - sage: from sage.categories.filtered_algebras_with_basis import FilteredAlgebrasWithBasis - sage: FilteredAlgebrasWithBasis._base_category_class - (,) - - The reason for wrapping the base category class in a tuple is - that, often, the base category class implements a - :meth:`__classget__` method which would get in the way upon - attribute access:: - - sage: F = FilteredAlgebrasWithBasis - sage: F._foo = F._base_category_class[0] - sage: F._foo - Traceback (most recent call last): - ... - AssertionError: base category class for <...AlgebrasWithBasis'> mismatch; - expected <...Algebras'>, got <...FilteredAlgebrasWithBasis'> - """ - module_name = cls.__module__.replace("filtered_","") - import sys - name = cls.__name__.replace("Filtered","") - __import__(module_name) - module = sys.modules[module_name] - return (module.__dict__[name],) - - @staticmethod - def __classcall__(cls, category, *args): - """ - Magic support for putting Filtered categories in their own file. - - EXAMPLES:: - - sage: from sage.categories.filtered_modules import FilteredModules - sage: FilteredModules(ZZ) # indirect doctest - Category of filtered modules over Integer Ring - sage: Modules(ZZ).Filtered() - Category of filtered modules over Integer Ring - sage: FilteredModules(ZZ) is Modules(ZZ).Filtered() - True - - .. TODO:: - - Generalize this support for all other functorial - constructions if at some point we have a category ``Blah`` for - which we want to implement the construction ``Blah.Foo`` in a - separate file like we do for e.g. :class:`FilteredModules`, - :class:`FilteredAlgebras`, ... - - .. SEEALSO:: :meth:`_base_category_class` - """ - base_category_class = cls._base_category_class[0] - if isinstance(category, base_category_class): - return super(FilteredModulesCategory, cls).__classcall__(cls, category, *args) - else: - return base_category_class(category, *args).Filtered() - def _repr_object_names(self): """ EXAMPLES:: @@ -168,7 +92,6 @@ class FilteredModules(FilteredModulesCategory): - :wikipedia:`Filtration_(mathematics)` """ - def extra_super_categories(self): r""" Add :class:`VectorSpaces` to the super categories of ``self`` if @@ -236,9 +159,3 @@ def Connected(self): class Connected(CategoryWithAxiom_over_base_ring): pass - class ParentMethods: - pass - - class ElementMethods: - pass - diff --git a/src/sage/categories/graded_modules.py b/src/sage/categories/graded_modules.py index 311c986215d..ca31efe005b 100644 --- a/src/sage/categories/graded_modules.py +++ b/src/sage/categories/graded_modules.py @@ -96,8 +96,7 @@ def default_super_categories(cls, category, *args): and Category of graded modules over Rational Field """ cat = super(GradedModulesCategory, cls).default_super_categories(category, *args) - return Category.join([category.Filtered(), - cat]) + return Category.join([category.Filtered(), cat]) class GradedModules(GradedModulesCategory): r""" From 256d26894f461b15acb2be7fb5815fc06cff5405 Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Wed, 15 Apr 2015 11:35:56 +0200 Subject: [PATCH 0166/1872] changed name TensorParallelism to TensorParallelCompute --- src/sage/tensor/modules/all.py | 2 +- src/sage/tensor/modules/comp.py | 30 +++++++++---------- src/sage/tensor/modules/parallel_utilities.py | 24 +++++++-------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/sage/tensor/modules/all.py b/src/sage/tensor/modules/all.py index 0c630e7ef4d..43f2cbbad2c 100644 --- a/src/sage/tensor/modules/all.py +++ b/src/sage/tensor/modules/all.py @@ -1,3 +1,3 @@ from finite_rank_free_module import FiniteRankFreeModule -from parallel_utilities import TensorParallelism,set_nproc,get_nproc +from parallel_utilities import TensorParallelCompute,set_nproc,get_nproc diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index f1412684a57..14d2cd050cd 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -249,7 +249,7 @@ class :class:`~sage.tensor.differential_form_element.DifferentialForm`) from sage.structure.sage_object import SageObject from sage.rings.integer import Integer from sage.parallel.all import parallel -from sage.tensor.modules.parallel_utilities import TensorParallelism +from sage.tensor.modules.parallel_utilities import TensorParallelCompute from operator import itemgetter class Components(SageObject): @@ -1311,10 +1311,10 @@ def __add__(self, other): "same starting index") - if TensorParallelism()._use_paral : + if TensorParallelCompute()._use_paral : # parallel sum result = self._new_instance() - nproc = TensorParallelism()._nproc + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in other._comp.iteritems()] @@ -1519,8 +1519,8 @@ def __mul__(self, other): # So we use a loop specific to the current case and return the # result: - if TensorParallelism()._use_paral : - nproc = TensorParallelism()._nproc + if TensorParallelCompute()._use_paral : + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind in result.non_redundant_index_generator()] @@ -1549,8 +1549,8 @@ def paral_mul(a,local_list_ind): result = Components(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter) - if TensorParallelism()._use_paral : - nproc = TensorParallelism()._nproc + if TensorParallelCompute()._use_paral : + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in self._comp.iteritems()] @@ -1889,11 +1889,11 @@ def contract(self, *args): res = 0 - if TensorParallelism()._use_paral: + if TensorParallelCompute()._use_paral: # parallel contraction to scalar # parallel multiplication - @parallel(p_iter='multiprocessing',ncpus=TensorParallelism()._nproc) + @parallel(p_iter='multiprocessing',ncpus=TensorParallelCompute()._nproc) def compprod(a,b): return a*b @@ -2023,9 +2023,9 @@ def compprod(a,b): start_index=self._sindex) shift_o = self._nid - ncontr - if TensorParallelism()._use_paral: + if TensorParallelCompute()._use_paral: # parallel computation - nproc = TensorParallelism()._nproc + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in res.non_redundant_index_generator()] ind_step = max(1,int(len(ind_list)/nproc/2)) @@ -3268,8 +3268,8 @@ def __mul__(self, other): self._sindex, self._output_formatter, sym, antisym) - if TensorParallelism()._use_paral : - nproc = TensorParallelism()._nproc + if TensorParallelCompute()._use_paral : + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in self._comp.iteritems()] @@ -4576,10 +4576,10 @@ def __add__(self, other): raise ValueError("the two sets of components do not have the " + "same starting index") - if TensorParallelism()._use_paral : + if TensorParallelCompute()._use_paral : # parallel sum result = self._new_instance() - nproc = TensorParallelism()._nproc + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in other._comp.iteritems()] diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py index 8ced7b8a59f..da5cf14e253 100644 --- a/src/sage/tensor/modules/parallel_utilities.py +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -25,7 +25,7 @@ from sage.parallel.ncpus import ncpus -class TensorParallelism(Singleton, SageObject): +class TensorParallelCompute(Singleton, SageObject): r""" Class governing Tensors Parallelism. @@ -33,10 +33,10 @@ class TensorParallelism(Singleton, SageObject): EXAMPLE :: - sage: print TensorParallelism() + sage: print TensorParallelCompute() Number of cpu used = 1 - sage: TensorParallelism().set(4) - sage: print TensorParallelism() + sage: TensorParallelCompute().set(4) + sage: print TensorParallelCompute() Number of cpu used = 4 """ @@ -48,13 +48,13 @@ class is created. TEST :: - sage: TP = TensorParallelism() + sage: TP = TensorParallelCompute() sage: print TP Number of cpu used = 1 Test of the singleton character:: - sage: TensorParallelism() is TP + sage: TensorParallelCompute() is TP True """ @@ -67,7 +67,7 @@ def _repr_(self): TEST :: - sage: TensorParallelism()._repr_() + sage: TensorParallelCompute()._repr_() 'Number of cpu used = 1' """ @@ -81,10 +81,10 @@ def set(self,nproc=None): EXAMPLE :: - sage: print TensorParallelism() + sage: print TensorParallelCompute() Number of cpu used = 1 - sage: TensorParallelism().set(4) - sage: print TensorParallelism() + sage: TensorParallelCompute().set(4) + sage: print TensorParallelCompute() Number of cpu used = 4 """ @@ -110,7 +110,7 @@ def set_nproc(nproc=None): """ - TensorParallelism().set(nproc) + TensorParallelCompute().set(nproc) def get_nproc(): r""" @@ -124,4 +124,4 @@ def get_nproc(): """ - return TensorParallelism()._nproc + return TensorParallelCompute()._nproc From f2eba8b1536b4dbaaafa2741c9bf2b68f1ffe913 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 15 Apr 2015 22:43:23 +0200 Subject: [PATCH 0167/1872] parameter 'category' for cartesian products --- .../covariant_functorial_construction.py | 4 +-- src/sage/categories/sets_cat.py | 30 +++++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/covariant_functorial_construction.py b/src/sage/categories/covariant_functorial_construction.py index cc2ea36216e..47ed9d8e370 100644 --- a/src/sage/categories/covariant_functorial_construction.py +++ b/src/sage/categories/covariant_functorial_construction.py @@ -201,7 +201,7 @@ def _repr_(self): """ return "The %s functorial construction"%self._functor_name - def __call__(self, args): + def __call__(self, args, **kwargs): """ Functorial construction application @@ -220,7 +220,7 @@ def __call__(self, args): args = tuple(args) # a bit brute force; let's see if this becomes a bottleneck later assert(all( hasattr(arg, self._functor_name) for arg in args)) assert(len(args) > 0) - return getattr(args[0], self._functor_name)(*args[1:]) + return getattr(args[0], self._functor_name)(*args[1:], **kwargs) class FunctorialConstructionCategory(Category): # Should this be CategoryWithBase? """ diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index a6df4fd9a78..c0a710bc69c 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1366,10 +1366,23 @@ def _test_some_elements(self, **options): # Functorial constructions CartesianProduct = CartesianProduct - def cartesian_product(*parents): + def cartesian_product(*parents, **kwargs): """ Return the cartesian product of the parents. + INPUT: + + - ``parents`` -- a list (or other iterable) of parents. + + - ``category`` -- (default: ``None``) the category the + cartesian product belongs to. If ``None``, then + :meth:`~sage.categories.covariant_functorial_construction.CovariantFactorialConstruction.category_from_parents` + is used the determine category. + + OUTPUT: + + The cartesian product. + EXAMPLES:: sage: C = AlgebrasWithBasis(QQ) @@ -1389,10 +1402,23 @@ def cartesian_product(*parents): sage: C.category() Join of Category of rings and ... and Category of Cartesian products of commutative additive groups + + :: + + sage: cartesian_product([ZZ, ZZ], category=Sets()).category() + Category of sets + sage: cartesian_product([ZZ, ZZ], blub=None).category() + Traceback (most recent call last) + ... + TypeError: unknown parameters: blub """ + category = kwargs.pop('category', None) + if kwargs: + raise TypeError('unknown parameters: %s' % + ', '.join(str(k) for k in kwargs.iterkeys())) return parents[0].CartesianProduct( parents, - category = cartesian_product.category_from_parents(parents)) + category=category or cartesian_product.category_from_parents(parents)) def algebra(self, base_ring, category=None): """ From 7b098f7d1e9b4e0d26bfce6dad46889afbf19117 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 16 Apr 2015 01:08:40 +0200 Subject: [PATCH 0168/1872] parameter extra_category for cartesian products --- src/sage/categories/sets_cat.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index c0a710bc69c..a38a8311b21 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1379,6 +1379,10 @@ def cartesian_product(*parents, **kwargs): :meth:`~sage.categories.covariant_functorial_construction.CovariantFactorialConstruction.category_from_parents` is used the determine category. + - ``extra_category`` -- (default: ``None``) this category is + added to the cartesian product additionally to the + categories obtained from the parents. + OUTPUT: The cartesian product. @@ -1413,12 +1417,18 @@ def cartesian_product(*parents, **kwargs): TypeError: unknown parameters: blub """ category = kwargs.pop('category', None) + extra_category = kwargs.pop('extra_category', None) if kwargs: raise TypeError('unknown parameters: %s' % ', '.join(str(k) for k in kwargs.iterkeys())) - return parents[0].CartesianProduct( - parents, - category=category or cartesian_product.category_from_parents(parents)) + + category = category or cartesian_product.category_from_parents(parents) + if extra_category: + if isinstance(category, (list, tuple)): + category = tuple(category) + (extra_category,) + else: + category = category & extra_category + return parents[0].CartesianProduct(parents, category=category) def algebra(self, base_ring, category=None): """ From 60518658bf6575db0a12a7fce0b863dffea8d9cb Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 07:38:51 +0200 Subject: [PATCH 0169/1872] add a doctest which hopefully works (hard to check while compiling) --- src/sage/algebras/weyl_algebra.py | 5 ++++- src/sage/categories/coalgebras.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 1f4ba9dac8e..6983a2bac6a 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -567,7 +567,10 @@ def __init__(self, R, names=None): raise ValueError("variable names cannot differ by a leading 'd'") # TODO: Make this into a filtered algebra under the natural grading of # x_i and dx_i have degree 1 - cat = AlgebrasWithBasis(R).NoZeroDivisors().Super() + if R.is_field(): + cat = AlgebrasWithBasis(R).NoZeroDivisors().Super() + else: + cat = AlgebrasWithBasis(R).Super() Algebra.__init__(self, R, names, category=cat) def _repr_(self): diff --git a/src/sage/categories/coalgebras.py b/src/sage/categories/coalgebras.py index 2b2cc74043a..c4ce8148121 100644 --- a/src/sage/categories/coalgebras.py +++ b/src/sage/categories/coalgebras.py @@ -191,6 +191,17 @@ def extra_super_categories(self): sage: Coalgebras(ZZ).Super().super_categories() [Category of super modules over Integer Ring, Category of coalgebras over Integer Ring] + + Compare this with the situation for bialgebras:: + + sage: Bialgebras(ZZ).Super().extra_super_categories() + [] + sage: Bialgebras(ZZ).Super().super_categories() + [Category of super algebras over Integer Ring, + Category of super coalgebras over Integer Ring] + + The category of bialgebras does not occur in these results, + since super bialgebras are not bialgebras. """ return [self.base_category().Graded()] From bea739dea7a019607b770eafc5e436392e7f0bbf Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Thu, 16 Apr 2015 10:22:55 +0200 Subject: [PATCH 0170/1872] Added Eric corrections to parallelism --- src/sage/tensor/modules/all.py | 2 +- src/sage/tensor/modules/comp.py | 65 ++++++++++--------- src/sage/tensor/modules/parallel_utilities.py | 14 +++- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/src/sage/tensor/modules/all.py b/src/sage/tensor/modules/all.py index 43f2cbbad2c..c06e7e8d2b4 100644 --- a/src/sage/tensor/modules/all.py +++ b/src/sage/tensor/modules/all.py @@ -1,3 +1,3 @@ from finite_rank_free_module import FiniteRankFreeModule -from parallel_utilities import TensorParallelCompute,set_nproc,get_nproc +from parallel_utilities import set_nproc, get_nproc diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 14d2cd050cd..fa96f82c8e4 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -40,6 +40,7 @@ - Joris Vankerschaver (2010): for the idea of storing only the non-zero components as dictionaries, whose keys are the component indices (see class :class:`~sage.tensor.differential_form_element.DifferentialForm`) +- Marco Mancini (2015) : parallelization of some computations EXAMPLES: @@ -239,6 +240,7 @@ class :class:`~sage.tensor.differential_form_element.DifferentialForm`) #****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger +# Copyright (C) 2015 Marco Mancini # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -251,6 +253,7 @@ class :class:`~sage.tensor.differential_form_element.DifferentialForm`) from sage.parallel.all import parallel from sage.tensor.modules.parallel_utilities import TensorParallelCompute from operator import itemgetter +import time class Components(SageObject): r""" @@ -283,7 +286,7 @@ class Components(SageObject): EXAMPLES: Set of components with 2 indices on a 3-dimensional vector space, the frame - being some basis of the vector space:: + being some basis of the vector space:: sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) @@ -1314,26 +1317,26 @@ def __add__(self, other): if TensorParallelCompute()._use_paral : # parallel sum result = self._new_instance() - nproc = TensorParallelCompute()._nproc + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in other._comp.iteritems()] ind_step = max(1,int(len(ind_list)/nproc/2)) local_list = lol(ind_list,ind_step) - + # definition of the list of input parameters listParalInput = [(self,other,ind_part) for ind_part in local_list] - + @parallel(p_iter='multiprocessing',ncpus=nproc) def paral_sum(a,b,local_list_ind): partial = [] for ind in local_list_ind: partial.append([ind,a[[ind]]+b[[ind]]]) return partial - + for ii,val in paral_sum(listParalInput): for jj in val: - result[[jj[0]]] = jj[1] + result[[jj[0]]] = jj[1] else: # sequential @@ -1520,7 +1523,7 @@ def __mul__(self, other): # result: if TensorParallelCompute()._use_paral : - nproc = TensorParallelCompute()._nproc + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind in result.non_redundant_index_generator()] @@ -1536,8 +1539,8 @@ def paral_mul(a,local_list_ind): for ii,val in paral_mul(listParalInput): for jj in val: - result[[jj[0]]] = jj[1] - else: + result[[jj[0]]] = jj[1] + else: for ind in result.non_redundant_index_generator(): result[[ind]] = self[[ind[0]]] * self[[ind[1]]] @@ -1550,13 +1553,13 @@ def paral_mul(a,local_list_ind): self._sindex, self._output_formatter) if TensorParallelCompute()._use_paral : - nproc = TensorParallelCompute()._nproc + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in self._comp.iteritems()] ind_step = max(1,int(len(ind_list)/nproc)) local_list = lol(ind_list,ind_step) - + # definition of the list of input parameters listParalInput = [(self,other,ind_part) for ind_part in local_list] @@ -1570,8 +1573,8 @@ def paral_mul(a,b,local_list_ind): for ii,val in paral_mul(listParalInput): for jj in val: - result._comp[jj[0]] = jj[1] - else: + result._comp[jj[0]] = jj[1] + else: for ind_s, val_s in self._comp.iteritems(): for ind_o, val_o in other._comp.iteritems(): result._comp[ind_s + ind_o] = val_s * val_o @@ -1785,8 +1788,8 @@ def contract(self, *args): sage: s = a.contract(0, b, 1) ; s[:] [12, 24, 36] sage: set_nproc(1) - - + + Contraction on 2 indices:: sage: c = a*b ; c @@ -1827,7 +1830,7 @@ def contract(self, *args): [-285, 570, 855] sage: set_nproc(1) - + Consistency check with :meth:`trace`:: sage: b = a*a ; b # the tensor product of a with itself @@ -1890,13 +1893,13 @@ def contract(self, *args): if TensorParallelCompute()._use_paral: - # parallel contraction to scalar + # parallel contraction to scalar # parallel multiplication @parallel(p_iter='multiprocessing',ncpus=TensorParallelCompute()._nproc) def compprod(a,b): return a*b - + # parallel list of inputs partial = list(compprod([(other[[ind]],self[[ind]]) for ind in comp_for_contr.index_generator() @@ -1909,8 +1912,8 @@ def compprod(a,b): res += self[[ind]] * other[[ind]] return res - - + + # # Positions of self and other indices in the result # (None = the position is involved in a contraction and therefore @@ -2057,12 +2060,12 @@ def make_Contraction(this,other,local_list,rev_s,rev_o,shift_o,contractions,comp sm += this[[ind_s]] * other[[ind_o]] local_res.append([ind,sm]) return local_res - + for ii, val in make_Contraction(listParalInput): for jj in val : res[[jj[0]]] = jj[1] else: - # sequential + # sequential for ind in res.non_redundant_index_generator(): ind_s = [None for i in range(self._nid)] # initialization ind_o = [None for i in range(other._nid)] # initialization @@ -3269,16 +3272,16 @@ def __mul__(self, other): if TensorParallelCompute()._use_paral : - nproc = TensorParallelCompute()._nproc + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in self._comp.iteritems()] ind_step = max(1,int(len(ind_list)/nproc)) local_list = lol(ind_list,ind_step) - + # definition of the list of input parameters listParalInput = [(self,other,ind_part) for ind_part in local_list] - + @parallel(p_iter='multiprocessing',ncpus=nproc) def paral_mul(a,b,local_list_ind): partial = [] @@ -3289,14 +3292,14 @@ def paral_mul(a,b,local_list_ind): for ii,val in paral_mul(listParalInput): for jj in val: - result._comp[jj[0]] = jj[1] - else: + result._comp[jj[0]] = jj[1] + else: for ind_s, val_s in self._comp.iteritems(): for ind_o, val_o in other._comp.iteritems(): result._comp[ind_s + ind_o] = val_s * val_o return result - + def trace(self, pos1, pos2): r""" @@ -4557,7 +4560,7 @@ def __add__(self, other): sage: s == a + c True sage: set_nproc(1) - + """ if other == 0: @@ -4579,7 +4582,7 @@ def __add__(self, other): if TensorParallelCompute()._use_paral : # parallel sum result = self._new_instance() - nproc = TensorParallelCompute()._nproc + nproc = TensorParallelCompute()._nproc lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in other._comp.iteritems()] @@ -4598,7 +4601,7 @@ def paral_sum(a,b,local_list_ind): for ii,val in paral_sum(listParalInput): for jj in val: - result[[jj[0]]] = jj[1] + result[[jj[0]]] = jj[1] else: # sequential diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py index da5cf14e253..7598f20688a 100644 --- a/src/sage/tensor/modules/parallel_utilities.py +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -33,14 +33,18 @@ class TensorParallelCompute(Singleton, SageObject): EXAMPLE :: + sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute sage: print TensorParallelCompute() Number of cpu used = 1 sage: TensorParallelCompute().set(4) sage: print TensorParallelCompute() Number of cpu used = 4 - + sage: TensorParallelCompute().set(1) + sage: print TensorParallelCompute() + Number of cpu used = 1 + """ - def __init__(self): + def __init__(self): r""" Intializes the parallelism. Only an instance (Singleton) of this class is created. @@ -48,6 +52,7 @@ class is created. TEST :: + sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute sage: TP = TensorParallelCompute() sage: print TP Number of cpu used = 1 @@ -56,7 +61,7 @@ class is created. sage: TensorParallelCompute() is TP True - + """ self._nproc = 1 self._use_paral = False @@ -67,6 +72,7 @@ def _repr_(self): TEST :: + sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute sage: TensorParallelCompute()._repr_() 'Number of cpu used = 1' @@ -81,11 +87,13 @@ def set(self,nproc=None): EXAMPLE :: + sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute sage: print TensorParallelCompute() Number of cpu used = 1 sage: TensorParallelCompute().set(4) sage: print TensorParallelCompute() Number of cpu used = 4 + sage: TensorParallelCompute().set(1) """ self._nproc = ncpus() if nproc is None else nproc From 94af4b0cf84d244d96b5bd3dcd65a572687cbb67 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 17 Apr 2015 08:19:55 +0200 Subject: [PATCH 0171/1872] tweak to_word methods to return non-Word results if so demanded; fix incorrect use of a^2 for a**2 (this works in the interactive session only due to the preparser); a few minor fixes here and there --- src/sage/combinat/skew_tableau.py | 44 ++++++++++++++++++++++--------- src/sage/combinat/tableau.py | 38 +++++++++++++++++++++----- 2 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 36ace110037..78708074a4b 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -24,7 +24,6 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -import copy from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.structure.parent import Parent @@ -41,7 +40,7 @@ from sage.structure.list_clone import ClonableList from sage.combinat.partition import Partition -from sage.combinat.tableau import TableauOptions, Tableaux, SemistandardTableau, StandardTableau, Tableau +from sage.combinat.tableau import TableauOptions, SemistandardTableau, StandardTableau, Tableau from sage.combinat.skew_partition import SkewPartition, SkewPartitions from sage.combinat.integer_vector import IntegerVectors from sage.combinat.words.words import Words @@ -405,13 +404,20 @@ def conjugate(self): return SkewTableau(conj) - def to_word_by_row(self): + def to_word_by_row(self, as_word=True): """ Return a word obtained from a row reading of ``self``. Specifically, this is the word obtained by concatenating the rows from the bottommost one (in English notation) to the topmost one. + INPUT: + + - ``as_word`` -- boolean (default: ``True``); if ``True``, + the result is returned as a word (i.e., an element of + :class:`Words`), while otherwise it is returned as a + list + EXAMPLES:: sage: s = SkewTableau([[None,1],[2,3]]) @@ -427,6 +433,8 @@ def to_word_by_row(self): 1 sage: s.to_word_by_row() word: 1324 + sage: s.to_word_by_row(as_word=False) + [1, 3, 2, 4] TESTS:: @@ -439,9 +447,11 @@ def to_word_by_row(self): for row in self: word = list(row) + word + if not as_word: + return filter(lambda x: x is not None, word) return Words("positive integers")([i for i in word if i is not None]) - def to_word_by_column(self): + def to_word_by_column(self, as_word=True): """ Return the word obtained from a column reading of the skew tableau. @@ -449,6 +459,13 @@ def to_word_by_column(self): columns from the rightmost one (in English notation) to the leftmost one. + INPUT: + + - ``as_word`` -- boolean (default: ``True``); if ``True``, + the result is returned as a word (i.e., an element of + :class:`Words`), while otherwise it is returned as a + list + EXAMPLES:: sage: s = SkewTableau([[None,1],[2,3]]) @@ -467,8 +484,10 @@ def to_word_by_column(self): 1 sage: s.to_word_by_column() word: 4231 + sage: s.to_word_by_column(as_word=False) + [4, 2, 3, 1] """ - return self.conjugate().to_word_by_row() + return self.conjugate().to_word_by_row(as_word=as_word) to_word = to_word_by_row @@ -780,8 +799,8 @@ def to_chain(self, max_entry=None): def slide(self, corner=None): """ Apply a jeu-de-taquin slide to ``self`` on the specified inner corner and - returns the new tableau. If no corner is given an arbitrary inner corner - is chosen. + return the resulting tableau. If no corner is given, an arbitrary inner + corner is chosen. See [FW]_ p12-13. @@ -902,7 +921,7 @@ def rectify(self, algorithm=None): if algorithm is None: la = self.outer_shape() la_size = la.size() - if mu_size^2 < len(la) * (la_size - mu_size): + if mu_size ** 2 < len(la) * (la_size - mu_size): algorithm = 'jdt' else: algorithm = 'schensted' @@ -912,7 +931,7 @@ def rectify(self, algorithm=None): for i in range(mu_size): rect = rect.slide() elif algorithm == 'schensted': - rect = Tableau([]).insert_word(self.to_word()) + rect = Tableau([]).insert_word(self.to_word(as_word=False)) else: raise ValueError("algorithm must be 'jdt', 'schensted', or None") if self in StandardSkewTableaux(): @@ -1801,9 +1820,10 @@ def cardinality(self): def __iter__(self): """ - 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. + An iterator for all the standard skew tableaux whose shape is + the skew partition ``skp``. The standard skew tableaux are + ordered lexicographically by the word obtained from their row + reading. EXAMPLES:: diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 0cc8b8fe065..2d044843caa 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -881,45 +881,67 @@ def pp(self): """ print self._repr_diagram() - def to_word_by_row(self): + def to_word_by_row(self, as_word=True): """ Return the word obtained from a row reading of the tableau ``self`` (starting with the lowermost row, reading every row from left to right). + INPUT: + + - ``as_word`` -- boolean (default: ``True``); if ``True``, + the result is returned as a word (i.e., an element of + :class:`Words`), while otherwise it is returned as a + list + EXAMPLES:: sage: Tableau([[1,2],[3,4]]).to_word_by_row() word: 3412 sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_row() word: 325146 + sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_row(as_word=False) + [3, 2, 5, 1, 4, 6] """ - from sage.combinat.words.word import Word w = [] for row in reversed(self): w += row + if not as_word: + return w + from sage.combinat.words.word import Word return Word(w) - def to_word_by_column(self): + def to_word_by_column(self, as_word=True): """ Return the word obtained from a column reading of the tableau ``self`` (starting with the leftmost column, reading every column from bottom to top). + INPUT: + + - ``as_word`` -- boolean (default: ``True``); if ``True``, + the result is returned as a word (i.e., an element of + :class:`Words`), while otherwise it is returned as a + list + EXAMPLES:: sage: Tableau([[1,2],[3,4]]).to_word_by_column() word: 3142 sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_column() word: 321546 + sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_column(as_word=False) + [3, 2, 1, 5, 4, 6] """ - from sage.combinat.words.word import Word w = [] for row in self.conjugate(): w += row[::-1] + if not as_word: + return w + from sage.combinat.words.word import Word return Word(w) - def to_word(self): + def to_word(self, as_word=True): """ An alias for :meth:`to_word_by_row`. @@ -929,8 +951,10 @@ def to_word(self): word: 3412 sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word() word: 325146 + sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word(as_word=False) + [3, 2, 5, 1, 4, 6] """ - return self.to_word_by_row() + return self.to_word_by_row(as_word=as_word) def attacking_pairs(self): """ @@ -2546,7 +2570,7 @@ def row_stabilizer(self): k = self.size() gens = [range(1, k+1)] for row in self: - for j in range(0, len(row)-1): + for j in range(len(row)-1): gens.append( (row[j], row[j+1]) ) return PermutationGroup( gens ) From f219ce3a60512bac0da8c8b05042c4ee02eacf07 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 22 Apr 2015 05:04:48 +0200 Subject: [PATCH 0172/1872] Fixed whitespace errors and corrected second-hand lazy import (probably a merge error) --- src/sage/algebras/clifford_algebra.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index ed22c0e6796..324660b0797 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -19,7 +19,7 @@ from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis -from sage.categories.modules_with_basis import ModuleMorphismByLinearity +from sage.modules.with_basis.morphism import ModuleMorphismByLinearity from sage.categories.poor_man_map import PoorManMap from sage.rings.all import ZZ from sage.modules.free_module import FreeModule, FreeModule_generic @@ -477,7 +477,7 @@ class CliffordAlgebra(CombinatorialFreeModule): sage: Cl = CliffordAlgebra(Q) sage: Cl The Clifford algebra of the Quadratic form in 3 variables - over Integer Ring with coefficients: + over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] @@ -557,7 +557,7 @@ def _repr_(self): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: CliffordAlgebra(Q) The Clifford algebra of the Quadratic form in 3 variables - over Integer Ring with coefficients: + over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] @@ -833,7 +833,7 @@ def quadratic_form(self): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl. = CliffordAlgebra(Q) sage: Cl.quadratic_form() - Quadratic form in 3 variables over Integer Ring with coefficients: + Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 2 3 ] [ * 4 5 ] [ * * 6 ] From c609f87a6fbe26ca8f549904c25f491808065c0d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 22 Apr 2015 14:15:39 -0700 Subject: [PATCH 0173/1872] Implement left_top and right_bottom methods for RC's. --- .../rigged_configuration_element.py | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py index 47b558bf4b4..6bb8e2c6961 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py +++ b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py @@ -1782,6 +1782,125 @@ def left_box(self, return_b=False): delta = left_box + def left_top(self): + r""" + Return the image of ``self`` under the left column top splitting + map `\gamma`. + + Consider the map `\gamma : RC(B^{r,1} \otimes B) \to RC(B^{1,1} + B^{r-1,1} \otimes B)` for `r > 1`, which is a natural strict + classical crystal injection. On rigged configurations, the map + `\gamma` adds a singular string of length `1` to `\nu^{(a)}`. + + We can extend `\gamma` when the left-most factor is not a single + column by precomposing with a :meth:`left_split()`. + + EXAMPLES:: + + sage: RC = RiggedConfigurations(['C',3,1], [[3,1], [2,1]]) + sage: mg = RC.module_generators[-1] + sage: ascii_art(mg) + 0[ ]0 0[ ][ ]0 0[ ]0 + 0[ ]0 0[ ]0 + sage: ascii_art(mg.left_top()) + 0[ ]0 0[ ][ ]0 0[ ]0 + 0[ ]0 0[ ]0 0[ ]0 + 0[ ]0 + + sage: RC = RiggedConfigurations(['C',3,1], [[2,1], [1,1], [3,1]]) + sage: mg = RC.module_generators[7] + sage: ascii_art(mg) + 1[ ]0 0[ ][ ]0 0[ ]0 + 0[ ]0 0[ ]0 + sage: ascii_art(mg.left_top()) + 1[ ]1 0[ ][ ]0 0[ ]0 + 1[ ]0 0[ ]0 0[ ]0 + """ + P = self.parent() + r = P.dims[0][0] + if r == 1: + raise ValueError("cannot split a single box") + ct = P.cartan_type() + if ct.type() == 'D': + if P.dims[0][0] >= ct.rank() - 2: + raise ValueError("only for non-spinor cases") + elif ct.type() == 'B' or ct.dual().type() == 'B': + if P.dims[0][0] == ct.rank() - 1: + raise ValueError("only for non-spinor cases") + + if P.dims[0][1] > 1: + return self.left_split().left_top() + + B = [[1,1], [r-1,1]] + B.extend(P.dims[1:]) + from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + RC = RiggedConfigurations(P._cartan_type, B) + parts = [x._clone() for x in self] # Make a deep copy + for nu in parts[:r-1]: + nu._list.append(1) + for a, nu in enumerate(parts[:r-1]): + vac_num = RC._calc_vacancy_number(parts, a, -1) + i = nu._list.index(1) + nu.vacancy_numbers.insert(i, vac_num) + nu.rigging.insert(i, vac_num) + return RC(*parts) + + def right_bottom(self): + r""" + Return the image of ``self`` under the right column bottom splitting + map `\gamma^*`. + + Consider the map `\gamma^* : RC(B \otimes B^{r,1}) \to RC(B \otimes + B^{r-1,1} \otimes B^{1,1})` for `r > 1`, which is a natural strict + classical crystal injection. On rigged configurations, the map + `\gamma` adds a string of length `1` with rigging 0 to `\nu^{(a)}` + for all `a < r` to a classically highest weight element and extended + as a classical crystal morphism. + + We can extend `\gamma^*` when the right-most factor is not a single + column by precomposing with a :meth:`right_split()`. + + EXAMPLES:: + + sage: RC = RiggedConfigurations(['C',3,1], [[2,1], [1,1], [3,1]]) + sage: mg = RC.module_generators[7] + sage: ascii_art(mg) + 1[ ]0 0[ ][ ]0 0[ ]0 + 0[ ]0 0[ ]0 + sage: ascii_art(mg.right_bottom()) + 1[ ]0 0[ ][ ]0 0[ ]0 + 1[ ]0 0[ ]0 0[ ]0 + 0[ ]0 + """ + P = self.parent() + r = P.dims[-1][0] + if r == 1: + raise ValueError("cannot split a single box") + ct = P.cartan_type() + if ct.type() == 'D': + if P.dims[-1][0] >= ct.rank() - 2: + raise ValueError("only for non-spinor cases") + elif ct.type() == 'B' or ct.dual().type() == 'B': + if P.dims[-1][0] == ct.rank() - 1: + raise ValueError("only for non-spinor cases") + + if P.dims[-1][1] > 1: + return self.right_split().right_bottom() + + rc, e_string = self.to_highest_weight(P.cartan_type().classical().index_set()) + + B = P.dims[:-1] + ([r-1,1], [1,1]) + from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + RC = RiggedConfigurations(P._cartan_type, B) + parts = [x._clone() for x in rc] # Make a deep copy + for nu in parts[:r-1]: + nu._list.append(1) + for a, nu in enumerate(parts[:r-1]): + vac_num = RC._calc_vacancy_number(parts, a, -1) + nu.vacancy_numbers.append(vac_num) + nu.rigging.append(0) + return RC(*parts).f_string(reversed(e_string)) + def complement_rigging(self, reverse_factors=False): r""" Apply the complement rigging morphism `\theta` to ``self``. From e90356f13323c36e2a8f8ed8e790577f48688c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 24 Apr 2015 11:49:30 +0200 Subject: [PATCH 0174/1872] trac #18284 making doc build --- .../rigged_configurations/rigged_configuration_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py index 6bb8e2c6961..742522a1ab5 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py +++ b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py @@ -1788,7 +1788,7 @@ def left_top(self): map `\gamma`. Consider the map `\gamma : RC(B^{r,1} \otimes B) \to RC(B^{1,1} - B^{r-1,1} \otimes B)` for `r > 1`, which is a natural strict + \otimes B^{r-1,1} \otimes B)` for `r > 1`, which is a natural strict classical crystal injection. On rigged configurations, the map `\gamma` adds a singular string of length `1` to `\nu^{(a)}`. From 0b6e3f732224e9784afad1cec93afb89d1a7810a Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2015 14:14:21 -0400 Subject: [PATCH 0175/1872] use list comprehension as Travis suggested --- src/sage/combinat/skew_tableau.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 78708074a4b..7f5dc2fa067 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -443,13 +443,10 @@ def to_word_by_row(self, as_word=True): sage: SkewTableau([]).to_word_by_row() word: """ - word = [] - for row in self: - word = list(row) + word - + word = [x for row in reversed(self) for x in row if x is not None] if not as_word: - return filter(lambda x: x is not None, word) - return Words("positive integers")([i for i in word if i is not None]) + return word + return Words("positive integers")(word) def to_word_by_column(self, as_word=True): """ From db1c8969aa371946ddbd092c555fc010a3d69a98 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 14:15:37 +0200 Subject: [PATCH 0176/1872] New encoder class --- src/sage/coding/encoder.py | 255 +++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 src/sage/coding/encoder.py diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py new file mode 100644 index 00000000000..47469d0f915 --- /dev/null +++ b/src/sage/coding/encoder.py @@ -0,0 +1,255 @@ +r""" +Encoder + +Given a code, an encoder embeds some specific methods to link this code's +message space to this code's ambient space. +""" + +#***************************************************************************** +# 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.modules.free_module_element import vector +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.structure.sage_object import SageObject + +class Encoder(SageObject): + r""" + Abstract top-class for Encoder objects. + + + This class contains all methods that can be used by encoders. + So, every encoder class should inherit from this abstract class. + + This class provides: + + - ``code``, the associated code of the encoder + + - methods that will work for any encoder + + To implement an encoder, you need to: + + - inherit from Encoder + + - call Encoder ``__init__`` method in the subclass constructor. Example: + ``super(SubclassName, self).__init__(code)``. + By doing that, your subclass will have its ``code`` parameter initialized. + You need of course to complete the constructor by adding any additional parameter + needed to describe properly the code defined in the subclass. + + Then, if the message space is a vectorial space, default implementation of ``encode`` and + ``unencode_nocheck`` methods are provided. These implementations rely on ``generator_matrix`` + which you need to override to use the default implementations. + + If the message space is not a vectorial space, you cannot have a generator matrix. + In that case, you need to override ``encode`` and ``unencode_nocheck``. + + As Encoder is not designed to be implemented, it does not have any representation + methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. + """ + + def __init__(self, code): + r""" + Initializes mandatory parameters for an Encoder object. + + This method only exists for inheritance purposes as it initializes + parameters that need to be known by every linear code. An abstract + encoder object should never be created. + + INPUT: + + - ``code`` -- the associated code of ``self`` + + EXAMPLES: + + We first create a new Encoder subclass:: + + sage: class EncoderExample(sage.coding.encoder.Encoder): + ....: def __init__(self, code): + ....: super(EncoderExample, self).__init__(code) + + We now create a member of our newly made class:: + + sage: G = Matrix(GF(2), [[1, 0, 0, 1], [0, 1, 1, 1]]) + sage: C = codes.LinearCode(G) + sage: E = EncoderExample(C) + + We can check its parameters:: + + sage: E.code() + Linear code of length 4, dimension 2 over Finite Field of size 2 + """ + self._code = code + + def encode(self, word): + r""" + Encodes ``word`` as a codeword of ``self``. + + This is a default implementation which assumes that the message + space of the encoder is a Vector Space. If this is not the case, + this method should be overwritten by the subclass. + + INPUT: + + - ``word`` -- a vector of the same length as dimension of ``self`` + + OUTPUT: + + - a vector 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 = codes.LinearCode(G) + sage: word = vector((0, 1, 1, 0)) + sage: C.encode(word) + (1, 1, 0, 0, 1, 1, 0) + """ + return vector(word) * self.generator_matrix() + + def unencode(self, c, nocheck=False, **kwargs): + r""" + Returns ``c`` decoded to the message space of ``self``. + + INPUT: + + - ``c`` -- a vector of the same length as ``self`` over the + base field of ``self`` + + - ``nocheck`` -- (default: ``False``) checks if ``c`` is in self. If this is set + to True, the return value of this method is not guaranteed to be correct. + + OUTPUT: + + - a vector of the message space 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 = codes.LinearCode(G) + sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) + sage: C.unencode(c) + (0, 1, 1, 0) + """ + if nocheck == False: + if c not in self.code(): + raise EncodingFailure("Given word is not in the code") + else: + return self.unencode_nocheck(c, **kwargs) + else: + return self.unencode_nocheck(c, **kwargs) + + @cached_method + def _unencoder_matrix(self): + r""" + Finds an information set for G, and return the inverse of those + columns of G. + + AUTHORS: + + This function is taken from codinglib (https://bitbucket.org/jsrn/codinglib/) + and was written by Johan Nielsen. + + 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 = codes.LinearCode(G) + sage: E = C.encoder() + sage: E._unencoder_matrix() + [1 0 1 9] + [0 3 3 6] + [0 4 2 5] + [0 4 5 2] + """ + Gt = self.generator_matrix().matrix_from_columns(self.code().information_set()) + return Gt.inverse() + + def unencode_nocheck(self, c, **kwargs): + r""" + Returns the message corresponding to a codeword. + + When c is not a codeword, the output is unspecified. + + AUTHORS: + + This function is taken from codinglib (https://bitbucket.org/jsrn/codinglib/) + and was written by Johan Nielsen. + + INPUT: + + - ``c`` -- a vector of the same length as ``self`` over the + base field of ``self`` + + OUTPUT: + + - a vector + + 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 = codes.LinearCode(G) + sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) + sage: c in C + True + sage: C.unencode_nocheck(c) + (0, 1, 1, 0) + #TODO: another exemple with a word that does not belong to C + """ + U = self._unencoder_matrix() + info_set = self.code().information_set() + cc = vector( c[i] for i in info_set ) + return cc * U + + def code(self): + r""" + Returns the code in which ``self.encode()`` has its output. + + 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 = codes.LinearCode(G) + sage: E = C.encoder() + sage: E.code() + Linear code of length 7, dimension 4 over Finite Field of size 2 + """ + return self._code + + def message_space(self): + r""" + Returns the ambient space of allowed input to ``self.encode()``. + Note that the ``self.encode()`` is possibly a partial function over + the ambient space. + + 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 = codes.LinearCode(G) + sage: E = C.encoder() + sage: E.message_space() + Vector space of dimension 4 over Finite Field of size 2 + """ + return self.code().base_field()**(self.code().dimension()) + + @abstract_method(optional = True) + def generator_matrix(self): + r""" + Returns a generator matrix of the associated code of self. + + This is an abstract method and it should be implemented separately. + Reimplementing this for each subclass of Encoder is not mandatory + (as encoders with a polynomial message space, for instance, do not + need a generator matrix). + """ + +class EncodingFailure(Exception): + r""" + Special exception class to indicate a failure during encoding or unencoding. + """ + pass From 7048dbb7d2be41d9b4983b92b6944e1d30ea0576 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 14:26:02 +0200 Subject: [PATCH 0177/1872] New encoder-related methods in linear_code.py --- src/sage/coding/linear_code.py | 122 +++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index f4fd1c0c00f..72b9578fd50 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1631,6 +1631,98 @@ def __eq__(self, right): return False return True + def encode(self, word, name=None, **kwargs): + r""" + Encodes ``word`` as a codeword of ``self``. + + INPUT: + + - ``word`` -- a vector of the same length as dimension of ``self`` + + - ``name`` -- (default: ``None``) Name of the encoder which will be used + to encode ``word``. The default encoder of ``self`` will be used if + default value is kept + + OUTPUT: + + - a vector 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 = codes.LinearCode(G) + sage: word = vector((0, 1, 1, 0)) + sage: C.encode(word) + (1, 1, 0, 0, 1, 1, 0) + + It is possible to manually choose the encoder amongst the list of the available ones:: + + sage: C.encoders_available() + ['GeneratorMatrix'] + sage: word = vector((0, 1, 1, 0)) + sage: C.encode(word, 'GeneratorMatrix') + (3, 5, 0, 4, 0, 4, 10, 1, 4, 2) + """ + E = self.encoder(name, **kwargs) + return E.encode(word) + + @cached_method + def encoder(self, name=None, **kwargs): + r""" + Returns an encoder of ``self``. + + INPUT: + + - ``name`` -- (default: ``None``) name of the encoder which will be + returned. The default encoder of ``self`` will be used if + default value is kept. + + OUTPUT: + + - an Encoder object + + + 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 = codes.LinearCode(G) + sage: C.encoder() + Generator-matrix based encoder for the Linear code of length 7, dimension 4 over + Finite Field of size 2 + + If the name of an encoder which is not known by ``self`` is passed, + an exception will be raised:: + + sage: C.encoders_available() + ['GeneratorMatrix'] + sage: C.encoder('NonExistingEncoder') + Traceback (most recent call last): + ... + ValueError: Passed Encoder name not known + """ + if name is None: + name = self._encoder_default_name + return self.encoder(name, **kwargs) + if name in self._registered_encoders: + encClass = self._registered_encoders[name] + E = encClass(self, **kwargs) + return E + else: + raise ValueError("Passed Encoder name not known") + + def encoders_available(self): + r""" + Returns a list of the possible encoders for ``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 = codes.LinearCode(G) + sage: C.encoders_available() + ['GeneratorMatrix'] + """ + return self._registered_encoders.keys() + def extended_code(self): r""" If ``self`` is a linear code of length `n` defined over `F` then this @@ -3011,6 +3103,36 @@ def syndrome(self, r): """ return self.parity_check_matrix()*r + def unencode(self, c, name=None, nocheck=False, **kwargs): + r""" + Returns ``c`` decoded to the message space of ``self``. + + INPUT: + + - ``c`` -- a vector of the same length as ``self`` over the + base field of ``self`` + + - ``name`` -- (default: ``None``) name of the decoder which will be used + to decode ``word``. The default decoder of ``self`` will be used if + default value is kept. + + - ``nocheck`` -- (default: ``False``) checks if ``c`` is in self. If this is set + to True, the return value of this method is not guaranteed to be correct. + + OUTPUT: + + - a vector + + 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 = codes.LinearCode(G) + sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) + sage: C.unencode(c) + (0, 1, 1, 0) + """ + E = self.encoder(name, **kwargs) + return E.unencode(c, nocheck) def weight_enumerator(self, names="xy", name2=None): """ From 15cd2cd1eb157c554ed04b78f67def2135e6e5d0 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 14:36:35 +0200 Subject: [PATCH 0178/1872] New encoder for linear codes --- src/sage/coding/linear_code_encoders.py | 90 +++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/sage/coding/linear_code_encoders.py diff --git a/src/sage/coding/linear_code_encoders.py b/src/sage/coding/linear_code_encoders.py new file mode 100644 index 00000000000..245a64eefc1 --- /dev/null +++ b/src/sage/coding/linear_code_encoders.py @@ -0,0 +1,90 @@ +r""" +Linear Code Encoders +""" + +#***************************************************************************** +# 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 encoder import Encoder +from sage.misc.cachefunc import cached_method + +class EncoderLinearCodeGeneratorMatrix(Encoder): + r""" + Encoder based on generator_matrix for Linear codes. + + The only purpose of this encoder is to include the existing code + into the new Encoder and Decoder structure. + + INPUT: + + - ``code`` -- The associated code of this encoder. + """ + + def __init__(self, code): + r""" + 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 = codes.LinearCode(G) + sage: C.encoder() + Generator-matrix based encoder for the Linear code of length 7, dimension 4 over + Finite Field of size 2 + """ + super(EncoderLinearCodeGeneratorMatrix, self).__init__(code) + + def _repr_(self): + r""" + Returns a string representation 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 = codes.LinearCode(G) + sage: C.encoder() + Generator-matrix based encoder for the Linear code of length 7, dimension 4 over + Finite Field of size 2 + """ + return "Generator matrix-based encoder for the %s" % self.code() + + def _latex_(self): + r""" + Returns a latex representation 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 = codes.LinearCode(G) + sage: E = C.encoder() + sage: latex(E) + \textnormal{Generator-matrix based encoder for the Linear code of length 7, dimension 4 over + Finite Field of size 2} + """ + return "\\textnormal{Generator matrix-based encoder for the %s}" % self.code()._latex_() + + @cached_method + def generator_matrix(self): + r""" + Returns a generator matrix of the associated code 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 = codes.LinearCode(G) + sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E.generator_matrix() + [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] + """ + if hasattr(self.code(), "_generator_matrix"): + return self.code()._generator_matrix + else: + return self.code().generator_matrix() From b54bac5c21435b47bb1cc4884b4c106640abf45c Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 15:05:16 +0200 Subject: [PATCH 0179/1872] Links with encoder structure --- src/sage/coding/__init__.py | 1 + src/sage/coding/all.py | 2 ++ src/sage/coding/encoder.py | 39 ++++++++++++++++++++++------------ src/sage/coding/linear_code.py | 3 +++ 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/sage/coding/__init__.py b/src/sage/coding/__init__.py index c9fecacd721..24bb6b11ac1 100644 --- a/src/sage/coding/__init__.py +++ b/src/sage/coding/__init__.py @@ -1 +1,2 @@ import all +linear_code.LinearCode._registered_encoders["GeneratorMatrix"] = linear_code_encoders.EncoderLinearCodeGeneratorMatrix diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 7512aac7a6d..4e1faf0d4db 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -68,6 +68,8 @@ bounds_minimum_distance, self_orthogonal_binary_codes) +from linear_code_encoders import EncoderLinearCodeGeneratorMatrix + from sd_codes import self_dual_codes_binary lazy_import("sage.coding.delsarte_bounds", diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 47469d0f915..61f75953acc 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -78,7 +78,7 @@ def __init__(self, code): We now create a member of our newly made class:: sage: G = Matrix(GF(2), [[1, 0, 0, 1], [0, 1, 1, 1]]) - sage: C = codes.LinearCode(G) + sage: C = LinearCode(G) sage: E = EncoderExample(C) We can check its parameters:: @@ -107,7 +107,7 @@ def encode(self, word): 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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: word = vector((0, 1, 1, 0)) sage: C.encode(word) (1, 1, 0, 0, 1, 1, 0) @@ -133,7 +133,7 @@ def unencode(self, c, nocheck=False, **kwargs): 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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: C.unencode(c) (0, 1, 1, 0) @@ -160,13 +160,13 @@ def _unencoder_matrix(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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: E = C.encoder() sage: E._unencoder_matrix() - [1 0 1 9] - [0 3 3 6] - [0 4 2 5] - [0 4 5 2] + [0 0 1 1] + [0 1 0 1] + [1 1 1 0] + [0 1 1 1] """ Gt = self.generator_matrix().matrix_from_columns(self.code().information_set()) return Gt.inverse() @@ -194,13 +194,26 @@ def unencode_nocheck(self, c, **kwargs): 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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: c in C True - sage: C.unencode_nocheck(c) + sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E.unencode_nocheck(c) (0, 1, 1, 0) - #TODO: another exemple with a word that does not belong to C + + We take a vector that does not belong to C:: + + sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 1)) + sage: c in C + False + sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E.unencode_nocheck(c) + (0, 1, 1, 0) + sage: m = vector(GF(2), (0, 1, 1, 0)) + sage: c1 = E.encode(m) + sage: c == c1 + False """ U = self._unencoder_matrix() info_set = self.code().information_set() @@ -214,7 +227,7 @@ def code(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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: E = C.encoder() sage: E.code() Linear code of length 7, dimension 4 over Finite Field of size 2 @@ -230,7 +243,7 @@ def message_space(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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: E = C.encoder() sage: E.message_space() Vector space of dimension 4 over Finite Field of size 2 diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 72b9578fd50..94ae90eb0e2 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -3408,6 +3408,8 @@ class LinearCode(AbstractLinearCode): # sage: C.minimum_distance_why() # optional (net connection) # Ub(7,4) = 3 follows by the Griesmer bound. + _registered_encoders = {} + def __init__(self, generator_matrix, d=None): r""" See the docstring for :meth:`LinearCode`. @@ -3473,6 +3475,7 @@ def __init__(self, generator_matrix, d=None): self._generator_matrix = generator_matrix self._dimension = generator_matrix.rank() self._minimum_distance = d + self._encoder_default_name = "GeneratorMatrix" def _repr_(self): r""" From 5f4ca778bdd1dffa809710f14982ddb462dc1e39 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 15:46:38 +0200 Subject: [PATCH 0180/1872] Default implementation of generator_matrix in AbstractLinearCode. Changed documentation --- src/sage/coding/__init__.py | 2 +- src/sage/coding/encoder.py | 6 +- src/sage/coding/linear_code.py | 104 +++++++++++++++--------- src/sage/coding/linear_code_encoders.py | 27 +++--- 4 files changed, 84 insertions(+), 55 deletions(-) diff --git a/src/sage/coding/__init__.py b/src/sage/coding/__init__.py index 24bb6b11ac1..661b4bbcef4 100644 --- a/src/sage/coding/__init__.py +++ b/src/sage/coding/__init__.py @@ -1,2 +1,2 @@ import all -linear_code.LinearCode._registered_encoders["GeneratorMatrix"] = linear_code_encoders.EncoderLinearCodeGeneratorMatrix +linear_code.AbstractLinearCode._registered_encoders["GeneratorMatrix"] = linear_code_encoders.EncoderLinearCodeGeneratorMatrix diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 61f75953acc..65e902b773e 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -109,7 +109,8 @@ def encode(self, word): 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: word = vector((0, 1, 1, 0)) - sage: C.encode(word) + sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E.encode(word) (1, 1, 0, 0, 1, 1, 0) """ return vector(word) * self.generator_matrix() @@ -135,7 +136,8 @@ def unencode(self, c, nocheck=False, **kwargs): 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 = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) - sage: C.unencode(c) + sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E.unencode(c) (0, 1, 1, 0) """ if nocheck == False: diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 94ae90eb0e2..068b023c006 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -706,6 +706,11 @@ class AbstractLinearCode(module.Module): - ``length``, the length of the code + - ``encoder_default_name``, the name of the encoder that will be used if no encoder name is passed + to an encoder-related method (``generator_matrix``, ``encode``, ``unencode``) + + - ``_registered_encoders``, a set of all encoders available for this class + - numerous methods that will work for any linear code (including families) To implement a linear code, you need to: @@ -719,19 +724,19 @@ 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. - .. 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. + ..NOTE:: + A lot of methods of the abstract class rely on the knowledge of a generator_matrix. + It is thus strongly recommended to set an encoder with a generator matrix implemented + as a default encoder. """ - def __init__(self, base_field, length): + + _registered_encoders = {} + + def __init__(self, base_field, length, encoder_default_name): """ Initializes mandatory parameters for a Linear Code object. @@ -745,13 +750,15 @@ def __init__(self, base_field, length): - ``length`` -- the length of ``self`` + - ``encoder_default_name`` -- the name of the default encoder of ``self`` + EXAMPLES: We first create a new LinearCode subclass:: sage: class CodeExample(sage.coding.linear_code.AbstractLinearCode): ....: def __init__(self, field, length, dimension, generator_matrix): - ....: sage.coding.linear_code.AbstractLinearCode.__init__(self,field, length) + ....: sage.coding.linear_code.AbstractLinearCode.__init__(self,field, length, "GeneratorMatrix") ....: self._dimension = dimension ....: self._generator_matrix = generator_matrix ....: def generator_matrix(self): @@ -795,10 +802,31 @@ def __init__(self, base_field, length): Traceback (most recent call last): ... ValueError: length must be a Python int or a Sage Integer + + If the name of the default encoder is not known by the class, it will raise + an exception:: + + sage: class CodeExample(sage.coding.linear_code.AbstractLinearCode): + ....: def __init__(self, field, length, dimension, generator_matrix): + ....: sage.coding.linear_code.AbstractLinearCode.__init__(self,field, length, "Fail") + ....: self._dimension = dimension + ....: self._generator_matrix = generator_matrix + ....: def generator_matrix(self): + ....: return self._generator_matrix + ....: def _repr_(self): + ....: return "Dummy code of length %d, dimension %d over %s" % (self.length(), self.dimension(), self.base_field()) + + sage: C = CodeExample(GF(17), 10, 5, generator_matrix) + Traceback (most recent call last): + ... + ValueError: You must set a valid encoder as default encoder for this code """ if not isinstance(length, (int, Integer)): raise ValueError("length must be a Python int or a Sage Integer") self._length = Integer(length) + if not encoder_default_name in self._registered_encoders: + raise ValueError("You must set a valid encoder as default encoder for this code") + self._encoder_default_name = encoder_default_name 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 @@ -1650,7 +1678,7 @@ def encode(self, word, name=None, **kwargs): 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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: word = vector((0, 1, 1, 0)) sage: C.encode(word) (1, 1, 0, 0, 1, 1, 0) @@ -1661,7 +1689,7 @@ def encode(self, word, name=None, **kwargs): ['GeneratorMatrix'] sage: word = vector((0, 1, 1, 0)) sage: C.encode(word, 'GeneratorMatrix') - (3, 5, 0, 4, 0, 4, 10, 1, 4, 2) + (1, 1, 0, 0, 1, 1, 0) """ E = self.encoder(name, **kwargs) return E.encode(word) @@ -1685,10 +1713,9 @@ def encoder(self, name=None, **kwargs): 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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: C.encoder() - Generator-matrix based encoder for the Linear code of length 7, dimension 4 over - Finite Field of size 2 + Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 If the name of an encoder which is not known by ``self`` is passed, an exception will be raised:: @@ -1717,7 +1744,7 @@ def encoders_available(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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: C.encoders_available() ['GeneratorMatrix'] """ @@ -1894,8 +1921,28 @@ def __getitem__(self, i): codeword.set_immutable() return codeword - def generator_matrix(self): - return NotImplementedError("This method must be set in subclasses") + def generator_matrix(self, name=None, **kwargs): + r""" + Returns a generator matrix of ``self``. + + INPUT: + + - ``name`` -- (default: ``None``) name of the encoder which will be + used to compute the generator matrix. The default encoder of ``self`` + will be used if default value is kept. + + 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] + """ + E = self.encoder(name, **kwargs) + return E.generator_matrix() + + gen_mat = deprecated_function_alias(17973, generator_matrix) def generator_matrix_systematic(self): """ @@ -3126,7 +3173,7 @@ def unencode(self, c, name=None, nocheck=False, **kwargs): 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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: C.unencode(c) (0, 1, 1, 0) @@ -3408,8 +3455,6 @@ class LinearCode(AbstractLinearCode): # sage: C.minimum_distance_why() # optional (net connection) # Ub(7,4) = 3 follows by the Griesmer bound. - _registered_encoders = {} - def __init__(self, generator_matrix, d=None): r""" See the docstring for :meth:`LinearCode`. @@ -3471,11 +3516,10 @@ def __init__(self, generator_matrix, d=None): if generator_matrix.nrows() == 0: raise ValueError("this linear code contains no non-zero vector") - super(LinearCode, self).__init__(base_ring, generator_matrix.ncols()) + super(LinearCode, self).__init__(base_ring, generator_matrix.ncols(), "GeneratorMatrix") self._generator_matrix = generator_matrix self._dimension = generator_matrix.rank() self._minimum_distance = d - self._encoder_default_name = "GeneratorMatrix" def _repr_(self): r""" @@ -3490,19 +3534,3 @@ 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) diff --git a/src/sage/coding/linear_code_encoders.py b/src/sage/coding/linear_code_encoders.py index 245a64eefc1..720923c0307 100644 --- a/src/sage/coding/linear_code_encoders.py +++ b/src/sage/coding/linear_code_encoders.py @@ -32,10 +32,10 @@ def __init__(self, code): 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 = codes.LinearCode(G) - sage: C.encoder() - Generator-matrix based encoder for the Linear code of length 7, dimension 4 over - Finite Field of size 2 + sage: C = LinearCode(G) + sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E + Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 """ super(EncoderLinearCodeGeneratorMatrix, self).__init__(code) @@ -46,10 +46,10 @@ def _repr_(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 = codes.LinearCode(G) - sage: C.encoder() - Generator-matrix based encoder for the Linear code of length 7, dimension 4 over - Finite Field of size 2 + sage: C = LinearCode(G) + sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E + Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 """ return "Generator matrix-based encoder for the %s" % self.code() @@ -60,13 +60,12 @@ def _latex_(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 = codes.LinearCode(G) - sage: E = C.encoder() + sage: C = LinearCode(G) + sage: E = EncoderLinearCodeGeneratorMatrix(C) sage: latex(E) - \textnormal{Generator-matrix based encoder for the Linear code of length 7, dimension 4 over - Finite Field of size 2} + \textnormal{Generator matrix-based encoder for the }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2} """ - return "\\textnormal{Generator matrix-based encoder for the %s}" % self.code()._latex_() + return "\\textnormal{Generator matrix-based encoder for the }%s" % self.code()._latex_() @cached_method def generator_matrix(self): @@ -76,7 +75,7 @@ def generator_matrix(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 = codes.LinearCode(G) + sage: C = LinearCode(G) sage: E = EncoderLinearCodeGeneratorMatrix(C) sage: E.generator_matrix() [1 1 1 0 0 0 0] From c6418c98de1a931c1736e31594330e38135780d1 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 28 Apr 2015 13:47:05 +0200 Subject: [PATCH 0181/1872] Changes to the documentation --- src/sage/coding/encoder.py | 9 ++++----- src/sage/coding/linear_code.py | 11 +++++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 65e902b773e..ee5b24f23b2 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -1,8 +1,7 @@ r""" Encoder -Given a code, an encoder embeds some specific methods to link this code's -message space to this code's ambient space. +Representation of a bijection between a message space and a code. """ #***************************************************************************** @@ -24,7 +23,6 @@ class Encoder(SageObject): r""" Abstract top-class for Encoder objects. - This class contains all methods that can be used by encoders. So, every encoder class should inherit from this abstract class. @@ -32,7 +30,7 @@ class Encoder(SageObject): - ``code``, the associated code of the encoder - - methods that will work for any encoder + - some methods for encoder objects To implement an encoder, you need to: @@ -48,7 +46,8 @@ class Encoder(SageObject): ``unencode_nocheck`` methods are provided. These implementations rely on ``generator_matrix`` which you need to override to use the default implementations. - If the message space is not a vectorial space, you cannot have a generator matrix. + If the message space is not of the form `F ** k`, where `F` is a finite field, + you cannot have a generator matrix. In that case, you need to override ``encode`` and ``unencode_nocheck``. As Encoder is not designed to be implemented, it does not have any representation diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 068b023c006..0873d9c50e2 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -709,7 +709,7 @@ class AbstractLinearCode(module.Module): - ``encoder_default_name``, the name of the encoder that will be used if no encoder name is passed to an encoder-related method (``generator_matrix``, ``encode``, ``unencode``) - - ``_registered_encoders``, a set of all encoders available for this class + - ``_registered_encoders``, a dictionary of all encoders available for this class - numerous methods that will work for any linear code (including families) @@ -724,8 +724,15 @@ 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. + - fill the dictionary of its encoders in ``sage.coding.__init__`` file. Example: + I want to link the encoder ``MyEncoderClass`` to ``MyNewCodeClass`` + under the name ``MyEncoderName``. + All I need to do is to write this line in the ``__init__.py`` file: + ``MyNewCodeClass._registered_encoders["NameOfMyEncoder"] = MyEncoderClass`` and all instances of + ``MyNewCodeClass`` will be able to use instances of ``MyEncoderClass``. + 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. + methods. You should implement ``_repr_`` and ``_latex_`` methods in the subclass. ..NOTE:: From 1a0a5a48f682ddc2867ad2f1ccbd9bb3b9f505bf Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 29 Apr 2015 12:52:22 +0200 Subject: [PATCH 0182/1872] Add new method for adding encoders to the list of available encoders on the fly. Changed encoders_available method --- src/sage/coding/linear_code.py | 92 +++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 0873d9c50e2..c1597271fc1 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -216,6 +216,7 @@ import sage.modules.free_module as fm import sage.modules.module as module from sage.categories.modules import Modules +from copy import copy from sage.interfaces.all import gap from sage.rings.finite_rings.constructor import FiniteField as GF from sage.groups.perm_gps.permgroup import PermutationGroup @@ -707,7 +708,7 @@ class AbstractLinearCode(module.Module): - ``length``, the length of the code - ``encoder_default_name``, the name of the encoder that will be used if no encoder name is passed - to an encoder-related method (``generator_matrix``, ``encode``, ``unencode``) + to an encoder-related method (``generator_matrix``, ``encode``, ``unencode``) - ``_registered_encoders``, a dictionary of all encoders available for this class @@ -734,9 +735,9 @@ 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 subclass. - ..NOTE:: + .. NOTE:: - A lot of methods of the abstract class rely on the knowledge of a generator_matrix. + A lot of methods of the abstract class rely on the knowledge of a generator matrix. It is thus strongly recommended to set an encoder with a generator matrix implemented as a default encoder. """ @@ -828,6 +829,7 @@ def __init__(self, base_field, length, encoder_default_name): ... ValueError: You must set a valid encoder as default encoder for this code """ + self._registered_encoders = copy(self._registered_encoders) if not isinstance(length, (int, Integer)): raise ValueError("length must be a Python int or a Sage Integer") self._length = Integer(length) @@ -871,6 +873,72 @@ def _an_element_(self): """ return self.gens()[0] + def add_encoder(self, name, encoder, check=True): + r""" + Adds an encoder to the list of registered encoders of ``self``. + + INPUT: + + - ``name`` -- the string name for the encoder + + - ``encoder`` -- the class name of the encoder + + - ``check`` -- (default: ``True``) if true, checks if ``name`` or ``encoder`` + are already in the list of registered encoders, and raises an error if yes + + EXAMPLES: + + First of all, we create a (very basic) new encoder:: + + sage: class MyEncoder(sage.coding.encoder.Encoder): + ....: def __init__(self, code): + ....: super(MyEncoder, self).__init__(code) + ....: def _repr_(self): + ....: return "MyEncoder encoder with associated code %s" % self.code() + + We now create a new code:: + + sage: C = codes.HammingCode(3, GF(2)) + + We can add our new encoder to the list of available encoders of C:: + + sage: C.add_encoder("MyEncoder", MyEncoder) + sage: C.encoders_available() + ['MyEncoder', 'GeneratorMatrix'] + + We can verify that any new code will not know MyEncoder:: + + sage: C2 = codes.HammingCode(3, GF(3)) + sage: C2.encoders_available() + ['GeneratorMatrix'] + + TESTS: + + If ``check`` is True, it is impossible to use a name which is in + the dictionnary of available encoders:: + + sage: C.add_encoder("GeneratorMatrix", MyEncoder) + Traceback (most recent call last): + ... + ValueError: There is already a registered encoder with this name + + But if ``check`` is set to false, overriding names is authorized:: + + sage: C.encoders_available(True) + [('MyEncoder', ), + ('GeneratorMatrix', + )] + sage: C.add_encoder("GeneratorMatrix", MyEncoder, False) + sage: C.encoders_available(True) + [('MyEncoder', ), + ('GeneratorMatrix', )] + """ + reg_enc = self._registered_encoders + if check==True: + if(name in reg_enc.keys()): + raise ValueError("There is already a registered encoder with this name") + reg_enc[name] = encoder + def automorphism_group_gens(self, equivalence="semilinear"): r""" Return generators of the automorphism group of ``self``. @@ -1744,9 +1812,14 @@ def encoder(self, name=None, **kwargs): else: raise ValueError("Passed Encoder name not known") - def encoders_available(self): + def encoders_available(self, values=False): r""" - Returns a list of the possible encoders for ``self``. + Returns a list of the available encoders' names for ``self``. + + INPUT: + + - ``values`` -- (default: ``False``) if values is set to ``True``, it also + returns the encoders' classes associated with the encoders' names EXAMPLES:: @@ -1754,8 +1827,15 @@ def encoders_available(self): sage: C = LinearCode(G) sage: C.encoders_available() ['GeneratorMatrix'] + + sage: C.encoders_available(True) + [('GeneratorMatrix', + )] """ - return self._registered_encoders.keys() + reg_enc = self._registered_encoders + if values == True: + return reg_enc.items() + return reg_enc.keys() def extended_code(self): r""" From d3cc5586e9039da92f1e87bf6a56a5dfae50386a Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Wed, 29 Apr 2015 22:14:18 +0200 Subject: [PATCH 0183/1872] #18338 bell_polynomial(n,k) should always return a polynomial. --- src/sage/combinat/combinat.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index f118cfe68fb..0c843d7511d 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -2702,6 +2702,22 @@ def bell_polynomial(n, k): sage: bell_polynomial(6,3) 15*x_2^3 + 60*x_1*x_2*x_3 + 15*x_1^2*x_4 + TESTS: + + Check that :trac:`18338` is fixed:: + + sage: bell_polynomial(0,0).parent() + Univariate Polynomial Ring in x_1 over Rational Field + + sage: for n in (0..4): + ....: print [bell_polynomial(n,k).coefficients() for k in (0..n)] + [[1]] + [[], [1]] + [[], [1], [1]] + [[], [1], [3], [1]] + [[], [1], [3, 4], [6], [1]] + + REFERENCES: - E.T. Bell, "Partition Polynomials" @@ -2709,24 +2725,23 @@ def bell_polynomial(n, k): AUTHORS: - Blair Sutton (2009-01-26) + - Thierry Monteil (2015-09-29): the result must always be a polynomial. """ from sage.combinat.partition import Partitions from sage.rings.arith import factorial - vars = ZZ[tuple(['x_'+str(i) for i in range(1, n-k+2)])].gens() - result = 0 + R = QQ[tuple(['x_'+str(i) for i in range(1, n-k+2)])] + vars = R.gens() + result = R.zero() for p in Partitions(n, length=k): - factorial_product = 1 + factorial_product = 1 power_factorial_product = 1 for part, count in p.to_exp_dict().iteritems(): factorial_product *= factorial(count) power_factorial_product *= factorial(part)**count - coefficient = factorial(n) / (factorial_product * power_factorial_product) result += coefficient * prod([vars[i - 1] for i in p]) - return result - def fibonacci_sequence(start, stop=None, algorithm=None): r""" Return an iterator over the Fibonacci sequence, for all fibonacci From 764667e818ac2d0a4b188bf1d8bb09ec4a2acd97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 30 Apr 2015 12:31:24 +0300 Subject: [PATCH 0184/1872] Corrected coding conventions --- .../combinat/root_system/coxeter_matrix.py | 152 +++++++++--------- src/sage/combinat/root_system/coxeter_type.py | 5 +- 2 files changed, 78 insertions(+), 79 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 2a18a8ee127..57e8d170a95 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -35,6 +35,7 @@ from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family + class CoxeterMatrix(CoxeterType): """ A Coxeter matrix. @@ -95,7 +96,7 @@ class CoxeterMatrix(CoxeterType): [ 1 3 -1] [ 3 1 4] [-1 4 1] - + It is possible to give a number `\leq -1` to represent an infinite label sage: CoxeterMatrix([[1,-1],[-1,1]]) @@ -149,9 +150,9 @@ def __classcall_private__(cls, *args, **kwds): """ # Special cases with 0 args if not args: - if "coxeter_type" in kwds: # kwds has Coxeter type + if "coxeter_type" in kwds: # kwds has Coxeter type args = ( CoxeterType(kwds["coxeter_type"]), ) - elif "cartan_type" in kwds: # kwds has Cartan type + elif "cartan_type" in kwds: # kwds has Cartan type args = ( CoxeterType(CartanType(kwds["cartan_type"])), ) base_ring = ZZ @@ -163,7 +164,7 @@ def __classcall_private__(cls, *args, **kwds): subdivisions = None base_ring = ZZ - elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling + elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling return typecall(cls, args[0], args[1], args[2], args[3]) elif isinstance(args[0], CoxeterMatrix): return args[0] @@ -196,7 +197,7 @@ def __classcall_private__(cls, *args, **kwds): m = e[2] if m is None: m = 3 - elif m == infinity: + elif m == infinity: m = -1 elif m not in ZZ and m > -1: raise ValueError("invalid Coxeter graph label") @@ -219,7 +220,7 @@ def __classcall_private__(cls, *args, **kwds): n = len(index_set) reverse = {index_set[i]: i for i in range(n)} data = [[1 if i == j else 2 for j in range(n)] for i in range(n)] - for (i,j,l) in coxeter_type.coxeter_graph().edge_iterator(): + for (i, j, l) in coxeter_type.coxeter_graph().edge_iterator(): if l == infinity: l = -1 data[reverse[i]][reverse[j]] = l @@ -270,12 +271,12 @@ def __init__(self, parent, data, coxeter_type, index_set): sage: C = CoxeterMatrix(['A', 2, 1]) sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) """ - - self._matrix = Matrix_generic_dense(parent,data,False,True) + + self._matrix = Matrix_generic_dense(parent, data, False, True) self._matrix.set_immutable() # Matrix_generic_dense.__init__(self, parent, data, False, True) - if self._matrix.base_ring() not in [ZZ,QQ]: + if self._matrix.base_ring() not in [ZZ, QQ]: self._is_cyclotomic = False else: self._is_cyclotomic = True @@ -283,7 +284,7 @@ def __init__(self, parent, data, coxeter_type, index_set): self._index_set = index_set self.rank = self._matrix.nrows() - self._dict = {(self._index_set[i],self._index_set[j]):self._matrix[i,j] + self._dict = {(self._index_set[i], self._index_set[j]): self._matrix[i, j] for i in range(self.rank) for j in range(self.rank)} def __reduce__(self): @@ -316,7 +317,7 @@ def _matrix_(self, R = None): Return ``self`` as a matrix over the ring ``R``. """ - if R != None: + if R is not None: return self._matrix.change_ring(R) else: return self._matrix @@ -501,7 +502,7 @@ def is_affine(self): ... NotImplementedError """ - if self._coxeter_type is not None: + if self._coxeter_type is not None: return self._coxeter_type.is_affine() else: return False @@ -563,9 +564,9 @@ def find_coxeter_type_from_matrix(coxeter_matrix): sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 4] - + Some affine graphs:: - + sage: CoxeterMatrix(CoxeterType(['A',3,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 3, 1] sage: CoxeterMatrix(CoxeterType(['B',3,1]).coxeter_graph()).coxeter_type() @@ -594,11 +595,11 @@ def find_coxeter_type_from_matrix(coxeter_matrix): """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) - G = Graph([range(n), lambda i,j: coxeter_matrix[i, j] not in [1,2]]) + G = Graph([range(n), lambda i, j: coxeter_matrix[i, j] not in [1, 2]]) # Coxeter graphs of finite Coxeter groups are forests # Coxeter graphs of affine Coxeter groups are forests possibly with cycle # graphs - + comps = G.connected_components() # The group is finite if and only if for every connected # component ``comp`` of its Coxeter graph, the submatrix of @@ -611,11 +612,11 @@ def find_coxeter_type_from_matrix(coxeter_matrix): G0 = G.subgraph(comp) if l == 1: # Any `1 \times 1` Coxeter matrix gives a finite group. - types.append(['A',1]) + types.append(['A', 1]) continue # A1 elif l == 2: # A finite dihedral group iff there is no `\infty` in its - # Coxeter matrix. Otherwise it is affine iff the + # Coxeter matrix. Otherwise it is affine iff the # off-diagonal value is -1. c0, c1 = comp if coxeter_matrix[c0, c1] > 0: @@ -625,7 +626,7 @@ def find_coxeter_type_from_matrix(coxeter_matrix): types.append(['A', 1, 1]) continue else: - return None #TODO: return hyperbolic type once implemented + return None # TODO: return hyperbolic type once implemented elif l == 3: # The `3`-node case. The finite groups to check for # here are `A_3`, `B_3` and `H_3`. @@ -635,29 +636,29 @@ def find_coxeter_type_from_matrix(coxeter_matrix): s = sorted([coxeter_matrix[c0, c1], coxeter_matrix[c0, c2], coxeter_matrix[c1, c2]]) - if s[0] == 2: #Have a tree + if s[0] == 2: # Have a tree if s[1] == 3: if s[2] == 3: - types.append(['A',3]) + types.append(['A', 3]) continue elif s[2] == 4: - types.append(['B',3]) + types.append(['B', 3]) continue elif s[2] == 5: - types.append(['H',3]) + types.append(['H', 3]) continue elif s[2] == 6: - types.append(['G',2,1]) + types.append(['G', 2, 1]) continue else: return None elif s[1] == 4 and s[2] == 4: - types.append(['B',2,1]) + types.append(['B', 2, 1]) continue else: return None elif s[0] == 3 and s[1] == 3 and s[2] == 3: - types.append(['A',2,1]) + types.append(['A', 2, 1]) continue else: return None @@ -682,21 +683,21 @@ def find_coxeter_type_from_matrix(coxeter_matrix): if s[:3] == [2, 2, 2]: if s[3:] == [3, 3, 3]: if max(G0.degree()) == 2: - types.append(['A',4]) + types.append(['A', 4]) continue else: - types.append(['D',4]) + types.append(['D', 4]) continue elif s[3:] == [3, 3, 4] or s[3:] == [3, 3, 5] or s[3:] == [3, - 4, 4]: + 4, 4]: if max(G0.degree()) == 3: if s[4:] == [3, 4]: types.append(['B', 3, 1]) continue else: return None - else: # The graph is a path - # Differenciate using sum of edge labels + else: # The graph is a path + # Differenciate using sum of edge labels u0 = u[0] + u[1] + u[2] u1 = u[0] + u[3] + u[4] u2 = u[1] + u[3] + u[5] @@ -704,18 +705,18 @@ def find_coxeter_type_from_matrix(coxeter_matrix): ss = sorted([u0, u1, u2, u3]) if s[5] == 4: if ss == [7, 7, 9, 9]: - types.append(['F',4]) + types.append(['F', 4]) continue elif ss == [7, 8, 8, 9]: - types.append(['B',4]) + types.append(['B', 4]) continue elif ss == [8, 8, 9, 9]: - types.append(['C',3,1]) + types.append(['C', 3, 1]) continue else: return None elif ss == [7, 8, 9, 10]: - types.append(['H',4]) + types.append(['H', 4]) continue else: return None @@ -724,7 +725,7 @@ def find_coxeter_type_from_matrix(coxeter_matrix): return None elif s == [2, 2, 3, 3, 3, 3] and max(G0.degree()) == 2: - types.append(['A',3,1]) + types.append(['A', 3, 1]) continue else: return None @@ -739,66 +740,64 @@ def find_coxeter_type_from_matrix(coxeter_matrix): # or `F_{4,1}`. degrees = G0.degree() - vertices= G0.vertices() - sub_cox_matrix = coxeter_matrix.matrix_from_rows_and_columns(vertices,vertices) + vertices = G0.vertices() + sub_cox_matrix = coxeter_matrix.matrix_from_rows_and_columns(vertices, vertices) vertices_labels = [set(filter(lambda x: x != 1, r)) for r in sub_cox_matrix.rows()] label_list = filter(lambda x: x != 1, sub_cox_matrix.list()) labels = sorted(set(label_list)) - + vertices_4 = [index for index in range(l) if 4 in vertices_labels[index]] - occur_4 = label_list.count(4)/2 # Each label appear twice + occur_4 = label_list.count(4)/2 # Each label appear twice if not G0.is_tree(): - if G0.is_isomorphic(CycleGraph(l)): # Type `A_{l-1,1}` - types.append(['A',l-1,1]) + if G0.is_isomorphic(CycleGraph(l)): # Type `A_{l-1,1}` + types.append(['A', l-1, 1]) continue else: return None - - elif max(degrees) == 2: # The component is a path - - - if labels[-1] == 3: # Highest label is 3 - types.append(['A',l]) + + elif max(degrees) == 2: # The component is a path + + if labels[-1] == 3: # Highest label is 3 + types.append(['A', l]) continue - elif labels[-1] == 4: # Highest label is 4 - - if occur_4 == 1: # There is 1 edge with label 4 + elif labels[-1] == 4: # Highest label is 4 + + if occur_4 == 1: # There is 1 edge with label 4 if not (3 in vertices_labels[vertices_4[0]] and 3 in - vertices_labels[vertices_4[1]]): # The edge is at the end of the path - types.append(['B',l]) + vertices_labels[vertices_4[1]]): # The edge is at the end of the path + types.append(['B', l]) continue elif l == 5: - types.append(['F',4,1]) + types.append(['F', 4, 1]) continue else: return None - elif occur_4 == 2: # There are 2 edges labeled 4 + elif occur_4 == 2: # There are 2 edges labeled 4 if len(filter(lambda x: 2 in x and 3 not in x and 4 in x, [vertices_labels[i] for i in vertices_4])) == 2: # The edges with 4 are at the ends of the path - types.append(['C',l-1,1]) + types.append(['C', l-1, 1]) continue else: return None else: return None - - else: # The graph contains branching vertices + else: # The graph contains branching vertices #Finite D_n,E_6,E_7,E_8 #Affine B_n,D_n, E_6,E_7,E_8 - if max(degrees) == 3: # Branching degree is 3 + if max(degrees) == 3: # Branching degree is 3 highest_label = labels[-1] nb_branching = degrees.count(3) ecc = sorted(G0.eccentricity()) - + if nb_branching == 1: if highest_label == 3: @@ -807,26 +806,26 @@ def find_coxeter_type_from_matrix(coxeter_matrix): types.append(['D', l]) continue # Dl elif l <= 9 and ecc[-2] == l - 2 and ecc[-5] == l - 3: - if l <= 8: #E_{6,7,8} + if l <= 8: # E_{6,7,8} types.append(['E', l]) continue - else: #E_{8,1} - types.append(['E',l-1,1]) + else: # E_{8,1} + types.append(['E', l-1, 1]) continue elif l <= 8 and ecc[0] == l-5 and ecc[-3] == l-3: - #TO TEST - types.append(['E',l-1,1]) + # TO TEST + types.append(['E', l-1, 1]) continue else: return None elif highest_label == 4: - if ecc[-3] == l - 2 and occur_4 == 1: # D_n graph + if ecc[-3] == l - 2 and occur_4 == 1: # D_n graph # and 1 occurence of label 4 if not (3 in vertices_labels[vertices_4[0]] and 3 in vertices_labels[vertices_4[1]]) and 3 not in G0.degree(vertices=vertices_4): # Edge with label 4 is at the end and not # on a degree 3 vertex. - types.append(['B',l-1,1]) + types.append(['B', l-1, 1]) continue else: return None @@ -834,18 +833,18 @@ def find_coxeter_type_from_matrix(coxeter_matrix): elif nb_branching == 2: if highest_label == 3: if ecc[-4] == l - 3: - types.append(['D',l-1,1]) + types.append(['D', l-1, 1]) continue else: return None - else: # Highest label too high + else: # Highest label too high return None - else: # Nb of branching too high + else: # Nb of branching too high return None - else: # Branching degree too high + else: # Branching degree too high return None @@ -913,7 +912,7 @@ def find_coxeter_type_from_matrix(coxeter_matrix): def check_coxeter_matrix(m): """ - Check if ``m`` represents a generalized Coxeter matrix and raise + Check if ``m`` represents a generalized Coxeter matrix and raise and error if not. EXAMPLES:: @@ -941,12 +940,12 @@ def check_coxeter_matrix(m): ValueError: the matrix is not symmetric """ - - mat=matrix(m) + + mat = matrix(m) if not mat.is_square(): raise ValueError("not a square matrix") for i, row in enumerate(m): - if mat[i,i] != 1: + if mat[i, i] != 1: raise ValueError("the matrix diagonal is not all 1") for j, val in enumerate(row[i+1:]): if val != m[j+i+1][i]: @@ -980,7 +979,7 @@ def coxeter_matrix_as_function(t): m = t.coxeter_matrix() index_set = t.index_set() reverse = dict((index_set[i], i) for i in range(len(index_set))) - return lambda i,j: m[reverse[i], reverse[j]] + return lambda i, j: m[reverse[i], reverse[j]] def coxeter_matrix(t): """ @@ -999,4 +998,3 @@ def coxeter_matrix(t): from sage.misc.superseded import deprecation deprecation(17798, 'coxeter_matrix() is deprecated. Use CoxeterMatrix() instead') return CoxeterMatrix(t) - diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 37b758b2d9c..5595a19be82 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -27,6 +27,7 @@ from sage.structure.sage_object import SageObject from sage.combinat.root_system.cartan_type import CartanType + class CoxeterType(object): """ Abstract class for Coxeter types. @@ -234,7 +235,7 @@ def bilinear_form(self, R=None): [-1 1 -1] [-1 -1 1] """ - + n = self.rank() mat = self.coxeter_matrix() base_ring = sum(mat.list()).parent() @@ -262,6 +263,7 @@ def bilinear_form(self, R=None): bilinear.set_immutable() return bilinear + class CoxeterTypeFromCartanType(SageObject, CoxeterType, UniqueRepresentation): """ A Coxeter type associated to a Cartan type. @@ -425,4 +427,3 @@ def is_simply_laced(self): False """ return self._cartan_type.is_simply_laced() - From f830a53d086c76b9cc2d43cd9d9fb9cb3ef663e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 30 Apr 2015 12:44:45 +0300 Subject: [PATCH 0185/1872] Made is_finite and is_affine attributes --- .../combinat/root_system/coxeter_matrix.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 57e8d170a95..49b5b39ffd8 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -281,6 +281,18 @@ def __init__(self, parent, data, coxeter_type, index_set): else: self._is_cyclotomic = True self._coxeter_type = coxeter_type + + if self._coxeter_type is not None: + if self._coxeter_type.is_finite(): + self._is_finite = True + self._is_affine = False + elif self._coxeter_type.is_affine(): + self._is_finite = False + self._is_affine = True + else: + self._is_finite = False + self._is_affine = False + self._index_set = index_set self.rank = self._matrix.nrows() @@ -473,13 +485,7 @@ def is_finite(self): sage: M.is_finite() False """ - if self._coxeter_type is not None: - return self._coxeter_type.is_finite() - # The type checker should catch all finite types, and checking for - # positive definiteness is difficult, so we just assume it is - # not finite if the type checker cannot determine the type. - #return self.bilinear_form().is_positive_definite() - return False + return self._is_finite def is_affine(self): """ @@ -502,14 +508,8 @@ def is_affine(self): ... NotImplementedError """ - if self._coxeter_type is not None: - return self._coxeter_type.is_affine() - else: - return False - # if self.bilinear_form().rank() == self.rank() - 1 and self.bilinear_form().determinant() == 0: - # return True - # else: - # return False + return self._is_affine + ##################################################################### ## Type check functions From 823c8f2ab1e70e518ede0a92b42be32b48e838f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 30 Apr 2015 12:47:45 +0300 Subject: [PATCH 0186/1872] Added the rank as an attribute --- .../combinat/root_system/coxeter_matrix.py | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 49b5b39ffd8..c6866df3d95 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -294,7 +294,7 @@ def __init__(self, parent, data, coxeter_type, index_set): self._is_affine = False self._index_set = index_set - self.rank = self._matrix.nrows() + self._rank = self._matrix.nrows() self._dict = {(self._index_set[i], self._index_set[j]): self._matrix[i, j] for i in range(self.rank) for j in range(self.rank)} @@ -374,19 +374,18 @@ def coxeter_type(self): return self return self._coxeter_type - # It seems that this method should be an attribute - # def rank(self): - # r""" - # Return the rank of ``self``. - # - # EXAMPLES:: - # - # sage: CoxeterMatrix(['C',3]).rank() - # 3 - # sage: CoxeterMatrix(["A2","B2","F4"]).rank() - # 8 - # """ - # return len(self._index_set) + def rank(self): + r""" + Return the rank of ``self``. + + EXAMPLES:: + + sage: CoxeterMatrix(['C',3]).rank() + 3 + sage: CoxeterMatrix(["A2","B2","F4"]).rank() + 8 + """ + return self._rank def coxeter_matrix(self): r""" From a5afb94f1d29337d307e4dde1b42d198d39cdf5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 30 Apr 2015 16:03:56 +0300 Subject: [PATCH 0187/1872] Subdivided the init (from matrix, graph, coxeter type) --- .../combinat/root_system/coxeter_matrix.py | 190 ++++++++++-------- 1 file changed, 107 insertions(+), 83 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index c6866df3d95..57f02b89075 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -148,119 +148,67 @@ def __classcall_private__(cls, *args, **kwds): Real Field with 53 bits of precision """ + # Special cases with 0 args if not args: if "coxeter_type" in kwds: # kwds has Coxeter type args = ( CoxeterType(kwds["coxeter_type"]), ) elif "cartan_type" in kwds: # kwds has Cartan type args = ( CoxeterType(CartanType(kwds["cartan_type"])), ) - base_ring = ZZ - if not args: data = [] n = 0 index_set = tuple() coxeter_type = None - subdivisions = None base_ring = ZZ + mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), data, coxeter_type, index_set) + mat._subdivisions = None + + return mat elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling return typecall(cls, args[0], args[1], args[2], args[3]) - elif isinstance(args[0], CoxeterMatrix): + elif isinstance(args[0], CoxeterMatrix): # Initiate from itself return args[0] - else: - coxeter_type = None - subdivisions = None - index_set = None - base_ring = ZZ + # Get the type check + if kwds.get("coxeter_type_check", True): + coxeter_type_check = True + else: + coxeter_type_check = False + + # Initiate from a graph: + if isinstance(args[0], Graph): + return cls._from_graph(args[0],coxeter_type_check) + # Get the Coxeter type + coxeter_type = None from sage.combinat.root_system.cartan_type import CartanType_abstract if isinstance(args[0], CartanType_abstract): coxeter_type = args[0].coxeter_type() - elif isinstance(args[0], Graph): - G = args[0] - n = G.num_verts() - - # Setup the basis matrix as all 2 except 1 on the diagonal - data = [] - for i in range(n): - data += [[]] - for j in range(n): - if i == j: - data[-1] += [ZZ.one()] - else: - data[-1] += [2] - - verts = sorted(G.vertices()) - for e in G.edges(): - m = e[2] - if m is None: - m = 3 - elif m == infinity: - m = -1 - elif m not in ZZ and m > -1: - raise ValueError("invalid Coxeter graph label") - elif m == 0 or m == 1: - raise ValueError("invalid Coxeter graph label") - i = verts.index(e[0]) - j = verts.index(e[1]) - data[j][i] = data[i][j] = m - base_ring = (base_ring.one()*m).parent() - index_set = tuple(verts) - args = [data] else: try: coxeter_type = CoxeterType(args[0]) except (TypeError, ValueError, NotImplementedError): pass + # Initiate from a Coxeter type if coxeter_type: - index_set = coxeter_type.index_set() - n = len(index_set) - reverse = {index_set[i]: i for i in range(n)} - data = [[1 if i == j else 2 for j in range(n)] for i in range(n)] - for (i, j, l) in coxeter_type.coxeter_graph().edge_iterator(): - if l == infinity: - l = -1 - data[reverse[i]][reverse[j]] = l - data[reverse[j]][reverse[i]] = l - data = [val for row in data for val in row] - else: - M = matrix(args[0]) - check_coxeter_matrix(args[0]) - base_ring = M.base_ring() - n = M.ncols() - if "coxeter_type" in kwds: - coxeter_type = CoxeterType(kwds["coxeter_type"]) - elif n == 1: - coxeter_type = CoxeterType(['A', 1]) - elif kwds.get("coxeter_type_check", True): - coxeter_type = find_coxeter_type_from_matrix(M) - data = M.list() - subdivisions = M._subdivisions - + return cls._from_coxetertype(coxeter_type) + + # Get the index set + n = len(list(args[0])) + index_set = None if kwds.get("index_set", None): index_set = tuple(kwds["index_set"]) - - if len(args) == 1: - if coxeter_type is not None and index_set is None: - index_set = tuple(coxeter_type.index_set()) - elif len(args) == 2: + if len(args) == 2: index_set = tuple(args[1]) - else: + elif len(args) > 2: raise ValueError("too many arguments") - - if index_set is None: - index_set = tuple(range(n)) - - if len(set(index_set)) != n: - raise ValueError("the given index set is not valid") - - mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), data, - coxeter_type, index_set) - mat._subdivisions = subdivisions - return mat + if index_set and len(set(index_set)) != n: + raise ValueError("the given index set is not valid") + + return cls._from_matrix(args[0],coxeter_type,index_set,coxeter_type_check) def __init__(self, parent, data, coxeter_type, index_set): """ @@ -297,7 +245,83 @@ def __init__(self, parent, data, coxeter_type, index_set): self._rank = self._matrix.nrows() self._dict = {(self._index_set[i], self._index_set[j]): self._matrix[i, j] - for i in range(self.rank) for j in range(self.rank)} + for i in range(self.rank()) for j in range(self.rank())} + + @classmethod + def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): + + # Check that the data is valid + check_coxeter_matrix(data) + + M = matrix(data) + base_ring = M.base_ring() + n = M.ncols() + if not coxeter_type: + if n == 1: + coxeter_type = CoxeterType(['A', 1]) + elif coxeter_type_check: + coxeter_type = find_coxeter_type_from_matrix(M) + else: + coxeter_type = None + if not index_set: + index_set = range(n) + + raw_data = M.list() + + mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), raw_data, + coxeter_type, index_set) + mat._subdivisions = M._subdivisions + + return mat + + @classmethod + def _from_graph(cls,graph,coxeter_type_check): + + verts = sorted(graph.vertices()) + index_set = tuple(verts) + n = len(index_set) + + # Setup the basis matrix as all 2 except 1 on the diagonal + data = [] + for i in range(n): + data += [[]] + for j in range(n): + if i == j: + data[-1] += [ZZ.one()] + else: + data[-1] += [2] + + for e in graph.edges(): + label = e[2] + if label is None: + label = 3 + elif label == infinity: + label = -1 + elif label not in ZZ and label > -1: + raise ValueError("invalid Coxeter graph label") + elif label == 0 or label == 1: + raise ValueError("invalid Coxeter graph label") + i = verts.index(e[0]) + j = verts.index(e[1]) + data[j][i] = data[i][j] = label + + return cls._from_matrix(data,None,index_set,coxeter_type_check) + + @classmethod + def _from_coxetertype(cls,coxeter_type): + + index_set = coxeter_type.index_set() + n = len(index_set) + reverse = {index_set[i]: i for i in range(n)} + data = [[1 if i == j else 2 for j in range(n)] for i in range(n)] + for (i, j, l) in coxeter_type.coxeter_graph().edge_iterator(): + if l == infinity: + l = -1 + data[reverse[i]][reverse[j]] = l + data[reverse[j]][reverse[i]] = l + data = [val for row in data for val in row] + + return cls._from_matrix(data,coxeter_type,index_set,False) def __reduce__(self): """ @@ -424,7 +448,7 @@ def coxeter_graph(self): sage: C.coxeter_graph() Graph on 4 vertices """ - n = self.rank + n = self.rank() I = self.index_set() val = lambda x: infinity if x == -1 else x G = Graph([(I[i], I[j], val((self._matrix)[i, j])) From d3526392209128a21ee631666e406dd8fc74f631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 30 Apr 2015 17:02:39 +0300 Subject: [PATCH 0188/1872] Added some tests --- .../combinat/root_system/coxeter_matrix.py | 91 ++++++++++++++++++- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 57f02b89075..fa79df60e7e 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -112,7 +112,8 @@ class CoxeterMatrix(CoxeterType): @staticmethod def __classcall_private__(cls, *args, **kwds): """ - Normalize input so we can get the appropriate ring. + A Coxeter matrix can we created via a graph, a Coxeter type, or + a matrix. .. NOTE:: @@ -249,13 +250,51 @@ def __init__(self, parent, data, coxeter_type, index_set): @classmethod def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): + """ + Initiate the Coxeter matrix from a matrix. + + TESTS:: + + sage: CM = CoxeterMatrix([[1,2],[2,1]]);CM + [1 2] + [2 1] + sage: CM = CoxeterMatrix([[1,-1],[-1,1]]);CM + [ 1 -1] + [-1 1] + sage: CM = CoxeterMatrix([[1,-1.5],[-1.5,1]]);CM + [ 1.00000000000000 -1.50000000000000] + [-1.50000000000000 1.00000000000000] + sage: CM = CoxeterMatrix([[1,-3/2],[-3/2,1]]);CM + [ 1 -3/2] + [-3/2 1] + sage: CM = CoxeterMatrix([[1,-3/2,5],[-3/2,1,-1],[5,-1,1]]);CM + [ 1 -3/2 5] + [-3/2 1 -1] + [ 5 -1 1] + sage: CM = CoxeterMatrix([[1,-3/2,5],[-3/2,1,oo],[5,oo,1]]);CM + [ 1 -3/2 5] + [-3/2 1 -1] + [ 5 -1 1] + """ + # Check that the data is valid check_coxeter_matrix(data) + M = matrix(data) - base_ring = M.base_ring() n = M.ncols() + + # TODO:: remove when oo is possible in matrices. + entries = [] + for r in data: + entries += r + raw_data = map(lambda x: x if x != infinity else -1, entries) + M = matrix(n,n,raw_data) + # until here + + base_ring = M.base_ring() + if not coxeter_type: if n == 1: coxeter_type = CoxeterType(['A', 1]) @@ -276,6 +315,40 @@ def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): @classmethod def _from_graph(cls,graph,coxeter_type_check): + """ + Initiate the Coxeter matrix from a graph. + + TESTS:: + + sage: CoxeterMatrix(CoxeterMatrix(['A',4,1]).coxeter_graph()) + [1 3 2 2 3] + [3 1 3 2 2] + [2 3 1 3 2] + [2 2 3 1 3] + [3 2 2 3 1] + sage: CoxeterMatrix(CoxeterMatrix(['B',4,1]).coxeter_graph()) + [1 2 3 2 2] + [2 1 3 2 2] + [3 3 1 3 2] + [2 2 3 1 4] + [2 2 2 4 1] + sage: CoxeterMatrix(CoxeterMatrix(['F',4]).coxeter_graph()) + [1 3 2 2] + [3 1 4 2] + [2 4 1 3] + [2 2 3 1] + + sage: G=Graph() + sage: G.add_edge([0,1,oo]) + sage: CoxeterMatrix(G) + [ 1 -1] + [-1 1] + sage: H = Graph() + sage: H.add_edge([0,1,-1.5]) + sage: CoxeterMatrix(H) + [ 1.00000000000000 -1.50000000000000] + [-1.50000000000000 1.00000000000000] + """ verts = sorted(graph.vertices()) index_set = tuple(verts) @@ -309,7 +382,18 @@ def _from_graph(cls,graph,coxeter_type_check): @classmethod def _from_coxetertype(cls,coxeter_type): + """ + Initiate the Coxeter matrix from a Coxeter type. + + TESTS:: + sage: CoxeterMatrix(['A',4]).coxeter_type() + Coxeter type of ['A', 4] + sage: CoxeterMatrix(['A',4,1]).coxeter_type() + Coxeter type of ['A', 4, 1] + sage: CoxeterMatrix(['D',4,1]).coxeter_type() + Coxeter type of ['D', 4, 1] + """ index_set = coxeter_type.index_set() n = len(index_set) reverse = {index_set[i]: i for i in range(n)} @@ -319,7 +403,6 @@ def _from_coxetertype(cls,coxeter_type): l = -1 data[reverse[i]][reverse[j]] = l data[reverse[j]][reverse[i]] = l - data = [val for row in data for val in row] return cls._from_matrix(data,coxeter_type,index_set,False) @@ -974,7 +1057,7 @@ def check_coxeter_matrix(m): if val != m[j+i+1][i]: raise ValueError("the matrix is not symmetric") if val not in ZZ: - if val > -1 and val in RR: + if val > -1 and val in RR and val != infinity: raise ValueError("invalid Coxeter label {}".format(val)) else: if val == 1 or val == 0: From 25a6f54cbb04c5946a155f2e7e4280727c04ab20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 30 Apr 2015 17:20:57 +0300 Subject: [PATCH 0189/1872] Added some values in the dictionnary of the matrix --- src/sage/combinat/root_system/coxeter_matrix.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index fa79df60e7e..5a0bbd888e4 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -247,6 +247,8 @@ def __init__(self, parent, data, coxeter_type, index_set): self._dict = {(self._index_set[i], self._index_set[j]): self._matrix[i, j] for i in range(self.rank()) for j in range(self.rank())} + for i in range(self.rank()): + self._dict[i] = self._matrix[i] @classmethod def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): From 03b24b442010925104c5e34968fdda16bce32a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 30 Apr 2015 17:49:15 +0300 Subject: [PATCH 0190/1872] Edited the check coxeter type function --- .../combinat/root_system/coxeter_matrix.py | 83 +++---------------- 1 file changed, 12 insertions(+), 71 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 5a0bbd888e4..ac040d2db58 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -223,7 +223,6 @@ def __init__(self, parent, data, coxeter_type, index_set): self._matrix = Matrix_generic_dense(parent, data, False, True) self._matrix.set_immutable() - # Matrix_generic_dense.__init__(self, parent, data, False, True) if self._matrix.base_ring() not in [ZZ, QQ]: self._is_cyclotomic = False @@ -238,6 +237,9 @@ def __init__(self, parent, data, coxeter_type, index_set): elif self._coxeter_type.is_affine(): self._is_finite = False self._is_affine = True + else: + self._is_finite = False + self._is_affine = False else: self._is_finite = False self._is_affine = False @@ -665,26 +667,18 @@ def find_coxeter_type_from_matrix(coxeter_matrix): Coxeter type of ['F', 4] sage: CoxeterMatrix(CoxeterType(['G',2]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2] - sage:CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() - Coxeter type of ['I', 100] sage: CoxeterMatrix(CoxeterType(['H',3]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 3] sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 4] + sage:CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() + Coxeter type of ['I', 100] Some affine graphs:: - sage: CoxeterMatrix(CoxeterType(['A',3,1]).coxeter_graph()).coxeter_type() - Coxeter type of ['A', 3, 1] - sage: CoxeterMatrix(CoxeterType(['B',3,1]).coxeter_graph()).coxeter_type() - Coxeter type of ['B', 3, 1] - sage: CoxeterMatrix(CoxeterType(['C',3,1]).coxeter_graph()).coxeter_type() - Coxeter type of ['C', 3, 1] - sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type() - Coxeter type of ['F', 4, 1] - - + sage: CoxeterMatrix(CoxeterType(['A',1,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['A', 1, 1] sage: CoxeterMatrix(CoxeterType(['A',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10, 1] sage: CoxeterMatrix(CoxeterType(['B',10,1]).coxeter_graph()).coxeter_type() @@ -699,7 +693,10 @@ def find_coxeter_type_from_matrix(coxeter_matrix): Coxeter type of ['E', 7, 1] sage: CoxeterMatrix(CoxeterType(['E',8,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8, 1] - + sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['F', 4, 1] + sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type() + Coxeter type of ['G', 2, 1] """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) @@ -768,7 +765,7 @@ def find_coxeter_type_from_matrix(coxeter_matrix): elif s[0] == 3 and s[1] == 3 and s[2] == 3: types.append(['A', 2, 1]) continue - else: + else: # Have a hyperbolic type of rank 3 return None elif l == 4: # The `4`-node case. The finite groups to check for @@ -955,62 +952,6 @@ def find_coxeter_type_from_matrix(coxeter_matrix): else: # Branching degree too high return None - - # # Checking that the Coxeter matrix of the subgroup - # # corresponding to the vertices ``comp`` has all its - # # off-diagonal entries equal to 2, 3 or at most once 4 - # found_a_4 = False - # for j in range(l): - # for i in range(j): - # coxeter_entry = coxeter_matrix[comp[i], comp[j]] - # if coxeter_entry in [2, 3]: - # continue - # if coxeter_entry == 4 and not found_a_4: - # found_a_4 = True - # continue - # return None - # - # G0 = G.subgraph(comp) - # if found_a_4: - # # The case when a `4` has been found in the - # # Coxeter matrix. This needs only to be checked - # # against `B_l`. We use the observation that - # # the group is `B_l` if and only if the Coxeter - # # graph is an `l`-path (i.e., has diameter - # # `l - 1`) and the `4` corresponds to one of - # # its two outermost edges. - # diameter = G0.diameter() - # if diameter != l - 1: - # return None - # - # ecc = sorted(((u, v) for (v, u) in G0.eccentricity(with_labels=True).items())) - # left_end = ecc[-1][1] - # right_end = ecc[-2][1] - # left_almost_end = G0.neigbors(left_end)[0] - # right_almost_end = G0.neigbors(right_end)[0] - # if (coxeter_matrix[left_end, left_almost_end] == 4 - # or coxeter_matrix[right_end, right_almost_end] == 4): - # types.append(['B', l]) - # continue # Bl - # return None - # - # # Now, all off-diagonal entries of the Coxeter matrix - # # are 2's and 3's. We need to check our group against - # # `A_l`, `D_l` and `E_l`. Knowing that the Coxeter - # # graph is a tree, we can use its vertex - # # eccentricities to check this. - # ecc = sorted(G0.eccentricity()) - # if ecc[-1] == l - 1: - # types.append(['A', l]) - # continue # Al - # if ecc[-3] == l - 2: - # types.append(['D', l]) - # continue # Dl - # if l <= 8 and ecc[-2] == l - 2 and ecc[-5] == l - 3: - # types.append(['E', l]) - # continue # El - # return None - if len(types) == 1: types = types[0] return CoxeterType(types) From 532afda11e1e2c5854b650745358296c04b9b725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 30 Apr 2015 18:22:27 +0300 Subject: [PATCH 0191/1872] Added a samples method to CoxeterType --- src/sage/combinat/root_system/coxeter_type.py | 102 +++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 5595a19be82..89f05112b96 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -3,7 +3,8 @@ """ #***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw , -# +# 2015 Jean-Philippe Labbe , +# # Distributed under the terms of the GNU General Public License (GPL) # # This code is distributed in the hope that it will be useful, @@ -54,6 +55,105 @@ def __classcall_private__(cls, x): raise NotImplementedError("Coxeter types not from Cartan types not yet implemented") + def samples(self, finite=None, affine=None, crystallographic=None): + """ + Return a sample of the available Coxeter types. + + INPUT: + + - ``finite`` -- a boolean or ``None`` (default: ``None``) + + - ``affine`` -- a boolean or ``None`` (default: ``None``) + + - ``crystallographic`` -- a boolean or ``None`` (default: ``None``) + + The sample contains all the exceptional finite and affine + Coxeter types, as well as typical representatives of the + infinite families. + + EXAMPLES:: + + sage: CartanType.samples() + [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], + ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4], + ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], + ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], + ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], + ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] + + The finite, affine and crystallographic options allow + respectively for restricting to (non) finite, (non) affine, + and (non) crystallographic Cartan types:: + + sage: CartanType.samples(finite=True) + [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], + ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4]] + + sage: CartanType.samples(affine=True) + [['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], + ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], + ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], + ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] + + sage: CartanType.samples(crystallographic=True) + [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], + ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], + ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], + ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], + ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], + ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] + + sage: CartanType.samples(crystallographic=False) + [['I', 5], ['H', 3], ['H', 4]] + + .. TODO:: add some reducible Coxeter types (suggestions?) + + TESTS:: + + sage: for ct in CoxeterType.samples(): TestSuite(ct).run() + sage: CartanType.samples(crystalographic=False) + doctest:...: DeprecationWarning: use the option 'crystallographic' instead of 'crystalographic' + See http://trac.sagemath.org/14673 for details. + [['I', 5], ['H', 3], ['H', 4]] + """ + result = self._samples() + if crystallographic is not None: + result = [t for t in result if t.is_crystallographic() == crystallographic ] + if finite is not None: + result = [t for t in result if t.is_finite() == finite] + if affine is not None: + result = [t for t in result if t.is_affine() == affine] + return result + + @cached_method + def _samples(self): + """ + Return a sample of all implemented Coxeter types. + + .. NOTE:: This is intended to be used through :meth:`samples`. + + EXAMPLES:: + + sage: CartanType._samples() + [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], + ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4], + ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], + ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], + ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], + ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] + """ + finite = [CoxeterType(t) for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5], + ['C', 1], ['C', 5], ['D', 4], ['D', 5], + ['E', 6], ['E', 7], ['E', 8], ['F', 4], + ['H', 3], ['H', 4], ['I', 10]]] + + affine = [CoxeterType(t) for t in ['A', 2, 1], ['B', 5, 1], + ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], + ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], + ['G', 2, 1], ['A', 1, 1]] + + return finite + affine + @abstract_method def rank(self): """ From 852fc7b91ce687cfe2e92fb501f9a034170c47cc Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 30 Apr 2015 19:57:37 -0700 Subject: [PATCH 0192/1872] Adding to the catalog and fixing bad mergeing. --- src/sage/algebras/catalog.py | 2 + src/sage/combinat/posets/posets.py | 165 ++++++++++++++++++----------- 2 files changed, 106 insertions(+), 61 deletions(-) diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 88a30534497..4a8cb39e407 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -23,6 +23,7 @@ - :class:`algebras.Incidence ` - :class:`algebras.IwahoriHecke ` +- :class:`algebras.Mobius ` - :class:`algebras.NilCoxeter ` - :func:`algebras.Quaternion @@ -48,5 +49,6 @@ 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') +lazy_import('sage.combinat.posets.mobius_algebra', 'MobiusAlgebra', 'Mobius') del lazy_import # We remove the object from here so it doesn't appear under tab completion diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index f7d9a4d114e..10b47a095b4 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -80,6 +80,7 @@ :meth:`~FinitePoset.is_incomparable_chain_free` | Returns whether the poset is `(m+n)`-free. :meth:`~FinitePoset.is_ranked` | Returns whether this poset is ranked. :meth:`~FinitePoset.is_slender` | Returns whether the poset ``self`` is slender or not. + :meth:`~FinitePoset.kazhdan_lusztig_polynomial` | Return the Kazhdan-Lusztig polynomial `P_{x,y}(q)` of ``self``. :meth:`~FinitePoset.lequal_matrix` | Computes the matrix whose ``(i,j)`` entry is 1 if ``self.linear_extension()[i] < self.linear_extension()[j]`` and 0 otherwise :meth:`~FinitePoset.level_sets` | Returns a list l such that l[i+1] is the set of minimal elements of the poset obtained by removing the elements in l[0], l[1], ..., l[i]. :meth:`~FinitePoset.linear_extension` | Returns a linear extension of this poset. @@ -5337,91 +5338,133 @@ def incidence_algebra(self, R, prefix='I'): @cached_method(key=lambda self,x,y,l: (x,y)) def _kl_poly(self, x=None, y=None, canonical_labels=None): r""" - Return the list of cuts of the poset ``self``. + Cached Kazhdan-Lusztig polynomial of ``self`` for generic `q`. - A cut is a subset `A` of ``self`` such that the set of lower - bounds of the set of upper bounds of `A` is exactly `A`. + .. SEEALSO:: - The cuts are computed here using the maximal independent sets in the - auxiliary graph defined as `P \times [0,1]` with an edge - from `(x, 0)` to `(y, 1)` if - and only if `x \not\geq_P y`. See the end of section 4 in [JRJ94]_. + :meth:`kazhdan_lusztig_polynomial` EXAMPLES:: - sage: P = posets.AntichainPoset(3) - sage: Pc = P.cuts() - sage: [list(c) for c in Pc] - [[0], [0, 1, 2], [], [1], [2]] - sage: Pc[0] - frozenset({0}) + sage: L = posets.SymmetricGroupWeakOrderPoset(4) + sage: L._kl_poly() + 1 + sage: x = '2314' + sage: y = '3421' + sage: L._kl_poly(x, y) + -q + 1 - .. SEEALSO:: + AUTHORS: - :meth:`completion_by_cuts` + - Travis Scrimshaw (27-12-2014) + """ + R = PolynomialRing(ZZ, 'q') + q = R.gen(0) - REFERENCES: + # Handle some special cases + if self.cardinality() == 0: + return q.parent().zero() + if not self.rank(): + return q.parent().one() - .. [JRJ94] Jourdan, Guy-Vincent; Rampon, Jean-Xavier; Jard, Claude - (1994), "Computing on-line the lattice of maximal antichains - of posets", Order 11 (3) p. 197-210, :doi:`10.1007/BF02115811` - """ - from sage.graphs.graph import Graph - from sage.graphs.independent_sets import IndependentSets - auxg = Graph({(u, 0): [(v, 1) for v in self if not self.ge(u, v)] - for u in self}) - auxg.add_vertices([(v, 1) for v in self]) - return [frozenset([xa for xa, xb in c if xb == 0]) - for c in IndependentSets(auxg, maximal=True)] + if canonical_labels is None: + canonical_labels = x is None and y is None + + if x is not None or y is not None: + if x == y: + return q.parent().one() + if x is None: + x = self.minimal_elements()[0] + if y is None: + y = self.maximal_elements()[0] + if not self.le(x, y): + return q.parent().zero() + P = self.subposet(self.interval(x, y)) + return P.kazhdan_lusztig_polynomial(q=q, canonical_labels=canonical_labels) + + min_elt = self.minimal_elements()[0] + if canonical_labels: + sublat = lambda P: self.subposet(P).canonical_label() + else: + sublat = lambda P: self.subposet(P) + poly = -sum(sublat(self.order_ideal([x])).characteristic_polynomial() + * sublat(self.order_filter([x])).kazhdan_lusztig_polynomial() + for x in self if x != min_elt) + tr = floor(self.rank()/2) + 1 + ret = poly.truncate(tr) + return ret(q=q) + + def kazhdan_lusztig_polynomial(self, x=None, y=None, q=None, canonical_labels=None): + r""" + Return the Kazhdan-Lusztig polynomial `P_{x,y}(q)` of ``self``. - def completion_by_cuts(self): - """ - Return the completion by cuts of ``self``. + We follow the definition given in [EPW14]_. Let `G` denote a + graded poset with unique minimal and maximal elements and `\chi_G` + denote the characteristic polynomial of `G`. Let `I_x` and `F^x` + denote the order ideal and filter of `x` respectively. Define the + *Kazhdan-Lusztig polynomial* of `G` as the unique polynomial + `P_G(q)` satisfying the following: - This is a lattice, also called the Dedekind-MacNeille completion. + 1. If `\operatorname{rank} G = 0`, then `P_G(q) = 1`. + 2. If `\operatorname{rank} G > 0`, then `\deg P_G(q) < + \frac{1}{2} \operatorname{rank} G`. + 3. We have - See the :wikipedia:`Dedekind-MacNeille completion`. + .. MATH:: - OUTPUT: + q^{\operatorname{rank} G} P_G(q^{-1}) + = \sum_{x \in G} \chi_{I_x}(q) P_{F^x}(q). - - a finite lattice + We then extend this to `P_{x,y}(q)` by considering the subposet + corresponding to the (closed) interval `[x, y]`. We also + define `P_{\emptyset}(q) = 0` (so if `x \not\leq y`, + then `P_{x,y}(q) = 0`). - EXAMPLES:: + INPUT: - sage: P = posets.PentagonPoset() - sage: P.completion_by_cuts().is_isomorphic(P) - True + - ``q`` -- (default: `q \in \ZZ[q]`) the indeterminate `q` + - ``x`` -- (default: the minimal element) the element `x` + - ``y`` -- (default: the maximal element) the element `y` + - ``canonical_labels`` -- (optional) for subposets, use the + canonical labeling (this can limit recursive calls for posets + with large amounts of symmetry, but producing the labeling + takes time); if not specified, this is ``True`` if ``x`` + and ``y`` are both not specified and ``False`` otherwise - sage: P = posets.AntichainPoset(3) - sage: Q = P.completion_by_cuts() - sage: Q.is_isomorphic(posets.DiamondPoset(5)) - True + EXAMPLES:: - sage: P = posets.SymmetricGroupBruhatOrderPoset(3) - sage: Q = P.completion_by_cuts(); Q - Finite lattice containing 7 elements + sage: L = posets.BooleanLattice(3) + sage: L.kazhdan_lusztig_polynomial() + 1 - .. SEEALSO:: + :: - :meth:`cuts` - """ - from sage.combinat.posets.lattices import LatticePoset - from sage.misc.misc import attrcall - return LatticePoset((self.cuts(), attrcall("issubset"))) + sage: L = posets.SymmetricGroupWeakOrderPoset(4) + sage: L.kazhdan_lusztig_polynomial() + 1 + sage: x = '2314' + sage: y = '3421' + sage: L.kazhdan_lusztig_polynomial(x, y) + -q + 1 + sage: L.kazhdan_lusztig_polynomial(x, y, var('t')) + -t + 1 - def incidence_algebra(self, R, prefix='I'): - r""" - Return the incidence algebra of ``self`` over ``R``. + REFERENCES: - EXAMPLES:: + .. [EPW14] Ben Elias, Nicholas Proudfoot, and Max Wakefield. + *The Kazhdan-Lusztig polynomial of a matroid*. 2014. + :arxiv:`1412.7408`. - sage: P = posets.BooleanLattice(4) - sage: P.incidence_algebra(QQ) - Incidence algebra of Finite lattice containing 16 elements - over Rational Field + AUTHORS: + + - Travis Scrimshaw (27-12-2014) """ - from sage.combinat.posets.incidence_algebras import IncidenceAlgebra - return IncidenceAlgebra(R, self, prefix) + if not self.is_ranked(): + raise ValueError("poset is not ranked") + if q is None: + q = PolynomialRing(ZZ, 'q').gen(0) + poly = self._kl_poly(x, y, canonical_labels) + return poly(q=q) FinitePoset._dual_class = FinitePoset From aeefa26675de05fc06c064a1f340017d87797745 Mon Sep 17 00:00:00 2001 From: elixyre Date: Fri, 1 May 2015 19:01:24 +0200 Subject: [PATCH 0193/1872] new operator --- src/sage/categories/hopf_algebras.py | 56 +++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index eba5add5d9a..d0ecf14bad2 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -8,12 +8,11 @@ # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #****************************************************************************** - from sage.misc.lazy_import import LazyImport from category import Category from category_types import Category_over_base_ring from sage.categories.bialgebras import Bialgebras -from sage.categories.tensor import TensorProductsCategory # tensor +from sage.categories.tensor import TensorProductsCategory, tensor from sage.categories.realizations import RealizationsCategory from sage.misc.cachefunc import cached_method #from sage.misc.lazy_attribute import lazy_attribute @@ -86,6 +85,59 @@ def antipode(self): # This choice should be done consistently with coproduct, ... # return operator.antipode(self) + def adams_operator(self, k): + """ + (I am not sure about the name...) + + Iterate `k` times the coproduct and then the product: + + MATH:: + + \mu^k \circ \Delta^{k} + + where `\Delta^k := (\Delta \otimes Id^{k -1 \otimes}) \circ \Delta^{k-1}` and + `\mu^k := \mu \circ (Id \otimes \mu^{k-1})` with `\mu^1 = \mu`. + + TESTS:: + + sage: h = SymmetricFunctions(QQ).h() + sage: h[5].adams_operator(2) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h[5].plethysm(2*h[1]) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S[4].adams_operator(5) + 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + + """ + if k == 1: return self + + S = self.parent() + term = self.coproduct() + dom = tensor((S,)*2) + cod = tensor((S,)*3) + for _ in range(k-2): + term = dom.module_morphism( + on_basis=lambda t: cod.sum_of_terms(map(lambda (a, c): (a+t[1:], c), S(t[0]).coproduct())), + codomain=cod + )(term) + dom, cod = cod, tensor([S, cod]) + + for i in range(k-1): + dom = tensor((S,)*(k-i)) + cod = tensor((S,)*(k-i-1)) + term = dom.module_morphism( + on_basis=lambda t: cod.sum_of_terms(map(lambda (a, c): ((a,) + t[:-2], c), S(t[-2]) * S(t[-1]))), + codomain=cod + )(term) + + return term + + + + + class ParentMethods: #def __setup__(self): # Check the conventions for _setup_ or __setup__ # if self.implements("antipode"): From a685ad1c5acbb5dc1451e06809ce74955d54d53c Mon Sep 17 00:00:00 2001 From: elixyre Date: Fri, 1 May 2015 19:19:06 +0200 Subject: [PATCH 0194/1872] new operator: iterate coproduct and product k times --- src/sage/categories/hopf_algebras.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index d0ecf14bad2..6552d87419a 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -95,8 +95,8 @@ def adams_operator(self, k): \mu^k \circ \Delta^{k} - where `\Delta^k := (\Delta \otimes Id^{k -1 \otimes}) \circ \Delta^{k-1}` and - `\mu^k := \mu \circ (Id \otimes \mu^{k-1})` with `\mu^1 = \mu`. + where `\Delta^k := (\Delta \otimes Id^{k -1 \otimes}) \circ \Delta^{k-1}` with `\Delta^1 = Id` and + `\mu^k := \mu \circ (Id \otimes \mu^{k-1})` with `\mu^1 = Id`. TESTS:: From fc8726a50725479d84aa9a07f55e28e1f879880a Mon Sep 17 00:00:00 2001 From: elixyre Date: Sat, 2 May 2015 00:49:46 +0200 Subject: [PATCH 0195/1872] ticket 18350: revision following comments --- src/sage/categories/hopf_algebras.py | 29 +++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index 6552d87419a..16d1c74e118 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -87,7 +87,6 @@ def antipode(self): def adams_operator(self, k): """ - (I am not sure about the name...) Iterate `k` times the coproduct and then the product: @@ -95,29 +94,36 @@ def adams_operator(self, k): \mu^k \circ \Delta^{k} - where `\Delta^k := (\Delta \otimes Id^{k -1 \otimes}) \circ \Delta^{k-1}` with `\Delta^1 = Id` and - `\mu^k := \mu \circ (Id \otimes \mu^{k-1})` with `\mu^1 = Id`. + where `\Delta^k := (\Delta \otimes Id^{k -1 \otimes}) \circ \Delta^{k-1}` with `\Delta^1 = \Delta`, + `\Delta^0 = Id` and `\mu^k := \mu \circ (Id \otimes \mu^{k-1})` with `\mu^1 = \mu`, `\mu^0 = \mu`. + + Reference + --------- + + .. [AL] The characteristic polynomial of the Adams operators on graded connected Hopf algebras + Marcelo Aguiar and Aaron Lauve + http://www.math.cornell.edu/~maguiar/adams.pdf TESTS:: sage: h = SymmetricFunctions(QQ).h() - sage: h[5].adams_operator(2) + sage: h[5].adams_operator(1) 2*h[3, 2] + 2*h[4, 1] + 2*h[5] sage: h[5].plethysm(2*h[1]) 2*h[3, 2] + 2*h[4, 1] + 2*h[5] sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S[4].adams_operator(5) + sage: S[4].adams_operator(4) 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] """ - if k == 1: return self + if k == 0: return self S = self.parent() term = self.coproduct() dom = tensor((S,)*2) cod = tensor((S,)*3) - for _ in range(k-2): + for _ in range(k-1): term = dom.module_morphism( on_basis=lambda t: cod.sum_of_terms(map(lambda (a, c): (a+t[1:], c), S(t[0]).coproduct())), codomain=cod @@ -125,13 +131,18 @@ def adams_operator(self, k): dom, cod = cod, tensor([S, cod]) for i in range(k-1): - dom = tensor((S,)*(k-i)) - cod = tensor((S,)*(k-i-1)) + dom = tensor((S,)*(k-i+1)) + cod = tensor((S,)*(k-i)) term = dom.module_morphism( on_basis=lambda t: cod.sum_of_terms(map(lambda (a, c): ((a,) + t[:-2], c), S(t[-2]) * S(t[-1]))), codomain=cod )(term) + term = tensor((S,S)).module_morphism( + on_basis=lambda t: S(t[0]) * S(t[1]), + codomain=S + )(term) + return term From 145a97c362ca5faee034430f2a67ce915283fc7e Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Mon, 4 May 2015 14:13:22 +0000 Subject: [PATCH 0196/1872] #18338 variables start at x0, not x_1 --- src/sage/combinat/combinat.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 0c843d7511d..0dd9bc3df5f 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -2698,16 +2698,16 @@ def bell_polynomial(n, k): EXAMPLES:: sage: bell_polynomial(6,2) - 10*x_3^2 + 15*x_2*x_4 + 6*x_1*x_5 + 10*x2^2 + 15*x1*x3 + 6*x0*x4 sage: bell_polynomial(6,3) - 15*x_2^3 + 60*x_1*x_2*x_3 + 15*x_1^2*x_4 + 15*x1^3 + 60*x0*x1*x2 + 15*x0^2*x3 TESTS: Check that :trac:`18338` is fixed:: sage: bell_polynomial(0,0).parent() - Univariate Polynomial Ring in x_1 over Rational Field + Multivariate Polynomial Ring in x over Rational Field sage: for n in (0..4): ....: print [bell_polynomial(n,k).coefficients() for k in (0..n)] @@ -2727,9 +2727,10 @@ def bell_polynomial(n, k): - Blair Sutton (2009-01-26) - Thierry Monteil (2015-09-29): the result must always be a polynomial. """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.combinat.partition import Partitions from sage.rings.arith import factorial - R = QQ[tuple(['x_'+str(i) for i in range(1, n-k+2)])] + R = PolynomialRing(QQ, 'x', n-k+1) vars = R.gens() result = R.zero() for p in Partitions(n, length=k): From c82673a12d3209ab2351aff25f7d4ac6d5eee761 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 5 May 2015 09:58:36 +0200 Subject: [PATCH 0197/1872] Changes to the documentation --- src/doc/en/reference/coding/index.rst | 1 + src/sage/coding/encoder.py | 14 +++++++------- src/sage/coding/linear_code.py | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/doc/en/reference/coding/index.rst b/src/doc/en/reference/coding/index.rst index 293158d8682..97e862db7ff 100644 --- a/src/doc/en/reference/coding/index.rst +++ b/src/doc/en/reference/coding/index.rst @@ -6,6 +6,7 @@ Coding Theory .. toctree:: :maxdepth: 1 + sage/coding/encoder sage/coding/codes_catalog sage/coding/linear_code sage/coding/code_constructions diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index ee5b24f23b2..4ac1f0de82e 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -37,16 +37,16 @@ class Encoder(SageObject): - inherit from Encoder - call Encoder ``__init__`` method in the subclass constructor. Example: - ``super(SubclassName, self).__init__(code)``. - By doing that, your subclass will have its ``code`` parameter initialized. - You need of course to complete the constructor by adding any additional parameter - needed to describe properly the code defined in the subclass. + ``super(SubclassName, self).__init__(code)``. + By doing that, your subclass will have its ``code`` parameter initialized. + You need of course to complete the constructor by adding any additional parameter + needed to describe properly the code defined in the subclass. Then, if the message space is a vectorial space, default implementation of ``encode`` and ``unencode_nocheck`` methods are provided. These implementations rely on ``generator_matrix`` which you need to override to use the default implementations. - If the message space is not of the form `F ** k`, where `F` is a finite field, + If the message space is not of the form `F^k`, where `F` is a finite field, you cannot have a generator matrix. In that case, you need to override ``encode`` and ``unencode_nocheck``. @@ -89,7 +89,7 @@ def __init__(self, code): def encode(self, word): r""" - Encodes ``word`` as a codeword of ``self``. + Transforms an element of the message space into an element of the code. This is a default implementation which assumes that the message space of the encoder is a Vector Space. If this is not the case, @@ -97,7 +97,7 @@ def encode(self, word): INPUT: - - ``word`` -- a vector of the same length as dimension of ``self`` + - ``word`` -- a vector of the message space of the code OUTPUT: diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index c1597271fc1..a60292d7f46 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1736,11 +1736,11 @@ def __eq__(self, right): def encode(self, word, name=None, **kwargs): r""" - Encodes ``word`` as a codeword of ``self``. + Transforms an element of the message space into an element of the code. INPUT: - - ``word`` -- a vector of the same length as dimension of ``self`` + - ``word`` -- a vector of the message space of the code - ``name`` -- (default: ``None``) Name of the encoder which will be used to encode ``word``. The default encoder of ``self`` will be used if From 9b7ac0bcada31f0b09800dd799c0e88a59b8fe85 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 7 May 2015 13:28:19 +0200 Subject: [PATCH 0198/1872] Default equality check method in Encoder. Changed naming convention for encoders. Removed linear_code_encoders file. Updated documentation --- src/sage/coding/__init__.py | 2 +- src/sage/coding/all.py | 2 +- src/sage/coding/encoder.py | 71 +++++++++++++++--- src/sage/coding/linear_code.py | 95 ++++++++++++++++++++++++- src/sage/coding/linear_code_encoders.py | 89 ----------------------- 5 files changed, 157 insertions(+), 102 deletions(-) delete mode 100644 src/sage/coding/linear_code_encoders.py diff --git a/src/sage/coding/__init__.py b/src/sage/coding/__init__.py index 661b4bbcef4..b2cee969e25 100644 --- a/src/sage/coding/__init__.py +++ b/src/sage/coding/__init__.py @@ -1,2 +1,2 @@ import all -linear_code.AbstractLinearCode._registered_encoders["GeneratorMatrix"] = linear_code_encoders.EncoderLinearCodeGeneratorMatrix +linear_code.AbstractLinearCode._registered_encoders["GeneratorMatrix"] = linear_code.LinearCodeGeneratorMatrixEncoder diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 02f9891ecb4..cada61837a0 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -68,7 +68,7 @@ bounds_minimum_distance, self_orthogonal_binary_codes) -from linear_code_encoders import EncoderLinearCodeGeneratorMatrix +from linear_code import LinearCodeGeneratorMatrixEncoder from sd_codes import self_dual_codes_binary diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 4ac1f0de82e..a1b6419f55b 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -50,6 +50,17 @@ class Encoder(SageObject): you cannot have a generator matrix. In that case, you need to override ``encode`` and ``unencode_nocheck``. + Equality methods (``__eq__`` and ``__ne__``) might be useful for encoding in advanced + codes constructions (like concatenated codes). If provided default implementation of + these methods is not enough for your subclass, you are strongly encouraged to override + them. + + .. NOTE:: + + For consistency on encoders, please follow this convention on names for subclasses: + for a new encoder named ``EncName``, for code family ``CodeFam``, call it + ``CodeFamEncNameEncoder``. + As Encoder is not designed to be implemented, it does not have any representation methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. """ @@ -87,6 +98,46 @@ def __init__(self, code): """ self._code = code + def __eq__(self, other): + r""" + Checks equality between ``self`` and ``other``. + + 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: E1 = LinearCodeGeneratorMatrixEncoder(C) + sage: E2 = LinearCodeGeneratorMatrixEncoder(C) + sage: E1 == E2 + True + sage: G = Matrix(GF(3), [[2,1,1,0,0,0,1],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,1,1,0,0,1]]) + sage: C1 = LinearCode(G) + sage: E2 = LinearCodeGeneratorMatrixEncoder(C1) + sage: E1 == E2 + False + """ + return self.code() == other.code() + + def __ne__(self, other): + r""" + Checks difference between ``self`` and ``other``. + + 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: E1 = LinearCodeGeneratorMatrixEncoder(C) + sage: E2 = LinearCodeGeneratorMatrixEncoder(C) + sage: E1 != E2 + False + sage: G = Matrix(GF(3), [[2,1,1,0,0,0,1],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,1,1,0,0,1]]) + sage: C1 = LinearCode(G) + sage: E2 = LinearCodeGeneratorMatrixEncoder(C1) + sage: E1 != E2 + True + """ + return not self.__eq__(other) + def encode(self, word): r""" Transforms an element of the message space into an element of the code. @@ -108,7 +159,7 @@ def encode(self, word): 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: word = vector((0, 1, 1, 0)) - sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E = LinearCodeGeneratorMatrixEncoder(C) sage: E.encode(word) (1, 1, 0, 0, 1, 1, 0) """ @@ -116,7 +167,7 @@ def encode(self, word): def unencode(self, c, nocheck=False, **kwargs): r""" - Returns ``c`` decoded to the message space of ``self``. + Returns the message corresponding to ``c``. INPUT: @@ -135,7 +186,7 @@ def unencode(self, c, nocheck=False, **kwargs): 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 = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) - sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E = LinearCodeGeneratorMatrixEncoder(C) sage: E.unencode(c) (0, 1, 1, 0) """ @@ -148,11 +199,15 @@ def unencode(self, c, nocheck=False, **kwargs): return self.unencode_nocheck(c, **kwargs) @cached_method - def _unencoder_matrix(self): + def unencoder_matrix(self): r""" - Finds an information set for G, and return the inverse of those + Finds an information set for G, and returns the inverse of those columns of G. + .. NOTE:: + + This is a helper function, for internal use only. + AUTHORS: This function is taken from codinglib (https://bitbucket.org/jsrn/codinglib/) @@ -174,7 +229,7 @@ def _unencoder_matrix(self): def unencode_nocheck(self, c, **kwargs): r""" - Returns the message corresponding to a codeword. + Returns the message corresponding to ``c``. When c is not a codeword, the output is unspecified. @@ -199,7 +254,7 @@ def unencode_nocheck(self, c, **kwargs): sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: c in C True - sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E = LinearCodeGeneratorMatrixEncoder(C) sage: E.unencode_nocheck(c) (0, 1, 1, 0) @@ -208,7 +263,7 @@ def unencode_nocheck(self, c, **kwargs): sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 1)) sage: c in C False - sage: E = EncoderLinearCodeGeneratorMatrix(C) + sage: E = LinearCodeGeneratorMatrixEncoder(C) sage: E.unencode_nocheck(c) (0, 1, 1, 0) sage: m = vector(GF(2), (0, 1, 1, 0)) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index a60292d7f46..b26bdb9abe3 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -927,7 +927,7 @@ def add_encoder(self, name, encoder, check=True): sage: C.encoders_available(True) [('MyEncoder', ), ('GeneratorMatrix', - )] + )] sage: C.add_encoder("GeneratorMatrix", MyEncoder, False) sage: C.encoders_available(True) [('MyEncoder', ), @@ -1774,6 +1774,10 @@ def encoder(self, name=None, **kwargs): r""" Returns an encoder of ``self``. + This methods creates a new instance of the encoder subclass designated by ``name``. + While it is also possible to do the same by directly calling the subclass' constructor, + it is strongly advised to use this method to take advantage of the caching mechanism. + INPUT: - ``name`` -- (default: ``None``) name of the encoder which will be @@ -1830,7 +1834,7 @@ def encoders_available(self, values=False): sage: C.encoders_available(True) [('GeneratorMatrix', - )] + )] """ reg_enc = self._registered_encoders if values == True: @@ -3239,7 +3243,7 @@ def syndrome(self, r): def unencode(self, c, name=None, nocheck=False, **kwargs): r""" - Returns ``c`` decoded to the message space of ``self``. + Returns the message corresponding to ``c``. INPUT: @@ -3621,3 +3625,88 @@ 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()) + +####################### encoders ############################### +from encoder import Encoder + +class LinearCodeGeneratorMatrixEncoder(Encoder): + r""" + Encoder based on generator_matrix for Linear codes. + + The only purpose of this encoder is to set generic linear codes + into the new Encoder structure by providing a valid ``generator_matrix`` + method. + + This encoder uses default implementations of ``encode`` and ``unencode``. + Its ``generator_matrix`` method returns private field ``_generator_matrix`` + of its associated code if any, else it calls the ``generator_matrix`` method + of the default encoder of the associated code. + + According to this behaviour, this encoder should never be used for other codes than + :class:`LinearCode`. + + INPUT: + + - ``code`` -- The associated code of this encoder. + """ + + def __init__(self, code): + r""" + 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: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E + Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 + """ + super(LinearCodeGeneratorMatrixEncoder, self).__init__(code) + + def _repr_(self): + r""" + Returns a string representation 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: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E + Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 + """ + return "Generator matrix-based encoder for the %s" % self.code() + + def _latex_(self): + r""" + Returns a latex representation 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: E = LinearCodeGeneratorMatrixEncoder(C) + sage: latex(E) + \textnormal{Generator matrix-based encoder for the }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2} + """ + return "\\textnormal{Generator matrix-based encoder for the }%s" % self.code()._latex_() + + @cached_method + def generator_matrix(self): + r""" + Returns a generator matrix of the associated code 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: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E.generator_matrix() + [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] + """ + if hasattr(self.code(), "_generator_matrix"): + return self.code()._generator_matrix + else: + return self.code().generator_matrix() diff --git a/src/sage/coding/linear_code_encoders.py b/src/sage/coding/linear_code_encoders.py deleted file mode 100644 index 720923c0307..00000000000 --- a/src/sage/coding/linear_code_encoders.py +++ /dev/null @@ -1,89 +0,0 @@ -r""" -Linear Code Encoders -""" - -#***************************************************************************** -# 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 encoder import Encoder -from sage.misc.cachefunc import cached_method - -class EncoderLinearCodeGeneratorMatrix(Encoder): - r""" - Encoder based on generator_matrix for Linear codes. - - The only purpose of this encoder is to include the existing code - into the new Encoder and Decoder structure. - - INPUT: - - - ``code`` -- The associated code of this encoder. - """ - - def __init__(self, code): - r""" - 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: E = EncoderLinearCodeGeneratorMatrix(C) - sage: E - Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 - """ - super(EncoderLinearCodeGeneratorMatrix, self).__init__(code) - - def _repr_(self): - r""" - Returns a string representation 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: E = EncoderLinearCodeGeneratorMatrix(C) - sage: E - Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 - """ - return "Generator matrix-based encoder for the %s" % self.code() - - def _latex_(self): - r""" - Returns a latex representation 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: E = EncoderLinearCodeGeneratorMatrix(C) - sage: latex(E) - \textnormal{Generator matrix-based encoder for the }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2} - """ - return "\\textnormal{Generator matrix-based encoder for the }%s" % self.code()._latex_() - - @cached_method - def generator_matrix(self): - r""" - Returns a generator matrix of the associated code 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: E = EncoderLinearCodeGeneratorMatrix(C) - sage: E.generator_matrix() - [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] - """ - if hasattr(self.code(), "_generator_matrix"): - return self.code()._generator_matrix - else: - return self.code().generator_matrix() From bad97158f1e6b46821bb311422c2e0f73b06319d Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 7 May 2015 14:47:23 +0200 Subject: [PATCH 0199/1872] Hid encoders under codes.encoders. --- src/doc/en/reference/coding/index.rst | 3 ++- src/sage/coding/codes_catalog.py | 2 ++ src/sage/coding/encoder.py | 24 ++++++++++++------------ src/sage/coding/linear_code.py | 8 ++++---- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/doc/en/reference/coding/index.rst b/src/doc/en/reference/coding/index.rst index 31b91f7dd89..6311e17f696 100644 --- a/src/doc/en/reference/coding/index.rst +++ b/src/doc/en/reference/coding/index.rst @@ -7,8 +7,9 @@ Coding Theory :maxdepth: 1 sage/coding/encoder - sage/coding/channels_catalog + sage/coding/encoders_catalog sage/coding/channel_constructions + sage/coding/channels_catalog sage/coding/codes_catalog sage/coding/linear_code sage/coding/code_constructions diff --git a/src/sage/coding/codes_catalog.py b/src/sage/coding/codes_catalog.py index edbd32e5dac..d90ebe36f04 100644 --- a/src/sage/coding/codes_catalog.py +++ b/src/sage/coding/codes_catalog.py @@ -52,3 +52,5 @@ ToricCode, TrivialCode, WalshCode) from guava import BinaryReedMullerCode, QuasiQuadraticResidueCode, RandomLinearCodeGuava + +import encoders_catalog as encoders diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index a1b6419f55b..1b2be944dbf 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -106,13 +106,13 @@ def __eq__(self, other): 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: E1 = LinearCodeGeneratorMatrixEncoder(C) - sage: E2 = LinearCodeGeneratorMatrixEncoder(C) + sage: E1 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) + sage: E2 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E1 == E2 True sage: G = Matrix(GF(3), [[2,1,1,0,0,0,1],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,1,1,0,0,1]]) sage: C1 = LinearCode(G) - sage: E2 = LinearCodeGeneratorMatrixEncoder(C1) + sage: E2 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C1) sage: E1 == E2 False """ @@ -126,13 +126,13 @@ def __ne__(self, other): 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: E1 = LinearCodeGeneratorMatrixEncoder(C) - sage: E2 = LinearCodeGeneratorMatrixEncoder(C) + sage: E1 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) + sage: E2 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E1 != E2 False sage: G = Matrix(GF(3), [[2,1,1,0,0,0,1],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,1,1,0,0,1]]) sage: C1 = LinearCode(G) - sage: E2 = LinearCodeGeneratorMatrixEncoder(C1) + sage: E2 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C1) sage: E1 != E2 True """ @@ -159,7 +159,7 @@ def encode(self, word): 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: word = vector((0, 1, 1, 0)) - sage: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E.encode(word) (1, 1, 0, 0, 1, 1, 0) """ @@ -186,7 +186,7 @@ def unencode(self, c, nocheck=False, **kwargs): 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 = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) - sage: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E.unencode(c) (0, 1, 1, 0) """ @@ -218,7 +218,7 @@ def unencoder_matrix(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: E = C.encoder() - sage: E._unencoder_matrix() + sage: E.unencoder_matrix() [0 0 1 1] [0 1 0 1] [1 1 1 0] @@ -254,7 +254,7 @@ def unencode_nocheck(self, c, **kwargs): sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) sage: c in C True - sage: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E.unencode_nocheck(c) (0, 1, 1, 0) @@ -263,7 +263,7 @@ def unencode_nocheck(self, c, **kwargs): sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 1)) sage: c in C False - sage: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E.unencode_nocheck(c) (0, 1, 1, 0) sage: m = vector(GF(2), (0, 1, 1, 0)) @@ -271,7 +271,7 @@ def unencode_nocheck(self, c, **kwargs): sage: c == c1 False """ - U = self._unencoder_matrix() + U = self.unencoder_matrix() info_set = self.code().information_set() cc = vector( c[i] for i in info_set ) return cc * U diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index b26bdb9abe3..00e35d784d2 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -3656,7 +3656,7 @@ def __init__(self, code): 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: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 """ @@ -3670,7 +3670,7 @@ def _repr_(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: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 """ @@ -3684,7 +3684,7 @@ def _latex_(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: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: latex(E) \textnormal{Generator matrix-based encoder for the }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2} """ @@ -3699,7 +3699,7 @@ def generator_matrix(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: E = LinearCodeGeneratorMatrixEncoder(C) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E.generator_matrix() [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] From d018e28cab80aa27c4a907b59d83c50db7a74a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 7 May 2015 16:53:45 +0300 Subject: [PATCH 0200/1872] Added samples and made many tests pass --- .../combinat/root_system/coxeter_matrix.py | 248 ++++++++++++++++-- src/sage/combinat/root_system/coxeter_type.py | 100 ++++--- 2 files changed, 294 insertions(+), 54 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index ac040d2db58..bbd33464bb0 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -141,11 +141,11 @@ def __classcall_private__(cls, *args, **kwds): The base ring of the matrix depends on the entries given:: - sage: CoxeterMatrix([[1,-1],[-1,1]]).base_ring() + sage: CoxeterMatrix([[1,-1],[-1,1]])._matrix.base_ring() Integer Ring - sage: CoxeterMatrix([[1,-3/2],[-3/2,1]]).base_ring() + sage: CoxeterMatrix([[1,-3/2],[-3/2,1]])._matrix.base_ring() Rational Field - sage: CoxeterMatrix([[1,-1.5],[-1.5,1]]).base_ring() + sage: CoxeterMatrix([[1,-1.5],[-1.5,1]])._matrix.base_ring() Real Field with 53 bits of precision """ @@ -248,9 +248,11 @@ def __init__(self, parent, data, coxeter_type, index_set): self._rank = self._matrix.nrows() self._dict = {(self._index_set[i], self._index_set[j]): self._matrix[i, j] - for i in range(self.rank()) for j in range(self.rank())} - for i in range(self.rank()): - self._dict[i] = self._matrix[i] + for i in range(self._rank) for j in range(self._rank)} + + for key in self._index_set: + index_key = self._index_set.index(key) + self._dict[key] = {i:self._matrix[index_key,self._index_set.index(i)] for i in self._index_set} @classmethod def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): @@ -281,7 +283,6 @@ def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): [ 5 -1 1] """ - # Check that the data is valid check_coxeter_matrix(data) @@ -292,7 +293,7 @@ def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): # TODO:: remove when oo is possible in matrices. entries = [] for r in data: - entries += r + entries += list(r) raw_data = map(lambda x: x if x != infinity else -1, entries) M = matrix(n,n,raw_data) # until here @@ -303,7 +304,7 @@ def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): if n == 1: coxeter_type = CoxeterType(['A', 1]) elif coxeter_type_check: - coxeter_type = find_coxeter_type_from_matrix(M) + coxeter_type = recognize_coxeter_type_from_matrix(M) else: coxeter_type = None if not index_set: @@ -410,6 +411,198 @@ def _from_coxetertype(cls,coxeter_type): return cls._from_matrix(data,coxeter_type,index_set,False) + @classmethod + def samples(self, finite=None, affine=None, crystallographic=None, + higher_rank=None): + """ + Return a sample of the available Coxeter types. + + INPUT: + + - ``finite`` -- a boolean or ``None`` (default: ``None``) + + - ``affine`` -- a boolean or ``None`` (default: ``None``) + + - ``crystallographic`` -- a boolean or ``None`` (default: ``None``) + + - ``higher_rank`` -- a boolean or ``None`` (default: ``None``) + + The sample contains all the exceptional finite and affine + Coxeter types, as well as typical representatives of the + infinite families. + + EXAMPLES:: + + sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples()] + [Coxeter type of ['A', 1], Coxeter type of ['A', 5], + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + Coxeter type of ['F', 4], Coxeter type of ['H', 3], + Coxeter type of ['H', 4], Coxeter type of ['I', 10], + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], + [ 1 -2] + [-2 1], + [ 1 -1 -1] + [-1 1 -1] + [-1 -1 1], + [1 2 3] + [2 1 7] + [3 7 1], + [ 1 -2 3 2] + [-2 1 2 3] + [ 3 2 1 -8] + [ 2 3 -8 1]] + + The finite, affine and crystallographic options allow + respectively for restricting to (non) finite, (non) affine, + and (non) crystallographic Cartan types:: + + sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples(finite=True)] + [Coxeter type of ['A', 1], Coxeter type of ['A', 5], + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + Coxeter type of ['F', 4], Coxeter type of ['H', 3], + Coxeter type of ['H', 4], Coxeter type of ['I', 10]] + + sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples(affine=True)] + [Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] + + sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples(crystallographic=True)] + [Coxeter type of ['A', 1], Coxeter type of ['A', 5], + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + Coxeter type of ['F', 4], Coxeter type of ['A', 2, 1], + Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], + Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], + Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], + Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1]] + + sage: CoxeterMatrix.samples(crystallographic=False) + [[1 3 2] + [3 1 5] + [2 5 1], [1 3 2 2] + [3 1 3 2] + [2 3 1 5] + [2 2 5 1], [ 1 10] + [10 1], [ 1 -1] + [-1 1], [ 1 -2] + [-2 1], [ 1 -1 -1] + [-1 1 -1] + [-1 -1 1], [1 2 3] + [2 1 7] + [3 7 1], [ 1 -2 3 2] + [-2 1 2 3] + [ 3 2 1 -8] + [ 2 3 -8 1]] + + .. TODO:: add some reducible Coxeter types (suggestions?) + + TESTS:: + + sage: for ct in CoxeterMatrix.samples(): TestSuite(ct).run() + """ + result = self._samples() + if crystallographic is not None: + result = [t for t in result if t.is_crystallographic() == crystallographic ] + if finite is not None: + result = [t for t in result if t.is_finite() == finite] + if affine is not None: + result = [t for t in result if t.is_affine() == affine] + if higher_rank is not None: + result = [t for t in result if not t.is_affine() and not t.is_finite()] + return result + + @cached_method + def _samples(self): + """ + Return a sample of all implemented Coxeter types. + + .. NOTE:: This is intended to be used through :meth:`samples`. + + EXAMPLES:: + + sage: [CM.coxeter_type() for CM in CoxeterMatrix._samples()] + [Coxeter type of ['A', 1], Coxeter type of ['A', 5], + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + Coxeter type of ['F', 4], Coxeter type of ['H', 3], + Coxeter type of ['H', 4], Coxeter type of ['I', 10], + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], + [ 1 -2] + [-2 1], + [ 1 -1 -1] + [-1 1 -1] + [-1 -1 1], + [1 2 3] + [2 1 7] + [3 7 1], + [ 1 -2 3 2] + [-2 1 2 3] + [ 3 2 1 -8] + [ 2 3 -8 1]] + """ + finite = [CoxeterMatrix(t) for t in [['A', 1], ['A', 5], ['B', 5], + ['D', 4], ['D', 5], ['E', 6], ['E', 7], + ['E', 8], ['F', 4], ['H', 3], ['H', 4], + ['I', 10]]] + + affine = [CoxeterMatrix(t) for t in ['A', 2, 1], ['B', 5, 1], + ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], + ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], + ['G', 2, 1], ['A', 1, 1]] + + higher_matrices = [[[1,-2],[-2,1]], + [[1,-1,-1],[-1,1,-1],[-1,-1,1]], [[1,2,3],[2,1,7],[3,7,1]], + [[1,-2,3,2],[-2,1,2,3],[3,2,1,-8],[2,3,-8,1]]] + + higher = [CoxeterMatrix(m) for m in higher_matrices] + + return finite + affine + higher + + def relabel(self, relabelling): + """ + Return a relabelled copy of this Coxeter matrix. + + INPUT: + + - ``relabelling`` -- a function (or a list or dictionary) + + OUTPUT: + + an isomorphic Coxeter type obtained by relabelling the nodes of + the Coxeter graph. Namely, the node with label ``i`` is + relabelled ``f(i)`` (or, by ``f[i]`` if ``f`` is a list or + dictionary). + + EXAMPLES:: + + sage: CoxeterMatrix(['F',4]).relabel({ 1:2, 2:3, 3:4, 4:1}) + [1 4 2 3] + [4 1 3 2] + [2 3 1 2] + [3 2 2 1] + """ + + data = [[self[relabelling[i]][relabelling[j]] for j in self.index_set()] for i in self.index_set()] + + return CoxeterMatrix(data) + def __reduce__(self): """ Used for pickling. @@ -421,7 +614,7 @@ def __reduce__(self): sage: M._index_set (1, 2, 3, 4) """ - return (CoxeterMatrix, (self.parent(), self.list(), + return (CoxeterMatrix, (self._matrix.parent(), self._matrix.list(), self._coxeter_type, self._index_set)) def __repr__(self): @@ -431,10 +624,22 @@ def __repr__(self): return self._matrix.__repr__() + def __iter__(self): + + return self._matrix.__iter__() + def __getitem__(self, key): return self._dict[key] + def __hash__(self): + + return self._matrix.__hash__() + + def __eq__(self,other): + + return self._matrix.__eq__(other._matrix) + def _matrix_(self, R = None): """ Return ``self`` as a matrix over the ring ``R``. @@ -614,9 +819,7 @@ def is_affine(self): False sage: M = CoxeterMatrix([[1, -1, 7], [-1, 1, 3], [7, 3, 1]]) sage: M.is_affine() - Traceback (most recent call last): - ... - NotImplementedError + False """ return self._is_affine @@ -624,7 +827,7 @@ def is_affine(self): ##################################################################### ## Type check functions -def find_coxeter_type_from_matrix(coxeter_matrix): +def recognize_coxeter_type_from_matrix(coxeter_matrix): """ Return the Coxeter type of ``coxeter_matrix`` if known, otherwise return ``None``. @@ -671,10 +874,9 @@ def find_coxeter_type_from_matrix(coxeter_matrix): Coxeter type of ['H', 3] sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 4] - sage:CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() + sage: CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() Coxeter type of ['I', 100] - Some affine graphs:: sage: CoxeterMatrix(CoxeterType(['A',1,1]).coxeter_graph()).coxeter_type() @@ -697,6 +899,18 @@ def find_coxeter_type_from_matrix(coxeter_matrix): Coxeter type of ['F', 4, 1] sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2, 1] + + TESTS:: + + sage: from sage.combinat.root_system.coxeter_matrix import recognize_coxeter_type_from_matrix + sage: for C in CoxeterMatrix.samples(): + ....: relabelling_perm = Permutations(C.index_set()).random_element() + ....: relabelling_dict = {C.index_set()[i]: relabelling_perm[i] for i in range(C.rank())} + ....: relabeled_matrix = C.relabel(relabelling_dict)._matrix + ....: recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix) + ....: if C.is_finite() or C.is_affine(): + ....: assert recognized_type == C.coxeter_type() + """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) @@ -1028,7 +1242,7 @@ def coxeter_matrix_as_function(t): m = t.coxeter_matrix() index_set = t.index_set() reverse = dict((index_set[i], i) for i in range(len(index_set))) - return lambda i, j: m[reverse[i], reverse[j]] + return lambda i, j: m[i,j] # m[reverse[i], reverse[j]] def coxeter_matrix(t): """ diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 89f05112b96..92ddf70fd00 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -26,7 +26,6 @@ from sage.symbolic.ring import SR from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject -from sage.combinat.root_system.cartan_type import CartanType class CoxeterType(object): @@ -55,6 +54,7 @@ def __classcall_private__(cls, x): raise NotImplementedError("Coxeter types not from Cartan types not yet implemented") + @classmethod def samples(self, finite=None, affine=None, crystallographic=None): """ Return a sample of the available Coxeter types. @@ -73,38 +73,57 @@ def samples(self, finite=None, affine=None, crystallographic=None): EXAMPLES:: - sage: CartanType.samples() - [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], - ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4], - ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], - ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], - ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], - ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] + sage: CoxeterType.samples() + [Coxeter type of ['A', 1], Coxeter type of ['A', 5], + Coxeter type of ['B', 1], Coxeter type of ['B', 5], + Coxeter type of ['C', 1], Coxeter type of ['C', 5], + Coxeter type of ['D', 4], Coxeter type of ['D', 5], + Coxeter type of ['E', 6], Coxeter type of ['E', 7], + Coxeter type of ['E', 8], Coxeter type of ['F', 4], + Coxeter type of ['H', 3], Coxeter type of ['H', 4], + Coxeter type of ['I', 10], Coxeter type of ['A', 2, 1], + Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], + Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], + Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], + Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1], + Coxeter type of ['A', 1, 1]] The finite, affine and crystallographic options allow respectively for restricting to (non) finite, (non) affine, and (non) crystallographic Cartan types:: - sage: CartanType.samples(finite=True) - [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], - ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4]] - - sage: CartanType.samples(affine=True) - [['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], - ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], - ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], - ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] - - sage: CartanType.samples(crystallographic=True) - [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], - ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], - ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], - ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], - ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], - ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] - - sage: CartanType.samples(crystallographic=False) - [['I', 5], ['H', 3], ['H', 4]] + sage: CoxeterType.samples(finite=True) + [Coxeter type of ['A', 1], Coxeter type of ['A', 5], + Coxeter type of ['B', 1], Coxeter type of ['B', 5], + Coxeter type of ['C', 1], Coxeter type of ['C', 5], + Coxeter type of ['D', 4], Coxeter type of ['D', 5], + Coxeter type of ['E', 6], Coxeter type of ['E', 7], + Coxeter type of ['E', 8], Coxeter type of ['F', 4], + Coxeter type of ['H', 3], Coxeter type of ['H', 4], + Coxeter type of ['I', 10]] + + sage: CoxeterType.samples(affine=True) + [Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] + + sage: CoxeterType.samples(crystallographic=True) + [Coxeter type of ['A', 1], Coxeter type of ['A', 5], + Coxeter type of ['B', 1], Coxeter type of ['B', 5], + Coxeter type of ['C', 1], Coxeter type of ['C', 5], + Coxeter type of ['D', 4], Coxeter type of ['D', 5], + Coxeter type of ['E', 6], Coxeter type of ['E', 7], + Coxeter type of ['E', 8], Coxeter type of ['F', 4], + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] + + sage: CoxeterType.samples(crystallographic=False) + [Coxeter type of ['H', 3], Coxeter type of ['H', 4], Coxeter type of ['I', 10]] .. TODO:: add some reducible Coxeter types (suggestions?) @@ -134,13 +153,20 @@ def _samples(self): EXAMPLES:: - sage: CartanType._samples() - [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], - ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4], - ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], - ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], - ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], - ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] + sage: CoxeterType._samples() + [Coxeter type of ['A', 1], Coxeter type of ['A', 5], + Coxeter type of ['B', 1], Coxeter type of ['B', 5], + Coxeter type of ['C', 1], Coxeter type of ['C', 5], + Coxeter type of ['D', 4], Coxeter type of ['D', 5], + Coxeter type of ['E', 6], Coxeter type of ['E', 7], + Coxeter type of ['E', 8], Coxeter type of ['F', 4], + Coxeter type of ['H', 3], Coxeter type of ['H', 4], + Coxeter type of ['I', 10], Coxeter type of ['A', 2, 1], + Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], + Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], + Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], + Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1], + Coxeter type of ['A', 1, 1]] """ finite = [CoxeterType(t) for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 4], ['D', 5], @@ -337,8 +363,8 @@ def bilinear_form(self, R=None): """ n = self.rank() - mat = self.coxeter_matrix() - base_ring = sum(mat.list()).parent() + mat = self.coxeter_matrix()._matrix + base_ring = mat.base_ring() from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField if UniversalCyclotomicField.has_coerce_map_from(base_ring): From fb77b786305566dff1200521cc8330cee7e6ec5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 7 May 2015 17:07:03 +0300 Subject: [PATCH 0201/1872] PEP8 conventions --- .../combinat/root_system/coxeter_matrix.py | 65 +++++++++---------- src/sage/combinat/root_system/coxeter_type.py | 8 +-- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index bbd33464bb0..d9b04fb009c 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -177,10 +177,10 @@ def __classcall_private__(cls, *args, **kwds): coxeter_type_check = True else: coxeter_type_check = False - + # Initiate from a graph: if isinstance(args[0], Graph): - return cls._from_graph(args[0],coxeter_type_check) + return cls._from_graph(args[0], coxeter_type_check) # Get the Coxeter type coxeter_type = None @@ -196,7 +196,7 @@ def __classcall_private__(cls, *args, **kwds): # Initiate from a Coxeter type if coxeter_type: return cls._from_coxetertype(coxeter_type) - + # Get the index set n = len(list(args[0])) index_set = None @@ -208,8 +208,8 @@ def __classcall_private__(cls, *args, **kwds): raise ValueError("too many arguments") if index_set and len(set(index_set)) != n: raise ValueError("the given index set is not valid") - - return cls._from_matrix(args[0],coxeter_type,index_set,coxeter_type_check) + + return cls._from_matrix(args[0], coxeter_type, index_set, coxeter_type_check) def __init__(self, parent, data, coxeter_type, index_set): """ @@ -252,15 +252,15 @@ def __init__(self, parent, data, coxeter_type, index_set): for key in self._index_set: index_key = self._index_set.index(key) - self._dict[key] = {i:self._matrix[index_key,self._index_set.index(i)] for i in self._index_set} + self._dict[key] = {i: self._matrix[index_key, self._index_set.index(i)] for i in self._index_set} @classmethod - def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): + def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): """ Initiate the Coxeter matrix from a matrix. TESTS:: - + sage: CM = CoxeterMatrix([[1,2],[2,1]]);CM [1 2] [2 1] @@ -286,7 +286,6 @@ def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): # Check that the data is valid check_coxeter_matrix(data) - M = matrix(data) n = M.ncols() @@ -295,7 +294,7 @@ def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): for r in data: entries += list(r) raw_data = map(lambda x: x if x != infinity else -1, entries) - M = matrix(n,n,raw_data) + M = matrix(n, n, raw_data) # until here base_ring = M.base_ring() @@ -311,7 +310,7 @@ def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): index_set = range(n) raw_data = M.list() - + mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), raw_data, coxeter_type, index_set) mat._subdivisions = M._subdivisions @@ -319,12 +318,12 @@ def _from_matrix(cls,data,coxeter_type,index_set,coxeter_type_check): return mat @classmethod - def _from_graph(cls,graph,coxeter_type_check): + def _from_graph(cls, graph, coxeter_type_check): """ Initiate the Coxeter matrix from a graph. TESTS:: - + sage: CoxeterMatrix(CoxeterMatrix(['A',4,1]).coxeter_graph()) [1 3 2 2 3] [3 1 3 2 2] @@ -382,11 +381,11 @@ def _from_graph(cls,graph,coxeter_type_check): i = verts.index(e[0]) j = verts.index(e[1]) data[j][i] = data[i][j] = label - - return cls._from_matrix(data,None,index_set,coxeter_type_check) + + return cls._from_matrix(data, None, index_set, coxeter_type_check) @classmethod - def _from_coxetertype(cls,coxeter_type): + def _from_coxetertype(cls, coxeter_type): """ Initiate the Coxeter matrix from a Coxeter type. @@ -409,11 +408,10 @@ def _from_coxetertype(cls,coxeter_type): data[reverse[i]][reverse[j]] = l data[reverse[j]][reverse[i]] = l - return cls._from_matrix(data,coxeter_type,index_set,False) + return cls._from_matrix(data, coxeter_type, index_set, False) @classmethod - def samples(self, finite=None, affine=None, crystallographic=None, - higher_rank=None): + def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=None): """ Return a sample of the available Coxeter types. @@ -426,7 +424,7 @@ def samples(self, finite=None, affine=None, crystallographic=None, - ``crystallographic`` -- a boolean or ``None`` (default: ``None``) - ``higher_rank`` -- a boolean or ``None`` (default: ``None``) - + The sample contains all the exceptional finite and affine Coxeter types, as well as typical representatives of the infinite families. @@ -440,7 +438,7 @@ def samples(self, finite=None, affine=None, crystallographic=None, Coxeter type of ['E', 7], Coxeter type of ['E', 8], Coxeter type of ['F', 4], Coxeter type of ['H', 3], Coxeter type of ['H', 4], Coxeter type of ['I', 10], - Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], @@ -472,7 +470,7 @@ def samples(self, finite=None, affine=None, crystallographic=None, sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples(affine=True)] [Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], - Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] @@ -514,7 +512,7 @@ def samples(self, finite=None, affine=None, crystallographic=None, """ result = self._samples() if crystallographic is not None: - result = [t for t in result if t.is_crystallographic() == crystallographic ] + result = [t for t in result if t.is_crystallographic() == crystallographic] if finite is not None: result = [t for t in result if t.is_finite() == finite] if affine is not None: @@ -534,8 +532,8 @@ def _samples(self): sage: [CM.coxeter_type() for CM in CoxeterMatrix._samples()] [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 5], Coxeter type of ['D', 4], - Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], Coxeter type of ['E', 7], Coxeter type of ['E', 8], Coxeter type of ['F', 4], Coxeter type of ['H', 3], Coxeter type of ['H', 4], Coxeter type of ['I', 10], @@ -559,17 +557,18 @@ def _samples(self): """ finite = [CoxeterMatrix(t) for t in [['A', 1], ['A', 5], ['B', 5], ['D', 4], ['D', 5], ['E', 6], ['E', 7], - ['E', 8], ['F', 4], ['H', 3], ['H', 4], + ['E', 8], ['F', 4], ['H', 3], ['H', 4], ['I', 10]]] - affine = [CoxeterMatrix(t) for t in ['A', 2, 1], ['B', 5, 1], + affine = [CoxeterMatrix(t) for t in ['A', 2, 1], ['B', 5, 1], ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['A', 1, 1]] - higher_matrices = [[[1,-2],[-2,1]], - [[1,-1,-1],[-1,1,-1],[-1,-1,1]], [[1,2,3],[2,1,7],[3,7,1]], - [[1,-2,3,2],[-2,1,2,3],[3,2,1,-8],[2,3,-8,1]]] + higher_matrices = [[[1, -2], [-2, 1]], + [[1, -1, -1], [-1, 1, -1], [-1, -1, 1]], + [[1, 2, 3], [2, 1, 7], [3, 7, 1]], + [[1, -2, 3, 2], [-2, 1, 2, 3], [3, 2, 1, -8], [2, 3, -8, 1]]] higher = [CoxeterMatrix(m) for m in higher_matrices] @@ -636,7 +635,7 @@ def __hash__(self): return self._matrix.__hash__() - def __eq__(self,other): + def __eq__(self, other): return self._matrix.__eq__(other._matrix) @@ -1096,7 +1095,7 @@ def recognize_coxeter_type_from_matrix(coxeter_matrix): return None elif occur_4 == 2: # There are 2 edges labeled 4 if len(filter(lambda x: 2 in x and 3 not in x and 4 in - x, [vertices_labels[i] for i in vertices_4])) == 2: + x, [vertices_labels[i] for i in vertices_4])) == 2: # The edges with 4 are at the ends of the path types.append(['C', l-1, 1]) continue @@ -1242,7 +1241,7 @@ def coxeter_matrix_as_function(t): m = t.coxeter_matrix() index_set = t.index_set() reverse = dict((index_set[i], i) for i in range(len(index_set))) - return lambda i, j: m[i,j] # m[reverse[i], reverse[j]] + return lambda i, j: m[i, j] def coxeter_matrix(t): """ diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 92ddf70fd00..da9ae92c2cb 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -4,7 +4,7 @@ #***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw , # 2015 Jean-Philippe Labbe , -# +# # Distributed under the terms of the GNU General Public License (GPL) # # This code is distributed in the hope that it will be useful, @@ -137,7 +137,7 @@ def samples(self, finite=None, affine=None, crystallographic=None): """ result = self._samples() if crystallographic is not None: - result = [t for t in result if t.is_crystallographic() == crystallographic ] + result = [t for t in result if t.is_crystallographic() == crystallographic] if finite is not None: result = [t for t in result if t.is_finite() == finite] if affine is not None: @@ -173,13 +173,13 @@ def _samples(self): ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['H', 3], ['H', 4], ['I', 10]]] - affine = [CoxeterType(t) for t in ['A', 2, 1], ['B', 5, 1], + affine = [CoxeterType(t) for t in ['A', 2, 1], ['B', 5, 1], ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['A', 1, 1]] return finite + affine - + @abstract_method def rank(self): """ From d063050fa1e0abe4506eaa30fa911ba7791a3a97 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 7 May 2015 09:30:35 -0700 Subject: [PATCH 0202/1872] Fix doctest from update to Coxeter groups. --- src/sage/combinat/colored_permutations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 0d3699b947d..9b89fda5806 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -744,7 +744,7 @@ class SignedPermutations(ColoredPermutations): This is a finite Coxeter group of type `B_n`:: sage: S.canonical_representation() - Coxeter group over Universal Cyclotomic Field with Coxeter matrix: + Finite Coxeter group over Universal Cyclotomic Field with Coxeter matrix: [1 3 2 2] [3 1 3 2] [2 3 1 4] From 3262e4300df3e199f0db66136b4ad51d166490a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Fri, 8 May 2015 15:50:21 +0300 Subject: [PATCH 0203/1872] Added tests --- .../combinat/root_system/coxeter_matrix.py | 103 ++++++++++++++++-- 1 file changed, 93 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index d9b04fb009c..ec45f318876 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -44,8 +44,6 @@ class CoxeterMatrix(CoxeterType): Because there is no object `\ZZ \cup \{ \infty \}`, we define `-1` to represent `\infty`. - Make it possible to input algebraic number in the matrix and have the - corresponding base ring EXAMPLES:: @@ -122,7 +120,7 @@ def __classcall_private__(cls, *args, **kwds): EXAMPLES:: - sage: C = CoxeterMatrix(['A',1,1]) + sage: C = CoxeterMatrix(['A',1,1],['a','b']) sage: C2 = CoxeterMatrix([[1, -1], [-1, 1]]) sage: C3 = CoxeterMatrix(matrix([[1, -1], [-1, 1]]), [0, 1]) sage: C == C2 and C == C3 @@ -429,6 +427,12 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N Coxeter types, as well as typical representatives of the infinite families. + Here the ``higher_rank`` term denotes non-finite, non-affine, + Coxeter groups (including hyperbolic types). + + .. TODO:: Implement the hyperbolic and compact hyperbolic in the + samples. + EXAMPLES:: sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples()] @@ -580,14 +584,13 @@ def relabel(self, relabelling): INPUT: - - ``relabelling`` -- a function (or a list or dictionary) + - ``relabelling`` -- a function (or dictionary) OUTPUT: an isomorphic Coxeter type obtained by relabelling the nodes of the Coxeter graph. Namely, the node with label ``i`` is - relabelled ``f(i)`` (or, by ``f[i]`` if ``f`` is a list or - dictionary). + relabelled ``f(i)`` (or, by ``f[i]`` if ``f`` is a dictionary). EXAMPLES:: @@ -596,9 +599,17 @@ def relabel(self, relabelling): [4 1 3 2] [2 3 1 2] [3 2 2 1] + sage: CoxeterMatrix(['F',4]).relabel(lambda x: x+1 if x<4 else 1) + [1 4 2 3] + [4 1 3 2] + [2 3 1 2] + [3 2 2 1] """ - data = [[self[relabelling[i]][relabelling[j]] for j in self.index_set()] for i in self.index_set()] + if isinstance(relabelling,type({})): + data = [[self[relabelling[i]][relabelling[j]] for j in self.index_set()] for i in self.index_set()] + else: + data = [[self[relabelling(i)][relabelling(j)] for j in self.index_set()] for i in self.index_set()] return CoxeterMatrix(data) @@ -624,24 +635,84 @@ def __repr__(self): return self._matrix.__repr__() def __iter__(self): + """ + Return an iterator for the rows of the Coxeter matrix. + + EXAMPLES:: + + sage: CM = CoxeterMatrix([[1,8],[8,1]]) + sage: CM.__iter__().next() + (1, 8) + """ return self._matrix.__iter__() def __getitem__(self, key): + """ + Return a dictionary of labels adjacent to a node or + the label of an edge in the Coxeter graph. + + EXAMPLES:: + + sage: CM = CoxeterMatrix([[1,-2],[-2,1]]) + sage: CM = CoxeterMatrix([[1,-2],[-2,1]],['a','b']) + sage: CM['a'] + {'a': 1, 'b': -2} + sage: CM['b'] + {'a': -2, 'b': 1} + sage: CM['a','b'] + -2 + sage: CM['a','a'] + 1 + """ return self._dict[key] def __hash__(self): + r""" + Return hash of the Coxeter matrix. + EXAMPLES:: + + sage: CM = CoxeterMatrix([[1,-2],[-2,1]],['a','b']) + sage: CM.__hash__() + 1 + sage: CM = CoxeterMatrix([[1,-3],[-3,1]],['1','2']) + sage: CM.__hash__() + 4 + """ + return self._matrix.__hash__() def __eq__(self, other): + r""" + Return if ``self`` and ``other`` are equal, ``False`` otherwise. + + EXAMPLES:: + + sage: CM = CoxeterMatrix([[1,-2],[-2,1]],['a','b']) + sage: CM.__hash__() + 1 + sage: CM = CoxeterMatrix([[1,-3],[-3,1]],['1','2']) + sage: CM.__hash__() + 4 + """ return self._matrix.__eq__(other._matrix) def _matrix_(self, R = None): """ Return ``self`` as a matrix over the ring ``R``. + + EXAMPLES:: + + sage: CM = CoxeterMatrix([[1,-3],[-3,1]]) + sage: matrix(CM) + [ 1 -3] + [-3 1] + sage: matrix(CM,RR) + [ 1.00000000000000 -3.00000000000000] + [-3.00000000000000 1.00000000000000] """ if R is not None: @@ -669,7 +740,7 @@ def index_set(self): def coxeter_type(self): """ - Return the Cartan type of ``self`` or ``self`` if unknown. + Return the Coxeter type of ``self`` or ``self`` if unknown. EXAMPLES:: @@ -677,7 +748,7 @@ def coxeter_type(self): sage: C.coxeter_type() Coxeter type of ['A', 4, 1] - If the Cartan type is unknown:: + If the Coxeter type is unknown:: sage: C = CoxeterMatrix([[1,3,4], [3,1,-1], [4,-1,1]]) sage: C.coxeter_type() @@ -1201,6 +1272,18 @@ def check_coxeter_matrix(m): ... ValueError: the matrix is not symmetric + sage: m = matrix([[1,3,1/2],[3,1,-1],[1/2,-1,1]]) + sage: check_coxeter_matrix(m) + Traceback (most recent call last): + ... + ValueError: invalid Coxeter label 1/2 + + sage: m = matrix([[1,3,1],[3,1,-1],[1,-1,1]]) + sage: check_coxeter_matrix(m) + Traceback (most recent call last): + ... + ValueError: invalid Coxeter label 1 + """ mat = matrix(m) @@ -1221,7 +1304,7 @@ def check_coxeter_matrix(m): def coxeter_matrix_as_function(t): """ - Returns the Coxeter matrix, as a function + Return the Coxeter matrix, as a function INPUT: From fcc3273fbb9e83da6c61027463e3ed4582009514 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 9 May 2015 18:17:22 -0700 Subject: [PATCH 0204/1872] Move dim to all manifolds, move methods from H-plane to metric spaces, some fixes. --- src/sage/categories/manifolds.py | 74 ++++++++-------- src/sage/categories/metric_spaces.py | 84 +++++++++++++++---- src/sage/categories/sets_cat.py | 4 +- src/sage/categories/simplicial_complexes.py | 21 +++++ .../hyperbolic_space/hyperbolic_interface.py | 35 +------- 5 files changed, 132 insertions(+), 86 deletions(-) diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index fa8ce5ff6d0..67708e7858d 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -22,9 +22,9 @@ class Manifolds(Category_singleton): r""" The category of manifolds over any field. - Let `k` be a field. A `k`-*manifold* `M` is a second countable - Hausdorff space such that the neighborhood of any point `x \in M` - is homeomorphic to `k^d` for some `d`. + Let `k` be a field. A `k`-*manifold* `M` of dimension `d` is a + second countable Hausdorff space such that the neighborhood of + any point `x \in M` is homeomorphic to `k^b` for some `b \leq d`. EXAMPLES:: @@ -66,6 +66,13 @@ def additional_structure(self): """ return None + class ParentMethods: + @abstract_method + def dimension(self): + """ + Return the dimension of ``self``. + """ + class SubcategoryMethods: @cached_method def Connected(self): @@ -143,44 +150,37 @@ def Complex(self): """ return self._with_axiom('Complex') + @cached_method + def FiniteDimensional(self): + """ + Return the full subcategory of the finite dimensional + objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds().Connected().FiniteDimensional(); C + Category of finite dimensional connected manifolds + + TESTS:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds().Connected().FiniteDimensional() + sage: TestSuite(C).run() + sage: Manifolds().Connected().FiniteDimensional.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('FiniteDimensional') + + class FiniteDimensional(CategoryWithAxiom): + """ + Category of finite dimensional manifolds. + """ + class Connected(CategoryWithAxiom): """ The category of connected manifolds. """ - class ParentMethods: - @abstract_method - def dimension(self): - """ - Return the dimension of ``self``. - """ - - class SubcategoryMethods: - @cached_method - def FiniteDimensional(self): - """ - Return the full subcategory of the finite dimensional - objects of ``self``. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds().Connected().FiniteDimensional(); C - Category of finite dimensional connected manifolds - - TESTS:: - - sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds().Connected().FiniteDimensional() - sage: TestSuite(C).run() - sage: Manifolds().Connected().FiniteDimensional.__module__ - 'sage.categories.manifolds' - """ - return self._with_axiom('FiniteDimensional') - - class FiniteDimensional(CategoryWithAxiom): - """ - Category of finite dimensional (connected) manifolds. - """ class Differentiable(CategoryWithAxiom): """ diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index d01c992fe4f..b1ca4144ea1 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -11,6 +11,7 @@ from sage.misc.abstract_method import abstract_method from sage.categories.category import Category from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory +from sage.categories.with_realizations import WithRealizationsCategory class MetricSpacesCategory(RegressiveCovariantConstructionCategory): @@ -33,7 +34,7 @@ def default_super_categories(cls, category): A (join) category - In practice, this returns ``category.Subquotients()``, joined + In practice, this returns ``category.Metric()``, joined together with the result of the method :meth:`RegressiveCovariantConstructionCategory.default_super_categories() ` @@ -42,24 +43,20 @@ def default_super_categories(cls, category): EXAMPLES: - Consider ``category=Groups()``, which has ``cat=Monoids()`` as - super category. Then, a subgroup of a group `G` is - simultaneously a subquotient of `G`, a group by itself, and a - submonoid of `G`:: + Consider ``category=Groups()``. Then, a group `G` with a metric + is simultaneously a topological group by itself, and a + topogological space:: - sage: Groups().Subobjects().super_categories() - [Category of groups, Category of subquotients of monoids, Category of subobjects of sets] - - Mind the last item above: there is indeed currently nothing - implemented about submonoids. + sage: Groups().Metric().super_categories() + [Category of topological groups, Category of metric spaces] This resulted from the following call:: - sage: sage.categories.subobjects.SubobjectsCategory.default_super_categories(Groups()) - Join of Category of groups and Category of subquotients of monoids and Category of subobjects of sets + sage: sage.categories.metric_spaces.MetricSpacesCategory.default_super_categories(Groups()) + Join of Category of topological groups and Category of metric spaces """ return Category.join([category.Topological(), - super(MetricSpaces, cls).default_super_categories(category)]) + super(MetricSpacesCategory, cls).default_super_categories(category)]) # We currently don't have a use for this, but we probably will def _repr_object_names(self): @@ -67,7 +64,7 @@ def _repr_object_names(self): EXAMPLES:: sage: Groups().Metric() # indirect doctest - Category of metric groups + Join of Category of topological groups and Category of metric spaces """ return "metric {}".format(self.base_category()._repr_object_names()) @@ -101,6 +98,13 @@ def _test_metric(self, **options): - ``options`` -- any keyword arguments accepted by :meth:`_tester` + + EXAMPLES:: + + sage: UHP = HyperbolicPlane().UHP() + sage: UHP._test_metric() + sage: elts = [UHP.random_element() for i in range(5)] + sage: UHP._test_metric(some_elements=elts) """ tester = self._tester(**options) S = tester.some_elements() @@ -108,7 +112,7 @@ def _test_metric(self, **options): for a in S: for b in S: d = dist(a, b) - if a != b: + if a is not b: tester.assertGreater(d, 0) else: tester.assertEqual(d, 0) @@ -116,6 +120,15 @@ def _test_metric(self, **options): def metric(self): """ Return the metric of ``self``. + + EXAMPLES:: + + sage: UHP = HyperbolicPlane().UHP() + sage: m = UHP.metric() + sage: p1 = UHP.get_point(5 + 7*I) + sage: p2 = UHP.get_point(1.0 + I) + sage: m(p1, p2) + 2.23230104635820 """ return lambda a,b: self.dist(a, b) @@ -123,12 +136,51 @@ def metric(self): def dist(self, a, b): """ Return the distance between ``a`` and ``b`` in ``self``. + + EXAMPLES:: + + sage: UHP = HyperbolicPlane().UHP() + sage: p1 = UHP.get_point(5 + 7*I) + sage: p2 = UHP.get_point(1.0 + I) + sage: UHP.dist(p1, p2) + 2.23230104635820 + + sage: PD = HyperbolicPlane().PD() + sage: PD.dist(PD.get_point(0), PD.get_point(I/2)) + arccosh(5/3) """ class ElementMethods: def dist(self, b): """ - Return the distance between ``self`` and ``b``. + Return the distance between ``self`` and ``other``. + + EXAMPLES:: + + sage: UHP = HyperbolicPlane().UHP() + sage: p1 = UHP.get_point(5 + 7*I) + sage: p2 = UHP.get_point(1 + I) + sage: p1.dist(p2) + arccosh(33/7) """ return self.parent().dist(self, b) + class WithRealizations(WithRealizationsCategory): + class ParentMethods: + def dist(self, a, b): + """ + Return the distance between ``a`` and ``b`` by converting them + to a realization of ``self`` and doing the computation. + + EXAMPLES:: + + sage: H = HyperbolicPlane() + sage: PD = H.PD() + sage: p1 = PD.get_point(0) + sage: p2 = PD.get_point(I/2) + sage: H.dist(p1, p2) + arccosh(5/3) + """ + R = self.a_realization() + return R.dist(R(a), R(b)) + diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 16cd6b9fd00..bda38036ff8 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -670,8 +670,8 @@ def Metric(self): sage: TestSuite(Sets().Metric()).run() """ - from sage.categories.metric_spaces import MetricSpaces - return MetricSpaces.category_of(self) + from sage.categories.metric_spaces import MetricSpacesCategory + return MetricSpacesCategory.category_of(self) @cached_method def Algebras(self, base_ring): diff --git a/src/sage/categories/simplicial_complexes.py b/src/sage/categories/simplicial_complexes.py index 81121e68920..d5ca22561aa 100644 --- a/src/sage/categories/simplicial_complexes.py +++ b/src/sage/categories/simplicial_complexes.py @@ -60,6 +60,12 @@ class ParentMethods: def dimension(self): """ Return the dimension of ``self``. + + EXAMPLES:: + + sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) + sage: S.dimension() + 2 """ return max(c.dimension() for c in self.facets()) @@ -68,11 +74,26 @@ class ParentMethods: def facets(self): """ Return the facets of ``self``. + + EXAMPLES:: + + sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) + sage: S.facets() + {(1, 2), (1, 3, 4), (2, 5), (4, 5)} """ @abstract_method def faces(self): """ Return the faces of ``self``. + + EXAMPLES:: + + sage: S = SimplicialComplex([[1,3,4], [1,2],[2,5],[4,5]]) + sage: S.faces() + {-1: {()}, + 0: {(1,), (2,), (3,), (4,), (5,)}, + 1: {(1, 2), (1, 3), (1, 4), (2, 5), (3, 4), (4, 5)}, + 2: {(1, 3, 4)}} """ diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py b/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py index d8d3c411467..d2a4008207f 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py @@ -97,7 +97,7 @@ def __init__(self): sage: H = HyperbolicPlane() sage: TestSuite(H).run() """ - Parent.__init__(self, category=Sets().WithRealizations()) + Parent.__init__(self, category=Sets().Metric().WithRealizations()) self.a_realization() # We create a realization so at least one is known def _repr_(self): @@ -181,9 +181,10 @@ def super_categories(self): sage: H = HyperbolicPlane() sage: models = HyperbolicModels(H) sage: models.super_categories() - [Category of sets, Category of realizations of Hyperbolic plane] + [Category of metric spaces, + Category of realizations of Hyperbolic plane] """ - return [Sets(), Realizations(self.base())] + return [Sets().Metric(), Realizations(self.base())] class ParentMethods: def _an_element_(self): @@ -204,31 +205,3 @@ def _an_element_(self): """ return self(self.realization_of().PD().get_point(0)) - # TODO: Move to a category of metric spaces once created - @abstract_method - def dist(self, a, b): - """ - Return the distance between ``a`` and ``b``. - - EXAMPLES:: - - sage: PD = HyperbolicPlane().PD() - sage: PD.dist(PD.get_point(0), PD.get_point(I/2)) - arccosh(5/3) - """ - - class ElementMethods: - # TODO: Move to a category of metric spaces once created - def dist(self, other): - """ - Return the distance between ``self`` and ``other``. - - EXAMPLES:: - - sage: UHP = HyperbolicPlane().UHP() - sage: p1 = UHP.get_point(5 + 7*I) - sage: p2 = UHP.get_point(1 + I) - sage: p1.dist(p2) - arccosh(33/7) - """ - return self.parent().dist(self, other) From 5f32618962e05ffec650d973c10328ea8cc6bd85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 May 2015 12:32:53 +0200 Subject: [PATCH 0205/1872] trac #17411 a few doc typo corrections and also some pep8 code changes --- src/sage/combinat/colored_permutations.py | 52 ++++++++++++----------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 9b89fda5806..a698eedbbd4 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -149,7 +149,7 @@ def __iter__(self): sage: list(x) [(1, 3), (0, 1), (0, 2)] """ - for i,p in enumerate(self._perm): + for i, p in enumerate(self._perm): yield (self._colors[i], p) def one_line_form(self): @@ -218,10 +218,12 @@ def to_matrix(self): """ Cp = CyclotomicField(self.parent()._m) g = Cp.gen() - D = diagonal_matrix(Cp, [g**i for i in self._colors]) + D = diagonal_matrix(Cp, [g ** i for i in self._colors]) return self._perm.to_matrix() * D -# TODO: Parts of this should be put in the category of complex reflection groups + +# TODO: Parts of this should be put in the category of complex +# reflection groups class ColoredPermutations(Parent, UniqueRepresentation): r""" The group of `m`-colored permutations on `\{1, 2, \ldots, n\}`. @@ -319,7 +321,7 @@ def gens(self): [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]]) """ - zero = [self._C.zero()]*self._n + zero = [self._C.zero()] * self._n g = [] for i in range(self._n-1): p = range(1, self._n+1) @@ -408,7 +410,7 @@ def cardinality(self): sage: C.cardinality() == 4**3 * factorial(3) True """ - return self._m**self._n * self._P.cardinality() + return self._m ** self._n * self._P.cardinality() def rank(self): """ @@ -461,9 +463,9 @@ def degrees(self): sage: prod(S.degrees()) == S.cardinality() True """ - if self._m == 1: # Special case for the usual symmetric group - return range(2, self._n+1) - return [self._m * i for i in range(1, self._n+1)] + if self._m == 1: # Special case for the usual symmetric group + return range(2, self._n + 1) + return [self._m * i for i in range(1, self._n + 1)] def codegrees(self): """ @@ -503,8 +505,8 @@ def codegrees(self): sage: f == g True """ - if self._m == 1: # Special case for the usual symmetric group - return list(reversed(range(self._n-1))) + if self._m == 1: # Special case for the usual symmetric group + return list(reversed(range(self._n - 1))) return [self._m * i for i in reversed(range(self._n))] def number_reflection_hyperplanes(self): @@ -512,7 +514,7 @@ def number_reflection_hyperplanes(self): Return the number of reflection hyperplanes of ``self``. The number of reflection hyperplanes of a complex reflection - group is equal to the sume of the codegrees plus the rank. + group is equal to the sum of the codegrees plus the rank. EXAMPLES:: @@ -533,7 +535,7 @@ def fixed_point_polynomial(self, q=None): The fixed point polynomial of ``self``. The fixed point polynomial `f_G` of a complex reflection group `G` is - counting the dimesions fixed points subspaces: + counting the dimensions of fixed points subspaces: .. MATH:: @@ -595,13 +597,14 @@ def is_well_generated(self): """ deg = self.degrees() dstar = self.codegrees() - return all(deg[-1] == d + dstar[i] for i,d in enumerate(deg)) + return all(deg[-1] == d + dstar[i] for i, d in enumerate(deg)) Element = ColoredPermutation ##################################################################### ## Signed permutations + class SignedPermutation(ColoredPermutation): """ A signed permutation. @@ -642,7 +645,7 @@ def _mul_(self, other): True """ colors = tuple(self._colors[i] * other._colors[val-1] #-1 for indexing - for i,val in enumerate(self._perm)) + for i, val in enumerate(self._perm)) p = self._perm._left_to_right_multiply_on_right(other._perm) return self.__class__(self.parent(), colors, p) @@ -679,7 +682,7 @@ def __iter__(self): sage: [a for a in x] [-4, 1, 2, -3] """ - for i,p in enumerate(self._perm): + for i, p in enumerate(self._perm): yield self._colors[i] * p def to_matrix(self): @@ -720,10 +723,11 @@ def has_left_descent(self, i): n = self.parent()._n if i == n: return self._colors[-1] == -1 - if self._colors[i-1] == -1: + if self._colors[i - 1] == -1: return self._colors[i] == 1 or self._perm[i-1] < self._perm[i] return self._colors[i] == 1 and self._perm[i-1] > self._perm[i] + class SignedPermutations(ColoredPermutations): r""" Group of signed permutations. @@ -791,7 +795,8 @@ def one(self): sage: S.one() [1, 2, 3, 4] """ - return self.element_class(self, [ZZ.one()]*self._n, self._P.identity()) + return self.element_class(self, [ZZ.one()] * self._n, + self._P.identity()) def simple_reflection(self, i): r""" @@ -810,11 +815,11 @@ def simple_reflection(self, i): if i not in self.index_set(): raise ValueError("i must be in the index set") if i < self._n: - p = range(1, self._n+1) - p[i-1] = i+1 + p = range(1, self._n + 1) + p[i - 1] = i + 1 p[i] = i return self.element_class(self, [ZZ.one()]*self._n, self._P(p)) - temp = [ZZ.one()]*self._n + temp = [ZZ.one()] * self._n temp[-1] = -ZZ.one() return self.element_class(self, temp, self._P.identity()) @@ -889,7 +894,7 @@ def __iter__(self): [2, 1], [2, -1], [-2, 1], [-2, -1]] """ one = ZZ.one() - C = CartesianProduct(*[[one,-one]]*self._n) + C = CartesianProduct(*[[one,-one]] * self._n) for p in self._P: for c in C: yield self.element_class(self, c, p) @@ -930,7 +935,7 @@ def long_element(self, index_set=None): INPUT: - - ``index_set`` -- (optioal) a subset (as a list or iterable) + - ``index_set`` -- (optional) a subset (as a list or iterable) of the nodes of the indexing set EXAMPLES:: @@ -942,7 +947,7 @@ def long_element(self, index_set=None): if index_set is not None: return super(SignedPermutations, self).long_element() p = range(self._n, 0, -1) - return self.element_class(self, [-ZZ.one()]*self._n, self._P(p)) + return self.element_class(self, [-ZZ.one()] * self._n, self._P(p)) Element = SignedPermutation @@ -969,4 +974,3 @@ def long_element(self, index_set=None): # # if total % 2 == 0: # yield s - From 66a2290ff1013646e7aa6de18a5d4a846fe53f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 May 2015 14:58:08 +0200 Subject: [PATCH 0206/1872] trac #17411 final pep8 cleanup --- src/sage/combinat/colored_permutations.py | 60 ++++++++++++++--------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index a698eedbbd4..912e0717643 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -1,5 +1,10 @@ r""" Colored Permutations + +.. TODO:: + + Much of the colored permutations (and element) class can be + generalized to `G \wr S_n` """ from sage.categories.groups import Groups from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -18,8 +23,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.all import ZZ -# TODO: Much of the colored permutations (and element) class can be -# generalized to `G \wr S_n` + class ColoredPermutation(MultiplicativeGroupElement): """ A colored permutation. @@ -64,7 +68,7 @@ def _latex_(self): """ ret = "[" ret += ", ".join("{}_{{{}}}".format(x, self._colors[i]) - for i,x in enumerate(self._perm)) + for i, x in enumerate(self._perm)) return ret + "]" def _mul_(self, other): @@ -78,8 +82,8 @@ def _mul_(self, other): sage: s1*s2*s1 == s2*s1*s2 True """ - colors = tuple(self._colors[i] + other._colors[val-1] #-1 for indexing - for i,val in enumerate(self._perm)) + colors = tuple(self._colors[i] + other._colors[val - 1] # -1 for indexing + for i, val in enumerate(self._perm)) p = self._perm._left_to_right_multiply_on_right(other._perm) return self.__class__(self.parent(), colors, p) @@ -98,7 +102,7 @@ def __invert__(self): """ ip = ~self._perm return self.__class__(self.parent(), - tuple([-self._colors[i-1] for i in ip]), #-1 for indexing + tuple([-self._colors[i - 1] for i in ip]), # -1 for indexing ip) def __eq__(self, other): @@ -186,6 +190,8 @@ def permutation(self): """ Return the permutation of ``self``. + This is obtained by forgetting the colors. + EXAMPLES:: sage: C = ColoredPermutations(4, 3) @@ -200,6 +206,8 @@ def to_matrix(self): """ Return a matrix of ``self``. + The colors are mapped to roots of unity. + EXAMPLES:: sage: C = ColoredPermutations(4, 3) @@ -306,7 +314,8 @@ def one(self): sage: C.one() [[0, 0, 0], [1, 2, 3]] """ - return self.element_class(self, [self._C.zero()]*self._n, self._P.identity()) + return self.element_class(self, [self._C.zero()] * self._n, + self._P.identity()) @cached_method def gens(self): @@ -323,13 +332,13 @@ def gens(self): """ zero = [self._C.zero()] * self._n g = [] - for i in range(self._n-1): - p = range(1, self._n+1) - p[i] = i+2 - p[i+1] = i+1 - g.append( self.element_class(self, zero, self._P(p)) ) + for i in range(self._n - 1): + p = range(1, self._n + 1) + p[i] = i + 2 + p[i + 1] = i + 1 + g.append(self.element_class(self, zero, self._P(p))) zero[-1] = self._C.one() - g.append( self.element_class(self, zero, self._P.identity()) ) + g.append(self.element_class(self, zero, self._P.identity())) return tuple(g) def matrix_group(self): @@ -353,6 +362,11 @@ def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. + INPUT: + + either a list of pairs (color, element) + or a pair of lists (colors, elements) + TESTS:: sage: C = ColoredPermutations(4, 3) @@ -368,7 +382,7 @@ def _element_constructor_(self, x): for k in x: if len(k) != 2: raise ValueError("input must be pairs (color, element)") - c.append( self._C(k[0]) ) + c.append(self._C(k[0])) p.append(k[1]) return self.element_class(self, c, self._P(p)) @@ -393,7 +407,7 @@ def __iter__(self): [[1, 0], [2, 1]], [[1, 1], [2, 1]]] """ - C = CartesianProduct(*[self._C]*self._n) + C = CartesianProduct(*[self._C] * self._n) for p in self._P: for c in C: yield self.element_class(self, c, p) @@ -644,7 +658,7 @@ def _mul_(self, other): sage: s3*s4*s3*s4 == s4*s3*s4*s3 True """ - colors = tuple(self._colors[i] * other._colors[val-1] #-1 for indexing + colors = tuple(self._colors[i] * other._colors[val - 1] # -1 for indexing for i, val in enumerate(self._perm)) p = self._perm._left_to_right_multiply_on_right(other._perm) return self.__class__(self.parent(), colors, p) @@ -665,7 +679,7 @@ def inverse(self): """ ip = ~self._perm return self.__class__(self.parent(), - tuple([self._colors[i-1] for i in ip]), #-1 for indexing + tuple([self._colors[i - 1] for i in ip]), # -1 for indexing ip) __invert__ = inverse @@ -724,8 +738,8 @@ def has_left_descent(self, i): if i == n: return self._colors[-1] == -1 if self._colors[i - 1] == -1: - return self._colors[i] == 1 or self._perm[i-1] < self._perm[i] - return self._colors[i] == 1 and self._perm[i-1] > self._perm[i] + return self._colors[i] == 1 or self._perm[i - 1] < self._perm[i] + return self._colors[i] == 1 and self._perm[i - 1] > self._perm[i] class SignedPermutations(ColoredPermutations): @@ -818,7 +832,7 @@ def simple_reflection(self, i): p = range(1, self._n + 1) p[i - 1] = i + 1 p[i] = i - return self.element_class(self, [ZZ.one()]*self._n, self._P(p)) + return self.element_class(self, [ZZ.one()] * self._n, self._P(p)) temp = [ZZ.one()] * self._n temp[-1] = -ZZ.one() return self.element_class(self, temp, self._P.identity()) @@ -859,7 +873,7 @@ def _element_constructor_(self, x): raise ValueError("input must be pairs (sign, element)") if k[0] != 1 and k[0] != -1: raise ValueError("the sign must be +1 or -1") - c.append( ZZ(k[0]) ) + c.append(ZZ(k[0])) p.append(k[1]) return self.element_class(self, c, self._P(p)) @@ -894,7 +908,7 @@ def __iter__(self): [2, 1], [2, -1], [-2, 1], [-2, -1]] """ one = ZZ.one() - C = CartesianProduct(*[[one,-one]] * self._n) + C = CartesianProduct(*[[one, -one]] * self._n) for p in self._P: for c in C: yield self.element_class(self, c, p) @@ -910,7 +924,7 @@ def index_set(self): sage: S.index_set() (1, 2, 3, 4) """ - return tuple(range(1, self._n+1)) + return tuple(range(1, self._n + 1)) def coxeter_matrix(self): """ From 0350849cd7f02b23156de843e2dadcead7d4baa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 May 2015 15:04:05 +0200 Subject: [PATCH 0207/1872] trac #17411 insertion in module_list --- src/doc/en/reference/combinat/module_list.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 2b6bb9989b7..7bdb55c6626 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -35,6 +35,7 @@ Comprehensive Module list sage/combinat/cluster_algebra_quiver/mutation_type sage/combinat/cluster_algebra_quiver/quiver sage/combinat/cluster_algebra_quiver/quiver_mutation_type + sage/combinat/colored_permutations sage/combinat/combinat sage/combinat/combinat_cython sage/combinat/combination From 0b56cd3df944345e4578570cba8df571f1a158b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 May 2015 17:05:29 +0200 Subject: [PATCH 0208/1872] trac #17411 one typo found --- src/sage/combinat/colored_permutations.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 912e0717643..3a501b65ebf 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -814,9 +814,7 @@ def one(self): def simple_reflection(self, i): r""" - Return the ``i``-th simple refection of ``self``. - - Return the generators of ``self``. + Return the ``i``-th simple reflection of ``self``. EXAMPLES:: From 24b4b4fe83f7453c155714439ff255e576e5f652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 May 2015 17:08:40 +0200 Subject: [PATCH 0209/1872] trac #17411 lazy import --- src/sage/combinat/all.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index a390a0896f9..b27e2a75902 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -36,7 +36,8 @@ #Permutations from permutation import Permutation, Permutations, Arrangements, PermutationOptions, CyclicPermutations, CyclicPermutationsOfPartition from affine_permutation import AffinePermutationGroup -from colored_permutations import ColoredPermutations, SignedPermutations +lazy_import('sage.combinat.colored_permutations', ['ColoredPermutations', + 'SignedPermutations']) from derangements import Derangements lazy_import('sage.combinat.baxter_permutations', ['BaxterPermutations']) From 8053f0c833809ff45347aadf7e66d93035064488 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 13 May 2015 08:46:58 -0700 Subject: [PATCH 0210/1872] Fixing some issues that were uncovered by the changes in Tableau. --- .../combinat/crystals/kirillov_reshetikhin.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index 3524f1f375c..8976bb67c0f 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -3199,6 +3199,44 @@ def from_coordinates(self, coords): + [l(-2)]*coords[4] + [l(-1)]*coords[5]) return self.element_class(self, C(*lst)) + def _element_constructor_(self, *args, **options): + """ + Construct an element of ``self``. + + TESTS:: + + sage: KRC = crystals.KirillovReshetikhin(['D',4,3], 1, 3) + sage: KRT = crystals.KirillovReshetikhin(['D',4,3], 1, 3, model='KR') + sage: elt = KRC.module_generators[2].f_string([1,1,2,1,2]); elt + [[3, 0]] + sage: ret = KRT(elt); ret + [[3, 0, E]] + sage: test = KRC(ret); test + [[3, 0]] + sage: test == elt + True + """ + from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableauxElement + if isinstance(args[0], KirillovReshetikhinTableauxElement): + elt = args[0] + # Check to make sure it can be converted + if elt.cartan_type() != self.cartan_type() \ + or elt.parent().r() != self._r or elt.parent().s() != self._s: + raise ValueError("the Kirillov-Reshetikhin tableau must have the same Cartan type and shape") + + to_hw = elt.to_classical_highest_weight() + # The classically HW element consists of 1, -1, and 'E' + wt = sum(x.value for x in to_hw[0] if x.value != 'E') + letters = elt.parent().letters + if wt: + rows = [[letters(1)]*int(wt)] + else: + rows = [] + hw_elt = self(rows=rows) + f_str = reversed(to_hw[1]) + return hw_elt.f_string(f_str) + return KirillovReshetikhinGenericCrystal._element_constructor_(self, *args, **options) + class Element(KirillovReshetikhinGenericCrystalElement): @cached_method def coordinates(self): From ebc2a65c5d377cc1e7872201709fabcec3e9e4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 17 May 2015 20:20:50 +0200 Subject: [PATCH 0211/1872] trac #17096 fixing two doctests --- src/sage/combinat/ncsf_qsym/generic_basis_code.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/ncsf_qsym/generic_basis_code.py b/src/sage/combinat/ncsf_qsym/generic_basis_code.py index 571dd69036e..2e062819317 100644 --- a/src/sage/combinat/ncsf_qsym/generic_basis_code.py +++ b/src/sage/combinat/ncsf_qsym/generic_basis_code.py @@ -940,15 +940,16 @@ def degree(self): sage: S.zero().degree() Traceback (most recent call last): ... - ValueError: The zero element does not have a well-defined degree. + ValueError: the zero element does not have a well-defined degree sage: F = QuasiSymmetricFunctions(QQ).F() sage: F.zero().degree() Traceback (most recent call last): ... - ValueError: The zero element does not have a well-defined degree. + ValueError: the zero element does not have a well-defined degree """ return self.maximal_degree() + class AlgebraMorphism(ModuleMorphismByLinearity): # Find a better name """ A class for algebra morphism defined on a free algebra from the image of the generators From c5281c075bf4e196aea84cafa2c54d119ee6cd7e Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Thu, 21 May 2015 17:45:32 +0200 Subject: [PATCH 0212/1872] #18338 : return a polynomial over ZZ. --- src/sage/combinat/combinat.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 0dd9bc3df5f..ef788e7ccc0 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -2693,7 +2693,7 @@ def bell_polynomial(n, k): OUTPUT: - - a polynomial in `n-k+1` variables over `\QQ` + - a polynomial in `n-k+1` variables over `\ZZ` EXAMPLES:: @@ -2707,7 +2707,7 @@ def bell_polynomial(n, k): Check that :trac:`18338` is fixed:: sage: bell_polynomial(0,0).parent() - Multivariate Polynomial Ring in x over Rational Field + Multivariate Polynomial Ring in x over Integer Ring sage: for n in (0..4): ....: print [bell_polynomial(n,k).coefficients() for k in (0..n)] @@ -2730,7 +2730,7 @@ def bell_polynomial(n, k): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.combinat.partition import Partitions from sage.rings.arith import factorial - R = PolynomialRing(QQ, 'x', n-k+1) + R = PolynomialRing(ZZ, 'x', n-k+1) vars = R.gens() result = R.zero() for p in Partitions(n, length=k): @@ -2741,7 +2741,7 @@ def bell_polynomial(n, k): power_factorial_product *= factorial(part)**count coefficient = factorial(n) / (factorial_product * power_factorial_product) result += coefficient * prod([vars[i - 1] for i in p]) - return result + return R(result) def fibonacci_sequence(start, stop=None, algorithm=None): r""" From 81f662cc7cb2a1add3e14d862654d1658f16bb43 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Thu, 21 May 2015 18:16:03 +0200 Subject: [PATCH 0213/1872] Improve documentation of class TensorParallelCompute. --- src/sage/tensor/modules/parallel_utilities.py | 127 +++++++++++++----- 1 file changed, 93 insertions(+), 34 deletions(-) diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py index 7598f20688a..e3e35c229f1 100644 --- a/src/sage/tensor/modules/parallel_utilities.py +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -1,9 +1,17 @@ r""" Parallelization utilities -This module defines a singleton class containing parallelization -informations when using tensor algebra. +This module defines +- the singleton class :class:`TensorParallelCompute` to gather the information + relative to the parallelization of tensor algebra (basically the number of + cores to be used) +- the global functions :func:`set_nproc` and :func:`get_nproc` to be used in + a Sage session for managing the number of cores involved in the + parallelization. + +Some examples of parallelization are provided in the documentation +of :meth:`sage.tensor.modules.comp.Components.contract`. AUTHORS: @@ -27,34 +35,31 @@ class TensorParallelCompute(Singleton, SageObject): r""" - Class governing Tensors Parallelism. - - Contains information about parallelism of Tensor algebra. + Singleton class for managing the number of processors in parallel + computations involved in tensor algebra. - EXAMPLE :: + EXAMPLES:: sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute - sage: print TensorParallelCompute() + sage: TensorParallelCompute() Number of cpu used = 1 sage: TensorParallelCompute().set(4) - sage: print TensorParallelCompute() + sage: TensorParallelCompute() Number of cpu used = 4 sage: TensorParallelCompute().set(1) - sage: print TensorParallelCompute() + sage: TensorParallelCompute() Number of cpu used = 1 """ def __init__(self): r""" - Intializes the parallelism. Only an instance (Singleton) of this - class is created. - Default : 1 processor is used, so no parallelism. + Only a single instance of this class is created (singleton model) - TEST :: + TEST:: sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute sage: TP = TensorParallelCompute() - sage: print TP + sage: TP Number of cpu used = 1 Test of the singleton character:: @@ -62,74 +67,128 @@ class is created. sage: TensorParallelCompute() is TP True + The test suite is passed:: + + sage: TestSuite(TP).run() + """ self._nproc = 1 self._use_paral = False def _repr_(self): r""" - String to print the number of cores. + String representation of the object. - TEST :: + TEST:: sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute sage: TensorParallelCompute()._repr_() 'Number of cpu used = 1' """ - return "Number of cpu used = "+str(self._nproc) + return "Number of cpu used = {}".format(self._nproc) - def set(self,nproc=None): + def set(self, nproc=None): r""" - Changes the status of the parallelism in tensorial computations. - If not argument is given, the number of processors will set - to the maximum of cores found. + Set the number of processors (cores) to be used in parallel + computations + + INPUT: - EXAMPLE :: + - ``nproc`` -- (defaut: ``None``) number of processors; if ``None``, the + number of processors will be set to the maximum of cores found on the + computer. + + EXAMPLES: + + The default is a single processor (no parallelization):: sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute - sage: print TensorParallelCompute() + sage: TensorParallelCompute() Number of cpu used = 1 + + Asking for parallelization on 4 processors:: + sage: TensorParallelCompute().set(4) - sage: print TensorParallelCompute() + sage: TensorParallelCompute() Number of cpu used = 4 + + Using all the processors available on the computer:: + + sage: TensorParallelCompute().set() + sage: TensorParallelCompute() # random + Number of cpu used = 8 + + Switching off the parallelization:: + sage: TensorParallelCompute().set(1) + sage: TensorParallelCompute() + Number of cpu used = 1 """ self._nproc = ncpus() if nproc is None else nproc self._use_paral = True if self._nproc!=1 else False - - def set_nproc(nproc=None): r""" - Changes the status of the parallelism in tensorial computations. - If not argument is given, the number of processors will set - to the maximum of cores found. + Set the number of processors (cores) for parallelizing computations + relative to tensor algebra. + + INPUT: + + - ``nproc`` -- (defaut: ``None``) number of processors; if ``None``, the + number of processors will be set to the maximum of cores found on the + computer. - EXAMPLE :: + EXAMPLES: + + The default is a single processor (no parallelization):: sage: get_nproc() 1 + + Asking for parallelization on 4 processors:: + sage: set_nproc(4) sage: get_nproc() 4 - """ + Using all the processors available on the computer:: + + sage: set_nproc() + sage: get_nproc() # random + 8 + + Switching off the parallelization:: + + sage: set_nproc(1) + sage: get_nproc() + 1 + See :meth:`sage.tensor.modules.comp.Components.contract` for a concrete + example of use. + + """ TensorParallelCompute().set(nproc) def get_nproc(): r""" - Return the number of processus used in tensorial computations. + Return the number of processors (cores) used in parallelized tensorial + computations. + + EXAMPLES: + + The default is a single processor (no parallelization):: - TEST :: + sage: get_nproc() + 1 + + Asking for parallelization on 4 processors:: sage: set_nproc(4) sage: get_nproc() 4 """ - return TensorParallelCompute()._nproc From ea38c84d685446a1de5793cd00d79ea6c5448605 Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Fri, 22 May 2015 11:31:40 +0200 Subject: [PATCH 0214/1872] In doc, changed processor with process --- src/sage/tensor/modules/parallel_utilities.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py index e3e35c229f1..3549832ca17 100644 --- a/src/sage/tensor/modules/parallel_utilities.py +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -5,9 +5,9 @@ - the singleton class :class:`TensorParallelCompute` to gather the information relative to the parallelization of tensor algebra (basically the number of - cores to be used) + processes to be used) - the global functions :func:`set_nproc` and :func:`get_nproc` to be used in - a Sage session for managing the number of cores involved in the + a Sage session for managing the number of processes involved in the parallelization. Some examples of parallelization are provided in the documentation @@ -35,7 +35,7 @@ class TensorParallelCompute(Singleton, SageObject): r""" - Singleton class for managing the number of processors in parallel + Singleton class for managing the number of processes used in parallel computations involved in tensor algebra. EXAMPLES:: @@ -90,13 +90,13 @@ def _repr_(self): def set(self, nproc=None): r""" - Set the number of processors (cores) to be used in parallel + Set the number of processes to be launched in parallel computations INPUT: - - ``nproc`` -- (defaut: ``None``) number of processors; if ``None``, the - number of processors will be set to the maximum of cores found on the + - ``nproc`` -- (defaut: ``None``) number of processes; if ``None``, the + number of processes will be set to the maximum of cores found on the computer. EXAMPLES: @@ -107,13 +107,13 @@ def set(self, nproc=None): sage: TensorParallelCompute() Number of cpu used = 1 - Asking for parallelization on 4 processors:: + Asking for parallelization on 4 cores:: sage: TensorParallelCompute().set(4) sage: TensorParallelCompute() Number of cpu used = 4 - Using all the processors available on the computer:: + Using all the cores available on the computer:: sage: TensorParallelCompute().set() sage: TensorParallelCompute() # random @@ -132,13 +132,13 @@ def set(self, nproc=None): def set_nproc(nproc=None): r""" - Set the number of processors (cores) for parallelizing computations + Set the number of processes for parallelizing computations relative to tensor algebra. INPUT: - - ``nproc`` -- (defaut: ``None``) number of processors; if ``None``, the - number of processors will be set to the maximum of cores found on the + - ``nproc`` -- (defaut: ``None``) number of processes; if ``None``, the + number of processes will be set to the maximum of cores found on the computer. EXAMPLES: @@ -148,13 +148,13 @@ def set_nproc(nproc=None): sage: get_nproc() 1 - Asking for parallelization on 4 processors:: + Asking for parallelization on 4 cores:: sage: set_nproc(4) sage: get_nproc() 4 - Using all the processors available on the computer:: + Using all the cores available on the computer:: sage: set_nproc() sage: get_nproc() # random @@ -174,7 +174,7 @@ def set_nproc(nproc=None): def get_nproc(): r""" - Return the number of processors (cores) used in parallelized tensorial + Return the number of processes used in parallelized tensorial computations. EXAMPLES: @@ -184,7 +184,7 @@ def get_nproc(): sage: get_nproc() 1 - Asking for parallelization on 4 processors:: + Asking for parallelization on 4 cores:: sage: set_nproc(4) sage: get_nproc() From 3715880126fce2176ca4f12ab700d3e1cf5ea804 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Fri, 29 May 2015 11:25:24 +0200 Subject: [PATCH 0215/1872] Fix related to encoders_catalog file --- src/sage/coding/encoders_catalog.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/sage/coding/encoders_catalog.py diff --git a/src/sage/coding/encoders_catalog.py b/src/sage/coding/encoders_catalog.py new file mode 100644 index 00000000000..743e021b3a7 --- /dev/null +++ b/src/sage/coding/encoders_catalog.py @@ -0,0 +1,16 @@ +r""" +Index of encoders + +The ``codes.encoders`` object may be used to access the codes that Sage can build. + +- :func:`linear_code.LinearCodeGeneratorMatrixEncoder + + +.. NOTE:: + + To import these names into the global namespace, use: + + sage: from sage.coding.encoders_catalog import * +""" + +from linear_code import (LinearCodeGeneratorMatrixEncoder) From f447b9aaa45eb900812c8e21f7a6e601d1d422d2 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Fri, 29 May 2015 12:47:58 +0200 Subject: [PATCH 0216/1872] Updated documentation in encoder --- src/sage/coding/encoder.py | 42 ++++++++++++++--------------- src/sage/coding/encoders_catalog.py | 5 ++-- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 1b2be944dbf..1eea44019fd 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -21,10 +21,9 @@ class Encoder(SageObject): r""" - Abstract top-class for Encoder objects. + Abstract top-class for :class:`Encoder` objects. - This class contains all methods that can be used by encoders. - So, every encoder class should inherit from this abstract class. + Every encoder class should inherit from this abstract class. This class provides: @@ -34,21 +33,21 @@ class Encoder(SageObject): To implement an encoder, you need to: - - inherit from Encoder + - inherit from :class:`Encoder` - - call Encoder ``__init__`` method in the subclass constructor. Example: - ``super(SubclassName, self).__init__(code)``. + - call :class:`Encoder`'s :meth:`__init__` in the subclass constructor. + Example: ``super(SubclassName, self).__init__(code)``. By doing that, your subclass will have its ``code`` parameter initialized. You need of course to complete the constructor by adding any additional parameter needed to describe properly the code defined in the subclass. - Then, if the message space is a vectorial space, default implementation of ``encode`` and - ``unencode_nocheck`` methods are provided. These implementations rely on ``generator_matrix`` + Then, if the message space is a vectorial space, default implementation of :meth:`encode` and + :meth:`unencode_nocheck` methods are provided. These implementations rely on :meth:`generator_matrix` which you need to override to use the default implementations. If the message space is not of the form `F^k`, where `F` is a finite field, you cannot have a generator matrix. - In that case, you need to override ``encode`` and ``unencode_nocheck``. + In that case, you need to override :meth:`encode` and :meth:`unencode_nocheck`. Equality methods (``__eq__`` and ``__ne__``) might be useful for encoding in advanced codes constructions (like concatenated codes). If provided default implementation of @@ -61,13 +60,13 @@ class Encoder(SageObject): for a new encoder named ``EncName``, for code family ``CodeFam``, call it ``CodeFamEncNameEncoder``. - As Encoder is not designed to be implemented, it does not have any representation + As :class:`Encoder` is not designed to be implemented, it does not have any representation methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. """ def __init__(self, code): r""" - Initializes mandatory parameters for an Encoder object. + Initializes mandatory parameters for an :class:`Encoder` object. This method only exists for inheritance purposes as it initializes parameters that need to be known by every linear code. An abstract @@ -79,7 +78,7 @@ def __init__(self, code): EXAMPLES: - We first create a new Encoder subclass:: + We first create a new :class:`Encoder` subclass:: sage: class EncoderExample(sage.coding.encoder.Encoder): ....: def __init__(self, code): @@ -143,7 +142,8 @@ def encode(self, word): Transforms an element of the message space into an element of the code. This is a default implementation which assumes that the message - space of the encoder is a Vector Space. If this is not the case, + space of the encoder is `F^k`, where `F` is ``self.code().base_field()`` + and ``k`` is ``self.code().dimension()``. If this is not the case, this method should be overwritten by the subclass. INPUT: @@ -174,8 +174,8 @@ def unencode(self, c, nocheck=False, **kwargs): - ``c`` -- a vector of the same length as ``self`` over the base field of ``self`` - - ``nocheck`` -- (default: ``False``) checks if ``c`` is in self. If this is set - to True, the return value of this method is not guaranteed to be correct. + - ``nocheck`` -- (default: ``False``) checks if ``c`` is in ``self``. If this is set + to ``True``, the return value of this method is not guaranteed to be correct. OUTPUT: @@ -201,8 +201,8 @@ def unencode(self, c, nocheck=False, **kwargs): @cached_method def unencoder_matrix(self): r""" - Finds an information set for G, and returns the inverse of those - columns of G. + Finds an information set for the matrix ``G`` returned by :meth:`generator_matrix`, + and returns the inverse of that submatrix of ``G``. .. NOTE:: @@ -231,7 +231,7 @@ def unencode_nocheck(self, c, **kwargs): r""" Returns the message corresponding to ``c``. - When c is not a codeword, the output is unspecified. + When ``c`` is not a codeword, the output is unspecified. AUTHORS: @@ -293,7 +293,7 @@ def code(self): def message_space(self): r""" Returns the ambient space of allowed input to ``self.encode()``. - Note that the ``self.encode()`` is possibly a partial function over + Note that `self.encode()` is possibly a partial function over the ambient space. EXAMPLES:: @@ -309,10 +309,10 @@ def message_space(self): @abstract_method(optional = True) def generator_matrix(self): r""" - Returns a generator matrix of the associated code of self. + Returns a generator matrix of the associated code of ``self``. This is an abstract method and it should be implemented separately. - Reimplementing this for each subclass of Encoder is not mandatory + Reimplementing this for each subclass of :class:`Encoder` is not mandatory (as encoders with a polynomial message space, for instance, do not need a generator matrix). """ diff --git a/src/sage/coding/encoders_catalog.py b/src/sage/coding/encoders_catalog.py index 743e021b3a7..23c0ecb7998 100644 --- a/src/sage/coding/encoders_catalog.py +++ b/src/sage/coding/encoders_catalog.py @@ -1,10 +1,9 @@ r""" Index of encoders -The ``codes.encoders`` object may be used to access the codes that Sage can build. - -- :func:`linear_code.LinearCodeGeneratorMatrixEncoder +The ``codes.encoders`` object may be used to access the encoders that Sage can build. +- :func:`linear_code.LinearCodeGeneratorMatrixEncoder ` .. NOTE:: From 95a30aa57fc62f23a884790b57835d107d8bdeef Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 30 May 2015 22:26:07 -0700 Subject: [PATCH 0217/1872] Adding examples of categories and full coverage. --- src/sage/categories/cw_complexes.py | 55 +++++- src/sage/categories/examples/cw_complexes.py | 164 ++++++++++++++++++ src/sage/categories/examples/graphs.py | 122 +++++++++++++ src/sage/categories/examples/manifolds.py | 93 ++++++++++ src/sage/categories/graphs.py | 49 +++++- src/sage/categories/manifolds.py | 13 +- .../hyperbolic_space/hyperbolic_geodesic.py | 1 + .../hyperbolic_space/hyperbolic_model.py | 4 - 8 files changed, 490 insertions(+), 11 deletions(-) create mode 100644 src/sage/categories/examples/cw_complexes.py create mode 100644 src/sage/categories/examples/graphs.py create mode 100644 src/sage/categories/examples/manifolds.py diff --git a/src/sage/categories/cw_complexes.py b/src/sage/categories/cw_complexes.py index 764fac8b896..0193f7fe136 100644 --- a/src/sage/categories/cw_complexes.py +++ b/src/sage/categories/cw_complexes.py @@ -50,7 +50,7 @@ def _repr_object_names(self): EXAMPLES:: sage: from sage.categories.cw_complexes import CWComplexes - sage: CWComplexes() + sage: CWComplexes() # indirect doctest Category of CW complexes """ return "CW complexes" @@ -110,12 +110,22 @@ class FiniteDimensional(CategoryWithAxiom): class Finite(CategoryWithAxiom): """ Category of finite CW complexes. + + A finite CW complex is a CW complex with a finite number of cells. """ def extra_super_categories(self): """ Return the extra super categories of ``self``. A finite CW complex is a compact finite-dimensional CW complex. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: C = CWComplexes().Finite() + sage: C.extra_super_categories() + [Category of finite dimensional CW complexes, + Category of compact topological spaces] """ return [CWComplexes().FiniteDimensional(), Sets().Topological().Compact()] @@ -124,8 +134,16 @@ class ParentMethods: def dimension(self): """ Return the dimension of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: X.dimension() + 2 """ - return max(c.dimension() for c in self.cells()) + C = self.cells() + return max(c.dimension() for d in C.keys() for c in C[d]) def Compact_extra_super_categories(self): """ @@ -140,23 +158,54 @@ def Compact_extra_super_categories(self): EXAMPLES:: sage: from sage.categories.cw_complexes import CWComplexes - sage: CWComplexes().Compact() + sage: CWComplexes().Compact() # indirect doctest Category of finite finite dimensional CW complexes sage: CWComplexes().Compact() is CWComplexes().Finite() True """ return (Sets().Finite(),) + class ElementMethods: + @abstract_method + def dimension(self): + """ + Return the dimension of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: X.an_element().dimension() + 2 + """ + class ParentMethods: @abstract_method def dimension(self): """ Return the dimension of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: X.dimension() + 2 """ @abstract_method(optional=True) def cells(self): """ Return the cells of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: C = X.cells() + sage: sorted((d, C[d]) for d in C.keys()) + [(0, (0-cell v,)), + (1, (0-cell e1, 0-cell e2)), + (2, (2-cell f,))] """ diff --git a/src/sage/categories/examples/cw_complexes.py b/src/sage/categories/examples/cw_complexes.py new file mode 100644 index 00000000000..8c33b303e61 --- /dev/null +++ b/src/sage/categories/examples/cw_complexes.py @@ -0,0 +1,164 @@ +""" +Examples of CW complexes +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element import Element +from sage.categories.cw_complexes import CWComplexes +from sage.rings.integer import Integer +from sage.rings.all import QQ +from sage.sets.family import Family + +class Surface(UniqueRepresentation, Parent): + r""" + An example of a CW complex: a (2-dimensional) surface. + + This class illustrates a minimal implementation of a CW complex. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example(); X + An example of a CW complex: the surface given by the boundary map (1, 2, 1, 2) + + sage: X.category() + Category of finite finite dimensional CW complexes + + We conclude by running systematic tests on this manifold:: + + sage: TestSuite(X).run() + """ + def __init__(self, bdy=(1, 2, 1, 2)): + r""" + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example((1, 2)); X + An example of a CW complex: the surface given by the boundary map (1, 2) + + TESTS:: + + sage: TestSuite(X).run() + """ + self._bdy = bdy + self._edges = frozenset(bdy) + Parent.__init__(self, category=CWComplexes().Finite()) + + def _repr_(self): + r""" + TESTS:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: CWComplexes().example() + An example of a CW complex: the surface given by the boundary map (1, 2, 1, 2) + """ + return "An example of a CW complex: the surface given by the boundary map {}".format(self._bdy) + + def cells(self): + """ + Return the cells of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: C = X.cells() + sage: sorted((d, C[d]) for d in C.keys()) + [(0, (0-cell v,)), + (1, (0-cell e1, 0-cell e2)), + (2, (2-cell f,))] + """ + d = {0: (self.element_class(self, 0, 'v'),)} + d[1] = tuple([self.element_class(self, 0, 'e'+str(e)) for e in self._edges]) + d[2] = (self.an_element(),) + return Family(d) + + def an_element(self): + r""" + Return an element of the CW complex, as per + :meth:`Sets.ParentMethods.an_element`. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: X.an_element() + 2-cell f + """ + return self.element_class(self, 2, 'f') + + class Element(Element): + """ + A cell in a CW complex. + """ + def __init__(self, parent, dim, name): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: f = X.an_element() + sage: TestSuite(f).run() + """ + Element.__init__(self, parent) + self._dim = dim + self._name = name + + def _repr_(self): + """ + Return a string represention of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: X.an_element() + 2-cell f + """ + return "{}-cell {}".format(self._dim, self._name) + + def __eq__(self, other): + """ + Check equality. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: f = X.an_element() + sage: f == X(2, 'f') + True + sage: e1 = X(1, 'e1') + sage: e1 == f + False + """ + return (isinstance(other, Surface.Element) + and self.parent() is other.parent() + and self._dim == other._dim + and self._name == other._name) + + def dimension(self): + """ + Return the dimension of ``self``. + + EXAMPLES:: + + sage: from sage.categories.cw_complexes import CWComplexes + sage: X = CWComplexes().example() + sage: f = X.an_element() + sage: f.dimension() + 2 + """ + return self._dim + +Example = Surface + diff --git a/src/sage/categories/examples/graphs.py b/src/sage/categories/examples/graphs.py new file mode 100644 index 00000000000..9c1e1eddb7e --- /dev/null +++ b/src/sage/categories/examples/graphs.py @@ -0,0 +1,122 @@ +""" +Examples of graphs +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element_wrapper import ElementWrapper +from sage.categories.graphs import Graphs +from sage.rings.all import QQ + +class Cycle(UniqueRepresentation, Parent): + r""" + An example of a graph: the cycle of length `n`. + + This class illustrates a minimal implementation of a graph. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example(); C + An example of a graph: the 5-cycle + + sage: C.category() + Category of graphs + + We conclude by running systematic tests on this graph:: + + sage: TestSuite(C).run() + """ + def __init__(self, n=5): + r""" + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example(6); C + An example of a graph: the 6-cycle + + TESTS:: + + sage: TestSuite(C).run() + """ + self._n = n + Parent.__init__(self, category=Graphs()) + + def _repr_(self): + r""" + TESTS:: + + sage: from sage.categories.graphs import Graphs + sage: Graphs().example() + An example of a graph: the 5-cycle + """ + return "An example of a graph: the {}-cycle".format(self._n) + + def an_element(self): + r""" + Return an element of the graph, as per + :meth:`Sets.ParentMethods.an_element`. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: C.an_element() + 0 + """ + return self(0) + + def vertices(self): + """ + Return the vertices of ``self``. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: C.vertices() + [0, 1, 2, 3, 4] + """ + return [self(i) for i in range(self._n)] + + def edges(self): + """ + Return the edges of ``self``. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: C.edges() + [(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)] + """ + return [self( (i, (i+1) % self._n) ) for i in range(self._n)] + + class Element(ElementWrapper): + def dimension(self): + """ + Return the dimension of ``self``. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: e = C.edges()[0] + sage: e.dimension() + 2 + sage: v = C.vertices()[0] + sage: v.dimension() + 1 + """ + if isinstance(self.value, tuple): + return 2 + return 1 + +Example = Cycle + diff --git a/src/sage/categories/examples/manifolds.py b/src/sage/categories/examples/manifolds.py new file mode 100644 index 00000000000..68d428856c2 --- /dev/null +++ b/src/sage/categories/examples/manifolds.py @@ -0,0 +1,93 @@ +""" +Examples of manifolds +""" +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element_wrapper import ElementWrapper +from sage.categories.manifolds import Manifolds +from sage.rings.all import QQ + +class Plane(UniqueRepresentation, Parent): + r""" + An example of a manifold: the `n`-dimensional plane. + + This class illustrates a minimal implementation of a manifold. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: M = Manifolds().example(); M + An example of a manifold: the 3-dimensional plane + + sage: M.category() + Category of manifolds + + We conclude by running systematic tests on this manifold:: + + sage: TestSuite(M).run() + """ + + def __init__(self, n=3): + r""" + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: M = Manifolds().example(6); M + An example of a manifold: the 6-dimensional plane + + TESTS:: + + sage: TestSuite(M).run() + """ + self._n = n + Parent.__init__(self, category=Manifolds()) + + def _repr_(self): + r""" + TESTS:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().example() + An example of a manifold: the 3-dimensional plane + """ + return "An example of a manifold: the {}-dimensional plane".format(self._n) + + def dimension(self): + """ + Return the dimension of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: M = Manifolds().example() + sage: M.dimension() + 3 + """ + return self._n + + def an_element(self): + r""" + Return an element of the manifold, as per + :meth:`Sets.ParentMethods.an_element`. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: M = Manifolds().example() + sage: M.an_element() + (0, 0, 0) + """ + zero = QQ.zero() + return self(tuple([zero]*self._n)) + + Element = ElementWrapper + +Example = Plane + diff --git a/src/sage/categories/graphs.py b/src/sage/categories/graphs.py index 275bec76808..1be42bb94a5 100644 --- a/src/sage/categories/graphs.py +++ b/src/sage/categories/graphs.py @@ -8,7 +8,7 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -#from sage.misc.abstract_method import abstract_method +from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton from sage.categories.simplicial_complexes import SimplicialComplexes @@ -39,9 +39,42 @@ def super_categories(self): return [SimplicialComplexes()] class ParentMethods: + @abstract_method + def vertices(self): + """ + Return the vertices of ``self``. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: C.vertices() + [0, 1, 2, 3, 4] + """ + + @abstract_method + def edges(self): + """ + Return the edges of ``self``. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: C.edges() + [(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)] + """ + def dimension(self): """ Return the dimension of ``self`` as a CW complex. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: C.dimension() + 1 """ if self.edges(): return 1 @@ -50,12 +83,26 @@ def dimension(self): def facets(self): """ Return the facets of ``self``. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: C.facets() + [(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)] """ return self.edges() def faces(self): """ Return the faces of ``self``. + + EXAMPLES:: + + sage: from sage.categories.graphs import Graphs + sage: C = Graphs().example() + sage: sorted(C.faces(), key=lambda x: (x.dimension(), x.value)) + [0, 1, 2, 3, 4, (0, 1), (1, 2), (2, 3), (3, 4), (4, 0)] """ return set(self.edges()).union(self.vertices()) diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index 67708e7858d..775567230cf 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -22,9 +22,9 @@ class Manifolds(Category_singleton): r""" The category of manifolds over any field. - Let `k` be a field. A `k`-*manifold* `M` of dimension `d` is a - second countable Hausdorff space such that the neighborhood of - any point `x \in M` is homeomorphic to `k^b` for some `b \leq d`. + Let `k` be a topological field. A `d`-dimensional `k`-*manifold* `M` + is a second countable Hausdorff space such that the neighborhood of + any point `x \in M` is homeomorphic to `k^d`. EXAMPLES:: @@ -71,6 +71,13 @@ class ParentMethods: def dimension(self): """ Return the dimension of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: M = Manifolds().example() + sage: M.dimension() + 3 """ class SubcategoryMethods: diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index 73fd2c6414e..eb5d473efa8 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -31,6 +31,7 @@ .. TODO:: Implement a parent for all geodesics of the hyperbolic plane? + Or implement geodesics as a parent in the subobjects category? """ diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py index 73cbf2eee26..6717d0206fe 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py @@ -65,10 +65,6 @@ False sage: U.boundary_point_in_model(2) True - -.. TODO:: - - Implement a category for metric spaces. """ #*********************************************************************** From 55d9a5ef6747d4cac7df581af41c126a676fa280 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Sun, 31 May 2015 22:23:34 +0200 Subject: [PATCH 0218/1872] #18338 coefficients are integers. --- src/sage/combinat/combinat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index ef788e7ccc0..300d6ddf0f0 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -2739,9 +2739,9 @@ def bell_polynomial(n, k): for part, count in p.to_exp_dict().iteritems(): factorial_product *= factorial(count) power_factorial_product *= factorial(part)**count - coefficient = factorial(n) / (factorial_product * power_factorial_product) + coefficient = factorial(n) // (factorial_product * power_factorial_product) result += coefficient * prod([vars[i - 1] for i in p]) - return R(result) + return result def fibonacci_sequence(start, stop=None, algorithm=None): r""" From c6a01f816703c97cb3c2845c4d8c557567c3d0e7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 09:55:37 +0200 Subject: [PATCH 0219/1872] allow kwargs in CartesianProduct (to be used in inherited classes) --- src/sage/sets/cartesian_product.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index a208f257250..64246e9832d 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -52,7 +52,7 @@ class CartesianProduct(UniqueRepresentation, Parent): .. automethod:: _cartesian_product_of_elements """ - def __init__(self, sets, category, flatten=False): + def __init__(self, sets, category, flatten=False, **kwargs): r""" INPUT: @@ -62,6 +62,8 @@ def __init__(self, sets, category, flatten=False): ``flatten`` is current ignored, and reserved for future use. + No other keyword arguments (``kwargs``) are accepted. + TESTS:: sage: from sage.sets.cartesian_product import CartesianProduct @@ -71,7 +73,14 @@ def __init__(self, sets, category, flatten=False): sage: C.an_element() (1/2, 1, 1) sage: TestSuite(C).run() + sage: cartesian_product([ZZ, ZZ], blub=None) + Traceback (most recent call last): + ... + TypeError: unknown parameters: blub """ + if kwargs: + raise TypeError('unknown parameters: %s' % + ', '.join(str(k) for k in kwargs.iterkeys())) self._sets = tuple(sets) Parent.__init__(self, category=category) From 85f44f3001f43b68ab7829b8356a56937ef10ba2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 09:56:21 +0200 Subject: [PATCH 0220/1872] pass on keyword arguments in cartesian product of the sets category --- src/sage/categories/sets_cat.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index a38a8311b21..e3307fd9464 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1418,9 +1418,6 @@ def cartesian_product(*parents, **kwargs): """ category = kwargs.pop('category', None) extra_category = kwargs.pop('extra_category', None) - if kwargs: - raise TypeError('unknown parameters: %s' % - ', '.join(str(k) for k in kwargs.iterkeys())) category = category or cartesian_product.category_from_parents(parents) if extra_category: @@ -1428,7 +1425,7 @@ def cartesian_product(*parents, **kwargs): category = tuple(category) + (extra_category,) else: category = category & extra_category - return parents[0].CartesianProduct(parents, category=category) + return parents[0].CartesianProduct(parents, category=category, **kwargs) def algebra(self, base_ring, category=None): """ From ba5dab93e6c7b33eeefc0c937dd2a7d11098807a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 09:57:04 +0200 Subject: [PATCH 0221/1872] update docstring and complete doctests --- src/sage/categories/sets_cat.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index e3307fd9464..4913a2d6caa 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1383,6 +1383,10 @@ def cartesian_product(*parents, **kwargs): added to the cartesian product additionally to the categories obtained from the parents. + - other keyword arguments will passed on to the class used + for this cartesian product (see also + :class:`~sage.sets.cartesian_product.CartesianProduct`). + OUTPUT: The cartesian product. @@ -1411,10 +1415,21 @@ def cartesian_product(*parents, **kwargs): sage: cartesian_product([ZZ, ZZ], category=Sets()).category() Category of sets - sage: cartesian_product([ZZ, ZZ], blub=None).category() - Traceback (most recent call last) - ... - TypeError: unknown parameters: blub + sage: cartesian_product([ZZ, ZZ]).category() + Join of + Category of rings and + Category of Cartesian products of distributive magmas and additive magmas and + Category of Cartesian products of monoids and + Category of Cartesian products of commutative additive groups and + Category of Cartesian products of enumerated sets + sage: cartesian_product([ZZ, ZZ], extra_category=Posets()).category() + Join of + Category of rings and + Category of Cartesian products of distributive magmas and additive magmas and + Category of Cartesian products of monoids and + Category of Cartesian products of commutative additive groups and + Category of posets and + Category of Cartesian products of enumerated sets """ category = kwargs.pop('category', None) extra_category = kwargs.pop('extra_category', None) From 55a7020df64790be37b1bb4527f74444bc21a602 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 13:12:20 +0200 Subject: [PATCH 0222/1872] create class for cartesian products of posets --- src/sage/sets/cartesian_product.py | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 64246e9832d..a820323266b 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -285,3 +285,37 @@ def __iter__(self): 1 """ return iter(self.value) + + +class CartesianProductPosets(CartesianProduct): + r""" + + .. SEEALSO: + + :class:`CartesianProduct` + """ + + def __init__(self, sets, category, order, **kwargs): + r""" + See :class:`CartesianProductPosets` for details, + + TESTS:: + + sage: P = Poset((srange(3), lambda left, right: left <= right)) + sage: P.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: Cl = cartesian_product((P, P), order='notexisting') + Traceback (most recent call last): + ... + ValueError: No order 'notexisting' known. + """ + if isinstance(order, str): + try: + self._le_ = getattr(self, 'le_' + order) + except AttributeError: + raise ValueError("No order '%s' known." % (order,)) + else: + self._le_ = order + + super(CartesianProductPosets, self).__init__( + sets, category, **kwargs) + From 6ed924696625f67a5e0e814c758ca5b53885bdcc Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 13:12:39 +0200 Subject: [PATCH 0223/1872] method "le" --- src/sage/sets/cartesian_product.py | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index a820323266b..4adeab61471 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -319,3 +319,41 @@ def __init__(self, sets, category, order, **kwargs): super(CartesianProductPosets, self).__init__( sets, category, **kwargs) + + def le(self, left, right): + r""" + Tests if ``left`` is smaller or equal to ``right``. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the order defined on creation of this + cartesian product. See :class:`CartesianProductPosets` + + EXAMPLES:: + + sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C.le(C((1/3, 2)), C((2, 1/3))) + True + sage: C.le(C((2, 1/3)), C((1/3, 2))) + False + sage: C.le(C((1/3, 2)), C((2, 2))) + True + sage: C.le(C((2, 2)), C((1/3, 2))) + False + """ + return self._le_(left, right) + From 4c9f72ce4920838b49e87bc8efd05ce6c6aecdef Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 13:13:12 +0200 Subject: [PATCH 0224/1872] methods for comparing lexicographically and component-wise --- src/sage/sets/cartesian_product.py | 104 +++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 4adeab61471..35d5f64c036 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -357,3 +357,107 @@ def le(self, left, right): """ return self._le_(left, right) + + def le_lex(self, left, right): + r""" + Tests if ``left`` is lexicographically smaller or equal + to ``right``. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: P = Poset((srange(2), lambda left, right: left <= right)) + sage: P.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: Q = cartesian_product((P, P), order='lex') + sage: T = [Q((0, 0)), Q((1, 1)), Q((0, 1)), Q((1, 0))] + sage: for a in T: + ....: for b in T: + ....: assert(Q.le(a, b) == (a <= b)) + ....: print '%s <= %s = %s' % (a, b, a <= b) + (0, 0) <= (0, 0) = True + (0, 0) <= (1, 1) = True + (0, 0) <= (0, 1) = True + (0, 0) <= (1, 0) = True + (1, 1) <= (0, 0) = False + (1, 1) <= (1, 1) = True + (1, 1) <= (0, 1) = False + (1, 1) <= (1, 0) = False + (0, 1) <= (0, 0) = False + (0, 1) <= (1, 1) = True + (0, 1) <= (0, 1) = True + (0, 1) <= (1, 0) = True + (1, 0) <= (0, 0) = False + (1, 0) <= (1, 1) = True + (1, 0) <= (0, 1) = False + (1, 0) <= (1, 0) = True + """ + for l, r, S in \ + zip(left.value, right.value, self.cartesian_factors()): + if l == r: + continue + if S.le(l, r): + return True + if S.le(r, l): + return False + return True # equal + + + def le_components(self, left, right): + r""" + Tests if ``left`` is component-wise smaller or equal + to ``right``. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + A boolean. + + The comparison is ``True`` if the result of the + comparision in each component is ``True``. + + EXAMPLES:: + + sage: P = Poset((srange(2), lambda left, right: left <= right)) + sage: P.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: Q = cartesian_product((P, P), order='components') + sage: T = [Q((0, 0)), Q((1, 1)), Q((0, 1)), Q((1, 0))] + sage: for a in T: + ....: for b in T: + ....: assert(Q.le(a, b) == (a <= b)) + ....: print '%s <= %s = %s' % (a, b, a <= b) + (0, 0) <= (0, 0) = True + (0, 0) <= (1, 1) = True + (0, 0) <= (0, 1) = True + (0, 0) <= (1, 0) = True + (1, 1) <= (0, 0) = False + (1, 1) <= (1, 1) = True + (1, 1) <= (0, 1) = False + (1, 1) <= (1, 0) = False + (0, 1) <= (0, 0) = False + (0, 1) <= (1, 1) = True + (0, 1) <= (0, 1) = True + (0, 1) <= (1, 0) = False + (1, 0) <= (0, 0) = False + (1, 0) <= (1, 1) = True + (1, 0) <= (0, 1) = False + (1, 0) <= (1, 0) = True + """ + return all( + S.le(l, r) + for l, r, S in + zip(left.value, right.value, self.cartesian_factors())) + From e589e9b6f474c1ae87781e135a462c8717c27700 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 13:14:10 +0200 Subject: [PATCH 0225/1872] create Element: implement <=, <, >=, > --- src/sage/sets/cartesian_product.py | 185 +++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 35d5f64c036..7e225ee507c 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -461,3 +461,188 @@ def le_components(self, left, right): for l, r, S in zip(left.value, right.value, self.cartesian_factors())) + + class Element(CartesianProduct.Element): + + def _le_(self, other): + r""" + Return if this element is less or equal to ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method calls :meth:`CartesianProductPosets.le`. Override + it in inherited class to change this. + + It can be assumed that this element and ``other`` have + the same parent. + + TESTS:: + + sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) <= C((2, 1/3)) # indirect doctest + True + sage: C((1/3, 2)) <= C((2, 2)) # indirect doctest + True + """ + return self.parent().le(self, other) + + + def __le__(self, other): + r""" + Return if this element is less than or equal to ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the coercion framework to find a + suitable common parent. + + This method can be deleted once :trac:`10130` is fixed and + provides these methods automatically. + + TESTS:: + + sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) <= C((2, 1/3)) + True + sage: C((1/3, 2)) <= C((2, 2)) + True + """ + from sage.structure.element import have_same_parent + if have_same_parent(self, other): + return self._le_(other) + + from sage.structure.element import get_coercion_model + import operator + try: + return get_coercion_model().bin_op(self, other, operator.le) + except TypeError: + return False + + + def __ge__(self, other): + r""" + Return if this element is greater than or equal to ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the coercion framework to find a + suitable common parent. + + This method can be deleted once :trac:`10130` is fixed and + provides these methods automatically. + + TESTS:: + + sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) >= C((2, 1/3)) + False + sage: C((1/3, 2)) >= C((2, 2)) + False + """ + return other.__le__(self) + + + def __lt__(self, other): + r""" + Return if this element is less than ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the coercion framework to find a + suitable common parent. + + This method can be deleted once :trac:`10130` is fixed and + provides these methods automatically. + + TESTS:: + + sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) < C((2, 1/3)) + True + sage: C((1/3, 2)) < C((2, 2)) + True + """ + return not self == other and self.__le__(other) + + + def __gt__(self, other): + r""" + Return if this element is greater than ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the coercion framework to find a + suitable common parent. + + This method can be deleted once :trac:`10130` is fixed and + provides these methods automatically. + + TESTS:: + + sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) > C((2, 1/3)) + False + sage: C((1/3, 2)) > C((2, 2)) + False + """ + return not self == other and other.__le__(self) From 69335cc0f8d0e4344804b3ca1de76471a8a91574 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 13:14:29 +0200 Subject: [PATCH 0226/1872] write a class description --- src/sage/sets/cartesian_product.py | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 7e225ee507c..19b84870fc6 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -4,6 +4,7 @@ AUTHORS: - Nicolas Thiery (2010-03): initial version +- Daniel Krenn (2015-06): cartesian products for posets with different orders """ #***************************************************************************** @@ -289,6 +290,47 @@ def __iter__(self): class CartesianProductPosets(CartesianProduct): r""" + A class implementing cartesian products of posets (and elements + thereof). Compared to :class:`CartesianProduct` you are able to + specify an order for comparison of the elements. + + INPUT: + + - ``sets`` -- a tuple of parents. + + - ``category`` -- a subcategory of + ``Sets().CartesianProducts() & Posets()``. + + - ``order`` -- a string or function specifing an order less or equal. + It can be one of the following: + + - ``'lex'`` -- elements are ordered lexicographically. + + - ``'components'`` -- an element is less or equal to another + element, if less or equal is true for all its components + (cartesian factors). + + - a function ``order_le(left, right)``, which performs the comparison. + + Other keyword arguments (``kwargs``) are passed to the constructor + of :class:`CartesianProduct`. + + EXAMPLES:: + + sage: P = Poset((srange(3), lambda left, right: left <= right)) + sage: P.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets + sage: Cl = cartesian_product((P, P), order='lex') + sage: Cl((1, 1)) <= Cl((2, 0)) + True + sage: Cc = cartesian_product((P, P), order='components') + sage: Cc((1, 1)) <= Cc((2, 0)) + False + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: Cs = cartesian_product((P, P), order=le_sum) + sage: Cs((1, 1)) <= Cs((2, 0)) + True .. SEEALSO: From 8fea2307e9cfd93edea836222a73d14da502b2d5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 15:27:41 +0200 Subject: [PATCH 0227/1872] create cartesian product of growth groups --- src/sage/groups/asymptotic_growth_group.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index c82db83aa2d..1e903c4e341 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -17,6 +17,7 @@ - Benjamin Hackl (2015-01): initial version - Daniel Krenn (2015-05-29): initial version and review +- Daniel Krenn (2015-06-02): cartesian products """ #***************************************************************************** @@ -32,6 +33,20 @@ import sage +from sage.sets.cartesian_product import CartesianProductPosets +class CartesianProductGrowthGroups(CartesianProductPosets): + r""" + A cartesian product of growth groups. + .. SEEALSO: + + :class:`~sage.sets.cartesian_product.CartesianProduct`, + :class:`~sage.sets.cartesian_product.CartesianProductPosets`. + """ + + +CartesianProductGrowthGroups.CartesianProduct = CartesianProductGrowthGroups + + class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): r""" An abstract implementation of a generic growth element. @@ -769,6 +784,9 @@ def _coerce_map_from_(self, S): return True + CartesianProduct = CartesianProductGrowthGroups + + class MonomialGrowthElement(GenericGrowthElement): r""" An implementation of monomial growth elements. From bfe9aaab22dbafc042f600655e306debc1f0ea91 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 15:28:29 +0200 Subject: [PATCH 0228/1872] introduce _repr_short_ for nicer representations --- src/sage/groups/asymptotic_growth_group.py | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 1e903c4e341..779fdc8dc80 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -43,6 +43,12 @@ class CartesianProductGrowthGroups(CartesianProductPosets): :class:`~sage.sets.cartesian_product.CartesianProductPosets`. """ + def _repr_(self): + return 'Growth Group ' + self._repr_short_() + + + def _repr_short_(self): + return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) CartesianProductGrowthGroups.CartesianProduct = CartesianProductGrowthGroups @@ -543,6 +549,10 @@ def _repr_(self): return 'Generic Growth Group over %s' % (self.base(),) + def _repr_short_(self): + return 'GenericGrowthGroup(%s)' % (self.base(),) + + def __hash__(self): r""" Return the hash of this group. @@ -1144,6 +1154,21 @@ def _repr_(self): return 'Monomial Growth Group in %s over %s' % (self._var_, self.base()) + def _repr_short_(self): + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ + base = self.base() + if base == ZZ: + repr_base = 'ZZ' + elif base == QQ: + repr_base = 'QQ' + else: + repr_base == repr(base) + if ' ' in repr_base: + repr_base = '(' + repr_base + ')' + return '%s^%s' % (self._var_, repr_base) + + def __hash__(self): r""" Return the hash of this group. From d8b29451bb9f2e5c0e577445dcd00042f56b2495 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 15:28:53 +0200 Subject: [PATCH 0229/1872] override repr of cartesian product elements --- src/sage/groups/asymptotic_growth_group.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 779fdc8dc80..36143f53d7e 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -50,6 +50,13 @@ def _repr_(self): def _repr_short_(self): return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) + class Element(CartesianProductPosets.Element): + def _repr_(self): + r""" + """ + return ' * '.join(repr(v) for v in self.value) + + CartesianProductGrowthGroups.CartesianProduct = CartesianProductGrowthGroups From 8ebbe9dd177596bc2de97c41801d98eedd143dbc Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 15:29:05 +0200 Subject: [PATCH 0230/1872] add examples --- src/sage/groups/asymptotic_growth_group.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 36143f53d7e..148ef2c7184 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -37,6 +37,28 @@ class CartesianProductGrowthGroups(CartesianProductPosets): r""" A cartesian product of growth groups. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: C = cartesian_product([P, L], order='lex'); C + Growth Group x^QQ * log(x)^ZZ + sage: C.an_element() + x^(1/2) * log(x) + + :: + + sage: Px = agg.MonomialGrowthGroup(QQ, 'x') + sage: Lx = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: Cx = cartesian_product([Px, Lx], order='lex') + sage: Py = agg.MonomialGrowthGroup(QQ, 'y') + sage: C = cartesian_product([Cx, Py], order='components'); C + Growth Group x^QQ * log(x)^ZZ * y^QQ + sage: C.an_element() + x^(1/2) * log(x) * y^(1/2) + .. SEEALSO: :class:`~sage.sets.cartesian_product.CartesianProduct`, From c35bd864269ad55baac18c649741fa445aa6cf4f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 16:07:46 +0200 Subject: [PATCH 0231/1872] docstrings for _repr*_ methods --- src/sage/groups/asymptotic_growth_group.py | 110 ++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 148ef2c7184..f9107a1598f 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -66,15 +66,72 @@ class CartesianProductGrowthGroups(CartesianProductPosets): """ def _repr_(self): + r""" + A representation string for this cartesian product of growth groups. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: cartesian_product([P, L], order='lex')._repr_() + 'Growth Group x^QQ * log(x)^ZZ' + """ return 'Growth Group ' + self._repr_short_() def _repr_short_(self): + r""" + A short (shorter than :meth:`._repr_`) representation string + for this cartesian product of growth groups. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: cartesian_product([P, L], order='lex')._repr_short_() + 'x^QQ * log(x)^ZZ' + """ return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) + class Element(CartesianProductPosets.Element): def _repr_(self): r""" + A representation string for this cartesian product element. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: cartesian_product([P, L], order='lex').an_element()._repr_() + 'x^(1/2) * log(x)' """ return ' * '.join(repr(v) for v in self.value) @@ -579,6 +636,28 @@ def _repr_(self): def _repr_short_(self): + r""" + A short (shorter than :meth:`._repr_`) representation string + for this abstract growth group. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + .. NOTE:: + + This is used in :class:`CartesianProductGrowthGroups`. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: agg.GenericGrowthGroup(QQ)._repr_short_() + 'GenericGrowthGroup(Rational Field)' + """ return 'GenericGrowthGroup(%s)' % (self.base(),) @@ -1184,17 +1263,46 @@ def _repr_(self): def _repr_short_(self): + r""" + A short (shorter than :meth:`._repr_`) representation string + for this monomial growth group. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + .. NOTE:: + + This is used in :class:`CartesianProductGrowthGroups`. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: agg.MonomialGrowthGroup(ZZ, 'a')._repr_short_() + 'a^ZZ' + sage: agg.MonomialGrowthGroup(QQ, 'a')._repr_short_() + 'a^QQ' + sage: agg.MonomialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() + 'a^(Univariate Polynomial Ring in x over Rational Field)' + """ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + base = self.base() if base == ZZ: repr_base = 'ZZ' elif base == QQ: repr_base = 'QQ' else: - repr_base == repr(base) + repr_base = repr(base) + if ' ' in repr_base: repr_base = '(' + repr_base + ')' + return '%s^%s' % (self._var_, repr_base) From 9352031b310b81f83c09ecac11b1ce15163f55f9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 2 Jun 2015 16:10:08 +0200 Subject: [PATCH 0232/1872] change one word in docstring --- src/sage/sets/cartesian_product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 19b84870fc6..895289dfe9c 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -308,7 +308,7 @@ class CartesianProductPosets(CartesianProduct): - ``'components'`` -- an element is less or equal to another element, if less or equal is true for all its components - (cartesian factors). + (cartesian projections). - a function ``order_le(left, right)``, which performs the comparison. From b6e225a8dd952fb267c488c7cc97cfbd56823fb2 Mon Sep 17 00:00:00 2001 From: Salvatore Stella Date: Tue, 2 Jun 2015 16:42:51 +0200 Subject: [PATCH 0233/1872] Add d-vector to ClusterSeed --- .../cluster_algebra_quiver/cluster_seed.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index c983bebb262..7e87fa4308e 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -605,6 +605,24 @@ def g_matrix(self,ignore_coefficients=False): raise ValueError("No principal coefficients initialized. Use principal_extension, or ignore_coefficients to ignore this.") return matrix( [ self.g_vector(k,ignore_coefficients=ignore_coefficients) for k in range(self._n) ] ).transpose() + def d_vector(self, k): + r""" + Returns the ``k``-th *d-vector* of ``self``. This is the exponent vector + of the denominator of the ``k``-th cluster variable. + + EXAMPLES:: + + sage: S = ClusterSeed(['A',3]) + sage: S.mutate([2,1,2]) + sage: [ S.d_vector(k) for k in range(3) ] + [(-1, 0, 0), (0, 1, 1), (0, 1, 0)] + """ + from sage.modules.free_module_element import vector + f = self.cluster_variable(k) + if f in self._R.gens(): + return -vector(f.numerator().monomials()[0].exponents()[0][:self._n]) + return vector(f.denominator().monomials()[0].exponents()[0][:self._n]) + def c_vector(self,k,ignore_coefficients=False): r""" Returns the ``k``-th *c-vector* of ``self``. It is obtained as the From d18903f10330bced19b96e56df66e38222312a0a Mon Sep 17 00:00:00 2001 From: Salvatore Stella Date: Tue, 2 Jun 2015 16:49:46 +0200 Subject: [PATCH 0234/1872] Add d-matrix to ClusterSeed --- .../cluster_algebra_quiver/cluster_seed.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 7e87fa4308e..7e84da51aed 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -623,6 +623,26 @@ def d_vector(self, k): return -vector(f.numerator().monomials()[0].exponents()[0][:self._n]) return vector(f.denominator().monomials()[0].exponents()[0][:self._n]) + def d_matrix(self): + r""" + Returns the matrix of all *d-vectors* of ``self``. This is the matrix + having as columns the exponent vectors of the denominator of the cluster + variables of ``self``.. + + EXAMPLES:: + + sage: S = ClusterSeed(['A',3]) + sage: S.mutate([2,1,2]) + sage: S.d_matrix() + [-1 0 0] + [ 0 1 1] + [ 0 1 0] + + """ + from sage.matrix.all import matrix + D = [ self.d_vector(i) for i in range(self._n) ] + return matrix(D).transpose() + def c_vector(self,k,ignore_coefficients=False): r""" Returns the ``k``-th *c-vector* of ``self``. It is obtained as the From b2a8278e1d7a9e6d7f637ae5b5eaa92a315af258 Mon Sep 17 00:00:00 2001 From: Salvatore Stella Date: Tue, 2 Jun 2015 19:28:04 +0200 Subject: [PATCH 0235/1872] Removed trailing spaces --- .../combinat/cluster_algebra_quiver/cluster_seed.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 7e84da51aed..6f8bab2de72 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -609,9 +609,9 @@ def d_vector(self, k): r""" Returns the ``k``-th *d-vector* of ``self``. This is the exponent vector of the denominator of the ``k``-th cluster variable. - + EXAMPLES:: - + sage: S = ClusterSeed(['A',3]) sage: S.mutate([2,1,2]) sage: [ S.d_vector(k) for k in range(3) ] @@ -627,17 +627,16 @@ def d_matrix(self): r""" Returns the matrix of all *d-vectors* of ``self``. This is the matrix having as columns the exponent vectors of the denominator of the cluster - variables of ``self``.. - + variables of ``self``. + EXAMPLES:: - + sage: S = ClusterSeed(['A',3]) sage: S.mutate([2,1,2]) sage: S.d_matrix() [-1 0 0] [ 0 1 1] [ 0 1 0] - """ from sage.matrix.all import matrix D = [ self.d_vector(i) for i in range(self._n) ] From df182e500b4723fbf2a87aa4b565293397d8f904 Mon Sep 17 00:00:00 2001 From: Vincent Pilaud Date: Wed, 3 Jun 2015 12:10:54 -0500 Subject: [PATCH 0236/1872] I changed the name of the function fan to d_vector_fan. This function now allows cyclic initial seeds. I merged with #18588 which implements d_matrix. I also added a function g_vector_fan. --- .../combinat/cluster_algebra_quiver/quiver.py | 113 +++++++++++------- 1 file changed, 72 insertions(+), 41 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 3c9b4a57b56..4c50e2c7ae0 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -1599,71 +1599,102 @@ def is_mutation_finite( self, nr_of_checks=None, return_path=False ): else: return is_finite - def fan(self): - """ - Return the cluster fan associated with the quiver. - - This is a complete simplicial (and even smooth) fan. It only makes - sense for acyclic quivers of finite type. + def d_vector_fan(self): + r""" + Return the d-vector fan associated with the quiver. - This fan is defined using the denominator vectors of the cluster - variables. Cones are in correspondance with clusters and - rays with cluster variables. + It is the fan whose maximal cones are generated by the d-matrices of the + clusters. - More precisely, starting from the seed made of the quiver `Q` - with `n` vertices and variables `x_1, ..., x_n`, one obtains - by iterating mutation a finite set of seeds. Each of these - seeds is made of a quiver and `n` cluster variables (that form - a cluster). - - Each cluster variable is mapped to the vector - `d = (d_1, d_2, \ldots, d_n) \in \ZZ^n`, where + This is a complete simplicial fan (and even smooth when the initial quiver + is acyclic). It only makes sense for quivers of finite type. + + EXAMPLES:: + + sage: Fd = ClusterQuiver([[1,2]]).d_vector_fan(); Fd + Rational polyhedral fan in 2-d lattice N + sage: Fd.ngenerating_cones() + 5 - .. MATH:: + sage: Fd = ClusterQuiver([[1,2],[2,3]]).d_vector_fan(); Fd + Rational polyhedral fan in 3-d lattice N + sage: Fd.ngenerating_cones() + 14 + sage: Fd.is_smooth() + True - \prod_{i=1}^{n} x_i^d_i + sage: Fd = ClusterQuiver([[1,2],[2,3],[3,1]]).d_vector_fan(); Fd + Rational polyhedral fan in 3-d lattice N + sage: Fd.ngenerating_cones() + 14 + sage: Fd.is_smooth() + False + + TESTS:: + + sage: ClusterQuiver(['A',[2,2],1]).d_vector_fan() + Traceback (most recent call last): + ... + ValueError: only makes sense for quivers of finite type + """ + from cluster_seed import ClusterSeed + from cluster_seed import ClusterSeed + from sage.geometry.fan import Fan + from sage.geometry.cone import Cone + from sage.modules.free_module_element import vector + + if not(self.is_finite()): + raise ValueError('only makes sense for quivers of finite type') + seed = ClusterSeed(self) + return Fan([Cone(s.d_matrix().columns()) for s in seed.mutation_class()]) + + def g_vector_fan(self): + r""" + Return the g-vector fan associated with the quiver. - is the denominator of this cluster variable (written in lowest - terms). By convention, the denominator of each initial - variable `x_i` is `x_i^{-1}`. + It is the fan whose maximal cones are generated by the g-matrices of the + clusters. - Using this map, every cluster defines a cone in `\ZZ^n` -- - the cone spanned by the vectors corresponding to its cluster - variables. These are the maximal cones of the cluster fan. + This is a complete simplicial fan. It is only supported for quivers of + finite type. EXAMPLES:: - sage: F = ClusterQuiver(DiGraph({0:[1]})).fan(); F + sage: Fg = ClusterQuiver([[1,2]]).g_vector_fan(); Fg Rational polyhedral fan in 2-d lattice N - sage: F.ngenerating_cones() + sage: Fg.ngenerating_cones() 5 - sage: F = ClusterQuiver(['A',3]).fan(); F + sage: Fg = ClusterQuiver([[1,2],[2,3]]).g_vector_fan(); Fg Rational polyhedral fan in 3-d lattice N - sage: F.ngenerating_cones() + sage: Fg.ngenerating_cones() 14 - sage: F.is_smooth() + sage: Fg.is_smooth() True + sage: Fg = ClusterQuiver([[1,2],[2,3],[3,1]]).g_vector_fan(); Fg + Rational polyhedral fan in 3-d lattice N + sage: Fg.ngenerating_cones() + 14 + sage: Fg.is_smooth() + True + + TESTS:: - sage: ClusterQuiver(DiGraph({0:[1],1:[2],2:[0]})).fan() + sage: ClusterQuiver(['A',[2,2],1]).g_vector_fan() Traceback (most recent call last): ... - ValueError: only makes sense for acyclic quivers of finite type + ValueError: only supported for quivers of finite type + """ from cluster_seed import ClusterSeed from sage.geometry.fan import Fan from sage.geometry.cone import Cone from sage.modules.free_module_element import vector - if not(self.is_finite() and self.is_acyclic()): - raise ValueError('only makes sense for acyclic quivers' - ' of finite type') - seed = ClusterSeed(self) - # could maybe use a direct custom "denominator" function - # instead of going through almost_positive_roots - return Fan([Cone([vector(v.almost_positive_root()) - for v in s.cluster()]) - for s in seed.mutation_class()]) + if not(self.is_finite()): + raise ValueError('only supported for quivers of finite type') + seed = ClusterSeed(self).principal_extension() + return Fan([Cone(s.g_matrix().columns()) for s in seed.mutation_class()]) From f2be73c3bdf6c76518e1899ee2753d8447ab58bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Thu, 4 Jun 2015 18:38:21 +0300 Subject: [PATCH 0237/1872] Made tests pass in coxeter_type --- src/sage/combinat/root_system/coxeter_type.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index da9ae92c2cb..28bfb2363a1 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -366,13 +366,14 @@ def bilinear_form(self, R=None): mat = self.coxeter_matrix()._matrix base_ring = mat.base_ring() - from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField - if UniversalCyclotomicField.has_coerce_map_from(base_ring): - R = UniversalCyclotomicField() + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + UCF = UniversalCyclotomicField() + if UCF.has_coerce_map_from(base_ring): + R = UCF else: R = base_ring # Compute the matrix with entries `- \cos( \pi / m_{ij} )`. - if R is UniversalCyclotomicField(): + if R is UCF: val = lambda x: (R.gen(2*x) + ~R.gen(2*x)) / R(-2) if x > -1 else R.one()*x else: from sage.functions.trig import cos From 1878996de32be22026a41c87c12e2df1ef75091f Mon Sep 17 00:00:00 2001 From: Nathan Williams Date: Thu, 4 Jun 2015 11:21:16 -0500 Subject: [PATCH 0238/1872] work in progress: new implementations are presumably correct, but existing bug discovered --- src/sage/categories/coxeter_groups.py | 973 ++++++++++--------- src/sage/categories/finite_coxeter_groups.py | 133 +++ src/sage/categories/finite_weyl_groups.py | 59 +- 3 files changed, 674 insertions(+), 491 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index e3721e7c8e4..0bdc6f4060f 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -26,50 +26,50 @@ class CoxeterGroups(Category_singleton): r""" The category of Coxeter groups. - + A *Coxeter group* is a group `W` with a distinguished (finite) family of involutions `(s_i)_{i\in I}`, called the *simple reflections*, subject to relations of the form `(s_is_j)^{m_{i,j}} = 1`. - + `I` is the *index set* of `W` and `|I|` is the *rank* of `W`. - + See :Wikipedia:`Coxeter_group` for details. - + EXAMPLES:: - + sage: C = CoxeterGroups(); C Category of coxeter groups sage: C.super_categories() [Category of finitely generated groups] - + sage: W = C.example(); W The symmetric group on {0, ..., 3} - + sage: W.simple_reflections() Finite family {0: (1, 0, 2, 3), 1: (0, 2, 1, 3), 2: (0, 1, 3, 2)} - + Here are some further examples:: - + sage: FiniteCoxeterGroups().example() The 5-th dihedral group of order 10 sage: FiniteWeylGroups().example() The symmetric group on {0, ..., 3} sage: WeylGroup(["B", 3]) Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space) - + Those will eventually be also in this category:: - + sage: SymmetricGroup(4) Symmetric group of order 4! as a permutation group sage: DihedralGroup(5) Dihedral group of order 10 as a permutation group - + .. TODO:: add a demo of usual computations on Coxeter groups. - + .. SEEALSO:: :class:`WeylGroups`, :mod:`sage.combinat.root_system` - + .. WARNING:: - + It is assumed that morphisms in this category preserve the distinguished choice of simple reflections. In particular, subobjects in this category are parabolic subgroups. In this @@ -77,12 +77,12 @@ class CoxeterGroups(Category_singleton): Systems``. In the long run we might want to have two distinct categories, one for Coxeter groups (with morphisms being just group morphisms) and one for Coxeter systems:: - + sage: CoxeterGroups().is_full_subcategory(Groups()) False - + TESTS:: - + sage: W = CoxeterGroups().example(); TestSuite(W).run(verbose = "True") running ._test_an_element() . . . pass running ._test_associativity() . . . pass @@ -112,60 +112,60 @@ class CoxeterGroups(Category_singleton): running ._test_simple_projections() . . . pass running ._test_some_elements() . . . pass """ - + def super_categories(self): """ EXAMPLES:: - + sage: CoxeterGroups().super_categories() [Category of finitely generated groups] """ return [Groups().FinitelyGenerated()] - + Finite = LazyImport('sage.categories.finite_coxeter_groups', 'FiniteCoxeterGroups') Algebras = LazyImport('sage.categories.coxeter_group_algebras', 'CoxeterGroupAlgebras') - + class ParentMethods: - + @abstract_method def index_set(self): """ Returns the index set of (the simple reflections of) ``self``, as a list (or iterable). - + EXAMPLES:: - + sage: W = FiniteCoxeterGroups().example(); W The 5-th dihedral group of order 10 sage: W.index_set() [1, 2] """ # return self.simple_reflections().keys() - + def _an_element_(self): """ Implements: :meth:`Sets.ParentMethods.an_element` by returning the product of the simple reflections (a Coxeter element). - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} sage: W.an_element() # indirect doctest (1, 2, 3, 0) - + """ return self.prod(self.simple_reflections()) - + def some_elements(self): """ Implements :meth:`Sets.ParentMethods.some_elements` by returning some typical element of `self`. - + EXAMPLES:: - + sage: W=WeylGroup(['A',3]) sage: W.some_elements() [ @@ -178,13 +178,13 @@ def some_elements(self): 24 """ return list(self.simple_reflections()) + [ self.one(), self.an_element() ] - + def __iter__(self): r""" Returns an iterator over the elements of this Coxeter group. - + EXAMPLES:: - + sage: D5 = FiniteCoxeterGroups().example(5) sage: sorted(list(D5)) # indirect doctest (but see :meth:`._test_enumerated_set_iter_list`) [(), @@ -197,7 +197,7 @@ def __iter__(self): (2, 1), (2, 1, 2), (2, 1, 2, 1)] - + sage: W = WeylGroup(["A",2,1]) sage: g = iter(W) sage: next(g) @@ -214,30 +214,30 @@ def __iter__(self): [ 0 0 1] """ return iter(self.weak_order_ideal(predicate = ConstantFunction(True))) - + def weak_order_ideal(self, predicate, side ="right", category = None): """ Returns a weak order ideal defined by a predicate - + INPUT: - + - ``predicate``: a predicate on the elements of ``self`` defining an weak order ideal in ``self`` - ``side``: "left" or "right" (default: "right") - + OUTPUT: an enumerated set - + EXAMPLES:: - + sage: D6 = FiniteCoxeterGroups().example(5) sage: I = D6.weak_order_ideal(predicate = lambda w: w.length() <= 3) sage: I.cardinality() 7 sage: list(I) [(), (1,), (1, 2), (1, 2, 1), (2,), (2, 1), (2, 1, 2)] - + We now consider an infinite Coxeter group:: - + sage: W = WeylGroup(["A",1,1]) sage: I = W.weak_order_ideal(predicate = lambda w: w.length() <= 2) sage: list(iter(I)) @@ -245,16 +245,16 @@ def weak_order_ideal(self, predicate, side ="right", category = None): [1 0] [-1 2] [ 3 -2] [ 1 0] [-1 2] [0 1], [ 0 1], [ 2 -1], [ 2 -1], [-2 3] ] - + Even when the result is finite, some features of :class:`FiniteEnumeratedSets` are not available:: - + sage: I.cardinality() # todo: not implemented 5 sage: list(I) # todo: not implemented - + unless this finiteness is explicitly specified:: - + sage: I = W.weak_order_ideal(predicate = lambda w: w.length() <= 2, ... category = FiniteEnumeratedSets()) sage: I.cardinality() @@ -264,14 +264,14 @@ def weak_order_ideal(self, predicate, side ="right", category = None): [1 0] [-1 2] [ 3 -2] [ 1 0] [-1 2] [0 1], [ 0 1], [ 2 -1], [ 2 -1], [-2 3] ] - + .. rubric:: Background - + The weak order is returned as a :class:`SearchForest`. This is achieved by assigning to each element `u1` of the ideal a single ancestor `u=u1 s_i`, where `i` is the smallest descent of `u`. - + This allows for iterating through the elements in roughly Constant Amortized Time and constant memory (taking the operations and size of the generated objects @@ -287,17 +287,17 @@ def succ(u): from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups default_category = FiniteEnumeratedSets() if self in FiniteCoxeterGroups() else EnumeratedSets() return SearchForest((self.one(),), succ, category = default_category.or_subcategory(category)) - + def grassmannian_elements(self, side = "right"): """ INPUT: - + - ``side``: "left" or "right" (default: "right") - + Returns the left or right grassmanian elements of self, as an enumerated set - + EXAMPLES:: - + sage: S = CoxeterGroups().example() sage: G = S.grassmannian_elements() sage: G.cardinality() @@ -314,24 +314,24 @@ def grassmannian_elements(self, side = "right"): """ order_side = "left" if side == "right" else "right" return self.weak_order_ideal(attrcall("is_grassmannian", side = side), side = order_side) - + def from_reduced_word(self, word): r""" INPUT: - + - ``word`` - a list (or iterable) of elements of ``self.index_set()`` - + Returns the group element corresponding to the given word. Namely, if ``word`` is `[i_1,i_2,\ldots,i_k]`, then this returns the corresponding product of simple reflections `s_{i_1} s_{i_2} \cdots s_{i_k}`. - + Note: the main use case is for constructing elements from reduced words, hence the name of this method. But actually the input word need *not* be reduced. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -342,13 +342,13 @@ def from_reduced_word(self, word): (0, 3, 1, 2) sage: s[0]*s[2]*s[0]*s[1] (0, 3, 1, 2) - + See also :meth:'._test_reduced_word':: - + sage: W._test_reduced_word() - + TESTS:: - + sage: W=WeylGroup(['E',6]) sage: W.from_reduced_word([2,3,4,2]) [ 0 1 0 0 0 0 0 0] @@ -359,20 +359,20 @@ def from_reduced_word(self, word): [ 0 0 0 0 0 1 0 0] [ 0 0 0 0 0 0 1 0] [ 0 0 0 0 0 0 0 1] - + """ return self.one().apply_simple_reflections(word, side = 'right') - + def _test_reduced_word(self, **options): """ Runs sanity checks on :meth:'CoxeterGroups.ElementMethods.reduced_word' and :meth:'.from_reduced_word`. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W._test_reduced_word() - + """ tester = self._tester(**options) s = self.simple_reflections() @@ -380,17 +380,17 @@ def _test_reduced_word(self, **options): red = x.reduced_word() tester.assertEquals(self.from_reduced_word(red), x) tester.assertEquals(self.prod((s[i] for i in red)), x) - + def simple_reflection(self, i): """ INPUT: - + - ``i`` - an element from the index set. - + Returns the simple reflection `s_i` - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -399,19 +399,19 @@ def simple_reflection(self, i): sage: s = W.simple_reflections() sage: s[1] (0, 2, 1, 3) - + """ if not i in self.index_set(): raise ValueError("%s is not in the Dynkin node set %s"%(i,self.index_set())) return self.one().apply_simple_reflection(i) # don't care about left/right - + @cached_method def simple_reflections(self): r""" Returns the simple reflections `(s_i)_{i\in I}`, as a family. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -425,41 +425,41 @@ def simple_reflections(self): sage: s[2] (0, 1, 3, 2) - + This default implementation uses :meth:`.index_set` and :meth:`.simple_reflection`. """ from sage.sets.family import Family return Family(self.index_set(), self.simple_reflection) - + @cached_method def rank(self): r""" Return the rank of ``self``. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W.rank() 3 """ return len(self.simple_reflections()) - + def group_generators(self): r""" Implements :meth:`Groups.ParentMethods.group_generators` by returning the simple reflections of ``self``. - + EXAMPLES:: - + sage: D10 = FiniteCoxeterGroups().example(10) sage: D10.group_generators() Finite family {1: (1,), 2: (2,)} sage: SymmetricGroup(5).group_generators() Finite family {1: (1,2), 2: (2,3), 3: (3,4), 4: (4,5)} - + Those give semigroup generators, even for an infinite group:: - + sage: W = WeylGroup(["A",2,1]) sage: W.semigroup_generators() Finite family {0: [-1 1 1] @@ -473,22 +473,22 @@ def group_generators(self): [ 1 1 -1]} """ return self.simple_reflections() - + semigroup_generators = group_generators - + def simple_projection(self, i, side = 'right', length_increasing = True): r""" INPUT: - + - ``i`` - an element of the index set of ``self`` - + Returns the simple projection `\pi_i` (or `\overline\pi_i` if `length_increasing` is False). - + See :meth:`.simple_projections` for the options and for the definition of the simple projections. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -513,48 +513,48 @@ def simple_projection(self, i, side = 'right', length_increasing = True): (1, 2, 3, 0) sage: d0(pi) (1, 2, 3, 0) - + """ if not (i in self.index_set() or i == 0): raise ValueError("%s is not 0 and not in the Dynkin node set %s"%(i, self.index_set())) return lambda x: x.apply_simple_projection(i, side = side, length_increasing = length_increasing) - + @cached_method def simple_projections(self, side = 'right', length_increasing = True): r""" Returns the family of simple projections, also known as 0-Hecke or Demazure operators. - + INPUT: - + - ``self`` - a Coxeter group `W` - ``side`` - 'left' or 'right' (default: 'right') - ``length_increasing`` - a boolean (default: True) specifying whether the operator increases or decreases length - + Returns the simple projections of `W`, as a family. - + To each simple reflection `s_i` of `W`, corresponds a *simple projection* `\pi_i` from `W` to `W` defined by: - + `\pi_i(w) = w s_i` if `i` is not a descent of `w` `\pi_i(w) = w` otherwise. - + The simple projections `(\pi_i)_{i\in I}` move elements down the right permutohedron, toward the maximal element. They satisfy the same braid relations as the simple reflections, but are idempotents `\pi_i^2=\pi` not involutions `s_i^2 = 1`. As such, the simple projections generate the `0`-Hecke monoid. - + By symmetry, one can also define the projections `(\overline\pi_i)_{i\in I}` (when the option ``length_increasing`` is False): - + `\overline\pi_i(w) = w s_i` if `i` is a descent of `w` `\overline\pi_i(w) = w` otherwise. - + as well as the analogues acting on the left (when the option ``side`` is 'left'). - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -572,43 +572,43 @@ def simple_projections(self, side = 'right', length_increasing = True): """ from sage.sets.family import Family return Family(self.index_set(), lambda i: self.simple_projection(i, side = side, length_increasing = length_increasing)) - + def demazure_product(self,Q): r""" Returns the Demazure product of the list ``Q`` in ``self``. - + INPUT: - + - ``Q`` is a list of elements from the index set of ``self``. - + This returns the Coxeter group element that represents the composition of 0-Hecke or Demazure operators. See :meth:`CoxeterGroups.ParentMethods.simple_projections`. - + EXAMPLES:: - + sage: W = WeylGroup(['A',2]) sage: w = W.demazure_product([2,2,1]) sage: w.reduced_word() [2, 1] - + sage: w = W.demazure_product([2,1,2,1,2]) sage: w.reduced_word() [1, 2, 1] - + sage: W = WeylGroup(['B',2]) sage: w = W.demazure_product([2,1,2,1,2]) sage: w.reduced_word() [2, 1, 2, 1] - + """ return self.one().apply_demazure_product(Q) - + def bruhat_interval(self, x, y): """ Returns the list of t such that x <= t <= y. - + EXAMPLES:: - + sage: W = WeylGroup("A3", prefix="s") sage: [s1,s2,s3]=W.simple_reflections() sage: W.bruhat_interval(s2,s1*s3*s2*s1*s3) @@ -637,13 +637,13 @@ def bruhat_interval(self, x, y): nextlayer.append(t) ret.append(nextlayer) return flatten(ret) - + def canonical_representation(self): r""" Return the canonical faithful representation of ``self``. - + EXAMPLES:: - + sage: W = WeylGroup("A3") sage: W.canonical_representation() Finite Coxeter group over Universal Cyclotomic Field with Coxeter matrix: @@ -654,47 +654,47 @@ def canonical_representation(self): from sage.groups.matrix_gps.coxeter_group import CoxeterMatrixGroup return CoxeterMatrixGroup(self.coxeter_matrix(), index_set=self.index_set()) - + def elements_of_length(self, n): r""" Return all elements of length `n`. - + EXAMPLES:: - + sage: A = AffinePermutationGroup(['A',2,1]) sage: [len(list(A.elements_of_length(i))) for i in [0..5]] [1, 3, 6, 9, 12, 15] - + sage: W = CoxeterGroup(['H',3]) sage: [len(list(W.elements_of_length(i))) for i in range(4)] [1, 3, 5, 7] - + sage: W = CoxeterGroup(['A',2]) sage: [len(list(W.elements_of_length(i))) for i in range(6)] [1, 2, 2, 1, 0, 0] """ I = self.weak_order_ideal(ConstantFunction(True), side='right') return I.elements_of_depth_iterator(n) - + def random_element_of_length(self, n): r""" Return a random element of length ``n`` in ``self``. - + Starts at the identity, then chooses an upper cover at random. - + Not very uniform: actually constructs a uniformly random reduced word of length `n`. Thus we most likely get elements with lots of reduced words! - + EXAMPLES:: - + sage: A = AffinePermutationGroup(['A', 7, 1]) sage: p = A.random_element_of_length(10) sage: p in A True sage: p.length() == 10 True - + sage: W = CoxeterGroup(['A', 4]) sage: p = W.random_element_of_length(5) sage: p in W @@ -709,20 +709,20 @@ def random_element_of_length(self, n): rnd = randint(0, len(antiD) - 1) x = x.apply_simple_reflection_right(antiD[rnd]) return x - + # TODO: Groups() should have inverse() call __invert__ # With strong doc stating that this is just a convenience for the user # and links to ~ / __invert__ - + # parabolic_subgroup - + def _test_simple_projections(self, **options): """ Runs sanity checks on :meth:`.simple_projections` and :meth:`CoxeterGroups.ElementMethods.apply_simple_projection` - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W._test_simple_projections() """ @@ -740,15 +740,15 @@ def _test_simple_projections(self, **options): tester.assertEquals(set([pi[i](w), opi[i](w)]), set([w, w.apply_simple_reflection(i, side = side)])) - + def _test_has_descent(self, **options): """ Runs sanity checks on the method :meth:`CoxeterGroups.ElementMethods.has_descent` of the elements of self. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W._test_has_descent() """ @@ -776,16 +776,16 @@ def _test_has_descent(self, **options): tester.assert_((s[i]*s[j]).has_descent(j, side = 'right')) tester.assertEquals((s[i]*s[j]).has_descent(j, side = 'left' ), u == v) tester.assertEquals((s[i]*s[j]).has_descent(i, side = 'right'), u == v) - + class ElementMethods: def has_descent(self, i, side = 'right', positive=False): """ Returns whether i is a (left/right) descent of self. - + See :meth:`.descents` for a description of the options. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: s = W.simple_reflections() sage: w = s[0] * s[1] * s[2] @@ -797,7 +797,7 @@ def has_descent(self, i, side = 'right', positive=False): [True, False, False] sage: [ w.has_descent(i, positive = True) for i in [0,1,2] ] [True, True, False] - + This default implementation delegates the work to :meth:`.has_left_descent` and :meth:`.has_right_descent`. """ @@ -813,9 +813,9 @@ def has_descent(self, i, side = 'right', positive=False): def has_right_descent(self, i): """ Returns whether ``i`` is a right descent of self. - + EXAMPLES:: - + sage: W = CoxeterGroups().example(); W The symmetric group on {0, ..., 3} sage: w = W.an_element(); w @@ -828,16 +828,16 @@ def has_right_descent(self, i): True """ return (~self).has_left_descent(i) - + def has_left_descent(self, i): """ Returns whether `i` is a left descent of self. - + This default implementation uses that a left descent of `w` is a right descent of `w^{-1}`. - + EXAMPLES:: - + sage: W = CoxeterGroups().example(); W The symmetric group on {0, ..., 3} sage: w = W.an_element(); w @@ -848,23 +848,23 @@ def has_left_descent(self, i): False sage: w.has_left_descent(2) False - + TESTS:: - + sage: w.has_left_descent.__module__ 'sage.categories.coxeter_groups' """ return (~self).has_right_descent(i) - + def first_descent(self, side = 'right', index_set=None, positive=False): """ Returns the first left (resp. right) descent of self, as ane element of ``index_set``, or ``None`` if there is none. - + See :meth:`.descents` for a description of the options. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: s = W.simple_reflections() sage: w = s[2]*s[0] @@ -883,33 +883,33 @@ def first_descent(self, side = 'right', index_set=None, positive=False): if self.has_descent(i, side = side, positive = positive): return i return None - + def descents(self, side = 'right', index_set=None, positive=False): """ INPUT: - + - ``index_set`` - a subset (as a list or iterable) of the nodes of the Dynkin diagram; (default: all of them) - ``side`` - 'left' or 'right' (default: 'right') - ``positive`` - a boolean (default: ``False``) - + Returns the descents of self, as a list of elements of the index_set. - + The ``index_set`` option can be used to restrict to the parabolic subgroup indexed by ``index_set``. - + If positive is ``True``, then returns the non-descents instead - + TODO: find a better name for ``positive``: complement? non_descent? - + Caveat: the return type may change to some other iterable (tuple, ...) in the future. Please use keyword arguments also, as the order of the arguments may change as well. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: s=W.simple_reflections() sage: w=s[0]*s[1] @@ -918,24 +918,24 @@ def descents(self, side = 'right', index_set=None, positive=False): sage: w=s[0]*s[2] sage: w.descents() [0, 2] - + TODO: side, index_set, positive """ if index_set is None: index_set=self.parent().index_set() return [ i for i in index_set if self.has_descent(i, side = side, positive = positive) ] - + def is_grassmannian(self, side = "right"): """ INPUT: - + - ``side`` - "left" or "right" (default: "right") - + Tests whether ``self`` is Grassmannian, i.e. it has at most one descent on the right (resp. on the left). v EXAMPLES:: - + sage: W = CoxeterGroups().example(); W The symmetric group on {0, ..., 3} sage: s = W.simple_reflections() @@ -949,7 +949,7 @@ def is_grassmannian(self, side = "right"): True sage: (s[1]*s[2]*s[1]).is_grassmannian() False - + sage: (s[0]*s[2]*s[1]).is_grassmannian(side = "left") False sage: (s[0]*s[2]*s[1]).is_grassmannian(side = "right") @@ -958,13 +958,13 @@ def is_grassmannian(self, side = "right"): True """ return len(self.descents(side = side)) <= 1 - + def reduced_word_reverse_iterator(self): """ Return a reverse iterator on a reduced word for ``self``. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: s = W.simple_reflections() sage: sigma = s[0]*s[1]*s[2] @@ -975,15 +975,15 @@ def reduced_word_reverse_iterator(self): True sage: sigma.length() 3 - + .. SEEALSO:: - + :meth:`.reduced_word` - + Default implementation: recursively remove the first right descent until the identity is reached (see :meth:`.first_descent` and :meth:`apply_simple_reflection`). - + """ while True: i = self.first_descent() @@ -991,18 +991,18 @@ def reduced_word_reverse_iterator(self): return self = self.apply_simple_reflection(i, 'right') yield i - + def reduced_word(self): r""" 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} = \operatorname{self}`, where the `s_i` are the simple reflections. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: s=W.simple_reflections() sage: w=s[0]*s[1]*s[2] @@ -1011,45 +1011,45 @@ def reduced_word(self): sage: w=s[0]*s[2] sage: w.reduced_word() [2, 0] - + .. 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)) - + #def lex_min_reduced_word(w): # return list(reversed((w.inverse()).reduced_word())) - + def support(self): r""" Return the support of ``self``, that is the simple reflections that appear in the reduced expressions of ``self``. - + OUTPUT: - + The support of ``self`` as a set of integers - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: w = W.from_reduced_word([1,2,1]) sage: w.support() {1, 2} """ return set(self.reduced_word()) - + def has_full_support(self): r""" Return whether ``self`` has full support. - + An element is said to have full support if its support contains all simple reflections. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: w = W.from_reduced_word([1,2,1]) sage: w.has_full_support() @@ -1059,16 +1059,16 @@ def has_full_support(self): True """ return self.support() == set(self.parent().index_set()) - + def reduced_words(self): r""" Return all reduced words for ``self``. - + See :meth:`reduced_word` for the definition of a reduced word. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: s=W.simple_reflections() sage: w=s[0]*s[2] @@ -1078,12 +1078,12 @@ def reduced_words(self): sage: w=W.from_reduced_word([2,3,4,2]) sage: w.reduced_words() [[3, 2, 4, 2], [2, 3, 4, 2], [3, 4, 2, 4]] - + 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` """ @@ -1095,23 +1095,23 @@ def reduced_words(self): for i in self.descents() 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 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:: - + sage: W = WeylGroup(['A',3], prefix='s') sage: w0 = W.long_element() sage: G = w0.reduced_word_graph() @@ -1125,18 +1125,18 @@ def reduced_word_graph(self): 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` """ @@ -1145,7 +1145,7 @@ def reduced_word_graph(self): # 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): @@ -1176,14 +1176,14 @@ def reduced_word_graph(self): 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 a product of simple reflections giving self. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: s1 = W.simple_reflection(1) sage: s2 = W.simple_reflection(2) @@ -1199,25 +1199,25 @@ def length(self): sage: W = CoxeterGroups().example() sage: sum((x^w.length()) for w in W) - expand(prod(sum(x^i for i in range(j+1)) for j in range(4))) # This is scandalously slow!!! 0 - + SEE ALSO: :meth:`.reduced_word` - + TODO: Should use reduced_word_iterator (or reverse_iterator) - + """ return len(self.reduced_word()) - + def absolute_length(self): """ Return the absolute length of ``self`` - + The absolute length is the length of the shortest expression of the element as a product of reflections. - + .. SEEALSO:: :meth:`absolute_le`. - + EXAMPLES:: - + sage: W = WeylGroup(["A", 3]) sage: s = W.simple_reflections() sage: (s[1]*s[2]*s[3]).absolute_length() @@ -1225,24 +1225,24 @@ def absolute_length(self): """ M = self.canonical_matrix() return (M - 1).image().dimension() - + def absolute_le(self, other): r""" Return whether ``self`` is smaller than ``other`` in the absolute order. - + A general reflection is an element of the form `w s_i w^{-1}`, where `s_i` is a simple reflection. The absolute order is defined analogously to the weak order but using general reflections rather than just simple reflections. - + This partial order can be used to define noncrossing partitions associated with this Coxeter group. - + .. SEEALSO:: :meth:`absolute_length` - + EXAMPLES:: - + sage: W = WeylGroup(["A", 3]) sage: s = W.simple_reflections() sage: w0 = s[1] @@ -1259,19 +1259,19 @@ def absolute_le(self, other): if self.absolute_length() >= other.absolute_length(): return False return self.absolute_length() + (self.inverse() * other).absolute_length() == other.absolute_length() - + def canonical_matrix(self): r""" Return the matrix of ``self`` in the canonical faithful representation. - + This is an `n`-dimension real faithful essential representation, where `n` is the number of generators of the Coxeter group. Note that this is not always the most natural matrix representation, for instance in type `A_n`. - + EXAMPLES:: - + sage: W = WeylGroup(["A", 3]) sage: s = W.simple_reflections() sage: (s[1]*s[2]*s[3]).canonical_matrix() @@ -1281,20 +1281,20 @@ def canonical_matrix(self): """ G = self.parent().canonical_representation() return G.prod(G.simple_reflection(i) for i in self.reduced_word()).matrix() - + def coset_representative(self, index_set, side = 'right'): r""" INPUT: - + - ``index_set`` - a subset (or iterable) of the nodes of the Dynkin diagram - ``side`` - 'left' or 'right' - + Returns the unique shortest element of the Coxeter group $W$ which is in the same left (resp. right) coset as ``self``, with respect to the parabolic subgroup $W_I$. - + EXAMPLES:: - + sage: W = CoxeterGroups().example(5) sage: s = W.simple_reflections() sage: w = s[2]*s[1]*s[3] @@ -1322,31 +1322,31 @@ def coset_representative(self, index_set, side = 'right'): [1] sage: w.coset_representative([1,2,3], side = 'left').reduced_word() [] - + """ while True: i = self.first_descent(side = side, index_set = index_set) if i is None: return self self = self.apply_simple_reflection(i, side = side) - + def apply_simple_projection(self, i, side = 'right', length_increasing = True): r""" INPUT: - + - ``i`` - an element of the index set of the Coxeter group - ``side`` - 'left' or 'right' (default: 'right') - ``length_increasing`` - a boolean (default: True) specifying the direction of the projection - + Returns the result of the application of the simple projection `\pi_i` (resp. `\overline\pi_i`) on ``self``. - + See :meth:`CoxeterGroups.ParentMethods.simple_projections` for the definition of the simple projections. - + EXAMPLE:: - + sage: W=CoxeterGroups().example() sage: w=W.an_element() sage: w @@ -1365,53 +1365,53 @@ def apply_simple_projection(self, i, side = 'right', length_increasing = True): s1*s2*s3*s4*s3*s1 sage: v.apply_simple_projection(1, length_increasing = False) s1*s2*s3*s4*s3 - + """ if self.has_descent(i, side = side, positive = length_increasing): return self.apply_simple_reflection(i, side=side) return self - + def binary_factorizations(self, predicate = ConstantFunction(True)): """ Returns the set of all the factorizations `self = u v` such that `l(self) = l(u) + l(v)`. - + Iterating through this set is Constant Amortized Time (counting arithmetic operations in the Coxeter group as constant time) complexity, and memory linear in the length of `self`. - + One can pass as optional argument a predicate p such that `p(u)` implies `p(u')` for any `u` left factor of `self` and `u'` left factor of `u`. Then this returns only the factorizations `self = uv` such `p(u)` holds. - + EXAMPLES: - + We construct the set of all factorizations of the maximal element of the group:: - + sage: W = WeylGroup(['A',3]) sage: s = W.simple_reflections() sage: w0 = W.from_reduced_word([1,2,3,1,2,1]) sage: w0.binary_factorizations().cardinality() 24 - + The same number of factorizations, by bounded length:: - + sage: [w0.binary_factorizations(lambda u: u.length() <= l).cardinality() for l in [-1,0,1,2,3,4,5,6]] [0, 1, 4, 9, 15, 20, 23, 24] - + The number of factorizations of the elements just below the maximal element:: - + sage: [(s[i]*w0).binary_factorizations().cardinality() for i in [1,2,3]] [12, 12, 12] sage: w0.binary_factorizations(lambda u: False).cardinality() 0 - + TESTS:: - + sage: w0.binary_factorizations().category() Category of finite enumerated sets """ @@ -1428,20 +1428,20 @@ def succ(u_v): if i == u1.first_descent() and predicate(u1): yield (u1, s[i]*v) return SearchForest(((W.one(), self),), succ, category = FiniteEnumeratedSets()) - + # TODO: standardize / cleanup def apply_simple_reflections(self, word, side = 'right'): """ INPUT: - + - ``word`` -- A sequence of indices of Coxeter generators - ``side`` -- Indicates multiplying from left or right - + Returns the result of the (left/right) multiplication of word to self. ``self`` is not changed. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: w=W.an_element(); w (1, 2, 3, 0) @@ -1456,17 +1456,17 @@ def apply_simple_reflections(self, word, side = 'right'): self = self.apply_simple_reflection(i, side) return self - + def apply_simple_reflection_left(self, i): """ Returns ``self`` multiplied by the simple reflection ``s[i]`` on the left - + This low level method is used intensively. Coxeter groups are encouraged to override this straightforward implementation whenever a faster approach exists. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: w = W.an_element(); w (1, 2, 3, 0) @@ -1476,25 +1476,25 @@ def apply_simple_reflection_left(self, i): (2, 1, 3, 0) sage: w.apply_simple_reflection_left(2) (1, 3, 2, 0) - + TESTS:: - + sage: w.apply_simple_reflection_left.__module__ 'sage.categories.coxeter_groups' """ s = self.parent().simple_reflections() return s[i] * self - + def apply_simple_reflection_right(self, i): """ Returns ``self`` multiplied by the simple reflection ``s[i]`` on the right - + This low level method is used intensively. Coxeter groups are encouraged to override this straightforward implementation whenever a faster approach exists. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: w = W.an_element(); w (1, 2, 3, 0) @@ -1504,30 +1504,30 @@ def apply_simple_reflection_right(self, i): (1, 3, 2, 0) sage: w.apply_simple_reflection_right(2) (1, 2, 0, 3) - + TESTS:: - + sage: w.apply_simple_reflection_right.__module__ 'sage.categories.coxeter_groups' """ s = self.parent().simple_reflections() return self * s[i] - + def apply_simple_reflection(self, i, side = 'right'): """ Returns ``self`` multiplied by the simple reflection ``s[i]`` - + INPUT: - + - ``i`` -- an element of the index set - ``side`` -- "left" or "right" (default: "right") - + This default implementation simply calls :meth:`apply_simple_reflection_left` or :meth:`apply_simple_reflection_right`. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: w = W.an_element(); w (1, 2, 3, 0) @@ -1537,21 +1537,21 @@ def apply_simple_reflection(self, i, side = 'right'): (2, 1, 3, 0) sage: w.apply_simple_reflection(2, side = "left") (1, 3, 2, 0) - + sage: w.apply_simple_reflection(0, side = "right") (2, 1, 3, 0) sage: w.apply_simple_reflection(1, side = "right") (1, 3, 2, 0) sage: w.apply_simple_reflection(2, side = "right") (1, 2, 0, 3) - + By default, ``side`` is "right":: - + sage: w.apply_simple_reflection(0) (2, 1, 3, 0) - + TESTS:: - + sage: w.apply_simple_reflection_right.__module__ 'sage.categories.coxeter_groups' """ @@ -1559,18 +1559,18 @@ def apply_simple_reflection(self, i, side = 'right'): return self.apply_simple_reflection_right(i) else: return self.apply_simple_reflection_left(i) - + def _mul_(self, other): r""" Returns the product of ``self`` and ``other`` - + This default implementation computes a reduced word of ``other`` using :meth:`reduced_word`, and applies the corresponding simple reflections on ``self`` using :meth:`apply_simple_reflections`. - + EXAMPLES:: - + sage: W = FiniteCoxeterGroups().example(); W The 5-th dihedral group of order 10 sage: w = W.an_element() @@ -1580,25 +1580,25 @@ def _mul_(self, other): (1, 2, 1, 2) sage: w._mul_(w)._mul_(w) (2, 1, 2, 1) - + This method is called when computing ``self*other``:: - + sage: w * w (1, 2, 1, 2) - + TESTS:: - + sage: w._mul_.__module__ 'sage.categories.coxeter_groups' """ return self.apply_simple_reflections(other.reduced_word()) - + def inverse(self): """ Returns the inverse of self - + EXAMPLES:: - + sage: W=WeylGroup(['B',7]) sage: w=W.an_element() sage: u=w.inverse() @@ -1614,30 +1614,30 @@ def inverse(self): [0 0 0 0 1 0 0] [0 0 0 0 0 1 0] [0 0 0 0 0 0 1] - + """ - + return self.parent().one().apply_simple_reflections(self.reduced_word_reverse_iterator()) - + __invert__ = inverse - + @cached_in_parent_method def bruhat_lower_covers(self): """ Returns all elements that ``self`` covers in (strong) Bruhat order. - + If ``w = self`` has a descent at `i`, then the elements that `w` covers are exactly `\{ws_i, u_1s_i, u_2s_i,..., u_js_i\}`, where the `u_k` are elements that `ws_i` covers that also do not have a descent at `i`. - + EXAMPLES:: - + sage: W = WeylGroup(["A",3]) sage: w = W.from_reduced_word([3,2,3]) sage: print([v.reduced_word() for v in w.bruhat_lower_covers()]) [[3, 2], [2, 3]] - + sage: W = WeylGroup(["A",3]) sage: print([v.reduced_word() for v in W.simple_reflection(1).bruhat_lower_covers()]) [[]] @@ -1647,18 +1647,18 @@ def bruhat_lower_covers(self): sage: w = W.from_reduced_word([0,2]) sage: print([v.reduced_word() for v in w.bruhat_lower_covers()]) [[2], [0]] - + We now show how to construct the Bruhat poset:: - + sage: W = WeylGroup(["A",3]) sage: covers = tuple([u, v] for v in W for u in v.bruhat_lower_covers() ) sage: P = Poset((W, covers), cover_relations = True) sage: P.show() - + Alternatively, one can just use:: - + sage: P = W.bruhat_poset() - + The algorithm is taken from Stembridge's 'coxeter/weyl' package for Maple. """ desc = self.first_descent() @@ -1667,30 +1667,30 @@ def bruhat_lower_covers(self): return [u.apply_simple_reflection(desc) for u in ww.bruhat_lower_covers() if not u.has_descent(desc)] + [ww] else: return [] - + @cached_in_parent_method def bruhat_upper_covers(self): r""" Returns all elements that cover ``self`` in (strong) Bruhat order. - + The algorithm works recursively, using the 'inverse' of the method described for lower covers :meth:`bruhat_lower_covers`. Namely, it runs through all `i` in the index set. Let `w` equal ``self``. If `w` has no right descent `i`, then `w s_i` is a cover; if `w` has a decent at `i`, then `u_j s_i` is a cover of `w` where `u_j` is a cover of `w s_i`. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3,1], prefix="s") sage: w = W.from_reduced_word([1,2,1]) sage: w.bruhat_upper_covers() [s1*s2*s1*s0, s1*s2*s0*s1, s0*s1*s2*s1, s3*s1*s2*s1, s2*s3*s1*s2, s1*s2*s3*s1] - + sage: W = WeylGroup(['A',3]) sage: w = W.long_element() sage: w.bruhat_upper_covers() [] - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([1,2,1]) sage: S = [v for v in W if w in v.bruhat_lower_covers()] @@ -1706,69 +1706,69 @@ def bruhat_upper_covers(self): else: Covers += [ self.apply_simple_reflection(i) ] return uniq(Covers) - + @cached_in_parent_method def bruhat_lower_covers_reflections(self): r""" Returns all 2-tuples of lower_covers and reflections (``v``, ``r``) where ``v`` is covered by ``self`` and ``r`` is the reflection such that ``self`` = ``v`` ``r``. - + ALGORITHM: - + See :meth:`.bruhat_lower_covers` - + EXAMPLES:: - + sage: W = WeylGroup(['A',3], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.bruhat_lower_covers_reflections() [(s1*s2*s1, s1*s2*s3*s2*s1), (s3*s2*s1, s2), (s3*s1*s2, s1)] - + """ i = self.first_descent() if i is None: return [] wi = self.apply_simple_reflection(i) return [(u.apply_simple_reflection(i),r.apply_conjugation_by_simple_reflection(i)) for u,r in wi.bruhat_lower_covers_reflections() if not u.has_descent(i)] + [(wi, self.parent().simple_reflection(i))] - + def lower_cover_reflections(self, side = 'right'): r""" Returns the reflections ``t`` such that ``self`` covers ``self`` ``t``. - + If ``side`` is 'left', ``self`` covers ``t`` ``self``. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3],prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.lower_cover_reflections() [s1*s2*s3*s2*s1, s2, s1] sage: w.lower_cover_reflections(side = 'left') [s2*s3*s2, s3, s1] - + """ - + if side == 'left': self = self.inverse() return [x[1] for x in self.bruhat_lower_covers_reflections()] - + @cached_in_parent_method def bruhat_upper_covers_reflections(self): r""" Returns all 2-tuples of covers and reflections (``v``, ``r``) where ``v`` covers ``self`` and ``r`` is the reflection such that ``self`` = ``v`` ``r``. - + ALGORITHM: - + See :meth:`.bruhat_upper_covers` - + EXAMPLES:: - + sage: W = WeylGroup(['A',4], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.bruhat_upper_covers_reflections() [(s1*s2*s3*s2*s1, s3), (s2*s3*s1*s2*s1, s2*s3*s2), (s3*s4*s1*s2*s1, s4), (s4*s3*s1*s2*s1, s1*s2*s3*s4*s3*s2*s1)] - + """ - + Covers = [] for i in self.parent().index_set(): wi = self.apply_simple_reflection(i) @@ -1777,43 +1777,43 @@ def bruhat_upper_covers_reflections(self): else: Covers += [(wi,self.parent().simple_reflection(i))] return uniq(Covers) - + def cover_reflections(self, side = 'right'): r""" Returns the set of reflections ``t`` such that ``self`` ``t`` covers ``self``. - + If ``side`` is 'left', ``t`` ``self`` covers ``self``. - + EXAMPLES:: - + sage: W = WeylGroup(['A',4], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.cover_reflections() [s3, s2*s3*s2, s4, s1*s2*s3*s4*s3*s2*s1] sage: w.cover_reflections(side = 'left') [s4, s2, s1*s2*s1, s3*s4*s3] - + """ - + if side == 'left': self = self.inverse() return [x[1] for x in self.bruhat_upper_covers_reflections()] - + @cached_in_parent_method def bruhat_le(self, other): """ Bruhat comparison - + INPUT: - + - other - an element of the same Coxeter group - + OUTPUT: a boolean - + Returns whether ``self`` <= ``other`` in the Bruhat order. - + EXAMPLES:: - + sage: W = WeylGroup(["A",3]) sage: u = W.from_reduced_word([1,2,1]) sage: v = W.from_reduced_word([1,2,3,2,1]) @@ -1828,31 +1828,31 @@ def bruhat_le(self, other): sage: s = W.simple_reflections() sage: s[1].bruhat_le(W.one()) False - + The implementation uses the equivalent condition that any reduced word for ``other`` contains a reduced word for ``self`` as subword. See Stembridge, A short derivation of the Mobius function for the Bruhat order. J. Algebraic Combin. 25 (2007), no. 2, 141--148, Proposition 1.1. - + Complexity: `O(l * c)`, where `l` is the minimum of the lengths of `u` and of `v`, and `c` is the cost of the low level methods :meth:`first_descent`, :meth:`has_descent`, :meth:`apply_simple_reflection`, etc. Those are typically `O(n)`, where `n` is the rank of the Coxeter group. - + TESTS: - + We now run consistency tests with permutations and :meth:`bruhat_lower_covers`:: - + sage: W = WeylGroup(["A",3]) sage: P4 = Permutations(4) sage: def P4toW(w): return W.from_reduced_word(w.reduced_word()) sage: for u in P4: ... for v in P4: ... assert u.bruhat_lequal(v) == P4toW(u).bruhat_le(P4toW(v)) - + sage: W = WeylGroup(["B",3]) sage: P = W.bruhat_poset() # This is built from bruhat_lower_covers sage: Q = Poset((W, attrcall("bruhat_le"))) # long time (10s) @@ -1860,7 +1860,7 @@ def bruhat_le(self, other): True sage: all( P.is_lequal(u,v) == Q.is_lequal(u,v) for u in W for v in W) # long time (9s) True - + """ if not have_same_parent(self, other): raise TypeError("%s and %s do not have the same parent"%(self, other)) @@ -1870,25 +1870,25 @@ def bruhat_le(self, other): return self.apply_simple_projection(desc, length_increasing = False).bruhat_le(other.apply_simple_reflection(desc)) else: return self == other - + def weak_le(self, other, side = 'right'): """ comparison in weak order - + INPUT: - + - other - an element of the same Coxeter group - side - 'left' or 'right' (default: 'right') - + OUTPUT: a boolean - + Returns whether ``self`` <= ``other`` in left (resp. right) weak order, that is if 'v' can be obtained from 'v' by length increasing multiplication by simple reflections on the left (resp. right). - + EXAMPLES:: - + sage: W = WeylGroup(["A",3]) sage: u = W.from_reduced_word([1,2]) sage: v = W.from_reduced_word([1,2,3,2]) @@ -1900,24 +1900,24 @@ def weak_le(self, other, side = 'right'): False sage: v.weak_le(v) True - + Comparison for left weak order is achieved with the option ``side``:: - + sage: u.weak_le(v, side = 'left') False - + The implementation uses the equivalent condition that any reduced word for `u` is a right (resp. left) prefix of some reduced word for `v`. - + Complexity: `O(l * c)`, where `l` is the minimum of the lengths of `u` and of `v`, and `c` is the cost of the low level methods :meth:`first_descent`, :meth:`has_descent`, :meth:`apply_simple_reflection`. Those are typically `O(n)`, where `n` is the rank of the Coxeter group. - + We now run consistency tests with permutations:: - + sage: W = WeylGroup(["A",3]) sage: P4 = Permutations(4) sage: def P4toW(w): return W.from_reduced_word(w.reduced_word()) @@ -1930,7 +1930,7 @@ def weak_le(self, other, side = 'right'): raise TypeError("%s and %s do not have the same parent"%(self,other)) # could first compare the length, when that information is cheap prefix_side = 'left' if side == 'right' else 'right' - + while True: desc = self.first_descent(side = prefix_side) if desc is None: @@ -1939,33 +1939,33 @@ def weak_le(self, other, side = 'right'): return False self = self.apply_simple_reflection(desc, side = prefix_side) other = other.apply_simple_reflection(desc, side = prefix_side) - + def weak_covers(self, side = 'right', index_set = None, positive = False): """ Returns all elements that ``self`` covers in weak order. - + INPUT: - + - side - 'left' or 'right' (default: 'right') - positive - a boolean (default: False) - index_set - a list of indices or None - + OUTPUT: a list - + EXAMPLES:: - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([3,2,1]) sage: [x.reduced_word() for x in w.weak_covers()] [[3, 2]] - + To obtain instead elements that cover self, set ``positive = True``:: - + sage: [x.reduced_word() for x in w.weak_covers(positive = True)] [[3, 1, 2, 1], [2, 3, 2, 1]] - + To obtain covers for left weak order, set the option side to 'left':: - + sage: [x.reduced_word() for x in w.weak_covers(side='left')] [[2, 1]] sage: w = W.from_reduced_word([3,2,3,1]) @@ -1973,38 +1973,41 @@ def weak_covers(self, side = 'right', index_set = None, positive = False): [[2, 3, 2], [3, 2, 1]] sage: [x.reduced_word() for x in w.weak_covers(side='left')] [[3, 2, 1], [2, 3, 1]] - + Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - + sage: [x.reduced_word() for x in w.weak_covers(index_set = [1,2])] [[2, 3, 2]] """ return [ self.apply_simple_reflection(i, side=side) for i in self.descents(side=side, index_set = index_set, positive = positive) ] - + def coxeter_sorting_word(self,c): r""" Return the ``c``-sorting word of ``self``. - + For a Coxeter element `c` and an element `w`, the `c`-sorting word of `w` is the lexicographic minimal reduced expression of `w` in the infinite word `c^\infty`. - + INPUT: - + - ``c``-- a Coxeter element. - + OUTPUT: - + the ``c``-sorting word of ``self`` as a list of integers. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: c = W.from_reduced_word([0,2,1]) sage: w = W.from_reduced_word([1,2,1,0,1]) sage: w.coxeter_sorting_word(c) [2, 1, 2, 0, 1] + + sage: W = WyelGroup(['A',2]).long_element().coxeter_sorting_word([1,2]) + [1,2,1] """ if hasattr(c,"reduced_word"): c = c.reduced_word() @@ -2025,27 +2028,27 @@ def coxeter_sorting_word(self,c): if i == n: i = 0 return sorting_word - + def is_coxeter_sortable(self,c,sorting_word=None): r""" Return whether ``self`` is ``c``-sortable. - + Given a Coxeter element `c`, an element `w` is `c`-sortable if its `c`-sorting word decomposes into a sequence of weakly decreasing subwords of `c`. - + INPUT: - + - ``c`` -- a Coxeter element. - ``sorting_word`` -- sorting word (default: None) used to not recompute the ``c``-sorting word if already computed. - + OUTPUT: - + is ``self`` ``c``-sortable - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: c = W.from_reduced_word([0,2,1]) sage: w = W.from_reduced_word([1,2,1,0,1]) @@ -2086,30 +2089,30 @@ def is_coxeter_sortable(self,c,sorting_word=None): if i == n: i = 0 return True - + def apply_demazure_product(self, element, side = 'right', length_increasing = True): r""" Returns the Demazure or 0-Hecke product of ``self`` with another Coxeter group element. - + See :meth:`CoxeterGroups.ParentMethods.simple_projections`. - + INPUT: - + - ``element`` -- either an element of the same Coxeter group as ``self`` or a tuple or a list (such as a reduced word) of elements from the index set of the Coxeter group. - + - ``side`` -- 'left' or 'right' (default: 'right'); the side of ``self`` on which the element should be applied. If ``side`` is 'left' then the operation is applied on the left. - + - ``length_increasing`` -- a boolean (default True) whether to act length increasingly or decreasingly - + EXAMPLES:: - + sage: W = WeylGroup(['C',4],prefix="s") sage: v = W.from_reduced_word([1,2,3,4,3,1]) sage: v.apply_demazure_product([1,3,4,3,3]) @@ -2120,9 +2123,9 @@ def apply_demazure_product(self, element, side = 'right', length_increasing = Tr s3*s4*s1*s2*s3*s4*s2*s3*s1 sage: v.apply_demazure_product(v) s2*s3*s4*s1*s2*s3*s4*s2*s3*s2*s1 - + """ - + # if self and element have the same parent if self.parent().is_parent_of(element): the_word = element.reduced_word() @@ -2143,17 +2146,17 @@ def apply_demazure_product(self, element, side = 'right', length_increasing = Tr for i in the_word: self = self.apply_simple_projection(i, side = side, length_increasing = length_increasing) return self - + def min_demazure_product_greater(self, element): r""" Finds the unique Bruhat-minimum element ``u`` such that ``v`` $\le$ ``w`` * ``u`` where ``v`` is ``self``, ``w`` is ``element`` and ``*`` is the Demazure product. - + INPUT: - + - ``element`` is either an element of the same Coxeter group as ``self`` or a list (such as a reduced word) of elements from the index set of the Coxeter group. - + EXAMPLES:: - + sage: W = WeylGroup(['A',4],prefix="s") sage: v = W.from_reduced_word([2,3,4,1,2]) sage: u = W.from_reduced_word([2,3,2,1]) @@ -2163,9 +2166,9 @@ def min_demazure_product_greater(self, element): s4*s2 sage: v.min_demazure_product_greater((2,3,2,1)) s4*s2 - + """ - + # if self and element have the same parent if self.parent().is_parent_of(element): the_word = element.reduced_word() @@ -2181,27 +2184,27 @@ def min_demazure_product_greater(self, element): if self.has_descent(i, side = 'left'): self = self.apply_simple_reflection(i, side = 'left') return self - + def deodhar_factor_element(self, w, index_set): r""" Returns Deodhar's Bruhat order factoring element. - + INPUT: - + - ``w`` is an element of the same Coxeter group ``W`` as ``self`` - ``index_set`` is a subset of Dynkin nodes defining a parabolic subgroup ``W'`` of ``W`` - + It is assumed that ``v = self`` and ``w`` are minimum length coset representatives for ``W/W'`` such that ``v`` $\le$ ``w`` in Bruhat order. - + OUTPUT: - + Deodhar's element ``f(v,w)`` is the unique element of ``W'`` such that, for all ``v'`` and ``w'`` in ``W'``, ``vv'`` $\le$ ``ww'`` in ``W`` if and only if ``v'`` $\le$ ``f(v,w) * w'`` in ``W'`` where ``*`` is the Demazure product. - + EXAMPLES:: - + sage: W = WeylGroup(['A',5],prefix="s") sage: v = W.from_reduced_word([5]) sage: w = W.from_reduced_word([4,5,2,3,1,2]) @@ -2213,13 +2216,13 @@ def deodhar_factor_element(self, w, index_set): Traceback (most recent call last): ... ValueError: [2, 1] is not of minimum length in its coset for the parabolic subgroup with index set [1] - + REFERENCES: - + .. [Deodhar] V. Deodhar, A splitting criterion for the Bruhat orderings on Coxeter groups. Comm. Algebra, 15:1889-1894, 1987. - + """ - + if self != self.coset_representative(index_set): raise ValueError("%s is not of minimum length in its coset for the parabolic subgroup with index set %s"%(self.reduced_word(),index_set)) if w != w.coset_representative(index_set): @@ -2238,35 +2241,35 @@ def deodhar_factor_element(self, w, index_set): if des is None: return dsp return dsp.apply_simple_projection(des, side = 'left') - + def deodhar_lift_up(self, w, index_set): """ Letting ``v = self``, given a Bruhat relation ``v W'`` $\le$ ``w W'`` among cosets with respect to the subgroup ``W'`` given by the Dynkin node subset ``index_set``, returns the Bruhat-minimum lift ``x`` of ``wW'`` such that ``v`` $\le$ ``x``. - + INPUT: - + - ``w`` is an element of the same Coxeter group ``W`` as ``self``. - ``index_set`` is a subset of Dynkin nodes defining a parabolic subgroup ``W'``. - + OUTPUT: - + The unique Bruhat-minimum element ``x`` in ``W`` such that ``x W' = w W'`` and ``v`` $\le$ ``x``. - + .. SEEALSO:: :meth:`sage.categories.coxeter_groups.CoxeterGroups.ElementMethods.deodhar_lift_down` - + EXAMPLES:: - + sage: W = WeylGroup(['A',3],prefix="s") sage: v = W.from_reduced_word([1,2,3]) sage: w = W.from_reduced_word([1,3,2]) sage: v.deodhar_lift_up(w, [3]) s1*s2*s3*s2 - + """ - + vmin = self.coset_representative(index_set) wmin = w.coset_representative(index_set) if not vmin.bruhat_le(wmin): @@ -2274,154 +2277,154 @@ def deodhar_lift_up(self, w, index_set): vJ = vmin.inverse() * self dsp = vmin.deodhar_factor_element(wmin,index_set) return wmin * vJ.min_demazure_product_greater(dsp) - + def deodhar_lift_down(self, w, index_set): r""" Letting ``v = self``, given a Bruhat relation ``v W'`` $\ge$ ``w W'`` among cosets with respect to the subgroup ``W'`` given by the Dynkin node subset ``index_set``, returns the Bruhat-maximum lift ``x`` of ``wW'`` such that ``v`` $\ge$ ``x``. - + INPUT: - + - ``w`` is an element of the same Coxeter group ``W`` as ``self``. - ``index_set`` is a subset of Dynkin nodes defining a parabolic subgroup ``W'``. - + OUTPUT: - + The unique Bruhat-maximum element ``x`` in ``W`` such that ``x W' = w W'`` and ``v $\ge$ ``x``. - + .. SEEALSO:: :meth:`sage.categories.coxeter_groups.CoxeterGroups.ElementMethods.deodhar_lift_up` - + EXAMPLES:: - + sage: W = WeylGroup(['A',3],prefix="s") sage: v = W.from_reduced_word([1,2,3,2]) sage: w = W.from_reduced_word([3,2]) sage: v.deodhar_lift_down(w, [3]) s2*s3*s2 - + """ - + vmin = self.coset_representative(index_set) wmin = w.coset_representative(index_set) if not wmin.bruhat_le(vmin): raise ValueError("Must have %s <= %s mod the parabolic subgroup with index set %s"%(w.reduced_word(), self.reduced_word(), index_set)) - + vJ = vmin.inverse() * self dsp = wmin.deodhar_factor_element(vmin,index_set) return wmin * dsp.apply_demazure_product(vJ) - + def apply_conjugation_by_simple_reflection(self, i): r""" Conjugates ``self`` by the ``i``-th simple reflection. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([3,1,2,1]) sage: w.apply_conjugation_by_simple_reflection(1).reduced_word() [3, 2] - + """ - + return (self.apply_simple_reflection(i)).apply_simple_reflection(i,side='left') - + @cached_in_parent_method def inversions_as_reflections(self): r""" Returns the set of reflections ``r`` such that ``self`` ``r < self``. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.inversions_as_reflections() [s1, s1*s2*s1, s2, s1*s2*s3*s2*s1] - + """ - + i = self.first_descent() if i is None: return [] wi = self.apply_simple_reflection(i) return [self.parent().simple_reflection(i)]+[u.apply_conjugation_by_simple_reflection(i) for u in wi.inversions_as_reflections()] - + def left_inversions_as_reflections(self): r""" Returns the set of reflections ``r`` such that ``r`` ``self`` < ``self``. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.left_inversions_as_reflections() [s1, s3, s1*s2*s3*s2*s1, s2*s3*s2] - + """ - + return self.inverse().inversions_as_reflections() - + def lower_covers(self, side = 'right', index_set = None): """ Returns all elements that ``self`` covers in weak order. - + INPUT: - + - side - 'left' or 'right' (default: 'right') - index_set - a list of indices or None - + OUTPUT: a list - + EXAMPLES:: - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([3,2,1]) sage: [x.reduced_word() for x in w.lower_covers()] [[3, 2]] - + To obtain covers for left weak order, set the option side to 'left':: - + sage: [x.reduced_word() for x in w.lower_covers(side='left')] [[2, 1]] sage: w = W.from_reduced_word([3,2,3,1]) sage: [x.reduced_word() for x in w.lower_covers()] [[2, 3, 2], [3, 2, 1]] - + Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - + sage: [x.reduced_word() for x in w.lower_covers(index_set = [1,2])] [[2, 3, 2]] sage: [x.reduced_word() for x in w.lower_covers(side='left')] [[3, 2, 1], [2, 3, 1]] """ return self.weak_covers(side = side, index_set = index_set, positive = False) - + def upper_covers(self, side = 'right', index_set = None): """ Returns all elements that cover ``self`` in weak order. - + INPUT: - + - side - 'left' or 'right' (default: 'right') - index_set - a list of indices or None - + OUTPUT: a list - + EXAMPLES:: - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([2,3]) sage: [x.reduced_word() for x in w.upper_covers()] [[2, 3, 1], [2, 3, 2]] - + To obtain covers for left weak order, set the option ``side`` to 'left':: - + sage: [x.reduced_word() for x in w.upper_covers(side = 'left')] [[1, 2, 3], [2, 3, 2]] - + Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - + sage: [x.reduced_word() for x in w.upper_covers(index_set = [1])] [[2, 3, 1]] sage: [x.reduced_word() for x in w.upper_covers(side = 'left', index_set = [1])] diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 91e2c1db758..bfe42e73c54 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -278,6 +278,139 @@ def weak_poset(self, side = "right", facade = False): weak_lattice = weak_poset + + @cached_method + def cambrian_lattice(self, c, side = "right", facade = False): + """ + INPUT: + + - ``c`` -- a standard Coxeter element in ``self`` (as a tuple, or as an element of ``self``) + - ``side`` -- "left", "right", or "twosided" (default: "right") + - ``facade`` -- a boolean (default: False) + + Return the left (resp. right) Cambrian lattice, which is the + sublattice of the weak lattice containing all + ``c``-sortable elements. + + EXAMPLES:: + + sage: CoxeterGroup(["A", 2]).cambrian_lattice((1,2)) + Finite lattice containing 5 elements + + sage: CoxeterGroup(["B", 2]).cambrian_lattice((1,2)) + Finite lattice containing 6 elements + + sage: CoxeterGroup(["G", 2]).cambrian_lattice((1,2)) + Finite lattice containing 8 elements + + """ + from sage.combinat.posets.lattices import LatticePoset + return LatticePoset(self.weak_lattice(side=side,facade=facade).subposet( [ w for w in self if w.is_coxeter_sortable(c) ] )) + + def inversion_sequence(self, word): + """ + INPUT: + + - ``word`` -- a word in the simple generators of ``self`` + + Return the inversion sequence corresponding to ``word``. If + ``word``=`[w_0,w_1,...w_k]`, then the output is `[w_0,w_0w_1w_0,\ldots,w_0w_1\cdots w_k \cdots w_1 w_0]`. + + EXAMPLES:: + + sage: CoxeterGroup(["A", 2]).inversion_sequence([1,2,1]) + [ + [-1 1] [ 0 -1] [ 1 0] + [ 0 1], [-1 0], [ 1 -1] + ] + + sage: [t.reduced_word() for t in CoxeterGroup(["A",3]).inversion_sequence([2,1,3,2,1,3])] + [[2], [1, 2, 1], [2, 3, 2], [1, 2, 3, 2, 1], [3], [1]] + + """ + return [self.from_reduced_word(word[:i+1]+list(reversed(word[:i]))) for i in range(len(word))] + + def reflections_from_w0(self): + """ + Return the reflections of ``self`` using the inversion set of ``w_0``. + + EXAMPLES:: + + sage: WeylGroup(['A',2]).reflections_from_w0() + [ + [0 1 0] [0 0 1] [1 0 0] + [1 0 0] [0 1 0] [0 0 1] + [0 0 1], [1 0 0], [0 1 0] + ] + + sage: WeylGroup(['A',3]).reflections_from_w0() + [ + [-1 1 0] [ 0 -1 1] [ 1 0 0] [ 0 0 -1] [ 1 0 0] [ 1 0 0] + [ 0 1 0] [-1 0 1] [ 1 -1 1] [-1 1 -1] [ 1 0 -1] [ 0 1 0] + [ 0 0 1], [ 0 0 1], [ 0 0 1], [-1 0 0], [ 1 -1 0], [ 0 1 -1] + ] + + """ + return self.long_element().inversions_as_reflections() + + @cached_method + def m_cambrian_lattice(self, c, m = 1): + """ + INPUT: + + - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) + - ``m`` -- a positive integer (default: 1) + + Returns the m-Cambrian lattice on delta sequences. + + EXAMPLES:: + + sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2)) + Finite poset containing 5 elements + + sage: CoxeterGroup(["A",2]).m_Cambrian_Lattice([1,2],2) + Finite poset containing 12 elements + + """ + from sage.combinat.posets.posets import Poset + from sage.combinat.posets.lattices import LatticePoset + if hasattr(c,"reduced_word"): + c = c.reduced_word() + elif not isinstance(c,list): + c = list(c) + inv_woc = self.inversion_sequence(self.long_element().coxeter_sorting_word(c)) + S = self.simple_reflections() + T = self.reflections_from_w0() + Twords = {t:t.reduced_word() for t in T}#PhiP=T + id = sorted([[s,0] for s in S]) + elements = [] + covers = [] + new = [id] + while new != []: + for new_element in new: + new.remove(new_element) + elements.append(new_element) + for t in new_element: + if t[1] Date: Thu, 4 Jun 2015 20:06:10 +0300 Subject: [PATCH 0239/1872] Made tests pass in matrixcoxetergroup --- src/sage/combinat/root_system/coxeter_matrix.py | 6 +++++- src/sage/groups/matrix_gps/coxeter_group.py | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index ec45f318876..f65c0b828c1 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -305,7 +305,7 @@ def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): else: coxeter_type = None if not index_set: - index_set = range(n) + index_set = tuple(range(1,n+1)) raw_data = M.list() @@ -1216,6 +1216,10 @@ def recognize_coxeter_type_from_matrix(coxeter_matrix): # on a degree 3 vertex. types.append(['B', l-1, 1]) continue + else: + return None + else: + return None else: return None diff --git a/src/sage/groups/matrix_gps/coxeter_group.py b/src/sage/groups/matrix_gps/coxeter_group.py index 654894c4110..d4a46d4933b 100644 --- a/src/sage/groups/matrix_gps/coxeter_group.py +++ b/src/sage/groups/matrix_gps/coxeter_group.py @@ -259,7 +259,7 @@ def __init__(self, coxeter_matrix, base_ring, index_set): from sage.functions.trig import cos from sage.symbolic.constants import pi val = lambda x: base_ring(2*cos(pi / x)) if x != -1 else base_ring(2) - gens = [MS.one() + MC(MS, entries={(i, j): val(coxeter_matrix[i, j]) + gens = [MS.one() + MC(MS, entries={(i, j): val(coxeter_matrix[index_set[i], index_set[j]]) for j in range(n)}, coerce=True, copy=True) for i in range(n)] @@ -494,7 +494,7 @@ def coxeter_diagram(self): sage: CoxeterGroup(W.coxeter_diagram()) is W True """ - return self._matrix.coxeter_diagram() + return self._matrix.coxeter_graph() coxeter_graph = deprecated_function_alias(17798, coxeter_diagram) @@ -522,7 +522,7 @@ def bilinear_form(self): [ 0 -1/2 1 0] [ 0 -1/2 0 1] """ - return self._matrix.bilinear_form(self.base_ring()) + return self._matrix.bilinear_form() def is_finite(self): """ From c37a5efb5841aa5e9ce49d1df02201fa29910165 Mon Sep 17 00:00:00 2001 From: Nathan Williams Date: Thu, 4 Jun 2015 17:47:47 -0500 Subject: [PATCH 0240/1872] things appear to work in the sense that all tests have passed. --- src/sage/categories/coxeter_groups.py | 4 +- src/sage/categories/finite_coxeter_groups.py | 42 ++++++++++---------- src/sage/categories/finite_weyl_groups.py | 22 ++++++---- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 1402bfbb954..6af0e9c2ac8 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -2008,8 +2008,8 @@ def coxeter_sorting_word(self,c): sage: w.coxeter_sorting_word(c) [2, 1, 2, 0, 1] - sage: W = WyelGroup(['A',2]).long_element().coxeter_sorting_word([1,2]) - [1,2,1] + sage: WeylGroup(['A',2]).long_element().coxeter_sorting_word([1,2]) + [1, 2, 1] """ if hasattr(c,"reduced_word"): c = c.reduced_word() diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index bfe42e73c54..32454fd7bcd 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -278,19 +278,16 @@ def weak_poset(self, side = "right", facade = False): weak_lattice = weak_poset - + @cached_method - def cambrian_lattice(self, c, side = "right", facade = False): + def cambrian_lattice(self, c): """ INPUT: - ``c`` -- a standard Coxeter element in ``self`` (as a tuple, or as an element of ``self``) - - ``side`` -- "left", "right", or "twosided" (default: "right") - - ``facade`` -- a boolean (default: False) - - Return the left (resp. right) Cambrian lattice, which is the - sublattice of the weak lattice containing all - ``c``-sortable elements. + + Returns the c-Cambrian lattice on delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). + Delta sequences are certain 2-colored minimal factorizations of ``c`` into reflections. EXAMPLES:: @@ -305,8 +302,8 @@ def cambrian_lattice(self, c, side = "right", facade = False): """ from sage.combinat.posets.lattices import LatticePoset - return LatticePoset(self.weak_lattice(side=side,facade=facade).subposet( [ w for w in self if w.is_coxeter_sortable(c) ] )) - + return self.m_cambrian_lattice(c,1) + def inversion_sequence(self, word): """ INPUT: @@ -342,13 +339,13 @@ def reflections_from_w0(self): [1 0 0] [0 1 0] [0 0 1] [0 0 1], [1 0 0], [0 1 0] ] - - sage: WeylGroup(['A',3]).reflections_from_w0() - [ - [-1 1 0] [ 0 -1 1] [ 1 0 0] [ 0 0 -1] [ 1 0 0] [ 1 0 0] - [ 0 1 0] [-1 0 1] [ 1 -1 1] [-1 1 -1] [ 1 0 -1] [ 0 1 0] - [ 0 0 1], [ 0 0 1], [ 0 0 1], [-1 0 0], [ 1 -1 0], [ 0 1 -1] - ] + + sage: WeylGroup(['A',3]).reflections_from_w0() + [ + [-1 1 0] [ 0 -1 1] [ 1 0 0] [ 0 0 -1] [ 1 0 0] [ 1 0 0] + [ 0 1 0] [-1 0 1] [ 1 -1 1] [-1 1 -1] [ 1 0 -1] [ 0 1 0] + [ 0 0 1], [ 0 0 1], [ 0 0 1], [-1 0 0], [ 1 -1 0], [ 0 1 -1] + ] """ return self.long_element().inversions_as_reflections() @@ -361,15 +358,16 @@ def m_cambrian_lattice(self, c, m = 1): - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) - ``m`` -- a positive integer (default: 1) - Returns the m-Cambrian lattice on delta sequences. + Return the m-Cambrian lattice on ``m``-delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). + ``m``-delta sequences are certain ``m``-colored minimal factorizations of ``c`` into reflections. EXAMPLES:: - sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2)) - Finite poset containing 5 elements + sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2)) + Finite lattice containing 5 elements - sage: CoxeterGroup(["A",2]).m_Cambrian_Lattice([1,2],2) - Finite poset containing 12 elements + sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2),2) + Finite lattice containing 12 elements """ from sage.combinat.posets.posets import Poset diff --git a/src/sage/categories/finite_weyl_groups.py b/src/sage/categories/finite_weyl_groups.py index 9fbf1f27425..b6ce9b81e3e 100644 --- a/src/sage/categories/finite_weyl_groups.py +++ b/src/sage/categories/finite_weyl_groups.py @@ -9,6 +9,7 @@ #****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom +from sage.misc.cachefunc import cached_method, cached_in_parent_method class FiniteWeylGroups(CategoryWithAxiom): """ @@ -58,7 +59,8 @@ class FiniteWeylGroups(CategoryWithAxiom): """ class ParentMethods: - + + @cached_method def m_cambrian_lattice(W,c,m): """ INPUT: @@ -66,17 +68,23 @@ def m_cambrian_lattice(W,c,m): - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) - ``m`` -- a positive integer (default: 1) - Returns the m-Cambrian lattice on delta sequences. + Return the m-Cambrian lattice on ``m``-delta sequences, realized on roots rather than reflections. EXAMPLES:: - sage: WeylGroup(["A",2]).m_cambrian_lattice((1,2)) - Finite poset containing 5 elements + sage: WeylGroup(["A",2]).m_cambrian_lattice((1,2),1) + Finite lattice containing 5 elements - sage: WeylGroup(["A",2]).m_Cambrian_Lattice([1,2],2) - Finite poset containing 12 elements + sage: WeylGroup(["A",2]).m_cambrian_lattice((1,2),2) + Finite lattice containing 12 elements """ + from sage.combinat.posets.posets import Poset + from sage.combinat.posets.lattices import LatticePoset + if hasattr(c,"reduced_word"): + c = c.reduced_word() + elif not isinstance(c,list): + c = list(c) inv_woc = [t.reflection_to_root() for t in W.inversion_sequence(W.long_element().coxeter_sorting_word(c))] S = [s.reflection_to_root() for s in W.simple_reflections()] PhiP = [t.reflection_to_root() for t in W.reflections().keys()] @@ -104,7 +112,7 @@ def m_cambrian_lattice(W,c,m): if cov_element not in elements and cov_element not in new: new.append(cov_element) covers.append([tuple(map(tuple,new_element)),tuple(map(tuple,cov_element))]) - return Poset([[tuple(map(tuple,e)) for e in elements],covers],cover_relations=True) + return LatticePoset([[tuple(map(tuple,e)) for e in elements],covers],cover_relations=True) class ElementMethods: From 1862325350cb6ac88f1033c53e4915428a74698c Mon Sep 17 00:00:00 2001 From: Nathan Williams Date: Fri, 5 Jun 2015 10:36:09 -0500 Subject: [PATCH 0241/1872] removed trailing whitespace. --- src/sage/categories/coxeter_groups.py | 968 +++++++++---------- src/sage/categories/finite_coxeter_groups.py | 50 +- src/sage/categories/finite_weyl_groups.py | 26 +- 3 files changed, 522 insertions(+), 522 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 6af0e9c2ac8..cfe67fb57f5 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -26,50 +26,50 @@ class CoxeterGroups(Category_singleton): r""" The category of Coxeter groups. - + A *Coxeter group* is a group `W` with a distinguished (finite) family of involutions `(s_i)_{i\in I}`, called the *simple reflections*, subject to relations of the form `(s_is_j)^{m_{i,j}} = 1`. - + `I` is the *index set* of `W` and `|I|` is the *rank* of `W`. - + See :Wikipedia:`Coxeter_group` for details. - + EXAMPLES:: - + sage: C = CoxeterGroups(); C Category of coxeter groups sage: C.super_categories() [Category of finitely generated groups] - + sage: W = C.example(); W The symmetric group on {0, ..., 3} - + sage: W.simple_reflections() Finite family {0: (1, 0, 2, 3), 1: (0, 2, 1, 3), 2: (0, 1, 3, 2)} - + Here are some further examples:: - + sage: FiniteCoxeterGroups().example() The 5-th dihedral group of order 10 sage: FiniteWeylGroups().example() The symmetric group on {0, ..., 3} sage: WeylGroup(["B", 3]) Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space) - + Those will eventually be also in this category:: - + sage: SymmetricGroup(4) Symmetric group of order 4! as a permutation group sage: DihedralGroup(5) Dihedral group of order 10 as a permutation group - + .. TODO:: add a demo of usual computations on Coxeter groups. - + .. SEEALSO:: :class:`WeylGroups`, :mod:`sage.combinat.root_system` - + .. WARNING:: - + It is assumed that morphisms in this category preserve the distinguished choice of simple reflections. In particular, subobjects in this category are parabolic subgroups. In this @@ -77,12 +77,12 @@ class CoxeterGroups(Category_singleton): Systems``. In the long run we might want to have two distinct categories, one for Coxeter groups (with morphisms being just group morphisms) and one for Coxeter systems:: - + sage: CoxeterGroups().is_full_subcategory(Groups()) False - + TESTS:: - + sage: W = CoxeterGroups().example(); TestSuite(W).run(verbose = "True") running ._test_an_element() . . . pass running ._test_associativity() . . . pass @@ -112,60 +112,60 @@ class CoxeterGroups(Category_singleton): running ._test_simple_projections() . . . pass running ._test_some_elements() . . . pass """ - + def super_categories(self): """ EXAMPLES:: - + sage: CoxeterGroups().super_categories() [Category of finitely generated groups] """ return [Groups().FinitelyGenerated()] - + Finite = LazyImport('sage.categories.finite_coxeter_groups', 'FiniteCoxeterGroups') Algebras = LazyImport('sage.categories.coxeter_group_algebras', 'CoxeterGroupAlgebras') - + class ParentMethods: - + @abstract_method def index_set(self): """ Returns the index set of (the simple reflections of) ``self``, as a list (or iterable). - + EXAMPLES:: - + sage: W = FiniteCoxeterGroups().example(); W The 5-th dihedral group of order 10 sage: W.index_set() [1, 2] """ # return self.simple_reflections().keys() - + def _an_element_(self): """ Implements: :meth:`Sets.ParentMethods.an_element` by returning the product of the simple reflections (a Coxeter element). - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} sage: W.an_element() # indirect doctest (1, 2, 3, 0) - + """ return self.prod(self.simple_reflections()) - + def some_elements(self): """ Implements :meth:`Sets.ParentMethods.some_elements` by returning some typical element of `self`. - + EXAMPLES:: - + sage: W=WeylGroup(['A',3]) sage: W.some_elements() [ @@ -178,13 +178,13 @@ def some_elements(self): 24 """ return list(self.simple_reflections()) + [ self.one(), self.an_element() ] - + def __iter__(self): r""" Returns an iterator over the elements of this Coxeter group. - + EXAMPLES:: - + sage: D5 = FiniteCoxeterGroups().example(5) sage: sorted(list(D5)) # indirect doctest (but see :meth:`._test_enumerated_set_iter_list`) [(), @@ -197,7 +197,7 @@ def __iter__(self): (2, 1), (2, 1, 2), (2, 1, 2, 1)] - + sage: W = WeylGroup(["A",2,1]) sage: g = iter(W) sage: next(g) @@ -214,30 +214,30 @@ def __iter__(self): [ 0 0 1] """ return iter(self.weak_order_ideal(predicate = ConstantFunction(True))) - + def weak_order_ideal(self, predicate, side ="right", category = None): """ Returns a weak order ideal defined by a predicate - + INPUT: - + - ``predicate``: a predicate on the elements of ``self`` defining an weak order ideal in ``self`` - ``side``: "left" or "right" (default: "right") - + OUTPUT: an enumerated set - + EXAMPLES:: - + sage: D6 = FiniteCoxeterGroups().example(5) sage: I = D6.weak_order_ideal(predicate = lambda w: w.length() <= 3) sage: I.cardinality() 7 sage: list(I) [(), (1,), (1, 2), (1, 2, 1), (2,), (2, 1), (2, 1, 2)] - + We now consider an infinite Coxeter group:: - + sage: W = WeylGroup(["A",1,1]) sage: I = W.weak_order_ideal(predicate = lambda w: w.length() <= 2) sage: list(iter(I)) @@ -245,16 +245,16 @@ def weak_order_ideal(self, predicate, side ="right", category = None): [1 0] [-1 2] [ 3 -2] [ 1 0] [-1 2] [0 1], [ 0 1], [ 2 -1], [ 2 -1], [-2 3] ] - + Even when the result is finite, some features of :class:`FiniteEnumeratedSets` are not available:: - + sage: I.cardinality() # todo: not implemented 5 sage: list(I) # todo: not implemented - + unless this finiteness is explicitly specified:: - + sage: I = W.weak_order_ideal(predicate = lambda w: w.length() <= 2, ... category = FiniteEnumeratedSets()) sage: I.cardinality() @@ -264,14 +264,14 @@ def weak_order_ideal(self, predicate, side ="right", category = None): [1 0] [-1 2] [ 3 -2] [ 1 0] [-1 2] [0 1], [ 0 1], [ 2 -1], [ 2 -1], [-2 3] ] - + .. rubric:: Background - + The weak order is returned as a :class:`SearchForest`. This is achieved by assigning to each element `u1` of the ideal a single ancestor `u=u1 s_i`, where `i` is the smallest descent of `u`. - + This allows for iterating through the elements in roughly Constant Amortized Time and constant memory (taking the operations and size of the generated objects @@ -287,17 +287,17 @@ def succ(u): from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups default_category = FiniteEnumeratedSets() if self in FiniteCoxeterGroups() else EnumeratedSets() return SearchForest((self.one(),), succ, category = default_category.or_subcategory(category)) - + def grassmannian_elements(self, side = "right"): """ INPUT: - + - ``side``: "left" or "right" (default: "right") - + Returns the left or right grassmanian elements of self, as an enumerated set - + EXAMPLES:: - + sage: S = CoxeterGroups().example() sage: G = S.grassmannian_elements() sage: G.cardinality() @@ -314,24 +314,24 @@ def grassmannian_elements(self, side = "right"): """ order_side = "left" if side == "right" else "right" return self.weak_order_ideal(attrcall("is_grassmannian", side = side), side = order_side) - + def from_reduced_word(self, word): r""" INPUT: - + - ``word`` - a list (or iterable) of elements of ``self.index_set()`` - + Returns the group element corresponding to the given word. Namely, if ``word`` is `[i_1,i_2,\ldots,i_k]`, then this returns the corresponding product of simple reflections `s_{i_1} s_{i_2} \cdots s_{i_k}`. - + Note: the main use case is for constructing elements from reduced words, hence the name of this method. But actually the input word need *not* be reduced. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -342,13 +342,13 @@ def from_reduced_word(self, word): (0, 3, 1, 2) sage: s[0]*s[2]*s[0]*s[1] (0, 3, 1, 2) - + See also :meth:'._test_reduced_word':: - + sage: W._test_reduced_word() - + TESTS:: - + sage: W=WeylGroup(['E',6]) sage: W.from_reduced_word([2,3,4,2]) [ 0 1 0 0 0 0 0 0] @@ -359,20 +359,20 @@ def from_reduced_word(self, word): [ 0 0 0 0 0 1 0 0] [ 0 0 0 0 0 0 1 0] [ 0 0 0 0 0 0 0 1] - + """ return self.one().apply_simple_reflections(word, side = 'right') - + def _test_reduced_word(self, **options): """ Runs sanity checks on :meth:'CoxeterGroups.ElementMethods.reduced_word' and :meth:'.from_reduced_word`. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W._test_reduced_word() - + """ tester = self._tester(**options) s = self.simple_reflections() @@ -380,17 +380,17 @@ def _test_reduced_word(self, **options): red = x.reduced_word() tester.assertEquals(self.from_reduced_word(red), x) tester.assertEquals(self.prod((s[i] for i in red)), x) - + def simple_reflection(self, i): """ INPUT: - + - ``i`` - an element from the index set. - + Returns the simple reflection `s_i` - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -399,19 +399,19 @@ def simple_reflection(self, i): sage: s = W.simple_reflections() sage: s[1] (0, 2, 1, 3) - + """ if not i in self.index_set(): raise ValueError("%s is not in the Dynkin node set %s"%(i,self.index_set())) return self.one().apply_simple_reflection(i) # don't care about left/right - + @cached_method def simple_reflections(self): r""" Returns the simple reflections `(s_i)_{i\in I}`, as a family. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -425,41 +425,41 @@ def simple_reflections(self): sage: s[2] (0, 1, 3, 2) - + This default implementation uses :meth:`.index_set` and :meth:`.simple_reflection`. """ from sage.sets.family import Family return Family(self.index_set(), self.simple_reflection) - + @cached_method def rank(self): r""" Return the rank of ``self``. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W.rank() 3 """ return len(self.simple_reflections()) - + def group_generators(self): r""" Implements :meth:`Groups.ParentMethods.group_generators` by returning the simple reflections of ``self``. - + EXAMPLES:: - + sage: D10 = FiniteCoxeterGroups().example(10) sage: D10.group_generators() Finite family {1: (1,), 2: (2,)} sage: SymmetricGroup(5).group_generators() Finite family {1: (1,2), 2: (2,3), 3: (3,4), 4: (4,5)} - + Those give semigroup generators, even for an infinite group:: - + sage: W = WeylGroup(["A",2,1]) sage: W.semigroup_generators() Finite family {0: [-1 1 1] @@ -473,22 +473,22 @@ def group_generators(self): [ 1 1 -1]} """ return self.simple_reflections() - + semigroup_generators = group_generators - + def simple_projection(self, i, side = 'right', length_increasing = True): r""" INPUT: - + - ``i`` - an element of the index set of ``self`` - + Returns the simple projection `\pi_i` (or `\overline\pi_i` if `length_increasing` is False). - + See :meth:`.simple_projections` for the options and for the definition of the simple projections. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -513,48 +513,48 @@ def simple_projection(self, i, side = 'right', length_increasing = True): (1, 2, 3, 0) sage: d0(pi) (1, 2, 3, 0) - + """ if not (i in self.index_set() or i == 0): raise ValueError("%s is not 0 and not in the Dynkin node set %s"%(i, self.index_set())) return lambda x: x.apply_simple_projection(i, side = side, length_increasing = length_increasing) - + @cached_method def simple_projections(self, side = 'right', length_increasing = True): r""" Returns the family of simple projections, also known as 0-Hecke or Demazure operators. - + INPUT: - + - ``self`` - a Coxeter group `W` - ``side`` - 'left' or 'right' (default: 'right') - ``length_increasing`` - a boolean (default: True) specifying whether the operator increases or decreases length - + Returns the simple projections of `W`, as a family. - + To each simple reflection `s_i` of `W`, corresponds a *simple projection* `\pi_i` from `W` to `W` defined by: - + `\pi_i(w) = w s_i` if `i` is not a descent of `w` `\pi_i(w) = w` otherwise. - + The simple projections `(\pi_i)_{i\in I}` move elements down the right permutohedron, toward the maximal element. They satisfy the same braid relations as the simple reflections, but are idempotents `\pi_i^2=\pi` not involutions `s_i^2 = 1`. As such, the simple projections generate the `0`-Hecke monoid. - + By symmetry, one can also define the projections `(\overline\pi_i)_{i\in I}` (when the option ``length_increasing`` is False): - + `\overline\pi_i(w) = w s_i` if `i` is a descent of `w` `\overline\pi_i(w) = w` otherwise. - + as well as the analogues acting on the left (when the option ``side`` is 'left'). - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W The symmetric group on {0, ..., 3} @@ -572,43 +572,43 @@ def simple_projections(self, side = 'right', length_increasing = True): """ from sage.sets.family import Family return Family(self.index_set(), lambda i: self.simple_projection(i, side = side, length_increasing = length_increasing)) - + def demazure_product(self,Q): r""" Returns the Demazure product of the list ``Q`` in ``self``. - + INPUT: - + - ``Q`` is a list of elements from the index set of ``self``. - + This returns the Coxeter group element that represents the composition of 0-Hecke or Demazure operators. See :meth:`CoxeterGroups.ParentMethods.simple_projections`. - + EXAMPLES:: - + sage: W = WeylGroup(['A',2]) sage: w = W.demazure_product([2,2,1]) sage: w.reduced_word() [2, 1] - + sage: w = W.demazure_product([2,1,2,1,2]) sage: w.reduced_word() [1, 2, 1] - + sage: W = WeylGroup(['B',2]) sage: w = W.demazure_product([2,1,2,1,2]) sage: w.reduced_word() [2, 1, 2, 1] - + """ return self.one().apply_demazure_product(Q) - + def bruhat_interval(self, x, y): """ Returns the list of t such that x <= t <= y. - + EXAMPLES:: - + sage: W = WeylGroup("A3", prefix="s") sage: [s1,s2,s3]=W.simple_reflections() sage: W.bruhat_interval(s2,s1*s3*s2*s1*s3) @@ -637,13 +637,13 @@ def bruhat_interval(self, x, y): nextlayer.append(t) ret.append(nextlayer) return flatten(ret) - + def canonical_representation(self): r""" Return the canonical faithful representation of ``self``. - + EXAMPLES:: - + sage: W = WeylGroup("A3") sage: W.canonical_representation() Finite Coxeter group over Universal Cyclotomic Field with Coxeter matrix: @@ -654,47 +654,47 @@ def canonical_representation(self): from sage.groups.matrix_gps.coxeter_group import CoxeterMatrixGroup return CoxeterMatrixGroup(self.coxeter_matrix(), index_set=self.index_set()) - + def elements_of_length(self, n): r""" Return all elements of length `n`. - + EXAMPLES:: - + sage: A = AffinePermutationGroup(['A',2,1]) sage: [len(list(A.elements_of_length(i))) for i in [0..5]] [1, 3, 6, 9, 12, 15] - + sage: W = CoxeterGroup(['H',3]) sage: [len(list(W.elements_of_length(i))) for i in range(4)] [1, 3, 5, 7] - + sage: W = CoxeterGroup(['A',2]) sage: [len(list(W.elements_of_length(i))) for i in range(6)] [1, 2, 2, 1, 0, 0] """ I = self.weak_order_ideal(ConstantFunction(True), side='right') return I.elements_of_depth_iterator(n) - + def random_element_of_length(self, n): r""" Return a random element of length ``n`` in ``self``. - + Starts at the identity, then chooses an upper cover at random. - + Not very uniform: actually constructs a uniformly random reduced word of length `n`. Thus we most likely get elements with lots of reduced words! - + EXAMPLES:: - + sage: A = AffinePermutationGroup(['A', 7, 1]) sage: p = A.random_element_of_length(10) sage: p in A True sage: p.length() == 10 True - + sage: W = CoxeterGroup(['A', 4]) sage: p = W.random_element_of_length(5) sage: p in W @@ -709,20 +709,20 @@ def random_element_of_length(self, n): rnd = randint(0, len(antiD) - 1) x = x.apply_simple_reflection_right(antiD[rnd]) return x - + # TODO: Groups() should have inverse() call __invert__ # With strong doc stating that this is just a convenience for the user # and links to ~ / __invert__ - + # parabolic_subgroup - + def _test_simple_projections(self, **options): """ Runs sanity checks on :meth:`.simple_projections` and :meth:`CoxeterGroups.ElementMethods.apply_simple_projection` - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W._test_simple_projections() """ @@ -740,15 +740,15 @@ def _test_simple_projections(self, **options): tester.assertEquals(set([pi[i](w), opi[i](w)]), set([w, w.apply_simple_reflection(i, side = side)])) - + def _test_has_descent(self, **options): """ Runs sanity checks on the method :meth:`CoxeterGroups.ElementMethods.has_descent` of the elements of self. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: W._test_has_descent() """ @@ -776,16 +776,16 @@ def _test_has_descent(self, **options): tester.assert_((s[i]*s[j]).has_descent(j, side = 'right')) tester.assertEquals((s[i]*s[j]).has_descent(j, side = 'left' ), u == v) tester.assertEquals((s[i]*s[j]).has_descent(i, side = 'right'), u == v) - + class ElementMethods: def has_descent(self, i, side = 'right', positive=False): """ Returns whether i is a (left/right) descent of self. - + See :meth:`.descents` for a description of the options. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: s = W.simple_reflections() sage: w = s[0] * s[1] * s[2] @@ -797,7 +797,7 @@ def has_descent(self, i, side = 'right', positive=False): [True, False, False] sage: [ w.has_descent(i, positive = True) for i in [0,1,2] ] [True, True, False] - + This default implementation delegates the work to :meth:`.has_left_descent` and :meth:`.has_right_descent`. """ @@ -813,9 +813,9 @@ def has_descent(self, i, side = 'right', positive=False): def has_right_descent(self, i): """ Returns whether ``i`` is a right descent of self. - + EXAMPLES:: - + sage: W = CoxeterGroups().example(); W The symmetric group on {0, ..., 3} sage: w = W.an_element(); w @@ -834,12 +834,12 @@ def has_right_descent(self, i): def has_left_descent(self, i): """ Returns whether `i` is a left descent of self. - + This default implementation uses that a left descent of `w` is a right descent of `w^{-1}`. - + EXAMPLES:: - + sage: W = CoxeterGroups().example(); W The symmetric group on {0, ..., 3} sage: w = W.an_element(); w @@ -850,23 +850,23 @@ def has_left_descent(self, i): False sage: w.has_left_descent(2) False - + TESTS:: - + sage: w.has_left_descent.__module__ 'sage.categories.coxeter_groups' """ return (~self).has_right_descent(i) - + def first_descent(self, side = 'right', index_set=None, positive=False): """ Returns the first left (resp. right) descent of self, as ane element of ``index_set``, or ``None`` if there is none. - + See :meth:`.descents` for a description of the options. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: s = W.simple_reflections() sage: w = s[2]*s[0] @@ -885,33 +885,33 @@ def first_descent(self, side = 'right', index_set=None, positive=False): if self.has_descent(i, side = side, positive = positive): return i return None - + def descents(self, side = 'right', index_set=None, positive=False): """ INPUT: - + - ``index_set`` - a subset (as a list or iterable) of the nodes of the Dynkin diagram; (default: all of them) - ``side`` - 'left' or 'right' (default: 'right') - ``positive`` - a boolean (default: ``False``) - + Returns the descents of self, as a list of elements of the index_set. - + The ``index_set`` option can be used to restrict to the parabolic subgroup indexed by ``index_set``. - + If positive is ``True``, then returns the non-descents instead - + TODO: find a better name for ``positive``: complement? non_descent? - + Caveat: the return type may change to some other iterable (tuple, ...) in the future. Please use keyword arguments also, as the order of the arguments may change as well. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: s=W.simple_reflections() sage: w=s[0]*s[1] @@ -920,24 +920,24 @@ def descents(self, side = 'right', index_set=None, positive=False): sage: w=s[0]*s[2] sage: w.descents() [0, 2] - + TODO: side, index_set, positive """ if index_set is None: index_set=self.parent().index_set() return [ i for i in index_set if self.has_descent(i, side = side, positive = positive) ] - + def is_grassmannian(self, side = "right"): """ INPUT: - + - ``side`` - "left" or "right" (default: "right") - + Tests whether ``self`` is Grassmannian, i.e. it has at most one descent on the right (resp. on the left). v EXAMPLES:: - + sage: W = CoxeterGroups().example(); W The symmetric group on {0, ..., 3} sage: s = W.simple_reflections() @@ -951,7 +951,7 @@ def is_grassmannian(self, side = "right"): True sage: (s[1]*s[2]*s[1]).is_grassmannian() False - + sage: (s[0]*s[2]*s[1]).is_grassmannian(side = "left") False sage: (s[0]*s[2]*s[1]).is_grassmannian(side = "right") @@ -960,13 +960,13 @@ def is_grassmannian(self, side = "right"): True """ return len(self.descents(side = side)) <= 1 - + def reduced_word_reverse_iterator(self): """ Return a reverse iterator on a reduced word for ``self``. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: s = W.simple_reflections() sage: sigma = s[0]*s[1]*s[2] @@ -977,15 +977,15 @@ def reduced_word_reverse_iterator(self): True sage: sigma.length() 3 - + .. SEEALSO:: - + :meth:`.reduced_word` - + Default implementation: recursively remove the first right descent until the identity is reached (see :meth:`.first_descent` and :meth:`apply_simple_reflection`). - + """ while True: i = self.first_descent() @@ -993,18 +993,18 @@ def reduced_word_reverse_iterator(self): return self = self.apply_simple_reflection(i, 'right') yield i - + def reduced_word(self): r""" 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} = \operatorname{self}`, where the `s_i` are the simple reflections. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: s=W.simple_reflections() sage: w=s[0]*s[1]*s[2] @@ -1013,45 +1013,45 @@ def reduced_word(self): sage: w=s[0]*s[2] sage: w.reduced_word() [2, 0] - + .. 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)) - + #def lex_min_reduced_word(w): # return list(reversed((w.inverse()).reduced_word())) - + def support(self): r""" Return the support of ``self``, that is the simple reflections that appear in the reduced expressions of ``self``. - + OUTPUT: - + The support of ``self`` as a set of integers - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: w = W.from_reduced_word([1,2,1]) sage: w.support() {1, 2} """ return set(self.reduced_word()) - + def has_full_support(self): r""" Return whether ``self`` has full support. - + An element is said to have full support if its support contains all simple reflections. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: w = W.from_reduced_word([1,2,1]) sage: w.has_full_support() @@ -1061,16 +1061,16 @@ def has_full_support(self): True """ return self.support() == set(self.parent().index_set()) - + def reduced_words(self): r""" Return all reduced words for ``self``. - + See :meth:`reduced_word` for the definition of a reduced word. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: s=W.simple_reflections() sage: w=s[0]*s[2] @@ -1080,12 +1080,12 @@ def reduced_words(self): sage: w=W.from_reduced_word([2,3,4,2]) sage: w.reduced_words() [[3, 2, 4, 2], [2, 3, 4, 2], [3, 4, 2, 4]] - + 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` """ @@ -1097,23 +1097,23 @@ def reduced_words(self): for i in self.descents() 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 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:: - + sage: W = WeylGroup(['A',3], prefix='s') sage: w0 = W.long_element() sage: G = w0.reduced_word_graph() @@ -1127,18 +1127,18 @@ def reduced_word_graph(self): 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` """ @@ -1147,7 +1147,7 @@ def reduced_word_graph(self): # 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): @@ -1178,14 +1178,14 @@ def reduced_word_graph(self): 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 a product of simple reflections giving self. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: s1 = W.simple_reflection(1) sage: s2 = W.simple_reflection(2) @@ -1201,25 +1201,25 @@ def length(self): sage: W = CoxeterGroups().example() sage: sum((x^w.length()) for w in W) - expand(prod(sum(x^i for i in range(j+1)) for j in range(4))) # This is scandalously slow!!! 0 - + SEE ALSO: :meth:`.reduced_word` - + TODO: Should use reduced_word_iterator (or reverse_iterator) - + """ return len(self.reduced_word()) - + def absolute_length(self): """ Return the absolute length of ``self`` - + The absolute length is the length of the shortest expression of the element as a product of reflections. - + .. SEEALSO:: :meth:`absolute_le`. - + EXAMPLES:: - + sage: W = WeylGroup(["A", 3]) sage: s = W.simple_reflections() sage: (s[1]*s[2]*s[3]).absolute_length() @@ -1227,24 +1227,24 @@ def absolute_length(self): """ M = self.canonical_matrix() return (M - 1).image().dimension() - + def absolute_le(self, other): r""" Return whether ``self`` is smaller than ``other`` in the absolute order. - + A general reflection is an element of the form `w s_i w^{-1}`, where `s_i` is a simple reflection. The absolute order is defined analogously to the weak order but using general reflections rather than just simple reflections. - + This partial order can be used to define noncrossing partitions associated with this Coxeter group. - + .. SEEALSO:: :meth:`absolute_length` - + EXAMPLES:: - + sage: W = WeylGroup(["A", 3]) sage: s = W.simple_reflections() sage: w0 = s[1] @@ -1261,19 +1261,19 @@ def absolute_le(self, other): if self.absolute_length() >= other.absolute_length(): return False return self.absolute_length() + (self.inverse() * other).absolute_length() == other.absolute_length() - + def canonical_matrix(self): r""" Return the matrix of ``self`` in the canonical faithful representation. - + This is an `n`-dimension real faithful essential representation, where `n` is the number of generators of the Coxeter group. Note that this is not always the most natural matrix representation, for instance in type `A_n`. - + EXAMPLES:: - + sage: W = WeylGroup(["A", 3]) sage: s = W.simple_reflections() sage: (s[1]*s[2]*s[3]).canonical_matrix() @@ -1283,20 +1283,20 @@ def canonical_matrix(self): """ G = self.parent().canonical_representation() return G.prod(G.simple_reflection(i) for i in self.reduced_word()).matrix() - + def coset_representative(self, index_set, side = 'right'): r""" INPUT: - + - ``index_set`` - a subset (or iterable) of the nodes of the Dynkin diagram - ``side`` - 'left' or 'right' - + Returns the unique shortest element of the Coxeter group $W$ which is in the same left (resp. right) coset as ``self``, with respect to the parabolic subgroup $W_I$. - + EXAMPLES:: - + sage: W = CoxeterGroups().example(5) sage: s = W.simple_reflections() sage: w = s[2]*s[1]*s[3] @@ -1324,31 +1324,31 @@ def coset_representative(self, index_set, side = 'right'): [1] sage: w.coset_representative([1,2,3], side = 'left').reduced_word() [] - + """ while True: i = self.first_descent(side = side, index_set = index_set) if i is None: return self self = self.apply_simple_reflection(i, side = side) - + def apply_simple_projection(self, i, side = 'right', length_increasing = True): r""" INPUT: - + - ``i`` - an element of the index set of the Coxeter group - ``side`` - 'left' or 'right' (default: 'right') - ``length_increasing`` - a boolean (default: True) specifying the direction of the projection - + Returns the result of the application of the simple projection `\pi_i` (resp. `\overline\pi_i`) on ``self``. - + See :meth:`CoxeterGroups.ParentMethods.simple_projections` for the definition of the simple projections. - + EXAMPLE:: - + sage: W=CoxeterGroups().example() sage: w=W.an_element() sage: w @@ -1367,53 +1367,53 @@ def apply_simple_projection(self, i, side = 'right', length_increasing = True): s1*s2*s3*s4*s3*s1 sage: v.apply_simple_projection(1, length_increasing = False) s1*s2*s3*s4*s3 - + """ if self.has_descent(i, side = side, positive = length_increasing): return self.apply_simple_reflection(i, side=side) return self - + def binary_factorizations(self, predicate = ConstantFunction(True)): """ Returns the set of all the factorizations `self = u v` such that `l(self) = l(u) + l(v)`. - + Iterating through this set is Constant Amortized Time (counting arithmetic operations in the Coxeter group as constant time) complexity, and memory linear in the length of `self`. - + One can pass as optional argument a predicate p such that `p(u)` implies `p(u')` for any `u` left factor of `self` and `u'` left factor of `u`. Then this returns only the factorizations `self = uv` such `p(u)` holds. - + EXAMPLES: - + We construct the set of all factorizations of the maximal element of the group:: - + sage: W = WeylGroup(['A',3]) sage: s = W.simple_reflections() sage: w0 = W.from_reduced_word([1,2,3,1,2,1]) sage: w0.binary_factorizations().cardinality() 24 - + The same number of factorizations, by bounded length:: - + sage: [w0.binary_factorizations(lambda u: u.length() <= l).cardinality() for l in [-1,0,1,2,3,4,5,6]] [0, 1, 4, 9, 15, 20, 23, 24] - + The number of factorizations of the elements just below the maximal element:: - + sage: [(s[i]*w0).binary_factorizations().cardinality() for i in [1,2,3]] [12, 12, 12] sage: w0.binary_factorizations(lambda u: False).cardinality() 0 - + TESTS:: - + sage: w0.binary_factorizations().category() Category of finite enumerated sets """ @@ -1430,20 +1430,20 @@ def succ(u_v): if i == u1.first_descent() and predicate(u1): yield (u1, s[i]*v) return SearchForest(((W.one(), self),), succ, category = FiniteEnumeratedSets()) - + # TODO: standardize / cleanup def apply_simple_reflections(self, word, side = 'right'): """ INPUT: - + - ``word`` -- A sequence of indices of Coxeter generators - ``side`` -- Indicates multiplying from left or right - + Returns the result of the (left/right) multiplication of word to self. ``self`` is not changed. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: w=W.an_element(); w (1, 2, 3, 0) @@ -1458,17 +1458,17 @@ def apply_simple_reflections(self, word, side = 'right'): self = self.apply_simple_reflection(i, side) return self - + def apply_simple_reflection_left(self, i): """ Returns ``self`` multiplied by the simple reflection ``s[i]`` on the left - + This low level method is used intensively. Coxeter groups are encouraged to override this straightforward implementation whenever a faster approach exists. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: w = W.an_element(); w (1, 2, 3, 0) @@ -1478,25 +1478,25 @@ def apply_simple_reflection_left(self, i): (2, 1, 3, 0) sage: w.apply_simple_reflection_left(2) (1, 3, 2, 0) - + TESTS:: - + sage: w.apply_simple_reflection_left.__module__ 'sage.categories.coxeter_groups' """ s = self.parent().simple_reflections() return s[i] * self - + def apply_simple_reflection_right(self, i): """ Returns ``self`` multiplied by the simple reflection ``s[i]`` on the right - + This low level method is used intensively. Coxeter groups are encouraged to override this straightforward implementation whenever a faster approach exists. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: w = W.an_element(); w (1, 2, 3, 0) @@ -1506,30 +1506,30 @@ def apply_simple_reflection_right(self, i): (1, 3, 2, 0) sage: w.apply_simple_reflection_right(2) (1, 2, 0, 3) - + TESTS:: - + sage: w.apply_simple_reflection_right.__module__ 'sage.categories.coxeter_groups' """ s = self.parent().simple_reflections() return self * s[i] - + def apply_simple_reflection(self, i, side = 'right'): """ Returns ``self`` multiplied by the simple reflection ``s[i]`` - + INPUT: - + - ``i`` -- an element of the index set - ``side`` -- "left" or "right" (default: "right") - + This default implementation simply calls :meth:`apply_simple_reflection_left` or :meth:`apply_simple_reflection_right`. - + EXAMPLES:: - + sage: W=CoxeterGroups().example() sage: w = W.an_element(); w (1, 2, 3, 0) @@ -1539,21 +1539,21 @@ def apply_simple_reflection(self, i, side = 'right'): (2, 1, 3, 0) sage: w.apply_simple_reflection(2, side = "left") (1, 3, 2, 0) - + sage: w.apply_simple_reflection(0, side = "right") (2, 1, 3, 0) sage: w.apply_simple_reflection(1, side = "right") (1, 3, 2, 0) sage: w.apply_simple_reflection(2, side = "right") (1, 2, 0, 3) - + By default, ``side`` is "right":: - + sage: w.apply_simple_reflection(0) (2, 1, 3, 0) - + TESTS:: - + sage: w.apply_simple_reflection_right.__module__ 'sage.categories.coxeter_groups' """ @@ -1561,18 +1561,18 @@ def apply_simple_reflection(self, i, side = 'right'): return self.apply_simple_reflection_right(i) else: return self.apply_simple_reflection_left(i) - + def _mul_(self, other): r""" Returns the product of ``self`` and ``other`` - + This default implementation computes a reduced word of ``other`` using :meth:`reduced_word`, and applies the corresponding simple reflections on ``self`` using :meth:`apply_simple_reflections`. - + EXAMPLES:: - + sage: W = FiniteCoxeterGroups().example(); W The 5-th dihedral group of order 10 sage: w = W.an_element() @@ -1582,25 +1582,25 @@ def _mul_(self, other): (1, 2, 1, 2) sage: w._mul_(w)._mul_(w) (2, 1, 2, 1) - + This method is called when computing ``self*other``:: - + sage: w * w (1, 2, 1, 2) - + TESTS:: - + sage: w._mul_.__module__ 'sage.categories.coxeter_groups' """ return self.apply_simple_reflections(other.reduced_word()) - + def inverse(self): """ Returns the inverse of self - + EXAMPLES:: - + sage: W=WeylGroup(['B',7]) sage: w=W.an_element() sage: u=w.inverse() @@ -1616,30 +1616,30 @@ def inverse(self): [0 0 0 0 1 0 0] [0 0 0 0 0 1 0] [0 0 0 0 0 0 1] - + """ - + return self.parent().one().apply_simple_reflections(self.reduced_word_reverse_iterator()) - + __invert__ = inverse - + @cached_in_parent_method def bruhat_lower_covers(self): """ Returns all elements that ``self`` covers in (strong) Bruhat order. - + If ``w = self`` has a descent at `i`, then the elements that `w` covers are exactly `\{ws_i, u_1s_i, u_2s_i,..., u_js_i\}`, where the `u_k` are elements that `ws_i` covers that also do not have a descent at `i`. - + EXAMPLES:: - + sage: W = WeylGroup(["A",3]) sage: w = W.from_reduced_word([3,2,3]) sage: print([v.reduced_word() for v in w.bruhat_lower_covers()]) [[3, 2], [2, 3]] - + sage: W = WeylGroup(["A",3]) sage: print([v.reduced_word() for v in W.simple_reflection(1).bruhat_lower_covers()]) [[]] @@ -1649,18 +1649,18 @@ def bruhat_lower_covers(self): sage: w = W.from_reduced_word([0,2]) sage: print([v.reduced_word() for v in w.bruhat_lower_covers()]) [[2], [0]] - + We now show how to construct the Bruhat poset:: - + sage: W = WeylGroup(["A",3]) sage: covers = tuple([u, v] for v in W for u in v.bruhat_lower_covers() ) sage: P = Poset((W, covers), cover_relations = True) sage: P.show() - + Alternatively, one can just use:: - + sage: P = W.bruhat_poset() - + The algorithm is taken from Stembridge's 'coxeter/weyl' package for Maple. """ desc = self.first_descent() @@ -1669,30 +1669,30 @@ def bruhat_lower_covers(self): return [u.apply_simple_reflection(desc) for u in ww.bruhat_lower_covers() if not u.has_descent(desc)] + [ww] else: return [] - + @cached_in_parent_method def bruhat_upper_covers(self): r""" Returns all elements that cover ``self`` in (strong) Bruhat order. - + The algorithm works recursively, using the 'inverse' of the method described for lower covers :meth:`bruhat_lower_covers`. Namely, it runs through all `i` in the index set. Let `w` equal ``self``. If `w` has no right descent `i`, then `w s_i` is a cover; if `w` has a decent at `i`, then `u_j s_i` is a cover of `w` where `u_j` is a cover of `w s_i`. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3,1], prefix="s") sage: w = W.from_reduced_word([1,2,1]) sage: w.bruhat_upper_covers() [s1*s2*s1*s0, s1*s2*s0*s1, s0*s1*s2*s1, s3*s1*s2*s1, s2*s3*s1*s2, s1*s2*s3*s1] - + sage: W = WeylGroup(['A',3]) sage: w = W.long_element() sage: w.bruhat_upper_covers() [] - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([1,2,1]) sage: S = [v for v in W if w in v.bruhat_lower_covers()] @@ -1708,69 +1708,69 @@ def bruhat_upper_covers(self): else: Covers += [ self.apply_simple_reflection(i) ] return uniq(Covers) - + @cached_in_parent_method def bruhat_lower_covers_reflections(self): r""" Returns all 2-tuples of lower_covers and reflections (``v``, ``r``) where ``v`` is covered by ``self`` and ``r`` is the reflection such that ``self`` = ``v`` ``r``. - + ALGORITHM: - + See :meth:`.bruhat_lower_covers` - + EXAMPLES:: - + sage: W = WeylGroup(['A',3], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.bruhat_lower_covers_reflections() [(s1*s2*s1, s1*s2*s3*s2*s1), (s3*s2*s1, s2), (s3*s1*s2, s1)] - + """ i = self.first_descent() if i is None: return [] wi = self.apply_simple_reflection(i) return [(u.apply_simple_reflection(i),r.apply_conjugation_by_simple_reflection(i)) for u,r in wi.bruhat_lower_covers_reflections() if not u.has_descent(i)] + [(wi, self.parent().simple_reflection(i))] - + def lower_cover_reflections(self, side = 'right'): r""" Returns the reflections ``t`` such that ``self`` covers ``self`` ``t``. - + If ``side`` is 'left', ``self`` covers ``t`` ``self``. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3],prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.lower_cover_reflections() [s1*s2*s3*s2*s1, s2, s1] sage: w.lower_cover_reflections(side = 'left') [s2*s3*s2, s3, s1] - + """ - + if side == 'left': self = self.inverse() return [x[1] for x in self.bruhat_lower_covers_reflections()] - + @cached_in_parent_method def bruhat_upper_covers_reflections(self): r""" Returns all 2-tuples of covers and reflections (``v``, ``r``) where ``v`` covers ``self`` and ``r`` is the reflection such that ``self`` = ``v`` ``r``. - + ALGORITHM: - + See :meth:`.bruhat_upper_covers` - + EXAMPLES:: - + sage: W = WeylGroup(['A',4], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.bruhat_upper_covers_reflections() [(s1*s2*s3*s2*s1, s3), (s2*s3*s1*s2*s1, s2*s3*s2), (s3*s4*s1*s2*s1, s4), (s4*s3*s1*s2*s1, s1*s2*s3*s4*s3*s2*s1)] - + """ - + Covers = [] for i in self.parent().index_set(): wi = self.apply_simple_reflection(i) @@ -1779,43 +1779,43 @@ def bruhat_upper_covers_reflections(self): else: Covers += [(wi,self.parent().simple_reflection(i))] return uniq(Covers) - + def cover_reflections(self, side = 'right'): r""" Returns the set of reflections ``t`` such that ``self`` ``t`` covers ``self``. - + If ``side`` is 'left', ``t`` ``self`` covers ``self``. - + EXAMPLES:: - + sage: W = WeylGroup(['A',4], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.cover_reflections() [s3, s2*s3*s2, s4, s1*s2*s3*s4*s3*s2*s1] sage: w.cover_reflections(side = 'left') [s4, s2, s1*s2*s1, s3*s4*s3] - + """ - + if side == 'left': self = self.inverse() return [x[1] for x in self.bruhat_upper_covers_reflections()] - + @cached_in_parent_method def bruhat_le(self, other): """ Bruhat comparison - + INPUT: - + - other - an element of the same Coxeter group - + OUTPUT: a boolean - + Returns whether ``self`` <= ``other`` in the Bruhat order. - + EXAMPLES:: - + sage: W = WeylGroup(["A",3]) sage: u = W.from_reduced_word([1,2,1]) sage: v = W.from_reduced_word([1,2,3,2,1]) @@ -1830,31 +1830,31 @@ def bruhat_le(self, other): sage: s = W.simple_reflections() sage: s[1].bruhat_le(W.one()) False - + The implementation uses the equivalent condition that any reduced word for ``other`` contains a reduced word for ``self`` as subword. See Stembridge, A short derivation of the Mobius function for the Bruhat order. J. Algebraic Combin. 25 (2007), no. 2, 141--148, Proposition 1.1. - + Complexity: `O(l * c)`, where `l` is the minimum of the lengths of `u` and of `v`, and `c` is the cost of the low level methods :meth:`first_descent`, :meth:`has_descent`, :meth:`apply_simple_reflection`, etc. Those are typically `O(n)`, where `n` is the rank of the Coxeter group. - + TESTS: - + We now run consistency tests with permutations and :meth:`bruhat_lower_covers`:: - + sage: W = WeylGroup(["A",3]) sage: P4 = Permutations(4) sage: def P4toW(w): return W.from_reduced_word(w.reduced_word()) sage: for u in P4: ... for v in P4: ... assert u.bruhat_lequal(v) == P4toW(u).bruhat_le(P4toW(v)) - + sage: W = WeylGroup(["B",3]) sage: P = W.bruhat_poset() # This is built from bruhat_lower_covers sage: Q = Poset((W, attrcall("bruhat_le"))) # long time (10s) @@ -1862,7 +1862,7 @@ def bruhat_le(self, other): True sage: all( P.is_lequal(u,v) == Q.is_lequal(u,v) for u in W for v in W) # long time (9s) True - + """ if not have_same_parent(self, other): raise TypeError("%s and %s do not have the same parent"%(self, other)) @@ -1872,25 +1872,25 @@ def bruhat_le(self, other): return self.apply_simple_projection(desc, length_increasing = False).bruhat_le(other.apply_simple_reflection(desc)) else: return self == other - + def weak_le(self, other, side = 'right'): """ comparison in weak order - + INPUT: - + - other - an element of the same Coxeter group - side - 'left' or 'right' (default: 'right') - + OUTPUT: a boolean - + Returns whether ``self`` <= ``other`` in left (resp. right) weak order, that is if 'v' can be obtained from 'v' by length increasing multiplication by simple reflections on the left (resp. right). - + EXAMPLES:: - + sage: W = WeylGroup(["A",3]) sage: u = W.from_reduced_word([1,2]) sage: v = W.from_reduced_word([1,2,3,2]) @@ -1902,24 +1902,24 @@ def weak_le(self, other, side = 'right'): False sage: v.weak_le(v) True - + Comparison for left weak order is achieved with the option ``side``:: - + sage: u.weak_le(v, side = 'left') False - + The implementation uses the equivalent condition that any reduced word for `u` is a right (resp. left) prefix of some reduced word for `v`. - + Complexity: `O(l * c)`, where `l` is the minimum of the lengths of `u` and of `v`, and `c` is the cost of the low level methods :meth:`first_descent`, :meth:`has_descent`, :meth:`apply_simple_reflection`. Those are typically `O(n)`, where `n` is the rank of the Coxeter group. - + We now run consistency tests with permutations:: - + sage: W = WeylGroup(["A",3]) sage: P4 = Permutations(4) sage: def P4toW(w): return W.from_reduced_word(w.reduced_word()) @@ -1932,7 +1932,7 @@ def weak_le(self, other, side = 'right'): raise TypeError("%s and %s do not have the same parent"%(self,other)) # could first compare the length, when that information is cheap prefix_side = 'left' if side == 'right' else 'right' - + while True: desc = self.first_descent(side = prefix_side) if desc is None: @@ -1941,33 +1941,33 @@ def weak_le(self, other, side = 'right'): return False self = self.apply_simple_reflection(desc, side = prefix_side) other = other.apply_simple_reflection(desc, side = prefix_side) - + def weak_covers(self, side = 'right', index_set = None, positive = False): """ Returns all elements that ``self`` covers in weak order. - + INPUT: - + - side - 'left' or 'right' (default: 'right') - positive - a boolean (default: False) - index_set - a list of indices or None - + OUTPUT: a list - + EXAMPLES:: - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([3,2,1]) sage: [x.reduced_word() for x in w.weak_covers()] [[3, 2]] - + To obtain instead elements that cover self, set ``positive = True``:: - + sage: [x.reduced_word() for x in w.weak_covers(positive = True)] [[3, 1, 2, 1], [2, 3, 2, 1]] - + To obtain covers for left weak order, set the option side to 'left':: - + sage: [x.reduced_word() for x in w.weak_covers(side='left')] [[2, 1]] sage: w = W.from_reduced_word([3,2,3,1]) @@ -1975,33 +1975,33 @@ def weak_covers(self, side = 'right', index_set = None, positive = False): [[2, 3, 2], [3, 2, 1]] sage: [x.reduced_word() for x in w.weak_covers(side='left')] [[3, 2, 1], [2, 3, 1]] - + Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - + sage: [x.reduced_word() for x in w.weak_covers(index_set = [1,2])] [[2, 3, 2]] """ return [ self.apply_simple_reflection(i, side=side) for i in self.descents(side=side, index_set = index_set, positive = positive) ] - + def coxeter_sorting_word(self,c): r""" Return the ``c``-sorting word of ``self``. - + For a Coxeter element `c` and an element `w`, the `c`-sorting word of `w` is the lexicographic minimal reduced expression of `w` in the infinite word `c^\infty`. - + INPUT: - + - ``c``-- a Coxeter element. - + OUTPUT: - + the ``c``-sorting word of ``self`` as a list of integers. - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: c = W.from_reduced_word([0,2,1]) sage: w = W.from_reduced_word([1,2,1,0,1]) @@ -2030,27 +2030,27 @@ def coxeter_sorting_word(self,c): if i == n: i = 0 return sorting_word - + def is_coxeter_sortable(self,c,sorting_word=None): r""" Return whether ``self`` is ``c``-sortable. - + Given a Coxeter element `c`, an element `w` is `c`-sortable if its `c`-sorting word decomposes into a sequence of weakly decreasing subwords of `c`. - + INPUT: - + - ``c`` -- a Coxeter element. - ``sorting_word`` -- sorting word (default: None) used to not recompute the ``c``-sorting word if already computed. - + OUTPUT: - + is ``self`` ``c``-sortable - + EXAMPLES:: - + sage: W = CoxeterGroups().example() sage: c = W.from_reduced_word([0,2,1]) sage: w = W.from_reduced_word([1,2,1,0,1]) @@ -2091,30 +2091,30 @@ def is_coxeter_sortable(self,c,sorting_word=None): if i == n: i = 0 return True - + def apply_demazure_product(self, element, side = 'right', length_increasing = True): r""" Returns the Demazure or 0-Hecke product of ``self`` with another Coxeter group element. - + See :meth:`CoxeterGroups.ParentMethods.simple_projections`. - + INPUT: - + - ``element`` -- either an element of the same Coxeter group as ``self`` or a tuple or a list (such as a reduced word) of elements from the index set of the Coxeter group. - + - ``side`` -- 'left' or 'right' (default: 'right'); the side of ``self`` on which the element should be applied. If ``side`` is 'left' then the operation is applied on the left. - + - ``length_increasing`` -- a boolean (default True) whether to act length increasingly or decreasingly - + EXAMPLES:: - + sage: W = WeylGroup(['C',4],prefix="s") sage: v = W.from_reduced_word([1,2,3,4,3,1]) sage: v.apply_demazure_product([1,3,4,3,3]) @@ -2125,9 +2125,9 @@ def apply_demazure_product(self, element, side = 'right', length_increasing = Tr s3*s4*s1*s2*s3*s4*s2*s3*s1 sage: v.apply_demazure_product(v) s2*s3*s4*s1*s2*s3*s4*s2*s3*s2*s1 - + """ - + # if self and element have the same parent if self.parent().is_parent_of(element): the_word = element.reduced_word() @@ -2148,17 +2148,17 @@ def apply_demazure_product(self, element, side = 'right', length_increasing = Tr for i in the_word: self = self.apply_simple_projection(i, side = side, length_increasing = length_increasing) return self - + def min_demazure_product_greater(self, element): r""" Finds the unique Bruhat-minimum element ``u`` such that ``v`` $\le$ ``w`` * ``u`` where ``v`` is ``self``, ``w`` is ``element`` and ``*`` is the Demazure product. - + INPUT: - + - ``element`` is either an element of the same Coxeter group as ``self`` or a list (such as a reduced word) of elements from the index set of the Coxeter group. - + EXAMPLES:: - + sage: W = WeylGroup(['A',4],prefix="s") sage: v = W.from_reduced_word([2,3,4,1,2]) sage: u = W.from_reduced_word([2,3,2,1]) @@ -2168,9 +2168,9 @@ def min_demazure_product_greater(self, element): s4*s2 sage: v.min_demazure_product_greater((2,3,2,1)) s4*s2 - + """ - + # if self and element have the same parent if self.parent().is_parent_of(element): the_word = element.reduced_word() @@ -2186,27 +2186,27 @@ def min_demazure_product_greater(self, element): if self.has_descent(i, side = 'left'): self = self.apply_simple_reflection(i, side = 'left') return self - + def deodhar_factor_element(self, w, index_set): r""" Returns Deodhar's Bruhat order factoring element. - + INPUT: - + - ``w`` is an element of the same Coxeter group ``W`` as ``self`` - ``index_set`` is a subset of Dynkin nodes defining a parabolic subgroup ``W'`` of ``W`` - + It is assumed that ``v = self`` and ``w`` are minimum length coset representatives for ``W/W'`` such that ``v`` $\le$ ``w`` in Bruhat order. - + OUTPUT: - + Deodhar's element ``f(v,w)`` is the unique element of ``W'`` such that, for all ``v'`` and ``w'`` in ``W'``, ``vv'`` $\le$ ``ww'`` in ``W`` if and only if ``v'`` $\le$ ``f(v,w) * w'`` in ``W'`` where ``*`` is the Demazure product. - + EXAMPLES:: - + sage: W = WeylGroup(['A',5],prefix="s") sage: v = W.from_reduced_word([5]) sage: w = W.from_reduced_word([4,5,2,3,1,2]) @@ -2218,13 +2218,13 @@ def deodhar_factor_element(self, w, index_set): Traceback (most recent call last): ... ValueError: [2, 1] is not of minimum length in its coset for the parabolic subgroup with index set [1] - + REFERENCES: - + .. [Deodhar] V. Deodhar, A splitting criterion for the Bruhat orderings on Coxeter groups. Comm. Algebra, 15:1889-1894, 1987. - + """ - + if self != self.coset_representative(index_set): raise ValueError("%s is not of minimum length in its coset for the parabolic subgroup with index set %s"%(self.reduced_word(),index_set)) if w != w.coset_representative(index_set): @@ -2243,35 +2243,35 @@ def deodhar_factor_element(self, w, index_set): if des is None: return dsp return dsp.apply_simple_projection(des, side = 'left') - + def deodhar_lift_up(self, w, index_set): """ Letting ``v = self``, given a Bruhat relation ``v W'`` $\le$ ``w W'`` among cosets with respect to the subgroup ``W'`` given by the Dynkin node subset ``index_set``, returns the Bruhat-minimum lift ``x`` of ``wW'`` such that ``v`` $\le$ ``x``. - + INPUT: - + - ``w`` is an element of the same Coxeter group ``W`` as ``self``. - ``index_set`` is a subset of Dynkin nodes defining a parabolic subgroup ``W'``. - + OUTPUT: - + The unique Bruhat-minimum element ``x`` in ``W`` such that ``x W' = w W'`` and ``v`` $\le$ ``x``. - + .. SEEALSO:: :meth:`sage.categories.coxeter_groups.CoxeterGroups.ElementMethods.deodhar_lift_down` - + EXAMPLES:: - + sage: W = WeylGroup(['A',3],prefix="s") sage: v = W.from_reduced_word([1,2,3]) sage: w = W.from_reduced_word([1,3,2]) sage: v.deodhar_lift_up(w, [3]) s1*s2*s3*s2 - + """ - + vmin = self.coset_representative(index_set) wmin = w.coset_representative(index_set) if not vmin.bruhat_le(wmin): @@ -2279,154 +2279,154 @@ def deodhar_lift_up(self, w, index_set): vJ = vmin.inverse() * self dsp = vmin.deodhar_factor_element(wmin,index_set) return wmin * vJ.min_demazure_product_greater(dsp) - + def deodhar_lift_down(self, w, index_set): r""" Letting ``v = self``, given a Bruhat relation ``v W'`` $\ge$ ``w W'`` among cosets with respect to the subgroup ``W'`` given by the Dynkin node subset ``index_set``, returns the Bruhat-maximum lift ``x`` of ``wW'`` such that ``v`` $\ge$ ``x``. - + INPUT: - + - ``w`` is an element of the same Coxeter group ``W`` as ``self``. - ``index_set`` is a subset of Dynkin nodes defining a parabolic subgroup ``W'``. - + OUTPUT: - + The unique Bruhat-maximum element ``x`` in ``W`` such that ``x W' = w W'`` and ``v $\ge$ ``x``. - + .. SEEALSO:: :meth:`sage.categories.coxeter_groups.CoxeterGroups.ElementMethods.deodhar_lift_up` - + EXAMPLES:: - + sage: W = WeylGroup(['A',3],prefix="s") sage: v = W.from_reduced_word([1,2,3,2]) sage: w = W.from_reduced_word([3,2]) sage: v.deodhar_lift_down(w, [3]) s2*s3*s2 - + """ - + vmin = self.coset_representative(index_set) wmin = w.coset_representative(index_set) if not wmin.bruhat_le(vmin): raise ValueError("Must have %s <= %s mod the parabolic subgroup with index set %s"%(w.reduced_word(), self.reduced_word(), index_set)) - + vJ = vmin.inverse() * self dsp = wmin.deodhar_factor_element(vmin,index_set) return wmin * dsp.apply_demazure_product(vJ) - + def apply_conjugation_by_simple_reflection(self, i): r""" Conjugates ``self`` by the ``i``-th simple reflection. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([3,1,2,1]) sage: w.apply_conjugation_by_simple_reflection(1).reduced_word() [3, 2] - + """ - + return (self.apply_simple_reflection(i)).apply_simple_reflection(i,side='left') - + @cached_in_parent_method def inversions_as_reflections(self): r""" Returns the set of reflections ``r`` such that ``self`` ``r < self``. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.inversions_as_reflections() [s1, s1*s2*s1, s2, s1*s2*s3*s2*s1] - + """ - + i = self.first_descent() if i is None: return [] wi = self.apply_simple_reflection(i) return [self.parent().simple_reflection(i)]+[u.apply_conjugation_by_simple_reflection(i) for u in wi.inversions_as_reflections()] - + def left_inversions_as_reflections(self): r""" Returns the set of reflections ``r`` such that ``r`` ``self`` < ``self``. - + EXAMPLES:: - + sage: W = WeylGroup(['A',3], prefix="s") sage: w = W.from_reduced_word([3,1,2,1]) sage: w.left_inversions_as_reflections() [s1, s3, s1*s2*s3*s2*s1, s2*s3*s2] - + """ - + return self.inverse().inversions_as_reflections() - + def lower_covers(self, side = 'right', index_set = None): """ Returns all elements that ``self`` covers in weak order. - + INPUT: - + - side - 'left' or 'right' (default: 'right') - index_set - a list of indices or None - + OUTPUT: a list - + EXAMPLES:: - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([3,2,1]) sage: [x.reduced_word() for x in w.lower_covers()] [[3, 2]] - + To obtain covers for left weak order, set the option side to 'left':: - + sage: [x.reduced_word() for x in w.lower_covers(side='left')] [[2, 1]] sage: w = W.from_reduced_word([3,2,3,1]) sage: [x.reduced_word() for x in w.lower_covers()] [[2, 3, 2], [3, 2, 1]] - + Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - + sage: [x.reduced_word() for x in w.lower_covers(index_set = [1,2])] [[2, 3, 2]] sage: [x.reduced_word() for x in w.lower_covers(side='left')] [[3, 2, 1], [2, 3, 1]] """ return self.weak_covers(side = side, index_set = index_set, positive = False) - + def upper_covers(self, side = 'right', index_set = None): """ Returns all elements that cover ``self`` in weak order. - + INPUT: - + - side - 'left' or 'right' (default: 'right') - index_set - a list of indices or None - + OUTPUT: a list - + EXAMPLES:: - + sage: W = WeylGroup(['A',3]) sage: w = W.from_reduced_word([2,3]) sage: [x.reduced_word() for x in w.upper_covers()] [[2, 3, 1], [2, 3, 2]] - + To obtain covers for left weak order, set the option ``side`` to 'left':: - + sage: [x.reduced_word() for x in w.upper_covers(side = 'left')] [[1, 2, 3], [2, 3, 2]] - + Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``:: - + sage: [x.reduced_word() for x in w.upper_covers(index_set = [1])] [[2, 3, 1]] sage: [x.reduced_word() for x in w.upper_covers(side = 'left', index_set = [1])] diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 32454fd7bcd..96792b72db0 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -278,19 +278,19 @@ def weak_poset(self, side = "right", facade = False): weak_lattice = weak_poset - + @cached_method def cambrian_lattice(self, c): """ INPUT: - + - ``c`` -- a standard Coxeter element in ``self`` (as a tuple, or as an element of ``self``) - + Returns the c-Cambrian lattice on delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). - Delta sequences are certain 2-colored minimal factorizations of ``c`` into reflections. - + Delta sequences are certain 2-colored minimal factorizations of ``c`` into reflections. + EXAMPLES:: - + sage: CoxeterGroup(["A", 2]).cambrian_lattice((1,2)) Finite lattice containing 5 elements @@ -307,68 +307,68 @@ def cambrian_lattice(self, c): def inversion_sequence(self, word): """ INPUT: - + - ``word`` -- a word in the simple generators of ``self`` - + Return the inversion sequence corresponding to ``word``. If ``word``=`[w_0,w_1,...w_k]`, then the output is `[w_0,w_0w_1w_0,\ldots,w_0w_1\cdots w_k \cdots w_1 w_0]`. - + EXAMPLES:: - + sage: CoxeterGroup(["A", 2]).inversion_sequence([1,2,1]) [ [-1 1] [ 0 -1] [ 1 0] [ 0 1], [-1 0], [ 1 -1] ] - + sage: [t.reduced_word() for t in CoxeterGroup(["A",3]).inversion_sequence([2,1,3,2,1,3])] [[2], [1, 2, 1], [2, 3, 2], [1, 2, 3, 2, 1], [3], [1]] - + """ return [self.from_reduced_word(word[:i+1]+list(reversed(word[:i]))) for i in range(len(word))] - + def reflections_from_w0(self): """ Return the reflections of ``self`` using the inversion set of ``w_0``. - + EXAMPLES:: - + sage: WeylGroup(['A',2]).reflections_from_w0() [ [0 1 0] [0 0 1] [1 0 0] [1 0 0] [0 1 0] [0 0 1] [0 0 1], [1 0 0], [0 1 0] ] - + sage: WeylGroup(['A',3]).reflections_from_w0() [ [-1 1 0] [ 0 -1 1] [ 1 0 0] [ 0 0 -1] [ 1 0 0] [ 1 0 0] [ 0 1 0] [-1 0 1] [ 1 -1 1] [-1 1 -1] [ 1 0 -1] [ 0 1 0] [ 0 0 1], [ 0 0 1], [ 0 0 1], [-1 0 0], [ 1 -1 0], [ 0 1 -1] ] - + """ return self.long_element().inversions_as_reflections() - + @cached_method def m_cambrian_lattice(self, c, m = 1): """ INPUT: - + - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) - ``m`` -- a positive integer (default: 1) - + Return the m-Cambrian lattice on ``m``-delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). - ``m``-delta sequences are certain ``m``-colored minimal factorizations of ``c`` into reflections. - + ``m``-delta sequences are certain ``m``-colored minimal factorizations of ``c`` into reflections. + EXAMPLES:: - + sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2)) Finite lattice containing 5 elements sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2),2) - Finite lattice containing 12 elements - + Finite lattice containing 12 elements + """ from sage.combinat.posets.posets import Poset from sage.combinat.posets.lattices import LatticePoset diff --git a/src/sage/categories/finite_weyl_groups.py b/src/sage/categories/finite_weyl_groups.py index b6ce9b81e3e..755889ecd40 100644 --- a/src/sage/categories/finite_weyl_groups.py +++ b/src/sage/categories/finite_weyl_groups.py @@ -14,9 +14,9 @@ class FiniteWeylGroups(CategoryWithAxiom): """ The category of finite Weyl groups. - + EXAMPLES:: - + sage: C = FiniteWeylGroups() sage: C Category of finite weyl groups @@ -24,9 +24,9 @@ class FiniteWeylGroups(CategoryWithAxiom): [Category of finite coxeter groups, Category of weyl groups] sage: C.example() The symmetric group on {0, ..., 3} - + TESTS:: - + sage: W = FiniteWeylGroups().example() sage: TestSuite(W).run(verbose = "True") running ._test_an_element() . . . pass @@ -57,27 +57,27 @@ class FiniteWeylGroups(CategoryWithAxiom): running ._test_simple_projections() . . . pass running ._test_some_elements() . . . pass """ - + class ParentMethods: - + @cached_method def m_cambrian_lattice(W,c,m): """ INPUT: - + - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) - ``m`` -- a positive integer (default: 1) - + Return the m-Cambrian lattice on ``m``-delta sequences, realized on roots rather than reflections. - + EXAMPLES:: - + sage: WeylGroup(["A",2]).m_cambrian_lattice((1,2),1) Finite lattice containing 5 elements - + sage: WeylGroup(["A",2]).m_cambrian_lattice((1,2),2) Finite lattice containing 12 elements - + """ from sage.combinat.posets.posets import Poset from sage.combinat.posets.lattices import LatticePoset @@ -114,6 +114,6 @@ def m_cambrian_lattice(W,c,m): covers.append([tuple(map(tuple,new_element)),tuple(map(tuple,cov_element))]) return LatticePoset([[tuple(map(tuple,e)) for e in elements],covers],cover_relations=True) - + class ElementMethods: pass From 1f29ae63a00bfb86c3fdd152a1f4bf98fccf4e28 Mon Sep 17 00:00:00 2001 From: Nathan Williams Date: Fri, 5 Jun 2015 11:13:10 -0500 Subject: [PATCH 0242/1872] reordered documentation, as requested by chapoton --- src/sage/categories/finite_coxeter_groups.py | 18 +++++++++--------- src/sage/categories/finite_weyl_groups.py | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 96792b72db0..e06922a914a 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -282,13 +282,13 @@ def weak_poset(self, side = "right", facade = False): @cached_method def cambrian_lattice(self, c): """ + Return the c-Cambrian lattice on delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). + Delta sequences are certain 2-colored minimal factorizations of ``c`` into reflections. + INPUT: - ``c`` -- a standard Coxeter element in ``self`` (as a tuple, or as an element of ``self``) - Returns the c-Cambrian lattice on delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). - Delta sequences are certain 2-colored minimal factorizations of ``c`` into reflections. - EXAMPLES:: sage: CoxeterGroup(["A", 2]).cambrian_lattice((1,2)) @@ -306,13 +306,13 @@ def cambrian_lattice(self, c): def inversion_sequence(self, word): """ + Return the inversion sequence corresponding to ``word``. If + ``word``=`[w_0,w_1,...w_k]`, then the output is `[w_0,w_0w_1w_0,\ldots,w_0w_1\cdots w_k \cdots w_1 w_0]`. + INPUT: - ``word`` -- a word in the simple generators of ``self`` - Return the inversion sequence corresponding to ``word``. If - ``word``=`[w_0,w_1,...w_k]`, then the output is `[w_0,w_0w_1w_0,\ldots,w_0w_1\cdots w_k \cdots w_1 w_0]`. - EXAMPLES:: sage: CoxeterGroup(["A", 2]).inversion_sequence([1,2,1]) @@ -353,14 +353,14 @@ def reflections_from_w0(self): @cached_method def m_cambrian_lattice(self, c, m = 1): """ + Return the m-Cambrian lattice on ``m``-delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). + ``m``-delta sequences are certain ``m``-colored minimal factorizations of ``c`` into reflections. + INPUT: - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) - ``m`` -- a positive integer (default: 1) - Return the m-Cambrian lattice on ``m``-delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). - ``m``-delta sequences are certain ``m``-colored minimal factorizations of ``c`` into reflections. - EXAMPLES:: sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2)) diff --git a/src/sage/categories/finite_weyl_groups.py b/src/sage/categories/finite_weyl_groups.py index 755889ecd40..878b73dcbac 100644 --- a/src/sage/categories/finite_weyl_groups.py +++ b/src/sage/categories/finite_weyl_groups.py @@ -68,7 +68,8 @@ def m_cambrian_lattice(W,c,m): - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) - ``m`` -- a positive integer (default: 1) - Return the m-Cambrian lattice on ``m``-delta sequences, realized on roots rather than reflections. + Return the m-Cambrian lattice on ``m``-delta sequences, realized on roots rather than reflections (see arXiv:1503.00710 and arXiv:math/0611106). + ``m``-delta sequences are certain ``m``-colored minimal factorizations of ``c`` into reflections. EXAMPLES:: From 0eea07be8e10af1b0606cc3ecd4c3040e10339b9 Mon Sep 17 00:00:00 2001 From: Vincent Pilaud Date: Sat, 6 Jun 2015 10:49:43 -0500 Subject: [PATCH 0243/1872] remove duplicate import, as well as a non-necessary import --- src/sage/combinat/cluster_algebra_quiver/quiver.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 4c50e2c7ae0..4b89986ec69 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -1638,10 +1638,8 @@ def d_vector_fan(self): ValueError: only makes sense for quivers of finite type """ from cluster_seed import ClusterSeed - from cluster_seed import ClusterSeed from sage.geometry.fan import Fan from sage.geometry.cone import Cone - from sage.modules.free_module_element import vector if not(self.is_finite()): raise ValueError('only makes sense for quivers of finite type') @@ -1691,7 +1689,6 @@ def g_vector_fan(self): from cluster_seed import ClusterSeed from sage.geometry.fan import Fan from sage.geometry.cone import Cone - from sage.modules.free_module_element import vector if not(self.is_finite()): raise ValueError('only supported for quivers of finite type') From 19846a08c352ce041a3d5a8f2a6bf0757a91aae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Sun, 7 Jun 2015 11:49:39 +0300 Subject: [PATCH 0244/1872] Fixed documentation --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/root_system/__init__.py | 1 + .../combinat/root_system/coxeter_matrix.py | 23 +++++++++++++++---- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index b5a90e17e12..ef5f17805b7 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -203,6 +203,7 @@ Comprehensive Module list sage/combinat/root_system/cartan_type sage/combinat/root_system/coxeter_group sage/combinat/root_system/coxeter_matrix + sage/combinat/root_system/coxeter_type sage/combinat/root_system/dynkin_diagram sage/combinat/root_system/hecke_algebra_representation sage/combinat/root_system/integrable_representations diff --git a/src/sage/combinat/root_system/__init__.py b/src/sage/combinat/root_system/__init__.py index e762b391d15..aab2cc3eb68 100644 --- a/src/sage/combinat/root_system/__init__.py +++ b/src/sage/combinat/root_system/__init__.py @@ -35,6 +35,7 @@ - :ref:`sage.combinat.root_system.dynkin_diagram` - :ref:`sage.combinat.root_system.cartan_matrix` - :ref:`sage.combinat.root_system.coxeter_matrix` +- :ref:`sage.combinat.root_system.coxeter_type` Root systems ------------ diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index f65c0b828c1..996bd15a501 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -37,7 +37,7 @@ class CoxeterMatrix(CoxeterType): - """ + r""" A Coxeter matrix. .. TODO:: @@ -95,7 +95,7 @@ class CoxeterMatrix(CoxeterType): [ 3 1 4] [-1 4 1] - It is possible to give a number `\leq -1` to represent an infinite label + It is possible to give a number `\leq -1` to represent an infinite label:: sage: CoxeterMatrix([[1,-1],[-1,1]]) [ 1 -1] @@ -109,7 +109,7 @@ class CoxeterMatrix(CoxeterType): @staticmethod def __classcall_private__(cls, *args, **kwds): - """ + r""" A Coxeter matrix can we created via a graph, a Coxeter type, or a matrix. @@ -430,8 +430,7 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N Here the ``higher_rank`` term denotes non-finite, non-affine, Coxeter groups (including hyperbolic types). - .. TODO:: Implement the hyperbolic and compact hyperbolic in the - samples. + .. TODO:: Implement the hyperbolic and compact hyperbolic in the samples. EXAMPLES:: @@ -791,6 +790,20 @@ def bilinear_form(self): Return the bilinear form of ``self``. EXAMPLES:: + + sage: CoxeterType(['A', 2, 1]).bilinear_form() + [ 1 -1/2 -1/2] + [-1/2 1 -1/2] + [-1/2 -1/2 1] + sage: CoxeterType(['H', 3]).bilinear_form() + [ 1 -1/2 0] + [ -1/2 1 1/2*E(5)^2 + 1/2*E(5)^3] + [ 0 1/2*E(5)^2 + 1/2*E(5)^3 1] + sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) + sage: C.bilinear_form() + [ 1 -1 -1] + [-1 1 -1] + [-1 -1 1] """ return CoxeterType.bilinear_form(self) From 32f216883758c1416d6f680b7dd3b571f8ad1a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Sun, 7 Jun 2015 14:46:46 +0300 Subject: [PATCH 0245/1872] Made test pass in Category of Coxeter groups --- src/sage/categories/coxeter_groups.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 4cce4740c25..b3b5ee538c8 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -1110,8 +1110,7 @@ def reduced_word_graph(self): 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)] + m = P.coxeter_matrix()[a,b] subword = [a,b] * (m // 2) subword2 = [b,a] * (m // 2) if m % 2 != 0: From 522f9a4cc0c316553b1e9d34c74776223494d865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Sun, 7 Jun 2015 16:07:51 +0300 Subject: [PATCH 0246/1872] Added doctest coverage to __repr__ --- src/sage/combinat/root_system/coxeter_matrix.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 996bd15a501..cb452ccf7ec 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -629,6 +629,16 @@ def __reduce__(self): def __repr__(self): """ String representation of the Coxeter matrix. + + EXAMPLES:: + + sage: CM = CoxeterMatrix(['A',3]);CM + [1 3 2] + [3 1 3] + [2 3 1] + sage: CM = CoxeterMatrix([[1,-3/2],[-3/2,1]]);CM + [ 1 -3/2] + [-3/2 1] """ return self._matrix.__repr__() From 058e4e8e1f32d1b7fce3385aea93be984a34fb0d Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Mon, 8 Jun 2015 11:47:41 +0200 Subject: [PATCH 0247/1872] removed diffs implemented in #18590 and #18610 --- src/sage/categories/coxeter_groups.py | 163 +------------------------- 1 file changed, 2 insertions(+), 161 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index cfe67fb57f5..4cce4740c25 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -3,7 +3,6 @@ """ #***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery -# 2015 Christian Stump 0: - s = c[i] - if pi.has_left_descent(s): - pi = pi.apply_simple_reflection_left(s) - l -= 1 - sorting_word.append(s) - i += 1 - if i == n: - i = 0 - return sorting_word - - def is_coxeter_sortable(self,c,sorting_word=None): - r""" - Return whether ``self`` is ``c``-sortable. - - Given a Coxeter element `c`, an element `w` is `c`-sortable if - its `c`-sorting word decomposes into a sequence of weakly - decreasing subwords of `c`. - - INPUT: - - - ``c`` -- a Coxeter element. - - ``sorting_word`` -- sorting word (default: None) used to - not recompute the ``c``-sorting word if already computed. - - OUTPUT: - - is ``self`` ``c``-sortable - - EXAMPLES:: - - sage: W = CoxeterGroups().example() - sage: c = W.from_reduced_word([0,2,1]) - sage: w = W.from_reduced_word([1,2,1,0,1]) - sage: w.coxeter_sorting_word(c) - [2, 1, 2, 0, 1] - sage: w.is_coxeter_sortable(c) - False - sage: w = W.from_reduced_word([0,2,1,0,2]) - sage: w.coxeter_sorting_word(c) - [2, 0, 1, 2, 0] - sage: w.is_coxeter_sortable(c) - True - sage: W = CoxeterGroup(['A',3]) - sage: c = W.from_reduced_word([1,2,3]) - sage: len([w for w in W if w.is_coxeter_sortable(c)]) # number of c-sortable elements in A_3 (Catalan number) - 14 - """ - if hasattr(c,"reduced_word"): - c = c.reduced_word() - elif not isinstance(c,list): - c = list(c) - if sorting_word is None: - sorting_word = self.coxeter_sorting_word(c) - n = len(c) - containment_list = [ True ]*n - l = 0 - i = 0 - while l < len(sorting_word): - s = c[i] - t = sorting_word[l] - if s == t: - l += 1 - if not containment_list[i]: - return False - else: - containment_list[i] = False - i += 1 - if i == n: - i = 0 - return True def apply_demazure_product(self, element, side = 'right', length_increasing = True): r""" From 2020f582c67e346ca9e2c33e94edfeade04472c5 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Mon, 8 Jun 2015 11:56:28 +0200 Subject: [PATCH 0248/1872] merged #18590 --- src/sage/categories/coxeter_groups.py | 156 +++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 4cce4740c25..e3721e7c8e4 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -3,6 +3,7 @@ """ #***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery +# 2015 Christian Stump 0: + s = c[i] + if pi.has_left_descent(s): + pi = pi.apply_simple_reflection_left(s) + l -= 1 + sorting_word.append(s) + i += 1 + if i == n: + i = 0 + return sorting_word + + def is_coxeter_sortable(self,c,sorting_word=None): + r""" + Return whether ``self`` is ``c``-sortable. + + Given a Coxeter element `c`, an element `w` is `c`-sortable if + its `c`-sorting word decomposes into a sequence of weakly + decreasing subwords of `c`. + + INPUT: + + - ``c`` -- a Coxeter element. + - ``sorting_word`` -- sorting word (default: None) used to + not recompute the ``c``-sorting word if already computed. + + OUTPUT: + + is ``self`` ``c``-sortable + + EXAMPLES:: + + sage: W = CoxeterGroups().example() + sage: c = W.from_reduced_word([0,2,1]) + sage: w = W.from_reduced_word([1,2,1,0,1]) + sage: w.coxeter_sorting_word(c) + [2, 1, 2, 0, 1] + sage: w.is_coxeter_sortable(c) + False + sage: w = W.from_reduced_word([0,2,1,0,2]) + sage: w.coxeter_sorting_word(c) + [2, 0, 1, 2, 0] + sage: w.is_coxeter_sortable(c) + True + sage: W = CoxeterGroup(['A',3]) + sage: c = W.from_reduced_word([1,2,3]) + sage: len([w for w in W if w.is_coxeter_sortable(c)]) # number of c-sortable elements in A_3 (Catalan number) + 14 + """ + if hasattr(c,"reduced_word"): + c = c.reduced_word() + elif not isinstance(c,list): + c = list(c) + if sorting_word is None: + sorting_word = self.coxeter_sorting_word(c) + n = len(c) + containment_list = [ True ]*n + l = 0 + i = 0 + while l < len(sorting_word): + s = c[i] + t = sorting_word[l] + if s == t: + l += 1 + if not containment_list[i]: + return False + else: + containment_list[i] = False + i += 1 + if i == n: + i = 0 + return True def apply_demazure_product(self, element, side = 'right', length_increasing = True): r""" From a77406367fd4d671ced241e1d6866ca786332c80 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Mon, 8 Jun 2015 12:56:03 +0200 Subject: [PATCH 0249/1872] moved the two version of cambrian lattice both into finite_coxeter_groups.py --- src/sage/categories/finite_coxeter_groups.py | 122 +++++++++++-------- src/sage/categories/finite_weyl_groups.py | 58 +-------- 2 files changed, 74 insertions(+), 106 deletions(-) diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index e06922a914a..f00088d8bf0 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -278,40 +278,18 @@ def weak_poset(self, side = "right", facade = False): weak_lattice = weak_poset - - @cached_method - def cambrian_lattice(self, c): - """ - Return the c-Cambrian lattice on delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). - Delta sequences are certain 2-colored minimal factorizations of ``c`` into reflections. - - INPUT: - - - ``c`` -- a standard Coxeter element in ``self`` (as a tuple, or as an element of ``self``) - - EXAMPLES:: - - sage: CoxeterGroup(["A", 2]).cambrian_lattice((1,2)) - Finite lattice containing 5 elements - - sage: CoxeterGroup(["B", 2]).cambrian_lattice((1,2)) - Finite lattice containing 6 elements - - sage: CoxeterGroup(["G", 2]).cambrian_lattice((1,2)) - Finite lattice containing 8 elements - - """ - from sage.combinat.posets.lattices import LatticePoset - return self.m_cambrian_lattice(c,1) - def inversion_sequence(self, word): """ - Return the inversion sequence corresponding to ``word``. If - ``word``=`[w_0,w_1,...w_k]`, then the output is `[w_0,w_0w_1w_0,\ldots,w_0w_1\cdots w_k \cdots w_1 w_0]`. + Return the inversion sequence corresponding to the ``word`` + in indices of simple generators of ``self``. + + If ``word`` corresponds to `[w_0,w_1,...w_k]`, the output is + `[w_0,w_0w_1w_0,\ldots,w_0w_1\cdots w_k \cdots w_1 w_0]`. INPUT: - - ``word`` -- a word in the simple generators of ``self`` + - ``word`` -- a word in the indices of the simple + generators of ``self``. EXAMPLES:: @@ -342,16 +320,16 @@ def reflections_from_w0(self): sage: WeylGroup(['A',3]).reflections_from_w0() [ - [-1 1 0] [ 0 -1 1] [ 1 0 0] [ 0 0 -1] [ 1 0 0] [ 1 0 0] - [ 0 1 0] [-1 0 1] [ 1 -1 1] [-1 1 -1] [ 1 0 -1] [ 0 1 0] - [ 0 0 1], [ 0 0 1], [ 0 0 1], [-1 0 0], [ 1 -1 0], [ 0 1 -1] + [0 1 0 0] [0 0 1 0] [1 0 0 0] [0 0 0 1] [1 0 0 0] [1 0 0 0] + [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 1 0 0] [0 0 0 1] [0 1 0 0] + [0 0 1 0] [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 1 0] [0 0 0 1] + [0 0 0 1], [0 0 0 1], [0 0 0 1], [1 0 0 0], [0 1 0 0], [0 0 1 0] ] - """ return self.long_element().inversions_as_reflections() @cached_method - def m_cambrian_lattice(self, c, m = 1): + def m_cambrian_lattice(self, c, m=1, on_roots=False): """ Return the m-Cambrian lattice on ``m``-delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). ``m``-delta sequences are certain ``m``-colored minimal factorizations of ``c`` into reflections. @@ -370,44 +348,90 @@ def m_cambrian_lattice(self, c, m = 1): Finite lattice containing 12 elements """ - from sage.combinat.posets.posets import Poset from sage.combinat.posets.lattices import LatticePoset if hasattr(c,"reduced_word"): c = c.reduced_word() elif not isinstance(c,list): c = list(c) - inv_woc = self.inversion_sequence(self.long_element().coxeter_sorting_word(c)) - S = self.simple_reflections() - T = self.reflections_from_w0() - Twords = {t:t.reduced_word() for t in T}#PhiP=T - id = sorted([[s,0] for s in S]) + + if on_roots: + if not hasattr(self.long_element(),"reflection_to_root"): + raise ValueError("The parameter 'on_root=True' needs the ElementMethod 'reflection_to_root'") + + inv_woc = [t.reflection_to_root() for t in self.inversion_sequence(self.long_element().coxeter_sorting_word(c))] + S = [s.reflection_to_root() for s in self.simple_reflections()] + PhiP = [t.reflection_to_root() for t in self.reflections().keys()] + else: + inv_woc = self.inversion_sequence(self.long_element().coxeter_sorting_word(c)) + S = self.simple_reflections() + T = self.reflections_from_w0() + Twords = {t : t.reduced_word() for t in T} + elements = [] covers = [] - new = [id] + + bottom_elt = sorted([[s,0] for s in S]) + new = [bottom_elt] while new != []: for new_element in new: new.remove(new_element) elements.append(new_element) for t in new_element: - if t[1] Date: Mon, 8 Jun 2015 12:58:43 +0200 Subject: [PATCH 0250/1872] fixed the docstring --- src/sage/categories/finite_coxeter_groups.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index f00088d8bf0..9897814ccb3 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -337,8 +337,14 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): INPUT: - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) + - ``m`` -- a positive integer (default: 1) + - ``on_roots`` (optional) -- if ``on_roots`` is ``True``, + the lattice is realized on roots rather than on + reflections. In order for this to work, the ElementMethod + ``reflection_to_root`` must be available. + EXAMPLES:: sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2)) @@ -418,7 +424,8 @@ def cambrian_lattice(self, c, on_roots=False): - ``on_roots`` (optional) -- if ``on_roots`` is ``True``, the lattice is realized on roots rather than on - reflections ( + reflections. In order for this to work, the ElementMethod + ``reflection_to_root`` must be available. EXAMPLES:: From 188b56f3367da3bcd1e5298dc012c663f5f08025 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 9 Jun 2015 13:52:22 +0200 Subject: [PATCH 0251/1872] Minor changes --- src/sage/coding/encoder.py | 65 ++++++++++------------------------ src/sage/coding/linear_code.py | 32 ++++++----------- 2 files changed, 29 insertions(+), 68 deletions(-) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 1eea44019fd..6c8cb90305e 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -97,46 +97,6 @@ def __init__(self, code): """ self._code = code - def __eq__(self, other): - r""" - Checks equality between ``self`` and ``other``. - - 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: E1 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) - sage: E2 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) - sage: E1 == E2 - True - sage: G = Matrix(GF(3), [[2,1,1,0,0,0,1],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,1,1,0,0,1]]) - sage: C1 = LinearCode(G) - sage: E2 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C1) - sage: E1 == E2 - False - """ - return self.code() == other.code() - - def __ne__(self, other): - r""" - Checks difference between ``self`` and ``other``. - - 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: E1 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) - sage: E2 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) - sage: E1 != E2 - False - sage: G = Matrix(GF(3), [[2,1,1,0,0,0,1],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,1,1,0,0,1]]) - sage: C1 = LinearCode(G) - sage: E2 = codes.encoders.LinearCodeGeneratorMatrixEncoder(C1) - sage: E1 != E2 - True - """ - return not self.__eq__(other) - def encode(self, word): r""" Transforms an element of the message space into an element of the code. @@ -158,14 +118,25 @@ def encode(self, word): 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: word = vector((0, 1, 1, 0)) + sage: word = vector(GF(2), (0, 1, 1, 0)) sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E.encode(word) (1, 1, 0, 0, 1, 1, 0) + + If ``word`` is not in the message space of ``self``, it will return an exception:: + + sage: word = random_vector(GF(7), 4) + sage: E.encode(word) + Traceback (most recent call last): + ... + ValueError: Vector to encode must be in a Vector space of dimension 4 over Finite Field of size 2 """ + M = self.message_space() + if word not in M: + raise ValueError("Vector to encode must be in a %s" % M) return vector(word) * self.generator_matrix() - def unencode(self, c, nocheck=False, **kwargs): + def unencode(self, c, nocheck=False): r""" Returns the message corresponding to ``c``. @@ -194,9 +165,9 @@ def unencode(self, c, nocheck=False, **kwargs): if c not in self.code(): raise EncodingFailure("Given word is not in the code") else: - return self.unencode_nocheck(c, **kwargs) + return self.unencode_nocheck(c) else: - return self.unencode_nocheck(c, **kwargs) + return self.unencode_nocheck(c) @cached_method def unencoder_matrix(self): @@ -227,7 +198,7 @@ def unencoder_matrix(self): Gt = self.generator_matrix().matrix_from_columns(self.code().information_set()) return Gt.inverse() - def unencode_nocheck(self, c, **kwargs): + def unencode_nocheck(self, c): r""" Returns the message corresponding to ``c``. @@ -313,8 +284,8 @@ def generator_matrix(self): This is an abstract method and it should be implemented separately. Reimplementing this for each subclass of :class:`Encoder` is not mandatory - (as encoders with a polynomial message space, for instance, do not - need a generator matrix). + (as a generator matrix only makes sense when the message space is of the `F^k`, + where `F` is the base field of :meth:`code`.) """ class EncodingFailure(Exception): diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 2f3657c6078..5d3ad8455f9 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -744,6 +744,12 @@ 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 + and thus can be long for certain families of code. + In that case, overriding these methods is encouraged. + A lot of methods of the abstract class rely on the knowledge of a generator matrix. It is thus strongly recommended to set an encoder with a generator matrix implemented as a default encoder. @@ -880,7 +886,7 @@ def _an_element_(self): """ return self.gens()[0] - def add_encoder(self, name, encoder, check=True): + def add_encoder(self, name, encoder): r""" Adds an encoder to the list of registered encoders of ``self``. @@ -890,9 +896,6 @@ def add_encoder(self, name, encoder, check=True): - ``encoder`` -- the class name of the encoder - - ``check`` -- (default: ``True``) if true, checks if ``name`` or ``encoder`` - are already in the list of registered encoders, and raises an error if yes - EXAMPLES: First of all, we create a (very basic) new encoder:: @@ -921,29 +924,16 @@ def add_encoder(self, name, encoder, check=True): TESTS: - If ``check`` is True, it is impossible to use a name which is in - the dictionnary of available encoders:: + It is impossible to use a name which is in the dictionnary of available encoders:: sage: C.add_encoder("GeneratorMatrix", MyEncoder) Traceback (most recent call last): ... ValueError: There is already a registered encoder with this name - - But if ``check`` is set to false, overriding names is authorized:: - - sage: C.encoders_available(True) - [('MyEncoder', ), - ('GeneratorMatrix', - )] - sage: C.add_encoder("GeneratorMatrix", MyEncoder, False) - sage: C.encoders_available(True) - [('MyEncoder', ), - ('GeneratorMatrix', )] """ reg_enc = self._registered_encoders - if check==True: - if(name in reg_enc.keys()): - raise ValueError("There is already a registered encoder with this name") + if(name in reg_enc.keys()): + raise ValueError("There is already a registered encoder with this name") reg_enc[name] = encoder def automorphism_group_gens(self, equivalence="semilinear"): @@ -2126,7 +2116,7 @@ def __iter__(self): FiniteFieldsubspace_iterator return FiniteFieldsubspace_iterator(self.generator_matrix(), immutable=True) - + @cached_method def information_set(self): """ Return an information set of the code. From 12dd9fe9073fef76e81f841466f860c899a5e027 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Tue, 9 Jun 2015 19:46:23 +0200 Subject: [PATCH 0252/1872] #18338 : update docstring formula. --- src/sage/combinat/combinat.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 300d6ddf0f0..dbbd38019ef 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -2681,9 +2681,9 @@ def bell_polynomial(n, k): .. MATH:: - B_{n,k}(x_1, x_2, \ldots, x_{n-k+1}) = \sum_{\sum{j_i}=k, \sum{i j_i} - =n} \frac{n!}{j_1!j_2!\cdots} \frac{x_1}{1!}^j_1 \frac{x_2}{2!}^j_2 - \cdots. + B_{n,k}(x_0, x_1, \ldots, x_{n-k}) = \sum_{\sum{j_i}=k, \sum{(i+1) j_i} + =n} \frac{n!}{j_0!j_1!\cdots j_{n-k}!} \left(\frac{x_0}{(0+1)!}\right)^{j_0} \left(\frac{x_1}{(1+1)!}\right)^{j_1} + \cdots \left(\frac{x_{n-k}}{(n-k+1)!}\right)^{j_{n-k}}. INPUT: From 6de51b865d814879c98e0b3a7c4dbeed963dfb25 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Wed, 10 Jun 2015 08:39:20 +0200 Subject: [PATCH 0253/1872] #18338 reformat formula. --- src/sage/combinat/combinat.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index dbbd38019ef..38a08ef898a 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -2681,9 +2681,12 @@ def bell_polynomial(n, k): .. MATH:: - B_{n,k}(x_0, x_1, \ldots, x_{n-k}) = \sum_{\sum{j_i}=k, \sum{(i+1) j_i} - =n} \frac{n!}{j_0!j_1!\cdots j_{n-k}!} \left(\frac{x_0}{(0+1)!}\right)^{j_0} \left(\frac{x_1}{(1+1)!}\right)^{j_1} - \cdots \left(\frac{x_{n-k}}{(n-k+1)!}\right)^{j_{n-k}}. + B_{n,k}(x_0, x_1, \ldots, x_{n-k}) = + \sum_{\sum{j_i}=k, \sum{(i+1) j_i}=n} + \frac{n!}{j_0!j_1!\cdots j_{n-k}!} + \left(\frac{x_0}{(0+1)!}\right)^{j_0} + \left(\frac{x_1}{(1+1)!}\right)^{j_1} \cdots + \left(\frac{x_{n-k}}{(n-k+1)!}\right)^{j_{n-k}}. INPUT: From 63df8b790d52b2d45cdd8060099931486914ce34 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 11 Jun 2015 07:21:35 -0500 Subject: [PATCH 0254/1872] removed most instances of choose_nk and split_nk, choose_nk.from_rank and choose_nk.rank seem to remain --- src/doc/en/reference/combinat/module_list.rst | 2 - src/sage/combinat/choose_nk.py | 189 ------------------ src/sage/combinat/combination.py | 25 --- src/sage/combinat/enumerated_sets.py | 2 - src/sage/combinat/set_partition_ordered.py | 27 --- src/sage/combinat/split_nk.py | 61 ------ src/sage/combinat/subset.py | 1 - 7 files changed, 307 deletions(-) delete mode 100644 src/sage/combinat/choose_nk.py delete mode 100644 src/sage/combinat/split_nk.py diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index b5a90e17e12..ba02d240deb 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -27,7 +27,6 @@ Comprehensive Module list sage/combinat/binary_tree sage/combinat/cartesian_product sage/combinat/catalog_partitions - sage/combinat/choose_nk sage/combinat/cluster_algebra_quiver/__init__ sage/combinat/cluster_algebra_quiver/all sage/combinat/cluster_algebra_quiver/cluster_seed @@ -299,7 +298,6 @@ Comprehensive Module list sage/combinat/species/structure sage/combinat/species/subset_species sage/combinat/species/sum_species - sage/combinat/split_nk sage/combinat/subset sage/combinat/subsets_hereditary sage/combinat/subsets_pairwise diff --git a/src/sage/combinat/choose_nk.py b/src/sage/combinat/choose_nk.py deleted file mode 100644 index faa48df8beb..00000000000 --- a/src/sage/combinat/choose_nk.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -Deprecated combinations - -AUTHORS: - -- Mike Hansen (2007): initial implementation - -- Vincent Delecroix (2014): deprecation -""" -#***************************************************************************** -# Copyright (C) 2007 Mike Hansen , -# -# 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.rings.arith import binomial - -def ChooseNK(n, k): - """ - All possible choices of k elements out of range(n) without repetitions. - - The elements of the output are tuples of Python int (and not Sage Integer). - - This was deprecated in :trac:`10534` for :func:`Combinations` - (or ``itertools.combinations`` for doing iteration). - - EXAMPLES:: - - sage: from sage.combinat.choose_nk import ChooseNK - sage: c = ChooseNK(4,2) - doctest:...: DeprecationWarning: ChooseNk is deprecated and will be - removed. Use Combinations instead (or combinations from the itertools - module for iteration) - See http://trac.sagemath.org/10534 for details. - sage: c.first() - [0, 1] - sage: c.list() - [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]] - """ - from sage.misc.superseded import deprecation - deprecation(10534, "ChooseNk is deprecated and will be removed. Use Combinations instead (or combinations from the itertools module for iteration)") - from sage.combinat.combination import Combinations - return Combinations(n,k) - -#TODO: the following functions are used sage.combinat.combination and -# sage.combinat.subset. It might be good to move them somewhere else. -def rank(comb, n, check=True): - """ - Return the rank of ``comb`` in the subsets of ``range(n)`` of size ``k`` - where ``k`` is the length of ``comb``. - - The algorithm used is based on combinadics and James McCaffrey's - MSDN article. See: :wikipedia:`Combinadic`. - - EXAMPLES:: - - sage: import sage.combinat.choose_nk as choose_nk - sage: choose_nk.rank((), 3) - 0 - sage: choose_nk.rank((0,), 3) - 0 - sage: choose_nk.rank((1,), 3) - 1 - sage: choose_nk.rank((2,), 3) - 2 - sage: choose_nk.rank((0,1), 3) - 0 - sage: choose_nk.rank((0,2), 3) - 1 - sage: choose_nk.rank((1,2), 3) - 2 - sage: choose_nk.rank((0,1,2), 3) - 0 - - sage: choose_nk.rank((0,1,2,3), 3) - Traceback (most recent call last): - ... - ValueError: len(comb) must be <= n - sage: choose_nk.rank((0,0), 2) - Traceback (most recent call last): - ... - ValueError: comb must be a subword of (0,1,...,n) - - sage: choose_nk.rank([1,2], 3) - 2 - sage: choose_nk.rank([0,1,2], 3) - 0 - """ - k = len(comb) - if check: - if k > n: - raise ValueError("len(comb) must be <= n") - comb = [int(_) for _ in comb] - for i in xrange(k - 1): - if comb[i + 1] <= comb[i]: - raise ValueError("comb must be a subword of (0,1,...,n)") - - #Generate the combinadic from the - #combination - - #w = [n-1-comb[i] for i in xrange(k)] - - #Calculate the integer that is the dual of - #the lexicographic index of the combination - r = k - t = 0 - for i in range(k): - t += binomial(n - 1 - comb[i], r) - r -= 1 - - return binomial(n,k)-t-1 - - - -def _comb_largest(a,b,x): - """ - Returns the largest w < a such that binomial(w,b) <= x. - - EXAMPLES:: - - sage: from sage.combinat.choose_nk import _comb_largest - sage: _comb_largest(6,3,10) - 5 - sage: _comb_largest(6,3,5) - 4 - """ - w = a - 1 - - while binomial(w,b) > x: - w -= 1 - - return w - -def from_rank(r, n, k): - """ - Returns the combination of rank r in the subsets of range(n) of - size k when listed in lexicographic order. - - The algorithm used is based on combinadics and James McCaffrey's - MSDN article. See: http://en.wikipedia.org/wiki/Combinadic - - EXAMPLES:: - - sage: import sage.combinat.choose_nk as choose_nk - sage: choose_nk.from_rank(0,3,0) - () - sage: choose_nk.from_rank(0,3,1) - (0,) - sage: choose_nk.from_rank(1,3,1) - (1,) - sage: choose_nk.from_rank(2,3,1) - (2,) - sage: choose_nk.from_rank(0,3,2) - (0, 1) - sage: choose_nk.from_rank(1,3,2) - (0, 2) - sage: choose_nk.from_rank(2,3,2) - (1, 2) - sage: choose_nk.from_rank(0,3,3) - (0, 1, 2) - """ - if k < 0: - raise ValueError("k must be > 0") - if k > n: - raise ValueError("k must be <= n") - - a = n - b = k - x = binomial(n, k) - 1 - r # x is the 'dual' of m - comb = [None] * k - - for i in xrange(k): - comb[i] = _comb_largest(a, b, x) - x = x - binomial(comb[i], b) - a = comb[i] - b = b - 1 - - for i in xrange(k): - comb[i] = (n - 1) - comb[i] - - return tuple(comb) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index e72bce63ae7..00dadb2a0fe 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -27,7 +27,6 @@ from sage.rings.all import ZZ, Integer from sage.rings.arith import binomial from combinat import CombinatorialClass -from choose_nk import rank, from_rank from integer_vector import IntegerVectors from sage.misc.misc import uniq @@ -465,27 +464,3 @@ def rank(self, x): x = [self.mset.index(_) for _ in x] return rank(x, len(self.mset)) - -########################################################## -# Deprecations - -class ChooseNK(Combinations_setk): - def __setstate__(self, state): - r""" - For unpickling old ``ChooseNK`` objects. - - TESTS:: - - sage: loads("x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1K\xce\xc8\xcf" - ....: "/N\x8d\xcf\xcb\xe6r\x06\xb3\xfc\xbc\xb9\n\x195\x1b\x0b" - ....: "\x99j\x0b\x995B\x99\xe2\xf3\nY :\x8a2\xf3\xd2\x8b\xf52" - ....: "\xf3JR\xd3S\x8b\xb8r\x13\xb3S\xe3a\x9cB\xd6PF\xd3\xd6\xa0" - ....: "B6\xa0\xfa\xecB\xf6\x0c \xd7\x08\xc8\xe5(M\xd2\x03\x00{" - ....: "\x82$\xd8") - Combinations of [0, 1, 2, 3, 4] of length 2 - """ - self.__class__ = Combinations_setk - Combinations_setk.__init__(self, range(state['_n']), state['_k']) - -from sage.structure.sage_object import register_unpickle_override -register_unpickle_override("sage.combinat.choose_nk", "ChooseNK", ChooseNK) diff --git a/src/sage/combinat/enumerated_sets.py b/src/sage/combinat/enumerated_sets.py index a39220a900e..ce295b1dff8 100644 --- a/src/sage/combinat/enumerated_sets.py +++ b/src/sage/combinat/enumerated_sets.py @@ -130,8 +130,6 @@ ------------------------- - :ref:`sage.combinat.permutation_nk` -- :ref:`sage.combinat.split_nk` -- :ref:`sage.combinat.choose_nk` - :ref:`sage.combinat.multichoose_nk` - :ref:`sage.combinat.gray_codes` diff --git a/src/sage/combinat/set_partition_ordered.py b/src/sage/combinat/set_partition_ordered.py index 908401920fd..e42b52b3b37 100644 --- a/src/sage/combinat/set_partition_ordered.py +++ b/src/sage/combinat/set_partition_ordered.py @@ -585,30 +585,3 @@ def __iter__(self): yield self.element_class(self, [Set(res[dcomp[i]+1:dcomp[i+1]+1]) for i in range(l)]) -########################################################## -# Deprecations - - -class SplitNK(OrderedSetPartitions_scomp): - def __setstate__(self, state): - r""" - For unpickling old ``SplitNK`` objects. - - TESTS:: - - sage: loads("x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+.\xc8\xc9," - ....: "\x89\xcf\xcb\xe6\n\x061\xfc\xbcA\xccBF\xcd\xc6B\xa6\xda" - ....: "Bf\x8dP\xa6\xf8\xbcB\x16\x88\x96\xa2\xcc\xbc\xf4b\xbd\xcc" - ....: "\xbc\x92\xd4\xf4\xd4\"\xae\xdc\xc4\xec\xd4x\x18\xa7\x905" - ....: "\x94\xd1\xb45\xa8\x90\r\xa8>\xbb\x90=\x03\xc85\x02r9J\x93" - ....: "\xf4\x00\xb4\xc6%f") - Ordered set partitions of {0, 1, 2, 3, 4} into parts of size [2, 3] - """ - self.__class__ = OrderedSetPartitions_scomp - n = state['_n'] - k = state['_k'] - OrderedSetPartitions_scomp.__init__(self, range(state['_n']), (k,n-k)) - -from sage.structure.sage_object import register_unpickle_override -register_unpickle_override("sage.combinat.split_nk", "SplitNK_nk", SplitNK) - diff --git a/src/sage/combinat/split_nk.py b/src/sage/combinat/split_nk.py deleted file mode 100644 index 93ae9f754f7..00000000000 --- a/src/sage/combinat/split_nk.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Derecated splits - -Authors: - -- Mike Hansen (2007): original version - -- Vincent Delecroix (2014): deprecation -""" -#***************************************************************************** -# Copyright (C) 2007 Mike Hansen , -# -# 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/ -#***************************************************************************** - -def SplitNK(n, k): - """ - Returns the combinatorial class of splits of a the set range(n) - into a set of size k and a set of size n-k. - - This was deprecated in :trac:`10534`. Use instead - :class:`OrderedSetPartitions`. - - EXAMPLES:: - - sage: from sage.combinat.split_nk import SplitNK - sage: S = SplitNK(5,2) - doctest:...: DeprecationWarning: SplitNk is deprecated and will be - removed. Use OrderedSetPartitions instead. - See http://trac.sagemath.org/10534 for details. - sage: S - Ordered set partitions of {0, 1, 2, 3, 4} into parts of size [2, 3] - sage: S.first() - [{0, 1}, {2, 3, 4}] - sage: S.last() - [{3, 4}, {0, 1, 2}] - sage: S.list() - [[{0, 1}, {2, 3, 4}], - [{0, 2}, {1, 3, 4}], - [{0, 3}, {1, 2, 4}], - [{0, 4}, {1, 2, 3}], - [{1, 2}, {0, 3, 4}], - [{1, 3}, {0, 2, 4}], - [{1, 4}, {0, 2, 3}], - [{2, 3}, {0, 1, 4}], - [{2, 4}, {0, 1, 3}], - [{3, 4}, {0, 1, 2}]] - """ - from sage.misc.superseded import deprecation - from sage.combinat.set_partition_ordered import OrderedSetPartitions - deprecation(10534, "SplitNk is deprecated and will be removed. Use OrderedSetPartitions instead.") - return OrderedSetPartitions(range(n), [k, n-k]) diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index 39aff81e561..082fde42379 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -41,7 +41,6 @@ from sage.rings.arith import binomial from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer -import choose_nk ZZ_0 = ZZ.zero() From 5258e5ed24489ece0d699f32a841df7fc1808921 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 11 Jun 2015 07:48:59 -0500 Subject: [PATCH 0255/1872] saved the functions rank and from_rank in choose_nk.py --- src/sage/combinat/combination.py | 1 + src/sage/combinat/subset.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 00dadb2a0fe..ba11496a418 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -29,6 +29,7 @@ from combinat import CombinatorialClass from integer_vector import IntegerVectors from sage.misc.misc import uniq +from choose_nk import rank, from_rank def Combinations(mset, k=None): """ diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index 082fde42379..39aff81e561 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -41,6 +41,7 @@ from sage.rings.arith import binomial from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer +import choose_nk ZZ_0 = ZZ.zero() From ec6c8c9bf60fafdc0e20887b1620b5271daf9ec4 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 11 Jun 2015 07:50:51 -0500 Subject: [PATCH 0256/1872] readded file choose_nk.py --- src/sage/combinat/choose_nk.py | 162 +++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/sage/combinat/choose_nk.py diff --git a/src/sage/combinat/choose_nk.py b/src/sage/combinat/choose_nk.py new file mode 100644 index 00000000000..7e5da370c1d --- /dev/null +++ b/src/sage/combinat/choose_nk.py @@ -0,0 +1,162 @@ +""" +Deprecated combinations + +AUTHORS: + +- Mike Hansen (2007): initial implementation + +- Vincent Delecroix (2014): deprecation +""" +#***************************************************************************** +# Copyright (C) 2007 Mike Hansen , +# +# 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.rings.arith import binomial + +#TODO: the following functions are used sage.combinat.combination and +# sage.combinat.subset. It might be good to move them somewhere else. +def rank(comb, n, check=True): + """ + Return the rank of ``comb`` in the subsets of ``range(n)`` of size ``k`` + where ``k`` is the length of ``comb``. + + The algorithm used is based on combinadics and James McCaffrey's + MSDN article. See: :wikipedia:`Combinadic`. + + EXAMPLES:: + + sage: import sage.combinat.choose_nk as choose_nk + sage: choose_nk.rank((), 3) + 0 + sage: choose_nk.rank((0,), 3) + 0 + sage: choose_nk.rank((1,), 3) + 1 + sage: choose_nk.rank((2,), 3) + 2 + sage: choose_nk.rank((0,1), 3) + 0 + sage: choose_nk.rank((0,2), 3) + 1 + sage: choose_nk.rank((1,2), 3) + 2 + sage: choose_nk.rank((0,1,2), 3) + 0 + + sage: choose_nk.rank((0,1,2,3), 3) + Traceback (most recent call last): + ... + ValueError: len(comb) must be <= n + sage: choose_nk.rank((0,0), 2) + Traceback (most recent call last): + ... + ValueError: comb must be a subword of (0,1,...,n) + + sage: choose_nk.rank([1,2], 3) + 2 + sage: choose_nk.rank([0,1,2], 3) + 0 + """ + k = len(comb) + if check: + if k > n: + raise ValueError("len(comb) must be <= n") + comb = [int(_) for _ in comb] + for i in xrange(k - 1): + if comb[i + 1] <= comb[i]: + raise ValueError("comb must be a subword of (0,1,...,n)") + + #Generate the combinadic from the + #combination + + #w = [n-1-comb[i] for i in xrange(k)] + + #Calculate the integer that is the dual of + #the lexicographic index of the combination + r = k + t = 0 + for i in range(k): + t += binomial(n - 1 - comb[i], r) + r -= 1 + + return binomial(n,k)-t-1 + + + +def _comb_largest(a,b,x): + """ + Returns the largest w < a such that binomial(w,b) <= x. + + EXAMPLES:: + + sage: from sage.combinat.choose_nk import _comb_largest + sage: _comb_largest(6,3,10) + 5 + sage: _comb_largest(6,3,5) + 4 + """ + w = a - 1 + + while binomial(w,b) > x: + w -= 1 + + return w + +def from_rank(r, n, k): + """ + Returns the combination of rank r in the subsets of range(n) of + size k when listed in lexicographic order. + + The algorithm used is based on combinadics and James McCaffrey's + MSDN article. See: http://en.wikipedia.org/wiki/Combinadic + + EXAMPLES:: + + sage: import sage.combinat.choose_nk as choose_nk + sage: choose_nk.from_rank(0,3,0) + () + sage: choose_nk.from_rank(0,3,1) + (0,) + sage: choose_nk.from_rank(1,3,1) + (1,) + sage: choose_nk.from_rank(2,3,1) + (2,) + sage: choose_nk.from_rank(0,3,2) + (0, 1) + sage: choose_nk.from_rank(1,3,2) + (0, 2) + sage: choose_nk.from_rank(2,3,2) + (1, 2) + sage: choose_nk.from_rank(0,3,3) + (0, 1, 2) + """ + if k < 0: + raise ValueError("k must be > 0") + if k > n: + raise ValueError("k must be <= n") + + a = n + b = k + x = binomial(n, k) - 1 - r # x is the 'dual' of m + comb = [None] * k + + for i in xrange(k): + comb[i] = _comb_largest(a, b, x) + x = x - binomial(comb[i], b) + a = comb[i] + b = b - 1 + + for i in xrange(k): + comb[i] = (n - 1) - comb[i] + + return tuple(comb) From 462efd556a38f382de865d9152a0dfb59185a5eb Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 11 Jun 2015 07:55:37 -0500 Subject: [PATCH 0257/1872] restore important lines --- src/sage/combinat/combination.py | 2 +- src/sage/combinat/enumerated_sets.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index ba11496a418..6cdc988b569 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -27,9 +27,9 @@ from sage.rings.all import ZZ, Integer from sage.rings.arith import binomial from combinat import CombinatorialClass +from choose_nk import rank, from_rank from integer_vector import IntegerVectors from sage.misc.misc import uniq -from choose_nk import rank, from_rank def Combinations(mset, k=None): """ diff --git a/src/sage/combinat/enumerated_sets.py b/src/sage/combinat/enumerated_sets.py index ce295b1dff8..3f789bd584c 100644 --- a/src/sage/combinat/enumerated_sets.py +++ b/src/sage/combinat/enumerated_sets.py @@ -130,6 +130,7 @@ ------------------------- - :ref:`sage.combinat.permutation_nk` +- :ref:`sage.combinat.choose_nk` - :ref:`sage.combinat.multichoose_nk` - :ref:`sage.combinat.gray_codes` From 58f409befffcd138a1c29caefe671a309be82408 Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Thu, 11 Jun 2015 16:58:40 +0000 Subject: [PATCH 0258/1872] Added convolution_product and hopf_power method --- src/sage/categories/hopf_algebras.py | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index eba5add5d9a..2d5c02feb05 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -61,6 +61,79 @@ def dual(self): WithBasis = LazyImport('sage.categories.hopf_algebras_with_basis', 'HopfAlgebrasWithBasis') class ElementMethods: + def convolution_product(h,a,b): + r""" + input: h - an element of a Hopf algebra H + a,b - linear maps from H to H + output: [a*b](h) + """ + H = h.parent() + out = 0 + for (bimonom,coef) in h.coproduct(): + out += coef*a(H(bimonom[0]))*b(H(bimonom[1])) + return out + + def convolution_power(h, L, n): + r""" + input: h - an element of a Hopf algebra H + L - linear map from H to H + n - the convolution power to which to take 'L' + output: [L^*n](h) + """ + from sage.categories.tensor import tensor + H = h.parent() + def n_fold_coproduct(h, n): + H = h.parent() + if n == 0: + return H(h.counit()) + elif n == 1: + return h + elif n == 2: + return h.coproduct() + else: + # apply some kind of multilinear recursion + Hn = tensor([H]*n) # or: tensor([H for i in range(n)]) + terms = [] + hh = n_fold_coproduct(h, n-1) + for (monom,cof) in hh: + h0 = H(monom[0]).coproduct() + terms += [(tuple((h00, h01) + monom[1:]), cof0 * cof) for ((h00, h01), cof0) in h0] + return Hn.sum_of_terms(terms) + hhh = n_fold_coproduct(h,n) + out = H.zero() + for term in hhh: + out += H.prod(L(H(t)) for t in term[0]) * term[1] + return out + + def hopf_power(h,n=2): + r""" + Input: + h - an element of a Hopf algebra H + n - the convolution power of the identity morphism to use + Output: + the nth convolution power of the identity morphism, applied to h., i.e., [id^*n](h) + + Remark: for historical reasons (see saga of Frobenius-Schur indicators), the second power deserves special attention. + we use '2' as the default value for 'n' + """ + H = h.parent() + def Id(x): + return x + def S(x): + return x.antipode() + + if n<0: + L = S + else: + L = Id + + if n==0: + return H(h.counit()) + elif abs(n)==1: + return L(h) + else: + return h.convolution_power(L,abs(n)) + def antipode(self): """ Returns the antipode of self. @@ -86,6 +159,7 @@ def antipode(self): # This choice should be done consistently with coproduct, ... # return operator.antipode(self) + class ParentMethods: #def __setup__(self): # Check the conventions for _setup_ or __setup__ # if self.implements("antipode"): From 7b35f5508523a517e1f213e9a6b53749e9b5e8ed Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 11 Jun 2015 15:03:00 -0500 Subject: [PATCH 0259/1872] restore pickles --- src/sage/combinat/combination.py | 24 +++++++++++++++++++ src/sage/combinat/set_partition_ordered.py | 27 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 6cdc988b569..e72bce63ae7 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -465,3 +465,27 @@ def rank(self, x): x = [self.mset.index(_) for _ in x] return rank(x, len(self.mset)) + +########################################################## +# Deprecations + +class ChooseNK(Combinations_setk): + def __setstate__(self, state): + r""" + For unpickling old ``ChooseNK`` objects. + + TESTS:: + + sage: loads("x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1K\xce\xc8\xcf" + ....: "/N\x8d\xcf\xcb\xe6r\x06\xb3\xfc\xbc\xb9\n\x195\x1b\x0b" + ....: "\x99j\x0b\x995B\x99\xe2\xf3\nY :\x8a2\xf3\xd2\x8b\xf52" + ....: "\xf3JR\xd3S\x8b\xb8r\x13\xb3S\xe3a\x9cB\xd6PF\xd3\xd6\xa0" + ....: "B6\xa0\xfa\xecB\xf6\x0c \xd7\x08\xc8\xe5(M\xd2\x03\x00{" + ....: "\x82$\xd8") + Combinations of [0, 1, 2, 3, 4] of length 2 + """ + self.__class__ = Combinations_setk + Combinations_setk.__init__(self, range(state['_n']), state['_k']) + +from sage.structure.sage_object import register_unpickle_override +register_unpickle_override("sage.combinat.choose_nk", "ChooseNK", ChooseNK) diff --git a/src/sage/combinat/set_partition_ordered.py b/src/sage/combinat/set_partition_ordered.py index e42b52b3b37..908401920fd 100644 --- a/src/sage/combinat/set_partition_ordered.py +++ b/src/sage/combinat/set_partition_ordered.py @@ -585,3 +585,30 @@ def __iter__(self): yield self.element_class(self, [Set(res[dcomp[i]+1:dcomp[i+1]+1]) for i in range(l)]) +########################################################## +# Deprecations + + +class SplitNK(OrderedSetPartitions_scomp): + def __setstate__(self, state): + r""" + For unpickling old ``SplitNK`` objects. + + TESTS:: + + sage: loads("x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+.\xc8\xc9," + ....: "\x89\xcf\xcb\xe6\n\x061\xfc\xbcA\xccBF\xcd\xc6B\xa6\xda" + ....: "Bf\x8dP\xa6\xf8\xbcB\x16\x88\x96\xa2\xcc\xbc\xf4b\xbd\xcc" + ....: "\xbc\x92\xd4\xf4\xd4\"\xae\xdc\xc4\xec\xd4x\x18\xa7\x905" + ....: "\x94\xd1\xb45\xa8\x90\r\xa8>\xbb\x90=\x03\xc85\x02r9J\x93" + ....: "\xf4\x00\xb4\xc6%f") + Ordered set partitions of {0, 1, 2, 3, 4} into parts of size [2, 3] + """ + self.__class__ = OrderedSetPartitions_scomp + n = state['_n'] + k = state['_k'] + OrderedSetPartitions_scomp.__init__(self, range(state['_n']), (k,n-k)) + +from sage.structure.sage_object import register_unpickle_override +register_unpickle_override("sage.combinat.split_nk", "SplitNK_nk", SplitNK) + From da729cc7e957de9095eb9cdfe909edb7c4fc5d5e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 15 Jun 2015 12:48:32 -0700 Subject: [PATCH 0260/1872] Added more axioms and reworked the manifolds category structure. --- src/sage/categories/category_with_axiom.py | 3 +- src/sage/categories/manifolds.py | 131 +++++++++++++++++---- 2 files changed, 113 insertions(+), 21 deletions(-) diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 214e71085d0..0893af7af75 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1673,7 +1673,8 @@ class ``Sets.Finite``), or in a separate file (typically in a class all_axioms = AxiomContainer() all_axioms += ("Flying", "Blue", - "Compact", "Complex", "Differentiable", "Smooth", + "Compact", "AlmostComplex", "Complex", + "Differentiable", "Smooth", "Analytic", "FinitelyGeneratedAsMagma", "Facade", "Finite", "Infinite", "FiniteDimensional", "Connected", "WithBasis", diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index 775567230cf..ec96693156d 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -100,6 +100,28 @@ def Connected(self): """ return self._with_axiom('Connected') + @cached_method + def FiniteDimensional(self): + """ + Return the full subcategory of the finite dimensional + objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds().Connected().FiniteDimensional(); C + Category of finite dimensional connected manifolds + + TESTS:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds().Connected().FiniteDimensional() + sage: TestSuite(C).run() + sage: Manifolds().Connected().FiniteDimensional.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('FiniteDimensional') + @cached_method def Differentiable(self): """ @@ -139,45 +161,61 @@ def Smooth(self): return self._with_axiom('Smooth') @cached_method - def Complex(self): + def Analytic(self): """ - Return the full subcategory of the complex objects of ``self``. + Return the subcategory of the analytic objects of ``self``. EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Complex() - Category of complex manifolds + sage: Manifolds().Analytic() + Category of analytic manifolds TESTS:: - sage: TestSuite(Manifolds().Complex()).run() - sage: Manifolds().Complex.__module__ + sage: TestSuite(Manifolds().Analytic()).run() + sage: Manifolds().Smooth.__module__ 'sage.categories.manifolds' """ - return self._with_axiom('Complex') + return self._with_axiom('Analytic') @cached_method - def FiniteDimensional(self): + def AlmostComplex(self): """ - Return the full subcategory of the finite dimensional - objects of ``self``. + Return the subcategory of the almost complex objects of ``self``. EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds().Connected().FiniteDimensional(); C - Category of finite dimensional connected manifolds + sage: Manifolds().AlmostComplex() + Category of almost complex manifolds TESTS:: + sage: TestSuite(Manifolds().AlmostComplex()).run() + sage: Manifolds().Smooth.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('AlmostComplex') + + @cached_method + def Complex(self): + """ + Return the subcategory of the complex objects of ``self``. + + EXAMPLES:: + sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds().Connected().FiniteDimensional() - sage: TestSuite(C).run() - sage: Manifolds().Connected().FiniteDimensional.__module__ + sage: Manifolds().Complex() + Category of complex manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Complex()).run() + sage: Manifolds().Smooth.__module__ 'sage.categories.manifolds' """ - return self._with_axiom('FiniteDimensional') + return self._with_axiom('Complex') class FiniteDimensional(CategoryWithAxiom): """ @@ -191,12 +229,18 @@ class Connected(CategoryWithAxiom): class Differentiable(CategoryWithAxiom): """ - The category of differentiable manifolds. + The category of differentiable manifolds over `\RR`. + + A `d`-dimensional differentiable manifold is a manifold whose + underlying vector space is `\RR^d` and differentiable atlas. """ class Smooth(CategoryWithAxiom): """ - The category of smooth manifolds. + The category of smooth manifolds over `\RR`. + + A `d`-dimensional differentiable manifold is a manifold whose + underlying vector space is `\RR^d` and smooth atlas. """ def extra_super_categories(self): """ @@ -212,9 +256,56 @@ def extra_super_categories(self): """ return [Manifolds().Differentiable()] + class Analytic(CategoryWithAxiom): + r""" + The category of complex manifolds. + + A `d`-dimensional analytic manifold is a manifold whose underlying + vector space is `\RR^d` and an analytic atlas. + """ + def extra_super_categories(self): + """ + Return the extra super categories of ``self``. + + An analytic manifold is smooth. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Analytic().super_categories() # indirect doctest + [Category of smooth manifolds] + """ + return [Manifolds().Smooth()] + + class AlmostComplex(CategoryWithAxiom): + r""" + The category of almost complex manifolds. + + A `d`-dimensional almost complex manifold `M` is a manifold + whose underlying vector space is `\RR^d` with a smooth tensor + field `J` of rank `(1, 1)` such that `J^2 = -1` when regarded as a + vector bundle isomorphism `J : TM \to TM` on the tangent bundle. + The tensor field `J` is called the almost complex structure of `M`. + """ + def extra_super_categories(self): + """ + Return the extra super categories of ``self``. + + An analytic manifold is smooth. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Analytic().super_categories() # indirect doctest + [Category of smooth manifolds] + """ + return [Manifolds().Smooth()] + class Complex(CategoryWithAxiom): r""" - The category of complex manifolds, i.e., the underlying vector - space is `\CC^d`. + The category of complex manifolds. + + A `d`-dimensional complex manifold is a manifold whose underlying + vector space is `\CC^d` and a holomorphic atlas. """ From 2763e276f0aa539faa0ee8ae0b63522b55821bd3 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 17 Jun 2015 21:54:20 +0200 Subject: [PATCH 0261/1872] first implementation of _update_poset_ and _add_ for expressions --- src/sage/rings/asymptotic_ring.py | 135 ++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 src/sage/rings/asymptotic_ring.py diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py new file mode 100644 index 00000000000..59f9dcdee19 --- /dev/null +++ b/src/sage/rings/asymptotic_ring.py @@ -0,0 +1,135 @@ +r""" +Asymptotic Ring + +AUTHORS: + +- Benjamin Hackl (2015-06): initial version + +""" + +# ***************************************************************************** +# Copyright (C) 2015 Benjamin Hackl +# +# 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/ +# ***************************************************************************** + +import sage + +def _absorption_(left, right): + r""" + Helper method for the mutable poset associated to our + """ + try: + return left.absorb(right) + except ArithmeticError: + return right.absorb(left) + + +class AsymptoticExpression(sage.rings.ring_element.RingElement): + r""" + ... + """ + def __init__(self, parent, poset): + r""" + ... + """ + self._poset_ = poset + super(AsymptoticExpression, self).__init__(parent=parent) + + + @property + def poset(self): + r""" + + """ + return self._poset_ + + def _repr_(self, reverse=False): + r""" + A representation string for this asymptotic expression. + """ + s = ' + '.join(repr(elem) for elem in + self._poset_.shells_topological(include_special=False, + reverse=reverse)) + return s + + # todo: implement _le_? + + def _update_poset_(self): + r""" + Helper method. This is called by ring operations like + :meth:`_add_` and :meth:`_mul_`. This triggers the absorption + of elements that are already in the poset. + + INPUT: + + Nothing. + + OUTPUT: + + Nothing. + + ... + """ + for shell in self.poset.shells_topological(reverse=True): + from sage.monoids.asymptotic_term_monoid import OTerm + if isinstance(shell.element, OTerm) and shell.element in self.poset: + while self.poset.null not in shell.predecessors(): + for elem in shell.predecessors(): + self.poset.remove(elem) + + + def _add_(self, other): + r""" + Add ``other`` to this asymptotic expression. + + INPUT: + + - ``other`` -- an :class:`AsymptoticExpression`. + + OUTPUT: + + An :class:`AsymptoticExpression`. + """ + poset = self.poset.union(other.poset) + self._update_poset_() + return self.parent()(poset=poset) + + + def _sub_(self, other): + r""" + Subtract ``other`` from this asymptotic expression. + + INPUT: + + - ``other`` -- an :class:`AsymptoticExpression`. + + OUTPUT: + + An :class:`AsymptoticExpression`. + """ + pass + + + def _mul_(self, other): + r""" + Multiply ``other`` to this asymptotic expression. + + INPUT: + + - ``other`` -- an :class:`AsymptoticExpression`. + + OUTPUT: + + An :class:`AsymptoticExpression`. + """ + pass + + + +class AsymptoticRing(sage.rings.ring.Ring): + pass \ No newline at end of file From df35a439d6b5b7f184f0d72647d1f5ae86e324aa Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 19 Jun 2015 15:27:02 -0700 Subject: [PATCH 0262/1872] Implement a better API for pickling/classcall for Cartan/Coxeter matrices. --- .../combinat/root_system/cartan_matrix.py | 54 ++- .../combinat/root_system/coxeter_matrix.py | 345 +++++++++--------- src/sage/combinat/root_system/coxeter_type.py | 115 +++--- 3 files changed, 248 insertions(+), 266 deletions(-) diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index a93232cf5b7..f9744012a1c 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -195,7 +195,8 @@ class CartanMatrix(Matrix_integer_sparse, CartanType_abstract): __metaclass__ = ClasscallMetaclass @staticmethod - def __classcall_private__(cls, *args, **kwds): + def __classcall_private__(cls, data=None, index_set=None, + cartan_type=None, cartan_type_check=True): """ Normalize input so we can inherit from sparse integer matrix. @@ -225,30 +226,28 @@ def __classcall_private__(cls, *args, **kwds): ('a', 'b') """ # Special case with 0 args and kwds has Cartan type - if "cartan_type" in kwds and len(args) == 0: - args = (CartanType(kwds["cartan_type"]),) - if len(args) == 0: + if cartan_type is not None and data is None: + data = CartanType(cartan_type) + + if data is None: data = [] n = 0 index_set = tuple() cartan_type = None subdivisions = None - elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling - return typecall(cls, args[0], args[1], args[2], args[3]) - elif isinstance(args[0], CartanMatrix): - return args[0] + elif isinstance(data, CartanMatrix): + return data else: - cartan_type = None dynkin_diagram = None subdivisions = None from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class - if isinstance(args[0], DynkinDiagram_class): - dynkin_diagram = args[0] - cartan_type = args[0]._cartan_type + if isinstance(data, DynkinDiagram_class): + dynkin_diagram = data + cartan_type = data._cartan_type else: try: - cartan_type = CartanType(args[0]) + cartan_type = CartanType(data) dynkin_diagram = cartan_type.dynkin_diagram() except (TypeError, ValueError): pass @@ -261,30 +260,24 @@ def __classcall_private__(cls, *args, **kwds): for (i,j,l) in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l else: - M = matrix(args[0]) + M = matrix(data) if not is_generalized_cartan_matrix(M): raise ValueError("the input matrix is not a generalized Cartan matrix") n = M.ncols() - if "cartan_type" in kwds: - cartan_type = CartanType(kwds["cartan_type"]) + if cartan_type is not None: + cartan_type = CartanType(cartan_type) elif n == 1: cartan_type = CartanType(['A', 1]) - elif kwds.get("cartan_type_check", True): + elif cartan_type_check: cartan_type = find_cartan_type_from_matrix(M) data = M.dict() subdivisions = M._subdivisions - if len(args) == 1: - if cartan_type is not None: - index_set = tuple(cartan_type.index_set()) - elif dynkin_diagram is None: - index_set = tuple(range(n)) - elif len(args) == 2: - index_set = tuple(args[1]) - if len(index_set) != n and len(set(index_set)) != n: - raise ValueError("the given index set is not valid") - else: - raise ValueError("too many arguments") + if index_set is None: + index_set = tuple(range(n)) + + if len(index_set) != n and len(set(index_set)) != n: + raise ValueError("the given index set is not valid") mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, cartan_type, index_set) mat._subdivisions = subdivisions @@ -315,8 +308,9 @@ def __reduce__(self): sage: x._index_set (1, 2, 3, 4) """ - return (CartanMatrix, (self.parent(), self.list(), - self._cartan_type, self._index_set)) + if self._cartan_type: + return (CartanMatrix, (self._cartan_type,)) + return (CartanMatrix, (self.dynkin_diagram(),)) def root_system(self): """ diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index cb452ccf7ec..83f1a9ed5d2 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -40,10 +40,22 @@ class CoxeterMatrix(CoxeterType): r""" A Coxeter matrix. - .. TODO:: + A Coxeter matrix `M = (m_{ij})_{i,j \in I}` is a matrix encoding + a Coxeter system `(W, S)`, where the relations are given by + `(s_i s_j)^{m_{ij}}`. Thus `M` is symmetric and has entries + in `\{1, 2, 3, \ldots, \infty\}` with `m_{ij} = 1` if and only + if `i = j`. - Because there is no object `\ZZ \cup \{ \infty \}`, we define `-1` - to represent `\infty`. + We represent `m_{ij} = \infty` by any number `m_{ij} \leq -1`. In + particular, we can construct a bilinear form `B = (b_{ij})_{i,j \in I}` + from `M` by + + .. MATH:: + + b_{ij} = \begin{cases} + m_{ij} & m_{ij} < 0 (\text{i.e.,} m_{ij} = \infty), + -\cos\left( \frac{\pi}{m_{ij}} \right) & \text{otherwise}. + \end{cases} EXAMPLES:: @@ -86,8 +98,8 @@ class CoxeterMatrix(CoxeterType): [1 6] [6 1] - Because there currently is no class for `\ZZ \cup \{ \infty \}`, labels - of `\infty` are given by `-1` in the Coxeter matrix:: + By default, entries representing `\infty` are given by `-1` + in the Coxeter matrix:: sage: G = Graph([(0,1,None), (1,2,4), (0,2,oo)]) sage: CoxeterMatrix(G) @@ -103,12 +115,12 @@ class CoxeterMatrix(CoxeterType): sage: CoxeterMatrix([[1,-3/2],[-3/2,1]]) [ 1 -3/2] [-3/2 1] - """ __metaclass__ = ClasscallMetaclass @staticmethod - def __classcall_private__(cls, *args, **kwds): + def __classcall_private__(cls, data=None, index_set=None, coxeter_type=None, + cartan_type=None, coxeter_type_check=True): r""" A Coxeter matrix can we created via a graph, a Coxeter type, or a matrix. @@ -145,16 +157,15 @@ def __classcall_private__(cls, *args, **kwds): Rational Field sage: CoxeterMatrix([[1,-1.5],[-1.5,1]])._matrix.base_ring() Real Field with 53 bits of precision - """ + if not data: + if coxeter_type: + data = CoxeterType(coxeter_type) + elif cartan_type: + data = CoxeterType(CartanType(cartan_type)) - # Special cases with 0 args - if not args: - if "coxeter_type" in kwds: # kwds has Coxeter type - args = ( CoxeterType(kwds["coxeter_type"]), ) - elif "cartan_type" in kwds: # kwds has Cartan type - args = ( CoxeterType(CartanType(kwds["cartan_type"])), ) - + # Special cases with no arguments passed + if not data: data = [] n = 0 index_set = tuple() @@ -165,49 +176,44 @@ def __classcall_private__(cls, *args, **kwds): return mat - elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling - return typecall(cls, args[0], args[1], args[2], args[3]) - elif isinstance(args[0], CoxeterMatrix): # Initiate from itself - return args[0] + if isinstance(data, CoxeterMatrix): # Initiate from itself + return data + + # Initiate from a graph: + # TODO: Check if a CoxeterDiagram once implemented + if isinstance(data, Graph): + return cls._from_graph(data, coxeter_type_check) + + # Get the Coxeter type + coxeter_type = None + from sage.combinat.root_system.cartan_type import CartanType_abstract + if isinstance(data, CartanType_abstract): + coxeter_type = data.coxeter_type() else: - # Get the type check - if kwds.get("coxeter_type_check", True): - coxeter_type_check = True - else: - coxeter_type_check = False + try: + coxeter_type = CoxeterType(data) + except (TypeError, ValueError, NotImplementedError): + pass - # Initiate from a graph: - if isinstance(args[0], Graph): - return cls._from_graph(args[0], coxeter_type_check) + # Initiate from a Coxeter type + if coxeter_type: + return cls._from_coxetertype(coxeter_type) - # Get the Coxeter type - coxeter_type = None - from sage.combinat.root_system.cartan_type import CartanType_abstract - if isinstance(args[0], CartanType_abstract): - coxeter_type = args[0].coxeter_type() - else: - try: - coxeter_type = CoxeterType(args[0]) - except (TypeError, ValueError, NotImplementedError): - pass + # TODO:: remove when oo is possible in matrices. + n = len(data[0]) + data = [x if x != infinity else -1 for r in data for x in r] + data = matrix(n, n, data) + # until here - # Initiate from a Coxeter type - if coxeter_type: - return cls._from_coxetertype(coxeter_type) - - # Get the index set - n = len(list(args[0])) - index_set = None - if kwds.get("index_set", None): - index_set = tuple(kwds["index_set"]) - if len(args) == 2: - index_set = tuple(args[1]) - elif len(args) > 2: - raise ValueError("too many arguments") - if index_set and len(set(index_set)) != n: - raise ValueError("the given index set is not valid") - - return cls._from_matrix(args[0], coxeter_type, index_set, coxeter_type_check) + # Get the index set + if index_set: + index_set = tuple(index_set) + else: + index_set = tuple(range(1,n+1)) + if len(set(index_set)) != n: + raise ValueError("the given index set is not valid") + + return cls._from_matrix(data, coxeter_type, index_set, coxeter_type_check) def __init__(self, parent, data, coxeter_type, index_set): """ @@ -218,7 +224,6 @@ def __init__(self, parent, data, coxeter_type, index_set): sage: C = CoxeterMatrix(['A', 2, 1]) sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) """ - self._matrix = Matrix_generic_dense(parent, data, False, True) self._matrix.set_immutable() @@ -246,11 +251,11 @@ def __init__(self, parent, data, coxeter_type, index_set): self._rank = self._matrix.nrows() self._dict = {(self._index_set[i], self._index_set[j]): self._matrix[i, j] - for i in range(self._rank) for j in range(self._rank)} + for i in range(self._rank) for j in range(self._rank)} - for key in self._index_set: - index_key = self._index_set.index(key) - self._dict[key] = {i: self._matrix[index_key, self._index_set.index(i)] for i in self._index_set} + for i,key in enumerate(self._index_set): + self._dict[key] = {key2: self._matrix[i,j] + for j,key2 in enumerate(self._index_set)} @classmethod def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): @@ -280,21 +285,12 @@ def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): [-3/2 1 -1] [ 5 -1 1] """ - # Check that the data is valid check_coxeter_matrix(data) M = matrix(data) n = M.ncols() - # TODO:: remove when oo is possible in matrices. - entries = [] - for r in data: - entries += list(r) - raw_data = map(lambda x: x if x != infinity else -1, entries) - M = matrix(n, n, raw_data) - # until here - base_ring = M.base_ring() if not coxeter_type: @@ -304,8 +300,6 @@ def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): coxeter_type = recognize_coxeter_type_from_matrix(M) else: coxeter_type = None - if not index_set: - index_set = tuple(range(1,n+1)) raw_data = M.list() @@ -351,7 +345,6 @@ def _from_graph(cls, graph, coxeter_type_check): [ 1.00000000000000 -1.50000000000000] [-1.50000000000000 1.00000000000000] """ - verts = sorted(graph.vertices()) index_set = tuple(verts) n = len(index_set) @@ -415,13 +408,13 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N INPUT: - - ``finite`` -- a boolean or ``None`` (default: ``None``) + - ``finite`` -- (default: ``None``) a boolean or ``None`` - - ``affine`` -- a boolean or ``None`` (default: ``None``) + - ``affine`` -- (default: ``None``) a boolean or ``None`` - - ``crystallographic`` -- a boolean or ``None`` (default: ``None``) + - ``crystallographic`` -- (default: ``None``) a boolean or ``None`` - - ``higher_rank`` -- a boolean or ``None`` (default: ``None``) + - ``higher_rank`` -- (default: ``None``) a boolean or ``None`` The sample contains all the exceptional finite and affine Coxeter types, as well as typical representatives of the @@ -436,28 +429,28 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples()] [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 5], Coxeter type of ['D', 4], - Coxeter type of ['D', 5], Coxeter type of ['E', 6], - Coxeter type of ['E', 7], Coxeter type of ['E', 8], - Coxeter type of ['F', 4], Coxeter type of ['H', 3], - Coxeter type of ['H', 4], Coxeter type of ['I', 10], - Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], - Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], - Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], - Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], - [ 1 -2] - [-2 1], - [ 1 -1 -1] - [-1 1 -1] - [-1 -1 1], - [1 2 3] - [2 1 7] - [3 7 1], - [ 1 -2 3 2] - [-2 1 2 3] - [ 3 2 1 -8] - [ 2 3 -8 1]] + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + Coxeter type of ['F', 4], Coxeter type of ['H', 3], + Coxeter type of ['H', 4], Coxeter type of ['I', 10], + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], + [ 1 -2] + [-2 1], + [ 1 -1 -1] + [-1 1 -1] + [-1 -1 1], + [1 2 3] + [2 1 7] + [3 7 1], + [ 1 -2 3 2] + [-2 1 2 3] + [ 3 2 1 -8] + [ 2 3 -8 1]] The finite, affine and crystallographic options allow respectively for restricting to (non) finite, (non) affine, @@ -465,47 +458,47 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples(finite=True)] [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 5], Coxeter type of ['D', 4], - Coxeter type of ['D', 5], Coxeter type of ['E', 6], - Coxeter type of ['E', 7], Coxeter type of ['E', 8], - Coxeter type of ['F', 4], Coxeter type of ['H', 3], - Coxeter type of ['H', 4], Coxeter type of ['I', 10]] + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + Coxeter type of ['F', 4], Coxeter type of ['H', 3], + Coxeter type of ['H', 4], Coxeter type of ['I', 10]] sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples(affine=True)] [Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], - Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], - Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], - Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples(crystallographic=True)] [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 5], Coxeter type of ['D', 4], - Coxeter type of ['D', 5], Coxeter type of ['E', 6], - Coxeter type of ['E', 7], Coxeter type of ['E', 8], - Coxeter type of ['F', 4], Coxeter type of ['A', 2, 1], - Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], - Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], - Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], - Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1]] + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + Coxeter type of ['F', 4], Coxeter type of ['A', 2, 1], + Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], + Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], + Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], + Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1]] sage: CoxeterMatrix.samples(crystallographic=False) [[1 3 2] - [3 1 5] - [2 5 1], [1 3 2 2] - [3 1 3 2] - [2 3 1 5] - [2 2 5 1], [ 1 10] - [10 1], [ 1 -1] - [-1 1], [ 1 -2] - [-2 1], [ 1 -1 -1] - [-1 1 -1] - [-1 -1 1], [1 2 3] - [2 1 7] - [3 7 1], [ 1 -2 3 2] - [-2 1 2 3] - [ 3 2 1 -8] - [ 2 3 -8 1]] + [3 1 5] + [2 5 1], [1 3 2 2] + [3 1 3 2] + [2 3 1 5] + [2 2 5 1], [ 1 10] + [10 1], [ 1 -1] + [-1 1], [ 1 -2] + [-2 1], [ 1 -1 -1] + [-1 1 -1] + [-1 -1 1], [1 2 3] + [2 1 7] + [3 7 1], [ 1 -2 3 2] + [-2 1 2 3] + [ 3 2 1 -8] + [ 2 3 -8 1]] .. TODO:: add some reducible Coxeter types (suggestions?) @@ -535,38 +528,38 @@ def _samples(self): sage: [CM.coxeter_type() for CM in CoxeterMatrix._samples()] [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 5], Coxeter type of ['D', 4], - Coxeter type of ['D', 5], Coxeter type of ['E', 6], - Coxeter type of ['E', 7], Coxeter type of ['E', 8], - Coxeter type of ['F', 4], Coxeter type of ['H', 3], - Coxeter type of ['H', 4], Coxeter type of ['I', 10], - Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], - Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], - Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], - Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], - [ 1 -2] - [-2 1], - [ 1 -1 -1] - [-1 1 -1] - [-1 -1 1], - [1 2 3] - [2 1 7] - [3 7 1], - [ 1 -2 3 2] - [-2 1 2 3] - [ 3 2 1 -8] - [ 2 3 -8 1]] + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + Coxeter type of ['F', 4], Coxeter type of ['H', 3], + Coxeter type of ['H', 4], Coxeter type of ['I', 10], + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], + [ 1 -2] + [-2 1], + [ 1 -1 -1] + [-1 1 -1] + [-1 -1 1], + [1 2 3] + [2 1 7] + [3 7 1], + [ 1 -2 3 2] + [-2 1 2 3] + [ 3 2 1 -8] + [ 2 3 -8 1]] """ - finite = [CoxeterMatrix(t) for t in [['A', 1], ['A', 5], ['B', 5], - ['D', 4], ['D', 5], ['E', 6], ['E', 7], - ['E', 8], ['F', 4], ['H', 3], ['H', 4], - ['I', 10]]] + finite = [CoxeterMatrix(t) for t in [['A', 1], ['A', 5], ['B', 5], + ['D', 4], ['D', 5], ['E', 6], ['E', 7], + ['E', 8], ['F', 4], ['H', 3], ['H', 4], + ['I', 10]]] - affine = [CoxeterMatrix(t) for t in ['A', 2, 1], ['B', 5, 1], - ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], - ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], - ['G', 2, 1], ['A', 1, 1]] + affine = [CoxeterMatrix(t) for t in [['A', 2, 1], ['B', 5, 1], + ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], + ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], + ['G', 2, 1], ['A', 1, 1]]] higher_matrices = [[[1, -2], [-2, 1]], [[1, -1, -1], [-1, 1, -1], [-1, -1, 1]], @@ -604,11 +597,12 @@ def relabel(self, relabelling): [2 3 1 2] [3 2 2 1] """ - - if isinstance(relabelling,type({})): - data = [[self[relabelling[i]][relabelling[j]] for j in self.index_set()] for i in self.index_set()] + if isinstance(relabelling, dict): + data = [[self[relabelling[i]][relabelling[j]] + for j in self.index_set()] for i in self.index_set()] else: - data = [[self[relabelling(i)][relabelling(j)] for j in self.index_set()] for i in self.index_set()] + data = [[self[relabelling(i)][relabelling(j)] + for j in self.index_set()] for i in self.index_set()] return CoxeterMatrix(data) @@ -623,8 +617,9 @@ def __reduce__(self): sage: M._index_set (1, 2, 3, 4) """ - return (CoxeterMatrix, (self._matrix.parent(), self._matrix.list(), - self._coxeter_type, self._index_set)) + if self._coxeter_type: + return (CoxeterMatrix, (self._coxeter_type,)) + return (CoxeterMatrix, (self._matrix, self._index_set)) def __repr__(self): """ @@ -640,7 +635,6 @@ def __repr__(self): [ 1 -3/2] [-3/2 1] """ - return self._matrix.__repr__() def __iter__(self): @@ -653,7 +647,6 @@ def __iter__(self): sage: CM.__iter__().next() (1, 8) """ - return self._matrix.__iter__() def __getitem__(self, key): @@ -664,7 +657,7 @@ def __getitem__(self, key): EXAMPLES:: sage: CM = CoxeterMatrix([[1,-2],[-2,1]]) - sage: CM = CoxeterMatrix([[1,-2],[-2,1]],['a','b']) + sage: CM = CoxeterMatrix([[1,-2],[-2,1]], ['a','b']) sage: CM['a'] {'a': 1, 'b': -2} sage: CM['b'] @@ -674,7 +667,6 @@ def __getitem__(self, key): sage: CM['a','a'] 1 """ - return self._dict[key] def __hash__(self): @@ -689,8 +681,7 @@ def __hash__(self): sage: CM = CoxeterMatrix([[1,-3],[-3,1]],['1','2']) sage: CM.__hash__() 4 - """ - + """ return self._matrix.__hash__() def __eq__(self, other): @@ -705,11 +696,10 @@ def __eq__(self, other): sage: CM = CoxeterMatrix([[1,-3],[-3,1]],['1','2']) sage: CM.__hash__() 4 - """ - + """ return self._matrix.__eq__(other._matrix) - def _matrix_(self, R = None): + def _matrix_(self, R=None): """ Return ``self`` as a matrix over the ring ``R``. @@ -723,7 +713,6 @@ def _matrix_(self, R = None): [ 1.00000000000000 -3.00000000000000] [-3.00000000000000 1.00000000000000] """ - if R is not None: return self._matrix.change_ring(R) else: @@ -815,7 +804,6 @@ def bilinear_form(self): [-1 1 -1] [-1 -1 1] """ - return CoxeterType.bilinear_form(self) @cached_method @@ -1310,9 +1298,7 @@ def check_coxeter_matrix(m): Traceback (most recent call last): ... ValueError: invalid Coxeter label 1 - """ - mat = matrix(m) if not mat.is_square(): raise ValueError("not a square matrix") @@ -1331,7 +1317,7 @@ def check_coxeter_matrix(m): def coxeter_matrix_as_function(t): """ - Return the Coxeter matrix, as a function + Return the Coxeter matrix, as a function. INPUT: @@ -1370,3 +1356,4 @@ def coxeter_matrix(t): from sage.misc.superseded import deprecation deprecation(17798, 'coxeter_matrix() is deprecated. Use CoxeterMatrix() instead') return CoxeterMatrix(t) + diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 28bfb2363a1..9711064dd56 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -75,18 +75,18 @@ def samples(self, finite=None, affine=None, crystallographic=None): sage: CoxeterType.samples() [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 1], Coxeter type of ['B', 5], - Coxeter type of ['C', 1], Coxeter type of ['C', 5], - Coxeter type of ['D', 4], Coxeter type of ['D', 5], - Coxeter type of ['E', 6], Coxeter type of ['E', 7], - Coxeter type of ['E', 8], Coxeter type of ['F', 4], - Coxeter type of ['H', 3], Coxeter type of ['H', 4], - Coxeter type of ['I', 10], Coxeter type of ['A', 2, 1], - Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], - Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], - Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], - Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1], - Coxeter type of ['A', 1, 1]] + Coxeter type of ['B', 1], Coxeter type of ['B', 5], + Coxeter type of ['C', 1], Coxeter type of ['C', 5], + Coxeter type of ['D', 4], Coxeter type of ['D', 5], + Coxeter type of ['E', 6], Coxeter type of ['E', 7], + Coxeter type of ['E', 8], Coxeter type of ['F', 4], + Coxeter type of ['H', 3], Coxeter type of ['H', 4], + Coxeter type of ['I', 10], Coxeter type of ['A', 2, 1], + Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], + Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], + Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], + Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1], + Coxeter type of ['A', 1, 1]] The finite, affine and crystallographic options allow respectively for restricting to (non) finite, (non) affine, @@ -94,46 +94,44 @@ def samples(self, finite=None, affine=None, crystallographic=None): sage: CoxeterType.samples(finite=True) [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 1], Coxeter type of ['B', 5], - Coxeter type of ['C', 1], Coxeter type of ['C', 5], - Coxeter type of ['D', 4], Coxeter type of ['D', 5], - Coxeter type of ['E', 6], Coxeter type of ['E', 7], - Coxeter type of ['E', 8], Coxeter type of ['F', 4], - Coxeter type of ['H', 3], Coxeter type of ['H', 4], - Coxeter type of ['I', 10]] + Coxeter type of ['B', 1], Coxeter type of ['B', 5], + Coxeter type of ['C', 1], Coxeter type of ['C', 5], + Coxeter type of ['D', 4], Coxeter type of ['D', 5], + Coxeter type of ['E', 6], Coxeter type of ['E', 7], + Coxeter type of ['E', 8], Coxeter type of ['F', 4], + Coxeter type of ['H', 3], Coxeter type of ['H', 4], + Coxeter type of ['I', 10]] sage: CoxeterType.samples(affine=True) [Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], - Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], - Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], - Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] sage: CoxeterType.samples(crystallographic=True) [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 1], Coxeter type of ['B', 5], - Coxeter type of ['C', 1], Coxeter type of ['C', 5], - Coxeter type of ['D', 4], Coxeter type of ['D', 5], - Coxeter type of ['E', 6], Coxeter type of ['E', 7], - Coxeter type of ['E', 8], Coxeter type of ['F', 4], - Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], - Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], - Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], - Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] + Coxeter type of ['B', 1], Coxeter type of ['B', 5], + Coxeter type of ['C', 1], Coxeter type of ['C', 5], + Coxeter type of ['D', 4], Coxeter type of ['D', 5], + Coxeter type of ['E', 6], Coxeter type of ['E', 7], + Coxeter type of ['E', 8], Coxeter type of ['F', 4], + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] sage: CoxeterType.samples(crystallographic=False) - [Coxeter type of ['H', 3], Coxeter type of ['H', 4], Coxeter type of ['I', 10]] + [Coxeter type of ['H', 3], + Coxeter type of ['H', 4], + Coxeter type of ['I', 10]] .. TODO:: add some reducible Coxeter types (suggestions?) TESTS:: sage: for ct in CoxeterType.samples(): TestSuite(ct).run() - sage: CartanType.samples(crystalographic=False) - doctest:...: DeprecationWarning: use the option 'crystallographic' instead of 'crystalographic' - See http://trac.sagemath.org/14673 for details. - [['I', 5], ['H', 3], ['H', 4]] """ result = self._samples() if crystallographic is not None: @@ -149,34 +147,36 @@ def _samples(self): """ Return a sample of all implemented Coxeter types. - .. NOTE:: This is intended to be used through :meth:`samples`. + .. NOTE:: + + This is intended to be used through :meth:`samples`. EXAMPLES:: sage: CoxeterType._samples() [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 1], Coxeter type of ['B', 5], - Coxeter type of ['C', 1], Coxeter type of ['C', 5], - Coxeter type of ['D', 4], Coxeter type of ['D', 5], - Coxeter type of ['E', 6], Coxeter type of ['E', 7], - Coxeter type of ['E', 8], Coxeter type of ['F', 4], - Coxeter type of ['H', 3], Coxeter type of ['H', 4], - Coxeter type of ['I', 10], Coxeter type of ['A', 2, 1], - Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], - Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], - Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], - Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1], - Coxeter type of ['A', 1, 1]] - """ - finite = [CoxeterType(t) for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5], + Coxeter type of ['B', 1], Coxeter type of ['B', 5], + Coxeter type of ['C', 1], Coxeter type of ['C', 5], + Coxeter type of ['D', 4], Coxeter type of ['D', 5], + Coxeter type of ['E', 6], Coxeter type of ['E', 7], + Coxeter type of ['E', 8], Coxeter type of ['F', 4], + Coxeter type of ['H', 3], Coxeter type of ['H', 4], + Coxeter type of ['I', 10], Coxeter type of ['A', 2, 1], + Coxeter type of ['B', 5, 1], Coxeter type of ['C', 5, 1], + Coxeter type of ['D', 5, 1], Coxeter type of ['E', 6, 1], + Coxeter type of ['E', 7, 1], Coxeter type of ['E', 8, 1], + Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1], + Coxeter type of ['A', 1, 1]] + """ + finite = [CoxeterType(t) for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 4], ['D', 5], ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['H', 3], ['H', 4], ['I', 10]]] - affine = [CoxeterType(t) for t in ['A', 2, 1], ['B', 5, 1], - ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], - ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], - ['G', 2, 1], ['A', 1, 1]] + affine = [CoxeterType(t) for t in ['A', 2, 1], ['B', 5, 1], + ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], + ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], + ['G', 2, 1], ['A', 1, 1]] return finite + affine @@ -554,3 +554,4 @@ def is_simply_laced(self): False """ return self._cartan_type.is_simply_laced() + From 20bd15dd22b857e41bbe50244112f6128c8082bb Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 19 Jun 2015 15:54:00 -0700 Subject: [PATCH 0263/1872] Added support for _repr_option('ascii_art'). --- src/sage/repl/display/fancy_repr.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index 5c1aa6977fa..d8ec2165fd1 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -317,11 +317,36 @@ def __call__(self, obj, p, cycle): sage: format_list = TallListRepr().format_string sage: format_list([1, 2, identity_matrix(2)]) '[\n [1 0]\n1, 2, [0 1]\n]' + + Check that :trac:`18743` is fixed:: + + sage: class Foo(object): + ....: def __repr__(self): + ....: return '''BBB AA RRR + ....: B B A A R R + ....: BBB AAAA RRR + ....: B B A A R R + ....: BBB A A R R''' + ....: def _repr_option(self, key): + ....: return key == 'ascii_art' + sage: F = Foo() + sage: [F, F] + [ + BBB AA RRR BBB AA RRR + B B A A R R B B A A R R + BBB AAAA RRR BBB AAAA RRR + B B A A R R B B A A R R + BBB A A R R, BBB A A R R + ] """ if not (isinstance(obj, (tuple, list)) and len(obj) > 0): return False ascii_art_repr = False for o in obj: + try: + ascii_art_repr = ascii_art_repr or o._repr_option('ascii_art') + except (AttributeError, TypeError): + pass try: ascii_art_repr = ascii_art_repr or o.parent()._repr_option('element_ascii_art') except (AttributeError, TypeError): From eab7426aa7b98be3c11cce1bba68e035c9bf4b0c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 19 Jun 2015 16:04:16 -0700 Subject: [PATCH 0264/1872] Fixing doctest from #18743. --- .../combinat/root_system/coxeter_matrix.py | 171 +++++++++++------- src/sage/combinat/root_system/coxeter_type.py | 4 +- 2 files changed, 107 insertions(+), 68 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 83f1a9ed5d2..d18a958c3b2 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -35,7 +35,6 @@ from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family - class CoxeterMatrix(CoxeterType): r""" A Coxeter matrix. @@ -428,29 +427,35 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N EXAMPLES:: sage: [CM.coxeter_type() for CM in CoxeterMatrix.samples()] - [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 5], Coxeter type of ['D', 4], - Coxeter type of ['D', 5], Coxeter type of ['E', 6], - Coxeter type of ['E', 7], Coxeter type of ['E', 8], - Coxeter type of ['F', 4], Coxeter type of ['H', 3], - Coxeter type of ['H', 4], Coxeter type of ['I', 10], - Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], - Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], - Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], - Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], - [ 1 -2] - [-2 1], - [ 1 -1 -1] - [-1 1 -1] - [-1 -1 1], - [1 2 3] - [2 1 7] - [3 7 1], - [ 1 -2 3 2] - [-2 1 2 3] - [ 3 2 1 -8] - [ 2 3 -8 1]] + [ + Coxeter type of ['A', 1], Coxeter type of ['A', 5], + + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + + Coxeter type of ['F', 4], Coxeter type of ['H', 3], + + Coxeter type of ['H', 4], Coxeter type of ['I', 10], + + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + + [ 1 -2] + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], [-2 1], + + [ 1 -2 3 2] + [ 1 -1 -1] [1 2 3] [-2 1 2 3] + [-1 1 -1] [2 1 7] [ 3 2 1 -8] + [-1 -1 1], [3 7 1], [ 2 3 -8 1] + ] The finite, affine and crystallographic options allow respectively for restricting to (non) finite, (non) affine, @@ -483,22 +488,17 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1]] sage: CoxeterMatrix.samples(crystallographic=False) - [[1 3 2] - [3 1 5] - [2 5 1], [1 3 2 2] - [3 1 3 2] - [2 3 1 5] - [2 2 5 1], [ 1 10] - [10 1], [ 1 -1] - [-1 1], [ 1 -2] - [-2 1], [ 1 -1 -1] - [-1 1 -1] - [-1 -1 1], [1 2 3] - [2 1 7] - [3 7 1], [ 1 -2 3 2] - [-2 1 2 3] - [ 3 2 1 -8] - [ 2 3 -8 1]] + [ + [1 3 2 2] + [1 3 2] [3 1 3 2] [ 1 -1 -1] [1 2 3] + [3 1 5] [2 3 1 5] [ 1 10] [ 1 -1] [ 1 -2] [-1 1 -1] [2 1 7] + [2 5 1], [2 2 5 1], [10 1], [-1 1], [-2 1], [-1 -1 1], [3 7 1], + + [ 1 -2 3 2] + [-2 1 2 3] + [ 3 2 1 -8] + [ 2 3 -8 1] + ] .. TODO:: add some reducible Coxeter types (suggestions?) @@ -527,29 +527,35 @@ def _samples(self): EXAMPLES:: sage: [CM.coxeter_type() for CM in CoxeterMatrix._samples()] - [Coxeter type of ['A', 1], Coxeter type of ['A', 5], - Coxeter type of ['B', 5], Coxeter type of ['D', 4], - Coxeter type of ['D', 5], Coxeter type of ['E', 6], - Coxeter type of ['E', 7], Coxeter type of ['E', 8], - Coxeter type of ['F', 4], Coxeter type of ['H', 3], - Coxeter type of ['H', 4], Coxeter type of ['I', 10], - Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], - Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], - Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], - Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], - [ 1 -2] - [-2 1], - [ 1 -1 -1] - [-1 1 -1] - [-1 -1 1], - [1 2 3] - [2 1 7] - [3 7 1], - [ 1 -2 3 2] - [-2 1 2 3] - [ 3 2 1 -8] - [ 2 3 -8 1]] + [ + Coxeter type of ['A', 1], Coxeter type of ['A', 5], + + Coxeter type of ['B', 5], Coxeter type of ['D', 4], + + Coxeter type of ['D', 5], Coxeter type of ['E', 6], + + Coxeter type of ['E', 7], Coxeter type of ['E', 8], + + Coxeter type of ['F', 4], Coxeter type of ['H', 3], + + Coxeter type of ['H', 4], Coxeter type of ['I', 10], + + Coxeter type of ['A', 2, 1], Coxeter type of ['B', 5, 1], + + Coxeter type of ['C', 5, 1], Coxeter type of ['D', 5, 1], + + Coxeter type of ['E', 6, 1], Coxeter type of ['E', 7, 1], + + Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], + + [ 1 -2] + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], [-2 1], + + [ 1 -2 3 2] + [ 1 -1 -1] [1 2 3] [-2 1 2 3] + [-1 1 -1] [2 1 7] [ 3 2 1 -8] + [-1 -1 1], [3 7 1], [ 2 3 -8 1] + ] """ finite = [CoxeterMatrix(t) for t in [['A', 1], ['A', 5], ['B', 5], ['D', 4], ['D', 5], ['E', 6], ['E', 7], @@ -621,22 +627,55 @@ def __reduce__(self): return (CoxeterMatrix, (self._coxeter_type,)) return (CoxeterMatrix, (self._matrix, self._index_set)) - def __repr__(self): + def _repr_(self): """ String representation of the Coxeter matrix. EXAMPLES:: - sage: CM = CoxeterMatrix(['A',3]);CM + sage: CM = CoxeterMatrix(['A',3]); CM [1 3 2] [3 1 3] [2 3 1] - sage: CM = CoxeterMatrix([[1,-3/2],[-3/2,1]]);CM + sage: CM = CoxeterMatrix([[1,-3/2],[-3/2,1]]); CM [ 1 -3/2] [-3/2 1] """ return self._matrix.__repr__() + def _repr_option(self, key): + """ + Metadata about the :meth:`_repr_` output. + + See :meth:`sage.structure.parent._repr_option` for details. + + EXAMPLES:: + + sage: CM = CoxeterMatrix(['A',3]) + sage: CM._repr_option('ascii_art') + True + """ + if key == 'ascii_art' or key == 'element_ascii_art': + return self._matrix.nrows() > 1 + return super(CoxeterMatrix, self)._repr_option(key) + + def _latex_(self): + r""" + Latex representation of the Coxeter matrix. + + EXAMPLES:: + + sage: CM = CoxeterMatrix(['A',3]) + sage: latex(CM) + \left(\begin{array}{rrr} + 1 & 3 & 2 \\ + 3 & 1 & 3 \\ + 2 & 3 & 1 + \end{array}\right) + """ + return self._matrix._latex_() + + def __iter__(self): """ Return an iterator for the rows of the Coxeter matrix. diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 9711064dd56..11edd8622aa 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -28,7 +28,7 @@ from sage.structure.sage_object import SageObject -class CoxeterType(object): +class CoxeterType(SageObject): """ Abstract class for Coxeter types. """ @@ -391,7 +391,7 @@ def bilinear_form(self, R=None): return bilinear -class CoxeterTypeFromCartanType(SageObject, CoxeterType, UniqueRepresentation): +class CoxeterTypeFromCartanType(CoxeterType, UniqueRepresentation): """ A Coxeter type associated to a Cartan type. """ From b3ce76575466e02722797adf0fdb12bdb7171f8d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sun, 21 Jun 2015 02:50:11 +0200 Subject: [PATCH 0265/1872] firsts tests for multiplication and addition are working! --- src/sage/rings/asymptotic_ring.py | 254 ++++++++++++++++++++++++++---- 1 file changed, 224 insertions(+), 30 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 59f9dcdee19..6476af9ad5e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -1,6 +1,16 @@ r""" Asymptotic Ring +This module implements the central classes for computing with +asymptotic expressions. It provides the following two classes: + +- :class:`AsymptoticExpression` -- this class essentially represents + a sum of asymptotic terms (see + :mod:`Asymptotic Terms <~sage.monoids.asymptotic_term_monoid>`). + +- :class:`AsymptoticRing` -- parent structure for + :class:`AsymptoticExpression`. + AUTHORS: - Benjamin Hackl (2015-06): initial version @@ -28,6 +38,9 @@ def _absorption_(left, right): except ArithmeticError: return right.absorb(left) +def _can_absorb_(left, right): + return left.can_absorb(right) + class AsymptoticExpression(sage.rings.ring_element.RingElement): r""" @@ -37,6 +50,10 @@ def __init__(self, parent, poset): r""" ... """ + for shell in poset.shells_topological(reverse=True): + from sage.monoids.asymptotic_term_monoid import OTerm + if isinstance(shell.element, OTerm) and shell.element.growth in poset: + poset.merge(shell.key) self._poset_ = poset super(AsymptoticExpression, self).__init__(parent=parent) @@ -53,39 +70,33 @@ def _repr_(self, reverse=False): A representation string for this asymptotic expression. """ s = ' + '.join(repr(elem) for elem in - self._poset_.shells_topological(include_special=False, + self.poset.elements_topological(include_special=False, reverse=reverse)) - return s + if s == '': + return '0' + else: + return s - # todo: implement _le_? - def _update_poset_(self): + def _add_(self, other): r""" - Helper method. This is called by ring operations like - :meth:`_add_` and :meth:`_mul_`. This triggers the absorption - of elements that are already in the poset. + Add ``other`` to this asymptotic expression. INPUT: - Nothing. + - ``other`` -- an :class:`AsymptoticExpression`. OUTPUT: - Nothing. - - ... + An :class:`AsymptoticExpression`. """ - for shell in self.poset.shells_topological(reverse=True): - from sage.monoids.asymptotic_term_monoid import OTerm - if isinstance(shell.element, OTerm) and shell.element in self.poset: - while self.poset.null not in shell.predecessors(): - for elem in shell.predecessors(): - self.poset.remove(elem) + pst = self.poset.copy().union(other.poset) + return self.parent()(poset=pst) - def _add_(self, other): + def _sub_(self, other): r""" - Add ``other`` to this asymptotic expression. + Subtract ``other`` from this asymptotic expression. INPUT: @@ -95,24 +106,23 @@ def _add_(self, other): An :class:`AsymptoticExpression`. """ - poset = self.poset.union(other.poset) - self._update_poset_() - return self.parent()(poset=poset) - + return self + other._mul_term_( + self.parent().create_term('exact', growth=1, coefficient=-1)) - def _sub_(self, other): + def _mul_term_(self, other): r""" - Subtract ``other`` from this asymptotic expression. + Helper method: multiply this asymptotic expression with the + asymptotic term ``other``. INPUT: - - ``other`` -- an :class:`AsymptoticExpression`. + - ``other`` -- an asymptotic term. OUTPUT: An :class:`AsymptoticExpression`. """ - pass + return self.parent()([other * elem for elem in self.poset.elements()]) def _mul_(self, other): @@ -126,10 +136,194 @@ def _mul_(self, other): OUTPUT: An :class:`AsymptoticExpression`. + + .. TODO:: + + The current implementation is the simple school book + multiplication. More efficient variants like Karatsuba + multiplication, or methods that exploit the structure + of the underlying poset shall be implemented at a later + point. + """ + return self.parent()(sum(self._mul_term_(term_other) for + term_other in other.poset.elements())) + + + +class AsymptoticRing(sage.rings.ring.Ring, + sage.structure.unique_representation.UniqueRepresentation): + r""" + ... + """ + # enable the category framework for elements + Element = AsymptoticExpression + + def __init__(self, growth_group=None, coefficient_ring=None, category=None): + r""" + ... + """ + if growth_group is None: + raise ValueError('Growth group not specified. Cannot continue.') + elif coefficient_ring is None: + raise ValueError('Coefficient ring not specified. Cannot continue.') + elif not hasattr(coefficient_ring, 'is_ring') or\ + not coefficient_ring.is_ring(): + raise ValueError('%s has to be a ring.' % (coefficient_ring,)) + + from sage.categories.rings import Rings + if category is None: + category = Rings() + else: + if not isinstance(category, tuple): + category = (category,) + if not any(cat.is_subcategory(Rings()) for cat in category): + raise ValueError('%s is not a subcategory of %s' % (category, + Rings())) + + self._coefficient_ring_ = coefficient_ring + self._growth_group_ = growth_group + super(AsymptoticRing, self).__init__(base=coefficient_ring, + category=category) + + @property + def growth_group(self): + r""" + The growth group of this asymptotic ring. + + EXAMPLES:: + + sage: from sage.rings.asymptotic_ring import AsymptoticRing + sage: import sage.groups.asymptotic_growth_group as agg + sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) + sage: AR.growth_group + Monomial Growth Group in x over Integer Ring + """ + return self._growth_group_ + + + @property + def coefficient_ring(self): + r""" + The coefficient ring of this asymptotic ring. + + EXAMPLES:: + + sage: from sage.rings.asymptotic_ring import AsymptoticRing + sage: import sage.groups.asymptotic_growth_group as agg + sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) + sage: AR.coefficient_ring + Integer Ring + """ + return self._coefficient_ring_ + + + def _element_constructor_(self, data, poset=None): + r""" + Converts a given object to this asymptotic ring. + + INPUT: + + - ``data`` -- an object representing the element to be + initialized. + + - ``poset`` -- (default: None) if given, then this is + directly passed to the element constructor (i.e., no + conversion is performed). + + OUTPUT: + + An element of this growth group. + + TESTS:: + + sage: from sage.rings.asymptotic_ring import AsymptoticRing + sage: import sage.groups.asymptotic_growth_group as agg + sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) + sage: AR.create_term('exact', x^3, 3) + 3 * x^3 + sage: AR.create_term('exact', x^3, 3) + AR.create_term('exact', x, 1) + 1 * x + 3 * x^3 + sage: AR.create_term('exact', x^3, 3) * AR.create_term('exact', x, 5) + 15 * x^4 + sage: AR.create_term('exact', x^3, 3) + AR.create_term('O', x^5) + O(x^5) """ - pass + if poset is None: + if type(data) == self.element_class and data.parent() == self: + return data + if data in self.coefficient_ring: + if data != 0: + return self.create_term('exact', 1, data) + else: + from sage.data_structures.mutable_poset import MutablePoset + poset = MutablePoset(key=lambda elem: elem.growth, + can_merge=_can_absorb_, + merge=_absorption_) + return self.element_class(self, poset) + + from sage.monoids.asymptotic_term_monoid import OTerm, ExactTerm + from sage.data_structures.mutable_poset import MutablePoset + if isinstance(data, (OTerm, ExactTerm)): + data = (data,) + + try: + data_iter = iter(data) + if all(isinstance(elem, (OTerm, ExactTerm)) for elem in data_iter): + poset = MutablePoset(key=lambda elem: elem.growth, + can_merge=_can_absorb_, + merge=_absorption_) + poset = poset.union(data) + except: + raise TypeError('Input is ambiguous: cannot convert ' + '%s to an asymptotic expression' % (data,)) + + return self.element_class(self, poset) + + + def _coerce_map_from_(self, R): + r""" + ... + """ + if R is self.coefficient_ring: + return True + + def _repr_(self): + r""" + A representation string for this asymptotic ring. + INPUT: -class AsymptoticRing(sage.rings.ring.Ring): - pass \ No newline at end of file + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: from sage.rings.asymptotic_ring import AsymptoticRing + sage: import sage.groups.asymptotic_growth_group as agg + sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) + sage: repr(AR) # indirect doctest + 'Asymptotic Ring over Monomial Growth Group in x over Integer Ring with coefficients from Integer Ring' + """ + return 'Asymptotic Ring over %s with coefficients ' \ + 'from %s' % (self.growth_group, self.coefficient_ring) + + + def create_term(self, type, growth=None, coefficient=None): + r""" + ... + """ + from sage.monoids.asymptotic_term_monoid import TermMonoid + if type == 'O': + TM = TermMonoid(type, self.growth_group) + return self(TM(growth)) + else: + TM = TermMonoid(type, self.growth_group, self.coefficient_ring) + return self(TM(growth, coefficient)) From 52d11e500036f996dd4e2440eca89cbbb7e214f2 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Mon, 22 Jun 2015 14:39:55 -0500 Subject: [PATCH 0266/1872] Added morphism to SymmetricGroupAlgebra to DiagramAlgebra and registered it as coercion --- src/sage/combinat/diagram_algebras.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 93d55bcde01..17f2c81fa68 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -801,6 +801,9 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): self._base_diagrams = diagrams if category is None: category = FiniteDimensionalAlgebrasWithBasis(base_ring) + KSS = SymmetricGroupAlgebra(base_ring, k) + to_DA = KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)),codomain=self) + to_DA.register_as_coercion() CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) @@ -850,6 +853,12 @@ def __getitem__(self, i): return self.basis()[i] raise ValueError("{0} is not an index of a basis element".format(i)) + def _perm_to_Blst(self, w): + ## 'perm' is a permutation in one-line notation + ## turns w into an expression suitable for the element constructor. + u = sorted(w) + return [[u[i],-w[i]] for i in range(len(w))] + def order(self): r""" Return the order of ``self``. From 169e666878335aebe8fec04618851d7f76d71124 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Mon, 22 Jun 2015 18:36:15 -0500 Subject: [PATCH 0267/1872] added missing import statement to diagram algebras file --- src/sage/combinat/diagram_algebras.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 17f2c81fa68..8c3e0f1ccc5 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -25,10 +25,11 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.list_clone import ClonableArray -from sage.combinat.set_partition import SetPartitions, SetPartition +from sage.combinat.combinat import (bell_number, catalan_number) from sage.combinat.partition import Partitions from sage.combinat.permutation import Permutation -from sage.combinat.combinat import (bell_number, catalan_number) +from sage.combinat.set_partition import SetPartitions, SetPartition +from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.sets.set import Set from sage.graphs.graph import Graph from sage.misc.cachefunc import cached_method From 28ee71f199a7162aa57408864e451f8a3477fcbf Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Mon, 22 Jun 2015 19:23:08 -0500 Subject: [PATCH 0268/1872] fixed the order of commands and import statements --- src/sage/combinat/diagram_algebras.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 8c3e0f1ccc5..72ad8f2c17d 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -35,6 +35,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten from sage.rings.all import ZZ +from sage.rings.rational_field import RationalField import math import operator @@ -802,12 +803,12 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): self._base_diagrams = diagrams if category is None: category = FiniteDimensionalAlgebrasWithBasis(base_ring) - KSS = SymmetricGroupAlgebra(base_ring, k) - to_DA = KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)),codomain=self) - to_DA.register_as_coercion() CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) + KSS = SymmetricGroupAlgebra(RationalField(), k) # QQ probably should not be hardcoded here. + KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)), codomain=self).register_as_coercion() + def _element_constructor_(self, set_partition): r""" Construct an element of ``self``. From 69bd5dbdd4cb11875dc5ab79cd3a8735633f3226 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Mon, 22 Jun 2015 19:43:56 -0500 Subject: [PATCH 0269/1872] changed the ring of the symmetric group algebra created for the morphism from sga to diagram algebra to be the base ring of the diagram algebra. However, this causes a type error with the MRO --- src/sage/combinat/diagram_algebras.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 72ad8f2c17d..6c87efcb348 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -806,7 +806,8 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) - KSS = SymmetricGroupAlgebra(RationalField(), k) # QQ probably should not be hardcoded here. + + KSS = SymmetricGroupAlgebra(self.base_ring(), k) # QQ probably should not be hardcoded here. KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)), codomain=self).register_as_coercion() def _element_constructor_(self, set_partition): From c4464075dded42e4b7ca70ba4ddda7d8a7f40fd3 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 25 Jun 2015 14:47:42 +0200 Subject: [PATCH 0270/1872] added AsymptoticRing to the global namespace --- src/sage/rings/all.py | 3 +++ src/sage/rings/asymptotic_ring.py | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 28f56410883..a7a19b490f6 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -182,3 +182,6 @@ Hirzebruch_Jung_continued_fraction_list) # and deprecated continued fractions from sage.rings.contfrac import (CFF, ContinuedFractionField) + +# asymptotic ring +from asymptotic_ring import AsymptoticRing \ No newline at end of file diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 6476af9ad5e..9bff39b504f 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -192,7 +192,6 @@ def growth_group(self): EXAMPLES:: - sage: from sage.rings.asymptotic_ring import AsymptoticRing sage: import sage.groups.asymptotic_growth_group as agg sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) @@ -209,7 +208,6 @@ def coefficient_ring(self): EXAMPLES:: - sage: from sage.rings.asymptotic_ring import AsymptoticRing sage: import sage.groups.asymptotic_growth_group as agg sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) @@ -238,7 +236,6 @@ def _element_constructor_(self, data, poset=None): TESTS:: - sage: from sage.rings.asymptotic_ring import AsymptoticRing sage: import sage.groups.asymptotic_growth_group as agg sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) @@ -305,7 +302,6 @@ def _repr_(self): EXAMPLES:: - sage: from sage.rings.asymptotic_ring import AsymptoticRing sage: import sage.groups.asymptotic_growth_group as agg sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) From 29a97a7919ce9847c1957111f08114b8947d52ec Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 25 Jun 2015 11:13:22 -0700 Subject: [PATCH 0271/1872] Minor fixes and reorganizing the manifolds categories. --- src/sage/categories/category_with_axiom.py | 4 +- src/sage/categories/cw_complexes.py | 4 + src/sage/categories/manifolds.py | 296 ++++++++++++--------- 3 files changed, 183 insertions(+), 121 deletions(-) diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 0893af7af75..f62e83c8b90 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1673,8 +1673,8 @@ class ``Sets.Finite``), or in a separate file (typically in a class all_axioms = AxiomContainer() all_axioms += ("Flying", "Blue", - "Compact", "AlmostComplex", "Complex", - "Differentiable", "Smooth", "Analytic", + "Compact", "Complex", + "Differentiable", "Smooth", "Analytic", "AlmostComplex", "Real", "FinitelyGeneratedAsMagma", "Facade", "Finite", "Infinite", "FiniteDimensional", "Connected", "WithBasis", diff --git a/src/sage/categories/cw_complexes.py b/src/sage/categories/cw_complexes.py index 0193f7fe136..f7f4641d5cc 100644 --- a/src/sage/categories/cw_complexes.py +++ b/src/sage/categories/cw_complexes.py @@ -24,6 +24,10 @@ class CWComplexes(Category_singleton): - :wikipedia:`CW_complex` + .. NOTE:: + + The notion of "finite" is that the number of cells is finite. + EXAMPLES:: sage: from sage.categories.cw_complexes import CWComplexes diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index ec96693156d..83e7a4ec363 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -123,85 +123,28 @@ def FiniteDimensional(self): return self._with_axiom('FiniteDimensional') @cached_method - def Differentiable(self): + def Real(self): """ - Return the subcategory of the differentiable objects of ``self``. + Return the subcategory of manifolds over `\RR` of ``self``. EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Differentiable() - Category of differentiable manifolds + sage: Manifolds().Real() + Category of real manifolds TESTS:: - sage: TestSuite(Manifolds().Differentiable()).run() - sage: Manifolds().Differentiable.__module__ + sage: TestSuite(Manifolds().Real()).run() + sage: Manifolds().Real.__module__ 'sage.categories.manifolds' """ - return self._with_axiom('Differentiable') - - @cached_method - def Smooth(self): - """ - Return the subcategory of the smooth objects of ``self``. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Smooth() - Category of smooth manifolds - - TESTS:: - - sage: TestSuite(Manifolds().Smooth()).run() - sage: Manifolds().Smooth.__module__ - 'sage.categories.manifolds' - """ - return self._with_axiom('Smooth') - - @cached_method - def Analytic(self): - """ - Return the subcategory of the analytic objects of ``self``. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Analytic() - Category of analytic manifolds - - TESTS:: - - sage: TestSuite(Manifolds().Analytic()).run() - sage: Manifolds().Smooth.__module__ - 'sage.categories.manifolds' - """ - return self._with_axiom('Analytic') - - @cached_method - def AlmostComplex(self): - """ - Return the subcategory of the almost complex objects of ``self``. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().AlmostComplex() - Category of almost complex manifolds - - TESTS:: - - sage: TestSuite(Manifolds().AlmostComplex()).run() - sage: Manifolds().Smooth.__module__ - 'sage.categories.manifolds' - """ - return self._with_axiom('AlmostComplex') + return self._with_axiom('Real') @cached_method def Complex(self): """ - Return the subcategory of the complex objects of ``self``. + Return the subcategory of manifolds over `\CC` of ``self``. EXAMPLES:: @@ -212,7 +155,7 @@ def Complex(self): TESTS:: sage: TestSuite(Manifolds().Complex()).run() - sage: Manifolds().Smooth.__module__ + sage: Manifolds().Complex.__module__ 'sage.categories.manifolds' """ return self._with_axiom('Complex') @@ -227,79 +170,178 @@ class Connected(CategoryWithAxiom): The category of connected manifolds. """ - class Differentiable(CategoryWithAxiom): + class Real(CategoryWithAxiom): """ - The category of differentiable manifolds over `\RR`. - - A `d`-dimensional differentiable manifold is a manifold whose - underlying vector space is `\RR^d` and differentiable atlas. + The category of manifolds over `\RR`. """ + class SubcategoryMethods: + @cached_method + def Complex(self): + r""" + Raise an error as a manifold over `\RR` is not a manifold + over `\CC`. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Real().Complex() + Traceback (most recent call last): + ... + TypeError: a real manifold is not a complex manifold + """ + raise TypeError("a real manifold is not a complex manifold") + + @cached_method + def Differentiable(self): + """ + Return the subcategory of the differentiable objects + of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Real().Differentiable() + Category of differentiable real manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Real().Differentiable()).run() + sage: Manifolds().Real().Differentiable.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Differentiable') + + @cached_method + def Smooth(self): + """ + Return the subcategory of the smooth objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Real().Smooth() + Category of smooth real manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Real().Smooth()).run() + sage: Manifolds().Real().Smooth.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Smooth') + + @cached_method + def Analytic(self): + """ + Return the subcategory of the analytic objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Real().Analytic() + Category of analytic real manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Real().Analytic()).run() + sage: Manifolds().Real().Analytic.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Analytic') + + @cached_method + def AlmostComplex(self): + """ + Return the subcategory of the almost complex objects + of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Real().AlmostComplex() + Category of almost complex real manifolds + + TESTS:: + + sage: TestSuite(Manifolds().Real().AlmostComplex()).run() + sage: Manifolds().Real().AlmostComplex.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('AlmostComplex') + + class Differentiable(CategoryWithAxiom): + """ + The category of differentiable manifolds over `\RR`. - class Smooth(CategoryWithAxiom): - """ - The category of smooth manifolds over `\RR`. + A `d`-dimensional differentiable manifold is a manifold whose + underlying vector space is `\RR^d` and differentiable atlas. + """ - A `d`-dimensional differentiable manifold is a manifold whose - underlying vector space is `\RR^d` and smooth atlas. - """ - def extra_super_categories(self): + class Smooth(CategoryWithAxiom): """ - Return the extra super categories of ``self``. + The category of smooth manifolds over `\RR`. - A smooth manifold is differentiable. + A `d`-dimensional differentiable manifold is a manifold whose + underlying vector space is `\RR^d` and smooth atlas. + """ + def extra_super_categories(self): + """ + Return the extra super categories of ``self``. - EXAMPLES:: + A smooth manifold is differentiable. - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Smooth().super_categories() # indirect doctest - [Category of differentiable manifolds] - """ - return [Manifolds().Differentiable()] + EXAMPLES:: - class Analytic(CategoryWithAxiom): - r""" - The category of complex manifolds. + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Real().Smooth().super_categories() # indirect doctest + [Category of differentiable real manifolds] + """ + return [Manifolds().Real().Differentiable()] - A `d`-dimensional analytic manifold is a manifold whose underlying - vector space is `\RR^d` and an analytic atlas. - """ - def extra_super_categories(self): + class Analytic(CategoryWithAxiom): + r""" + The category of complex manifolds. + + A `d`-dimensional analytic manifold is a manifold whose underlying + vector space is `\RR^d` and an analytic atlas. """ - Return the extra super categories of ``self``. + def extra_super_categories(self): + """ + Return the extra super categories of ``self``. - An analytic manifold is smooth. + An analytic manifold is smooth. - EXAMPLES:: + EXAMPLES:: - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Analytic().super_categories() # indirect doctest - [Category of smooth manifolds] - """ - return [Manifolds().Smooth()] + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Real().Analytic().super_categories() # indirect doctest + [Category of smooth real manifolds] + """ + return [Manifolds().Real().Smooth()] - class AlmostComplex(CategoryWithAxiom): - r""" - The category of almost complex manifolds. + class AlmostComplex(CategoryWithAxiom): + r""" + The category of almost complex manifolds. - A `d`-dimensional almost complex manifold `M` is a manifold - whose underlying vector space is `\RR^d` with a smooth tensor - field `J` of rank `(1, 1)` such that `J^2 = -1` when regarded as a - vector bundle isomorphism `J : TM \to TM` on the tangent bundle. - The tensor field `J` is called the almost complex structure of `M`. - """ - def extra_super_categories(self): + A `d`-dimensional almost complex manifold `M` is a manifold + whose underlying vector space is `\RR^d` with a smooth tensor + field `J` of rank `(1, 1)` such that `J^2 = -1` when regarded as a + vector bundle isomorphism `J : TM \to TM` on the tangent bundle. + The tensor field `J` is called the almost complex structure of `M`. """ - Return the extra super categories of ``self``. + def extra_super_categories(self): + """ + Return the extra super categories of ``self``. - An analytic manifold is smooth. + An analytic manifold is smooth. - EXAMPLES:: + EXAMPLES:: - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Analytic().super_categories() # indirect doctest - [Category of smooth manifolds] - """ - return [Manifolds().Smooth()] + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Real().Analytic().super_categories() # indirect doctest + [Category of smooth real manifolds] + """ + return [Manifolds().Real().Smooth()] class Complex(CategoryWithAxiom): r""" @@ -308,4 +350,20 @@ class Complex(CategoryWithAxiom): A `d`-dimensional complex manifold is a manifold whose underlying vector space is `\CC^d` and a holomorphic atlas. """ + class SubcategoryMethods: + @cached_method + def Real(self): + r""" + Raise an error as a manifold over `\RR` is not a manifold + over `\CC`. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds().Complex().Real() + Traceback (most recent call last): + ... + TypeError: a complex manifold is not a real manifold + """ + raise TypeError("a complex manifold is not a real manifold") From e6076d2a41dbe5e3294c03a95e3e763e60d554ff Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 25 Jun 2015 11:31:30 -0700 Subject: [PATCH 0272/1872] Fixing failing doctests and last tweaks. --- src/sage/categories/category_cy_helper.pyx | 7 +++---- src/sage/categories/homset.py | 14 +++++--------- src/sage/categories/lie_groups.py | 4 ++-- src/sage/categories/simplicial_complexes.py | 4 +++- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/sage/categories/category_cy_helper.pyx b/src/sage/categories/category_cy_helper.pyx index 2156bf3169b..213034df6fc 100644 --- a/src/sage/categories/category_cy_helper.pyx +++ b/src/sage/categories/category_cy_helper.pyx @@ -135,17 +135,16 @@ cpdef tuple join_as_tuple(tuple categories, tuple axioms, tuple ignore_axioms): (Category of algebras over Integer Ring, Category of finite monoids, Category of coalgebras over Rational Field, - Category of simplicial complexes) + Category of finite simplicial complexes) sage: join_as_tuple(T,('WithBasis',),()) (Category of algebras with basis over Integer Ring, Category of finite monoids, Category of coalgebras with basis over Rational Field, - Category of simplicial complexes) + Category of finite simplicial complexes) sage: join_as_tuple(T,(),((Monoids(),'Finite'),)) (Category of algebras over Integer Ring, Category of coalgebras over Rational Field, - Category of finite sets, - Category of simplicial complexes) + Category of finite simplicial complexes) """ cdef set axiomsS = set(axioms) for category in categories: diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 8faeb207bc5..d9144cdf6b8 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -283,17 +283,13 @@ def Hom(X, Y, category=None, check=True): sage: S = SimplicialComplex([[1,2], [1,4]]); S.rename("S") sage: Hom(S, S, SimplicialComplexes()) - Set of Morphisms from S to S in Category of simplicial complexes + Set of Morphisms from S to S in Category of finite simplicial complexes - sage: H = Hom(Set(), S, Sets()) - Traceback (most recent call last): - ... - ValueError: S is not in Category of sets + sage: Hom(Set(), S, Sets()) + Set of Morphisms from {} to S in Category of sets - sage: H = Hom(S, Set(), Sets()) - Traceback (most recent call last): - ... - ValueError: S is not in Category of sets + sage: Hom(S, Set(), Sets()) + Set of Morphisms from S to {} in Category of sets sage: H = Hom(S, S, ChainComplexes(QQ)) Traceback (most recent call last): diff --git a/src/sage/categories/lie_groups.py b/src/sage/categories/lie_groups.py index eb9e31abb2a..cbb6571977b 100644 --- a/src/sage/categories/lie_groups.py +++ b/src/sage/categories/lie_groups.py @@ -37,9 +37,9 @@ def super_categories(self): sage: from sage.categories.lie_groups import LieGroups sage: LieGroups().super_categories() - [Category of topological groups, Category of smooth manifolds] + [Category of topological groups, Category of smooth real manifolds] """ - return [Groups().Topological(), Manifolds().Smooth()] + return [Groups().Topological(), Manifolds().Real().Smooth()] def additional_structure(self): r""" diff --git a/src/sage/categories/simplicial_complexes.py b/src/sage/categories/simplicial_complexes.py index d5ca22561aa..aa19a8a277b 100644 --- a/src/sage/categories/simplicial_complexes.py +++ b/src/sage/categories/simplicial_complexes.py @@ -28,7 +28,9 @@ class SimplicialComplexes(Category_singleton): .. TODO:: Implement the category of simplicial complexes considered - as :class:`CW complexes `. + as :class:`CW complexes ` + and rename this to the category of ``AbstractSimplicialComplexes`` + with appropriate functors. EXAMPLES:: From dbe528d524115679153344eabda83dba26a7961e Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 26 Jun 2015 16:25:24 +0200 Subject: [PATCH 0273/1872] implemented functionality of the big-oh constructor for asymptotic expressions --- src/sage/rings/asymptotic_ring.py | 31 +++++++++++++++++++++++++++++++ src/sage/rings/big_oh.py | 4 +++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 9bff39b504f..3f8a5a1c60e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -149,6 +149,37 @@ def _mul_(self, other): term_other in other.poset.elements())) + def O(self): + r""" + Convert all terms in this asymptotic expression to `O`-terms. + + INPUT: + + Nothing. + + OUTPUT: + + An asymptotic expression. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: AR = AsymptoticRing(MG, ZZ) + sage: x = AR.create_term('exact', x) + sage: expr = 42 * x^42 + x^10 + O(x^2); expr + 42 * x^42 + x^10 + O(x^2) + sage: expr.O() + x^42 + """ + if self.poset.null in self.poset.oo.predecessors(): + raise ValueError('O(%s) not defined' % self) + else: + return sum(self.parent().create_term('O', shell.element) for shell + in self.poset.oo.predecessors()) + + + class AsymptoticRing(sage.rings.ring.Ring, sage.structure.unique_representation.UniqueRepresentation): diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 7f0d49f541e..ec372306496 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -12,7 +12,7 @@ from sage.rings.polynomial.polynomial_element import Polynomial import multi_power_series_ring_element -def O(*x): +def O(*x, **kwds): """ Big O constructor for various types. @@ -99,5 +99,7 @@ def O(*x): elif isinstance(x, padic_generic_element.pAdicGenericElement): return x.parent()(0, absprec = x.valuation()) + elif len(x) == 1 and hasattr(x, 'O'): + return x[0].O(**kwds) raise ArithmeticError("O(x) not defined") From 7cc253c4ce6b41b0c7bd49b34ce253974bebf029 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 26 Jun 2015 17:03:00 +0200 Subject: [PATCH 0274/1872] moved helper methods to monoids/asymptotic_term_monoid.py --- src/sage/rings/asymptotic_ring.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 3f8a5a1c60e..7f9e286c420 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -29,19 +29,6 @@ import sage -def _absorption_(left, right): - r""" - Helper method for the mutable poset associated to our - """ - try: - return left.absorb(right) - except ArithmeticError: - return right.absorb(left) - -def _can_absorb_(left, right): - return left.can_absorb(right) - - class AsymptoticExpression(sage.rings.ring_element.RingElement): r""" ... @@ -287,6 +274,8 @@ def _element_constructor_(self, data, poset=None): return self.create_term('exact', 1, data) else: from sage.data_structures.mutable_poset import MutablePoset + from sage.monoids.asymptotic_term_monoid import \ + _can_absorb_, _absorption_ poset = MutablePoset(key=lambda elem: elem.growth, can_merge=_can_absorb_, merge=_absorption_) @@ -294,6 +283,8 @@ def _element_constructor_(self, data, poset=None): from sage.monoids.asymptotic_term_monoid import OTerm, ExactTerm from sage.data_structures.mutable_poset import MutablePoset + from sage.monoids.asymptotic_term_monoid import _can_absorb_, \ + _absorption_ if isinstance(data, (OTerm, ExactTerm)): data = (data,) From 14028c4f8e98c2ee3f0517842d4d94488c7f9c7e Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 26 Jun 2015 17:04:42 +0200 Subject: [PATCH 0275/1872] fixed failing doctests (new representation of exact terms) --- src/sage/rings/asymptotic_ring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 7f9e286c420..87d41ab5e90 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -258,11 +258,11 @@ def _element_constructor_(self, data, poset=None): sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: AR.create_term('exact', x^3, 3) - 3 * x^3 + 3*x^3 sage: AR.create_term('exact', x^3, 3) + AR.create_term('exact', x, 1) - 1 * x + 3 * x^3 + 1*x + 3*x^3 sage: AR.create_term('exact', x^3, 3) * AR.create_term('exact', x, 5) - 15 * x^4 + 15*x^4 sage: AR.create_term('exact', x^3, 3) + AR.create_term('O', x^5) O(x^5) """ From 9b7c4088fb644fd09243eb621e41650fe0d32625 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 26 Jun 2015 17:05:24 +0200 Subject: [PATCH 0276/1872] fixed big-oh constructor --- src/sage/rings/asymptotic_ring.py | 4 ++-- src/sage/rings/big_oh.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 87d41ab5e90..25a05110f71 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -155,9 +155,9 @@ def O(self): sage: AR = AsymptoticRing(MG, ZZ) sage: x = AR.create_term('exact', x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr - 42 * x^42 + x^10 + O(x^2) + O(x^2) + 1*x^10 + 42*x^42 sage: expr.O() - x^42 + O(x^42) """ if self.poset.null in self.poset.oo.predecessors(): raise ValueError('O(%s) not defined' % self) diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index ec372306496..699ab2eb2b1 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -99,7 +99,7 @@ def O(*x, **kwds): elif isinstance(x, padic_generic_element.pAdicGenericElement): return x.parent()(0, absprec = x.valuation()) - elif len(x) == 1 and hasattr(x, 'O'): - return x[0].O(**kwds) + elif hasattr(x, 'O'): + return x.O(**kwds) raise ArithmeticError("O(x) not defined") From d16a7f5087d26374c80b26d55dd608024ddd6bdb Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Fri, 26 Jun 2015 12:35:43 -0500 Subject: [PATCH 0277/1872] tried moving SymmetricGroupAlgebra declaration in DiagramAlgebras init to no avail --- src/sage/combinat/diagram_algebras.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 6c87efcb348..6dd95ad2bee 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -803,11 +803,10 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): self._base_diagrams = diagrams if category is None: category = FiniteDimensionalAlgebrasWithBasis(base_ring) + KSS = SymmetricGroupAlgebra(base_ring, k, category = category) # QQ probably should not be hardcoded here. CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) - - KSS = SymmetricGroupAlgebra(self.base_ring(), k) # QQ probably should not be hardcoded here. KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)), codomain=self).register_as_coercion() def _element_constructor_(self, set_partition): From 22c7116a9e7355b0b351a9d7dd733e8423fcdcf2 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Fri, 26 Jun 2015 12:52:54 -0500 Subject: [PATCH 0278/1872] temporary workaround for getting SymmetricGroupAlgebra initialized by initializing twice. --- src/sage/combinat/diagram_algebras.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 6dd95ad2bee..a9ac3dd92b8 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -797,6 +797,7 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): sage: D = da.DiagramAlgebra(2, x, R, 'P', da.PartitionDiagrams(2)) sage: TestSuite(D).run() """ + SymmetricGroupAlgebra(base_ring,k) self._prefix = prefix self._q = base_ring(q) self._k = k From 0d4ad6e133134a5015cc9e6253394c66bd60f2be Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Fri, 26 Jun 2015 13:27:42 -0500 Subject: [PATCH 0279/1872] added initial version of jucys-murphy method for the Brauer algebra and began documentation. --- src/sage/combinat/diagram_algebras.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index a9ac3dd92b8..65aae338b0f 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1465,6 +1465,27 @@ def _element_constructor_(self, set_partition): set_partition = to_Brauer_partition(set_partition, k = self.order()) return DiagramAlgebra._element_constructor_(self, set_partition) + def jucys_murphy(self, j): + r""" + Returns a generalized Jucys-Murphy elements for the Brauer algebra. These are outlined in [N]_. + + REFERENCES: + + .. [N] Maxim Nazarov, Young's Orthogonal Form for Brauer's Centralizer + Algebra. Journal of Algebra 182 (1996), 664--693. + + EXAMPLES: + + sage: z = var('z') + sage: B = BrauerAlgebra(3,z) + sage: B.jucys_murphy(1) + 1/2*z - 1/2 + sage: B.jucys_murphy(3) + + """ + B = self + return (B._q-1)/2 + sum(B([[i,-j],[j,-i]]) - B([[i,j],[-i,-j]]) for i in range(1,j)) + class TemperleyLiebAlgebra(SubPartitionAlgebra): r""" A Temperley--Lieb algebra. From 0535e52cc1d6ee4537639aa1c3212576299c8490 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 27 Jun 2015 15:55:54 +0200 Subject: [PATCH 0280/1872] implemented classcall, gens, and ngens --- src/sage/rings/asymptotic_ring.py | 81 +++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 25a05110f71..c5b87d2c3fb 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -176,6 +176,38 @@ class AsymptoticRing(sage.rings.ring.Ring, # enable the category framework for elements Element = AsymptoticExpression + @staticmethod + def __classcall__(cls, growth_group, coefficient_ring, names=None, + category=None): + r""" + Normalizes the input in order to ensure a unique + representation of the parent. + + For more information see :class:`AsymptoticRing`. + + TESTS:: + + sage: asdfasdfasdf + """ + if len(names) > 1: + raise NotImplementedError('Currently only one variable is supported') + if isinstance(growth_group, str) and names is None: + raise ValueError('names has to be specified if the growth group ' + 'is to be constructed') + elif growth_group == 'monomial': + from sage.groups.asymptotic_growth_group import MonomialGrowthGroup + # coefficient ring acts as the base ring of the growth group! + growth_group = MonomialGrowthGroup(coefficient_ring, names[0]) + elif hasattr(growth_group, '_var_') and names is not None: + if names[0] == growth_group._var_: + raise ValueError('Specified variable %s and growth group variable ' + '%s do not match' % (names[0], growth_group._var_)) + + return super(AsymptoticRing, cls).__classcall__(cls, growth_group, + coefficient_ring, category) + + + def __init__(self, growth_group=None, coefficient_ring=None, category=None): r""" ... @@ -334,6 +366,55 @@ def _repr_(self): 'from %s' % (self.growth_group, self.coefficient_ring) + def gens(self): + r""" + Return a tuple with generators of this asymptotic ring. + + INPUT: + + Noting. + + OUTPUT: + + A tuple. + + .. NOTE:: + + Generators do not necessarily exist. This depends on the + underlying growth group. For example, monomial growth + groups have a generator, and exponential growth groups + don't. + + EXAMPLES:: + + sage: asdfasdf + """ + from sage.groups.asymptotic_growth_group import MonomialGrowthGroup + if isinstance(self.growth_group, MonomialGrowthGroup): + return self.create_term('exact', self.growth_group.gen()), + + def ngens(self): + r""" + Return the number of generators of this asymptotic ring. + + INPUT: + + Nothing. + + OUTPUT: + + An integer. + + EXAMPLES:: + + sage: asdfasdf + """ + from sage.groups.asymptotic_growth_group import MonomialGrowthGroup + if isinstance(self.growth_group, MonomialGrowthGroup): + return 1 + else: + return 0 + def create_term(self, type, growth=None, coefficient=None): r""" ... From 12d96ef3a42888dd190d5921d2dc573608449f5d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 27 Jun 2015 16:30:47 +0200 Subject: [PATCH 0281/1872] added some doctests --- src/sage/rings/asymptotic_ring.py | 39 ++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index c5b87d2c3fb..2711445e1d4 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -185,11 +185,21 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, For more information see :class:`AsymptoticRing`. - TESTS:: + EXAMPLES: + + __classcall__ unifies the input to the constructor of + :class:`AsymptoticRing` such that the instances generated + are unique. Also, this enables the use of the generation + framework:: - sage: asdfasdfasdf + sage: import sage.groups.asymptotic_growth_group as agg + sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: AR1 = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) + sage: AR2. = AsymptoticRing(growth_group='monomial', coefficient_ring=ZZ) + sage: AR1 is AR2 + True """ - if len(names) > 1: + if names is not None and len(names) > 1: raise NotImplementedError('Currently only one variable is supported') if isinstance(growth_group, str) and names is None: raise ValueError('names has to be specified if the growth group ' @@ -207,7 +217,6 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, coefficient_ring, category) - def __init__(self, growth_group=None, coefficient_ring=None, category=None): r""" ... @@ -286,16 +295,14 @@ def _element_constructor_(self, data, poset=None): TESTS:: - sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') - sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) - sage: AR.create_term('exact', x^3, 3) + sage: AR. = AsymptoticRing('monomial', ZZ) + sage: 3 * x^3 3*x^3 - sage: AR.create_term('exact', x^3, 3) + AR.create_term('exact', x, 1) + sage: 3 * x^3 + x 1*x + 3*x^3 - sage: AR.create_term('exact', x^3, 3) * AR.create_term('exact', x, 5) + sage: (3 * x^3) * (5 * x) 15*x^4 - sage: AR.create_term('exact', x^3, 3) + AR.create_term('O', x^5) + sage: 3 * x^3 + O(x^5) O(x^5) """ if poset is None: @@ -387,11 +394,13 @@ def gens(self): EXAMPLES:: - sage: asdfasdf + sage: AR. = AsymptoticRing('monomial', ZZ) + sage: AR.gens() + (1*x,) """ from sage.groups.asymptotic_growth_group import MonomialGrowthGroup if isinstance(self.growth_group, MonomialGrowthGroup): - return self.create_term('exact', self.growth_group.gen()), + return self.create_term('exact', self.growth_group.gen(), 1), def ngens(self): r""" @@ -407,7 +416,9 @@ def ngens(self): EXAMPLES:: - sage: asdfasdf + sage: AR. = AsymptoticRing('monomial', ZZ) + sage: AR.ngens() + 1 """ from sage.groups.asymptotic_growth_group import MonomialGrowthGroup if isinstance(self.growth_group, MonomialGrowthGroup): From 7bc49f55af4b8758616f75855037387b89410b92 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 27 Jun 2015 08:06:51 -0700 Subject: [PATCH 0282/1872] Adding `_repr_option` to the interface element to avoid __getattr__. --- src/sage/interfaces/sage0.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/interfaces/sage0.py b/src/sage/interfaces/sage0.py index 0795ca7eec7..1462030975e 100644 --- a/src/sage/interfaces/sage0.py +++ b/src/sage/interfaces/sage0.py @@ -402,6 +402,22 @@ def _rich_repr_(self, display_manager, **kwds): """ return None + def _repr_option(self, option): + """ + Disable repr option. + + This is necessary because otherwise our :meth:`__getattr__` + would be called. + + EXAMPLES:: + + sage: from sage.repl.rich_output import get_display_manager + sage: m = sage0(4) + sage: m._repr_option('ascii_art') + False + """ + return False + def __getattr__(self, attrname): """ EXAMPLES:: From 249b939ee9144e5c2cfb939dda5a1c178cf82960 Mon Sep 17 00:00:00 2001 From: Wilfried Luebbe Date: Sat, 27 Jun 2015 21:02:13 +0200 Subject: [PATCH 0283/1872] Trac #18799: Change syntax of raise with traceback --- src/sage/interfaces/expect.py | 6 ++++-- src/sage/interfaces/singular.py | 4 +++- src/sage/schemes/elliptic_curves/ell_number_field.py | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py index 034df830ed3..167a945b056 100644 --- a/src/sage/interfaces/expect.py +++ b/src/sage/interfaces/expect.py @@ -67,6 +67,8 @@ from sage.env import SAGE_EXTCODE, LOCAL_IDENTIFIER from sage.misc.object_multiplexer import Multiplex +from six import reraise as raise_ + BAD_SESSION = -2 # The subprocess is a shared resource. In a multi-threaded @@ -878,7 +880,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if except (TypeError, RuntimeError): pass return self._eval_line(line,allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False) - raise RuntimeError, "%s\nError evaluating %s in %s"%(msg, line, self), sys.exc_info()[2] + raise_(RuntimeError, "%s\nError evaluating %s in %s"%(msg, line, self), sys.exc_info()[2]) if len(line)>0: try: @@ -1324,7 +1326,7 @@ def __init__(self, parent, value, is_name=False, name=None): # coercion to work properly. except (RuntimeError, ValueError) as x: self._session_number = -1 - raise TypeError, x, sys.exc_info()[2] + raise_(TypeError, x, sys.exc_info()[2]) except BaseException: self._session_number = -1 raise diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 7fa0abfc873..78dc83dec77 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -346,6 +346,8 @@ from sage.misc.misc import get_verbose +from six import reraise as raise_ + class SingularError(RuntimeError): """ Raised if Singular printed an error message @@ -1221,7 +1223,7 @@ def __init__(self, parent, type, value, is_name=False): # coercion to work properly. except SingularError as x: self._session_number = -1 - raise TypeError, x, sys.exc_info()[2] + raise_(TypeError, x, sys.exc_info()[2]) except BaseException: self._session_number = -1 raise diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 54489b9ccaf..da5cebf50eb 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -109,6 +109,8 @@ import gal_reps_number_field +from six import reraise as raise_ + class EllipticCurve_number_field(EllipticCurve_field): r""" Elliptic curve over a number field. @@ -891,7 +893,7 @@ def _reduce_model(self): (a1, a2, a3, a4, a6) = [ZK(a) for a in self.a_invariants()] except TypeError: import sys - raise TypeError, "_reduce_model() requires an integral model.", sys.exc_info()[2] + raise_(TypeError, "_reduce_model() requires an integral model.", sys.exc_info()[2]) # N.B. Must define s, r, t in the right order. if ZK.absolute_degree() == 1: From 2b1e105e52ff12082a58680b52d8e144aeb51cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 29 Jun 2015 19:51:36 +0200 Subject: [PATCH 0284/1872] trac #17947 taking care of trailing whitespaces --- .../combinat/cluster_algebra_quiver/quiver.py | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 4b89986ec69..0eadc5fbfc5 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -1603,14 +1603,15 @@ def d_vector_fan(self): r""" Return the d-vector fan associated with the quiver. - It is the fan whose maximal cones are generated by the d-matrices of the - clusters. + It is the fan whose maximal cones are generated by the + d-matrices of the clusters. + + This is a complete simplicial fan (and even smooth when the + initial quiver is acyclic). It only makes sense for quivers of + finite type. - This is a complete simplicial fan (and even smooth when the initial quiver - is acyclic). It only makes sense for quivers of finite type. - EXAMPLES:: - + sage: Fd = ClusterQuiver([[1,2]]).d_vector_fan(); Fd Rational polyhedral fan in 2-d lattice N sage: Fd.ngenerating_cones() @@ -1629,9 +1630,9 @@ def d_vector_fan(self): 14 sage: Fd.is_smooth() False - + TESTS:: - + sage: ClusterQuiver(['A',[2,2],1]).d_vector_fan() Traceback (most recent call last): ... @@ -1640,21 +1641,22 @@ def d_vector_fan(self): from cluster_seed import ClusterSeed from sage.geometry.fan import Fan from sage.geometry.cone import Cone - + if not(self.is_finite()): raise ValueError('only makes sense for quivers of finite type') seed = ClusterSeed(self) - return Fan([Cone(s.d_matrix().columns()) for s in seed.mutation_class()]) - + return Fan([Cone(s.d_matrix().columns()) + for s in seed.mutation_class()]) + def g_vector_fan(self): r""" Return the g-vector fan associated with the quiver. - It is the fan whose maximal cones are generated by the g-matrices of the - clusters. + It is the fan whose maximal cones are generated by the + g-matrices of the clusters. - This is a complete simplicial fan. It is only supported for quivers of - finite type. + This is a complete simplicial fan. It is only supported for + quivers of finite type. EXAMPLES:: @@ -1677,14 +1679,12 @@ def g_vector_fan(self): sage: Fg.is_smooth() True - TESTS:: sage: ClusterQuiver(['A',[2,2],1]).g_vector_fan() Traceback (most recent call last): ... ValueError: only supported for quivers of finite type - """ from cluster_seed import ClusterSeed from sage.geometry.fan import Fan @@ -1693,5 +1693,5 @@ def g_vector_fan(self): if not(self.is_finite()): raise ValueError('only supported for quivers of finite type') seed = ClusterSeed(self).principal_extension() - return Fan([Cone(s.g_matrix().columns()) for s in seed.mutation_class()]) - + return Fan([Cone(s.g_matrix().columns()) + for s in seed.mutation_class()]) From 66c6c0db714ae98ccb91c369964fe0dfe1844469 Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Mon, 29 Jun 2015 23:29:42 -0500 Subject: [PATCH 0285/1872] merging ticket 18350 --- src/sage/categories/hopf_algebras.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index 2d5c02feb05..b242c233bc1 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -105,9 +105,9 @@ def n_fold_coproduct(h, n): out += H.prod(L(H(t)) for t in term[0]) * term[1] return out - def hopf_power(h,n=2): + def hopf_power(h,n=2): r""" - Input: + Input: h - an element of a Hopf algebra H n - the convolution power of the identity morphism to use Output: @@ -132,7 +132,7 @@ def S(x): elif abs(n)==1: return L(h) else: - return h.convolution_power(L,abs(n)) + return h.convolution_power(L,abs(n)) def antipode(self): """ From a80d67fec7ca9965cc8963c2fb2000a97a569cf5 Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Tue, 30 Jun 2015 02:11:51 -0500 Subject: [PATCH 0286/1872] added convolution product based on code from Amy Pang --- src/sage/categories/bialgebras.py | 244 +++++++++++++----- src/sage/categories/hopf_algebras.py | 67 +---- .../categories/hopf_algebras_with_basis.py | 83 +++++- 3 files changed, 265 insertions(+), 129 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index 7bde7d016cf..382d8724acc 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -11,6 +11,9 @@ from sage.categories.category_types import Category_over_base_ring from sage.categories.all import Algebras, Coalgebras +from sage.categories.tensor import tensor +from sage.functions.other import floor, ceil +from sage.rings.integer import Integer class Bialgebras(Category_over_base_ring): """ @@ -61,76 +64,189 @@ class ParentMethods: class ElementMethods: - def convolution_product(h,a,b): - r""" - input: h - an element of a Hopf algebra H - a,b - linear maps from H to H - output: [a*b](h) + def adams_operator(self, n): """ - H = h.parent() - out = 0 - for (bimonom,coef) in h.coproduct(): - out += coef*a(H(bimonom[0]))*b(H(bimonom[1])) - return out + Compute the n-th convolution power of the identity morphism `Id` on self. + + INPUT: + + - ``n`` -- a nonnegative integer. + + OUTPUT: + + - the element of self.parent() corresponding to `Id^{*n}(self)`. + + .. SEEALSO:: + + :mod:`sage.categories.hopf_algebras.ElementMethods.convolution_product` + :mod:`sage.categories.hopf_algebras.ElementMethods.convolution_product` + + (In the literature, this is also called a Hopf power or Sweedler power, cf. [AL2015]_.) + + REFERENCES: + + .. [AL2015] The characteristic polynomial of the Adams operators on graded connected Hopf algebras. + Marcelo Aguiar and Aaron Lauve. + Algebra Number Theory, v.9, 2015, n.3, 2015. + + .. TODO:: + + Move to hopf_algebras.py (i.e., remove dependency on modules_with_basis methods). + + TESTS:: + + sage: h = SymmetricFunctions(QQ).h() + sage: h[5].adams_operator(2) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h[5].plethysm(2*h[1]) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h([]).adams_operator(0), h([]).adams_operator(1) + (h[], h[]) + sage: h[3,2].adams_operator(0), h[3,2].adams_operator(1) + (0, h[3, 2]) + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S[4].adams_operator(5) + 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: m[[1,3],[2]].adams_operator(-2) + 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} - def convolution_power(h, L, n): - r""" - input: h - an element of a Hopf algebra H - L - linear map from H to H - n - the convolution power to which to take 'L' - output: [L^*n](h) """ - from sage.categories.tensor import tensor - H = h.parent() - def n_fold_coproduct(h, n): - H = h.parent() - if n == 0: - return H(h.counit()) - elif n == 1: - return h - elif n == 2: - return h.coproduct() - else: - # apply some kind of multilinear recursion - Hn = tensor([H]*n) # or: tensor([H for i in range(n)]) - terms = [] - hh = n_fold_coproduct(h, n-1) - for (monom,cof) in hh: - h0 = H(monom[0]).coproduct() - terms += [(tuple((h00, h01) + monom[1:]), cof0 * cof) for ((h00, h01), cof0) in h0] - return Hn.sum_of_terms(terms) - hhh = n_fold_coproduct(h,n) - out = H.zero() - for term in hhh: - out += H.prod(L(H(t)) for t in term[0]) * term[1] - return out - - def hopf_power(h,n=2): - r""" - Input: - h - an element of a Hopf algebra H - n - the convolution power of the identity morphism to use - Output: - the nth convolution power of the identity morphism, applied to h., i.e., [id^*n](h) - - Remark: for historical reasons (see saga of Frobenius-Schur indicators), the second power deserves special attention. - we use '2' as the default value for 'n' + if n < 0: + raise ValueError("cannot take less than 0 coproduct iterations: %s < 0" % str(n)) + return self.convolution_product([lambda x: x] * n) + + def convolution_product(self, *maplist): + """ + Given a maplist `(R, S, ..., T)` of length `n`, compute the action of their convolution product on ``self.`` + + MATH:: + + (R*S*\cdots *T)(h) = \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h) + + where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, + with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; + and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` + (the ordinary product). See [Sw1969]_. + + (In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.) + + REFERENCES: + + .. [KMN2012] On the trace of the antipode and higher indicators. + Yevgenia Kashina and Susan Montgomery and Richard Ng. + Israel J. Math., v.188, 2012. + + .. [Sw1969] Hopf algebras. + Moss Sweedler. + W.A. Benjamin, Math Lec Note Ser., 1969. + + .. TODO:: + + Remove dependency on modules_with_basis methods. + + TESTS:: + + sage: Id = lambda x: x + sage: Antipode = lambda x: x.antipode() + + sage: h = SymmetricFunctions(QQ).h() + sage: h[5].convolution_product([Id,Id]) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h([]).convolution_product([Id,Antipode]) + h[] + sage: h[3,2].convolution_product([Id,Antipode]) + 0 + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S[4].convolution_product([Id]*5) + 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: m[[1,3],[2]].convolution_product([Antipode,Antipode]) + 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} + + sage: m[[]].convolution_product([]), m[[1,3],[2]].convolution_product([]) + (m{}, 0) + + sage: x = GroupAlgebra(SymmetricGroup(7),QQ).an_element(); x + () + 3*(1,2) + 3*(1,2,3,4,5,6,7) + sage: x.convolution_product([Id, Antipode, Antipode, Antipode]) + 4*() + 3*(1,6,4,2,7,5,3) + """ - H = h.parent() - def Id(x): - return x - def S(x): - return x.antipode() - - if n<0: - L = S + # be flexible on how the maps are entered... + if len(maplist)==1 and isinstance(maplist[0], (list,tuple)): + T = tuple(maplist[0]) + else: + T = maplist + + H = self.parent() + n = len(T) + if n == 0: + return H.one() * self.counit() + elif n == 1: + return T[0](self) else: - L = Id + # We apply the maps T_i and products concurrently with coproducts, as this + # seems to be faster than applying a composition of maps, e.g., (H.nfold_product) * tensor(T) * (H.nfold_coproduct). + + i = 0 + out = tensor((H.one(), self)) + dom = tensor((H, H)) + # ALGORITHM: + # `convolve` moves terms of the form x # y to x * T_i(y_1) # y_2, writing Delta(y) in Sweedler notation. + convolve = lambda (x,y): ( ((xy1, y2), c * d) for ((y1, y2), d) in H(y).coproduct() for (xy1, c) in H(x) * T[i](H(y1)) ) + while i < n-1: + out = dom.module_morphism(on_basis=lambda t: dom.sum_of_terms(convolve(t)), codomain = dom)(out) + i += 1 + + # Apply final map `T_n` to last term, `y`, and multiply. + cod = H + out = dom.module_morphism(on_basis=lambda (x,y): H(x) * T[n-1](H(y)), codomain=cod)(out) + + return out + + def coproduct_iterated(self, n=1): + r""" + Apply `k-1` coproducts to ``self``. + + + TESTS:: + + sage: p = SymmetricFunctions(QQ).p() + sage: p[5,2,2].coproduct_iterated() + p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5] + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[] + sage: p([]).coproduct_iterated(3) + p[] # p[] # p[] # p[] + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S[4].coproduct_iterated(0) + S[4] + sage: S[4].coproduct_iterated(2) + S[] # S[] # S[4] + S[] # S[1] # S[3] + S[] # S[2] # S[2] + S[] # S[3] # S[1] + S[] # S[4] # S[] + S[1] # S[] # S[3] + S[1] # S[1] # S[2] + S[1] # S[2] # S[1] + S[1] # S[3] # S[] + S[2] # S[] # S[2] + S[2] # S[1] # S[1] + S[2] # S[2] # S[] + S[3] # S[] # S[1] + S[3] # S[1] # S[] + S[4] # S[] # S[] + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: m[[1,3],[2]].convolution_product([Antipode,Antipode]) + 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} + + sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) + (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) + + + """ + if n < 0: + raise ValueError("cannot take fewer than 0 coproduct iterations: %s < 0" % str(n)) if n==0: - return H(h.counit()) - elif abs(n)==1: - return L(h) + return self + elif n==1: + return self.coproduct() else: - return h.convolution_power(L,abs(n)) + # Use coassociativity of `\Delta` to perform many coproducts simultaneously. + fn = floor(Integer(n-1)/2); cn = ceil(Integer(n-1)/2) + def split(a,b): return tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) + return (self.coproduct()).apply_multilinear_morphism(split) diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index 1e0bb87b5ac..c710583895e 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -12,7 +12,7 @@ from category import Category from category_types import Category_over_base_ring from sage.categories.bialgebras import Bialgebras -from sage.categories.tensor import TensorProductsCategory, tensor +from sage.categories.tensor import TensorProductsCategory # tensor from sage.categories.realizations import RealizationsCategory from sage.misc.cachefunc import cached_method #from sage.misc.lazy_attribute import lazy_attribute @@ -45,7 +45,7 @@ def super_categories(self): def dual(self): """ - Returns the dual category + Return the dual category EXAMPLES: @@ -63,7 +63,7 @@ class ElementMethods: def antipode(self): """ - Returns the antipode of self. + Return the antipode of self EXAMPLES:: @@ -86,67 +86,6 @@ def antipode(self): # This choice should be done consistently with coproduct, ... # return operator.antipode(self) - def adams_operator(self, k): - """ - - Iterate `k` times the coproduct and then the product: - - MATH:: - - \mu^k \circ \Delta^{k} - - where `\Delta^k := (\Delta \otimes Id^{k -1 \otimes}) \circ \Delta^{k-1}` with `\Delta^1 = \Delta`, - `\Delta^0 = Id` and `\mu^k := \mu \circ (Id \otimes \mu^{k-1})` with `\mu^1 = \mu`, `\mu^0 = \mu`. - - Reference - --------- - - .. [AL] The characteristic polynomial of the Adams operators on graded connected Hopf algebras - Marcelo Aguiar and Aaron Lauve - http://www.math.cornell.edu/~maguiar/adams.pdf - - TESTS:: - - sage: h = SymmetricFunctions(QQ).h() - sage: h[5].adams_operator(1) - 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h[5].plethysm(2*h[1]) - 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S[4].adams_operator(4) - 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] - - """ - if k == 0: return self - - S = self.parent() - term = self.coproduct() - dom = tensor((S,)*2) - cod = tensor((S,)*3) - for _ in range(k-1): - term = dom.module_morphism( - on_basis=lambda t: cod.sum_of_terms(map(lambda (a, c): (a+t[1:], c), S(t[0]).coproduct())), - codomain=cod - )(term) - dom, cod = cod, tensor([S, cod]) - - for i in range(k-1): - dom = tensor((S,)*(k-i+1)) - cod = tensor((S,)*(k-i)) - term = dom.module_morphism( - on_basis=lambda t: cod.sum_of_terms(map(lambda (a, c): ((a,) + t[:-2], c), S(t[-2]) * S(t[-1]))), - codomain=cod - )(term) - - term = tensor((S,S)).module_morphism( - on_basis=lambda t: S(t[0]) * S(t[1]), - codomain=S - )(term) - - return term - - class ParentMethods: #def __setup__(self): # Check the conventions for _setup_ or __setup__ # if self.implements("antipode"): diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index c9ea8527ae0..494b8f81160 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -260,7 +260,88 @@ def _test_antipode(self, **options): tester.assert_(IS(x) == self.counit(x) * self.one()) class ElementMethods: - pass + + def adams_operator(self, n): + """ + Compute the n-th convolution power of the identity morphism `Id` on self. + + INPUT: + + - ``n`` -- an integer. + + OUTPUT: + + - the element of self.parent() corresponding to `Id^{*n}(self)`. + + .. SEEALSO:: + + Extends code defined in bialgebras.py... + + :meth:`sage.categories.bialgebras.ElementMethods.adams_operator` + :meth:`sage.categories.bialgebras.ElementMethods.convolution_product` + + (In the literature, this is also called a Hopf power or Sweedler power, cf. [AL2015]_.) + + REFERENCES: + + .. [AL2015] The characteristic polynomial of the Adams operators on graded connected Hopf algebras. + Marcelo Aguiar and Aaron Lauve. + Algebra Number Theory, v.9, 2015, n.3, 2015. + + .. TODO:: + + Move to hopf_algebras.py (i.e., remove dependency on modules_with_basis methods). + + EXAMPLES:: + + sage: h = SymmetricFunctions(QQ).h() + sage: h[5].adams_operator(2) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h[5].plethysm(2*h[1]) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h([]).adams_operator(0), h([]).adams_operator(1) + (h[], h[]) + sage: h[3,2].adams_operator(0), h[3,2].adams_operator(1) + (0, h[3, 2]) + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S[4].adams_operator(5) + 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + + + sage: x = GroupAlgebra(SymmetricGroup(7),QQ).an_element(); x + () + 2*(6,7) + 3*(5,6) + (1,2,3,4,5,6,7) + sage: x.adams_operator(2) + 6*() + (1,3,5,7,2,4,6) + sage: x.antipode() + () + 2*(6,7) + 3*(5,6) + (1,7,6,5,4,3,2) + sage: x.adams_operator(-2) + 6*() + (1,6,4,2,7,5,3) + + TESTS:: + + sage: s = SymmetricFunctions(QQ).s() + sage: s[5,2,2].adams_operator(-1) + -s[3, 3, 1, 1, 1] + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: m[[1,3],[2]].adams_operator(-2) + 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} + + sage: x = GroupAlgebra(SymmetricGroup(7),QQ).an_element(); x + () + 2*(6,7) + 3*(5,6) + (1,2,3,4,5,6,7) + sage: x.adams_operator(-3) + () + 2*(6,7) + 3*(5,6) + (1,5,2,6,3,7,4) + sage: x.adams_operator(0) + 7*() + """ + if n < 0: + T = lambda x: x.antipode() + n = abs(n) + else: + T = lambda x: x + + return self.convolution_product([T] * n) class TensorProducts(TensorProductsCategory): """ From cb070380d79d62bdd560ba7b0f14c3c86074e5bf Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Wed, 1 Jul 2015 21:23:28 -0500 Subject: [PATCH 0287/1872] removed category declaration and unnecessary comment --- src/sage/combinat/diagram_algebras.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 23fdf4e687f..ee241162941 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -797,14 +797,14 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): sage: D = da.DiagramAlgebra(2, x, R, 'P', da.PartitionDiagrams(2)) sage: TestSuite(D).run() """ - SymmetricGroupAlgebra(base_ring,k) + SymmetricGroupAlgebra(base_ring,k) # Necessary for some odd reason self._prefix = prefix self._q = base_ring(q) self._k = k self._base_diagrams = diagrams if category is None: category = FiniteDimensionalAlgebrasWithBasis(base_ring) - KSS = SymmetricGroupAlgebra(base_ring, k, category = category) # QQ probably should not be hardcoded here. + KSS = SymmetricGroupAlgebra(base_ring, k) CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) From e07d789ade59bfc8f0475a9ed9bb9216aac0a5ca Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Wed, 1 Jul 2015 23:46:18 -0500 Subject: [PATCH 0288/1872] fixed doctests for added methods in hopf_algebras_with_basis.py and bialgebras.py --- src/sage/categories/bialgebras.py | 24 ++++++++++--------- .../categories/hopf_algebras_with_basis.py | 22 +++++++++-------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index 382d8724acc..c9d8918b423 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -171,11 +171,13 @@ def convolution_product(self, *maplist): sage: m[[]].convolution_product([]), m[[1,3],[2]].convolution_product([]) (m{}, 0) - sage: x = GroupAlgebra(SymmetricGroup(7),QQ).an_element(); x - () + 3*(1,2) + 3*(1,2,3,4,5,6,7) + sage: QS = SymmetricGroupAlgebra(QQ,5) + sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] + sage: x.convolution_product([Antipode]) + 2*[1, 2, 4, 5, 3] + [1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] sage: x.convolution_product([Id, Antipode, Antipode, Antipode]) - 4*() + 3*(1,6,4,2,7,5,3) - + 3*[1, 2, 3, 4, 5] + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] """ # be flexible on how the maps are entered... if len(maplist)==1 and isinstance(maplist[0], (list,tuple)): @@ -223,15 +225,15 @@ def coproduct_iterated(self, n=1): sage: p([]).coproduct_iterated(3) p[] # p[] # p[] # p[] - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S[4].coproduct_iterated(0) - S[4] - sage: S[4].coproduct_iterated(2) - S[] # S[] # S[4] + S[] # S[1] # S[3] + S[] # S[2] # S[2] + S[] # S[3] # S[1] + S[] # S[4] # S[] + S[1] # S[] # S[3] + S[1] # S[1] # S[2] + S[1] # S[2] # S[1] + S[1] # S[3] # S[] + S[2] # S[] # S[2] + S[2] # S[1] # S[1] + S[2] # S[2] # S[] + S[3] # S[] # S[1] + S[3] # S[1] # S[] + S[4] # S[] # S[] + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() + sage: Psi[2,2].coproduct_iterated(0) + Psi[2, 2] + sage: Psi[2,2].coproduct_iterated(3) + Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2] + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[] + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[] + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[] sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].convolution_product([Antipode,Antipode]) - 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} + sage: m[[1,3],[2]].coproduct_iterated(2) + m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}} + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{} + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{} + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{} + m{{1, 3}, {2}} # m{} # m{} sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index 494b8f81160..6e5e4d4732d 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -309,14 +309,15 @@ def adams_operator(self, n): 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] - sage: x = GroupAlgebra(SymmetricGroup(7),QQ).an_element(); x - () + 2*(6,7) + 3*(5,6) + (1,2,3,4,5,6,7) + sage: QS = SymmetricGroupAlgebra(QQ,5) + sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] sage: x.adams_operator(2) - 6*() + (1,3,5,7,2,4,6) + 3*[1, 2, 3, 4, 5] + 2*[1, 2, 4, 5, 3] + [1, 2, 5, 3, 4] sage: x.antipode() - () + 2*(6,7) + 3*(5,6) + (1,7,6,5,4,3,2) + 2*[1, 2, 4, 5, 3] + [1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] sage: x.adams_operator(-2) - 6*() + (1,6,4,2,7,5,3) + 3*[1, 2, 3, 4, 5] + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] TESTS:: @@ -328,12 +329,13 @@ def adams_operator(self, n): sage: m[[1,3],[2]].adams_operator(-2) 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} - sage: x = GroupAlgebra(SymmetricGroup(7),QQ).an_element(); x - () + 2*(6,7) + 3*(5,6) + (1,2,3,4,5,6,7) + sage: G = AlternatingGroup(5); QG = GroupAlgebra(G,QQ) + sage: x = QG.sum_of_terms(zip(G[3:6],[1,2,3])); x + (3,5,4) + 3*(1,2,4,3,5) + 2*(1,3,5,2,4) sage: x.adams_operator(-3) - () + 2*(6,7) + 3*(5,6) + (1,5,2,6,3,7,4) - sage: x.adams_operator(0) - 7*() + () + 3*(1,4,5,2,3) + 2*(1,5,4,3,2) + sage: x.adams_operator(0), x.adams_operator(10) + (6*(), 5*() + (3,5,4)) """ if n < 0: T = lambda x: x.antipode() From 8d3d190ddee6e8a1ca5ad60adaabf2ed632517d7 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 2 Jul 2015 20:42:03 +0200 Subject: [PATCH 0289/1872] improvement of _coerce_map_from_ --- src/sage/rings/asymptotic_ring.py | 48 +++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 2711445e1d4..924fe36947e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -199,7 +199,10 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, sage: AR1 is AR2 True """ - if names is not None and len(names) > 1: + if not isinstance(names, tuple): + names = (names,) + + if len(names) > 1: raise NotImplementedError('Currently only one variable is supported') if isinstance(growth_group, str) and names is None: raise ValueError('names has to be specified if the growth group ' @@ -343,10 +346,51 @@ def _element_constructor_(self, data, poset=None): def _coerce_map_from_(self, R): r""" - ... + Return if ``R`` coerces into this asymptotic ring. + + INPUT: + + - ``R`` -- a parent. + + OUTPUT: + + A boolean. + + .. NOTE:: + + There are two possible cases: either ``R`` is the + ``coefficient_ring`` of this asymptotic ring, or ``R`` + itself is an asymptotic ring (where both the + ``growth_group`` and the ``coefficient_ring`` coerce into + the ``growth_group`` and the ``coefficient_ring`` of this + asymptotic ring, respectively). + + TESTS:: + + sage: AR_ZZ = AsymptoticRing('monomial', coefficient_ring=ZZ, names='x'); AR_ZZ + Asymptotic Ring over Monomial Growth Group in x over Integer Ring with coefficients from Integer Ring + sage: (x_ZZ,) = AR_ZZ.gens() + sage: AR_QQ = AsymptoticRing('monomial', coefficient_ring=QQ, names='x'); AR_QQ + Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + sage: (x_QQ,) = AR_QQ.gens() + sage: AR_QQ.has_coerce_map_from(AR_ZZ) # indirect doctest + True + sage: x_ZZ * x_QQ + 1*x^2 + + :: + + sage: AR_QQ.has_coerce_map_from(QQ) + True + sage: 1/2 * x_QQ^2 + 7/8 * x_QQ^3 + 1/2*x^2 + 7/8*x^3 """ if R is self.coefficient_ring: return True + elif isinstance(R, AsymptoticRing): + if self.growth_group.has_coerce_map_from(R.growth_group) and \ + self.coefficient_ring.has_coerce_map_from(R.coefficient_ring): + return True def _repr_(self): From 67c0e22ea91602eea9d387fe82c02f867b381aa9 Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Thu, 2 Jul 2015 16:52:10 -0500 Subject: [PATCH 0290/1872] added convolution_product() at parent level, added a few more tests and examples. --- src/sage/categories/bialgebras.py | 204 +++++++++++++++++++++++++++--- 1 file changed, 188 insertions(+), 16 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index c9d8918b423..d761f855b6b 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -14,6 +14,7 @@ from sage.categories.tensor import tensor from sage.functions.other import floor, ceil from sage.rings.integer import Integer +from sage.categories.modules_with_basis import ModulesWithBasis class Bialgebras(Category_over_base_ring): """ @@ -60,7 +61,87 @@ def additional_structure(self): return None class ParentMethods: - pass + + def convolution_product(self, *maplist): + """ + Given a maplist `(R, S, ..., T)` of length `n`, return the new map representing their convolution product. + + MATH:: + + (R*S*\cdots *T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h) + + .. SEEALSO:: + + :meth:`sage.categories.bialgebras.ElementMethods.convolution_product` + + .. TODO:: + + Remove dependency on modules_with_basis methods. + + TESTS:: + + sage: Id = lambda x: x + sage: Antipode = lambda x: x.antipode() + sage: Proj2 = lambda x: x.parent().sum_of_terms([(m,c) for (m,c) in x if m.size()==2]) + + sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon() + sage: T = R.convolution_product([Id,Id]) + sage: [T(R(comp)) for comp in Compositions(3)] + [4*R[1, 1, 1] + R[1, 2] + R[2, 1], + 2*R[1, 1, 1] + 4*R[1, 2] + 2*R[2, 1] + 2*R[3], + 2*R[1, 1, 1] + 2*R[1, 2] + 4*R[2, 1] + 2*R[3], + R[1, 2] + R[2, 1] + 4*R[3]] + sage: T = R.convolution_product(Proj2,Id) + sage: [T(R([i])) for i in range(1,5)] + [0, R[2], R[2, 1] + R[3], R[2, 2] + R[4]] + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: T = m.convolution_product() + sage: [T(m(lam)) for lam in SetPartitions(0).list()+SetPartitions(2).list()] + [m{}, 0, 0] + sage: T = m.convolution_product(Proj2,Id) + sage: [T(m(lam)) for lam in SetPartitions(3)] + [0, + m{{1, 2}, {3}} + m{{1, 2, 3}}, + m{{1, 2}, {3}} + m{{1, 2, 3}}, + m{{1, 2}, {3}} + m{{1, 2, 3}}, + 3*m{{1}, {2}, {3}} + 3*m{{1}, {2, 3}} + 3*m{{1, 3}, {2}}] + + sage: G = SymmetricGroup(3); QG = GroupAlgebra(G,QQ) + sage: x = QG.sum_of_terms([(p,p.number_of_peaks() + p.number_of_inversions()) for p in Permutations(3)]); x + 2*[1, 3, 2] + [2, 1, 3] + 3*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] + sage: T = QG.convolution_product(Antipode,Antipode,Id) + sage: T(x) + 2*[1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 3*[3, 1, 2] + 3*[3, 2, 1] + """ + # Be flexible on how the maps are entered... + if len(maplist)==1 and isinstance(maplist[0], (list,tuple)): + T = tuple(maplist[0]) + else: + T = maplist + + n = len(T) + H = self + + # I do not know how to keep .convolution_product() from showing up in the + # list of methods available to, e.g., SymmetricFunctions(QQ). + # At present, the code below assumes Parent is something more like SymmetricFunctions(QQ).m() + # The code should either be rewritten (I don't know how), + # or we should do a check, e.g., + if not H in ModulesWithBasis: + raise TypeError('`self` must belong to ModulesWithBasis. Try a basis of %s' % H._repr_()) + + if n == 0: + return H.module_morphism(on_basis=lambda x: H.one() * H.term(x).counit(), codomain = H) + elif n == 1: + return H.module_morphism(on_basis=lambda x: T[0](H.term(x)), codomain = H) + else: + HHH = tensor((H,)*n) + Delta_n = H.module_morphism(on_basis=lambda x: H.term(x).coproduct_iterated(n-1), codomain = HHH) + apply_T = HHH.module_morphism(on_basis=lambda args: tensor([T[i](H.term(args[i])) for i in range(n)]), codomain = HHH) + Mu_n = HHH.module_morphism(on_basis=lambda args: H.prod([H.term(h) for h in args]), codomain = H) + + return Mu_n * apply_T * Delta_n class ElementMethods: @@ -124,7 +205,7 @@ def convolution_product(self, *maplist): MATH:: - (R*S*\cdots *T)(h) = \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h) + (R*S*\cdots *T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h) where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; @@ -147,6 +228,39 @@ def convolution_product(self, *maplist): Remove dependency on modules_with_basis methods. + EXAMPLES:: + + sage: Id = lambda x: x + sage: Antipode = lambda x: x.antipode() + sage: s = SymmetricFunctions(QQ).schur() + sage: s[3].convolution_product(Id,Id) + 2*s[2, 1] + 4*s[3] + sage: s[3,2].convolution_product(Id,Id) == s[3,2].convolution_product([Id,Id]) + True + sage: s[3,2].convolution_product(Id) == s[3,2] + True + sage: s[3,2].convolution_product() == s[3,2].convolution_product(Antipode,Id) == s[3,2].convolution_product(Id,Antipode) + True + sage: s[3,2].counit().parent() == s[3,2].convolution_product().parent() + False + + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() + sage: Psi[2,1].convolution_product(Id,Id,Id) + 3*Psi[1, 2] + 6*Psi[2, 1] + sage: (Psi[5,1] - Psi[1,5]).convolution_product(Id,Id,Id) + -3*Psi[1, 5] + 3*Psi[5, 1] + + sage: G = SymmetricGroup(3); QG = GroupAlgebra(G,QQ) + sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x + [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] + sage: x.convolution_product(Id,Id) + 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + sage: x.convolution_product(Id,Id,Id) + 4*[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + 3*[3, 2, 1] + sage: x.convolution_product(Id,Id,Id,Id,Id,Id) + 9*[1, 2, 3] + + TESTS:: sage: Id = lambda x: x @@ -155,10 +269,12 @@ def convolution_product(self, *maplist): sage: h = SymmetricFunctions(QQ).h() sage: h[5].convolution_product([Id,Id]) 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h([]).convolution_product([Id,Antipode]) + sage: h.one().convolution_product([Id,Antipode]) h[] sage: h[3,2].convolution_product([Id,Antipode]) 0 + sage: h.one().convolution_product([Id,Antipode]) == h.one().convolution_product() + True sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: S[4].convolution_product([Id]*5) @@ -174,12 +290,20 @@ def convolution_product(self, *maplist): sage: QS = SymmetricGroupAlgebra(QQ,5) sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] - sage: x.convolution_product([Antipode]) - 2*[1, 2, 4, 5, 3] + [1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] - sage: x.convolution_product([Id, Antipode, Antipode, Antipode]) + sage: x.convolution_product([Antipode,Id]) + 6*[1, 2, 3, 4, 5] + sage: x.convolution_product(Id, Antipode, Antipode, Antipode) 3*[1, 2, 3, 4, 5] + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + + sage: G = SymmetricGroup(3); QG = GroupAlgebra(G,QQ) + sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x + [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] + sage: x.convolution_product(Antipode,Id) + 9*[1, 2, 3] + sage: x.convolution_product([Id, Antipode, Antipode, Antipode]) + 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] """ - # be flexible on how the maps are entered... + # Be flexible on how the maps are entered... if len(maplist)==1 and isinstance(maplist[0], (list,tuple)): T = tuple(maplist[0]) else: @@ -196,26 +320,74 @@ def convolution_product(self, *maplist): # seems to be faster than applying a composition of maps, e.g., (H.nfold_product) * tensor(T) * (H.nfold_coproduct). i = 0 - out = tensor((H.one(), self)) - dom = tensor((H, H)) + out = tensor((H.one(),self)) + HH = tensor((H,H)) - # ALGORITHM: - # `convolve` moves terms of the form x # y to x * T_i(y_1) # y_2, writing Delta(y) in Sweedler notation. - convolve = lambda (x,y): ( ((xy1, y2), c * d) for ((y1, y2), d) in H(y).coproduct() for (xy1, c) in H(x) * T[i](H(y1)) ) + #ALGORITHM: + #`split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. + split_convolve = lambda (x,y): (((xy1,y2),c*d) for ((y1,y2),d) in H.term(y).coproduct() for (xy1,c) in H.term(x)*T[i](H.term(y1))) while i < n-1: - out = dom.module_morphism(on_basis=lambda t: dom.sum_of_terms(convolve(t)), codomain = dom)(out) + out = HH.module_morphism(on_basis=lambda t: HH.sum_of_terms(split_convolve(t)), codomain = HH)(out) i += 1 - # Apply final map `T_n` to last term, `y`, and multiply. - cod = H - out = dom.module_morphism(on_basis=lambda (x,y): H(x) * T[n-1](H(y)), codomain=cod)(out) + #Apply final map `T_n` to last term, `y`, and multiply. + out = HH.module_morphism(on_basis=lambda (x,y): H.term(x)*T[n-1](H.term(y)), codomain=H)(out) + +# #ALGORITHM: return out + # ------------ + # IMPLEMENTATION NOTE: + # In the `module_morphism()` version of this code (copied below), Sage sometimes throws a `TypeError`. E.g., + # ------- + # sage: Antipode = lambda x: x.antipode() + # + # sage: QS = SymmetricGroupAlgebra(QQ,3) + # sage: x = QS.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x + # [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] + # sage: x.convolution_product([Antipode, Antipode]) + # 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + # + # sage: QG GroupAlgebra(SymmetricGroup(3),QQ) + # sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x + # [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] + # sage: x.convolution_product([Antipode,Antipode]) + # TypeError: Don't know how to create an element of Group algebra of group... + # ------- + # #`split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. + # split_convolve = lambda x,y: (x.tensor(y.coproduct())).apply_multilinear_morphism(convolve, codomain = HH) + # convolve = lambda x,y1,y2: tensor([x * T[i](y1), y2]) + # + # while i < n-1: + # out = out.apply_multilinear_morphism(split_convolve, codomain = HH) + # i += 1 + # + # #Apply final map `T_n` to last term, `y`, and multiply. + # out = out.apply_multilinear_morphism(lambda x,y: x * T[n-1](y), codomain = H) + # ------- + # #`split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. + # split_convolve = lambda (x,y): (((xy1,y2),c*d) for ((y1,y2),d) in H(y).coproduct() for (xy1,c) in H(x)*T[i](H(y1))) + # while i < n-1: + # out = HH.module_morphism(on_basis=lambda t: HH.sum_of_terms(split_convolve(t)), codomain = HH)(out) + # i += 1 + + # #Apply final map `T_n` to last term, `y`, and multiply. + # out = HH.module_morphism(on_basis=lambda (x,y): H(x)*T[n-1](H(y)), codomain=H)(out) + # ------------ + + def coproduct_iterated(self, n=1): r""" Apply `k-1` coproducts to ``self``. + EXAMPLES:: + + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() + sage: Psi[2,2].coproduct_iterated(0) + Psi[2, 2] + sage: Psi[2,2].coproduct_iterated(2) + Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2] + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[] TESTS:: From de4fa8761667d770a5153e272c0522c8367188ca Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Fri, 3 Jul 2015 16:34:29 -0500 Subject: [PATCH 0291/1872] In ParentMethods of bialgebras.py, added ._convolution_product_from_element() for testing purposes. --- src/sage/categories/bialgebras.py | 128 ++++++++++-------- .../categories/hopf_algebras_with_basis.py | 85 +----------- 2 files changed, 72 insertions(+), 141 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index d761f855b6b..5f1e97b5b88 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -64,16 +64,37 @@ class ParentMethods: def convolution_product(self, *maplist): """ - Given a maplist `(R, S, ..., T)` of length `n`, return the new map representing their convolution product. + Return the convolution product (a map) of the maps in maplist. + + INPUT: + + - ``maplist`` -- any number of linear maps `R,S,...,T` on ``self``, say of length `n>=0`. + + OUTPUT: + + - the new map `R*S*...*T` representing their convolution product. MATH:: - (R*S*\cdots *T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h) + (R*S*\cdots *T) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}. + + where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, + with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; + and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` + (the ordinary product). See [Sw1969]_. + + (In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.) .. SEEALSO:: :meth:`sage.categories.bialgebras.ElementMethods.convolution_product` + AUTHORS: + + Aaron Lauve - 12 June 2015 - Sage Days 65 + - based off of .adams_operator() code in sage-trac ticket #18350 + - by Jean-Baptiste Priez + .. TODO:: Remove dependency on modules_with_basis methods. @@ -123,14 +144,13 @@ def convolution_product(self, *maplist): n = len(T) H = self - # I do not know how to keep .convolution_product() from showing up in the - # list of methods available to, e.g., SymmetricFunctions(QQ). - # At present, the code below assumes Parent is something more like SymmetricFunctions(QQ).m() - # The code should either be rewritten (I don't know how), - # or we should do a check, e.g., + # TYPE-CHECK: if not H in ModulesWithBasis: - raise TypeError('`self` must belong to ModulesWithBasis. Try a basis of %s' % H._repr_()) + raise AttributeError('`self` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `self` instead.' % H._repr_()) + # SPEED-NOTE: + # The code below, written as a composition of morphisms, is + # much slower than the code appearing under ElementMethods below. if n == 0: return H.module_morphism(on_basis=lambda x: H.one() * H.term(x).counit(), codomain = H) elif n == 1: @@ -143,6 +163,16 @@ def convolution_product(self, *maplist): return Mu_n * apply_T * Delta_n + def _convolution_product_from_elements(self, *maplist): + """ + Return the convolution product (a map) of the maps in maplist. + + A temporary function, created for speed-testing purposes. + """ + cpfe = lambda x: x.convolution_product(*maplist) + return cpfe + + class ElementMethods: def adams_operator(self, n): @@ -159,8 +189,7 @@ def adams_operator(self, n): .. SEEALSO:: - :mod:`sage.categories.hopf_algebras.ElementMethods.convolution_product` - :mod:`sage.categories.hopf_algebras.ElementMethods.convolution_product` + :mod:`sage.categories.bialgebras.ElementMethods.convolution_product` (In the literature, this is also called a Hopf power or Sweedler power, cf. [AL2015]_.) @@ -172,7 +201,7 @@ def adams_operator(self, n): .. TODO:: - Move to hopf_algebras.py (i.e., remove dependency on modules_with_basis methods). + Remove dependency on modules_with_basis methods. TESTS:: @@ -196,16 +225,30 @@ def adams_operator(self, n): """ if n < 0: - raise ValueError("cannot take less than 0 coproduct iterations: %s < 0" % str(n)) - return self.convolution_product([lambda x: x] * n) + if hasattr(self,'antipode'): + T = lambda x: x.antipode() + n = abs(n) + else: + raise AttributeError("`self` has no antipode, hence cannot take negative convolution powers of identity_map: %s < 0" % str(n)) + else: + T = lambda x: x + return self.convolution_product([T] * n) def convolution_product(self, *maplist): """ - Given a maplist `(R, S, ..., T)` of length `n`, compute the action of their convolution product on ``self.`` + Return the image of ``self`` under the convolution product (map) of the maps in ``maplist``. + + INPUT: + + - ``maplist`` -- any number of linear maps `R,S,...,T` on ``self.parent()``, say of length `n>=0`. + + OUTPUT: + + - `(R*S*...*T)` applied to ``self``. MATH:: - (R*S*\cdots *T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h) + (R*S*\cdots *T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h), where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; @@ -224,6 +267,10 @@ def convolution_product(self, *maplist): Moss Sweedler. W.A. Benjamin, Math Lec Note Ser., 1969. + AUTHORS: + + Amy Pang - 12 June 2015 - Sage Days 65 + .. TODO:: Remove dependency on modules_with_basis methods. @@ -310,6 +357,10 @@ def convolution_product(self, *maplist): T = maplist H = self.parent() + # TYPE-CHECK: + if not H in ModulesWithBasis: + raise AttributeError('`parent` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `parent` instead.' % H._repr_()) + n = len(T) if n == 0: return H.one() * self.counit() @@ -333,53 +384,16 @@ def convolution_product(self, *maplist): #Apply final map `T_n` to last term, `y`, and multiply. out = HH.module_morphism(on_basis=lambda (x,y): H.term(x)*T[n-1](H.term(y)), codomain=H)(out) -# #ALGORITHM: - return out - # ------------ - # IMPLEMENTATION NOTE: - # In the `module_morphism()` version of this code (copied below), Sage sometimes throws a `TypeError`. E.g., - # ------- - # sage: Antipode = lambda x: x.antipode() - # - # sage: QS = SymmetricGroupAlgebra(QQ,3) - # sage: x = QS.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x - # [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] - # sage: x.convolution_product([Antipode, Antipode]) - # 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] - # - # sage: QG GroupAlgebra(SymmetricGroup(3),QQ) - # sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x - # [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] - # sage: x.convolution_product([Antipode,Antipode]) - # TypeError: Don't know how to create an element of Group algebra of group... - # ------- - # #`split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. - # split_convolve = lambda x,y: (x.tensor(y.coproduct())).apply_multilinear_morphism(convolve, codomain = HH) - # convolve = lambda x,y1,y2: tensor([x * T[i](y1), y2]) - # - # while i < n-1: - # out = out.apply_multilinear_morphism(split_convolve, codomain = HH) - # i += 1 - # - # #Apply final map `T_n` to last term, `y`, and multiply. - # out = out.apply_multilinear_morphism(lambda x,y: x * T[n-1](y), codomain = H) - # ------- - # #`split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. - # split_convolve = lambda (x,y): (((xy1,y2),c*d) for ((y1,y2),d) in H(y).coproduct() for (xy1,c) in H(x)*T[i](H(y1))) - # while i < n-1: - # out = HH.module_morphism(on_basis=lambda t: HH.sum_of_terms(split_convolve(t)), codomain = HH)(out) - # i += 1 - - # #Apply final map `T_n` to last term, `y`, and multiply. - # out = HH.module_morphism(on_basis=lambda (x,y): H(x)*T[n-1](H(y)), codomain=H)(out) - # ------------ - def coproduct_iterated(self, n=1): r""" - Apply `k-1` coproducts to ``self``. + Apply `n` coproducts to ``self``. + + .. TODO:: + + Remove dependency on modules_with_basis methods. EXAMPLES:: diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index 6e5e4d4732d..c9ea8527ae0 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -260,90 +260,7 @@ def _test_antipode(self, **options): tester.assert_(IS(x) == self.counit(x) * self.one()) class ElementMethods: - - def adams_operator(self, n): - """ - Compute the n-th convolution power of the identity morphism `Id` on self. - - INPUT: - - - ``n`` -- an integer. - - OUTPUT: - - - the element of self.parent() corresponding to `Id^{*n}(self)`. - - .. SEEALSO:: - - Extends code defined in bialgebras.py... - - :meth:`sage.categories.bialgebras.ElementMethods.adams_operator` - :meth:`sage.categories.bialgebras.ElementMethods.convolution_product` - - (In the literature, this is also called a Hopf power or Sweedler power, cf. [AL2015]_.) - - REFERENCES: - - .. [AL2015] The characteristic polynomial of the Adams operators on graded connected Hopf algebras. - Marcelo Aguiar and Aaron Lauve. - Algebra Number Theory, v.9, 2015, n.3, 2015. - - .. TODO:: - - Move to hopf_algebras.py (i.e., remove dependency on modules_with_basis methods). - - EXAMPLES:: - - sage: h = SymmetricFunctions(QQ).h() - sage: h[5].adams_operator(2) - 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h[5].plethysm(2*h[1]) - 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h([]).adams_operator(0), h([]).adams_operator(1) - (h[], h[]) - sage: h[3,2].adams_operator(0), h[3,2].adams_operator(1) - (0, h[3, 2]) - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S[4].adams_operator(5) - 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] - - - sage: QS = SymmetricGroupAlgebra(QQ,5) - sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x - [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] - sage: x.adams_operator(2) - 3*[1, 2, 3, 4, 5] + 2*[1, 2, 4, 5, 3] + [1, 2, 5, 3, 4] - sage: x.antipode() - 2*[1, 2, 4, 5, 3] + [1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] - sage: x.adams_operator(-2) - 3*[1, 2, 3, 4, 5] + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] - - TESTS:: - - sage: s = SymmetricFunctions(QQ).s() - sage: s[5,2,2].adams_operator(-1) - -s[3, 3, 1, 1, 1] - - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].adams_operator(-2) - 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} - - sage: G = AlternatingGroup(5); QG = GroupAlgebra(G,QQ) - sage: x = QG.sum_of_terms(zip(G[3:6],[1,2,3])); x - (3,5,4) + 3*(1,2,4,3,5) + 2*(1,3,5,2,4) - sage: x.adams_operator(-3) - () + 3*(1,4,5,2,3) + 2*(1,5,4,3,2) - sage: x.adams_operator(0), x.adams_operator(10) - (6*(), 5*() + (3,5,4)) - """ - if n < 0: - T = lambda x: x.antipode() - n = abs(n) - else: - T = lambda x: x - - return self.convolution_product([T] * n) + pass class TensorProducts(TensorProductsCategory): """ From 958fb580519913386e15c36a58ca62b785b64e51 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Fri, 3 Jul 2015 21:01:04 -0500 Subject: [PATCH 0292/1872] Completed jucys-murphy doctest for BrauerAlgebra --- src/sage/combinat/diagram_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index cc279262646..06a1efb672d 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1580,7 +1580,7 @@ def jucys_murphy(self, j): sage: B.jucys_murphy(1) 1/2*z - 1/2 sage: B.jucys_murphy(3) - + -B{{-3, -2}, {-1, 1}, {2, 3}} - B{{-3, -1}, {-2, 2}, {1, 3}} + B{{-3, 1}, {-2, 2}, {-1, 3}} + B{{-3, 2}, {-2, 3}, {-1, 1}} + (1/2*z-1/2)*B{{-3, 3}, {-2, 2}, {-1, 1}} """ B = self return (B._q-1)/2 + sum(B([[i,-j],[j,-i]]) - B([[i,j],[-i,-j]]) for i in range(1,j)) From e138144a3975a51a005f06df98c6ef1b0fad1753 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Fri, 3 Jul 2015 21:09:29 -0500 Subject: [PATCH 0293/1872] Added documentation and a doctest for coercion --- src/sage/combinat/diagram_algebras.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 00685d98348..4749faefc1f 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -875,6 +875,19 @@ class DiagramAlgebra(CombinatorialFreeModule): P{{-2, 1, 2}, {-1}}, P{{-2, 2}, {-1}, {1}}, P{{-2, 2}, {-1, 1}}] + + Due to the nature of diagrams, there is also a built-in coercion to turn + SymmetricGroupAlgebra elements into DiagramAlgebra elements. However, + this coercion can cause errors if the SymmetricGroupAlgebra element + is not actually valid in the algebra. For instance, not all + SymmetricGroupAlgebra elements are valid in the Temperely--Lieb algebra, + but the planar ones are. + + :: + + sage: S = SymmetricGroupAlgebra(R, 2) + sage: S([2,1])*D([[1,-1],[2,-2]]) + P{{-2, 1}, {-1, 2}} """ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): r""" From e7cdb761c726d3a3ea526e9ac806ee2451ff2a99 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 9 Jul 2015 14:12:33 +0200 Subject: [PATCH 0294/1872] Add a gp2c optional package --- build/pkgs/gp2c/SPKG.txt | 18 ++++++++++++++++++ build/pkgs/gp2c/checksums.ini | 4 ++++ build/pkgs/gp2c/dependencies | 5 +++++ build/pkgs/gp2c/package-version.txt | 1 + build/pkgs/gp2c/spkg-check | 3 +++ build/pkgs/gp2c/spkg-install | 24 ++++++++++++++++++++++++ build/pkgs/gp2c/type | 1 + 7 files changed, 56 insertions(+) create mode 100644 build/pkgs/gp2c/SPKG.txt create mode 100644 build/pkgs/gp2c/checksums.ini create mode 100644 build/pkgs/gp2c/dependencies create mode 100644 build/pkgs/gp2c/package-version.txt create mode 100755 build/pkgs/gp2c/spkg-check create mode 100755 build/pkgs/gp2c/spkg-install create mode 100644 build/pkgs/gp2c/type diff --git a/build/pkgs/gp2c/SPKG.txt b/build/pkgs/gp2c/SPKG.txt new file mode 100644 index 00000000000..984b63c7865 --- /dev/null +++ b/build/pkgs/gp2c/SPKG.txt @@ -0,0 +1,18 @@ += gp2c = + +== Description == + +The gp2c compiler is a package for translating GP routines into the C +programming language, so that they can be compiled and used with the PARI +system or the GP calculator. + +== License == + +GPL version 2+ + +== Upstream Contact == + * http://pari.math.u-bordeaux.fr/ + +== Dependencies == + * PARI + * Perl diff --git a/build/pkgs/gp2c/checksums.ini b/build/pkgs/gp2c/checksums.ini new file mode 100644 index 00000000000..0f114ad0f51 --- /dev/null +++ b/build/pkgs/gp2c/checksums.ini @@ -0,0 +1,4 @@ +tarball=gp2c-VERSION.tar.gz +sha1=5acb1a13e1ed8ee877ffb34baa3b817e720f3e50 +md5=cb263990e399153aca6a2540930b4600 +cksum=1931194041 diff --git a/build/pkgs/gp2c/dependencies b/build/pkgs/gp2c/dependencies new file mode 100644 index 00000000000..58cfd0bc484 --- /dev/null +++ b/build/pkgs/gp2c/dependencies @@ -0,0 +1,5 @@ +$(INST)/$(PARI) + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/install into SAGE_ROOT/build/Makefile. diff --git a/build/pkgs/gp2c/package-version.txt b/build/pkgs/gp2c/package-version.txt new file mode 100644 index 00000000000..6eb15535643 --- /dev/null +++ b/build/pkgs/gp2c/package-version.txt @@ -0,0 +1 @@ +0.0.9pl3 diff --git a/build/pkgs/gp2c/spkg-check b/build/pkgs/gp2c/spkg-check new file mode 100755 index 00000000000..9adcda86f90 --- /dev/null +++ b/build/pkgs/gp2c/spkg-check @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +cd src && $MAKE check diff --git a/build/pkgs/gp2c/spkg-install b/build/pkgs/gp2c/spkg-install new file mode 100755 index 00000000000..0346d362ada --- /dev/null +++ b/build/pkgs/gp2c/spkg-install @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +if [ -z "$SAGE_LOCAL" ]; then + echo "SAGE_LOCAL undefined ... exiting" + echo "Maybe run 'sage -sh'?" + exit 1 +fi + +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 + echo >&2 "Error applying '$patch'" + exit 1 + fi +done + +set -e + +./configure --prefix="$SAGE_LOCAL" --with-paricfg="$SAGE_LOCAL/lib/pari/pari.cfg" + +$MAKE install diff --git a/build/pkgs/gp2c/type b/build/pkgs/gp2c/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/gp2c/type @@ -0,0 +1 @@ +optional From fbd976e2b1f92974cb8282b86471fb15ab27d53b Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 9 Jul 2015 14:55:47 +0200 Subject: [PATCH 0295/1872] Add fixes for PARI 2.8 --- build/pkgs/gp2c/patches/20150326.patch | 218 +++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 build/pkgs/gp2c/patches/20150326.patch diff --git a/build/pkgs/gp2c/patches/20150326.patch b/build/pkgs/gp2c/patches/20150326.patch new file mode 100644 index 00000000000..3f7651f8162 --- /dev/null +++ b/build/pkgs/gp2c/patches/20150326.patch @@ -0,0 +1,218 @@ +Various fixes between released version 0.0.9pl3 and gp2c git repo + +diff -ru gp2c-0.0.9pl3/gp2c gp2c/gp2c +--- gp2c-0.0.9pl3/gp2c 2011-10-02 22:28:23.000000000 +0200 ++++ gp2c/gp2c 2015-07-09 14:50:05.600098572 +0200 +@@ -14,4 +14,4 @@ + EOF + exit 1; + fi +-GP2C_FUNC_DSC=desc/func.dsc src/gp2c $* ++GP2C_FUNC_DSC=desc/func.dsc exec src/gp2c "$@" +diff -ru gp2c-0.0.9pl3/gp2c-dbg gp2c/gp2c-dbg +--- gp2c-0.0.9pl3/gp2c-dbg 2011-10-02 22:28:23.000000000 +0200 ++++ gp2c/gp2c-dbg 2015-07-09 14:50:05.601098584 +0200 +@@ -13,4 +13,4 @@ + EOF + exit 1; + fi +-GP2C=./gp2c scripts/gp2c-dbg $* ++GP2C=./gp2c exec scripts/gp2c-dbg "$@" +diff -ru gp2c-0.0.9pl3/gp2c-run gp2c/gp2c-run +--- gp2c-0.0.9pl3/gp2c-run 2011-10-02 22:28:23.000000000 +0200 ++++ gp2c/gp2c-run 2015-07-09 14:50:05.601098584 +0200 +@@ -13,4 +13,4 @@ + EOF + exit 1; + fi +-GP2C=./gp2c scripts/gp2c-run $* ++GP2C=./gp2c exec scripts/gp2c-run "$@" +diff -ru gp2c-0.0.9pl3/src/funcdesc.c gp2c/src/funcdesc.c +--- gp2c-0.0.9pl3/src/funcdesc.c 2014-11-17 14:30:55.000000000 +0100 ++++ gp2c/src/funcdesc.c 2015-07-09 14:50:05.603098609 +0200 +@@ -575,7 +575,8 @@ + gpfunc *gp = lfunc + findfunction(entryname(arg[0])); + if (gp->spec==GPuser && gp->user->wrapper>=0) + { +- if (funcmode(*gp)&(1<user->wrapper; ++ if ((funcmode(*gp)&(1<fout, nb-1,arg+1,FC_tovecprec,d->nerr); + else + { +diff -ru gp2c-0.0.9pl3/src/funcspec.c gp2c/src/funcspec.c +--- gp2c-0.0.9pl3/src/funcspec.c 2014-11-22 22:28:59.000000000 +0100 ++++ gp2c/src/funcspec.c 2015-07-09 14:50:05.604098621 +0200 +@@ -432,8 +432,11 @@ + arg[0] = newleaf(pred); + } + genblock(arg[0],n); +- arg[1]=geninsertvar(arg[1],ret); +- makesubblock(arg[1]); ++ if (arg[1]!=GNOARG) ++ { ++ arg[1]=geninsertvar(arg[1],ret); ++ makesubblock(arg[1]); ++ } + if(nb==3) + { + arg[2]=geninsertvar(arg[2],ret==-1?-1:newleaf(ret)); +diff -ru gp2c-0.0.9pl3/src/genfunc.c gp2c/src/genfunc.c +--- gp2c-0.0.9pl3/src/genfunc.c 2014-12-16 10:56:21.000000000 +0100 ++++ gp2c/src/genfunc.c 2015-07-09 14:50:05.605098633 +0200 +@@ -524,13 +524,15 @@ + } + if (name) + { +- if (i>=nb) +- die(err_func,"too few arguments in lambda"); + fputs(" ",fout); + if (c=='p') + fprintf(fout,"prec"); + else ++ { ++ if (i>=nb) ++ die(err_func,"too few arguments in lambda"); + gencode(fout, name[i++]); ++ } + } + } + if (name && i=nb) +- die(err_func,"too few arguments in lambda"); + if (c=='p') +- fprintf(fout,"prec"); ++ { ++ if (mode&(1<=nb) ++ die(err_func,"too few arguments in lambda"); ++ if (!firstarg) fprintf(fout,", "); ++ firstarg=0; ++ ot = tree[name[i]].t; ++ tree[name[i]].t = t; ++ gencast(fout, name[i], ot); ++ tree[name[i]].t = ot; ++ i++; ++ } + } + if (name && iuser->defnode; + int savc=s_ctx.n; +@@ -650,7 +667,6 @@ + int res; + ctxvar *vres; + context *fc=block+gp->user->bl; +- gpfunc *wr=lfunc+wrap; + gpdescarg *rule; + if (!wr->proto.code) + die(wr->node,"Wrapper not defined"); +@@ -688,7 +704,7 @@ + fprintf(fout," = "); + } + fprintf(fout,"%s(",gp->proto.cname); +- firstarg=genwrapargs(fout, wrap, nb, stack); ++ firstarg=genwrapargs(fout, wrap, nb, stack, m); + for (i=0,d=1;is.n;i++) + { + ctxvar *v=fc->c+i; +diff -ru gp2c-0.0.9pl3/src/printnode.c gp2c/src/printnode.c +--- gp2c-0.0.9pl3/src/printnode.c 2013-10-12 20:32:23.000000000 +0200 ++++ gp2c/src/printnode.c 2015-07-09 14:50:05.606098645 +0200 +@@ -231,6 +231,10 @@ + fprintf(fout,"&"); + printnode(fout,x); + break; ++ case Fvararg: ++ printnode(fout,x); ++ fprintf(fout,"[..]"); ++ break; + case Fcall: + printnode(fout,x); + fprintf(fout,"("); +diff -ru gp2c-0.0.9pl3/src/topfunc.c gp2c/src/topfunc.c +--- gp2c-0.0.9pl3/src/topfunc.c 2014-12-16 10:53:09.000000000 +0100 ++++ gp2c/src/topfunc.c 2015-07-09 14:50:05.606098645 +0200 +@@ -109,7 +109,7 @@ + int nn = newanon(); + int nf = newnode(Fdeffunc,newnode(Ffunction,nn,x),y); + int seq = newnode(Fentry,nn,-1); +- topfunc(n,p,fun,pfun,nf,wr); ++ topfunc(nf,p,fun,pfun,nf,wr); + if (fun>=0) tree[n] = tree[seq]; + } + +diff -ru gp2c-0.0.9pl3/test2/gp/apply.gp gp2c/test2/gp/apply.gp +--- gp2c-0.0.9pl3/test2/gp/apply.gp 2013-06-11 12:02:48.000000000 +0200 ++++ gp2c/test2/gp/apply.gp 2015-07-09 14:50:05.609098682 +0200 +@@ -3,6 +3,7 @@ + f3(f,v)=apply(f,v) + g(x)=x^2+1 + f4(v)=apply(g,v) ++f5(z:small)=apply(n:small->(n+z)!,[1,2,3,4,5]) + + g1(v,z)=select(x->x>z,v) + g2(v)=select(isprime,v) +diff -ru gp2c-0.0.9pl3/test2/input/apply gp2c/test2/input/apply +--- gp2c-0.0.9pl3/test2/input/apply 2013-06-11 12:02:48.000000000 +0200 ++++ gp2c/test2/input/apply 2015-07-09 14:50:05.609098682 +0200 +@@ -2,6 +2,7 @@ + f2([1,2,3,4]) + f3(sqr,[1,2,3,4]) + f4([1,2,3,4]) ++f5(-1) + + g1([1,2,3,4],2) + g2([1,2,3,4]) +diff -ru gp2c-0.0.9pl3/test2/res/apply.res gp2c/test2/res/apply.res +--- gp2c-0.0.9pl3/test2/res/apply.res 2013-06-11 12:02:48.000000000 +0200 ++++ gp2c/test2/res/apply.res 2015-07-09 14:50:05.610098694 +0200 +@@ -2,6 +2,7 @@ + [1, 4, 9, 16] + [1, 4, 9, 16] + [2, 5, 10, 17] ++[1, 1, 2, 6, 24] + [3, 4] + [2, 3] + [2, 3] From 2daa9ae692d1f1fc2d1799aec0b57cae76022e41 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 10 Jul 2015 10:10:14 +0200 Subject: [PATCH 0296/1872] Add a patch to fix global() --- build/pkgs/gp2c/patches/global.patch | 126 +++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 build/pkgs/gp2c/patches/global.patch diff --git a/build/pkgs/gp2c/patches/global.patch b/build/pkgs/gp2c/patches/global.patch new file mode 100644 index 00000000000..dd0c24d0472 --- /dev/null +++ b/build/pkgs/gp2c/patches/global.patch @@ -0,0 +1,126 @@ +Patch taken from upstream to fix global() + +diff --git a/src/genblock.c b/src/genblock.c +index a3582d2..e626e0f 100644 +--- a/src/genblock.c ++++ b/src/genblock.c +@@ -251,7 +251,11 @@ int genblockdeclaration(int args, int n, int flag, int type, int *seq) + /*Make sure GEN objects are gerepilable.*/ + val = newnode(Ftag, newnode(Ftag, newsmall(0), Ggen), tv); + if (decl==global) +- fillvar(var,flag,tv,val); ++ { ++ int f=fillvar(var,flag,tv,-1); ++ if (autogc) ++ affectval(f,val,seq); ++ } + else + pushvar(var,flag,tv,val); + break; +@@ -270,10 +274,12 @@ int genblockdeclaration(int args, int n, int flag, int type, int *seq) + val=newcall("_const_quote",newstringnode(entryname(stack[i]),-1)); + affectval(fillvar(stack[i],flag,mint,-1),val,seq); + } +- else if (autogc) ++ else + { ++ int f = fillvar(stack[i],flag,mint,-1); + /*Make sure (implicitly GEN) objects are gerepilable.*/ +- fillvar(stack[i],flag,mint, newsmall(0)); ++ if (autogc) ++ affectval(f, newsmall(0), seq); + } + break; + case function: +diff --git a/src/topfunc.c b/src/topfunc.c +index 872830e..bff787f 100644 +--- a/src/topfunc.c ++++ b/src/topfunc.c +@@ -154,13 +154,12 @@ static int topfuncproto(int n, int fun, int pfun, int nf) + break; + case 'I': + case 'E': +- if (wr>=-1) +- { +- case 'J': +- seq = newnode(Flambda,var,newleaf(a)); +- tree[a] = tree[seq]; +- topfunclambda(a, n, fun, pfun, wr); +- } ++ if (wr<-1) ++ break; ++ case 'J': /* Fall through */ ++ seq = newnode(Flambda,var,newleaf(a)); ++ tree[a] = tree[seq]; ++ topfunclambda(a, n, fun, pfun, wr); + break; + } + break; +diff --git a/src/toplevel.c b/src/toplevel.c +index f5999c4..23c92a8 100644 +--- a/src/toplevel.c ++++ b/src/toplevel.c +@@ -120,7 +120,7 @@ void gentoplevel(int n) + } + else + gentoplevel(x); +- if (y>=0 && tree[y].f!=Fdeffunc) ++ if (y>=0 && tree[y].f!=Fdeffunc && tree[y].f!=Fseq) + { + int dy = detag(y); + if (isfunc(dy,"global")) +diff --git a/test/gp/initfunc.gp b/test/gp/initfunc.gp +index 03c1dd3..ed0b87d 100644 +--- a/test/gp/initfunc.gp ++++ b/test/gp/initfunc.gp +@@ -1,4 +1,4 @@ +-global(y:var,n:small=0,m:small,k=2,L:vec,T2) ++global(y:var='y,n:small=0,m:small,k=2,L:vec,T2) + T=clone([4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0]) + T2=clone([4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0]) + L=[]~; +@@ -15,3 +15,10 @@ aff()=print(n," ",m); + M=[1,2;3,4] + print(x^4+k); + pow_M(k)=M^k ++global(x1:int,x2:int); ++global(y1,y2):int; ++global(z1,z2); ++f1(x)=my(z=x^2+1);if(z==1,x1=x,x2=x);z ++f2(x)=my(z=x^2+1);if(z==1,y1=x,y2=x);z ++f3(x)=my(z=x^2+1);if(z==1,z1=x,z2=x);z ++global(t1);t1=0 +diff --git a/test/input/initfunc b/test/input/initfunc +index 8506d08..46a126d 100644 +--- a/test/input/initfunc ++++ b/test/input/initfunc +@@ -2,3 +2,9 @@ init_initfunc(); print(pow_M(2)) + vector(100,i,mybfffo(i)) + vector(31,i,mybfffo(1<<(i-1))) + for(i=1,5,count();aff()) ++init_initfunc();f1(0) ++init_initfunc();f1(1) ++init_initfunc();f2(0) ++init_initfunc();f2(1) ++init_initfunc();f3(0) ++init_initfunc();f3(1) +diff --git a/test/res/initfunc.res b/test/res/initfunc.res +index 391d09d..a1e538c 100644 +--- a/test/res/initfunc.res ++++ b/test/res/initfunc.res +@@ -13,3 +13,15 @@ x^4 + 2 + 3 30 + 4 30 + 5 29 ++x^4 + 2 ++1 ++x^4 + 2 ++2 ++x^4 + 2 ++1 ++x^4 + 2 ++2 ++x^4 + 2 ++1 ++x^4 + 2 ++2 From c9125e118a46737c51400bbae469a6aa62b3014b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 12 Jul 2015 21:11:56 -0700 Subject: [PATCH 0297/1872] Implement better type recognition using (di)graph isomorphism testing. --- .../combinat/root_system/cartan_matrix.py | 154 ++++--- src/sage/combinat/root_system/cartan_type.py | 14 + .../combinat/root_system/coxeter_matrix.py | 384 +++++------------- src/sage/combinat/root_system/coxeter_type.py | 26 +- 4 files changed, 226 insertions(+), 352 deletions(-) diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index 1512d48d554..dc9e41fd976 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -34,6 +34,7 @@ from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family +from sage.graphs.digraph import DiGraph class CartanMatrix(Matrix_integer_sparse, CartanType_abstract): r""" @@ -265,12 +266,6 @@ def __classcall_private__(cls, data=None, index_set=None, if not is_generalized_cartan_matrix(M): raise ValueError("the input matrix is not a generalized Cartan matrix") n = M.ncols() - if cartan_type is not None: - cartan_type = CartanType(cartan_type) - elif n == 1: - cartan_type = CartanType(['A', 1]) - elif cartan_type_check: - cartan_type = find_cartan_type_from_matrix(M) data = M.dict() subdivisions = M._subdivisions @@ -280,24 +275,39 @@ def __classcall_private__(cls, data=None, index_set=None, if len(index_set) != n and len(set(index_set)) != n: raise ValueError("the given index set is not valid") - mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, cartan_type, index_set) + # We can do the Cartan type initialization later as this is not + # a unqiue representation + mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, False, False) + # FIXME: We have to initialize the CartanMatrix part separately because + # of the __cinit__ of the matrix. We should get rid of this workaround + mat._CM_init(cartan_type, index_set, cartan_type_check) mat._subdivisions = subdivisions return mat - def __init__(self, parent, data, cartan_type, index_set): + def _CM_init(self, cartan_type, index_set, cartan_type_check): """ - Initialize ``self``. + Initialize ``self`` as a Cartan matrix. TESTS:: - sage: C = CartanMatrix(['A',1,1]) + sage: C = CartanMatrix(['A',1,1]) # indirect doctest sage: TestSuite(C).run(skip=["_test_category", "_test_change_ring"]) """ - Matrix_integer_sparse.__init__(self, parent, data, False, False) - self._cartan_type = cartan_type self._index_set = index_set self.set_immutable() + if cartan_type is not None: + cartan_type = CartanType(cartan_type) + elif self.nrows() == 1: + cartan_type = CartanType(['A', 1]) + elif cartan_type_check: + # Placeholder so we don't have to reimplement creating a + # Dynkin diagram from a Cartan matrix + self._cartan_type = None + cartan_type = find_cartan_type_from_matrix(self) + + self._cartan_type = cartan_type + def __reduce__(self): """ Used for pickling. @@ -879,64 +889,84 @@ def is_generalized_cartan_matrix(M): return True def find_cartan_type_from_matrix(CM): - """ - Find a Cartan type by direct comparison of matrices given from the - generalized Cartan matrix ``CM`` and return ``None`` if not found. + r""" + Find a Cartan type by direct comparison of Dynkin diagrams given from + the generalized Cartan matrix ``CM`` and return ``None`` if not found. INPUT: - - ``CM`` -- A generalized Cartan matrix + - ``CM`` -- a generalized Cartan matrix EXAMPLES:: sage: from sage.combinat.root_system.cartan_matrix import find_cartan_type_from_matrix - sage: M = matrix([[2,-1,-1], [-1,2,-1], [-1,-1,2]]) - sage: find_cartan_type_from_matrix(M) + sage: CM = CartanMatrix([[2,-1,-1], [-1,2,-1], [-1,-1,2]]) + sage: find_cartan_type_from_matrix(CM) ['A', 2, 1] - sage: M = matrix([[2,-1,0], [-1,2,-2], [0,-1,2]]) - sage: find_cartan_type_from_matrix(M) - ['C', 3] - sage: M = matrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]]) - sage: find_cartan_type_from_matrix(M) + sage: CM = CartanMatrix([[2,-1,0], [-1,2,-2], [0,-1,2]]) + sage: find_cartan_type_from_matrix(CM) + ['C', 3] relabelled by {1: 0, 2: 1, 3: 2} + sage: CM = CartanMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]]) + sage: find_cartan_type_from_matrix(CM) """ - n = CM.ncols() - # Build the list to test based upon rank - if n == 1: - return CartanType(['A', 1]) - - test = [['A', n]] - if n >= 2: - if n == 2: - test += [['G',2], ['A',2,2]] - test += [['B',n], ['A',n-1,1]] - if n >= 3: - if n == 3: - test += [['G',2,1], ['D',4,3]] - test += [['C',n], ['BC',n-1,2], ['C',n-1,1]] - if n >= 4: - if n == 4: - test += [['F',4], ['G',2,1], ['D',4,3]] - test += [['D',n], ['B',n-1,1]] - if n == 5: - test += [['F',4,1], ['D',n-1,1]] - elif n == 6: - test.append(['E',6]) - elif n == 7: - test += [['E',7], ['E',6,1]] - elif n == 8: - test += [['E',8], ['E',7,1]] - elif n == 9: - test.append(['E',8,1]) - - # Test every possible Cartan type and its dual - for x in test: - ct = CartanType(x) - if ct.cartan_matrix() == CM: - return ct - if ct == ct.dual(): + types = [] + for S in CM.dynkin_diagram().connected_components_subgraphs(): + S = DiGraph(S) # We need a simple digraph here + n = S.num_verts() + # Build the list to test based upon rank + if n == 1: + types.append(CartanType(['A', 1])) continue - ct = ct.dual() - if ct.cartan_matrix() == CM: - return ct - return None + + test = [['A', n]] + if n >= 2: + if n == 2: + test += [['G',2], ['A',2,2]] + test += [['B',n], ['A',n-1,1]] + if n >= 3: + if n == 3: + test.append(['G',2,1]) + test += [['C',n], ['BC',n-1,2], ['C',n-1,1]] + if n >= 4: + if n == 4: + test.append(['F',4]) + test += [['D',n], ['B',n-1,1]] + if n >= 5: + if n == 5: + test.append(['F',4,1]) + test.append(['D',n-1,1]) + if n == 6: + test.append(['E',6]) + elif n == 7: + test += [['E',7], ['E',6,1]] + elif n == 8: + test += [['E',8], ['E',7,1]] + elif n == 9: + test.append(['E',8,1]) + + # Test every possible Cartan type and its dual + found = False + for x in test: + ct = CartanType(x) + T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here + iso, match = T.is_isomorphic(S, certify=True, edge_labels=True) + if iso: + types.append(ct.relabel(match)) + found = True + break + + if ct == ct.dual(): + continue # self-dual, so nothing more to test + + ct = ct.dual() + T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here + iso, match = T.is_isomorphic(S, certify=True, edge_labels=True) + if iso: + types.append(ct.relabel(match)) + found = True + break + if not found: + return None + + return CartanType(types) diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 7efc2e2c514..7c8bf0cac1f 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -602,6 +602,16 @@ def __call__(self, *args): True sage: CartanType('A2') ['A', 2] + + Check that we can pass any Cartan type as a single element list:: + + sage: CT = CartanType(['A2', 'A2', 'A2']) + sage: CartanType([CT]) + A2xA2xA2 + + sage: CT = CartanType('A2').relabel({1:-1, 2:-2}) + sage: CartanType([CT]) + ['A', 2] relabelled by {1: -1, 2: -2} """ if len(args) == 1: t = args[0] @@ -615,6 +625,10 @@ def __call__(self, *args): if len(t) == 1: # Fix for trac #13774 t = t[0] + # We need to make another check + if isinstance(t, CartanType_abstract): + return t + if isinstance(t, str): if "x" in t: import type_reducible diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index d18a958c3b2..1ae4343a51b 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -263,23 +263,23 @@ def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): TESTS:: - sage: CM = CoxeterMatrix([[1,2],[2,1]]);CM + sage: CM = CoxeterMatrix([[1,2],[2,1]]); CM [1 2] [2 1] - sage: CM = CoxeterMatrix([[1,-1],[-1,1]]);CM + sage: CM = CoxeterMatrix([[1,-1],[-1,1]]); CM [ 1 -1] [-1 1] - sage: CM = CoxeterMatrix([[1,-1.5],[-1.5,1]]);CM + sage: CM = CoxeterMatrix([[1,-1.5],[-1.5,1]]); CM [ 1.00000000000000 -1.50000000000000] [-1.50000000000000 1.00000000000000] - sage: CM = CoxeterMatrix([[1,-3/2],[-3/2,1]]);CM + sage: CM = CoxeterMatrix([[1,-3/2],[-3/2,1]]); CM [ 1 -3/2] [-3/2 1] - sage: CM = CoxeterMatrix([[1,-3/2,5],[-3/2,1,-1],[5,-1,1]]);CM + sage: CM = CoxeterMatrix([[1,-3/2,5],[-3/2,1,-1],[5,-1,1]]); CM [ 1 -3/2 5] [-3/2 1 -1] [ 5 -1 1] - sage: CM = CoxeterMatrix([[1,-3/2,5],[-3/2,1,oo],[5,oo,1]]);CM + sage: CM = CoxeterMatrix([[1,-3/2,5],[-3/2,1,oo],[5,oo,1]]); CM [ 1 -3/2 5] [-3/2 1 -1] [ 5 -1 1] @@ -296,7 +296,7 @@ def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): if n == 1: coxeter_type = CoxeterType(['A', 1]) elif coxeter_type_check: - coxeter_type = recognize_coxeter_type_from_matrix(M) + coxeter_type = recognize_coxeter_type_from_matrix(M, index_set) else: coxeter_type = None @@ -448,13 +448,14 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - [ 1 -2] - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], [-2 1], + [ 1 -1 -1] + [-1 1 -1] + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], [-1 -1 1], - [ 1 -2 3 2] - [ 1 -1 -1] [1 2 3] [-2 1 2 3] - [-1 1 -1] [2 1 7] [ 3 2 1 -8] - [-1 -1 1], [3 7 1], [ 2 3 -8 1] + [ 1 -2 3 2] + [1 2 3] [-2 1 2 3] + [2 1 7] [ 3 2 1 -8] + [3 7 1], [ 2 3 -8 1] ] The finite, affine and crystallographic options allow @@ -489,10 +490,10 @@ def samples(self, finite=None, affine=None, crystallographic=None, higher_rank=N sage: CoxeterMatrix.samples(crystallographic=False) [ - [1 3 2 2] - [1 3 2] [3 1 3 2] [ 1 -1 -1] [1 2 3] - [3 1 5] [2 3 1 5] [ 1 10] [ 1 -1] [ 1 -2] [-1 1 -1] [2 1 7] - [2 5 1], [2 2 5 1], [10 1], [-1 1], [-2 1], [-1 -1 1], [3 7 1], + [1 3 2 2] + [1 3 2] [3 1 3 2] [ 1 -1 -1] [1 2 3] + [3 1 5] [2 3 1 5] [ 1 10] [ 1 -1] [-1 1 -1] [2 1 7] + [2 5 1], [2 2 5 1], [10 1], [-1 1], [-1 -1 1], [3 7 1], [ 1 -2 3 2] [-2 1 2 3] @@ -548,13 +549,14 @@ def _samples(self): Coxeter type of ['E', 8, 1], Coxeter type of ['F', 4, 1], - [ 1 -2] - Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], [-2 1], + [ 1 -1 -1] + [-1 1 -1] + Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1], [-1 -1 1], - [ 1 -2 3 2] - [ 1 -1 -1] [1 2 3] [-2 1 2 3] - [-1 1 -1] [2 1 7] [ 3 2 1 -8] - [-1 -1 1], [3 7 1], [ 2 3 -8 1] + [ 1 -2 3 2] + [1 2 3] [-2 1 2 3] + [2 1 7] [ 3 2 1 -8] + [3 7 1], [ 2 3 -8 1] ] """ finite = [CoxeterMatrix(t) for t in [['A', 1], ['A', 5], ['B', 5], @@ -567,10 +569,9 @@ def _samples(self): ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['A', 1, 1]]] - higher_matrices = [[[1, -2], [-2, 1]], - [[1, -1, -1], [-1, 1, -1], [-1, -1, 1]], - [[1, 2, 3], [2, 1, 7], [3, 7, 1]], - [[1, -2, 3, 2], [-2, 1, 2, 3], [3, 2, 1, -8], [2, 3, -8, 1]]] + higher_matrices = [[[1, -1, -1], [-1, 1, -1], [-1, -1, 1]], + [[1, 2, 3], [2, 1, 7], [3, 7, 1]], + [[1, -2, 3, 2], [-2, 1, 2, 3], [3, 2, 1, -8], [2, 3, -8, 1]]] higher = [CoxeterMatrix(m) for m in higher_matrices] @@ -865,7 +866,7 @@ def coxeter_graph(self): val = lambda x: infinity if x == -1 else x G = Graph([(I[i], I[j], val((self._matrix)[i, j])) for i in range(n) for j in range(i) - if (self._matrix)[i, j] not in [1, 2]]) + if self._matrix[i, j] not in [1, 2]]) G.add_vertices(I) return G.copy(immutable = True) @@ -947,7 +948,7 @@ def is_affine(self): ##################################################################### ## Type check functions -def recognize_coxeter_type_from_matrix(coxeter_matrix): +def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set): """ Return the Coxeter type of ``coxeter_matrix`` if known, otherwise return ``None``. @@ -1020,278 +1021,87 @@ def recognize_coxeter_type_from_matrix(coxeter_matrix): sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2, 1] - TESTS:: + TESTS: + + Check that we detect relabellings:: + + sage: M = CoxeterMatrix([[1,2,3],[2,1,6],[3,6,1]], index_set=['a', 'b', 'c']) + sage: M.coxeter_type() + Coxeter type of ['G', 2, 1] relabelled by {0: 'a', 1: 'b', 2: 'c'} sage: from sage.combinat.root_system.coxeter_matrix import recognize_coxeter_type_from_matrix sage: for C in CoxeterMatrix.samples(): ....: relabelling_perm = Permutations(C.index_set()).random_element() ....: relabelling_dict = {C.index_set()[i]: relabelling_perm[i] for i in range(C.rank())} ....: relabeled_matrix = C.relabel(relabelling_dict)._matrix - ....: recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix) + ....: recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix, relabelling_perm) ....: if C.is_finite() or C.is_affine(): ....: assert recognized_type == C.coxeter_type() - """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) - G = Graph([range(n), lambda i, j: coxeter_matrix[i, j] not in [1, 2]]) - # Coxeter graphs of finite Coxeter groups are forests - # Coxeter graphs of affine Coxeter groups are forests possibly with cycle - # graphs - - comps = G.connected_components() - # The group is finite if and only if for every connected - # component ``comp`` of its Coxeter graph, the submatrix of - # the Coxeter matrix corresponding to ``comp`` is one of the - # type-A,B,D,E,F,H,I matrices (up to permutation). So we - # shall check this condition on every ``comp``. - types = [] - for comp in comps: - l = len(comp) - G0 = G.subgraph(comp) - if l == 1: - # Any `1 \times 1` Coxeter matrix gives a finite group. - types.append(['A', 1]) - continue # A1 - elif l == 2: - # A finite dihedral group iff there is no `\infty` in its - # Coxeter matrix. Otherwise it is affine iff the - # off-diagonal value is -1. - c0, c1 = comp - if coxeter_matrix[c0, c1] > 0: - types.append(['I', coxeter_matrix[c0, c1]]) - continue - elif coxeter_matrix[c0, c1] == -1: - types.append(['A', 1, 1]) - continue - else: - return None # TODO: return hyperbolic type once implemented - elif l == 3: - # The `3`-node case. The finite groups to check for - # here are `A_3`, `B_3` and `H_3`. - # The affine groups to check for here are `A_{2,1}`, `G_{2,1}`, - # `B_{2,1}`. - c0, c1, c2 = comp - s = sorted([coxeter_matrix[c0, c1], - coxeter_matrix[c0, c2], - coxeter_matrix[c1, c2]]) - if s[0] == 2: # Have a tree - if s[1] == 3: - if s[2] == 3: - types.append(['A', 3]) - continue - elif s[2] == 4: - types.append(['B', 3]) - continue - elif s[2] == 5: - types.append(['H', 3]) - continue - elif s[2] == 6: - types.append(['G', 2, 1]) - continue - else: - return None - elif s[1] == 4 and s[2] == 4: - types.append(['B', 2, 1]) - continue - else: - return None - elif s[0] == 3 and s[1] == 3 and s[2] == 3: - types.append(['A', 2, 1]) - continue - else: # Have a hyperbolic type of rank 3 - return None - elif l == 4: - # The `4`-node case. The finite groups to check for - # here are `A_4`, `B_4`, `D_4`, `F_4` and `H_4`. - # The affine groups to check for here are `A_{3,1}`, `B_{3,1}`, - # and `C_{3,1}`. - - c0, c1, c2, c3 = comp - u = [coxeter_matrix[c0, c1], - coxeter_matrix[c0, c2], - coxeter_matrix[c0, c3], - coxeter_matrix[c1, c2], - coxeter_matrix[c1, c3], - coxeter_matrix[c2, c3]] - s = sorted(u) - # ``s`` is the list of all off-diagonal entries of - # the ``comp``-submatrix of the Coxeter matrix, - # sorted in increasing order. - - if s[:3] == [2, 2, 2]: - if s[3:] == [3, 3, 3]: - if max(G0.degree()) == 2: - types.append(['A', 4]) - continue - else: - types.append(['D', 4]) - continue - elif s[3:] == [3, 3, 4] or s[3:] == [3, 3, 5] or s[3:] == [3, - 4, 4]: - if max(G0.degree()) == 3: - if s[4:] == [3, 4]: - types.append(['B', 3, 1]) - continue - else: - return None - else: # The graph is a path - # Differenciate using sum of edge labels - u0 = u[0] + u[1] + u[2] - u1 = u[0] + u[3] + u[4] - u2 = u[1] + u[3] + u[5] - u3 = u[2] + u[4] + u[5] - ss = sorted([u0, u1, u2, u3]) - if s[5] == 4: - if ss == [7, 7, 9, 9]: - types.append(['F', 4]) - continue - elif ss == [7, 8, 8, 9]: - types.append(['B', 4]) - continue - elif ss == [8, 8, 9, 9]: - types.append(['C', 3, 1]) - continue - else: - return None - elif ss == [7, 8, 9, 10]: - types.append(['H', 4]) - continue - else: - return None + G = Graph([[index_set[i], index_set[j], coxeter_matrix[i, j]] + for i in range(n) for j in range(i,n) + if coxeter_matrix[i, j] not in [1, 2]]) + G.add_vertices(index_set) - else: - return None - - elif s == [2, 2, 3, 3, 3, 3] and max(G0.degree()) == 2: - types.append(['A', 3, 1]) - continue + types = [] + for S in G.connected_components_subgraphs(): + r = S.num_verts() + # Handle the special cases first + if r == 1: + types.append(CoxeterType(['A',1]).relabel({1: S.vertices()[0]})) + continue + if r == 2: # Type B2, G2, or I_2(p) + e = S.edge_labels()[0] + if e == 3: # Can't be 2 because it is connected + ct = CoxeterType(['B',2]) + elif e == 4: + ct = CoxeterType(['G',2]) + elif e > 0 and e < float('inf'): # Remaining non-affine types + ct = CoxeterType(['I',e]) + else: # Otherwise it is infinite dihedral group Z_2 \ast Z_2 + ct = CoxeterType(['A',1,1]) + if not ct.is_affine(): + types.append(ct.relabel({1: S.vertices()[0], 2: S.vertices()[1]})) else: - return None + types.append(ct.relabel({0: S.vertices()[0], 1: S.vertices()[1]})) + continue + + test = [['A',r], ['B',r], ['A',r-1,1]] + if r >= 3: + if r == 3: + test += [['G',2,1], ['H',3]] + test.append(['C',r-1,1]) + if r >= 4: + if r == 4: + test += [['F',4], ['H',4]] + test += [['D',r], ['B',r-1,1]] + if r >= 5: + if r == 5: + test.append(['F',4,1]) + test.append(['D',r-1,1]) + if r == 6: + test.append(['E',6]) + elif r == 7: + test += [['E',7], ['E',6,1]] + elif r == 8: + test += [['E',8], ['E',7,1]] + elif r == 9: + test.append(['E',8,1]) + + found = False + for ct in test: + ct = CoxeterType(ct) + T = ct.coxeter_graph() + iso, match = T.is_isomorphic(S, certify=True, edge_labels=True) + if iso: + types.append(ct.relabel(match)) + found = True + break + if not found: return None - else: - # The case of `l \geq 5` nodes. The finite - # groups to check for here are `A_l`, `B_l`, `D_l`, - # and `E_l` (for `l = 6, 7, 8`). - - # The affine groups to check for here are `A_{l-1,1}`, `B_{l-1,1}`, - # `C_{l-1,1}`, `D_{l-1,1}`, `E_{l_1,1}` (for `l = 6, 7, 8`), - # or `F_{4,1}`. - - degrees = G0.degree() - vertices = G0.vertices() - sub_cox_matrix = coxeter_matrix.matrix_from_rows_and_columns(vertices, vertices) - vertices_labels = [set(filter(lambda x: x != 1, r)) for r in - sub_cox_matrix.rows()] - label_list = filter(lambda x: x != 1, sub_cox_matrix.list()) - labels = sorted(set(label_list)) - - vertices_4 = [index for index in range(l) if 4 in - vertices_labels[index]] - occur_4 = label_list.count(4)/2 # Each label appear twice - - if not G0.is_tree(): - if G0.is_isomorphic(CycleGraph(l)): # Type `A_{l-1,1}` - types.append(['A', l-1, 1]) - continue - else: - return None - - elif max(degrees) == 2: # The component is a path - - if labels[-1] == 3: # Highest label is 3 - types.append(['A', l]) - continue - elif labels[-1] == 4: # Highest label is 4 - - if occur_4 == 1: # There is 1 edge with label 4 - if not (3 in vertices_labels[vertices_4[0]] and 3 in - vertices_labels[vertices_4[1]]): # The edge is at the end of the path - types.append(['B', l]) - continue - elif l == 5: - types.append(['F', 4, 1]) - continue - else: - return None - elif occur_4 == 2: # There are 2 edges labeled 4 - if len(filter(lambda x: 2 in x and 3 not in x and 4 in - x, [vertices_labels[i] for i in vertices_4])) == 2: - # The edges with 4 are at the ends of the path - types.append(['C', l-1, 1]) - continue - else: - return None - else: - return None - - else: # The graph contains branching vertices - - #Finite D_n,E_6,E_7,E_8 - #Affine B_n,D_n, E_6,E_7,E_8 - - if max(degrees) == 3: # Branching degree is 3 - - highest_label = labels[-1] - - nb_branching = degrees.count(3) - ecc = sorted(G0.eccentricity()) - - if nb_branching == 1: - - if highest_label == 3: - - if ecc[-3] == l - 2: - types.append(['D', l]) - continue # Dl - elif l <= 9 and ecc[-2] == l - 2 and ecc[-5] == l - 3: - if l <= 8: # E_{6,7,8} - types.append(['E', l]) - continue - else: # E_{8,1} - types.append(['E', l-1, 1]) - continue - elif l <= 8 and ecc[0] == l-5 and ecc[-3] == l-3: - # TO TEST - types.append(['E', l-1, 1]) - continue - else: - return None - - elif highest_label == 4: - if ecc[-3] == l - 2 and occur_4 == 1: # D_n graph - # and 1 occurence of label 4 - if not (3 in vertices_labels[vertices_4[0]] and 3 in vertices_labels[vertices_4[1]]) and 3 not in G0.degree(vertices=vertices_4): - # Edge with label 4 is at the end and not - # on a degree 3 vertex. - types.append(['B', l-1, 1]) - continue - else: - return None - else: - return None - else: - return None - - elif nb_branching == 2: - if highest_label == 3: - if ecc[-4] == l - 3: - types.append(['D', l-1, 1]) - continue - else: - return None - - else: # Highest label too high - return None - - else: # Nb of branching too high - return None - - else: # Branching degree too high - return None - - if len(types) == 1: - types = types[0] + return CoxeterType(types) ##################################################################### diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 11edd8622aa..37fe46d679f 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -35,7 +35,7 @@ class CoxeterType(SageObject): __metaclass__ = ClasscallMetaclass @staticmethod - def __classcall_private__(cls, x): + def __classcall_private__(cls, *x): """ Parse input ``x``. @@ -44,6 +44,9 @@ def __classcall_private__(cls, x): sage: CoxeterType(['A',3]) Coxeter type of ['A', 3] """ + if len(x) == 1: + x = x[0] + if isinstance(x, CoxeterType): return x @@ -52,6 +55,9 @@ def __classcall_private__(cls, x): except (ValueError, TypeError): pass + if len(x) == 1: # In case the input is similar to CoxeterType([['A',2]]) + return CoxeterType(x[0]) + raise NotImplementedError("Coxeter types not from Cartan types not yet implemented") @classmethod @@ -322,7 +328,8 @@ def is_simply_laced(self): [['C', 1], True], [['C', 5], False], [['D', 2], True], [['D', 3], True], [['D', 5], True], [['E', 6], True], [['E', 7], True], [['E', 8], True], - [['F', 4], False], [['G', 2], False], [['I', 5], False], [['H', 3], False], [['H', 4], False], + [['F', 4], False], [['G', 2], False], + [['I', 5], False], [['H', 3], False], [['H', 4], False], [['A', 1, 1], False], [['A', 5, 1], True], [['B', 1, 1], False], [['B', 5, 1], False], [['C', 1, 1], False], [['C', 5, 1], False], @@ -330,7 +337,8 @@ def is_simply_laced(self): [['E', 6, 1], True], [['E', 7, 1], True], [['E', 8, 1], True], [['F', 4, 1], False], [['G', 2, 1], False], [['BC', 1, 2], False], [['BC', 5, 2], False], - [['B', 5, 1]^*, False], [['C', 4, 1]^*, False], [['F', 4, 1]^*, False], [['G', 2, 1]^*, False], + [['B', 5, 1]^*, False], [['C', 4, 1]^*, False], + [['F', 4, 1]^*, False], [['G', 2, 1]^*, False], [['BC', 1, 2]^*, False], [['BC', 5, 2]^*, False]] """ return False @@ -555,3 +563,15 @@ def is_simply_laced(self): """ return self._cartan_type.is_simply_laced() + def relabel(self, relabelling): + """ + Return a relabelled copy of ``self``. + + EXAMPLES:: + + sage: ct = CoxeterType(['A',2]) + sage: ct.relabel({1:-1, 2:-2}) + Coxeter type of ['A', 2] relabelled by {1: -1, 2: -2} + """ + return CoxeterType(self._cartan_type.relabel(relabelling)) + From 30f68ce7697bbeafb7c0bf0d02915cd1943c0e51 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 12 Jul 2015 23:48:13 -0700 Subject: [PATCH 0298/1872] Created a category for BialgebrasWithBasis. --- src/sage/categories/bialgebras.py | 4 ++++ src/sage/categories/bialgebras_with_basis.py | 13 ++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index e78f080ef18..50129155bb8 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -11,6 +11,7 @@ from sage.categories.category_types import Category_over_base_ring from sage.categories.all import Algebras, Coalgebras +from sage.misc.lazy_import import LazyImport class Bialgebras(Category_over_base_ring): """ @@ -61,3 +62,6 @@ class ParentMethods: class ElementMethods: pass + + WithBasis = LazyImport('sage.categories.bialgebras_with_basis', 'BialgebrasWithBasis') + diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index 0487c0db3a3..eb6fd332a2a 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -9,7 +9,9 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -def BialgebrasWithBasis(base_ring): +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring + +class BialgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ The category of bialgebras with a distinguished basis. @@ -27,6 +29,11 @@ def BialgebrasWithBasis(base_ring): sage: TestSuite(BialgebrasWithBasis(ZZ)).run() """ - from sage.categories.all import Bialgebras - return Bialgebras(base_ring).WithBasis() + class ParentMethods: + def foo(self): + return 'bar' + + class ElementMethods: + def bar(self): + return 'foo fighters' From 84d2af35beef9637136ae6e437d8b069baeb261e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 13 Jul 2015 00:47:07 -0700 Subject: [PATCH 0299/1872] Changed name left_top -> left_column_box. --- .../rigged_configuration_element.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py index 26d41166be2..26c840b3ece 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py +++ b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py @@ -1818,9 +1818,9 @@ def left_box(self, return_b=False): delta = left_box - def left_top(self): + def left_column_box(self): r""" - Return the image of ``self`` under the left column top splitting + Return the image of ``self`` under the left column box splitting map `\gamma`. Consider the map `\gamma : RC(B^{r,1} \otimes B) \to RC(B^{1,1} @@ -1838,7 +1838,7 @@ def left_top(self): sage: ascii_art(mg) 0[ ]0 0[ ][ ]0 0[ ]0 0[ ]0 0[ ]0 - sage: ascii_art(mg.left_top()) + sage: ascii_art(mg.left_column_box()) 0[ ]0 0[ ][ ]0 0[ ]0 0[ ]0 0[ ]0 0[ ]0 0[ ]0 @@ -1848,7 +1848,7 @@ def left_top(self): sage: ascii_art(mg) 1[ ]0 0[ ][ ]0 0[ ]0 0[ ]0 0[ ]0 - sage: ascii_art(mg.left_top()) + sage: ascii_art(mg.left_column_box()) 1[ ]1 0[ ][ ]0 0[ ]0 1[ ]0 0[ ]0 0[ ]0 """ @@ -1865,7 +1865,7 @@ def left_top(self): raise ValueError("only for non-spinor cases") if P.dims[0][1] > 1: - return self.left_split().left_top() + return self.left_split().left_column_box() B = [[1,1], [r-1,1]] B.extend(P.dims[1:]) @@ -1881,9 +1881,9 @@ def left_top(self): nu.rigging.insert(i, vac_num) return RC(*parts) - def right_bottom(self): + def right_column_box(self): r""" - Return the image of ``self`` under the right column bottom splitting + Return the image of ``self`` under the right column box splitting map `\gamma^*`. Consider the map `\gamma^* : RC(B \otimes B^{r,1}) \to RC(B \otimes @@ -1903,7 +1903,7 @@ def right_bottom(self): sage: ascii_art(mg) 1[ ]0 0[ ][ ]0 0[ ]0 0[ ]0 0[ ]0 - sage: ascii_art(mg.right_bottom()) + sage: ascii_art(mg.right_column_box()) 1[ ]0 0[ ][ ]0 0[ ]0 1[ ]0 0[ ]0 0[ ]0 0[ ]0 @@ -1921,7 +1921,7 @@ def right_bottom(self): raise ValueError("only for non-spinor cases") if P.dims[-1][1] > 1: - return self.right_split().right_bottom() + return self.right_split().right_column_box() rc, e_string = self.to_highest_weight(P.cartan_type().classical().index_set()) From 4882aae5206a2d0bdf18cff8a1ccce60aa8e4dba Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 15 Jul 2015 00:03:39 +0200 Subject: [PATCH 0300/1872] fixed errors from refactoring asymptotic terms --- src/sage/rings/asymptotic_ring.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 924fe36947e..e0f2957d0c8 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -317,16 +317,16 @@ def _element_constructor_(self, data, poset=None): else: from sage.data_structures.mutable_poset import MutablePoset from sage.monoids.asymptotic_term_monoid import \ - _can_absorb_, _absorption_ + can_absorb, absorption poset = MutablePoset(key=lambda elem: elem.growth, - can_merge=_can_absorb_, - merge=_absorption_) + can_merge=can_absorb, + merge=absorption) return self.element_class(self, poset) from sage.monoids.asymptotic_term_monoid import OTerm, ExactTerm from sage.data_structures.mutable_poset import MutablePoset - from sage.monoids.asymptotic_term_monoid import _can_absorb_, \ - _absorption_ + from sage.monoids.asymptotic_term_monoid import can_absorb, \ + absorption if isinstance(data, (OTerm, ExactTerm)): data = (data,) @@ -334,8 +334,8 @@ def _element_constructor_(self, data, poset=None): data_iter = iter(data) if all(isinstance(elem, (OTerm, ExactTerm)) for elem in data_iter): poset = MutablePoset(key=lambda elem: elem.growth, - can_merge=_can_absorb_, - merge=_absorption_) + can_merge=can_absorb, + merge=absorption) poset = poset.union(data) except: raise TypeError('Input is ambiguous: cannot convert ' From fbbb095e77d18248919100947731646bca5e0c08 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 15 Jul 2015 00:04:49 +0200 Subject: [PATCH 0301/1872] fixed coercion between asymptotic rings with suitable growth groups and coefficient rings --- src/sage/rings/asymptotic_ring.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index e0f2957d0c8..6842abcd47e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -311,6 +311,9 @@ def _element_constructor_(self, data, poset=None): if poset is None: if type(data) == self.element_class and data.parent() == self: return data + elif isinstance(data, AsymptoticExpression): + return self.element_class(self, data.poset) + if data in self.coefficient_ring: if data != 0: return self.create_term('exact', 1, data) From 354011b7307e7015fac07c57ed762d79bb6f7be4 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 15 Jul 2015 00:06:36 +0200 Subject: [PATCH 0302/1872] added @experimental to asymptotic ring --- src/sage/rings/asymptotic_ring.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 6842abcd47e..68e67919076 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -15,6 +15,28 @@ - Benjamin Hackl (2015-06): initial version + +.. WARNING:: + + As this code is experimental, a warning is thrown when an + asymptotic ring (or an associated structure) is created for the + first time in a session (see + :class:`sage.misc.superseded.experimental`). + + TESTS:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.monoids.asymptotic_term_monoid as atm + sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + 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/17600 for details. + sage: T = atm.ExactTermMonoid(G, ZZ) + 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/17715 for details. + sage: R. = AsymptoticRing('monomial', ZZ) + 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/17716 for details. + """ # ***************************************************************************** @@ -220,6 +242,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, coefficient_ring, category) + @sage.misc.superseded.experimental(trac_number=17716) def __init__(self, growth_group=None, coefficient_ring=None, category=None): r""" ... From be7a77d0ecc093edc40c51c88a4c9c70d6d33832 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 15 Jul 2015 18:28:38 +0200 Subject: [PATCH 0303/1872] added a flag for automatic simplification of expressions --- src/sage/rings/asymptotic_ring.py | 45 ++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 68e67919076..c1980b2bdc8 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -55,15 +55,13 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): r""" ... """ - def __init__(self, parent, poset): + def __init__(self, parent, poset, simplify=True): r""" ... """ - for shell in poset.shells_topological(reverse=True): - from sage.monoids.asymptotic_term_monoid import OTerm - if isinstance(shell.element, OTerm) and shell.element.growth in poset: - poset.merge(shell.key) self._poset_ = poset + if simplify: + self._simplify_() super(AsymptoticExpression, self).__init__(parent=parent) @@ -74,6 +72,35 @@ def poset(self): """ return self._poset_ + + def _simplify_(self): + r""" + Simplify this asymptotic expression. + + INPUT: + + Nothing. + + OUTPUT: + + An :class:`AsymptoticExpression`. + + .. NOTE:: + + This asymptotic expression is simplified by letting + `O`-terms that are included in this expression absorb all + terms of lesser growth. + + TESTS:: + + """ + from sage.monoids.asymptotic_term_monoid import OTerm + for shell in self.poset.shells_topological(reverse=True): + if shell.element.growth in self.poset and isinstance(shell.element, + OTerm): + self.poset.merge(shell.key) + + def _repr_(self, reverse=False): r""" A representation string for this asymptotic expression. @@ -302,7 +329,7 @@ def coefficient_ring(self): return self._coefficient_ring_ - def _element_constructor_(self, data, poset=None): + def _element_constructor_(self, data, poset=None, simplify=True): r""" Converts a given object to this asymptotic ring. @@ -335,7 +362,7 @@ def _element_constructor_(self, data, poset=None): if type(data) == self.element_class and data.parent() == self: return data elif isinstance(data, AsymptoticExpression): - return self.element_class(self, data.poset) + return self.element_class(self, data.poset, simplify) if data in self.coefficient_ring: if data != 0: @@ -347,7 +374,7 @@ def _element_constructor_(self, data, poset=None): poset = MutablePoset(key=lambda elem: elem.growth, can_merge=can_absorb, merge=absorption) - return self.element_class(self, poset) + return self.element_class(self, poset, simplify) from sage.monoids.asymptotic_term_monoid import OTerm, ExactTerm from sage.data_structures.mutable_poset import MutablePoset @@ -367,7 +394,7 @@ def _element_constructor_(self, data, poset=None): raise TypeError('Input is ambiguous: cannot convert ' '%s to an asymptotic expression' % (data,)) - return self.element_class(self, poset) + return self.element_class(self, poset, simplify) def _coerce_map_from_(self, R): From 0715a37aed1893088f472041123257e74b4036aa Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 15 Jul 2015 18:30:09 +0200 Subject: [PATCH 0304/1872] fixed subtraction --- src/sage/rings/asymptotic_ring.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index c1980b2bdc8..a6dfbe9414e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -141,9 +141,20 @@ def _sub_(self, other): OUTPUT: An :class:`AsymptoticExpression`. + + .. NOTE:: + + Subtraction of two asymptotic expressions is implemented + by means of addition: `e_1 - e_2 = e_1 + (-1)\cdot e_2`. + + EXAMPLES:: + + sage: R. = AsymptoticRing('monomial', ZZ) + sage: expr1 = x^123; expr2 = x^321 + sage: expr1 - expr2 # indirect doctest + 1*x^123 + -1*x^321 """ - return self + other._mul_term_( - self.parent().create_term('exact', growth=1, coefficient=-1)) + return self + (-1) * other def _mul_term_(self, other): r""" From 59a2710990da088fd71daafb3cfbb5843ab45153 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 15 Jul 2015 18:31:20 +0200 Subject: [PATCH 0305/1872] improved documentation --- src/sage/rings/asymptotic_ring.py | 136 ++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index a6dfbe9414e..84d9a4da4d3 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -57,7 +57,18 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): """ def __init__(self, parent, poset, simplify=True): r""" - ... + See :class:`AsymptoticExpression` for more information. + + TESTS:: + + sage: R_x. = AsymptoticRing('monomial', ZZ) + sage: R_y. = AsymptoticRing('monomial', ZZ) + sage: R_x is R_y + False + sage: ex1 = x + 2*x^2 + 3*x^3 + 4*x^4 + 5*x^5 + sage: ex2 = x + O(R_x(1)) + sage: ex1 * ex2 + O(x^5) + 5*x^6 """ self._poset_ = poset if simplify: @@ -68,7 +79,14 @@ def __init__(self, parent, poset, simplify=True): @property def poset(self): r""" + The poset of this asymptotic expression. + + EXAMPLES:: + sage: R. = AsymptoticRing('monomial', ZZ) + sage: expr = 7 * x^12 + x^5 + O(x^3) + sage: expr.poset + poset(O(x^3), 1*x^5, 7*x^12) """ return self._poset_ @@ -104,6 +122,29 @@ def _simplify_(self): def _repr_(self, reverse=False): r""" A representation string for this asymptotic expression. + + INPUT: + + - ``reverse`` -- a boolean (default: ``False``). + + OUTPUT: + + A string. + + .. NOTE:: + + By default, the elements with the weakest growth are + printed first. If ``reverse`` is ``True``, then the + printing order is reversed. + + EXAMPLES:: + + sage: R. = AsymptoticRing('monomial', ZZ) + sage: expr = (5*x^2 + 12*x) * (x^3 + O(x)) + sage: repr(expr) # indirect doctest + 'O(x^3) + 12*x^4 + 5*x^5' + sage: expr._repr_(reverse=True) + '5*x^5 + 12*x^4 + O(x^3)' """ s = ' + '.join(repr(elem) for elem in self.poset.elements_topological(include_special=False, @@ -125,6 +166,27 @@ def _add_(self, other): OUTPUT: An :class:`AsymptoticExpression`. + + EXAMPLES:: + sage: R. = AsymptoticRing('monomial', ZZ) + sage: expr1 = x^123; expr2 = x^321 + sage: expr1._add_(expr2) + 1*x^123 + 1*x^321 + sage: expr1 + expr2 # indirect doctest + 1*x^123 + 1*x^321 + + If an `O`-term is added to an asymptotic expression, then + the `O`-term absorbs everything it can:: + + sage: x^123 + x^321 + O(x^555) # indirect doctest + O(x^555) + + TESTS:: + + sage: x + O(x) + O(x) + sage: O(x) + x + O(x) """ pst = self.poset.copy().union(other.poset) return self.parent()(poset=pst) @@ -168,6 +230,16 @@ def _mul_term_(self, other): OUTPUT: An :class:`AsymptoticExpression`. + + TESTS:: + + sage: import sage.monoids.asymptotic_term_monoid as atm + sage: R. = AsymptoticRing('monomial', ZZ) + sage: T = atm.OTermMonoid(R.growth_group) + sage: expr = 10*x^2 + O(x) + sage: t = T(R.growth_group.gen()) + sage: expr._mul_term_(t) + O(x^3) """ return self.parent()([other * elem for elem in self.poset.elements()]) @@ -191,6 +263,14 @@ def _mul_(self, other): multiplication, or methods that exploit the structure of the underlying poset shall be implemented at a later point. + + EXAMPLES:: + + sage: R. = AsymptoticRing('monomial', ZZ) + sage: ex1 = 5*x^12 + sage: ex2 = x^3 + O(x) + sage: ex1 * ex2 # indirect doctest + O(x^13) + 5*x^15 """ return self.parent()(sum(self._mul_term_(term_other) for term_other in other.poset.elements())) @@ -227,7 +307,6 @@ def O(self): - class AsymptoticRing(sage.rings.ring.Ring, sage.structure.unique_representation.UniqueRepresentation): r""" @@ -283,7 +362,25 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, @sage.misc.superseded.experimental(trac_number=17716) def __init__(self, growth_group=None, coefficient_ring=None, category=None): r""" - ... + See :class:`AsymptoticRing` for more information. + + TESTS:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: R1 = AsymptoticRing(G, ZZ); R1 + Asymptotic Ring over Monomial Growth Group in x over Integer Ring with coefficients from Integer Ring + sage: R2. = AsymptoticRing('monomial', QQ); R2 + Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + sage: R1 is R2 + False + + :: + + sage: R3 = AsymptoticRing(G) + Traceback (most recent call last): + ... + TypeError: __classcall__() takes at least 3 arguments (2 given) """ if growth_group is None: raise ValueError('Growth group not specified. Cannot continue.') @@ -342,7 +439,7 @@ def coefficient_ring(self): def _element_constructor_(self, data, poset=None, simplify=True): r""" - Converts a given object to this asymptotic ring. + Convert a given object to this asymptotic ring. INPUT: @@ -536,7 +633,36 @@ def ngens(self): def create_term(self, type, growth=None, coefficient=None): r""" - ... + Create a simple asymptotic expression consisting of a single + term. + + INPUT: + + - ``type`` -- 'O' or 'exact', + + - ``growth`` -- a growth element, + + - ``coefficient`` -- a ring element. + + OUTPUT: + + An asymptotic expression. + + .. NOTE:: + + This method calls the factory + :class:`~sage.monoids.asymptotic_term_monoid.TermMonoid` + with the appropriate arguments. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: R = AsymptoticRing(G, ZZ) + sage: R.create_term('O', x^2) + O(x^2) + sage: R.create_term('exact', x^456, 123) + 123*x^456 """ from sage.monoids.asymptotic_term_monoid import TermMonoid if type == 'O': From 15af0bd55f558504d75e7cb8f62fcc9a40d11913 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 16 Jul 2015 14:52:32 +0200 Subject: [PATCH 0306/1872] implemented __pow__ for asymptotic expressions --- src/sage/rings/asymptotic_ring.py | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 84d9a4da4d3..adf213ee4ec 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -276,6 +276,50 @@ def _mul_(self, other): term_other in other.poset.elements())) + def __pow__(self, power): + r""" + Return this element to the power of ``power``. + + INPUT: + + - ``power`` -- an element. + + OUTPUT: + + An asymptotic expression. + + TESTS:: + + sage: R_QQ. = AsymptoticRing('monomial', QQ) + sage: x^(1/7) + 1*x^(1/7) + sage: R_ZZ. = AsymptoticRing('monomial', ZZ) + sage: y^(1/7) + Traceback (most recent call last): + ... + ValueError: Exponent 1/7 not in base of growth group Monomial Growth Group in y over Integer Ring + sage: (x^(1/2) + O(x^0))^15 + O(x^7) + 1*x^(15/2) + """ + P = self.parent() + if len(self.poset._shells_) == 1: + expr = self.poset.elements().next() + if power in P.growth_group.base(): + from sage.monoids.asymptotic_term_monoid import TermWithCoefficient + if isinstance(expr, TermWithCoefficient): + new_growth = expr.growth ** power + new_coef = expr.coefficient ** power + return P(expr.parent()(new_growth, new_coef)) + else: + new_growth = expr.growth ** power + return P(expr.parent()(new_growth)) + else: + raise ValueError('Exponent %s not in base of growth group %s' % + (power, P.growth_group)) + + return super(AsymptoticExpression, self).__pow__(power) + + def O(self): r""" Convert all terms in this asymptotic expression to `O`-terms. From f2d04482a41c65c597e939dbf6b0a8c3df7aa2ad Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 16 Jul 2015 15:58:36 +0200 Subject: [PATCH 0307/1872] doctests for _simplify_ --- src/sage/rings/asymptotic_ring.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index adf213ee4ec..1c4181af7fb 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -111,6 +111,18 @@ def _simplify_(self): TESTS:: + sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.monoids.asymptotic_term_monoid as atm + sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: OT = atm.TermMonoid('O', G); ET = atm.TermMonoid('exact', G, ZZ) + sage: R = AsymptoticRing(G, ZZ) + sage: lst = [ET(x,1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] + sage: expr = R(lst, simplify=False); expr # indirect doctest + 1*x + 2*x^2 + O(x^3) + 4*x^4 + sage: expr._simplify_(); expr + O(x^3) + 4*x^4 + sage: R(lst) # indirect doctest + O(x^3) + 4*x^4 """ from sage.monoids.asymptotic_term_monoid import OTerm for shell in self.poset.shells_topological(reverse=True): From cd0fc47d17078ddf28a5aecc3aa3326695f266a6 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Fri, 17 Jul 2015 14:58:48 -0400 Subject: [PATCH 0308/1872] 18678: improve documentation and add TODOs --- src/sage/categories/bialgebras.py | 178 ++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 61 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index 5f1e97b5b88..26acd5775dc 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -62,21 +62,23 @@ def additional_structure(self): class ParentMethods: - def convolution_product(self, *maplist): + def convolution_product(self, *maps): """ - Return the convolution product (a map) of the maps in maplist. + Return the convolution product (a map) of the given maps. INPUT: - - ``maplist`` -- any number of linear maps `R,S,...,T` on ``self``, say of length `n>=0`. + - ``maps`` -- any number of linear maps `R, S, \dots, T` on + ``self``, say of length `n \geq 0`. OUTPUT: - - the new map `R*S*...*T` representing their convolution product. + - the new map `R * S * \cdots * T` representing their convolution + product. MATH:: - (R*S*\cdots *T) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}. + (R*S*\cdots *T) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}, where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; @@ -97,30 +99,47 @@ def convolution_product(self, *maplist): .. TODO:: - Remove dependency on modules_with_basis methods. + Remove dependency on ``modules_with_basis`` methods. - TESTS:: + EXAMPLES: + + We construct some maps: the identity, the antipode and + projection onto the homogeneous componente of degree 2:: sage: Id = lambda x: x sage: Antipode = lambda x: x.antipode() - sage: Proj2 = lambda x: x.parent().sum_of_terms([(m,c) for (m,c) in x if m.size()==2]) + sage: Proj2 = lambda x: x.parent().sum_of_terms([(m, c) for (m, c) in x if m.size() == 2]) + + Compute the convolution product of the identity with itself and + with the projection ``Proj2`` on the Hopf algebra of + non-commutative symmetric functions:: sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon() - sage: T = R.convolution_product([Id,Id]) + sage: T = R.convolution_product([Id, Id]) sage: [T(R(comp)) for comp in Compositions(3)] [4*R[1, 1, 1] + R[1, 2] + R[2, 1], 2*R[1, 1, 1] + 4*R[1, 2] + 2*R[2, 1] + 2*R[3], 2*R[1, 1, 1] + 2*R[1, 2] + 4*R[2, 1] + 2*R[3], R[1, 2] + R[2, 1] + 4*R[3]] - sage: T = R.convolution_product(Proj2,Id) - sage: [T(R([i])) for i in range(1,5)] + sage: T = R.convolution_product(Proj2, Id) + sage: [T(R([i])) for i in range(1, 5)] [0, R[2], R[2, 1] + R[3], R[2, 2] + R[4]] + Compute the convolution product of no maps on the Hopf algebra of + symmetric functions in non-commuting variables. This should + return ...:: + + sage: TODO: finish the above sentence sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: T = m.convolution_product() - sage: [T(m(lam)) for lam in SetPartitions(0).list()+SetPartitions(2).list()] + sage: [T(m(lam)) for lam in SetPartitions(0).list() + SetPartitions(2).list()] [m{}, 0, 0] - sage: T = m.convolution_product(Proj2,Id) + + Compute the convolution product of the projection ``Proj2`` with + the identity on the Hopf algebra of symmetric functions in + non-commuting variables:: + + sage: T = m.convolution_product(Proj2, Id) sage: [T(m(lam)) for lam in SetPartitions(3)] [0, m{{1, 2}, {3}} + m{{1, 2, 3}}, @@ -128,18 +147,24 @@ def convolution_product(self, *maplist): m{{1, 2}, {3}} + m{{1, 2, 3}}, 3*m{{1}, {2}, {3}} + 3*m{{1}, {2, 3}} + 3*m{{1, 3}, {2}}] - sage: G = SymmetricGroup(3); QG = GroupAlgebra(G,QQ) + Compute the convolution product of the antipode with itself and the + identity map on group algebra of the symmetric group: + + sage: G = SymmetricGroup(3) + sage: QG = GroupAlgebra(G, QQ) sage: x = QG.sum_of_terms([(p,p.number_of_peaks() + p.number_of_inversions()) for p in Permutations(3)]); x 2*[1, 3, 2] + [2, 1, 3] + 3*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] - sage: T = QG.convolution_product(Antipode,Antipode,Id) + sage: T = QG.convolution_product(Antipode, Antipode, Id) sage: T(x) 2*[1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 3*[3, 1, 2] + 3*[3, 2, 1] """ # Be flexible on how the maps are entered... - if len(maplist)==1 and isinstance(maplist[0], (list,tuple)): - T = tuple(maplist[0]) + # TODO : test this if statement and explain what it means to be + # flexible + if len(maps) == 1 and isinstance(maps[0], (list, tuple)): + T = tuple(maps[0]) else: - T = maplist + T = maps n = len(T) H = self @@ -163,13 +188,13 @@ def convolution_product(self, *maplist): return Mu_n * apply_T * Delta_n - def _convolution_product_from_elements(self, *maplist): + def _convolution_product_from_elements(self, *maps): """ - Return the convolution product (a map) of the maps in maplist. + Return the convolution product (a map) of the maps. A temporary function, created for speed-testing purposes. """ - cpfe = lambda x: x.convolution_product(*maplist) + cpfe = lambda x: x.convolution_product(*maps) return cpfe @@ -177,7 +202,8 @@ class ElementMethods: def adams_operator(self, n): """ - Compute the n-th convolution power of the identity morphism `Id` on self. + Compute the `n`-th convolution power of the identity morphism `Id` + on ``self``. INPUT: @@ -185,7 +211,7 @@ def adams_operator(self, n): OUTPUT: - - the element of self.parent() corresponding to `Id^{*n}(self)`. + - the image of ``self`` under the convolution power `Id^{*n}`. .. SEEALSO:: @@ -201,31 +227,40 @@ def adams_operator(self, n): .. TODO:: - Remove dependency on modules_with_basis methods. + Remove dependency on ``modules_with_basis`` methods. - TESTS:: + EXAMPLES:: sage: h = SymmetricFunctions(QQ).h() sage: h[5].adams_operator(2) 2*h[3, 2] + 2*h[4, 1] + 2*h[5] sage: h[5].plethysm(2*h[1]) 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h([]).adams_operator(0), h([]).adams_operator(1) - (h[], h[]) - sage: h[3,2].adams_operator(0), h[3,2].adams_operator(1) - (0, h[3, 2]) + sage: h([]).adams_operator(0) + h[] + sage: h([]).adams_operator(1) + h[] + sage: h[3,2].adams_operator(0) + 0 + sage: h[3,2].adams_operator(1) + h[3, 2] + + :: sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: S[4].adams_operator(5) 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + + :: + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: m[[1,3],[2]].adams_operator(-2) 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} """ if n < 0: - if hasattr(self,'antipode'): + if hasattr(self, 'antipode'): T = lambda x: x.antipode() n = abs(n) else: @@ -234,17 +269,19 @@ def adams_operator(self, n): T = lambda x: x return self.convolution_product([T] * n) - def convolution_product(self, *maplist): + def convolution_product(self, *maps): """ - Return the image of ``self`` under the convolution product (map) of the maps in ``maplist``. + Return the image of ``self`` under the convolution product (map) of + the maps. INPUT: - - ``maplist`` -- any number of linear maps `R,S,...,T` on ``self.parent()``, say of length `n>=0`. + - ``maps`` -- any number of linear maps `R, S, \dots, T` on + ``self.parent()``, say of length `n \geq 0`. OUTPUT: - - `(R*S*...*T)` applied to ``self``. + - `(R * S * \cdots * T)` applied to ``self``. MATH:: @@ -273,38 +310,47 @@ def convolution_product(self, *maplist): .. TODO:: - Remove dependency on modules_with_basis methods. + Remove dependency on ``modules_with_basis`` methods. EXAMPLES:: sage: Id = lambda x: x sage: Antipode = lambda x: x.antipode() sage: s = SymmetricFunctions(QQ).schur() - sage: s[3].convolution_product(Id,Id) + sage: s[3].convolution_product(Id, Id) 2*s[2, 1] + 4*s[3] - sage: s[3,2].convolution_product(Id,Id) == s[3,2].convolution_product([Id,Id]) + + TODO : what is the next line testing? :: + + sage: s[3,2].convolution_product(Id, Id) == s[3,2].convolution_product([Id, Id]) True sage: s[3,2].convolution_product(Id) == s[3,2] True - sage: s[3,2].convolution_product() == s[3,2].convolution_product(Antipode,Id) == s[3,2].convolution_product(Id,Antipode) + sage: s[3,2].convolution_product() == s[3,2].convolution_product(Antipode, Id) == s[3,2].convolution_product(Id, Antipode) True + + TODO : what is the next line testing? :: + sage: s[3,2].counit().parent() == s[3,2].convolution_product().parent() False + :: + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,1].convolution_product(Id,Id,Id) + sage: Psi[2,1].convolution_product(Id, Id, Id) 3*Psi[1, 2] + 6*Psi[2, 1] - sage: (Psi[5,1] - Psi[1,5]).convolution_product(Id,Id,Id) + sage: (Psi[5,1] - Psi[1,5]).convolution_product(Id, Id, Id) -3*Psi[1, 5] + 3*Psi[5, 1] - sage: G = SymmetricGroup(3); QG = GroupAlgebra(G,QQ) + sage: G = SymmetricGroup(3) + sage: QG = GroupAlgebra(G,QQ) sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] - sage: x.convolution_product(Id,Id) + sage: x.convolution_product(Id, Id) 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] - sage: x.convolution_product(Id,Id,Id) + sage: x.convolution_product(Id, Id, Id) 4*[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + 3*[3, 2, 1] - sage: x.convolution_product(Id,Id,Id,Id,Id,Id) + sage: x.convolution_product(Id, Id, Id, Id, Id, Id) 9*[1, 2, 3] @@ -313,48 +359,57 @@ def convolution_product(self, *maplist): sage: Id = lambda x: x sage: Antipode = lambda x: x.antipode() + :: + sage: h = SymmetricFunctions(QQ).h() - sage: h[5].convolution_product([Id,Id]) + sage: h[5].convolution_product([Id, Id]) 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h.one().convolution_product([Id,Antipode]) + sage: h.one().convolution_product([Id, Antipode]) h[] - sage: h[3,2].convolution_product([Id,Antipode]) + sage: h[3,2].convolution_product([Id, Antipode]) 0 - sage: h.one().convolution_product([Id,Antipode]) == h.one().convolution_product() + sage: h.one().convolution_product([Id, Antipode]) == h.one().convolution_product() True + :: + sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: S[4].convolution_product([Id]*5) 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].convolution_product([Antipode,Antipode]) + sage: m[[1,3],[2]].convolution_product([Antipode, Antipode]) 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} sage: m[[]].convolution_product([]), m[[1,3],[2]].convolution_product([]) - (m{}, 0) + m{} + sage: m[[1,3],[2]].convolution_product([]) + 0 - sage: QS = SymmetricGroupAlgebra(QQ,5) + sage: QS = SymmetricGroupAlgebra(QQ, 5) sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] - sage: x.convolution_product([Antipode,Id]) + sage: x.convolution_product([Antipode, Id]) 6*[1, 2, 3, 4, 5] sage: x.convolution_product(Id, Antipode, Antipode, Antipode) 3*[1, 2, 3, 4, 5] + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] - sage: G = SymmetricGroup(3); QG = GroupAlgebra(G,QQ) + sage: G = SymmetricGroup(3) + sage: QG = GroupAlgebra(G,QQ) sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] - sage: x.convolution_product(Antipode,Id) + sage: x.convolution_product(Antipode, Id) 9*[1, 2, 3] sage: x.convolution_product([Id, Antipode, Antipode, Antipode]) 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] """ # Be flexible on how the maps are entered... - if len(maplist)==1 and isinstance(maplist[0], (list,tuple)): - T = tuple(maplist[0]) + # TODO : test this if statement and explain what it means to be + # flexible + if len(maps) == 1 and isinstance(maps[0], (list, tuple)): + T = tuple(maps[0]) else: - T = maplist + T = maps H = self.parent() # TYPE-CHECK: @@ -393,7 +448,7 @@ def coproduct_iterated(self, n=1): .. TODO:: - Remove dependency on modules_with_basis methods. + Remove dependency on ``modules_with_basis`` methods. EXAMPLES:: @@ -411,20 +466,21 @@ def coproduct_iterated(self, n=1): sage: p([]).coproduct_iterated(3) p[] # p[] # p[] # p[] + :: + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() sage: Psi[2,2].coproduct_iterated(0) Psi[2, 2] sage: Psi[2,2].coproduct_iterated(3) Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2] + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[] + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[] + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[] + :: + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: m[[1,3],[2]].coproduct_iterated(2) m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}} + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{} + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{} + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{} + m{{1, 3}, {2}} # m{} # m{} - sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) - - """ if n < 0: raise ValueError("cannot take fewer than 0 coproduct iterations: %s < 0" % str(n)) From 1d5853b2c72f5685a8543a21ef6b89dce7f13abb Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Fri, 17 Jul 2015 15:06:04 -0400 Subject: [PATCH 0309/1872] 18678: fix some doctests --- src/sage/categories/bialgebras.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index 26acd5775dc..6ccd1d8946f 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -127,9 +127,10 @@ def convolution_product(self, *maps): Compute the convolution product of no maps on the Hopf algebra of symmetric functions in non-commuting variables. This should - return ...:: + return ... + + TODO: finish the above sentence :: - sage: TODO: finish the above sentence sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: T = m.convolution_product() sage: [T(m(lam)) for lam in SetPartitions(0).list() + SetPartitions(2).list()] @@ -381,7 +382,7 @@ def convolution_product(self, *maps): sage: m[[1,3],[2]].convolution_product([Antipode, Antipode]) 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} - sage: m[[]].convolution_product([]), m[[1,3],[2]].convolution_product([]) + sage: m[[]].convolution_product([]) m{} sage: m[[1,3],[2]].convolution_product([]) 0 From 2e9f13338d90140da9a5595766309bcd887abb35 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Fri, 17 Jul 2015 17:18:37 -0400 Subject: [PATCH 0310/1872] 18678: deal with some todos; add others --- src/sage/categories/bialgebras.py | 86 +++++++++++++++++++------------ 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index 6ccd1d8946f..9c94859ac89 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -68,17 +68,17 @@ def convolution_product(self, *maps): INPUT: - - ``maps`` -- any number of linear maps `R, S, \dots, T` on - ``self``, say of length `n \geq 0`. + - ``maps`` -- any number `n \geq 0` of linear maps `R, S, \dots, + T` on ``self``; or a single ``list`` or ``tuple`` of such maps. OUTPUT: - the new map `R * S * \cdots * T` representing their convolution product. - MATH:: + .. MATH:: - (R*S*\cdots *T) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}, + (R*S*\cdots*T) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}, where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; @@ -126,10 +126,8 @@ def convolution_product(self, *maps): [0, R[2], R[2, 1] + R[3], R[2, 2] + R[4]] Compute the convolution product of no maps on the Hopf algebra of - symmetric functions in non-commuting variables. This should - return ... - - TODO: finish the above sentence :: + symmetric functions in non-commuting variables. This is the + composition of the counit with the unit:: sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: T = m.convolution_product() @@ -159,9 +157,8 @@ def convolution_product(self, *maps): sage: T(x) 2*[1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 3*[3, 1, 2] + 3*[3, 2, 1] """ - # Be flexible on how the maps are entered... - # TODO : test this if statement and explain what it means to be - # flexible + # Be flexible on how the maps are entered: accept a list/tuple of + # maps as well as multiple arguments if len(maps) == 1 and isinstance(maps[0], (list, tuple)): T = tuple(maps[0]) else: @@ -174,6 +171,10 @@ def convolution_product(self, *maps): if not H in ModulesWithBasis: raise AttributeError('`self` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `self` instead.' % H._repr_()) + # TODO: (1) create a ticket for speeding this up + # TODO: (2) replace this with the faster version; i.e., a module + # morphism constructed from ``lambda x: x.convolution_product(*maps)`` + # SPEED-NOTE: # The code below, written as a composition of morphisms, is # much slower than the code appearing under ElementMethods below. @@ -189,6 +190,7 @@ def convolution_product(self, *maps): return Mu_n * apply_T * Delta_n + # TODO: delete this method def _convolution_product_from_elements(self, *maps): """ Return the convolution product (a map) of the maps. @@ -265,7 +267,7 @@ def adams_operator(self, n): T = lambda x: x.antipode() n = abs(n) else: - raise AttributeError("`self` has no antipode, hence cannot take negative convolution powers of identity_map: %s < 0" % str(n)) + raise ValueError("`self` has no antipode, hence cannot take negative convolution powers of identity_map: %s < 0" % str(n)) else: T = lambda x: x return self.convolution_product([T] * n) @@ -277,16 +279,17 @@ def convolution_product(self, *maps): INPUT: - - ``maps`` -- any number of linear maps `R, S, \dots, T` on - ``self.parent()``, say of length `n \geq 0`. + - ``maps`` -- any number `n \geq 0` of linear maps `R, S, \dots, + T` on ``self.parent()``; or a single ``list`` or ``tuple`` of + such maps. OUTPUT: - `(R * S * \cdots * T)` applied to ``self``. - MATH:: + .. MATH:: - (R*S*\cdots *T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h), + (R*S*\cdots*T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h), where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; @@ -313,27 +316,34 @@ def convolution_product(self, *maps): Remove dependency on ``modules_with_basis`` methods. - EXAMPLES:: + EXAMPLES: + + We compute convolution products of the identity and antipode maps + on Schur functions:: sage: Id = lambda x: x sage: Antipode = lambda x: x.antipode() sage: s = SymmetricFunctions(QQ).schur() sage: s[3].convolution_product(Id, Id) 2*s[2, 1] + 4*s[3] - - TODO : what is the next line testing? :: - - sage: s[3,2].convolution_product(Id, Id) == s[3,2].convolution_product([Id, Id]) - True sage: s[3,2].convolution_product(Id) == s[3,2] True - sage: s[3,2].convolution_product() == s[3,2].convolution_product(Antipode, Id) == s[3,2].convolution_product(Id, Antipode) - True - TODO : what is the next line testing? :: + The method accepts multiple arguments, or a single argument + consisting of a list of maps:: - sage: s[3,2].counit().parent() == s[3,2].convolution_product().parent() - False + sage: s[3,2].convolution_product(Id, Id) + 2*s[2, 1, 1, 1] + 6*s[2, 2, 1] + 6*s[3, 1, 1] + 12*s[3, 2] + 6*s[4, 1] + 2*s[5] + sage: s[3,2].convolution_product([Id, Id]) + 2*s[2, 1, 1, 1] + 6*s[2, 2, 1] + 6*s[3, 1, 1] + 12*s[3, 2] + 6*s[4, 1] + 2*s[5] + + We test the defining property of the antipode morphism; namely, + that the antipode is the inverse of the identity map in the + convolution algebra whose identity element is the composition of + the counit and unit:: + + sage: s[3,2].convolution_product() == s[3,2].convolution_product(Antipode, Id) == s[3,2].convolution_product(Id, Antipode) + True :: @@ -343,6 +353,8 @@ def convolution_product(self, *maps): sage: (Psi[5,1] - Psi[1,5]).convolution_product(Id, Id, Id) -3*Psi[1, 5] + 3*Psi[5, 1] + :: + sage: G = SymmetricGroup(3) sage: QG = GroupAlgebra(G,QQ) sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x @@ -351,7 +363,7 @@ def convolution_product(self, *maps): 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] sage: x.convolution_product(Id, Id, Id) 4*[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + 3*[3, 2, 1] - sage: x.convolution_product(Id, Id, Id, Id, Id, Id) + sage: x.convolution_product([Id]*6) 9*[1, 2, 3] @@ -378,15 +390,18 @@ def convolution_product(self, *maps): sage: S[4].convolution_product([Id]*5) 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + :: + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: m[[1,3],[2]].convolution_product([Antipode, Antipode]) 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} - sage: m[[]].convolution_product([]) m{} sage: m[[1,3],[2]].convolution_product([]) 0 + :: + sage: QS = SymmetricGroupAlgebra(QQ, 5) sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] @@ -395,6 +410,8 @@ def convolution_product(self, *maps): sage: x.convolution_product(Id, Antipode, Antipode, Antipode) 3*[1, 2, 3, 4, 5] + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + :: + sage: G = SymmetricGroup(3) sage: QG = GroupAlgebra(G,QQ) sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x @@ -403,10 +420,15 @@ def convolution_product(self, *maps): 9*[1, 2, 3] sage: x.convolution_product([Id, Antipode, Antipode, Antipode]) 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + + :: + + sage: s[3,2].counit().parent() == s[3,2].convolution_product().parent() + False + """ - # Be flexible on how the maps are entered... - # TODO : test this if statement and explain what it means to be - # flexible + # Be flexible on how the maps are entered: accept a list/tuple of + # maps as well as multiple arguments if len(maps) == 1 and isinstance(maps[0], (list, tuple)): T = tuple(maps[0]) else: From 5cc81cb1dfa4d13db441d4ee2bb6616a054a4cee Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Sun, 19 Jul 2015 20:03:33 -0500 Subject: [PATCH 0311/1872] cleaned up conflicts due to recent merge with tscrim branch --- src/sage/categories/bialgebras.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index 5f1e97b5b88..c4c845ed949 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -15,6 +15,7 @@ from sage.functions.other import floor, ceil from sage.rings.integer import Integer from sage.categories.modules_with_basis import ModulesWithBasis +from sage.misc.lazy_import import LazyImport class Bialgebras(Category_over_base_ring): """ @@ -438,3 +439,5 @@ def coproduct_iterated(self, n=1): def split(a,b): return tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) return (self.coproduct()).apply_multilinear_morphism(split) + WithBasis = LazyImport('sage.categories.bialgebras_with_basis', 'BialgebrasWithBasis') + From d01c4dacf3896a967f82688a47e9d7b5cf30d8f3 Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Sun, 19 Jul 2015 22:46:38 -0500 Subject: [PATCH 0312/1872] moved convolution code from bialgebras to bialgebras_with_basis. replaced the slow code in ParentMethods (based on composition of module morphisms) with faster code based on Amy Pang's algorithm. --- src/sage/categories/bialgebras.py | 455 +------------------ src/sage/categories/bialgebras_with_basis.py | 420 ++++++++++++++++- 2 files changed, 418 insertions(+), 457 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index 95515dec87c..b592b700569 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -62,460 +62,9 @@ def additional_structure(self): return None class ParentMethods: - - def convolution_product(self, *maps): - """ - Return the convolution product (a map) of the given maps. - - INPUT: - - - ``maps`` -- any number `n \geq 0` of linear maps `R, S, \dots, - T` on ``self``; or a single ``list`` or ``tuple`` of such maps. - - OUTPUT: - - - the new map `R * S * \cdots * T` representing their convolution - product. - - .. MATH:: - - (R*S*\cdots*T) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}, - - where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, - with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; - and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` - (the ordinary product). See [Sw1969]_. - - (In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.) - - .. SEEALSO:: - - :meth:`sage.categories.bialgebras.ElementMethods.convolution_product` - - AUTHORS: - - Aaron Lauve - 12 June 2015 - Sage Days 65 - - based off of .adams_operator() code in sage-trac ticket #18350 - - by Jean-Baptiste Priez - - .. TODO:: - - Remove dependency on ``modules_with_basis`` methods. - - EXAMPLES: - - We construct some maps: the identity, the antipode and - projection onto the homogeneous componente of degree 2:: - - sage: Id = lambda x: x - sage: Antipode = lambda x: x.antipode() - sage: Proj2 = lambda x: x.parent().sum_of_terms([(m, c) for (m, c) in x if m.size() == 2]) - - Compute the convolution product of the identity with itself and - with the projection ``Proj2`` on the Hopf algebra of - non-commutative symmetric functions:: - - sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon() - sage: T = R.convolution_product([Id, Id]) - sage: [T(R(comp)) for comp in Compositions(3)] - [4*R[1, 1, 1] + R[1, 2] + R[2, 1], - 2*R[1, 1, 1] + 4*R[1, 2] + 2*R[2, 1] + 2*R[3], - 2*R[1, 1, 1] + 2*R[1, 2] + 4*R[2, 1] + 2*R[3], - R[1, 2] + R[2, 1] + 4*R[3]] - sage: T = R.convolution_product(Proj2, Id) - sage: [T(R([i])) for i in range(1, 5)] - [0, R[2], R[2, 1] + R[3], R[2, 2] + R[4]] - - Compute the convolution product of no maps on the Hopf algebra of - symmetric functions in non-commuting variables. This is the - composition of the counit with the unit:: - - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: T = m.convolution_product() - sage: [T(m(lam)) for lam in SetPartitions(0).list() + SetPartitions(2).list()] - [m{}, 0, 0] - - Compute the convolution product of the projection ``Proj2`` with - the identity on the Hopf algebra of symmetric functions in - non-commuting variables:: - - sage: T = m.convolution_product(Proj2, Id) - sage: [T(m(lam)) for lam in SetPartitions(3)] - [0, - m{{1, 2}, {3}} + m{{1, 2, 3}}, - m{{1, 2}, {3}} + m{{1, 2, 3}}, - m{{1, 2}, {3}} + m{{1, 2, 3}}, - 3*m{{1}, {2}, {3}} + 3*m{{1}, {2, 3}} + 3*m{{1, 3}, {2}}] - - Compute the convolution product of the antipode with itself and the - identity map on group algebra of the symmetric group: - - sage: G = SymmetricGroup(3) - sage: QG = GroupAlgebra(G, QQ) - sage: x = QG.sum_of_terms([(p,p.number_of_peaks() + p.number_of_inversions()) for p in Permutations(3)]); x - 2*[1, 3, 2] + [2, 1, 3] + 3*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] - sage: T = QG.convolution_product(Antipode, Antipode, Id) - sage: T(x) - 2*[1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 3*[3, 1, 2] + 3*[3, 2, 1] - """ - # Be flexible on how the maps are entered: accept a list/tuple of - # maps as well as multiple arguments - if len(maps) == 1 and isinstance(maps[0], (list, tuple)): - T = tuple(maps[0]) - else: - T = maps - - n = len(T) - H = self - - # TYPE-CHECK: - if not H in ModulesWithBasis: - raise AttributeError('`self` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `self` instead.' % H._repr_()) - - # TODO: (1) create a ticket for speeding this up - # TODO: (2) replace this with the faster version; i.e., a module - # morphism constructed from ``lambda x: x.convolution_product(*maps)`` - - # SPEED-NOTE: - # The code below, written as a composition of morphisms, is - # much slower than the code appearing under ElementMethods below. - if n == 0: - return H.module_morphism(on_basis=lambda x: H.one() * H.term(x).counit(), codomain = H) - elif n == 1: - return H.module_morphism(on_basis=lambda x: T[0](H.term(x)), codomain = H) - else: - HHH = tensor((H,)*n) - Delta_n = H.module_morphism(on_basis=lambda x: H.term(x).coproduct_iterated(n-1), codomain = HHH) - apply_T = HHH.module_morphism(on_basis=lambda args: tensor([T[i](H.term(args[i])) for i in range(n)]), codomain = HHH) - Mu_n = HHH.module_morphism(on_basis=lambda args: H.prod([H.term(h) for h in args]), codomain = H) - - return Mu_n * apply_T * Delta_n - - # TODO: delete this method - def _convolution_product_from_elements(self, *maps): - """ - Return the convolution product (a map) of the maps. - - A temporary function, created for speed-testing purposes. - """ - cpfe = lambda x: x.convolution_product(*maps) - return cpfe - + pass class ElementMethods: - - def adams_operator(self, n): - """ - Compute the `n`-th convolution power of the identity morphism `Id` - on ``self``. - - INPUT: - - - ``n`` -- a nonnegative integer. - - OUTPUT: - - - the image of ``self`` under the convolution power `Id^{*n}`. - - .. SEEALSO:: - - :mod:`sage.categories.bialgebras.ElementMethods.convolution_product` - - (In the literature, this is also called a Hopf power or Sweedler power, cf. [AL2015]_.) - - REFERENCES: - - .. [AL2015] The characteristic polynomial of the Adams operators on graded connected Hopf algebras. - Marcelo Aguiar and Aaron Lauve. - Algebra Number Theory, v.9, 2015, n.3, 2015. - - .. TODO:: - - Remove dependency on ``modules_with_basis`` methods. - - EXAMPLES:: - - sage: h = SymmetricFunctions(QQ).h() - sage: h[5].adams_operator(2) - 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h[5].plethysm(2*h[1]) - 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h([]).adams_operator(0) - h[] - sage: h([]).adams_operator(1) - h[] - sage: h[3,2].adams_operator(0) - 0 - sage: h[3,2].adams_operator(1) - h[3, 2] - - :: - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S[4].adams_operator(5) - 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] - - - :: - - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].adams_operator(-2) - 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} - - """ - if n < 0: - if hasattr(self, 'antipode'): - T = lambda x: x.antipode() - n = abs(n) - else: - raise ValueError("`self` has no antipode, hence cannot take negative convolution powers of identity_map: %s < 0" % str(n)) - else: - T = lambda x: x - return self.convolution_product([T] * n) - - def convolution_product(self, *maps): - """ - Return the image of ``self`` under the convolution product (map) of - the maps. - - INPUT: - - - ``maps`` -- any number `n \geq 0` of linear maps `R, S, \dots, - T` on ``self.parent()``; or a single ``list`` or ``tuple`` of - such maps. - - OUTPUT: - - - `(R * S * \cdots * T)` applied to ``self``. - - .. MATH:: - - (R*S*\cdots*T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h), - - where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, - with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; - and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` - (the ordinary product). See [Sw1969]_. - - (In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.) - - REFERENCES: - - .. [KMN2012] On the trace of the antipode and higher indicators. - Yevgenia Kashina and Susan Montgomery and Richard Ng. - Israel J. Math., v.188, 2012. - - .. [Sw1969] Hopf algebras. - Moss Sweedler. - W.A. Benjamin, Math Lec Note Ser., 1969. - - AUTHORS: - - Amy Pang - 12 June 2015 - Sage Days 65 - - .. TODO:: - - Remove dependency on ``modules_with_basis`` methods. - - EXAMPLES: - - We compute convolution products of the identity and antipode maps - on Schur functions:: - - sage: Id = lambda x: x - sage: Antipode = lambda x: x.antipode() - sage: s = SymmetricFunctions(QQ).schur() - sage: s[3].convolution_product(Id, Id) - 2*s[2, 1] + 4*s[3] - sage: s[3,2].convolution_product(Id) == s[3,2] - True - - The method accepts multiple arguments, or a single argument - consisting of a list of maps:: - - sage: s[3,2].convolution_product(Id, Id) - 2*s[2, 1, 1, 1] + 6*s[2, 2, 1] + 6*s[3, 1, 1] + 12*s[3, 2] + 6*s[4, 1] + 2*s[5] - sage: s[3,2].convolution_product([Id, Id]) - 2*s[2, 1, 1, 1] + 6*s[2, 2, 1] + 6*s[3, 1, 1] + 12*s[3, 2] + 6*s[4, 1] + 2*s[5] - - We test the defining property of the antipode morphism; namely, - that the antipode is the inverse of the identity map in the - convolution algebra whose identity element is the composition of - the counit and unit:: - - sage: s[3,2].convolution_product() == s[3,2].convolution_product(Antipode, Id) == s[3,2].convolution_product(Id, Antipode) - True - - :: - - sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,1].convolution_product(Id, Id, Id) - 3*Psi[1, 2] + 6*Psi[2, 1] - sage: (Psi[5,1] - Psi[1,5]).convolution_product(Id, Id, Id) - -3*Psi[1, 5] + 3*Psi[5, 1] - - :: - - sage: G = SymmetricGroup(3) - sage: QG = GroupAlgebra(G,QQ) - sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x - [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] - sage: x.convolution_product(Id, Id) - 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] - sage: x.convolution_product(Id, Id, Id) - 4*[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + 3*[3, 2, 1] - sage: x.convolution_product([Id]*6) - 9*[1, 2, 3] - - - TESTS:: - - sage: Id = lambda x: x - sage: Antipode = lambda x: x.antipode() - - :: - - sage: h = SymmetricFunctions(QQ).h() - sage: h[5].convolution_product([Id, Id]) - 2*h[3, 2] + 2*h[4, 1] + 2*h[5] - sage: h.one().convolution_product([Id, Antipode]) - h[] - sage: h[3,2].convolution_product([Id, Antipode]) - 0 - sage: h.one().convolution_product([Id, Antipode]) == h.one().convolution_product() - True - - :: - - sage: S = NonCommutativeSymmetricFunctions(QQ).S() - sage: S[4].convolution_product([Id]*5) - 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] - - :: - - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].convolution_product([Antipode, Antipode]) - 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} - sage: m[[]].convolution_product([]) - m{} - sage: m[[1,3],[2]].convolution_product([]) - 0 - - :: - - sage: QS = SymmetricGroupAlgebra(QQ, 5) - sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x - [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] - sage: x.convolution_product([Antipode, Id]) - 6*[1, 2, 3, 4, 5] - sage: x.convolution_product(Id, Antipode, Antipode, Antipode) - 3*[1, 2, 3, 4, 5] + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] - - :: - - sage: G = SymmetricGroup(3) - sage: QG = GroupAlgebra(G,QQ) - sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x - [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] - sage: x.convolution_product(Antipode, Id) - 9*[1, 2, 3] - sage: x.convolution_product([Id, Antipode, Antipode, Antipode]) - 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] - - :: - - sage: s[3,2].counit().parent() == s[3,2].convolution_product().parent() - False - - """ - # Be flexible on how the maps are entered: accept a list/tuple of - # maps as well as multiple arguments - if len(maps) == 1 and isinstance(maps[0], (list, tuple)): - T = tuple(maps[0]) - else: - T = maps - - H = self.parent() - # TYPE-CHECK: - if not H in ModulesWithBasis: - raise AttributeError('`parent` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `parent` instead.' % H._repr_()) - - n = len(T) - if n == 0: - return H.one() * self.counit() - elif n == 1: - return T[0](self) - else: - # We apply the maps T_i and products concurrently with coproducts, as this - # seems to be faster than applying a composition of maps, e.g., (H.nfold_product) * tensor(T) * (H.nfold_coproduct). - - i = 0 - out = tensor((H.one(),self)) - HH = tensor((H,H)) - - #ALGORITHM: - #`split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. - split_convolve = lambda (x,y): (((xy1,y2),c*d) for ((y1,y2),d) in H.term(y).coproduct() for (xy1,c) in H.term(x)*T[i](H.term(y1))) - while i < n-1: - out = HH.module_morphism(on_basis=lambda t: HH.sum_of_terms(split_convolve(t)), codomain = HH)(out) - i += 1 - - #Apply final map `T_n` to last term, `y`, and multiply. - out = HH.module_morphism(on_basis=lambda (x,y): H.term(x)*T[n-1](H.term(y)), codomain=H)(out) - - return out - - - def coproduct_iterated(self, n=1): - r""" - Apply `n` coproducts to ``self``. - - .. TODO:: - - Remove dependency on ``modules_with_basis`` methods. - - EXAMPLES:: - - sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,2].coproduct_iterated(0) - Psi[2, 2] - sage: Psi[2,2].coproduct_iterated(2) - Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2] + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[] - - TESTS:: - - sage: p = SymmetricFunctions(QQ).p() - sage: p[5,2,2].coproduct_iterated() - p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5] + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[] - sage: p([]).coproduct_iterated(3) - p[] # p[] # p[] # p[] - - :: - - sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,2].coproduct_iterated(0) - Psi[2, 2] - sage: Psi[2,2].coproduct_iterated(3) - Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2] + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[] + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[] + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[] - - :: - - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].coproduct_iterated(2) - m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}} + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{} + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{} + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{} + m{{1, 3}, {2}} # m{} # m{} - sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) - (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) - """ - if n < 0: - raise ValueError("cannot take fewer than 0 coproduct iterations: %s < 0" % str(n)) - if n==0: - return self - elif n==1: - return self.coproduct() - else: - # Use coassociativity of `\Delta` to perform many coproducts simultaneously. - fn = floor(Integer(n-1)/2); cn = ceil(Integer(n-1)/2) - def split(a,b): return tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) - return (self.coproduct()).apply_multilinear_morphism(split) + pass WithBasis = LazyImport('sage.categories.bialgebras_with_basis', 'BialgebrasWithBasis') \ No newline at end of file diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index eb6fd332a2a..74b447cedc5 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -30,10 +30,422 @@ class BialgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: TestSuite(BialgebrasWithBasis(ZZ)).run() """ class ParentMethods: - def foo(self): - return 'bar' + + def convolution_product(self, *maps): + """ + Return the convolution product (a map) of the given maps. + + INPUT: + + - ``maps`` -- any number `n \geq 0` of linear maps `R, S, \dots, + T` on ``self``; or a single ``list`` or ``tuple`` of such maps. + + OUTPUT: + + - the new map `R * S * \cdots * T` representing their convolution + product. + + .. MATH:: + + (R*S*\cdots*T) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}, + + where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, + with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; + and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` + (the ordinary product). See [Sw1969]_. + + (In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.) + + .. SEEALSO:: + + :meth:`sage.categories.bialgebras.ElementMethods.convolution_product` + + AUTHORS: + + Aaron Lauve - 12 June 2015 - Sage Days 65 + - based off of .adams_operator() code in sage-trac ticket #18350 + - by Jean-Baptiste Priez + + .. TODO:: + + Remove dependency on ``modules_with_basis`` methods. + + EXAMPLES: + + We construct some maps: the identity, the antipode and + projection onto the homogeneous componente of degree 2:: + + sage: Id = lambda x: x + sage: Antipode = lambda x: x.antipode() + sage: Proj2 = lambda x: x.parent().sum_of_terms([(m, c) for (m, c) in x if m.size() == 2]) + + Compute the convolution product of the identity with itself and + with the projection ``Proj2`` on the Hopf algebra of + non-commutative symmetric functions:: + + sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon() + sage: T = R.convolution_product([Id, Id]) + sage: [T(R(comp)) for comp in Compositions(3)] + [4*R[1, 1, 1] + R[1, 2] + R[2, 1], + 2*R[1, 1, 1] + 4*R[1, 2] + 2*R[2, 1] + 2*R[3], + 2*R[1, 1, 1] + 2*R[1, 2] + 4*R[2, 1] + 2*R[3], + R[1, 2] + R[2, 1] + 4*R[3]] + sage: T = R.convolution_product(Proj2, Id) + sage: [T(R([i])) for i in range(1, 5)] + [0, R[2], R[2, 1] + R[3], R[2, 2] + R[4]] + + Compute the convolution product of no maps on the Hopf algebra of + symmetric functions in non-commuting variables. This is the + composition of the counit with the unit:: + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: T = m.convolution_product() + sage: [T(m(lam)) for lam in SetPartitions(0).list() + SetPartitions(2).list()] + [m{}, 0, 0] + + Compute the convolution product of the projection ``Proj2`` with + the identity on the Hopf algebra of symmetric functions in + non-commuting variables:: + + sage: T = m.convolution_product(Proj2, Id) + sage: [T(m(lam)) for lam in SetPartitions(3)] + [0, + m{{1, 2}, {3}} + m{{1, 2, 3}}, + m{{1, 2}, {3}} + m{{1, 2, 3}}, + m{{1, 2}, {3}} + m{{1, 2, 3}}, + 3*m{{1}, {2}, {3}} + 3*m{{1}, {2, 3}} + 3*m{{1, 3}, {2}}] + + Compute the convolution product of the antipode with itself and the + identity map on group algebra of the symmetric group: + + sage: G = SymmetricGroup(3) + sage: QG = GroupAlgebra(G, QQ) + sage: x = QG.sum_of_terms([(p,p.number_of_peaks() + p.number_of_inversions()) for p in Permutations(3)]); x + 2*[1, 3, 2] + [2, 1, 3] + 3*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] + sage: T = QG.convolution_product(Antipode, Antipode, Id) + sage: T(x) + 2*[1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 3*[3, 1, 2] + 3*[3, 2, 1] + """ + H = self + # TYPE-CHECK: + if not H in ModulesWithBasis: + raise AttributeError('`self` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `self` instead.' % H._repr_()) + + onbasis = lambda x: H.term(x).convolution_product(*maps) + return H.module_morphism(on_basis=onbasis, codomain=H) class ElementMethods: - def bar(self): - return 'foo fighters' + def adams_operator(self, n): + """ + Compute the `n`-th convolution power of the identity morphism `Id` + on ``self``. + + INPUT: + + - ``n`` -- a nonnegative integer. + + OUTPUT: + + - the image of ``self`` under the convolution power `Id^{*n}`. + + .. SEEALSO:: + + :mod:`sage.categories.bialgebras.ElementMethods.convolution_product` + + (In the literature, this is also called a Hopf power or Sweedler power, cf. [AL2015]_.) + + REFERENCES: + + .. [AL2015] The characteristic polynomial of the Adams operators on graded connected Hopf algebras. + Marcelo Aguiar and Aaron Lauve. + Algebra Number Theory, v.9, 2015, n.3, 2015. + + .. TODO:: + + Remove dependency on ``modules_with_basis`` methods. + + EXAMPLES:: + + sage: h = SymmetricFunctions(QQ).h() + sage: h[5].adams_operator(2) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h[5].plethysm(2*h[1]) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h([]).adams_operator(0) + h[] + sage: h([]).adams_operator(1) + h[] + sage: h[3,2].adams_operator(0) + 0 + sage: h[3,2].adams_operator(1) + h[3, 2] + + :: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S[4].adams_operator(5) + 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + + + :: + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: m[[1,3],[2]].adams_operator(-2) + 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} + + """ + if n < 0: + if hasattr(self, 'antipode'): + T = lambda x: x.antipode() + n = abs(n) + else: + raise ValueError("`self` has no antipode, hence cannot take negative convolution powers of identity_map: %s < 0" % str(n)) + else: + T = lambda x: x + return self.convolution_product([T] * n) + + def convolution_product(self, *maps): + """ + Return the image of ``self`` under the convolution product (map) of + the maps. + + INPUT: + + - ``maps`` -- any number `n \geq 0` of linear maps `R, S, \dots, + T` on ``self.parent()``; or a single ``list`` or ``tuple`` of + such maps. + + OUTPUT: + + - `(R * S * \cdots * T)` applied to ``self``. + + .. MATH:: + + (R*S*\cdots*T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h), + + where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, + with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; + and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` + (the ordinary product). See [Sw1969]_. + + (In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.) + + REFERENCES: + + .. [KMN2012] On the trace of the antipode and higher indicators. + Yevgenia Kashina and Susan Montgomery and Richard Ng. + Israel J. Math., v.188, 2012. + + .. [Sw1969] Hopf algebras. + Moss Sweedler. + W.A. Benjamin, Math Lec Note Ser., 1969. + + AUTHORS: + + Amy Pang - 12 June 2015 - Sage Days 65 + + .. TODO:: + + Remove dependency on ``modules_with_basis`` methods. + + EXAMPLES: + + We compute convolution products of the identity and antipode maps + on Schur functions:: + + sage: Id = lambda x: x + sage: Antipode = lambda x: x.antipode() + sage: s = SymmetricFunctions(QQ).schur() + sage: s[3].convolution_product(Id, Id) + 2*s[2, 1] + 4*s[3] + sage: s[3,2].convolution_product(Id) == s[3,2] + True + + The method accepts multiple arguments, or a single argument + consisting of a list of maps:: + + sage: s[3,2].convolution_product(Id, Id) + 2*s[2, 1, 1, 1] + 6*s[2, 2, 1] + 6*s[3, 1, 1] + 12*s[3, 2] + 6*s[4, 1] + 2*s[5] + sage: s[3,2].convolution_product([Id, Id]) + 2*s[2, 1, 1, 1] + 6*s[2, 2, 1] + 6*s[3, 1, 1] + 12*s[3, 2] + 6*s[4, 1] + 2*s[5] + + We test the defining property of the antipode morphism; namely, + that the antipode is the inverse of the identity map in the + convolution algebra whose identity element is the composition of + the counit and unit:: + + sage: s[3,2].convolution_product() == s[3,2].convolution_product(Antipode, Id) == s[3,2].convolution_product(Id, Antipode) + True + + :: + + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() + sage: Psi[2,1].convolution_product(Id, Id, Id) + 3*Psi[1, 2] + 6*Psi[2, 1] + sage: (Psi[5,1] - Psi[1,5]).convolution_product(Id, Id, Id) + -3*Psi[1, 5] + 3*Psi[5, 1] + + :: + + sage: G = SymmetricGroup(3) + sage: QG = GroupAlgebra(G,QQ) + sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x + [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] + sage: x.convolution_product(Id, Id) + 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + sage: x.convolution_product(Id, Id, Id) + 4*[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + 3*[3, 2, 1] + sage: x.convolution_product([Id]*6) + 9*[1, 2, 3] + + + TESTS:: + + sage: Id = lambda x: x + sage: Antipode = lambda x: x.antipode() + + :: + + sage: h = SymmetricFunctions(QQ).h() + sage: h[5].convolution_product([Id, Id]) + 2*h[3, 2] + 2*h[4, 1] + 2*h[5] + sage: h.one().convolution_product([Id, Antipode]) + h[] + sage: h[3,2].convolution_product([Id, Antipode]) + 0 + sage: h.one().convolution_product([Id, Antipode]) == h.one().convolution_product() + True + + :: + + sage: S = NonCommutativeSymmetricFunctions(QQ).S() + sage: S[4].convolution_product([Id]*5) + 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + + :: + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: m[[1,3],[2]].convolution_product([Antipode, Antipode]) + 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} + sage: m[[]].convolution_product([]) + m{} + sage: m[[1,3],[2]].convolution_product([]) + 0 + + :: + + sage: QS = SymmetricGroupAlgebra(QQ, 5) + sage: x = QS.sum_of_terms(zip(Permutations(5)[3:6],[1,2,3])); x + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + 3*[1, 2, 5, 4, 3] + sage: x.convolution_product([Antipode, Id]) + 6*[1, 2, 3, 4, 5] + sage: x.convolution_product(Id, Antipode, Antipode, Antipode) + 3*[1, 2, 3, 4, 5] + [1, 2, 4, 5, 3] + 2*[1, 2, 5, 3, 4] + + :: + + sage: G = SymmetricGroup(3) + sage: QG = GroupAlgebra(G,QQ) + sage: x = QG.sum_of_terms([(p,p.length()) for p in Permutations(3)]); x + [1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + 3*[3, 2, 1] + sage: x.convolution_product(Antipode, Id) + 9*[1, 2, 3] + sage: x.convolution_product([Id, Antipode, Antipode, Antipode]) + 5*[1, 2, 3] + 2*[2, 3, 1] + 2*[3, 1, 2] + + :: + + sage: s[3,2].counit().parent() == s[3,2].convolution_product().parent() + False + + """ + # Be flexible on how the maps are entered: accept a list/tuple of + # maps as well as multiple arguments + if len(maps) == 1 and isinstance(maps[0], (list, tuple)): + T = tuple(maps[0]) + else: + T = maps + + H = self.parent() + # TYPE-CHECK: + if not H in ModulesWithBasis: + raise AttributeError('`parent` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `parent` instead.' % H._repr_()) + + n = len(T) + if n == 0: + return H.one() * self.counit() + elif n == 1: + return T[0](self) + else: + # We apply the maps T_i and products concurrently with coproducts, as this + # seems to be faster than applying a composition of maps, e.g., (H.nfold_product) * tensor(T) * (H.nfold_coproduct). + + i = 0 + out = tensor((H.one(),self)) + HH = tensor((H,H)) + + #ALGORITHM: + #`split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. + split_convolve = lambda (x,y): (((xy1,y2),c*d) for ((y1,y2),d) in H.term(y).coproduct() for (xy1,c) in H.term(x)*T[i](H.term(y1))) + while i < n-1: + out = HH.module_morphism(on_basis=lambda t: HH.sum_of_terms(split_convolve(t)), codomain = HH)(out) + i += 1 + + #Apply final map `T_n` to last term, `y`, and multiply. + out = HH.module_morphism(on_basis=lambda (x,y): H.term(x)*T[n-1](H.term(y)), codomain=H)(out) + + return out + + + def coproduct_iterated(self, n=1): + r""" + Apply `n` coproducts to ``self``. + + .. TODO:: + + Remove dependency on ``modules_with_basis`` methods. + + EXAMPLES:: + + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() + sage: Psi[2,2].coproduct_iterated(0) + Psi[2, 2] + sage: Psi[2,2].coproduct_iterated(2) + Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2] + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[] + + TESTS:: + + sage: p = SymmetricFunctions(QQ).p() + sage: p[5,2,2].coproduct_iterated() + p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5] + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[] + sage: p([]).coproduct_iterated(3) + p[] # p[] # p[] # p[] + + :: + + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() + sage: Psi[2,2].coproduct_iterated(0) + Psi[2, 2] + sage: Psi[2,2].coproduct_iterated(3) + Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2] + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[] + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[] + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[] + + :: + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: m[[1,3],[2]].coproduct_iterated(2) + m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}} + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{} + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{} + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{} + m{{1, 3}, {2}} # m{} # m{} + sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) + (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) + """ + if n < 0: + raise ValueError("cannot take fewer than 0 coproduct iterations: %s < 0" % str(n)) + if n==0: + return self + elif n==1: + return self.coproduct() + else: + # Use coassociativity of `\Delta` to perform many coproducts simultaneously. + fn = floor(Integer(n-1)/2); cn = ceil(Integer(n-1)/2) + def split(a,b): return tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) + return (self.coproduct()).apply_multilinear_morphism(split) \ No newline at end of file From 3f687bb4f5684ed08003a477735620558486f2ba Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 20 Jul 2015 10:47:52 +0200 Subject: [PATCH 0313/1872] docstring for AsymptoticRing added --- src/sage/rings/asymptotic_ring.py | 80 ++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 1c4181af7fb..35de693bca8 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -366,7 +366,85 @@ def O(self): class AsymptoticRing(sage.rings.ring.Ring, sage.structure.unique_representation.UniqueRepresentation): r""" - ... + Parent for asymptotic expressions. + + INPUT: + + - ``growth_group`` -- a partially ordered group (e.g. an instance + of :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`), + or a string that describes the type of the growth group (e.g. + "monomial"). + + - ``coefficient_ring`` -- the ring which contains the + coefficients of the expressions. + + - ``category`` -- the category of the parent can be specified + in order to broaden the base structure. It has to be a + subcategory of ``Category of rings``. This is also the default + category if ``None`` is specified. + + - ``names`` -- a tuple consisting of strings representing the + associated variables. + + OUTPUT: + + An asymptotic ring. + + .. NOTE:: + + See the following examples for more information on how to + create an asymptotic ring. + + EXAMPLES: + + We begin with the explicit construction of an asymptotic ring, + i.e. by explicitly specifying the underlying growth group:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: G_QQ = agg.MonomialGrowthGroup(QQ, 'x') + sage: R_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=QQ); R_x + Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + + Note that the coefficient ring of the asymptotic ring and the + base ring of the underlying growth group do not need to + coincide:: + + sage: R_ZZ_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=ZZ); R_ZZ_x + Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Integer Ring + + As mentioned above, the ring can also be constructed without + explicitly specifying the growth group. For example, passing the + string "monomial" as an argument for ``growth_group`` constructs + a ring over an appropriate growth group. Note that in this case, + also the variable name needs to be specified explicitly:: + + sage: R2_x = AsymptoticRing(growth_group='monomial', coefficient_ring=QQ, names=('x',)); R2_x + Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + + Alternatively, the preparser allows us to write:: + + sage: R3_x. = AsymptoticRing(growth_group='monomial', coefficient_ring=QQ); R3_x + Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + + According to the conventions for parents, uniqueness is ensured:: + + sage: R_x is R2_x is R3_x + True + + Furthermore, the coercion framework is also involved. Coercion + between two asymptotic rings is possible (given that the + underlying growth groups and coefficient rings are chosen + appropriately):: + + sage: R_x.has_coerce_map_from(R_ZZ_x) + True + + Additionally, for the sake of convenience, the coefficient ring + also coerces into the asymptotic ring (representing constant + quantities):: + + sage: R_x.has_coerce_map_from(QQ) + True """ # enable the category framework for elements Element = AsymptoticExpression From b109537a3658b5b8ce64f4e695222cbe7415e0fe Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 20 Jul 2015 11:16:23 +0200 Subject: [PATCH 0314/1872] gen implemented --- src/sage/rings/asymptotic_ring.py | 32 +++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 35de693bca8..dbeae04c089 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -664,10 +664,10 @@ def _coerce_map_from_(self, R): sage: AR_ZZ = AsymptoticRing('monomial', coefficient_ring=ZZ, names='x'); AR_ZZ Asymptotic Ring over Monomial Growth Group in x over Integer Ring with coefficients from Integer Ring - sage: (x_ZZ,) = AR_ZZ.gens() + sage: x_ZZ = AR_ZZ.gen() sage: AR_QQ = AsymptoticRing('monomial', coefficient_ring=QQ, names='x'); AR_QQ Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field - sage: (x_QQ,) = AR_QQ.gens() + sage: x_QQ = AR_QQ.gen() sage: AR_QQ.has_coerce_map_from(AR_ZZ) # indirect doctest True sage: x_ZZ * x_QQ @@ -741,6 +741,34 @@ def gens(self): if isinstance(self.growth_group, MonomialGrowthGroup): return self.create_term('exact', self.growth_group.gen(), 1), + + def gen(self, n=0): + r""" + Return the ``n``-th generator of this asymptotic ring. + + INPUT: + + - ``n`` -- a positive integer or `0`. Default: `0`. + + OUTPUT: + + An asymptotic expression. + + .. NOTE:: + + Generators do not necessarily exist. This depends on the + underlying growth group. For example, monomial growth + groups have a generator, and exponential growth groups + don't. + + EXAMPLES:: + + sage: R. = AsymptoticRing('monomial', ZZ) + sage: R.gen() + 1*x + """ + return self.gens()[n] + def ngens(self): r""" Return the number of generators of this asymptotic ring. From 40cae5bde7ecc580490d5fe9cbd937b7b0a4b039 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 20 Jul 2015 11:16:41 +0200 Subject: [PATCH 0315/1872] typo fixed --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index dbeae04c089..d785acf1f34 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -718,7 +718,7 @@ def gens(self): INPUT: - Noting. + Nothing. OUTPUT: From fa16ab6403bdd4f7c73449f4aa8fa1bddc150c41 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 20 Jul 2015 14:46:13 +0200 Subject: [PATCH 0316/1872] docstring for asymptotic expression added --- src/sage/rings/asymptotic_ring.py | 106 +++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index d785acf1f34..e27eba95da3 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -53,7 +53,111 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): r""" - ... + Class for asymptotic expressions. ... + + INPUT: + + - ``parent`` -- the parent of the asymptotic expression. + + - ``poset`` -- a mutable poset representing the underlying + growth structure. + + - ``simplify`` -- a boolean, controls automatic simplification + (absorption) of asymptotic expressions. Default: ``True``. + + EXAMPLES: + + There are ways to create an asymptotic expression. First, + we construct the corresponding parents:: + + sage: R_x. = AsymptoticRing('monomial', QQ) + sage: import sage.groups.asymptotic_growth_group as agg + sage: G = agg.MonomialGrowthGroup(ZZ, 'y') + sage: R_y = AsymptoticRing(G, ZZ); y = R_y.gen() + + At this point, `x` and `y` are already asymptotic expressions:: + + sage: (x, y) + (1*x, 1*y) + sage: isinstance(x, sage.rings.asymptotic_ring.AsymptoticExpression) + True + sage: type(x) + + + The usual ring operations can be performed:: + + sage: x^2 + 3*(x - x^2) + 3*x + -2*x^2 + sage: (3*x + 2)^3 + 8*1 + 36*x + 54*x^2 + 27*x^3 + + In addition to that, special powers (determined by the base ring + of the growth group) can also be computed:: + + sage: (x^(5/2) + x^(1/7)) * x^(-1/5) + 1*x^(-2/35) + 1*x^(23/10) + + One of the central ideas behind computing with asymptotic + expressions is that the `O`-notation (see + :wikipedia:`Big_O_notation`) can be used. For example, we have:: + + sage: (x + 2*x^2 + 3*x^3 + 4*x^4) * (O(x) + x^2) + O(x^5) + 4*x^6 + + In particular, :meth:`~sage.rings.big_oh.O` can be used to + construct the asymptotic expressions. With the help of the + ``poset``, we can also have a look at the inner structure + of an asymptotic expression:: + + sage: expr1 = x + 2*x^2 + 3*x^3 + 4*x^4; expr2 = O(x) + x^2 + sage: print(expr1.poset.repr_full()) + poset(1*x, 2*x^2, 3*x^3, 4*x^4) + +-- null + | +-- no predecessors + | +-- successors: 1*x + +-- 1*x + | +-- predecessors: null + | +-- successors: 2*x^2 + +-- 2*x^2 + | +-- predecessors: 1*x + | +-- successors: 3*x^3 + +-- 3*x^3 + | +-- predecessors: 2*x^2 + | +-- successors: 4*x^4 + +-- 4*x^4 + | +-- predecessors: 3*x^3 + | +-- successors: oo + +-- oo + | +-- predecessors: 4*x^4 + | +-- no successors + sage: print(expr2.poset.repr_full()) + poset(O(x), 1*x^2) + +-- null + | +-- no predecessors + | +-- successors: O(x) + +-- O(x) + | +-- predecessors: null + | +-- successors: 1*x^2 + +-- 1*x^2 + | +-- predecessors: O(x) + | +-- successors: oo + +-- oo + | +-- predecessors: 1*x^2 + | +-- no successors + sage: print((expr1 * expr2).poset.repr_full()) + poset(O(x^5), 4*x^6) + +-- null + | +-- no predecessors + | +-- successors: O(x^5) + +-- O(x^5) + | +-- predecessors: null + | +-- successors: 4*x^6 + +-- 4*x^6 + | +-- predecessors: O(x^5) + | +-- successors: oo + +-- oo + | +-- predecessors: 4*x^6 + | +-- no successors """ def __init__(self, parent, poset, simplify=True): r""" From fb9e828ecf3e7444a983924275ba6aaee0c11d48 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 20 Jul 2015 14:46:31 +0200 Subject: [PATCH 0317/1872] coercion from rings that coerce into coefficient_ring --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index e27eba95da3..17bedae54cc 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -784,7 +784,7 @@ def _coerce_map_from_(self, R): sage: 1/2 * x_QQ^2 + 7/8 * x_QQ^3 1/2*x^2 + 7/8*x^3 """ - if R is self.coefficient_ring: + if self.coefficient_ring.has_coerce_map_from(R): return True elif isinstance(R, AsymptoticRing): if self.growth_group.has_coerce_map_from(R.growth_group) and \ From 8bf88cf86180481add9ba8058ae7203ad505242a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 21 Jul 2015 16:36:50 +0200 Subject: [PATCH 0318/1872] doctests fixed --- src/sage/rings/asymptotic_ring.py | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 17bedae54cc..bcf94c3fdda 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -72,7 +72,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): sage: R_x. = AsymptoticRing('monomial', QQ) sage: import sage.groups.asymptotic_growth_group as agg - sage: G = agg.MonomialGrowthGroup(ZZ, 'y') + sage: G = agg.GrowthGroup('y^ZZ') sage: R_y = AsymptoticRing(G, ZZ); y = R_y.gen() At this point, `x` and `y` are already asymptotic expressions:: @@ -217,7 +217,7 @@ def _simplify_(self): sage: import sage.groups.asymptotic_growth_group as agg sage: import sage.monoids.asymptotic_term_monoid as atm - sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: G = agg.GrowthGroup('x^ZZ') sage: OT = atm.TermMonoid('O', G); ET = atm.TermMonoid('exact', G, ZZ) sage: R = AsymptoticRing(G, ZZ) sage: lst = [ET(x,1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] @@ -413,7 +413,7 @@ def __pow__(self, power): sage: y^(1/7) Traceback (most recent call last): ... - ValueError: Exponent 1/7 not in base of growth group Monomial Growth Group in y over Integer Ring + ValueError: Exponent 1/7 not in base of growth group y^ZZ sage: (x^(1/2) + O(x^0))^15 O(x^7) + 1*x^(15/2) """ @@ -451,7 +451,7 @@ def O(self): EXAMPLES:: sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(MG, ZZ) sage: x = AR.create_term('exact', x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr @@ -505,16 +505,16 @@ class AsymptoticRing(sage.rings.ring.Ring, i.e. by explicitly specifying the underlying growth group:: sage: import sage.groups.asymptotic_growth_group as agg - sage: G_QQ = agg.MonomialGrowthGroup(QQ, 'x') + sage: G_QQ = agg.GrowthGroup('x^QQ') sage: R_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=QQ); R_x - Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + Asymptotic Ring over x^QQ with coefficients from Rational Field Note that the coefficient ring of the asymptotic ring and the base ring of the underlying growth group do not need to coincide:: sage: R_ZZ_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=ZZ); R_ZZ_x - Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Integer Ring + Asymptotic Ring over x^QQ with coefficients from Integer Ring As mentioned above, the ring can also be constructed without explicitly specifying the growth group. For example, passing the @@ -523,12 +523,12 @@ class AsymptoticRing(sage.rings.ring.Ring, also the variable name needs to be specified explicitly:: sage: R2_x = AsymptoticRing(growth_group='monomial', coefficient_ring=QQ, names=('x',)); R2_x - Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + Asymptotic Ring over x^QQ with coefficients from Rational Field Alternatively, the preparser allows us to write:: sage: R3_x. = AsymptoticRing(growth_group='monomial', coefficient_ring=QQ); R3_x - Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + Asymptotic Ring over x^QQ with coefficients from Rational Field According to the conventions for parents, uniqueness is ensured:: @@ -570,7 +570,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, framework:: sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: MG = agg.GrowthGroup('x^ZZ') sage: AR1 = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: AR2. = AsymptoticRing(growth_group='monomial', coefficient_ring=ZZ) sage: AR1 is AR2 @@ -605,11 +605,11 @@ def __init__(self, growth_group=None, coefficient_ring=None, category=None): TESTS:: sage: import sage.groups.asymptotic_growth_group as agg - sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: G = agg.GrowthGroup('x^ZZ') sage: R1 = AsymptoticRing(G, ZZ); R1 - Asymptotic Ring over Monomial Growth Group in x over Integer Ring with coefficients from Integer Ring + Asymptotic Ring over x^ZZ with coefficients from Integer Ring sage: R2. = AsymptoticRing('monomial', QQ); R2 - Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + Asymptotic Ring over x^QQ with coefficients from Rational Field sage: R1 is R2 False @@ -651,10 +651,10 @@ def growth_group(self): EXAMPLES:: sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: AR.growth_group - Monomial Growth Group in x over Integer Ring + x^ZZ """ return self._growth_group_ @@ -667,7 +667,7 @@ def coefficient_ring(self): EXAMPLES:: sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: AR.coefficient_ring Integer Ring @@ -767,10 +767,10 @@ def _coerce_map_from_(self, R): TESTS:: sage: AR_ZZ = AsymptoticRing('monomial', coefficient_ring=ZZ, names='x'); AR_ZZ - Asymptotic Ring over Monomial Growth Group in x over Integer Ring with coefficients from Integer Ring + Asymptotic Ring over x^ZZ with coefficients from Integer Ring sage: x_ZZ = AR_ZZ.gen() sage: AR_QQ = AsymptoticRing('monomial', coefficient_ring=QQ, names='x'); AR_QQ - Asymptotic Ring over Monomial Growth Group in x over Rational Field with coefficients from Rational Field + Asymptotic Ring over x^QQ with coefficients from Rational Field sage: x_QQ = AR_QQ.gen() sage: AR_QQ.has_coerce_map_from(AR_ZZ) # indirect doctest True @@ -807,10 +807,10 @@ def _repr_(self): EXAMPLES:: sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.MonomialGrowthGroup(ZZ, 'x') + sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: repr(AR) # indirect doctest - 'Asymptotic Ring over Monomial Growth Group in x over Integer Ring with coefficients from Integer Ring' + 'Asymptotic Ring over x^ZZ with coefficients from Integer Ring' """ return 'Asymptotic Ring over %s with coefficients ' \ 'from %s' % (self.growth_group, self.coefficient_ring) @@ -923,7 +923,7 @@ def create_term(self, type, growth=None, coefficient=None): EXAMPLES:: sage: import sage.groups.asymptotic_growth_group as agg - sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: G = agg.GrowthGroup('x^ZZ') sage: R = AsymptoticRing(G, ZZ) sage: R.create_term('O', x^2) O(x^2) From d34a451d9622d4f08330b0fb91bb4f1bca4f25ed Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 21 Jul 2015 16:58:20 +0200 Subject: [PATCH 0319/1872] asymptotic ring, classcall: short notation can be used to specify the growth group --- src/sage/rings/asymptotic_ring.py | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index bcf94c3fdda..52ca352f65d 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -576,22 +576,9 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, sage: AR1 is AR2 True """ - if not isinstance(names, tuple): - names = (names,) - - if len(names) > 1: - raise NotImplementedError('Currently only one variable is supported') - if isinstance(growth_group, str) and names is None: - raise ValueError('names has to be specified if the growth group ' - 'is to be constructed') - elif growth_group == 'monomial': - from sage.groups.asymptotic_growth_group import MonomialGrowthGroup - # coefficient ring acts as the base ring of the growth group! - growth_group = MonomialGrowthGroup(coefficient_ring, names[0]) - elif hasattr(growth_group, '_var_') and names is not None: - if names[0] == growth_group._var_: - raise ValueError('Specified variable %s and growth group variable ' - '%s do not match' % (names[0], growth_group._var_)) + if isinstance(growth_group, str): + from sage.groups.asymptotic_growth_group import GrowthGroup + growth_group = GrowthGroup(growth_group) return super(AsymptoticRing, cls).__classcall__(cls, growth_group, coefficient_ring, category) From 2c59df10ef20729d4f8babc45155e08582877bdd Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 21 Jul 2015 16:59:51 +0200 Subject: [PATCH 0320/1872] doctests fixed ('monomial' --> gone) --- src/sage/rings/asymptotic_ring.py | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 52ca352f65d..b4d0b10e715 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -33,7 +33,7 @@ sage: T = atm.ExactTermMonoid(G, ZZ) 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/17715 for details. - sage: R. = AsymptoticRing('monomial', ZZ) + sage: R. = AsymptoticRing('x^ZZ', ZZ) 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/17716 for details. @@ -70,7 +70,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): There are ways to create an asymptotic expression. First, we construct the corresponding parents:: - sage: R_x. = AsymptoticRing('monomial', QQ) + sage: R_x. = AsymptoticRing('x^QQ', QQ) sage: import sage.groups.asymptotic_growth_group as agg sage: G = agg.GrowthGroup('y^ZZ') sage: R_y = AsymptoticRing(G, ZZ); y = R_y.gen() @@ -165,8 +165,8 @@ def __init__(self, parent, poset, simplify=True): TESTS:: - sage: R_x. = AsymptoticRing('monomial', ZZ) - sage: R_y. = AsymptoticRing('monomial', ZZ) + sage: R_x. = AsymptoticRing('x^ZZ', ZZ) + sage: R_y. = AsymptoticRing('y^ZZ', ZZ) sage: R_x is R_y False sage: ex1 = x + 2*x^2 + 3*x^3 + 4*x^4 + 5*x^5 @@ -187,7 +187,7 @@ def poset(self): EXAMPLES:: - sage: R. = AsymptoticRing('monomial', ZZ) + sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr = 7 * x^12 + x^5 + O(x^3) sage: expr.poset poset(O(x^3), 1*x^5, 7*x^12) @@ -255,7 +255,7 @@ def _repr_(self, reverse=False): EXAMPLES:: - sage: R. = AsymptoticRing('monomial', ZZ) + sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr = (5*x^2 + 12*x) * (x^3 + O(x)) sage: repr(expr) # indirect doctest 'O(x^3) + 12*x^4 + 5*x^5' @@ -284,7 +284,7 @@ def _add_(self, other): An :class:`AsymptoticExpression`. EXAMPLES:: - sage: R. = AsymptoticRing('monomial', ZZ) + sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1._add_(expr2) 1*x^123 + 1*x^321 @@ -327,7 +327,7 @@ def _sub_(self, other): EXAMPLES:: - sage: R. = AsymptoticRing('monomial', ZZ) + sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1 - expr2 # indirect doctest 1*x^123 + -1*x^321 @@ -350,7 +350,7 @@ def _mul_term_(self, other): TESTS:: sage: import sage.monoids.asymptotic_term_monoid as atm - sage: R. = AsymptoticRing('monomial', ZZ) + sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: T = atm.OTermMonoid(R.growth_group) sage: expr = 10*x^2 + O(x) sage: t = T(R.growth_group.gen()) @@ -382,7 +382,7 @@ def _mul_(self, other): EXAMPLES:: - sage: R. = AsymptoticRing('monomial', ZZ) + sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: ex1 = 5*x^12 sage: ex2 = x^3 + O(x) sage: ex1 * ex2 # indirect doctest @@ -406,10 +406,10 @@ def __pow__(self, power): TESTS:: - sage: R_QQ. = AsymptoticRing('monomial', QQ) + sage: R_QQ. = AsymptoticRing('x^QQ', QQ) sage: x^(1/7) 1*x^(1/7) - sage: R_ZZ. = AsymptoticRing('monomial', ZZ) + sage: R_ZZ. = AsymptoticRing('y^ZZ', ZZ) sage: y^(1/7) Traceback (most recent call last): ... @@ -522,12 +522,12 @@ class AsymptoticRing(sage.rings.ring.Ring, a ring over an appropriate growth group. Note that in this case, also the variable name needs to be specified explicitly:: - sage: R2_x = AsymptoticRing(growth_group='monomial', coefficient_ring=QQ, names=('x',)); R2_x + sage: R2_x = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R2_x Asymptotic Ring over x^QQ with coefficients from Rational Field Alternatively, the preparser allows us to write:: - sage: R3_x. = AsymptoticRing(growth_group='monomial', coefficient_ring=QQ); R3_x + sage: R3_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R3_x Asymptotic Ring over x^QQ with coefficients from Rational Field According to the conventions for parents, uniqueness is ensured:: @@ -572,7 +572,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, sage: import sage.groups.asymptotic_growth_group as agg sage: MG = agg.GrowthGroup('x^ZZ') sage: AR1 = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) - sage: AR2. = AsymptoticRing(growth_group='monomial', coefficient_ring=ZZ) + sage: AR2. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR1 is AR2 True """ @@ -595,7 +595,7 @@ def __init__(self, growth_group=None, coefficient_ring=None, category=None): sage: G = agg.GrowthGroup('x^ZZ') sage: R1 = AsymptoticRing(G, ZZ); R1 Asymptotic Ring over x^ZZ with coefficients from Integer Ring - sage: R2. = AsymptoticRing('monomial', QQ); R2 + sage: R2. = AsymptoticRing('x^QQ', QQ); R2 Asymptotic Ring over x^QQ with coefficients from Rational Field sage: R1 is R2 False @@ -681,7 +681,7 @@ def _element_constructor_(self, data, poset=None, simplify=True): TESTS:: - sage: AR. = AsymptoticRing('monomial', ZZ) + sage: AR. = AsymptoticRing('x^ZZ', ZZ) sage: 3 * x^3 3*x^3 sage: 3 * x^3 + x @@ -753,10 +753,10 @@ def _coerce_map_from_(self, R): TESTS:: - sage: AR_ZZ = AsymptoticRing('monomial', coefficient_ring=ZZ, names='x'); AR_ZZ + sage: AR_ZZ = AsymptoticRing('x^ZZ', coefficient_ring=ZZ); AR_ZZ Asymptotic Ring over x^ZZ with coefficients from Integer Ring sage: x_ZZ = AR_ZZ.gen() - sage: AR_QQ = AsymptoticRing('monomial', coefficient_ring=QQ, names='x'); AR_QQ + sage: AR_QQ = AsymptoticRing('x^QQ', coefficient_ring=QQ); AR_QQ Asymptotic Ring over x^QQ with coefficients from Rational Field sage: x_QQ = AR_QQ.gen() sage: AR_QQ.has_coerce_map_from(AR_ZZ) # indirect doctest @@ -824,7 +824,7 @@ def gens(self): EXAMPLES:: - sage: AR. = AsymptoticRing('monomial', ZZ) + sage: AR. = AsymptoticRing('x^ZZ', ZZ) sage: AR.gens() (1*x,) """ @@ -854,7 +854,7 @@ def gen(self, n=0): EXAMPLES:: - sage: R. = AsymptoticRing('monomial', ZZ) + sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: R.gen() 1*x """ @@ -874,7 +874,7 @@ def ngens(self): EXAMPLES:: - sage: AR. = AsymptoticRing('monomial', ZZ) + sage: AR. = AsymptoticRing('x^ZZ', ZZ) sage: AR.ngens() 1 """ From 8833c6a45425722e90ab0ac83ac50e8ce2257f05 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 21 Jul 2015 17:50:21 +0200 Subject: [PATCH 0321/1872] adapted documentation and header --- src/sage/rings/asymptotic_ring.py | 36 ++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index b4d0b10e715..516c86c9e89 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -14,6 +14,7 @@ AUTHORS: - Benjamin Hackl (2015-06): initial version +- Benjamin Hackl (2015-07): improvement user interface (short notation) .. WARNING:: @@ -158,6 +159,14 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): +-- oo | +-- predecessors: 4*x^6 | +-- no successors + + In addition to the monomial growth elements from above, we can + also compute with logarithmic terms (simply by constructing the + appropriate growth group):: + + sage: R_log. = AsymptoticRing('log(x)^QQ', QQ) + sage: (O(xl) + xl^3)^4 + O(log(x)^10) + 1*log(x)^12 """ def __init__(self, parent, poset, simplify=True): r""" @@ -476,8 +485,7 @@ class AsymptoticRing(sage.rings.ring.Ring, - ``growth_group`` -- a partially ordered group (e.g. an instance of :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`), - or a string that describes the type of the growth group (e.g. - "monomial"). + or a short representation string of a growth group. - ``coefficient_ring`` -- the ring which contains the coefficients of the expressions. @@ -487,9 +495,6 @@ class AsymptoticRing(sage.rings.ring.Ring, subcategory of ``Category of rings``. This is also the default category if ``None`` is specified. - - ``names`` -- a tuple consisting of strings representing the - associated variables. - OUTPUT: An asymptotic ring. @@ -516,11 +521,14 @@ class AsymptoticRing(sage.rings.ring.Ring, sage: R_ZZ_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=ZZ); R_ZZ_x Asymptotic Ring over x^QQ with coefficients from Integer Ring - As mentioned above, the ring can also be constructed without - explicitly specifying the growth group. For example, passing the - string "monomial" as an argument for ``growth_group`` constructs - a ring over an appropriate growth group. Note that in this case, - also the variable name needs to be specified explicitly:: + As mentioned above, the short notation for growth groups can also + be used to specify the underlying growth group. For now, + representation strings of the form ``"variable^base"`` are + allowed, where ``variable`` is some string, and ``base`` is + either ``ZZ`` (for `\mathbb{Z}`), ``QQ`` (for `\mathbb{Q}`), + or ``SR`` (for the symbolic ring). These strings correspond to + monomial growth groups (see + :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`):: sage: R2_x = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R2_x Asymptotic Ring over x^QQ with coefficients from Rational Field @@ -530,6 +538,14 @@ class AsymptoticRing(sage.rings.ring.Ring, sage: R3_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R3_x Asymptotic Ring over x^QQ with coefficients from Rational Field + Note that this allows us to create logarithmic and polynomial + growth groups:: + + sage: R. = AsymptoticRing('x^ZZ', QQ); R + Asymptotic Ring over x^ZZ with coefficients from Rational Field + sage: R_log. = AsymptoticRing('log(x)^ZZ', QQ); R_log + Asymptotic Ring over log(x)^ZZ with coefficients from Rational Field + According to the conventions for parents, uniqueness is ensured:: sage: R_x is R2_x is R3_x From 8b1d0213349d676a7722bdf25c545b0d100069c1 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 21 Jul 2015 18:44:42 +0200 Subject: [PATCH 0322/1872] doctests fixed --- src/sage/rings/asymptotic_ring.py | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 516c86c9e89..198ff008a18 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -79,7 +79,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): At this point, `x` and `y` are already asymptotic expressions:: sage: (x, y) - (1*x, 1*y) + (x, y) sage: isinstance(x, sage.rings.asymptotic_ring.AsymptoticExpression) True sage: type(x) @@ -90,13 +90,13 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): sage: x^2 + 3*(x - x^2) 3*x + -2*x^2 sage: (3*x + 2)^3 - 8*1 + 36*x + 54*x^2 + 27*x^3 + 8 + 36*x + 54*x^2 + 27*x^3 In addition to that, special powers (determined by the base ring of the growth group) can also be computed:: sage: (x^(5/2) + x^(1/7)) * x^(-1/5) - 1*x^(-2/35) + 1*x^(23/10) + x^(-2/35) + x^(23/10) One of the central ideas behind computing with asymptotic expressions is that the `O`-notation (see @@ -112,15 +112,15 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): sage: expr1 = x + 2*x^2 + 3*x^3 + 4*x^4; expr2 = O(x) + x^2 sage: print(expr1.poset.repr_full()) - poset(1*x, 2*x^2, 3*x^3, 4*x^4) + poset(x, 2*x^2, 3*x^3, 4*x^4) +-- null | +-- no predecessors - | +-- successors: 1*x - +-- 1*x + | +-- successors: x + +-- x | +-- predecessors: null | +-- successors: 2*x^2 +-- 2*x^2 - | +-- predecessors: 1*x + | +-- predecessors: x | +-- successors: 3*x^3 +-- 3*x^3 | +-- predecessors: 2*x^2 @@ -132,18 +132,18 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): | +-- predecessors: 4*x^4 | +-- no successors sage: print(expr2.poset.repr_full()) - poset(O(x), 1*x^2) + poset(O(x), x^2) +-- null | +-- no predecessors | +-- successors: O(x) +-- O(x) | +-- predecessors: null - | +-- successors: 1*x^2 - +-- 1*x^2 + | +-- successors: x^2 + +-- x^2 | +-- predecessors: O(x) | +-- successors: oo +-- oo - | +-- predecessors: 1*x^2 + | +-- predecessors: x^2 | +-- no successors sage: print((expr1 * expr2).poset.repr_full()) poset(O(x^5), 4*x^6) @@ -166,7 +166,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): sage: R_log. = AsymptoticRing('log(x)^QQ', QQ) sage: (O(xl) + xl^3)^4 - O(log(x)^10) + 1*log(x)^12 + O(log(x)^10) + log(x)^12 """ def __init__(self, parent, poset, simplify=True): r""" @@ -199,7 +199,7 @@ def poset(self): sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr = 7 * x^12 + x^5 + O(x^3) sage: expr.poset - poset(O(x^3), 1*x^5, 7*x^12) + poset(O(x^3), x^5, 7*x^12) """ return self._poset_ @@ -231,7 +231,7 @@ def _simplify_(self): sage: R = AsymptoticRing(G, ZZ) sage: lst = [ET(x,1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] sage: expr = R(lst, simplify=False); expr # indirect doctest - 1*x + 2*x^2 + O(x^3) + 4*x^4 + x + 2*x^2 + O(x^3) + 4*x^4 sage: expr._simplify_(); expr O(x^3) + 4*x^4 sage: R(lst) # indirect doctest @@ -296,9 +296,9 @@ def _add_(self, other): sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1._add_(expr2) - 1*x^123 + 1*x^321 + x^123 + x^321 sage: expr1 + expr2 # indirect doctest - 1*x^123 + 1*x^321 + x^123 + x^321 If an `O`-term is added to an asymptotic expression, then the `O`-term absorbs everything it can:: @@ -339,7 +339,7 @@ def _sub_(self, other): sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1 - expr2 # indirect doctest - 1*x^123 + -1*x^321 + x^123 + -x^321 """ return self + (-1) * other @@ -417,14 +417,14 @@ def __pow__(self, power): sage: R_QQ. = AsymptoticRing('x^QQ', QQ) sage: x^(1/7) - 1*x^(1/7) + x^(1/7) sage: R_ZZ. = AsymptoticRing('y^ZZ', ZZ) sage: y^(1/7) Traceback (most recent call last): ... ValueError: Exponent 1/7 not in base of growth group y^ZZ sage: (x^(1/2) + O(x^0))^15 - O(x^7) + 1*x^(15/2) + O(x^7) + x^(15/2) """ P = self.parent() if len(self.poset._shells_) == 1: @@ -464,7 +464,7 @@ def O(self): sage: AR = AsymptoticRing(MG, ZZ) sage: x = AR.create_term('exact', x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr - O(x^2) + 1*x^10 + 42*x^42 + O(x^2) + x^10 + 42*x^42 sage: expr.O() O(x^42) """ @@ -701,7 +701,7 @@ def _element_constructor_(self, data, poset=None, simplify=True): sage: 3 * x^3 3*x^3 sage: 3 * x^3 + x - 1*x + 3*x^3 + x + 3*x^3 sage: (3 * x^3) * (5 * x) 15*x^4 sage: 3 * x^3 + O(x^5) @@ -778,7 +778,7 @@ def _coerce_map_from_(self, R): sage: AR_QQ.has_coerce_map_from(AR_ZZ) # indirect doctest True sage: x_ZZ * x_QQ - 1*x^2 + x^2 :: @@ -842,7 +842,7 @@ def gens(self): sage: AR. = AsymptoticRing('x^ZZ', ZZ) sage: AR.gens() - (1*x,) + (x,) """ from sage.groups.asymptotic_growth_group import MonomialGrowthGroup if isinstance(self.growth_group, MonomialGrowthGroup): @@ -872,7 +872,7 @@ def gen(self, n=0): sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: R.gen() - 1*x + x """ return self.gens()[n] From 1eb53c38e523f7850b27f8d0e6d07c0e013b7e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Jul 2015 17:17:16 +0200 Subject: [PATCH 0323/1872] adding conversion from Arc class to Bezier paths. --- src/sage/plot/arc.py | 57 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/src/sage/plot/arc.py b/src/sage/plot/arc.py index 04fac945f42..efbf72b739a 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -235,6 +235,48 @@ def _allowed_options(self): "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} + def _matplotlib_arc(self): + """ + Return ``self`` as a matplotlib arc object. + + EXAMPLES:: + + sage: from sage.plot.arc import Arc + sage: Arc(2,3,2.2,2.2,0,2,3,{})._matplotlib_arc() + + """ + import matplotlib.patches as patches + p = patches.Arc( + (self.x, self.y), + 2. * self.r1, + 2. * self.r2, + fmod(self.angle, 2 * pi) * (180. / pi), + self.s1 * (180. / pi), + self.s2 * (180. / pi)) + return p + + def bezier_path(self): + """ + Return ``self`` as a Bezier path. + + This is useful to concatenate arcs, in particular to + create hyperbolic polygons. + + EXAMPLES:: + + sage: from sage.plot.arc import Arc + sage: Arc(2,3,2.2,2.2,0,2,3,{}).bezier_path() + Graphics object consisting of 1 graphics primitive + """ + from sage.plot.bezier_path import bezier_path + points = [list(u) for u in self._matplotlib_arc()._path.vertices] + cutlist = [points[0: 4]] + N = 4 + while N < len(points): + cutlist += [points[N: N + 3]] + N += 3 + return bezier_path(cutlist) + def _repr_(self): """ String representation of ``Arc`` primitive. @@ -254,26 +296,19 @@ def _render_on_subplot(self, subplot): sage: A = arc((1,1),3,4,pi/4,(pi,4*pi/3)); A Graphics object consisting of 1 graphics primitive """ - import matplotlib.patches as patches from sage.plot.misc import get_matplotlib_linestyle - options = self.options() - p = patches.Arc( - (self.x,self.y), - 2.*self.r1, - 2.*self.r2, - fmod(self.angle,2*pi)*(180./pi), - self.s1*(180./pi), - self.s2*(180./pi)) + p = self._matplotlib_arc() p.set_linewidth(float(options['thickness'])) a = float(options['alpha']) p.set_alpha(a) - z = int(options.pop('zorder',1)) + z = int(options.pop('zorder', 1)) p.set_zorder(z) c = to_mpl_color(options['rgbcolor']) - p.set_linestyle(get_matplotlib_linestyle(options['linestyle'],return_type='long')) + p.set_linestyle(get_matplotlib_linestyle(options['linestyle'], + return_type='long')) p.set_edgecolor(c) subplot.add_patch(p) From 639c9f6b52d0740126e83cf13b2cb51066f35e1f Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Wed, 22 Jul 2015 20:34:36 -0500 Subject: [PATCH 0324/1872] fixed an odd typo --- src/sage/combinat/diagram_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 647dfda5787..f570963ecb1 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -577,7 +577,7 @@ def __init__(self, diagram_func, order, category = None): category = FiniteEnumeratedSets() Parent.__init__(self, category=category) self.diagram_func = diagram_func - self.order = orderda.partition_diagrams, + self.order = order, def __iter__(self): r""" From e2f4420d0fa2ac59eaa26e587e8f853459b821b0 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Wed, 22 Jul 2015 22:52:33 -0500 Subject: [PATCH 0325/1872] actually fixed merge conflict --- src/sage/combinat/diagram_algebras.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 35beb60930e..16e982f36d5 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -577,11 +577,7 @@ def __init__(self, diagram_func, order, category = None): category = FiniteEnumeratedSets() Parent.__init__(self, category=category) self.diagram_func = diagram_func -<<<<<<< HEAD - self.order = order, -======= self.order = order ->>>>>>> t/18762/create_coercion_between_diagram_algebras_and_the_symmetric_group_algebra def __iter__(self): r""" From 0532942d022ab898d6a5ca359ba9d5e18a753a11 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 13:45:07 +0200 Subject: [PATCH 0326/1872] GrowthGroupFactory extension: construction of cartesian products --- src/sage/groups/asymptotic_growth_group.py | 49 ++++++++++++++++++---- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index a945b142ded..84e9c4f79d7 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -1647,6 +1647,16 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): 'Monomial Growth Group in x over Integer Ring' sage: agg.GrowthGroup('log(x)^QQ')._repr_long_() 'Monomial Growth Group in log(x) over Rational Field' + + This factory can also be used to construct Cartesian products + of growth groups:: + + sage: agg.GrowthGroup('x^ZZ * y^ZZ') + Growth Group x^ZZ * y^ZZ + sage: agg.GrowthGroup('x^ZZ * log(x)^ZZ') + Growth Group x^ZZ * log(x)^ZZ + sage: agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ') + Growth Group x^ZZ * log(x)^ZZ * y^QQ """ def create_key_and_extra_args(self, rep, **kwds): r""" @@ -1689,12 +1699,8 @@ def create_object(self, version, key, **kwds): rep, = key factors_rep = rep.split(' * ') - - if len(factors_rep) > 1: - raise NotImplementedError('Cartesian product of growth groups not ' - 'yet implemented') - # note: implementation already for cartesian products! factors = [] + for factor in factors_rep: sp = factor.split('^') if len(sp) != 2: @@ -1717,10 +1723,37 @@ def create_object(self, version, key, **kwds): "representation" % factor) factors.append(G) - # todo: factors --> lists with factors over same variable. - return factors[0] + if len(factors) == 1: + return factors[0] + + # otherwise, a cartesian product is created. the growth elements + # in this products are + # - ordered lexicographically (over the same variable (or a + # function thereof) + # - ordered component-wise (for different variables) + + if len(set(factors)) != len(factors): + raise ValueError('The cartesian product of equal growth ' + 'groups is not supported') + + hom_var_groups = [] + mon_vars = [] + for factor in factors: + var = factor._var_ + if not mon_vars or mon_vars[-1] not in var or '(' + mon_vars[-1] + ')' not in var: + mon_vars.append(var) + hom_var_groups.append([factor]) + else: + hom_var_groups[-1].append(factor) + from sage.categories.cartesian_product import cartesian_product + for k in range(len(hom_var_groups)): + if len(hom_var_groups[k]) > 1: + hom_var_groups[k] = cartesian_product(hom_var_groups[k], + order='lex') + else: + hom_var_groups[k] = hom_var_groups[k][0] + return cartesian_product(hom_var_groups, order='components') GrowthGroup = GrowthGroupFactory("GrowthGroup") - From c547712afe3dc3ae87f8d51ce6a70a5b5df3f680 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 13:48:57 +0200 Subject: [PATCH 0327/1872] header modified --- src/sage/groups/asymptotic_growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 84e9c4f79d7..cdd9730cc2d 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -18,7 +18,7 @@ - Benjamin Hackl (2015-01): initial version - Daniel Krenn (2015-05-29): initial version and review - Daniel Krenn (2015-06-02): cartesian products -- Benjamin Hackl (2015-07): short representation strings +- Benjamin Hackl (2015-07): growth group factory .. WARNING:: From b262d972aa792e70bb0f3c1afded2aaeb102dd77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 23 Jul 2015 14:03:47 +0200 Subject: [PATCH 0328/1872] trac #18939 now with correct options and proportions + fully pep8/pyflakes ok --- src/sage/plot/arc.py | 222 +++++++++++++++++++++++++------------------ 1 file changed, 132 insertions(+), 90 deletions(-) diff --git a/src/sage/plot/arc.py b/src/sage/plot/arc.py index efbf72b739a..789e68e07f5 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -22,6 +22,7 @@ from math import fmod, sin, cos, pi, atan + class Arc(GraphicPrimitive): """ Primitive class for the Arc graphics type. See ``arc?`` for information @@ -87,7 +88,7 @@ def __init__(self, x, y, r1, r2, angle, s1, s2, options): self.s1 = float(s1) self.s2 = float(s2) if self.s2 < self.s1: - self.s1,self.s2=self.s2,self.s1 + self.s1, self.s2 = self.s2, self.s1 GraphicPrimitive.__init__(self, options) def get_minmax_data(self): @@ -126,91 +127,113 @@ def get_minmax_data(self): """ from sage.plot.plot import minmax_data - twopi = 2*pi + twopi = 2 * pi s1 = self.s1 s2 = self.s2 - s = s2-s1 - s1 = fmod(s1,twopi) - if s1 < 0: s1 += twopi - s2 = fmod(s1 + s,twopi) - if s2 < 0: s2 += twopi + s = s2 - s1 + s1 = fmod(s1, twopi) + if s1 < 0: + s1 += twopi + s2 = fmod(s1 + s, twopi) + if s2 < 0: + s2 += twopi r1 = self.r1 r2 = self.r2 - angle = fmod(self.angle,twopi) - if angle < 0: angle += twopi + angle = fmod(self.angle, twopi) + if angle < 0: + angle += twopi epsilon = float(0.0000001) cos_angle = cos(angle) sin_angle = sin(angle) - if cos_angle > 1-epsilon: - xmin=-r1; ymin=-r2 - xmax=r1; ymax=r2 - axmin = pi; axmax = 0 - aymin = 3*pi/2; aymax = pi/2 - - elif cos_angle < -1+epsilon: - xmin=-r1; ymin=-r2 - xmax=r1; ymax=r2 - axmin=0; axmax=pi - aymin=pi/2; aymax=3*pi/2 - - elif sin_angle > 1-epsilon: - xmin=-r2; ymin=-r1 - xmax=r2; ymax=r1 - axmin = pi/2; axmax = 3*pi/2 - aymin = pi; aymax = 0 - - elif sin_angle < -1+epsilon: - xmin=-r2; ymin=-r1 - xmax=r2; ymax=r1 - axmin = 3*pi/2; axmax = pi/2 - aymin = 0; aymax = pi + if cos_angle > 1 - epsilon: + xmin = -r1 + ymin = -r2 + xmax = r1 + ymax = r2 + axmin = pi + axmax = 0 + aymin = 3 * pi / 2 + aymax = pi / 2 + + elif cos_angle < -1 + epsilon: + xmin = -r1 + ymin = -r2 + xmax = r1 + ymax = r2 + axmin = 0 + axmax = pi + aymin = pi / 2 + aymax = 3 * pi / 2 + + elif sin_angle > 1 - epsilon: + xmin = -r2 + ymin = -r1 + xmax = r2 + ymax = r1 + axmin = pi / 2 + axmax = 3 * pi / 2 + aymin = pi + aymax = 0 + + elif sin_angle < -1 + epsilon: + xmin = -r2 + ymin = -r1 + xmax = r2 + ymax = r1 + axmin = 3 * pi / 2 + axmax = pi / 2 + aymin = 0 + aymax = pi else: tan_angle = sin_angle / cos_angle - axmax = atan(-r2/r1*tan_angle) - if axmax < 0: axmax += twopi - xmax = ( - r1 * cos_angle * cos(axmax) - - r2 * sin_angle * sin(axmax)) + axmax = atan(-r2 / r1 * tan_angle) + if axmax < 0: + axmax += twopi + xmax = (r1 * cos_angle * cos(axmax) - + r2 * sin_angle * sin(axmax)) if xmax < 0: xmax = -xmax - axmax = fmod(axmax+pi,twopi) + axmax = fmod(axmax + pi, twopi) xmin = -xmax - axmin = fmod(axmax + pi,twopi) + axmin = fmod(axmax + pi, twopi) - aymax = atan(r2/(r1*tan_angle)) - if aymax < 0: aymax += twopi - ymax = ( - r1 * sin_angle * cos(aymax) + - r2 * cos_angle * sin(aymax)) + aymax = atan(r2 / (r1 * tan_angle)) + if aymax < 0: + aymax += twopi + ymax = (r1 * sin_angle * cos(aymax) + + r2 * cos_angle * sin(aymax)) if ymax < 0: ymax = -ymax - aymax = fmod(aymax+pi,twopi) + aymax = fmod(aymax + pi, twopi) ymin = -ymax aymin = fmod(aymax + pi, twopi) - if s < twopi-epsilon: # bb determined by the sector - def is_cyclic_ordered(x1,x2,x3): - return ( - (x1 < x2 and x2 < x3) or - (x2 < x3 and x3 < x1) or - (x3 < x1 and x1 < x2)) - - x1 = cos_angle*r1*cos(s1) - sin_angle*r2*sin(s1) - x2 = cos_angle*r1*cos(s2) - sin_angle*r2*sin(s2) - y1 = sin_angle*r1*cos(s1) + cos_angle*r2*sin(s1) - y2 = sin_angle*r1*cos(s2) + cos_angle*r2*sin(s2) - - if is_cyclic_ordered(s1,s2,axmin): xmin = min(x1,x2) - if is_cyclic_ordered(s1,s2,aymin): ymin = min(y1,y2) - if is_cyclic_ordered(s1,s2,axmax): xmax = max(x1,x2) - if is_cyclic_ordered(s1,s2,aymax): ymax = max(y1,y2) + if s < twopi - epsilon: # bb determined by the sector + def is_cyclic_ordered(x1, x2, x3): + return ((x1 < x2 and x2 < x3) or + (x2 < x3 and x3 < x1) or + (x3 < x1 and x1 < x2)) + + x1 = cos_angle * r1 * cos(s1) - sin_angle * r2 * sin(s1) + x2 = cos_angle * r1 * cos(s2) - sin_angle * r2 * sin(s2) + y1 = sin_angle * r1 * cos(s1) + cos_angle * r2 * sin(s1) + y2 = sin_angle * r1 * cos(s2) + cos_angle * r2 * sin(s2) + + if is_cyclic_ordered(s1, s2, axmin): + xmin = min(x1, x2) + if is_cyclic_ordered(s1, s2, aymin): + ymin = min(y1, y2) + if is_cyclic_ordered(s1, s2, axmax): + xmax = max(x1, x2) + if is_cyclic_ordered(s1, s2, aymax): + ymax = max(y1, y2) return minmax_data([self.x + xmin, self.x + xmax], [self.y + ymin, self.y + ymax], @@ -226,12 +249,12 @@ def _allowed_options(self): sage: p[0]._allowed_options()['alpha'] 'How transparent the figure is.' """ - return {'alpha':'How transparent the figure is.', - 'thickness':'How thick the border of the arc is.', - 'hue':'The color given as a hue.', - 'rgbcolor':'The color', - 'zorder':'2D only: The layer level in which to draw', - 'linestyle':"2D only: The style of the line, which is one of " + return {'alpha': 'How transparent the figure is.', + 'thickness': 'How thick the border of the arc is.', + 'hue': 'The color given as a hue.', + 'rgbcolor': 'The color', + 'zorder': '2D only: The layer level in which to draw', + 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} @@ -246,36 +269,54 @@ def _matplotlib_arc(self): """ import matplotlib.patches as patches - p = patches.Arc( - (self.x, self.y), - 2. * self.r1, - 2. * self.r2, - fmod(self.angle, 2 * pi) * (180. / pi), - self.s1 * (180. / pi), - self.s2 * (180. / pi)) + p = patches.Arc((self.x, self.y), + 2. * self.r1, + 2. * self.r2, + fmod(self.angle, 2 * pi) * (180. / pi), + self.s1 * (180. / pi), + self.s2 * (180. / pi)) return p def bezier_path(self): """ Return ``self`` as a Bezier path. - This is useful to concatenate arcs, in particular to + This is needed to concatenate arcs, in order to create hyperbolic polygons. - + EXAMPLES:: sage: from sage.plot.arc import Arc - sage: Arc(2,3,2.2,2.2,0,2,3,{}).bezier_path() + sage: op = {'alpha':0,'thickness':1,'rgbcolor':'blue','zorder':0, + ....: 'linestyle':'--'} + sage: Arc(2,3,2.2,2.2,0,2,3,op).bezier_path() Graphics object consisting of 1 graphics primitive + + sage: a = arc((0,0),2,1,0,(pi/5,pi/2+pi/12), linestyle="--", color="red") + sage: b = a[0].bezier_path() + sage: b[0] + Bezier path from (1.618..., 0.5877...) to (-0.5176..., 0.9659...) """ - from sage.plot.bezier_path import bezier_path - points = [list(u) for u in self._matplotlib_arc()._path.vertices] + from sage.plot.bezier_path import BezierPath + from sage.plot.graphics import Graphics + ma = self._matplotlib_arc() + transform = ma.get_transform().get_matrix() + cA, cC, cE = transform[0] + cB, cD, cF = transform[1] + points = [] + for u in ma._path.vertices: + x, y = list(u) + points += [(cA * x + cC * y + cE, cB * x + cD * y + cF)] cutlist = [points[0: 4]] N = 4 while N < len(points): cutlist += [points[N: N + 3]] N += 3 - return bezier_path(cutlist) + g = Graphics() + opt = self.options() + opt['fill'] = False + g.add_primitive(BezierPath(cutlist, opt)) + return g def _repr_(self): """ @@ -287,7 +328,7 @@ def _repr_(self): sage: print Arc(2,3,2.2,2.2,0,2,3,{}) Arc with center (2.0,3.0) radii (2.2,2.2) angle 0.0 inside the sector (2.0,3.0) """ - return "Arc with center (%s,%s) radii (%s,%s) angle %s inside the sector (%s,%s)" %(self.x,self.y,self.r1,self.r2,self.angle,self.s1,self.s2) + return "Arc with center (%s,%s) radii (%s,%s) angle %s inside the sector (%s,%s)" % (self.x, self.y, self.r1, self.r2, self.angle, self.s1, self.s2) def _render_on_subplot(self, subplot): """ @@ -324,10 +365,11 @@ def plot3d(self): """ raise NotImplementedError + @rename_keyword(color='rgbcolor') -@options(alpha=1, thickness=1, linestyle='solid', zorder=5,rgbcolor='blue', +@options(alpha=1, thickness=1, linestyle='solid', zorder=5, rgbcolor='blue', aspect_ratio=1.0) -def arc(center, r1, r2=None, angle=0.0, sector=(0.0,2*pi), **options): +def arc(center, r1, r2=None, angle=0.0, sector=(0.0, 2 * pi), **options): r""" An arc (that is a portion of a circle or an ellipse) @@ -407,19 +449,19 @@ def arc(center, r1, r2=None, angle=0.0, sector=(0.0,2*pi), **options): if scale == 'semilogy' or scale == 'semilogx': options['aspect_ratio'] = 'automatic' - if len(center)==2: - if r2 is None: r2 = r1 + if len(center) == 2: + if r2 is None: + r2 = r1 g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) if len(sector) != 2: raise ValueError("the sector must consist of two angles") g.add_primitive(Arc( - center[0],center[1], - r1,r2, + center[0], center[1], + r1, r2, angle, - sector[0],sector[1], + sector[0], sector[1], options)) return g - elif len(center)==3: + elif len(center) == 3: raise NotImplementedError - From 3af46e709eedb52f85457de2f1f6c326c9db9918 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 15:53:57 +0200 Subject: [PATCH 0329/1872] no unneccessary cartesian products --- src/sage/groups/asymptotic_growth_group.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index cdd9730cc2d..984c5e954be 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -1754,6 +1754,9 @@ def create_object(self, version, key, **kwds): else: hom_var_groups[k] = hom_var_groups[k][0] + if len(hom_var_groups) == 1: + return hom_var_groups[0] + return cartesian_product(hom_var_groups, order='components') GrowthGroup = GrowthGroupFactory("GrowthGroup") From 2e47dc2df348f80446c4724f6c8c066c2aa29d21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Thu, 23 Jul 2015 16:58:14 +0300 Subject: [PATCH 0330/1872] Shorted doc for is_chain_of_poset(). --- src/sage/combinat/posets/posets.py | 65 +++++++++--------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 047af78e04a..086d52e611e 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -114,10 +114,10 @@ :delim: | :meth:`~FinitePoset.is_chain_of_poset` | Return ``True`` if given iterable is a chain of the poset. - :meth:`~FinitePoset.chains` | Return all the chains of ``self``. + :meth:`~FinitePoset.chains` | Return the chains of the poset. :meth:`~FinitePoset.antichains` | Return the antichains of the poset. - :meth:`~FinitePoset.maximal_chains` | Return all maximal chains of the poset. - :meth:`~FinitePoset.maximal_antichains` | Return all maximal antichains of the poset. + :meth:`~FinitePoset.maximal_chains` | Return the maximal chains of the poset. + :meth:`~FinitePoset.maximal_antichains` | Return the maximal antichains of the poset. :meth:`~FinitePoset.antichains_iterator` | Return an iterator over the antichains of the poset. **Drawing** @@ -2392,77 +2392,48 @@ def is_chain(self): """ return self._hasse_diagram.is_chain() - def is_chain_of_poset(self, o, ordered=False): + def is_chain_of_poset(self, elms, ordered=False): """ - Return whether an iterable ``o`` is a chain of ``self``, - including a check for ``o`` being ordered from smallest - to largest element if the keyword ``ordered`` is set to - ``True``. + Return ``True`` if `elms` is a chain of the poset, and ``False`` otherwise. INPUT: - - ``o`` -- an iterable (e. g., list, set, or tuple) - containing some elements of ``self`` + - ``elms`` -- an iterable (e. g., list, set, or tuple) + containing some elements of the poset - - ``ordered`` -- a Boolean (default: ``False``) which - decides whether the notion of a chain includes being - ordered - - OUTPUT: - - If ``ordered`` is set to ``False``, the truth value of - the following assertion is returned: The subset of ``self`` - formed by the elements of ``o`` is a chain in ``self``. - - If ``ordered`` is set to ``True``, the truth value of - the following assertion is returned: Every element of the - list ``o`` is (strictly!) smaller than its successor in - ``self``. (This makes no sense if ``ordered`` is a set.) + - ``ordered`` -- a Boolean. If ``True``, then return ``True`` + only if elements in `elms` are strictly increasing in the poset. If + ``False`` (the default), then elements can be repeated and be in any + order. EXAMPLES:: sage: P = Poset((divisors(12), attrcall("divides"))) sage: sorted(P.list()) [1, 2, 3, 4, 6, 12] - sage: P.is_chain_of_poset([2, 4]) + sage: P.is_chain_of_poset([12, 3]) True - sage: P.is_chain_of_poset([12, 6]) - True - sage: P.is_chain_of_poset([12, 6], ordered=True) + sage: P.is_chain_of_poset({3, 4, 12}) False - sage: P.is_chain_of_poset([6, 12], ordered=True) - True - sage: P.is_chain_of_poset(()) - True - sage: P.is_chain_of_poset((), ordered=True) - True - sage: P.is_chain_of_poset((3, 4, 12)) - False - sage: P.is_chain_of_poset((3, 6, 12, 1)) - True - sage: P.is_chain_of_poset((3, 6, 12, 1), ordered=True) + sage: P.is_chain_of_poset([12, 3], ordered=True) False - sage: P.is_chain_of_poset((3, 6, 12), ordered=True) - True sage: P.is_chain_of_poset((1, 1, 3)) True sage: P.is_chain_of_poset((1, 1, 3), ordered=True) False sage: P.is_chain_of_poset((1, 3), ordered=True) True - sage: P.is_chain_of_poset((6, 1, 1, 3)) - True - sage: P.is_chain_of_poset((2, 1, 1, 3)) - False """ if ordered: - sorted_o = o + if not hasattr(elms, '__getitem__'): + raise TypeError("ordered=True not combatible with type %s for elms" % type(elms)) + sorted_o = elms return all(self.lt(a, b) for a, b in zip(sorted_o, sorted_o[1:])) else: # _element_to_vertex can be assumed to be a linear extension # of the poset according to the documentation of class # HasseDiagram. - sorted_o = sorted(o, key=self._element_to_vertex) + sorted_o = sorted(elms, key=self._element_to_vertex) return all(self.le(a, b) for a, b in zip(sorted_o, sorted_o[1:])) def is_connected(self): From 7e0fb9ef5ef47c27e60684affbcf7a31aab61ad0 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 18:29:13 +0200 Subject: [PATCH 0331/1872] representation of cartesian product elements improved --- src/sage/groups/asymptotic_growth_group.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 984c5e954be..da607d4ee76 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -231,7 +231,10 @@ def _repr_(self): sage: cartesian_product([P, L], order='lex').an_element()._repr_() 'x^(1/2) * log(x)' """ - return ' * '.join(repr(v) for v in self.value) + s = ' * '.join(repr(v) for v in self.value if not v.is_one()) + if s == '': + return '1' + return s CartesianProductGrowthGroups.CartesianProduct = CartesianProductGrowthGroups From ca73a61d07fae03a447a05b3b6fa875c7cb7a3cc Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 18:30:38 +0200 Subject: [PATCH 0332/1872] module description improved --- src/sage/groups/asymptotic_growth_group.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index da607d4ee76..508cca8d00e 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -7,8 +7,7 @@ - :class:`MonomialGrowthGroup` (whose elements are powers of a fixed symbol). -More complex growth groups can be constructed via cartesian products -(to be implemented). +More complex growth groups can be constructed via cartesian products. These growth groups are used behind the scenes when performing calculations in an asymptotic ring (to be implemented). @@ -37,6 +36,23 @@ 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/17600 for details. x^ZZ + + +.. NOTE:: + + By using the following short notation for growth groups, their + creation is very simple: *Monomial growth groups* (i.e. the + group for powers of a fixed symbol; + :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`) + are denoted as ``variable^base``, e.g. ``x^ZZ`` and ``y^QQ`` for + the group of integer powers of `x`, and the group of rational + powers of `y`, respectively. + + This also enables us to construct *logarithmic growth groups*, + e.g. ``log(x)^ZZ``. + + This notation will also be extended to *Exponential growth + groups*. """ #***************************************************************************** From ab9bcaf6861392a7b478138a73313418bbfa8451 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 18:31:12 +0200 Subject: [PATCH 0333/1872] element constructor of monomial growth groups also try to parse the representation string --- src/sage/groups/asymptotic_growth_group.py | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 508cca8d00e..5b950de5e05 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -1504,6 +1504,17 @@ def _convert_(self, data): Traceback (most recent call last): ... ValueError: Cannot convert w^7. + + :: + + sage: P('x^7') + x^7 + sage: P('1/x') + 1/x + sage: P('x^(-2)') + x^(-2) + sage: P('x^-2') + x^(-2) """ if data == 1: return self.base().zero() @@ -1513,7 +1524,17 @@ def _convert_(self, data): try: P = data.parent() except AttributeError: - return # this has to end here + if self._var_ not in str(data): + return # this has to end here + + elif str(data) == '1/' + self._var_: + return self.base()(-1) + elif str(data).startswith(self._var_ + '^'): + return self.base()(str(data).replace(self._var_ + '^', '') + .replace('(', '').replace(')', '')) + else: + return # end of parsing + from sage.symbolic.ring import SR from sage.rings.polynomial.polynomial_ring import PolynomialRing_general From a899bb743c4167ceacc688290a730cbcab04c467 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 18:31:51 +0200 Subject: [PATCH 0334/1872] element constructor for cartesian product elements implemented --- src/sage/groups/asymptotic_growth_group.py | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 5b950de5e05..94cbcf95d7b 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -179,6 +179,74 @@ class CartesianProductGrowthGroups(CartesianProductPosets): :class:`~sage.sets.cartesian_product.CartesianProductPosets`. """ + def _element_constructor_(self, data): + r""" + Converts the given object to an element of this cartesian + product. + + TESTS:: + + sage: from sage.groups.asymptotic_growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * y^ZZ') + sage: G_log = GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ') + + Conversion from the symbolic ring works:: + + sage: x,y = var('x y') + sage: G(x^-3 * y^2) + x^(-3) * y^2 + sage: G(x^4), G(y^2) + (x^4, y^2) + sage: G(1) + 1 + + Even more complex expressions can be parsed:: + + sage: G_log(x^42 * log(x)^-42 * y^42) + x^42 * log(x)^(-42) * y^42 + """ + if data == 1: + return self.one() + + if isinstance(data, list): + try: + obj = super(CartesianProductGrowthGroups, + self)._element_constructor_(data) + return obj + except ValueError: + factors = self.cartesian_factors() + one = self.one().value + for k in range(len(data)): + for l in range(len(factors)): + try: + conv_data = factors[l](data[k]) + data[k] = self([one[j] if j != l else conv_data + for j in range(len(one))]) + break + except (ValueError, TypeError): + continue + return self.prod(data) + + + if hasattr(data, 'parent'): + if data.parent() is self: + return data + + elif data.parent() is sage.symbolic.ring.SR: + import operator + from sage.symbolic.operators import mul_vararg + if data.operator() == operator.pow or data.is_symbol(): + return self([data]) + elif data.operator() == mul_vararg: + return self(data.operands()) + # room for other parents (e.g. polynomial ring et al.) + + # final attempt: try to parse the representation string + else: + str_lst = repr(data).replace(' ', '').split('*') + return self(str_lst) + + def _repr_(self): r""" A representation string for this cartesian product of growth groups. From 537f22c94d9014873f50a8a0bdca1cb0e631da3d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 18:45:25 +0200 Subject: [PATCH 0335/1872] problem with parsing of strings fixed --- src/sage/groups/asymptotic_growth_group.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 94cbcf95d7b..60fb063eaf8 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -184,7 +184,7 @@ def _element_constructor_(self, data): Converts the given object to an element of this cartesian product. - TESTS:: + EXAMPLES:: sage: from sage.groups.asymptotic_growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ * y^ZZ') @@ -204,6 +204,12 @@ def _element_constructor_(self, data): sage: G_log(x^42 * log(x)^-42 * y^42) x^42 * log(x)^(-42) * y^42 + + TESTS:: + + sage: G = GrowthGroup('x^ZZ * y^ZZ') + sage: G('x'), G('y') + (x, y) """ if data == 1: return self.one() @@ -243,7 +249,7 @@ def _element_constructor_(self, data): # final attempt: try to parse the representation string else: - str_lst = repr(data).replace(' ', '').split('*') + str_lst = str(data).replace(' ', '').split('*') return self(str_lst) From 327d7ca8c6ecedff6d07a02db164082ec37ae52d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 23 Jul 2015 18:45:52 +0200 Subject: [PATCH 0336/1872] module documentation: added some doctests --- src/sage/groups/asymptotic_growth_group.py | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 60fb063eaf8..25ef31d39a6 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -53,6 +53,33 @@ This notation will also be extended to *Exponential growth groups*. + +EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: G_x = agg.GrowthGroup('x^ZZ'); G_x._repr_long_() + 'Monomial Growth Group in x over Integer Ring' + sage: G_xy = agg.GrowthGroup('x^ZZ * y^ZZ'); G_xy + Growth Group x^ZZ * y^ZZ + sage: G_xy.an_element() + x * y + sage: x = G_xy('x'); y = G_xy('y') + sage: elem = x^21 * y^21; elem^2 + x^42 * y^42 + +A monomial growth group itself is totally ordered, all elements +are comparable. However, this does **not** hold for cartesian +products:: + + sage: e1 = x^2 * y; e2 = x * y^2 + sage: e1 <= e2 or e2 <= e1 + False + +In terms of uniqueness, the order of factors in the cartesian +product matters:: + + sage: agg.GrowthGroup('x^ZZ * y^ZZ') is agg.GrowthGroup('y^ZZ * x^ZZ') + False """ #***************************************************************************** From 041cf315cbec72a405b59e004e6a16d24474c9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Fri, 24 Jul 2015 14:17:58 +0300 Subject: [PATCH 0337/1872] Minor changes in doc for chains(). --- src/sage/combinat/posets/posets.py | 40 ++++++++++++++---------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 086d52e611e..1c9771be862 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -3435,51 +3435,47 @@ def dilworth_decomposition(self): def chains(self, element_constructor=__builtin__.list, exclude=None): """ - Return all the chains of ``self``. + Return the chains of the poset. + + A *chain* of a poset is a set of elements of the poset + that are pairwise comparable. INPUT: - ``element_constructor`` -- a function taking an iterable as - argument (default: ``list``) + argument (default: ``list``) - ``exclude`` -- elements of the poset to be excluded (default: ``None``) OUTPUT: - The enumerated set of all chains of ``self``, each of which - is given as an ``element_constructor``. - - A *chain* of a poset is a set of elements of the poset - that are pairwise comparable. + The enumerated set (of type + :class:`~sage.combinat.subsets_pairwise.PairwiseCompatibleSubsets`) + of all chains of the poset, each of which is given as an + ``element_constructor``. EXAMPLES:: - sage: A = Posets.PentagonPoset().chains(); A + sage: C = Posets.PentagonPoset().chains(); C Set of chains of Finite lattice containing 5 elements - sage: list(A) + sage: list(C) [[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4], [0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]] - To get the chains of a given size one can currently use:: - - sage: list(A.elements_of_depth_iterator(2)) - [[0, 1], [0, 2], [0, 3], [0, 4], [1, 4], [2, 3], [2, 4], [3, 4]] - - For bounded posets, one can exclude the bounds as follows:: - - sage: P = Posets.DiamondPoset(5) - sage: list(P.chains(exclude=[0, 4])) - [[], [1], [2], [3]] - - Another example of exclusion of vertices:: + Exclusion of vertices, tuple (instead of list) as constructor:: sage: P = Poset({1: [2, 3], 2: [4], 3: [4, 5]}) sage: list(P.chains(element_constructor=tuple, exclude=[3])) [(), (1,), (1, 2), (1, 2, 4), (1, 4), (1, 5), (2,), (2, 4), (4,), (5,)] + To get the chains of a given size one can currently use:: + + sage: list(C.elements_of_depth_iterator(2)) + [[0, 1], [0, 2], [0, 3], [0, 4], [1, 4], [2, 3], [2, 4], [3, 4]] + Eventually the following syntax will be accepted:: - sage: A.subset(size = 2) # todo: not implemented + sage: C.subset(size = 2) # todo: not implemented .. SEEALSO:: :meth:`maximal_chains`, :meth:`antichains` """ From d185533c18017b13368fd37886fbfe98af909cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Fri, 24 Jul 2015 14:33:53 +0300 Subject: [PATCH 0338/1872] Minor changes in doc for antichains(). --- src/sage/combinat/posets/posets.py | 33 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 1c9771be862..9203c99dbfe 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -3255,17 +3255,22 @@ def isomorphic_subposets(self, other): def antichains(self, element_constructor = __builtin__.list): """ - Returns the antichains of the poset. + Return the antichains of the poset. + + An *antichain* of a poset is a set of elements of the + poset that are pairwise incomparable. INPUT: - ``element_constructor`` -- a function taking an iterable as - argument (default: list) + argument (default: ``list``) - OUTPUT: an enumerated set + OUTPUT: - An *antichain* of a poset is a collection of elements of the - poset that are pairwise incomparable. + The enumerated set (of type + :class:`~sage.combinat.subsets_pairwise.PairwiseCompatibleSubsets`) + of all antichains of the poset, each of which is given as an + ``element_constructor.`` EXAMPLES:: @@ -3277,10 +3282,12 @@ def antichains(self, element_constructor = __builtin__.list): 8 sage: A[3] [1, 2] - sage: list(Posets.AntichainPoset(3).antichains()) - [[], [2], [2, 1], [2, 1, 0], [2, 0], [1], [1, 0], [0]] - sage: list(Posets.ChainPoset(3).antichains()) - [[], [0], [1], [2]] + + To get the antichains as, say, sets, one may use the + ``element_constructor`` option:: + + sage: list(Posets.ChainPoset(3).antichains(element_constructor=set)) + [set(), {0}, {1}, {2}] To get the antichains of a given size one can currently use:: @@ -3291,12 +3298,6 @@ def antichains(self, element_constructor = __builtin__.list): sage: A.subset(size = 2) # todo: not implemented - To get the antichains as, say, sets, one may use the - ``element_constructor`` option:: - - sage: list(Posets.ChainPoset(3).antichains(element_constructor = set)) - [set(), {0}, {1}, {2}] - .. NOTE:: Internally, this uses @@ -3312,7 +3313,7 @@ def antichains(self, element_constructor = __builtin__.list): On the other hand, this returns a full featured enumerated set, with containment testing, etc. - .. seealso:: :meth:`maximal_antichains` + .. seealso:: :meth:`maximal_antichains`, :meth:`chains` """ vertex_to_element = self._vertex_to_element From 9642c432505970dff49d647900ecd218596670ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Fri, 24 Jul 2015 14:45:33 +0300 Subject: [PATCH 0339/1872] Minor addition to maximal_antichains(). --- src/sage/combinat/posets/posets.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 9203c99dbfe..b28f68bf6ea 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -4395,7 +4395,11 @@ def incomparability_graph(self): def maximal_antichains(self): """ - Return all maximal antichains of the poset. + Return the maximal antichains of the poset. + + An antichain `a` of poset `P` is *maximal* if there is + no element `e \in P \setminus a` such that `a \cup \{e\}` + is an antichain. EXAMPLES:: @@ -4406,7 +4410,7 @@ def maximal_antichains(self): sage: Posets.PentagonPoset().maximal_antichains() [[0], [1, 2], [1, 3], [4]] - .. seealso:: :meth:`maximal_chains`, :meth:`antichains` + .. seealso:: :meth:`antichains`, :meth:`maximal_chains` """ # Maximal antichains are maximum cliques on incomparability graph. return self.incomparability_graph().cliques_maximal() From df6d947928eda82b989a1fd104c7ed57e911cbd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Fri, 24 Jul 2015 15:40:49 +0300 Subject: [PATCH 0340/1872] An example to antichains_iterator(). --- src/sage/combinat/posets/posets.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index b28f68bf6ea..9548e27ea38 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -3325,12 +3325,14 @@ def f(antichain): def antichains_iterator(self): """ - Returns an iterator over the antichains of the poset. + Return an iterator over the antichains of the poset. EXAMPLES:: - sage: Posets.PentagonPoset().antichains_iterator() + sage: it = Posets.PentagonPoset().antichains_iterator(); it + sage: it.next(), it.next() + ([], [4]) .. SEEALSO:: :meth:`antichains` """ From d03abe547f173f390c2debdc738551fb1de34e9c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 10:42:47 +0200 Subject: [PATCH 0341/1872] repr-option to suppress words "Growth Group" --- src/sage/groups/asymptotic_growth_group.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 9bf9b8afe1c..fcb6ca624d7 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -637,13 +637,14 @@ def _repr_short_(self): return 'Generic(%s)' % (parent_to_repr_short(self.base()),) - def _repr_(self): + def _repr_(self, display_GrowthGroup=True): r""" A representations string of this growth group. INPUT: - Nothing. + - ``display_GrowthGroupNothing`` -- (default: ``True``) if set, then + the prefix-string ``Growth Group`` is show, otherwise not. OUTPUT: @@ -656,8 +657,14 @@ def _repr_(self): Growth Group x^ZZ sage: agg.MonomialGrowthGroup(QQ, 'log(x)') # indirect doctest Growth Group log(x)^QQ + + TESTS:: + + sage: agg.MonomialGrowthGroup(QQ, 'log(x)')._repr_(display_GrowthGroup=False) + 'log(x)^QQ' """ - return 'Growth Group %s' % (self._repr_short_(),) + GG = 'Growth Group ' if display_GrowthGroup else '' + return '%s%s' % (GG, self._repr_short_(),) def __hash__(self): From 921b2f82fdf5695def96fbdc4cfabb21993ed771 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 10:53:10 +0200 Subject: [PATCH 0342/1872] change repr-string of ring --- src/sage/rings/asymptotic_ring.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 198ff008a18..05eb7c752bb 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -512,14 +512,14 @@ class AsymptoticRing(sage.rings.ring.Ring, sage: import sage.groups.asymptotic_growth_group as agg sage: G_QQ = agg.GrowthGroup('x^QQ') sage: R_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=QQ); R_x - Asymptotic Ring over x^QQ with coefficients from Rational Field + Asymptotic Ring over Rational Field Note that the coefficient ring of the asymptotic ring and the base ring of the underlying growth group do not need to coincide:: sage: R_ZZ_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=ZZ); R_ZZ_x - Asymptotic Ring over x^QQ with coefficients from Integer Ring + Asymptotic Ring over Integer Ring As mentioned above, the short notation for growth groups can also be used to specify the underlying growth group. For now, @@ -531,20 +531,20 @@ class AsymptoticRing(sage.rings.ring.Ring, :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`):: sage: R2_x = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R2_x - Asymptotic Ring over x^QQ with coefficients from Rational Field + Asymptotic Ring over Rational Field Alternatively, the preparser allows us to write:: sage: R3_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R3_x - Asymptotic Ring over x^QQ with coefficients from Rational Field + Asymptotic Ring over Rational Field Note that this allows us to create logarithmic and polynomial growth groups:: sage: R. = AsymptoticRing('x^ZZ', QQ); R - Asymptotic Ring over x^ZZ with coefficients from Rational Field + Asymptotic Ring over Rational Field sage: R_log. = AsymptoticRing('log(x)^ZZ', QQ); R_log - Asymptotic Ring over log(x)^ZZ with coefficients from Rational Field + Asymptotic Ring over Rational Field According to the conventions for parents, uniqueness is ensured:: @@ -610,9 +610,9 @@ def __init__(self, growth_group=None, coefficient_ring=None, category=None): sage: import sage.groups.asymptotic_growth_group as agg sage: G = agg.GrowthGroup('x^ZZ') sage: R1 = AsymptoticRing(G, ZZ); R1 - Asymptotic Ring over x^ZZ with coefficients from Integer Ring + Asymptotic Ring over Integer Ring sage: R2. = AsymptoticRing('x^QQ', QQ); R2 - Asymptotic Ring over x^QQ with coefficients from Rational Field + Asymptotic Ring over Rational Field sage: R1 is R2 False @@ -770,10 +770,10 @@ def _coerce_map_from_(self, R): TESTS:: sage: AR_ZZ = AsymptoticRing('x^ZZ', coefficient_ring=ZZ); AR_ZZ - Asymptotic Ring over x^ZZ with coefficients from Integer Ring + Asymptotic Ring over Integer Ring sage: x_ZZ = AR_ZZ.gen() sage: AR_QQ = AsymptoticRing('x^QQ', coefficient_ring=QQ); AR_QQ - Asymptotic Ring over x^QQ with coefficients from Rational Field + Asymptotic Ring over Rational Field sage: x_QQ = AR_QQ.gen() sage: AR_QQ.has_coerce_map_from(AR_ZZ) # indirect doctest True @@ -813,10 +813,13 @@ def _repr_(self): sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: repr(AR) # indirect doctest - 'Asymptotic Ring over x^ZZ with coefficients from Integer Ring' + 'Asymptotic Ring over Integer Ring' """ - return 'Asymptotic Ring over %s with coefficients ' \ - 'from %s' % (self.growth_group, self.coefficient_ring) + try: + G = '<' + self.growth_group._repr_(display_GrowthGroup=False) + '>' + except TypeError: + G = repr(self.growth_group) + return 'Asymptotic Ring %s over %s' % (G, self.coefficient_ring) def gens(self): From 7ebca64f1a9bb56a391f72f20d7b1e4d1d0c0e05 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 10:53:35 +0200 Subject: [PATCH 0343/1872] fix doctests after merge of group factory --- src/sage/rings/asymptotic_ring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 05eb7c752bb..be4c00df698 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -30,7 +30,7 @@ sage: import sage.monoids.asymptotic_term_monoid as atm sage: G = agg.MonomialGrowthGroup(ZZ, 'x') 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/17600 for details. + See http://trac.sagemath.org/17601 for details. sage: T = atm.ExactTermMonoid(G, ZZ) 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/17715 for details. @@ -422,7 +422,7 @@ def __pow__(self, power): sage: y^(1/7) Traceback (most recent call last): ... - ValueError: Exponent 1/7 not in base of growth group y^ZZ + ValueError: Exponent 1/7 not in base of growth group Growth Group y^ZZ sage: (x^(1/2) + O(x^0))^15 O(x^7) + x^(15/2) """ @@ -657,7 +657,7 @@ def growth_group(self): sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: AR.growth_group - x^ZZ + Growth Group x^ZZ """ return self._growth_group_ From 7b7ff44a4549fb274c69ec658e4822e9cc71f3de Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 10:58:56 +0200 Subject: [PATCH 0344/1872] changes during review: minor docstring rewritings, additional tests, minor code changes --- src/sage/rings/asymptotic_ring.py | 74 ++++++++++++++++++------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index be4c00df698..2702cee019a 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -54,22 +54,23 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): r""" - Class for asymptotic expressions. ... + Class for asymptotic expressions, i.e., the elements of an + :class:`AsymptoticRing`. INPUT: - ``parent`` -- the parent of the asymptotic expression. - ``poset`` -- a mutable poset representing the underlying - growth structure. + structure. - - ``simplify`` -- a boolean, controls automatic simplification - (absorption) of asymptotic expressions. Default: ``True``. + - ``simplify`` -- a boolean (default: ``True``). It controls + automatic simplification (absorption) of the asymptotic expression. EXAMPLES: - There are ways to create an asymptotic expression. First, - we construct the corresponding parents:: + There are several ways to create an asymptotic expression. First, + we construct the corresponding rings/parents:: sage: R_x. = AsymptoticRing('x^QQ', QQ) sage: import sage.groups.asymptotic_growth_group as agg @@ -183,16 +184,19 @@ def __init__(self, parent, poset, simplify=True): sage: ex1 * ex2 O(x^5) + 5*x^6 """ + super(AsymptoticExpression, self).__init__(parent=parent) + self._poset_ = poset if simplify: self._simplify_() - super(AsymptoticExpression, self).__init__(parent=parent) @property def poset(self): r""" - The poset of this asymptotic expression. + The underlying data structure (a + :class:`~sage.data_structures.mutable_poset.MutablePoset`) of + this asymptotic expression. EXAMPLES:: @@ -214,13 +218,18 @@ def _simplify_(self): OUTPUT: - An :class:`AsymptoticExpression`. + Nothing, but modifies this asymptotic expression. + + .. NOTE:: + + This method is usually called during initialization of + this asymptotic expression. .. NOTE:: This asymptotic expression is simplified by letting `O`-terms that are included in this expression absorb all - terms of lesser growth. + terms with smaller growth. TESTS:: @@ -272,12 +281,10 @@ def _repr_(self, reverse=False): '5*x^5 + 12*x^4 + O(x^3)' """ s = ' + '.join(repr(elem) for elem in - self.poset.elements_topological(include_special=False, - reverse=reverse)) - if s == '': + self.poset.elements_topological(reverse=reverse)) + if not s: return '0' - else: - return s + return s def _add_(self, other): @@ -290,9 +297,10 @@ def _add_(self, other): OUTPUT: - An :class:`AsymptoticExpression`. + The sum as an :class:`AsymptoticExpression`. EXAMPLES:: + sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1._add_(expr2) @@ -327,7 +335,7 @@ def _sub_(self, other): OUTPUT: - An :class:`AsymptoticExpression`. + The difference as an :class:`AsymptoticExpression`. .. NOTE:: @@ -340,21 +348,25 @@ def _sub_(self, other): sage: expr1 = x^123; expr2 = x^321 sage: expr1 - expr2 # indirect doctest x^123 + -x^321 + sage: O(x) - O(x) + O(x) """ return self + (-1) * other - def _mul_term_(self, other): + + def _mul_term_(self, term): r""" Helper method: multiply this asymptotic expression with the asymptotic term ``other``. INPUT: - - ``other`` -- an asymptotic term. + - ``term`` -- an asymptotic term (see + :mod:`~sage.monoids.asymptotic_term_monoid`). OUTPUT: - An :class:`AsymptoticExpression`. + The product as an :class:`AsymptoticExpression`. TESTS:: @@ -366,7 +378,7 @@ def _mul_term_(self, other): sage: expr._mul_term_(t) O(x^3) """ - return self.parent()([other * elem for elem in self.poset.elements()]) + return self.parent()([term * elem for elem in self.poset.elements()]) def _mul_(self, other): @@ -379,15 +391,7 @@ def _mul_(self, other): OUTPUT: - An :class:`AsymptoticExpression`. - - .. TODO:: - - The current implementation is the simple school book - multiplication. More efficient variants like Karatsuba - multiplication, or methods that exploit the structure - of the underlying poset shall be implemented at a later - point. + The product as an :class:`AsymptoticExpression`. EXAMPLES:: @@ -396,6 +400,14 @@ def _mul_(self, other): sage: ex2 = x^3 + O(x) sage: ex1 * ex2 # indirect doctest O(x^13) + 5*x^15 + + .. TODO:: + + The current implementation is the school book + multiplication. More efficient variants like Karatsuba + multiplication, or methods that exploit the structure + of the underlying poset shall be implemented at a later + point. """ return self.parent()(sum(self._mul_term_(term_other) for term_other in other.poset.elements())) @@ -403,7 +415,7 @@ def _mul_(self, other): def __pow__(self, power): r""" - Return this element to the power of ``power``. + Takes this element to the given ``power``. INPUT: From b0c7c520d3f864127d0fa54e385e57561c31b52c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 11:00:03 +0200 Subject: [PATCH 0345/1872] restructure code of __pow__ --- src/sage/rings/asymptotic_ring.py | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 2702cee019a..2d334f4dfb8 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -434,27 +434,29 @@ def __pow__(self, power): sage: y^(1/7) Traceback (most recent call last): ... - ValueError: Exponent 1/7 not in base of growth group Growth Group y^ZZ + ValueError: Growth Group y^ZZ disallows taking y to the power of 1/7. sage: (x^(1/2) + O(x^0))^15 O(x^7) + x^(15/2) """ + if len(self.poset._shells_) > 1: + return super(AsymptoticExpression, self).__pow__(power) + P = self.parent() - if len(self.poset._shells_) == 1: - expr = self.poset.elements().next() - if power in P.growth_group.base(): - from sage.monoids.asymptotic_term_monoid import TermWithCoefficient - if isinstance(expr, TermWithCoefficient): - new_growth = expr.growth ** power - new_coef = expr.coefficient ** power - return P(expr.parent()(new_growth, new_coef)) - else: - new_growth = expr.growth ** power - return P(expr.parent()(new_growth)) - else: - raise ValueError('Exponent %s not in base of growth group %s' % - (power, P.growth_group)) + if power not in P.growth_group.base(): + raise ValueError('%s disallows taking %s ' + 'to the power of %s.' % + (P.growth_group, self, power)) + + from sage.monoids.asymptotic_term_monoid import TermWithCoefficient + expr = self.poset.elements().next() + if isinstance(expr, TermWithCoefficient): + new_growth = expr.growth**power + new_coeff = expr.coefficient**power + return P(expr.parent()(new_growth, new_coeff)) + else: + new_growth = expr.growth**power + return P(expr.parent()(new_growth)) - return super(AsymptoticExpression, self).__pow__(power) def O(self): From 3c1329aab9d5b853c9debbe2722934c70e97ffed Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 11:10:21 +0200 Subject: [PATCH 0346/1872] update code to take care of changes of previous merge --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 2d334f4dfb8..7f7d0fbb8cd 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -830,7 +830,7 @@ def _repr_(self): 'Asymptotic Ring over Integer Ring' """ try: - G = '<' + self.growth_group._repr_(display_GrowthGroup=False) + '>' + G = self.growth_group._repr_(condense=True) except TypeError: G = repr(self.growth_group) return 'Asymptotic Ring %s over %s' % (G, self.coefficient_ring) From 9e7ccd44cc4a58c5e0fca2a1852d263c391990b3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 11:24:23 +0200 Subject: [PATCH 0347/1872] change ticket numberof experimental-warning to meta ticket --- src/sage/rings/asymptotic_ring.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 7f7d0fbb8cd..791398ea4c8 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -35,9 +35,6 @@ 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/17715 for details. sage: R. = AsymptoticRing('x^ZZ', ZZ) - 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/17716 for details. - """ # ***************************************************************************** @@ -614,7 +611,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, coefficient_ring, category) - @sage.misc.superseded.experimental(trac_number=17716) + @sage.misc.superseded.experimental(trac_number=17601) def __init__(self, growth_group=None, coefficient_ring=None, category=None): r""" See :class:`AsymptoticRing` for more information. From fa63a3dcc7ea55896b140df81e9e828038f6388c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 12:57:20 +0200 Subject: [PATCH 0348/1872] adapt code after merge --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 791398ea4c8..eda239f500a 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -827,7 +827,7 @@ def _repr_(self): 'Asymptotic Ring over Integer Ring' """ try: - G = self.growth_group._repr_(condense=True) + G = '<' + self.growth_group._repr_(condense=True) + '>' except TypeError: G = repr(self.growth_group) return 'Asymptotic Ring %s over %s' % (G, self.coefficient_ring) From 3babe99bce55bbc1293395d3dc921b0c6f2e8c24 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 16:01:23 +0200 Subject: [PATCH 0349/1872] smaller changes during review --- src/sage/rings/asymptotic_ring.py | 72 ++++++++++++++----------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index eda239f500a..3b2da09f5f0 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -496,7 +496,7 @@ class AsymptoticRing(sage.rings.ring.Ring, - ``growth_group`` -- a partially ordered group (e.g. an instance of :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`), - or a short representation string of a growth group. + or a string describing such a growth group. - ``coefficient_ring`` -- the ring which contains the coefficients of the expressions. @@ -506,15 +506,6 @@ class AsymptoticRing(sage.rings.ring.Ring, subcategory of ``Category of rings``. This is also the default category if ``None`` is specified. - OUTPUT: - - An asymptotic ring. - - .. NOTE:: - - See the following examples for more information on how to - create an asymptotic ring. - EXAMPLES: We begin with the explicit construction of an asymptotic ring, @@ -580,6 +571,7 @@ class AsymptoticRing(sage.rings.ring.Ring, # enable the category framework for elements Element = AsymptoticExpression + @staticmethod def __classcall__(cls, growth_group, coefficient_ring, names=None, category=None): @@ -591,7 +583,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, EXAMPLES: - __classcall__ unifies the input to the constructor of + ``__classcall__`` unifies the input to the constructor of :class:`AsymptoticRing` such that the instances generated are unique. Also, this enables the use of the generation framework:: @@ -608,11 +600,12 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, growth_group = GrowthGroup(growth_group) return super(AsymptoticRing, cls).__classcall__(cls, growth_group, - coefficient_ring, category) + coefficient_ring, + category) @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, growth_group=None, coefficient_ring=None, category=None): + def __init__(self, growth_group, coefficient_ring, category=None): r""" See :class:`AsymptoticRing` for more information. @@ -634,15 +627,15 @@ def __init__(self, growth_group=None, coefficient_ring=None, category=None): ... TypeError: __classcall__() takes at least 3 arguments (2 given) """ + from sage.categories.rings import Rings + if growth_group is None: raise ValueError('Growth group not specified. Cannot continue.') elif coefficient_ring is None: raise ValueError('Coefficient ring not specified. Cannot continue.') - elif not hasattr(coefficient_ring, 'is_ring') or\ - not coefficient_ring.is_ring(): - raise ValueError('%s has to be a ring.' % (coefficient_ring,)) + elif coefficient_ring not in Rings(): + raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) - from sage.categories.rings import Rings if category is None: category = Rings() else: @@ -657,6 +650,7 @@ def __init__(self, growth_group=None, coefficient_ring=None, category=None): super(AsymptoticRing, self).__init__(base=coefficient_ring, category=category) + @property def growth_group(self): r""" @@ -698,13 +692,16 @@ def _element_constructor_(self, data, poset=None, simplify=True): - ``data`` -- an object representing the element to be initialized. - - ``poset`` -- (default: None) if given, then this is + - ``poset`` -- (default: ``None``) if given, then this is directly passed to the element constructor (i.e., no conversion is performed). + - ``simplify`` -- (default: ``True``) if set, then the constructed + element is simplified (terms are absorbed) automatically. + OUTPUT: - An element of this growth group. + An element of this asymptotic ring. TESTS:: @@ -754,7 +751,7 @@ def _element_constructor_(self, data, poset=None, simplify=True): raise TypeError('Input is ambiguous: cannot convert ' '%s to an asymptotic expression' % (data,)) - return self.element_class(self, poset, simplify) + return self.element_class(self, poset, simplify=simplify) def _coerce_map_from_(self, R): @@ -771,12 +768,12 @@ def _coerce_map_from_(self, R): .. NOTE:: - There are two possible cases: either ``R`` is the - ``coefficient_ring`` of this asymptotic ring, or ``R`` - itself is an asymptotic ring (where both the - ``growth_group`` and the ``coefficient_ring`` coerce into - the ``growth_group`` and the ``coefficient_ring`` of this - asymptotic ring, respectively). + There are two possible cases: either ``R`` coerces in the + :meth:`coefficient_ring` of this asymptotic ring, or ``R`` + itself is an asymptotic ring, where both the + meth:`growth_group` and the :meth:`coefficient_ring` coerce into + the :meth:`growth_group` and the :meth:`coefficient_ring` of this + asymptotic ring, respectively. TESTS:: @@ -795,6 +792,8 @@ def _coerce_map_from_(self, R): sage: AR_QQ.has_coerce_map_from(QQ) True + sage: AR_QQ.has_coerce_map_from(ZZ) + True sage: 1/2 * x_QQ^2 + 7/8 * x_QQ^3 1/2*x^2 + 7/8*x^3 """ @@ -808,7 +807,7 @@ def _coerce_map_from_(self, R): def _repr_(self): r""" - A representation string for this asymptotic ring. + A representation string of this asymptotic ring. INPUT: @@ -843,7 +842,7 @@ def gens(self): OUTPUT: - A tuple. + A tuple of asymptotic expressions. .. NOTE:: @@ -869,19 +868,12 @@ def gen(self, n=0): INPUT: - - ``n`` -- a positive integer or `0`. Default: `0`. + - ``n`` -- (default: `0`) a non-negative integer. OUTPUT: An asymptotic expression. - .. NOTE:: - - Generators do not necessarily exist. This depends on the - underlying growth group. For example, monomial growth - groups have a generator, and exponential growth groups - don't. - EXAMPLES:: sage: R. = AsymptoticRing('x^ZZ', ZZ) @@ -890,6 +882,7 @@ def gen(self, n=0): """ return self.gens()[n] + def ngens(self): r""" Return the number of generators of this asymptotic ring. @@ -914,6 +907,7 @@ def ngens(self): else: return 0 + def create_term(self, type, growth=None, coefficient=None): r""" Create a simple asymptotic expression consisting of a single @@ -921,11 +915,11 @@ def create_term(self, type, growth=None, coefficient=None): INPUT: - - ``type`` -- 'O' or 'exact', + - ``type`` -- 'O' or 'exact'. - - ``growth`` -- a growth element, + - ``growth`` -- an element of the :meth:`growth_group`. - - ``coefficient`` -- a ring element. + - ``coefficient`` -- an element of the :meth:`coefficient_ring`. OUTPUT: From 1e93ee349633a62851bcedf5c5578f16169420b5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 16:54:48 +0200 Subject: [PATCH 0350/1872] rewrite/restructure element_constructor --- src/sage/rings/asymptotic_ring.py | 86 +++++++++++++++++-------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 3b2da09f5f0..f05bf6f5a59 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -715,43 +715,51 @@ def _element_constructor_(self, data, poset=None, simplify=True): sage: 3 * x^3 + O(x^5) O(x^5) """ - if poset is None: - if type(data) == self.element_class and data.parent() == self: - return data - elif isinstance(data, AsymptoticExpression): - return self.element_class(self, data.poset, simplify) - - if data in self.coefficient_ring: - if data != 0: - return self.create_term('exact', 1, data) - else: - from sage.data_structures.mutable_poset import MutablePoset - from sage.monoids.asymptotic_term_monoid import \ - can_absorb, absorption - poset = MutablePoset(key=lambda elem: elem.growth, - can_merge=can_absorb, - merge=absorption) - return self.element_class(self, poset, simplify) - - from sage.monoids.asymptotic_term_monoid import OTerm, ExactTerm - from sage.data_structures.mutable_poset import MutablePoset - from sage.monoids.asymptotic_term_monoid import can_absorb, \ - absorption - if isinstance(data, (OTerm, ExactTerm)): - data = (data,) - - try: - data_iter = iter(data) - if all(isinstance(elem, (OTerm, ExactTerm)) for elem in data_iter): - poset = MutablePoset(key=lambda elem: elem.growth, - can_merge=can_absorb, - merge=absorption) - poset = poset.union(data) - except: - raise TypeError('Input is ambiguous: cannot convert ' - '%s to an asymptotic expression' % (data,)) - - return self.element_class(self, poset, simplify=simplify) + if poset is not None: + if type(data) != int or data != 0: + raise ValueError('Input is ambigous: ' + '%s as well as poset=%s ' + 'are specified.' % (data, poset)) + return self.element_class(self, poset, simplify=simplify) + + if type(data) == self.element_class and data.parent() == self: + return data + + if isinstance(data, AsymptoticExpression): + return self.element_class(self, data.poset, simplify=simplify) + + from sage.monoids.asymptotic_term_monoid import GenericTerm + if isinstance(data, GenericTerm): + data = (data,) + + from sage.data_structures.mutable_poset import MutablePoset + from sage.monoids.asymptotic_term_monoid import \ + can_absorb, absorption + if isinstance(data, (list, tuple)): + if not all(isinstance(elem, GenericTerm) for elem in data): + raise TypeError('Not all list entries of %s ' + 'are asymptotic terms.' % (data,)) + poset = MutablePoset(key=lambda elem: elem.growth, + can_merge=can_absorb, + merge=absorption) + poset.union_update(data) + return self.element_class(self, poset, simplify=simplify) + + if data == 0: + poset = MutablePoset(key=lambda elem: elem.growth, + can_merge=can_absorb, + merge=absorption) + return self.element_class(self, poset, simplify=simplify) + + try: + coefficient = self.coefficient_ring(data) + except (TypeError, ValueError): + pass + else: + return self.create_term('exact', 1, coefficient) + + raise TypeError('Cannot convert %s to an asymptotic ' + 'expression.' % (data,)) def _coerce_map_from_(self, R): @@ -945,6 +953,8 @@ def create_term(self, type, growth=None, coefficient=None): if type == 'O': TM = TermMonoid(type, self.growth_group) return self(TM(growth)) - else: + elif type == 'exact': + if coefficient == 0: + return self(coefficient) TM = TermMonoid(type, self.growth_group, self.coefficient_ring) return self(TM(growth, coefficient)) From 8584f57429b7d3c85ce178eaefad79d787833c17 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 18:07:23 +0200 Subject: [PATCH 0351/1872] write __len__ --- src/sage/data_structures/mutable_poset.py | 29 +++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 19f26f1ec29..7f0a5868373 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1317,6 +1317,35 @@ def clear(self): self._shells_ = {} + def __len__(self): + r""" + Return the number of elements contained in this poset. + + INPUT: + + Nothing. + + OUTPUT: + + An integer. + + TESTS:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: P = MP() + sage: len(P) # indirect doctest + 0 + sage: bool(P) + False + sage: P.add(42) + sage: len(P) + 1 + sage: bool(P) + True + """ + return len(self._shells_) + + @property def null(self): r""" From a1678ed001fde620ab6b3cd63c4bda0113d791d9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 18:11:44 +0200 Subject: [PATCH 0352/1872] remove TODO-list of methods (list is now in separat branch) --- src/sage/data_structures/mutable_poset.py | 29 ----------------------- 1 file changed, 29 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 7f0a5868373..66a86bb5bb3 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1198,35 +1198,6 @@ class MutablePoset(sage.structure.sage_object.SageObject): sage: C = MP([5, 3, 11]); C poset(3, 5, 11) - - .. TODO:: - - Implement the following methods of - :class:`~sage.combinat.posets.posets.FinitePoset`: - - - :meth:`~sage.combinat.posets.posets.FinitePoset.bottom`: Returns the bottom element of the poset, if it exists. - - :meth:`~sage.combinat.posets.posets.FinitePoset.cardinality`: Returns the number of elements in the poset. - - :meth:`~sage.combinat.posets.posets.FinitePoset.compare_elements`: Compares x and y in the poset. - - :meth:`~sage.combinat.posets.posets.FinitePoset.covers`: Returns True if y covers x and False otherwise. - - :meth:`~sage.combinat.posets.posets.FinitePoset.has_bottom`: Returns True if the poset has a unique minimal element. - - :meth:`~sage.combinat.posets.posets.FinitePoset.has_top`: Returns True if the poset contains a unique maximal element, and False otherwise. - - :meth:`~sage.combinat.posets.posets.FinitePoset.is_bounded`: Returns True if the poset contains a unique maximal element and a unique minimal element, and False otherwise. - - :meth:`~sage.combinat.posets.posets.FinitePoset.is_chain`: Returns True if the poset is totally ordered, and False otherwise. - - :meth:`~sage.combinat.posets.posets.FinitePoset.is_gequal`: Returns True if x is greater than or equal to y in the poset, and False otherwise. - - :meth:`~sage.combinat.posets.posets.FinitePoset.is_greater_than`: Returns True if x is greater than but not equal to y in the poset, and False otherwise. - - :meth:`~sage.combinat.posets.posets.FinitePoset.is_lequal`: Returns True if x is less than or equal to y in the poset, and False otherwise. - - :meth:`~sage.combinat.posets.posets.FinitePoset.is_less_than`: Returns True if x is less than but not equal to y in the poset, and False otherwise. - - :meth:`~sage.combinat.posets.posets.FinitePoset.linear_extension`: Returns a linear extension of this poset. - - :meth:`~sage.combinat.posets.posets.FinitePoset.list`: List the elements of the poset. This just returns the result of linear_extension(). - - :meth:`~sage.combinat.posets.posets.FinitePoset.lower_covers_iterator`: Returns an iterator for the lower covers of the element y. An lower cover of y is an element x such that y x is a cover relation. - - :meth:`~sage.combinat.posets.posets.FinitePoset.lower_covers`: Returns a list of lower covers of the element y. An lower cover of y is an element x such that y x is a cover relation. - - :meth:`~sage.combinat.posets.posets.FinitePoset.maximal_elements`: Returns a list of the maximal elements of the poset. - - :meth:`~sage.combinat.posets.posets.FinitePoset.minimal_elements`: Returns a list of the minimal elements of the poset. - - :meth:`~sage.combinat.posets.posets.FinitePoset.relations_iterator`: Returns an iterator for all the relations of the poset. - - :meth:`~sage.combinat.posets.posets.FinitePoset.relations`: Returns a list of all relations of the poset. - - :meth:`~sage.combinat.posets.posets.FinitePoset.top`: Returns the top element of the poset, if it exists. - - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers_iterator`: Returns an iterator for the upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. - - :meth:`~sage.combinat.posets.posets.FinitePoset.upper_covers`: Returns a list of upper covers of the element y. An upper cover of y is an element x such that y x is a cover relation. """ def __init__(self, data=None, key=None, merge=None, can_merge=None): r""" From db4adec8f0598c38c00469d47a021884bf64c771 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 18:33:14 +0200 Subject: [PATCH 0353/1872] rename poset to summands --- src/sage/rings/asymptotic_ring.py | 85 ++++++++++++++++--------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index f05bf6f5a59..46be6680dd4 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -58,8 +58,9 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): - ``parent`` -- the parent of the asymptotic expression. - - ``poset`` -- a mutable poset representing the underlying - structure. + - ``summands`` -- the summands as a + :class:`~sage.data_structures.mutable_poset.MutablePoset`, which + represents the underlying structure. - ``simplify`` -- a boolean (default: ``True``). It controls automatic simplification (absorption) of the asymptotic expression. @@ -105,11 +106,11 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): In particular, :meth:`~sage.rings.big_oh.O` can be used to construct the asymptotic expressions. With the help of the - ``poset``, we can also have a look at the inner structure + :meth:`summands`, we can also have a look at the inner structure of an asymptotic expression:: sage: expr1 = x + 2*x^2 + 3*x^3 + 4*x^4; expr2 = O(x) + x^2 - sage: print(expr1.poset.repr_full()) + sage: print(expr1.summands.repr_full()) poset(x, 2*x^2, 3*x^3, 4*x^4) +-- null | +-- no predecessors @@ -129,7 +130,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): +-- oo | +-- predecessors: 4*x^4 | +-- no successors - sage: print(expr2.poset.repr_full()) + sage: print(expr2.summands.repr_full()) poset(O(x), x^2) +-- null | +-- no predecessors @@ -143,7 +144,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): +-- oo | +-- predecessors: x^2 | +-- no successors - sage: print((expr1 * expr2).poset.repr_full()) + sage: print((expr1 * expr2).summands.repr_full()) poset(O(x^5), 4*x^6) +-- null | +-- no predecessors @@ -166,7 +167,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): sage: (O(xl) + xl^3)^4 O(log(x)^10) + log(x)^12 """ - def __init__(self, parent, poset, simplify=True): + def __init__(self, parent, summands, simplify=True): r""" See :class:`AsymptoticExpression` for more information. @@ -183,26 +184,26 @@ def __init__(self, parent, poset, simplify=True): """ super(AsymptoticExpression, self).__init__(parent=parent) - self._poset_ = poset + self._summands_ = summands if simplify: self._simplify_() @property - def poset(self): + def summands(self): r""" - The underlying data structure (a - :class:`~sage.data_structures.mutable_poset.MutablePoset`) of - this asymptotic expression. + The summands of this asymptotic expression stored in the + underlying data structure (a + :class:`~sage.data_structures.mutable_poset.MutablePoset`). EXAMPLES:: sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr = 7 * x^12 + x^5 + O(x^3) - sage: expr.poset + sage: expr.summands poset(O(x^3), x^5, 7*x^12) """ - return self._poset_ + return self._summands_ def _simplify_(self): @@ -244,10 +245,10 @@ def _simplify_(self): O(x^3) + 4*x^4 """ from sage.monoids.asymptotic_term_monoid import OTerm - for shell in self.poset.shells_topological(reverse=True): - if shell.element.growth in self.poset and isinstance(shell.element, + for shell in self.summands.shells_topological(reverse=True): + if shell.element.growth in self.summands and isinstance(shell.element, OTerm): - self.poset.merge(shell.key) + self.summands.merge(shell.key) def _repr_(self, reverse=False): @@ -278,7 +279,7 @@ def _repr_(self, reverse=False): '5*x^5 + 12*x^4 + O(x^3)' """ s = ' + '.join(repr(elem) for elem in - self.poset.elements_topological(reverse=reverse)) + self.summands.elements_topological(reverse=reverse)) if not s: return '0' return s @@ -318,8 +319,8 @@ def _add_(self, other): sage: O(x) + x O(x) """ - pst = self.poset.copy().union(other.poset) - return self.parent()(poset=pst) + smds = self.summands.copy().union(other.summands) + return self.parent()(summands=smds) def _sub_(self, other): @@ -375,7 +376,7 @@ def _mul_term_(self, term): sage: expr._mul_term_(t) O(x^3) """ - return self.parent()([term * elem for elem in self.poset.elements()]) + return self.parent()([term * elem for elem in self.summands.elements()]) def _mul_(self, other): @@ -407,7 +408,7 @@ def _mul_(self, other): point. """ return self.parent()(sum(self._mul_term_(term_other) for - term_other in other.poset.elements())) + term_other in other.summands.elements())) def __pow__(self, power): @@ -435,7 +436,7 @@ def __pow__(self, power): sage: (x^(1/2) + O(x^0))^15 O(x^7) + x^(15/2) """ - if len(self.poset._shells_) > 1: + if len(self.summands._shells_) > 1: return super(AsymptoticExpression, self).__pow__(power) P = self.parent() @@ -445,7 +446,7 @@ def __pow__(self, power): (P.growth_group, self, power)) from sage.monoids.asymptotic_term_monoid import TermWithCoefficient - expr = self.poset.elements().next() + expr = self.summands.elements().next() if isinstance(expr, TermWithCoefficient): new_growth = expr.growth**power new_coeff = expr.coefficient**power @@ -479,11 +480,11 @@ def O(self): sage: expr.O() O(x^42) """ - if self.poset.null in self.poset.oo.predecessors(): + if self.summands.null in self.summands.oo.predecessors(): raise ValueError('O(%s) not defined' % self) else: return sum(self.parent().create_term('O', shell.element) for shell - in self.poset.oo.predecessors()) + in self.summands.oo.predecessors()) @@ -683,7 +684,7 @@ def coefficient_ring(self): return self._coefficient_ring_ - def _element_constructor_(self, data, poset=None, simplify=True): + def _element_constructor_(self, data, summands=None, simplify=True): r""" Convert a given object to this asymptotic ring. @@ -692,7 +693,7 @@ def _element_constructor_(self, data, poset=None, simplify=True): - ``data`` -- an object representing the element to be initialized. - - ``poset`` -- (default: ``None``) if given, then this is + - ``summands`` -- (default: ``None``) if given, then this is directly passed to the element constructor (i.e., no conversion is performed). @@ -715,18 +716,18 @@ def _element_constructor_(self, data, poset=None, simplify=True): sage: 3 * x^3 + O(x^5) O(x^5) """ - if poset is not None: + if summands is not None: if type(data) != int or data != 0: raise ValueError('Input is ambigous: ' - '%s as well as poset=%s ' - 'are specified.' % (data, poset)) - return self.element_class(self, poset, simplify=simplify) + '%s as well as summands=%s ' + 'are specified.' % (data, summands)) + return self.element_class(self, summands, simplify=simplify) if type(data) == self.element_class and data.parent() == self: return data if isinstance(data, AsymptoticExpression): - return self.element_class(self, data.poset, simplify=simplify) + return self.element_class(self, data.summands, simplify=simplify) from sage.monoids.asymptotic_term_monoid import GenericTerm if isinstance(data, GenericTerm): @@ -739,17 +740,17 @@ def _element_constructor_(self, data, poset=None, simplify=True): if not all(isinstance(elem, GenericTerm) for elem in data): raise TypeError('Not all list entries of %s ' 'are asymptotic terms.' % (data,)) - poset = MutablePoset(key=lambda elem: elem.growth, - can_merge=can_absorb, - merge=absorption) - poset.union_update(data) - return self.element_class(self, poset, simplify=simplify) + summands = MutablePoset(key=lambda elem: elem.growth, + can_merge=can_absorb, + merge=absorption) + summands.union_update(data) + return self.element_class(self, summands, simplify=simplify) if data == 0: - poset = MutablePoset(key=lambda elem: elem.growth, - can_merge=can_absorb, - merge=absorption) - return self.element_class(self, poset, simplify=simplify) + summands = MutablePoset(key=lambda elem: elem.growth, + can_merge=can_absorb, + merge=absorption) + return self.element_class(self, summands, simplify=simplify) try: coefficient = self.coefficient_ring(data) From f8564157158c5b1dbe5b0683af67c35e8d1e17d5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 18:35:22 +0200 Subject: [PATCH 0354/1872] rename create_term to create_summand --- src/sage/rings/asymptotic_ring.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 46be6680dd4..a4bbfe243e4 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -474,7 +474,7 @@ def O(self): sage: import sage.groups.asymptotic_growth_group as agg sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(MG, ZZ) - sage: x = AR.create_term('exact', x) + sage: x = AR.create_summand('exact', x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr O(x^2) + x^10 + 42*x^42 sage: expr.O() @@ -483,7 +483,7 @@ def O(self): if self.summands.null in self.summands.oo.predecessors(): raise ValueError('O(%s) not defined' % self) else: - return sum(self.parent().create_term('O', shell.element) for shell + return sum(self.parent().create_summand('O', shell.element) for shell in self.summands.oo.predecessors()) @@ -757,7 +757,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): except (TypeError, ValueError): pass else: - return self.create_term('exact', 1, coefficient) + return self.create_summand('exact', 1, coefficient) raise TypeError('Cannot convert %s to an asymptotic ' 'expression.' % (data,)) @@ -868,7 +868,7 @@ def gens(self): """ from sage.groups.asymptotic_growth_group import MonomialGrowthGroup if isinstance(self.growth_group, MonomialGrowthGroup): - return self.create_term('exact', self.growth_group.gen(), 1), + return self.create_summand('exact', self.growth_group.gen(), 1), def gen(self, n=0): @@ -917,10 +917,10 @@ def ngens(self): return 0 - def create_term(self, type, growth=None, coefficient=None): + def create_summand(self, type, growth=None, coefficient=None): r""" Create a simple asymptotic expression consisting of a single - term. + summand. INPUT: @@ -945,9 +945,9 @@ def create_term(self, type, growth=None, coefficient=None): sage: import sage.groups.asymptotic_growth_group as agg sage: G = agg.GrowthGroup('x^ZZ') sage: R = AsymptoticRing(G, ZZ) - sage: R.create_term('O', x^2) + sage: R.create_summand('O', x^2) O(x^2) - sage: R.create_term('exact', x^456, 123) + sage: R.create_summand('exact', x^456, 123) 123*x^456 """ from sage.monoids.asymptotic_term_monoid import TermMonoid From 1c6b196bac8386f97bb6234a8442040dd52e8b2d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 18:25:30 +0200 Subject: [PATCH 0355/1872] write methods for maximal/minimal elements --- src/sage/data_structures/mutable_poset.py | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 66a86bb5bb3..545ddf36400 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2792,6 +2792,70 @@ def can_merge(other): shell.merge(m.element, delete=True) + def maximal_elements(self): + r""" + Return an iterator over the maximal elements of this poset. + + INPUT: + + Nothing. + + OUTPUT: + + An iterator. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 1))) + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: list(P.maximal_elements()) + [(1, 3), (2, 2)] + """ + return iter(shell.element + for shell in self.oo.predecessors() + if not shell.is_special()) + + + def minimal_elements(self): + r""" + Return an iterator over the minimal elements of this poset. + + INPUT: + + Nothing. + + OUTPUT: + + An iterator. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: list(P.minimal_elements()) + [(1, 2), (2, 1)] + """ + return iter(shell.element + for shell in self.null.successors() + if not shell.is_special()) + + # ***************************************************************************** From 74e14f9a0ceb29e8f6729056cd1e3e388ea9aa20 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 18:41:38 +0200 Subject: [PATCH 0356/1872] raise exception when __pow__ not possible --- src/sage/rings/asymptotic_ring.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index a4bbfe243e4..44ba2e6efce 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -437,6 +437,11 @@ def __pow__(self, power): O(x^7) + x^(15/2) """ if len(self.summands._shells_) > 1: + from sage.rings.integer_ring import ZZ + if power not in ZZ: + raise NotImplementedError('Taking the sum %s to the ' + 'non-integer power %s not ' + 'implemented.' % (self, power)) return super(AsymptoticExpression, self).__pow__(power) P = self.parent() From f6bc337ac7f8e35a8076187dd77f012c4233eb22 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 19:24:30 +0200 Subject: [PATCH 0357/1872] implement __nonzero__ --- src/sage/rings/asymptotic_ring.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 44ba2e6efce..b27e18f4c7d 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -206,6 +206,31 @@ def summands(self): return self._summands_ + def __nonzero__(self): + r""" + Return if this asymptotic expression is not identially zero. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + TESTS:: + + sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: bool(R(0)) # indirect doctest + False + sage: bool(x) # indirect doctest + True + sage: bool(7 * x^12 + x^5 + O(x^3)) # indirect doctest + True + """ + return bool(self._summands_) + + def _simplify_(self): r""" Simplify this asymptotic expression. From 001d921f48f12189b061e6577dcccc3fe951d50b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 19:24:57 +0200 Subject: [PATCH 0358/1872] adapt O (previous merge and __nonzero__) --- src/sage/rings/asymptotic_ring.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index b27e18f4c7d..29ef4484293 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -505,16 +505,24 @@ def O(self): sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(MG, ZZ) sage: x = AR.create_summand('exact', x) + sage: O(x) + O(x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr O(x^2) + x^10 + 42*x^42 sage: expr.O() O(x^42) + + TESTS:: + + sage: O(AR(0)) + Traceback (most recent call last): + ... + ValueError: Cannot build O(0). """ - if self.summands.null in self.summands.oo.predecessors(): - raise ValueError('O(%s) not defined' % self) - else: - return sum(self.parent().create_summand('O', shell.element) for shell - in self.summands.oo.predecessors()) + if not self: + raise ValueError('Cannot build O(%s).' % (self,)) + return sum(self.parent().create_summand('O', element) + for element in self.summands.maximal_elements()) From 825bcbc1e003f35722243e335b80a0a7c00ce3a8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 19:29:05 +0200 Subject: [PATCH 0359/1872] remove reverse from _repr_ and reverse by default --- src/sage/rings/asymptotic_ring.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 29ef4484293..6d905a02560 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -276,13 +276,13 @@ def _simplify_(self): self.summands.merge(shell.key) - def _repr_(self, reverse=False): + def _repr_(self): r""" A representation string for this asymptotic expression. INPUT: - - ``reverse`` -- a boolean (default: ``False``). + Nothing. OUTPUT: @@ -300,11 +300,9 @@ def _repr_(self, reverse=False): sage: expr = (5*x^2 + 12*x) * (x^3 + O(x)) sage: repr(expr) # indirect doctest 'O(x^3) + 12*x^4 + 5*x^5' - sage: expr._repr_(reverse=True) - '5*x^5 + 12*x^4 + O(x^3)' """ s = ' + '.join(repr(elem) for elem in - self.summands.elements_topological(reverse=reverse)) + self.summands.elements_topological(reverse=True)) if not s: return '0' return s From 0cfa7514d4d027c8b85790939bce7e9cea63c082 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 19:32:00 +0200 Subject: [PATCH 0360/1872] fix doctests (_repr_ reverse) --- src/sage/rings/asymptotic_ring.py | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 6d905a02560..91cfea1309e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -87,22 +87,22 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): The usual ring operations can be performed:: sage: x^2 + 3*(x - x^2) - 3*x + -2*x^2 + -2*x^2 + 3*x sage: (3*x + 2)^3 - 8 + 36*x + 54*x^2 + 27*x^3 + 27*x^3 + 54*x^2 + 36*x + 8 In addition to that, special powers (determined by the base ring of the growth group) can also be computed:: sage: (x^(5/2) + x^(1/7)) * x^(-1/5) - x^(-2/35) + x^(23/10) + x^(23/10) + x^(-2/35) One of the central ideas behind computing with asymptotic expressions is that the `O`-notation (see :wikipedia:`Big_O_notation`) can be used. For example, we have:: sage: (x + 2*x^2 + 3*x^3 + 4*x^4) * (O(x) + x^2) - O(x^5) + 4*x^6 + 4*x^6 + O(x^5) In particular, :meth:`~sage.rings.big_oh.O` can be used to construct the asymptotic expressions. With the help of the @@ -165,7 +165,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): sage: R_log. = AsymptoticRing('log(x)^QQ', QQ) sage: (O(xl) + xl^3)^4 - O(log(x)^10) + log(x)^12 + log(x)^12 + O(log(x)^10) """ def __init__(self, parent, summands, simplify=True): r""" @@ -180,7 +180,7 @@ def __init__(self, parent, summands, simplify=True): sage: ex1 = x + 2*x^2 + 3*x^3 + 4*x^4 + 5*x^5 sage: ex2 = x + O(R_x(1)) sage: ex1 * ex2 - O(x^5) + 5*x^6 + 5*x^6 + O(x^5) """ super(AsymptoticExpression, self).__init__(parent=parent) @@ -263,11 +263,11 @@ def _simplify_(self): sage: R = AsymptoticRing(G, ZZ) sage: lst = [ET(x,1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] sage: expr = R(lst, simplify=False); expr # indirect doctest - x + 2*x^2 + O(x^3) + 4*x^4 + 4*x^4 + O(x^3) + 2*x^2 + x sage: expr._simplify_(); expr - O(x^3) + 4*x^4 + 4*x^4 + O(x^3) sage: R(lst) # indirect doctest - O(x^3) + 4*x^4 + 4*x^4 + O(x^3) """ from sage.monoids.asymptotic_term_monoid import OTerm for shell in self.summands.shells_topological(reverse=True): @@ -299,7 +299,7 @@ def _repr_(self): sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr = (5*x^2 + 12*x) * (x^3 + O(x)) sage: repr(expr) # indirect doctest - 'O(x^3) + 12*x^4 + 5*x^5' + '5*x^5 + 12*x^4 + O(x^3)' """ s = ' + '.join(repr(elem) for elem in self.summands.elements_topological(reverse=True)) @@ -325,9 +325,9 @@ def _add_(self, other): sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1._add_(expr2) - x^123 + x^321 + x^321 + x^123 sage: expr1 + expr2 # indirect doctest - x^123 + x^321 + x^321 + x^123 If an `O`-term is added to an asymptotic expression, then the `O`-term absorbs everything it can:: @@ -368,7 +368,7 @@ def _sub_(self, other): sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1 - expr2 # indirect doctest - x^123 + -x^321 + -x^321 + x^123 sage: O(x) - O(x) O(x) """ @@ -420,7 +420,7 @@ def _mul_(self, other): sage: ex1 = 5*x^12 sage: ex2 = x^3 + O(x) sage: ex1 * ex2 # indirect doctest - O(x^13) + 5*x^15 + 5*x^15 + O(x^13) .. TODO:: @@ -457,7 +457,7 @@ def __pow__(self, power): ... ValueError: Growth Group y^ZZ disallows taking y to the power of 1/7. sage: (x^(1/2) + O(x^0))^15 - O(x^7) + x^(15/2) + x^(15/2) + O(x^7) """ if len(self.summands._shells_) > 1: from sage.rings.integer_ring import ZZ @@ -506,7 +506,7 @@ def O(self): sage: O(x) O(x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr - O(x^2) + x^10 + 42*x^42 + 42*x^42 + x^10 + O(x^2) sage: expr.O() O(x^42) @@ -746,7 +746,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): sage: 3 * x^3 3*x^3 sage: 3 * x^3 + x - x + 3*x^3 + 3*x^3 + x sage: (3 * x^3) * (5 * x) 15*x^4 sage: 3 * x^3 + O(x^5) @@ -840,7 +840,7 @@ def _coerce_map_from_(self, R): sage: AR_QQ.has_coerce_map_from(ZZ) True sage: 1/2 * x_QQ^2 + 7/8 * x_QQ^3 - 1/2*x^2 + 7/8*x^3 + 7/8*x^3 + 1/2*x^2 """ if self.coefficient_ring.has_coerce_map_from(R): return True From 4a2f31a383053ef5834d7b66009aa7a84e31b881 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 19:33:06 +0200 Subject: [PATCH 0361/1872] minor rewrite of docstring --- src/sage/rings/asymptotic_ring.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 91cfea1309e..e3107a0c4e6 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -288,18 +288,11 @@ def _repr_(self): A string. - .. NOTE:: - - By default, the elements with the weakest growth are - printed first. If ``reverse`` is ``True``, then the - printing order is reversed. - EXAMPLES:: sage: R. = AsymptoticRing('x^ZZ', ZZ) - sage: expr = (5*x^2 + 12*x) * (x^3 + O(x)) - sage: repr(expr) # indirect doctest - '5*x^5 + 12*x^4 + O(x^3)' + sage: (5*x^2 + 12*x) * (x^3 + O(x)) # indirect doctest + 5*x^5 + 12*x^4 + O(x^3) """ s = ' + '.join(repr(elem) for elem in self.summands.elements_topological(reverse=True)) From bb75902c876d7c8a0a834995044aa44e5a4634bb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 28 Jul 2015 19:36:25 +0200 Subject: [PATCH 0362/1872] _repr_: handle a minus correct --- src/sage/rings/asymptotic_ring.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index e3107a0c4e6..b1e82096429 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -293,9 +293,12 @@ def _repr_(self): sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: (5*x^2 + 12*x) * (x^3 + O(x)) # indirect doctest 5*x^5 + 12*x^4 + O(x^3) + sage: (5*x^2 - 12*x) * (x^3 + O(x)) # indirect doctest + 5*x^5 - 12*x^4 + O(x^3) """ s = ' + '.join(repr(elem) for elem in self.summands.elements_topological(reverse=True)) + s = s.replace('+ -', '- ') if not s: return '0' return s From 19fd1556a56a6d250ca464c385e7960ac715b2ae Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 29 Jul 2015 10:36:50 +0200 Subject: [PATCH 0363/1872] allow merge to go over all elements --- src/sage/data_structures/mutable_poset.py | 28 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 545ddf36400..52d886757e7 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2703,13 +2703,19 @@ def is_superset(self, other): """ - def merge(self, key): + def merge(self, key=None, reverse=False): r""" Merge the given element with its successors/predecessors. INPUT: - ``key`` -- the key specifying an element. + - ``key`` -- the key specifying an element or ``None`` + (default), in which case this method is called on each + element in this poset. + + - ``reverse`` -- (default: ``False``) specifies which + direction to go first. When ``key=None``, then this also + specifies which elements are merged first. OUTPUT: @@ -2778,13 +2784,27 @@ def merge(self, key): merging (2, 2): poset((1, 3, 'b'), (2, 2, 'acef'), (4, 4, 'd')) merging (1, 1): poset((1, 1, 'a'), (1, 2, 'e'), (1, 3, 'b'), (2, 1, 'c'), (2, 2, 'f'), (4, 4, 'd')) + sage: Q = copy(P) + sage: Q.merge(); Q + poset((4, 4, 'abcdef')) + + TESTS:: + + sage: copy(P).merge(reverse=False) == copy(P).merge(reverse=True) + True """ + if key is None: + for shell in tuple(self.shells_topological(reverse=reverse)): + if shell.key in self._shells_: + self.merge(key=shell.key) + return + shell = self.shell(key) def can_merge(other): return self._can_merge_(shell.element, other.element) - for reverse in (False, True): + for rev in (reverse, not reverse): to_merge = shell.iter_depth_first( - reverse=reverse, condition=can_merge) + reverse=rev, condition=can_merge) next(to_merge) for m in tuple(to_merge): if m.is_special(): From 28633219f5d6a868e2d2522d573683af7fa19321 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 29 Jul 2015 10:36:50 +0200 Subject: [PATCH 0364/1872] allow merge to go over all elements --- src/sage/data_structures/mutable_poset.py | 28 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 545ddf36400..52d886757e7 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2703,13 +2703,19 @@ def is_superset(self, other): """ - def merge(self, key): + def merge(self, key=None, reverse=False): r""" Merge the given element with its successors/predecessors. INPUT: - ``key`` -- the key specifying an element. + - ``key`` -- the key specifying an element or ``None`` + (default), in which case this method is called on each + element in this poset. + + - ``reverse`` -- (default: ``False``) specifies which + direction to go first. When ``key=None``, then this also + specifies which elements are merged first. OUTPUT: @@ -2778,13 +2784,27 @@ def merge(self, key): merging (2, 2): poset((1, 3, 'b'), (2, 2, 'acef'), (4, 4, 'd')) merging (1, 1): poset((1, 1, 'a'), (1, 2, 'e'), (1, 3, 'b'), (2, 1, 'c'), (2, 2, 'f'), (4, 4, 'd')) + sage: Q = copy(P) + sage: Q.merge(); Q + poset((4, 4, 'abcdef')) + + TESTS:: + + sage: copy(P).merge(reverse=False) == copy(P).merge(reverse=True) + True """ + if key is None: + for shell in tuple(self.shells_topological(reverse=reverse)): + if shell.key in self._shells_: + self.merge(key=shell.key) + return + shell = self.shell(key) def can_merge(other): return self._can_merge_(shell.element, other.element) - for reverse in (False, True): + for rev in (reverse, not reverse): to_merge = shell.iter_depth_first( - reverse=reverse, condition=can_merge) + reverse=rev, condition=can_merge) next(to_merge) for m in tuple(to_merge): if m.is_special(): From 748444a8c0de1fc3dd999d71a6e0be2ac9305044 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 29 Jul 2015 10:39:55 +0200 Subject: [PATCH 0365/1872] rewrite simplify to use poset's merge method --- src/sage/rings/asymptotic_ring.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index b1e82096429..e582fdd56a5 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -269,11 +269,7 @@ def _simplify_(self): sage: R(lst) # indirect doctest 4*x^4 + O(x^3) """ - from sage.monoids.asymptotic_term_monoid import OTerm - for shell in self.summands.shells_topological(reverse=True): - if shell.element.growth in self.summands and isinstance(shell.element, - OTerm): - self.summands.merge(shell.key) + self.summands.merge(reverse=True) def _repr_(self): From 12d88c95c4f0718ac59a0cf75171356d46eb8392 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 29 Jul 2015 10:48:57 +0200 Subject: [PATCH 0366/1872] restructure creation of empty data structures (give them their own method) --- src/sage/rings/asymptotic_ring.py | 38 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index e582fdd56a5..8af6ee9ee1c 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -712,6 +712,33 @@ def coefficient_ring(self): return self._coefficient_ring_ + @staticmethod + def _create_empty_summands_(): + r""" + Create an empty data structure suitable for storing and working + with summands. + + INPUT: + + Nothing. + + OUTPUT: + + A :class:`~sage.data_structures.mutable_poset.MutablePoset`. + + TESTS:: + + sage: AsymptoticRing._create_empty_summands_() + poset() + """ + from sage.data_structures.mutable_poset import MutablePoset + from sage.monoids.asymptotic_term_monoid import \ + can_absorb, absorption + return MutablePoset(key=lambda element: element.growth, + can_merge=can_absorb, + merge=absorption) + + def _element_constructor_(self, data, summands=None, simplify=True): r""" Convert a given object to this asymptotic ring. @@ -761,23 +788,16 @@ def _element_constructor_(self, data, summands=None, simplify=True): if isinstance(data, GenericTerm): data = (data,) - from sage.data_structures.mutable_poset import MutablePoset - from sage.monoids.asymptotic_term_monoid import \ - can_absorb, absorption if isinstance(data, (list, tuple)): if not all(isinstance(elem, GenericTerm) for elem in data): raise TypeError('Not all list entries of %s ' 'are asymptotic terms.' % (data,)) - summands = MutablePoset(key=lambda elem: elem.growth, - can_merge=can_absorb, - merge=absorption) + summands = AsymptoticRing._create_empty_summands_() summands.union_update(data) return self.element_class(self, summands, simplify=simplify) if data == 0: - summands = MutablePoset(key=lambda elem: elem.growth, - can_merge=can_absorb, - merge=absorption) + summands = AsymptoticRing._create_empty_summands_() return self.element_class(self, summands, simplify=simplify) try: From aa42238c6754cff63c5cc42e8d77e78b36074fbc Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 29 Jul 2015 16:34:40 +0200 Subject: [PATCH 0367/1872] Integrated reviewer's comments --- src/sage/coding/all.py | 2 -- src/sage/coding/encoder.py | 57 ++++++++++++------------------- src/sage/coding/linear_code.py | 62 +++++++++++++++++----------------- 3 files changed, 53 insertions(+), 68 deletions(-) diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index cada61837a0..84e1b6e81f5 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -68,8 +68,6 @@ bounds_minimum_distance, self_orthogonal_binary_codes) -from linear_code import LinearCodeGeneratorMatrixEncoder - from sd_codes import self_dual_codes_binary lazy_import("sage.coding.delsarte_bounds", diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 6c8cb90305e..fd840ea3534 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -25,23 +25,17 @@ class Encoder(SageObject): Every encoder class should inherit from this abstract class. - This class provides: - - - ``code``, the associated code of the encoder - - - some methods for encoder objects - To implement an encoder, you need to: - inherit from :class:`Encoder` - - call :class:`Encoder`'s :meth:`__init__` in the subclass constructor. + - call ``Encoder.__init__`` in the subclass constructor. Example: ``super(SubclassName, self).__init__(code)``. By doing that, your subclass will have its ``code`` parameter initialized. You need of course to complete the constructor by adding any additional parameter needed to describe properly the code defined in the subclass. - Then, if the message space is a vectorial space, default implementation of :meth:`encode` and + Then, if the message space is a vector space, default implementations of :meth:`encode` and :meth:`unencode_nocheck` methods are provided. These implementations rely on :meth:`generator_matrix` which you need to override to use the default implementations. @@ -54,14 +48,12 @@ class Encoder(SageObject): these methods is not enough for your subclass, you are strongly encouraged to override them. - .. NOTE:: + As :class:`Encoder` is not designed to be instanciated, it does not have any representation + methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. - For consistency on encoders, please follow this convention on names for subclasses: - for a new encoder named ``EncName``, for code family ``CodeFam``, call it - ``CodeFamEncNameEncoder``. + REFERENCES: - As :class:`Encoder` is not designed to be implemented, it does not have any representation - methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. + .. [Nielsen] Johan S. R. Nielsen, (https://bitbucket.org/jsrn/codinglib/) """ def __init__(self, code): @@ -99,12 +91,13 @@ def __init__(self, code): def encode(self, word): r""" - Transforms an element of the message space into an element of the code. + Transforms an element of the message space into a codeword. This is a default implementation which assumes that the message - space of the encoder is `F^k`, where `F` is ``self.code().base_field()`` - and ``k`` is ``self.code().dimension()``. If this is not the case, - this method should be overwritten by the subclass. + space of the encoder is `F^k`, where `F` is + :meth:`sage.coding.linear_code.AbstractLinearCode.base_field` + and ``k`` is :meth:`sage.coding.linear_code.AbstractLinearCode.dimension`. + If this is not the case, this method should be overwritten by the subclass. INPUT: @@ -163,33 +156,28 @@ def unencode(self, c, nocheck=False): """ if nocheck == False: if c not in self.code(): - raise EncodingFailure("Given word is not in the code") + raise EncodingError("Given word is not in the code") else: return self.unencode_nocheck(c) else: return self.unencode_nocheck(c) @cached_method - def unencoder_matrix(self): + def _unencoder_matrix(self): r""" Finds an information set for the matrix ``G`` returned by :meth:`generator_matrix`, and returns the inverse of that submatrix of ``G``. - .. NOTE:: - - This is a helper function, for internal use only. - AUTHORS: - This function is taken from codinglib (https://bitbucket.org/jsrn/codinglib/) - and was written by Johan Nielsen. + This function is taken from codinglib [Nielsen]_ 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: E = C.encoder() - sage: E.unencoder_matrix() + sage: E._unencoder_matrix() [0 0 1 1] [0 1 0 1] [1 1 1 0] @@ -206,8 +194,7 @@ def unencode_nocheck(self, c): AUTHORS: - This function is taken from codinglib (https://bitbucket.org/jsrn/codinglib/) - and was written by Johan Nielsen. + This function is taken from codinglib [Nielsen]_ INPUT: @@ -242,14 +229,14 @@ def unencode_nocheck(self, c): sage: c == c1 False """ - U = self.unencoder_matrix() + U = self._unencoder_matrix() info_set = self.code().information_set() cc = vector( c[i] for i in info_set ) return cc * U def code(self): r""" - Returns the code in which ``self.encode()`` has its output. + Returns the code in which :meth:`encode` has its output. EXAMPLES:: @@ -263,8 +250,8 @@ def code(self): def message_space(self): r""" - Returns the ambient space of allowed input to ``self.encode()``. - Note that `self.encode()` is possibly a partial function over + Returns the ambient space of allowed input to :meth:`encode`. + Note that :meth:`encode` is possibly a partial function over the ambient space. EXAMPLES:: @@ -288,8 +275,8 @@ def generator_matrix(self): where `F` is the base field of :meth:`code`.) """ -class EncodingFailure(Exception): +class EncodingError(Exception): r""" - Special exception class to indicate a failure during encoding or unencoding. + Special exception class to indicate an error during encoding or unencoding. """ pass diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index dab90a9dd8e..4f608cefa4c 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -933,7 +933,7 @@ def add_encoder(self, name, encoder): ValueError: There is already a registered encoder with this name """ reg_enc = self._registered_encoders - if(name in reg_enc.keys()): + if name in reg_enc: raise ValueError("There is already a registered encoder with this name") reg_enc[name] = encoder @@ -1732,18 +1732,20 @@ def __eq__(self, right): return False return True - def encode(self, word, name=None, **kwargs): + def encode(self, word, encoder_name=None, **kwargs): r""" - Transforms an element of the message space into an element of the code. + Transforms an element of the message space into a codeword. INPUT: - ``word`` -- a vector of the message space of the code - - ``name`` -- (default: ``None``) Name of the encoder which will be used + - ``encoder_name`` -- (default: ``None``) Name of the encoder which will be used to encode ``word``. The default encoder of ``self`` will be used if default value is kept + - ``kwargs`` -- all additional arguments are forwarded to :meth:`encoder` + OUTPUT: - a vector of ``self`` @@ -1764,11 +1766,11 @@ def encode(self, word, name=None, **kwargs): sage: C.encode(word, 'GeneratorMatrix') (1, 1, 0, 0, 1, 1, 0) """ - E = self.encoder(name, **kwargs) + E = self.encoder(encoder_name, **kwargs) return E.encode(word) @cached_method - def encoder(self, name=None, **kwargs): + def encoder(self, encoder_name=None, **kwargs): r""" Returns an encoder of ``self``. @@ -1778,10 +1780,13 @@ def encoder(self, name=None, **kwargs): INPUT: - - ``name`` -- (default: ``None``) name of the encoder which will be + - ``encoder_name`` -- (default: ``None``) name of the encoder which will be returned. The default encoder of ``self`` will be used if default value is kept. + - ``kwargs`` -- all additional arguments are forwarded to the constructor of the encoder + this method will return + OUTPUT: - an Encoder object @@ -1804,11 +1809,11 @@ def encoder(self, name=None, **kwargs): ... ValueError: Passed Encoder name not known """ - if name is None: - name = self._encoder_default_name - return self.encoder(name, **kwargs) - if name in self._registered_encoders: - encClass = self._registered_encoders[name] + if encoder_name is None: + encoder_name = self._encoder_default_name + return self.encoder(encoder_name, **kwargs) + if encoder_name in self._registered_encoders: + encClass = self._registered_encoders[encoder_name] E = encClass(self, **kwargs) return E else: @@ -2010,16 +2015,18 @@ def __getitem__(self, i): codeword.set_immutable() return codeword - def generator_matrix(self, name=None, **kwargs): + def generator_matrix(self, encoder_name=None, **kwargs): r""" Returns a generator matrix of ``self``. INPUT: - - ``name`` -- (default: ``None``) name of the encoder which will be + - ``encoder_name`` -- (default: ``None``) name of the encoder which will be used to compute the generator matrix. The default encoder of ``self`` will be used if default value is kept. + - ``kwargs`` -- all additional arguments are forwarded to :meth:`encoder` + EXAMPLES:: sage: G = matrix(GF(3),2,[1,-1,1,-1,1,1]) @@ -2028,7 +2035,7 @@ def generator_matrix(self, name=None, **kwargs): [1 2 1] [2 1 1] """ - E = self.encoder(name, **kwargs) + E = self.encoder(encoder_name, **kwargs) return E.generator_matrix() gen_mat = deprecated_function_alias(17973, generator_matrix) @@ -2616,7 +2623,7 @@ def permutation_automorphism_group(self, algorithm="partition"): print "\n Using the %s codewords of weight %s \n Supergroup size: \n %s\n "%(wts[wt],wt,size) gap.eval("Cwt:=Filtered(eltsC,c->WeightCodeword(c)=%s)"%wt) # bottleneck 2 (repeated gap.eval("matCwt:=List(Cwt,c->VectorCodeword(c))") # for each i until stop = 1) - if gap("Length(matCwt)") > 0: + if gap("Length(matCwt)") > 0: A = gap("MatrixAutomorphisms(matCwt)") G2 = gap("Intersection2(%s,%s)"%(str(A).replace("\n",""),str(Gp).replace("\n",""))) # bottleneck 3 Gp = G2 @@ -3098,7 +3105,7 @@ def spectrum(self, algorithm=None): input = code2leon(self) + "::code" import os, subprocess lines = subprocess.check_output([os.path.join(guava_bin_dir, 'wtdist'), input]) - import StringIO # to use the already present output parser + import StringIO # to use the already present output parser wts = [0]*(n+1) s = 0 for L in StringIO.StringIO(lines).readlines(): @@ -3235,7 +3242,7 @@ def syndrome(self, r): """ return self.parity_check_matrix()*r - def unencode(self, c, name=None, nocheck=False, **kwargs): + def unencode(self, c, encoder_name=None, nocheck=False, **kwargs): r""" Returns the message corresponding to ``c``. @@ -3244,13 +3251,15 @@ def unencode(self, c, name=None, nocheck=False, **kwargs): - ``c`` -- a vector of the same length as ``self`` over the base field of ``self`` - - ``name`` -- (default: ``None``) name of the decoder which will be used + - ``encoder_name`` -- (default: ``None``) name of the decoder which will be used to decode ``word``. The default decoder of ``self`` will be used if default value is kept. - ``nocheck`` -- (default: ``False``) checks if ``c`` is in self. If this is set to True, the return value of this method is not guaranteed to be correct. + - ``kwargs`` -- all additional arguments are forwarded to :meth:`encoder` + OUTPUT: - a vector @@ -3263,7 +3272,7 @@ def unencode(self, c, name=None, nocheck=False, **kwargs): sage: C.unencode(c) (0, 1, 1, 0) """ - E = self.encoder(name, **kwargs) + E = self.encoder(encoder_name, **kwargs) return E.unencode(c, nocheck) def weight_enumerator(self, names="xy", name2=None): @@ -3627,21 +3636,12 @@ class LinearCodeGeneratorMatrixEncoder(Encoder): r""" Encoder based on generator_matrix for Linear codes. - The only purpose of this encoder is to set generic linear codes - into the new Encoder structure by providing a valid ``generator_matrix`` - method. - - This encoder uses default implementations of ``encode`` and ``unencode``. - Its ``generator_matrix`` method returns private field ``_generator_matrix`` - of its associated code if any, else it calls the ``generator_matrix`` method - of the default encoder of the associated code. - - According to this behaviour, this encoder should never be used for other codes than + This is the default encoder of a generic linear code, and should never be used for other codes than :class:`LinearCode`. INPUT: - - ``code`` -- The associated code of this encoder. + - ``code`` -- The associated :class:`LinearCode` of this encoder. """ def __init__(self, code): From b1471480a14c682c2d7fa30b49931810d95784f6 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 30 Jul 2015 15:41:46 +0200 Subject: [PATCH 0368/1872] Integrated reviewer's comments --- src/sage/coding/linear_code.py | 50 +++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 4f608cefa4c..6410e86c428 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -715,7 +715,7 @@ class AbstractLinearCode(module.Module): - ``length``, the length of the code - - ``encoder_default_name``, the name of the encoder that will be used if no encoder name is passed + - ``default_encoder_name``, the name of the encoder that will be used if no encoder name is passed to an encoder-related method (``generator_matrix``, ``encode``, ``unencode``) - ``_registered_encoders``, a dictionary of all encoders available for this class @@ -758,7 +758,7 @@ class AbstractLinearCode(module.Module): _registered_encoders = {} - def __init__(self, base_field, length, encoder_default_name): + def __init__(self, base_field, length, default_encoder_name): """ Initializes mandatory parameters for a Linear Code object. @@ -772,7 +772,7 @@ def __init__(self, base_field, length, encoder_default_name): - ``length`` -- the length of ``self`` - - ``encoder_default_name`` -- the name of the default encoder of ``self`` + - ``default_encoder_name`` -- the name of the default encoder of ``self`` EXAMPLES: @@ -847,9 +847,9 @@ def __init__(self, base_field, length, encoder_default_name): if not isinstance(length, (int, Integer)): raise ValueError("length must be a Python int or a Sage Integer") self._length = Integer(length) - if not encoder_default_name in self._registered_encoders: + if not default_encoder_name in self._registered_encoders: raise ValueError("You must set a valid encoder as default encoder for this code") - self._encoder_default_name = encoder_default_name + self._default_encoder_name = default_encoder_name 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 @@ -1810,7 +1810,7 @@ def encoder(self, encoder_name=None, **kwargs): ValueError: Passed Encoder name not known """ if encoder_name is None: - encoder_name = self._encoder_default_name + encoder_name = self._default_encoder_name return self.encoder(encoder_name, **kwargs) if encoder_name in self._registered_encoders: encClass = self._registered_encoders[encoder_name] @@ -1836,12 +1836,12 @@ def encoders_available(self, values=False): ['GeneratorMatrix'] sage: C.encoders_available(True) - [('GeneratorMatrix', - )] + {'GeneratorMatrix': + } """ reg_enc = self._registered_encoders if values == True: - return reg_enc.items() + return copy(self._registered_encoders) return reg_enc.keys() def extended_code(self): @@ -3629,6 +3629,33 @@ def _repr_(self): """ return "Linear code of length %s, dimension %s over %s"%(self.length(), self.dimension(), self.base_ring()) + def generator_matrix(self, encoder_name=None, **kwargs): + r""" + Returns a generator matrix of ``self``. + + INPUT: + + - ``encoder_name`` -- (default: ``None``) name of the encoder which will be + used to compute the generator matrix. ``self._generator_matrix`` + will be returned if default value is kept. + + - ``kwargs`` -- all additional arguments are forwarded to :meth:`encoder` + + 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] + """ + if hasattr(self, "_generator_matrix"): + return self._generator_matrix + E = self.encoder(encoder_name, **kwargs) + return E.generator_matrix() + + + ####################### encoders ############################### from encoder import Encoder @@ -3700,7 +3727,4 @@ def generator_matrix(self): [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] """ - if hasattr(self.code(), "_generator_matrix"): - return self.code()._generator_matrix - else: - return self.code().generator_matrix() + return self.code().generator_matrix() From 00c7ca58ceaa0febc0ff72c393cf265178cda03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 4 Aug 2015 11:35:45 +0200 Subject: [PATCH 0369/1872] towards new style spkg for patchbot --- build/pkgs/patchbot/SPKG.txt | 21 +++++++++++++++++++++ build/pkgs/patchbot/checksums.ini | 4 ++++ build/pkgs/patchbot/package-version.txt | 1 + build/pkgs/patchbot/spkg-install | 21 +++++++++++++++++++++ build/pkgs/patchbot/type | 1 + 5 files changed, 48 insertions(+) create mode 100644 build/pkgs/patchbot/SPKG.txt create mode 100644 build/pkgs/patchbot/checksums.ini create mode 100644 build/pkgs/patchbot/package-version.txt create mode 100755 build/pkgs/patchbot/spkg-install create mode 100644 build/pkgs/patchbot/type diff --git a/build/pkgs/patchbot/SPKG.txt b/build/pkgs/patchbot/SPKG.txt new file mode 100644 index 00000000000..93c9d3da752 --- /dev/null +++ b/build/pkgs/patchbot/SPKG.txt @@ -0,0 +1,21 @@ += SageMath patchbot = + +== Description == + +Apply branches and run tests on open Sage tickets. + +The patchbot is used to automate the testing of git branches. It has two different aspects: a server side and a client side. + +== License == + +GPLv2+ + +== Upstream Contact == + +Robert Bradshaw +Frédéric Chapoton +https://github.com/robertwb/sage-patchbot/ + +== Dependencies == + +python, sage-scripts diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini new file mode 100644 index 00000000000..73aec48e51f --- /dev/null +++ b/build/pkgs/patchbot/checksums.ini @@ -0,0 +1,4 @@ +tarball=patchbot-VERSION.tar.bz2 +sha1=338e924734df1228427a03fbf82ea65ec345b420 +md5=aaf9ee33455656a47f687e553d401cac +cksum=1478772629 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt new file mode 100644 index 00000000000..5aa7c523257 --- /dev/null +++ b/build/pkgs/patchbot/package-version.txt @@ -0,0 +1 @@ +2.3.9 diff --git a/build/pkgs/patchbot/spkg-install b/build/pkgs/patchbot/spkg-install new file mode 100755 index 00000000000..657ce96695c --- /dev/null +++ b/build/pkgs/patchbot/spkg-install @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +if [ "$SAGE_LOCAL" = "" ]; then + echo "SAGE_LOCAL undefined ... exiting"; + echo "Maybe run 'sage -sh'?" + exit 1 +fi + +# Move any currently exising patchbot out of the way. +if [ -e "$SAGE_LOCAL/bin/patchbot" ]; then + i=0 + while [ -e "$SAGE_LOCAL/bin/patchbot-old-$i" ]; do + i=$(( $i + 1 )) + done + echo "Renaming existing patchbot directory to patchbot-old-$i" + mv "$SAGE_LOCAL/bin/patchbot" "$SAGE_LOCAL/bin/patchbot-old-$i" +fi + +# Copy into final location. +# The sage-sage script knows how to call this... +cp -Rv src "$SAGE_LOCAL/bin/patchbot" diff --git a/build/pkgs/patchbot/type b/build/pkgs/patchbot/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/patchbot/type @@ -0,0 +1 @@ +optional From b27296098cc6a7e86dca7ea1bac66e4ef2dc429b Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Wed, 25 Jun 2014 23:41:54 +0200 Subject: [PATCH 0370/1872] Add pseudo-division and gcd for Polynomials (as generic as possible) --- .../rings/polynomial/polynomial_element.pyx | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 85bd0e705c9..90d91b8a581 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3879,6 +3879,154 @@ cdef class Polynomial(CommutativeAlgebraElement): else: raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials"%self.base_ring()) + def pseudo_quo_rem(self,other): + """ + Compute the pseudo-division of two polynomials. + + INPUT: + + - ``self`` -- A polynomial + + - ``other`` -- A nonzero polynomial, otherwise an exception ValueError is raised + + OUTPUT: + + If ``other`` is nonzero, this algorithm finds Q and R such that + l^(m-n+1) self = Q * other + R where m = deg(self), n = deg(other), + l is the leading coefficient of other, and such that deg(R) < deg(other). + + + EXAMPLES:: + + sage: R. = PolynomialRing(ZZ,Sparse=True) + sage: p = x^4 + 6*x^3 + x^2 - x + 2 + sage: q = 2*x^2 - 3*x - 1 + sage: (quo,rem)=p.pseudo_quo_rem(q); quo,rem + (4*x^2 + 30*x + 51, 175*x + 67) + sage: 2^(4-2+1)*p == quo*q + rem + True + + sage: S. = R[] + sage: p = (-3*x^2 - x)*T^3 - 3*x*T^2 + (x^2 - x)*T + 2*x^2 + 3*x - 2 + sage: q = (-x^2 - 4*x - 5)*T^2 + (6*x^2 + x + 1)*T + 2*x^2 - x + sage: quo,rem=p.pseudo_quo_rem(q); quo,rem + ((3*x^4 + 13*x^3 + 19*x^2 + 5*x)*T + 18*x^4 + 12*x^3 + 16*x^2 + 16*x, + (-113*x^6 - 106*x^5 - 133*x^4 - 101*x^3 - 42*x^2 - 41*x)*T - 34*x^6 + 13*x^5 + 54*x^4 + 126*x^3 + 134*x^2 - 5*x - 50) + sage: (-x^2 - 4*x - 5)^(3-2+1) * p == quo*q + rem + True + + AUTHORS: + + - Bruno Grenet (2014-06-25) + """ + # This is Algorithm 3.1.2 in Cohen [GTM 138] + if other.degree() < 0: + raise ValueError("Pseudo-division by zero is not possible") + + R = self + B = other + Q = self.parent().zero_element() + e = self.degree() - other.degree() + 1 + d = B.leading_coefficient() + X = self.parent().gen() + + while not R.degree() < B.degree(): + S = R.leading_coefficient()*X**(R.degree()-B.degree()) + Q = d*Q+S + R = d*R-S*B + e -= 1 + + q = d**e + return (q*Q,q*R) + + @coerce_binop + def gcd(self, other): + """ + Return the gcd of self and other + + INPUT: + + - ``self`` -- A polynomial + + - ``other`` -- A polynomial + + EXAMPLES:: + + sage: R. = PolynomialRing(ZZ,Sparse=True) + sage: p = x^4 + 6*x^3 + x^2 - x + 2 + sage: q = 2*x^2 - 3*x - 1 + sage: gcd(p,q) + 1 + sage: r = x^2 + x + 1 + sage: gcd(p*r,q*r) + x^2 + x + 1 + + sage: S. = R[] + sage: p = (-3*x^2 - x)*T^3 - 3*x*T^2 + (x^2 - x)*T + 2*x^2 + 3*x - 2 + sage: q = (-x^2 - 4*x - 5)*T^2 + (6*x^2 + x + 1)*T + 2*x^2 - x + sage: gcd(p,q) + 1 + sage: r = (1 + x)*T^2 + (x - 1)*T + 2*x + 3 + sage: gcd(p*r,q*r) + (x + 1)*T^2 + (x - 1)*T + 2*x + 3 + + AUTHORS: + + - Bruno Grenet (2014-06-25) + """ + # This is Algorithm 3.3.1 in Cohen [GTM 138] + if not self.parent().base_ring().is_unique_factorization_domain(): + raise ValueError("The base ring must be a unique factorization domain") + + if self.degree() < other.degree(): + A,B = other, self + else: + A,B = self, other + + if B.is_zero(): + return A + + #from sage.rings.arith import gcd + + a = b = self.base_ring().zero_element() + for c in A.coefficients(): + a = a.gcd(c) + if a.is_one(): + break + for c in B.coefficients(): + b = b.gcd(c) + if b.is_one(): + break + + d = a.gcd(b) + A = self.parent()(A/a) + B = self.parent()(B/b) + g = h = 1 + + delta = A.degree()-B.degree() + _,R = A.pseudo_quo_rem(B) + + while R.degree() > 0: + A = B + B = self.parent()(R/(g*h**delta)) + g = A.leading_coefficient() + h = self.parent().base_ring()(h*g**delta/h**delta) + delta = A.degree() - B.degree() + _, R = A.pseudo_quo_rem(B) + + if R.is_zero(): + b = self.base_ring().zero_element() + for c in B.coefficients(): + b = b.gcd(c) + if b.is_one(): + break + return self.parent()(d*B/b) + + return d + + + + @coerce_binop def lcm(self, other): """ From c88b600cc02a37759e5a33346a52115842c85050 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Thu, 26 Jun 2014 00:44:50 +0200 Subject: [PATCH 0371/1872] Add gcd method to class Polynomial_generic_sparse --- .../rings/polynomial/polynomial_element.pyx | 6 +- .../polynomial/polynomial_element_generic.py | 66 ++++++++++++++++++- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 90d91b8a581..91f563a5033 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3885,8 +3885,6 @@ cdef class Polynomial(CommutativeAlgebraElement): INPUT: - - ``self`` -- A polynomial - - ``other`` -- A nonzero polynomial, otherwise an exception ValueError is raised OUTPUT: @@ -3946,9 +3944,7 @@ cdef class Polynomial(CommutativeAlgebraElement): INPUT: - - ``self`` -- A polynomial - - - ``other`` -- A polynomial + - ``other`` -- a polynomial defined over the same ring as ``self`` EXAMPLES:: diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 7c261dc649a..7a95c7a9281 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -644,6 +644,71 @@ def shift(self, n): output[index + n] = coeff return self.parent()(output, check=False) + def gcd(self,other,algorithm=None): + """ + Return the gcd of ``self`` and ``other`` + + INPUT: + + - ``other`` -- a polynomial defined over the same ring as ``self`` + + Three algorithms are available: + + - "dense": The polynomials are converted to the dense representation, + their gcd are computed and is converted back to the sparse + representation. + - "fraction_field": The polynomials are coerced to the ring of + polynomials over the fraction field of their base ring. It won't + work with non integral domain as base rings. The gcd method is + called with the "dense" algorithm, in case there is no specific + sparse gcd method for the fraction field. + - "pseudo-division": Uses the gcd method of the class Polynomial. + + Default is "dense" for polynomials over ZZ and "pseudo-division" in the + other cases. + + EXAMPLES:: + + sage: R. = PolynomialRing(ZZ,sparse=True) + sage: p = x^6 + 7*x^5 + 8*x^4 + 6*x^3 + 2*x^2 + x + 2 + sage: q = 2*x^4 - x^3 - 2*x^2 - 4*x - 1 + sage: gcd(p,q) + x^2 + x + 1 + sage: gcd(p, q, algorithm = "dense") + x^2 + x + 1 + sage: gcd(p, q, algorithm = "fraction_field") + x^2 + x + 1 + sage: gcd(p, q, algorithm = "pseudo-division") + x^2 + x + 1 + + AUTHORS: + + - Bruno Grenet (2014-06-25) + """ + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.rings.arith import lcm + + if algorithm is None: + if self.base_ring() == ZZ: + algorithm = "dense" + else: + algorithm = "pseudo-division" + if algorithm=="dense": + S = self.parent() + D = PolynomialRing(S.base_ring(),'x',sparse=False) + g = D(self).gcd(D(other)) + return S(g) + if algorithm=="fraction_field": + R = self.parent().base_ring() + F = R.fraction_field() + S = PolynomialRing(F,'x',sparse=True) + g = S(self).gcd(S(other),algorithm="dense") + d = lcm([gg.denominator() for gg in g.coefficients()]) + return self.parent()(d*g) + if algorithm=="pseudo-division": + return Polynomial.gcd(self,other) + @coerce_binop def quo_rem(self, other): """ @@ -726,7 +791,6 @@ def quo_rem(self, other): rem = rem[:rem.degree()] - c*other[:d].shift(e) return (quo,rem) - class Polynomial_generic_domain(Polynomial, IntegralDomainElement): def __init__(self, parent, is_gen=False, construct=False): Polynomial.__init__(self, parent, is_gen=is_gen) From 6f6a167671cffbdcc0c1d91a226a77a26f3c1cc5 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Thu, 10 Jul 2014 15:20:24 +0200 Subject: [PATCH 0372/1872] Add special case for p.pseudo_quo_rem(q) when q is a constant --- src/sage/rings/polynomial/polynomial_element.pyx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 91f563a5033..cb01692c7ba 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3921,17 +3921,21 @@ cdef class Polynomial(CommutativeAlgebraElement): if other.degree() < 0: raise ValueError("Pseudo-division by zero is not possible") + # if other is a constant, then R = 0 and Q = self * other^(deg(self)) + if other in self.parent().base_ring(): + return (self * other**(self.degree()), self.parent().zero_element()) + R = self B = other Q = self.parent().zero_element() e = self.degree() - other.degree() + 1 d = B.leading_coefficient() - X = self.parent().gen() while not R.degree() < B.degree(): - S = R.leading_coefficient()*X**(R.degree()-B.degree()) - Q = d*Q+S - R = d*R-S*B + c = R.leading_coefficient() + diffdeg = R.degree() - B.degree() + Q = d*Q + self.parent()(c).shift(diffdeg) + R = d*R - c*B.shift(diffdeg) e -= 1 q = d**e @@ -4016,6 +4020,7 @@ cdef class Polynomial(CommutativeAlgebraElement): b = b.gcd(c) if b.is_one(): break + return self.parent()(d*B/b) return d From 9f797ef3ab0b1714454c7a6f1080e46f4f654411 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Sat, 13 Dec 2014 14:22:12 +0100 Subject: [PATCH 0373/1872] Correct formatting of doctests + raise error for unknown algorithm --- .../polynomial/polynomial_element_generic.py | 132 +++++++++--------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 7a95c7a9281..5fb03fdc7fd 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -644,71 +644,6 @@ def shift(self, n): output[index + n] = coeff return self.parent()(output, check=False) - def gcd(self,other,algorithm=None): - """ - Return the gcd of ``self`` and ``other`` - - INPUT: - - - ``other`` -- a polynomial defined over the same ring as ``self`` - - Three algorithms are available: - - - "dense": The polynomials are converted to the dense representation, - their gcd are computed and is converted back to the sparse - representation. - - "fraction_field": The polynomials are coerced to the ring of - polynomials over the fraction field of their base ring. It won't - work with non integral domain as base rings. The gcd method is - called with the "dense" algorithm, in case there is no specific - sparse gcd method for the fraction field. - - "pseudo-division": Uses the gcd method of the class Polynomial. - - Default is "dense" for polynomials over ZZ and "pseudo-division" in the - other cases. - - EXAMPLES:: - - sage: R. = PolynomialRing(ZZ,sparse=True) - sage: p = x^6 + 7*x^5 + 8*x^4 + 6*x^3 + 2*x^2 + x + 2 - sage: q = 2*x^4 - x^3 - 2*x^2 - 4*x - 1 - sage: gcd(p,q) - x^2 + x + 1 - sage: gcd(p, q, algorithm = "dense") - x^2 + x + 1 - sage: gcd(p, q, algorithm = "fraction_field") - x^2 + x + 1 - sage: gcd(p, q, algorithm = "pseudo-division") - x^2 + x + 1 - - AUTHORS: - - - Bruno Grenet (2014-06-25) - """ - - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.rings.arith import lcm - - if algorithm is None: - if self.base_ring() == ZZ: - algorithm = "dense" - else: - algorithm = "pseudo-division" - if algorithm=="dense": - S = self.parent() - D = PolynomialRing(S.base_ring(),'x',sparse=False) - g = D(self).gcd(D(other)) - return S(g) - if algorithm=="fraction_field": - R = self.parent().base_ring() - F = R.fraction_field() - S = PolynomialRing(F,'x',sparse=True) - g = S(self).gcd(S(other),algorithm="dense") - d = lcm([gg.denominator() for gg in g.coefficients()]) - return self.parent()(d*g) - if algorithm=="pseudo-division": - return Polynomial.gcd(self,other) - @coerce_binop def quo_rem(self, other): """ @@ -791,6 +726,73 @@ def quo_rem(self, other): rem = rem[:rem.degree()] - c*other[:d].shift(e) return (quo,rem) + def gcd(self,other,algorithm=None): + """ + Return the gcd of ``self`` and ``other`` + + INPUT: + + - ``other`` -- a polynomial defined over the same ring as ``self`` + + Three algorithms are available: + + - "dense": The polynomials are converted to the dense representation, + their gcd are computed and is converted back to the sparse + representation. + - "fraction_field": The polynomials are coerced to the ring of + polynomials over the fraction field of their base ring. It won't + work with non integral domain as base rings. The gcd method is + called with the "dense" algorithm, in case there is no specific + sparse gcd method for the fraction field. + - "pseudo-division": Uses the gcd method of the class Polynomial. + + Default is "dense" for polynomials over ZZ and "pseudo-division" in the + other cases. + + EXAMPLES:: + + sage: R. = PolynomialRing(ZZ,sparse=True) + sage: p = x^6 + 7*x^5 + 8*x^4 + 6*x^3 + 2*x^2 + x + 2 + sage: q = 2*x^4 - x^3 - 2*x^2 - 4*x - 1 + sage: gcd(p,q) + x^2 + x + 1 + sage: gcd(p, q, algorithm = "dense") + x^2 + x + 1 + sage: gcd(p, q, algorithm = "fraction_field") + x^2 + x + 1 + sage: gcd(p, q, algorithm = "pseudo-division") + x^2 + x + 1 + + AUTHORS: + + - Bruno Grenet (2014-06-25) + """ + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.rings.arith import lcm + + if algorithm is None: + if self.base_ring() == ZZ: + algorithm = "dense" + else: + algorithm = "pseudo-division" + if algorithm=="dense": + S = self.parent() + D = PolynomialRing(S.base_ring(),'x',sparse=False) + g = D(self).gcd(D(other)) + return S(g) + if algorithm=="fraction_field": + R = self.parent().base_ring() + F = R.fraction_field() + S = PolynomialRing(F,'x',sparse=True) + g = S(self).gcd(S(other),algorithm="dense") + d = lcm([gg.denominator() for gg in g.coefficients()]) + return self.parent()(d*g) + if algorithm=="pseudo-division": + return Polynomial.gcd(self,other) + else: + raise ValueError("Unknown algorithm '%s'" % algorithm) + class Polynomial_generic_domain(Polynomial, IntegralDomainElement): def __init__(self, parent, is_gen=False, construct=False): Polynomial.__init__(self, parent, is_gen=is_gen) From 6c31b67522c46efa26f5b7b60db6ee2b4869e89a Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Sat, 13 Dec 2014 14:51:01 +0100 Subject: [PATCH 0374/1872] Change Error for pseudo-division by zero --- src/sage/rings/polynomial/polynomial_element.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index cb01692c7ba..8608df269a9 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3918,8 +3918,8 @@ cdef class Polynomial(CommutativeAlgebraElement): - Bruno Grenet (2014-06-25) """ # This is Algorithm 3.1.2 in Cohen [GTM 138] - if other.degree() < 0: - raise ValueError("Pseudo-division by zero is not possible") + if other.is_zero(): + raise ZeroDivisionError("Pseudo-division by zero is not possible") # if other is a constant, then R = 0 and Q = self * other^(deg(self)) if other in self.parent().base_ring(): From f623b8893f9b08689be7e3df95e99a51d8c744ce Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Mon, 15 Dec 2014 18:35:12 +0100 Subject: [PATCH 0375/1872] Choice between FLINT and NTL --- .../rings/polynomial/polynomial_element_generic.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 5fb03fdc7fd..26487f33b05 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -778,7 +778,17 @@ def gcd(self,other,algorithm=None): algorithm = "pseudo-division" if algorithm=="dense": S = self.parent() - D = PolynomialRing(S.base_ring(),'x',sparse=False) + # FLINT is faster but a bug makes the conversion extremely slow, + # so NTL is used in those cases where the conversion is too slow. Cf + # + sd = self.degree() + od = other.degree() + if max(sd,od)<100 or \ + min(len(self.__coeffs)/sd, len(other.__coeffs)/od)>.06: + implementation="FLINT" + else: + implementation="NTL" + D = PolynomialRing(S.base_ring(),'x',implementation=implementation) g = D(self).gcd(D(other)) return S(g) if algorithm=="fraction_field": From 3015456844cb54f37cf4bbae8423521cdd33624a Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Fri, 7 Aug 2015 15:53:33 +0200 Subject: [PATCH 0376/1872] Adapted to 6.9beta1 => Merged two gcd methods --- .../rings/polynomial/polynomial_element.pyx | 162 ++++++++---------- 1 file changed, 67 insertions(+), 95 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 8608df269a9..a8a4f321be3 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3824,61 +3824,6 @@ cdef class Polynomial(CommutativeAlgebraElement): raise NotImplementedError("splitting_field() is only implemented over number fields and finite fields") - @coerce_binop - def gcd(self, other): - """ - Return a greatest common divisor of this polynomial and ``other``. - - INPUT: - - - ``other`` -- a polynomial in the same ring as this polynomial - - OUTPUT: - - A greatest common divisor as a polynomial in the same ring as - this polynomial. If the base ring is a field, the return value - is a monic polynomial. - - .. NOTE:: - - The actual algorithm for computing greatest common divisors depends - on the base ring underlying the polynomial ring. If the base ring - defines a method ``_gcd_univariate_polynomial``, then this method - will be called (see examples below). - - EXAMPLES:: - - sage: R. = QQ[] - sage: (2*x^2).gcd(2*x) - x - sage: R.zero().gcd(0) - 0 - sage: (2*x).gcd(0) - x - - One can easily add gcd functionality to new rings by providing a - method ``_gcd_univariate_polynomial``:: - - sage: R. = QQ[] - sage: S. = R[] - sage: h1 = y*x - sage: h2 = y^2*x^2 - sage: h1.gcd(h2) - Traceback (most recent call last): - ... - NotImplementedError: Univariate Polynomial Ring in x over Rational Field does not provide a gcd implementation for univariate polynomials - sage: T. = QQ[] - sage: R._gcd_univariate_polynomial = lambda f,g: S(T(f).gcd(g)) - sage: h1.gcd(h2) - x*y - sage: del R._gcd_univariate_polynomial - - """ - if hasattr(self.base_ring(), '_gcd_univariate_polynomial'): - return self.base_ring()._gcd_univariate_polynomial(self, other) - else: - raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials"%self.base_ring()) - def pseudo_quo_rem(self,other): """ Compute the pseudo-division of two polynomials. @@ -3893,10 +3838,13 @@ cdef class Polynomial(CommutativeAlgebraElement): l^(m-n+1) self = Q * other + R where m = deg(self), n = deg(other), l is the leading coefficient of other, and such that deg(R) < deg(other). + ALGORITHM: + + Algorithm 3.1.2 in [GTM138]_. EXAMPLES:: - sage: R. = PolynomialRing(ZZ,Sparse=True) + sage: R. = PolynomialRing(ZZ, sparse=True) sage: p = x^4 + 6*x^3 + x^2 - x + 2 sage: q = 2*x^2 - 3*x - 1 sage: (quo,rem)=p.pseudo_quo_rem(q); quo,rem @@ -3913,21 +3861,21 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: (-x^2 - 4*x - 5)^(3-2+1) * p == quo*q + rem True - AUTHORS: + REFERENCES: - - Bruno Grenet (2014-06-25) + .. [GTM138] Henri Cohen. A Course in Computational Number Theory. + Graduate Texts in Mathematics, vol. 138. Springer, 1993. """ - # This is Algorithm 3.1.2 in Cohen [GTM 138] if other.is_zero(): raise ZeroDivisionError("Pseudo-division by zero is not possible") # if other is a constant, then R = 0 and Q = self * other^(deg(self)) if other in self.parent().base_ring(): - return (self * other**(self.degree()), self.parent().zero_element()) + return (self * other**(self.degree()), self.parent().zero()) R = self B = other - Q = self.parent().zero_element() + Q = self.parent().zero() e = self.degree() - other.degree() + 1 d = B.leading_coefficient() @@ -3944,37 +3892,71 @@ cdef class Polynomial(CommutativeAlgebraElement): @coerce_binop def gcd(self, other): """ - Return the gcd of self and other + Return a greatest common divisor of this polynomial and ``other``. INPUT: - - ``other`` -- a polynomial defined over the same ring as ``self`` + - ``other`` -- a polynomial in the same ring as this polynomial + + OUTPUT: + + A greatest common divisor as a polynomial in the same ring as + this polynomial. If the base ring is a field, the return value + is a monic polynomial. + + .. NOTE:: + + The actual algorithm for computing greatest common divisors depends + on the base ring underlying the polynomial ring. If the base ring + defines a method ``_gcd_univariate_polynomial``, then this method + will be called (see examples below). If no such method exists, a + fallback algorithm is used. + + ALGORITHM: + + The fallback algorithm is Algorithm 3.3.1 in [GTM138]_. EXAMPLES:: - sage: R. = PolynomialRing(ZZ,Sparse=True) - sage: p = x^4 + 6*x^3 + x^2 - x + 2 - sage: q = 2*x^2 - 3*x - 1 - sage: gcd(p,q) - 1 - sage: r = x^2 + x + 1 - sage: gcd(p*r,q*r) - x^2 + x + 1 + sage: R. = QQ[] + sage: (2*x^2).gcd(2*x) + x + sage: R.zero().gcd(0) + 0 + sage: (2*x).gcd(0) + x - sage: S. = R[] - sage: p = (-3*x^2 - x)*T^3 - 3*x*T^2 + (x^2 - x)*T + 2*x^2 + 3*x - 2 - sage: q = (-x^2 - 4*x - 5)*T^2 + (6*x^2 + x + 1)*T + 2*x^2 - x - sage: gcd(p,q) + A fallback algorithm is implemented for rings that have no method + ``_gcd_univariate_polynomial``:: + + sage: R. = ZZ[] + sage: S. = PolynomialRing(R, sparse=True) + sage: p = (-3*x^2 - x)*y^3 - 3*x*y^2 + (x^2 - x)*y + 2*x^2 + 3*x - 2 + sage: q = (-x^2 - 4*x - 5)*y^2 + (6*x^2 + x + 1)*y + 2*x^2 - x + sage: p.gcd(q) 1 - sage: r = (1 + x)*T^2 + (x - 1)*T + 2*x + 3 - sage: gcd(p*r,q*r) - (x + 1)*T^2 + (x - 1)*T + 2*x + 3 + sage: r = (1 + x)*y^2 + (x - 1)*y + 2*x + 3 + sage: (p*r).gcd(q*r) + (x + 1)*y^2 + (x - 1)*y + 2*x + 3 - AUTHORS: + One can easily provide a specialized gcd function for rings by providing + a method ``_gcd_univariate_polynomial``:: + + sage: T. = QQ[] + sage: R._gcd_univariate_polynomial = lambda f,g: S(T(f).gcd(g)) + sage: (p*r).gcd(q*r) + (x + 1)*y^2 + (x - 1)*y + 2*x + 3 + sage: del R._gcd_univariate_polynomial + + REFERENCES: - - Bruno Grenet (2014-06-25) + .. [GTM138] Henri Cohen. A Course in Computational Number Theory. + Graduate Texts in Mathematics, vol. 138. Springer, 1993. """ - # This is Algorithm 3.3.1 in Cohen [GTM 138] + if hasattr(self.base_ring(), '_gcd_univariate_polynomial'): + return self.base_ring()._gcd_univariate_polynomial(self, other) + + # Fallback algorithm: Algorithm 3.3.1 in Cohen [GTM 138] if not self.parent().base_ring().is_unique_factorization_domain(): raise ValueError("The base ring must be a unique factorization domain") @@ -3986,9 +3968,7 @@ cdef class Polynomial(CommutativeAlgebraElement): if B.is_zero(): return A - #from sage.rings.arith import gcd - - a = b = self.base_ring().zero_element() + a = b = self.base_ring().zero() for c in A.coefficients(): a = a.gcd(c) if a.is_one(): @@ -4015,7 +3995,7 @@ cdef class Polynomial(CommutativeAlgebraElement): _, R = A.pseudo_quo_rem(B) if R.is_zero(): - b = self.base_ring().zero_element() + b = self.base_ring().zero() for c in B.coefficients(): b = b.gcd(c) if b.is_one(): @@ -4025,9 +4005,6 @@ cdef class Polynomial(CommutativeAlgebraElement): return d - - - @coerce_binop def lcm(self, other): """ @@ -6787,15 +6764,10 @@ cdef class Polynomial(CommutativeAlgebraElement): False 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 - Traceback (most recent call last): - ... - NotImplementedError: Univariate Polynomial Ring in y over Rational Field does not provide a gcd implementation for univariate polynomials + sage: (2*x*y).is_squarefree() + True sage: (2*x*y^2).is_squarefree() False From b91cd828945a4668938298ef741769ce64f909a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 9 Aug 2015 14:19:32 +0200 Subject: [PATCH 0377/1872] trac #18044 correct one typo in the doc --- src/sage/categories/modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 9d578f178ea..56bbe1b0b61 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -388,7 +388,7 @@ def Super(self, base_ring=None): r""" Return the super-analogue category of ``self``. - INPUT:: + INPUT: - ``base_ring`` -- this is ignored From fc7d6a56de2a3dc24003adfa5fddfbb711ca143b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Sun, 9 Aug 2015 17:58:47 +0300 Subject: [PATCH 0378/1872] Typo correction. --- src/sage/combinat/posets/posets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 9548e27ea38..9b7cef63f84 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -2426,7 +2426,7 @@ def is_chain_of_poset(self, elms, ordered=False): """ if ordered: if not hasattr(elms, '__getitem__'): - raise TypeError("ordered=True not combatible with type %s for elms" % type(elms)) + raise TypeError("ordered=True not compatible with type %s for elms" % type(elms)) sorted_o = elms return all(self.lt(a, b) for a, b in zip(sorted_o, sorted_o[1:])) else: From 29ab8f2b3ba3fb8d6366f694c26866e1c0f3e4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 11 Aug 2015 09:39:59 +0300 Subject: [PATCH 0379/1872] Added a function is_subposet(). --- src/sage/combinat/posets/posets.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 7224f4c41d7..67747db9b0c 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5601,6 +5601,29 @@ def incidence_algebra(self, R, prefix='I'): from sage.combinat.posets.incidence_algebras import IncidenceAlgebra return IncidenceAlgebra(R, self, prefix) + def is_subposet(self, other): + r""" + Return ``True`` if the poset is a subposet of ``other``, and ``False`` otherwise. + + .. NOTE:: + + This method does not check whether the poset is a + subposet *isomorphic* to ``other``, but only if ``other`` + directly contains the poset as an (induced) subposet. + For isomorphic subposets see :meth:`has_isomorphic_subposet`. + + EXAMPLES:: + + sage: P = Poset({1:[2, 3]}) + sage: Q = Poset({1:[2, 4], 2:[3]}) + sage: P.is_subposet(Q) + False + sage: R = Poset({0:[1], 1:[3, 4], 3:[5], 4:[2]}) + sage: P.is_subposet(R) + True + """ + return self.hasse_diagram().is_subgraph(other.hasse_diagram().transitive_closure()) + FinitePoset._dual_class = FinitePoset ##### Posets ##### From 618de1c14f9746ada9cc0676e4ce9eb365a94552 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 12 Aug 2015 14:13:57 +0200 Subject: [PATCH 0380/1872] experimental warning for terms: refer to #17601 --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 8af6ee9ee1c..7c681208a1d 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -33,7 +33,7 @@ See http://trac.sagemath.org/17601 for details. sage: T = atm.ExactTermMonoid(G, ZZ) 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/17715 for details. + See http://trac.sagemath.org/17601 for details. sage: R. = AsymptoticRing('x^ZZ', ZZ) """ From df6346f78d396f0a6aa066003bd446a5d9c158b0 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 12 Aug 2015 14:14:17 +0200 Subject: [PATCH 0381/1872] typo fixed --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 7c681208a1d..7b98610f18b 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -370,7 +370,7 @@ def _sub_(self, other): def _mul_term_(self, term): r""" Helper method: multiply this asymptotic expression with the - asymptotic term ``other``. + asymptotic term ``term``. INPUT: From b5e76acb1104af129176af6d40eb035cb986466a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 12 Aug 2015 14:14:26 +0200 Subject: [PATCH 0382/1872] use len(poset) instead of len(poset._shells_) --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 7b98610f18b..4bd2b35a9e9 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -451,7 +451,7 @@ def __pow__(self, power): sage: (x^(1/2) + O(x^0))^15 x^(15/2) + O(x^7) """ - if len(self.summands._shells_) > 1: + if len(self.summands) > 1: from sage.rings.integer_ring import ZZ if power not in ZZ: raise NotImplementedError('Taking the sum %s to the ' From 76f59a6cf7a8d376caff2ef8fa630d555c08b2e4 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 12 Aug 2015 18:10:28 +0200 Subject: [PATCH 0383/1872] removed unnecessary doctest --- src/sage/rings/asymptotic_ring.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 4bd2b35a9e9..13383451c9e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -851,8 +851,6 @@ def _coerce_map_from_(self, R): True sage: AR_QQ.has_coerce_map_from(ZZ) True - sage: 1/2 * x_QQ^2 + 7/8 * x_QQ^3 - 7/8*x^3 + 1/2*x^2 """ if self.coefficient_ring.has_coerce_map_from(R): return True From a5cb84ce1b70bf2e03228b18aef8c0664d775d5a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 12 Aug 2015 18:44:11 +0200 Subject: [PATCH 0384/1872] extended functionality and doctests of element_constructor --- src/sage/rings/asymptotic_ring.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 13383451c9e..415d41ee821 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -761,15 +761,19 @@ def _element_constructor_(self, data, summands=None, simplify=True): TESTS:: - sage: AR. = AsymptoticRing('x^ZZ', ZZ) - sage: 3 * x^3 - 3*x^3 - sage: 3 * x^3 + x - 3*x^3 + x - sage: (3 * x^3) * (5 * x) - 15*x^4 - sage: 3 * x^3 + O(x^5) - O(x^5) + sage: AR = AsymptoticRing('x^ZZ', ZZ) + sage: AR(5) + 5 + sage: AR(3*x^2) + 3*x^2 + sage: x = ZZ['x'].gen(); x.parent() + Univariate Polynomial Ring in x over Integer Ring + sage: AR(x) + x + sage: y = ZZ['y'].gen(); AR(y) + Traceback (most recent call last): + ... + TypeError: Cannot convert y to an asymptotic expression. """ if summands is not None: if type(data) != int or data != 0: @@ -800,6 +804,13 @@ def _element_constructor_(self, data, summands=None, simplify=True): summands = AsymptoticRing._create_empty_summands_() return self.element_class(self, summands, simplify=simplify) + try: + summand = self.create_summand('exact', data) + except (TypeError, ValueError): + pass + else: + return summand + try: coefficient = self.coefficient_ring(data) except (TypeError, ValueError): From a364c5bb852ae4d7fce12fbfef9bb2dbbc86d539 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 12 Aug 2015 19:13:18 +0200 Subject: [PATCH 0385/1872] minor simplification in create_summand --- src/sage/rings/asymptotic_ring.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 415d41ee821..e9b4d03bd1e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -1008,11 +1008,10 @@ def create_summand(self, type, growth=None, coefficient=None): 123*x^456 """ from sage.monoids.asymptotic_term_monoid import TermMonoid + TM = TermMonoid(type, self.growth_group, self.coefficient_ring) if type == 'O': - TM = TermMonoid(type, self.growth_group) return self(TM(growth)) elif type == 'exact': if coefficient == 0: return self(coefficient) - TM = TermMonoid(type, self.growth_group, self.coefficient_ring) return self(TM(growth, coefficient)) From 7635377d6df71f71cf457074f2151dd208ef5c16 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 13 Aug 2015 12:17:38 +0200 Subject: [PATCH 0386/1872] improved create_summand, modified some doctests --- src/sage/rings/asymptotic_ring.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index e9b4d03bd1e..9a7acdc711f 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -494,7 +494,7 @@ def O(self): sage: import sage.groups.asymptotic_growth_group as agg sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(MG, ZZ) - sage: x = AR.create_summand('exact', x) + sage: x = AR.create_summand('exact', growth=x) sage: O(x) O(x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr @@ -511,7 +511,7 @@ def O(self): """ if not self: raise ValueError('Cannot build O(%s).' % (self,)) - return sum(self.parent().create_summand('O', element) + return sum(self.parent().create_summand('O', growth=element) for element in self.summands.maximal_elements()) @@ -805,7 +805,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): return self.element_class(self, summands, simplify=simplify) try: - summand = self.create_summand('exact', data) + summand = self.create_summand('exact', growth=data) except (TypeError, ValueError): pass else: @@ -816,7 +816,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): except (TypeError, ValueError): pass else: - return self.create_summand('exact', 1, coefficient) + return self.create_summand('exact', growth=1, coefficient=coefficient) raise TypeError('Cannot convert %s to an asymptotic ' 'expression.' % (data,)) @@ -925,7 +925,7 @@ def gens(self): """ from sage.groups.asymptotic_growth_group import MonomialGrowthGroup if isinstance(self.growth_group, MonomialGrowthGroup): - return self.create_summand('exact', self.growth_group.gen(), 1), + return self.create_summand('exact', growth=self.growth_group.gen(), coefficient=1), def gen(self, n=0): @@ -974,7 +974,7 @@ def ngens(self): return 0 - def create_summand(self, type, growth=None, coefficient=None): + def create_summand(self, type, growth, **kwds): r""" Create a simple asymptotic expression consisting of a single summand. @@ -1002,16 +1002,15 @@ def create_summand(self, type, growth=None, coefficient=None): sage: import sage.groups.asymptotic_growth_group as agg sage: G = agg.GrowthGroup('x^ZZ') sage: R = AsymptoticRing(G, ZZ) - sage: R.create_summand('O', x^2) + sage: R.create_summand('O', growth=x^2) O(x^2) - sage: R.create_summand('exact', x^456, 123) + sage: R.create_summand('exact', growth=x^456, coefficient=123) 123*x^456 """ from sage.monoids.asymptotic_term_monoid import TermMonoid TM = TermMonoid(type, self.growth_group, self.coefficient_ring) - if type == 'O': - return self(TM(growth)) - elif type == 'exact': - if coefficient == 0: - return self(coefficient) - return self(TM(growth, coefficient)) + + if type == 'exact' and kwds.get('coefficient') == 0: + return self(kwds['coefficient']) + + return self(TM(growth, **kwds)) From 25ce2298e21a3550a358cc2a57e8f6014040183c Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 13 Aug 2015 18:33:42 +0200 Subject: [PATCH 0387/1872] added some line wraps --- src/sage/rings/asymptotic_ring.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 9a7acdc711f..aeb1e215d7b 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -29,10 +29,14 @@ sage: import sage.groups.asymptotic_growth_group as agg sage: import sage.monoids.asymptotic_term_monoid as atm sage: G = agg.MonomialGrowthGroup(ZZ, 'x') - doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + 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/17601 for details. sage: T = atm.ExactTermMonoid(G, ZZ) - doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + 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/17601 for details. sage: R. = AsymptoticRing('x^ZZ', ZZ) """ From 1aa064882c273a0f1e5f6b79409241024d65760e Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 13 Aug 2015 18:35:05 +0200 Subject: [PATCH 0388/1872] fixed two doctests --- src/sage/rings/asymptotic_ring.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index aeb1e215d7b..5d408c83fc2 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -167,8 +167,9 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): also compute with logarithmic terms (simply by constructing the appropriate growth group):: - sage: R_log. = AsymptoticRing('log(x)^QQ', QQ) - sage: (O(xl) + xl^3)^4 + sage: R_log = AsymptoticRing('log(x)^QQ', QQ) + sage: lx = R_log(log(SR.var('x'))) + sage: (O(lx) + lx^3)^4 log(x)^12 + O(log(x)^10) """ def __init__(self, parent, summands, simplify=True): @@ -578,7 +579,7 @@ class AsymptoticRing(sage.rings.ring.Ring, sage: R. = AsymptoticRing('x^ZZ', QQ); R Asymptotic Ring over Rational Field - sage: R_log. = AsymptoticRing('log(x)^ZZ', QQ); R_log + sage: R_log = AsymptoticRing('log(x)^ZZ', QQ); R_log Asymptotic Ring over Rational Field According to the conventions for parents, uniqueness is ensured:: From eb32b4cc38fff486227855691d86763126296f6a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 13 Aug 2015 18:50:53 +0200 Subject: [PATCH 0389/1872] bracket notation only works if the underlying growth group has a generator --- src/sage/rings/asymptotic_ring.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 5d408c83fc2..cec35db18f2 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -628,11 +628,22 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, sage: AR2. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR1 is AR2 True + + The bracket notation can only be used if the growth group + has a generator:: + + sage: AR. = AsymptoticRing('log(x)^ZZ', ZZ) + Traceback (most recent call last): + ... + ValueError: Growth Group log(x)^ZZ does not have a generator. """ if isinstance(growth_group, str): from sage.groups.asymptotic_growth_group import GrowthGroup growth_group = GrowthGroup(growth_group) + if names is not None and not growth_group.gens_monomial(): + raise ValueError("%s does not have a generator." % (growth_group,)) + return super(AsymptoticRing, cls).__classcall__(cls, growth_group, coefficient_ring, category) From 290ce06f47c508498e6493c857b52bd2e0baff58 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 13 Aug 2015 21:50:38 +0200 Subject: [PATCH 0390/1872] exponential growth group: initial version --- src/sage/groups/asymptotic_growth_group.py | 573 ++++++++++++++++++++- 1 file changed, 568 insertions(+), 5 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 3e5d42faa39..ea6b0f1861c 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -23,6 +23,7 @@ - Daniel Krenn (2015-05-29): initial version and review - Daniel Krenn (2015-06-02): cartesian products - Benjamin Hackl (2015-07): growth group factory +- Benjamin Hackl (2015-08): exponential growth group, initial version .. WARNING:: @@ -45,6 +46,12 @@ without a formal deprecation. See http://trac.sagemath.org/17601 for details. Growth Group x^ZZ + sage: G = agg.ExponentialGrowthGroup(QQ, 'x'); G + 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/17601 for details. + Growth Group QQ^x .. NOTE:: @@ -1797,6 +1804,564 @@ def ngens(self): return len(self.gens()) + +class ExponentialGrowthElement(GenericGrowthElement): + r""" + An implementation of exponential growth elements. + + INPUT: + + - ``parent`` -- an :class:`ExponentialGrowthGroup`. + + - ``raw_element`` -- an element from the base ring of the parent. + + This ``raw_element`` is the base of the created exponential + growth element. + + An exponential growth element represents a term of the type + `\operatorname{base}^{\operatorname{variable}}`. The multiplication + corresponds to the multiplication of the bases. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.GrowthGroup('ZZ^x') + sage: e1 = P(1); e1 + 1 + sage: e2 = P(raw_element=2); e2 + 2^x + sage: e1 == e2 + False + sage: P.le(e1, e2) + True + sage: P.le(e1, P(1)) and P.le(P(1), e2) + True + """ + + @property + def base(self): + r""" + The base of this exponential growth element. + + EXAMPLES: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.GrowthGroup('ZZ^x') + sage: P(42^x).base + 42 + """ + return self._raw_element_ + + + def _repr_(self): + r""" + A representation string for this exponential growth element. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.GrowthGroup('QQ^x') + sage: P(1)._repr_() + '1' + sage: P(5^x) # indirect doctest + 5^x + sage: P((1/2)^x) # indirect doctest + (1/2)^x + + TESTS:: + + sage: P((-1)^x) # indirect doctest + (-1)^x + """ + from sage.rings.integer_ring import ZZ + + if self.base == 1: + return '1' + elif self.base in ZZ and self.base > 0 or str(self.base).startswith('sqrt'): + return str(self.base) + '^' + self.parent()._var_ + else: + return '(' + str(self.base) + ')^' + self.parent()._var_ + + + def _mul_(self, other): + r""" + Multiply this exponential growth element with another. + + INPUT: + + - ``other`` -- a :class:`ExponentialGrowthElement` + + OUTPUT: + + The product as a :class:`ExponentialGrowthElement`. + + .. NOTE:: + + Two exponential growth elements are multiplied by + multiplying their bases. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.GrowthGroup('ZZ^x') + sage: a = P(2^x) + sage: b = P(3^x) + sage: c = a._mul_(b); c + 6^x + sage: c == a * b + True + sage: a * b * a # indirect doctest + 12^x + """ + return self.parent()(raw_element=self.base * other.base) + + + def __invert__(self): + r""" + Return the multiplicative inverse of this exponential growth element. + + INPUT: + + Nothing. + + OUTPUT: + + The multiplicative inverse as a :class:`ExponentialGrowthElement`. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.GrowthGroup('ZZ^x') + sage: e1 = P(raw_element=2) + sage: e2 = e1.__invert__(); e2 + (1/2)^x + sage: e2 == ~e1 + True + """ + new_base = 1 / self.base + try: + return self.parent()(raw_element=new_base) + except (ValueError, TypeError): + new_parent = ExponentialGrowthGroup(new_base.parent(), + self.parent()._var_) + return new_parent(raw_element=new_base) + + + def __pow__(self, power): + r""" + Takes this growth element to the given ``power``. + + INPUT: + + - ``power`` -- a number. This can anything that is valid to be + on the right hand side of ``*`` with an elements of the + parent's base. + + OUTPUT: + + The result of this exponentiation a :class:`ExponentialGrowthElement`. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.GrowthGroup('ZZ^x') + sage: a = P(7^x); a + 7^x + sage: b = a^(1/2); b + sqrt(7)^x + sage: b.parent() + Growth Group SR^x + sage: b^12 + 117649^x + """ + new_base = self.base ** power + try: + return self.parent()(raw_element=new_base) + except (ValueError, TypeError): + pass + + new_parent = ExponentialGrowthGroup(new_base.parent(), + self.parent()._var_) + return new_parent(raw_element=new_base) + + + def _le_(self, other): + r""" + Return if this :class:`ExponentialGrowthElement` is at most + (less than or equal to) ``other``. + + INPUT: + + - ``other`` -- a :class:`ExponentialGrowthElement`. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This function compares two instances of + :class:`ExponentialGrowthElement`. + + TESTS:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P_ZZ = agg.GrowthGroup('ZZ^x') + sage: P_SR = agg.GrowthGroup('SR^x') + sage: P_ZZ(2^x) <= P_SR(sqrt(3)^x)^2 # indirect doctest + True + """ + return bool(abs(self.base) <= abs(other.base)) + + +class ExponentialGrowthGroup(GenericGrowthGroup): + r""" + A growth group dealing with expressions involving a fixed + variable/symbol as the exponent. + + The elements :class:`ExponentialGrowthElement` of this group + represent exponential functions with bases from a fixed base + ring; the group law is the multiplication. + + INPUT: + + - ``base`` -- one of SageMath's parents, out of which the elements + get their data (``raw_element``). + + As exponential expressions are represented by this group, + the elements in ``base`` are the bases of these exponentials. + + - ``var`` -- an object. + + The string representation of ``var`` acts as an exponent of the + elements represented by this group. + + - ``category`` -- (default: ``None``) the category of the newly + created growth group. It has to be a subcategory of ``Join of + Category of groups and Category of posets``. This is also the + default category if ``None`` is specified. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.ExponentialGrowthGroup(QQ, 'x'); P + Growth Group QQ^x + + .. SEEALSO:: + + :class:`GenericGrowthGroup` + """ + + # enable the category framework for elements + Element = ExponentialGrowthElement + + + @staticmethod + def __classcall__(cls, base, var, category=None): + r""" + Normalizes the input in order to ensure a unique + representation. + + For more information see :class:`ExponentialGrowthGroup`. + + TESTS:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P1 = agg.ExponentialGrowthGroup(QQ, 'x') + sage: P2 = agg.ExponentialGrowthGroup(QQ, ZZ['x'].gen()) + sage: P3 = agg.ExponentialGrowthGroup(QQ, SR.var('x')) + sage: P1 is P2 and P2 is P3 + True + sage: P4 = agg.ExponentialGrowthGroup(QQ, buffer('xylophone', 0, 1)) + sage: P1 is P4 + True + sage: P5 = agg.ExponentialGrowthGroup(QQ, 'x ') + sage: P1 is P5 + True + """ + var = str(var).strip() + return super(ExponentialGrowthGroup, cls).__classcall__( + cls, base, var, category) + + + @sage.misc.superseded.experimental(trac_number=17601) + def __init__(self, base, var, category): + r""" + For more information see :class:`ExponentialGrowthGroup`. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: agg.ExponentialGrowthGroup(QQ, 'x') + Growth Group QQ^x + sage: agg.ExponentialGrowthGroup(SR, ZZ['y'].gen()) + Growth Group SR^y + + TESTS:: + + sage: agg.ExponentialGrowthGroup('x', ZZ) + Traceback (most recent call last): + ... + TypeError: x is not a valid base + """ + if not var: + raise ValueError('Empty var is not allowed.') + if var[0] in '0123456789=+-*/^%': + # This restriction is mainly for optical reasons on the + # representation. Feel free to relax this if needed. + raise ValueError("The variable name '%s' is inappropriate." % + (var,)) + self._var_ = var + + super(ExponentialGrowthGroup, self).__init__(category=category, base=base) + + + def _repr_short_(self): + r""" + A short representation string of this exponential growth group. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: agg.ExponentialGrowthGroup(QQ, 'a') # indirect doctest + Growth Group QQ^a + + + TESTS:: + + sage: agg.ExponentialGrowthGroup(QQ, 'a')._repr_short_() + 'QQ^a' + sage: agg.ExponentialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() + '(Univariate Polynomial Ring in x over Rational Field)^a' + """ + return '%s^%s' % (parent_to_repr_short(self.base()), self._var_) + + + def __hash__(self): + r""" + Return the hash of this group. + + INPUT: + + Nothing. + + OUTPUT: + + An integer. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') + sage: hash(P) # random + -1234567890123456789 + """ + return hash((super(ExponentialGrowthGroup, self).__hash__(), self._var_)) + + + def _convert_(self, data): + r""" + Converts given ``data`` to something the constructor of the + element class accepts (``raw_element``). + + INPUT: + + - ``data`` -- an object. + + OUTPUT: + + An element of the base ring or ``None`` (when no such element + can be constructed). + + TESTS:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') + sage: P._convert_('icecream') is None + True + sage: P(1) # indirect doctest + 1 + sage: P('2^x') # indirect doctest + 2^x + + :: + + sage: P(2^x) # indirect doctest + 2^x + sage: P((-333)^x) # indirect doctest + (-333)^x + + :: + + sage: P('7^x') + 7^x + sage: P('(-2)^x') + (-2)^x + + :: + + sage: P = agg.GrowthGroup('SR^x') + sage: P(sqrt(3)^x) + sqrt(3)^x + sage: P((3^(1/3))^x) + (3^(1/3))^x + """ + if data == 1 or data == '1': + return self.base().one() + + try: + P = data.parent() + except AttributeError: + import re + if self._var_ not in str(data): + return # this has to end here + + elif str(data).endswith('^' + self._var_): + return self.base()(str(data).replace('^' + self._var_, '') + .replace('(', '').replace(')', '')) + else: + return # end of parsing + + + from sage.symbolic.ring import SR + import operator + from sage.symbolic.operators import mul_vararg + if P is SR: + if data.operator() == operator.pow: + base, exponent = data.operands() + if str(exponent) == self._var_: + return base + elif exponent.operator() == mul_vararg: + return base ** (exponent / SR(self._var_)) + + + def _coerce_map_from_(self, S): + r""" + Return if ``S`` coerces into this growth group. + + INPUT: + + - ``S`` -- a parent. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P_x_ZZ = agg.GrowthGroup('ZZ^x') + sage: P_x_QQ = agg.GrowthGroup('QQ^x') + sage: bool(P_x_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + False + sage: bool(P_x_QQ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + True + sage: P_y_ZZ = agg.GrowthGroup('ZZ^y') + sage: bool(P_y_ZZ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + False + sage: bool(P_x_ZZ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + False + sage: bool(P_y_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + False + sage: bool(P_x_QQ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + False + """ + if super(ExponentialGrowthGroup, self)._coerce_map_from_(S): + if self._var_ == S._var_: + return True + + + def gens_monomial(self): + r""" + Return a tuple containing generators of this growth group. + + INPUT: + + Nothing. + + OUTPUT: + + A tuple containing elements of this growth group. + + .. NOTE:: + + A :class:`ExponentialGrowthGroup` has no generators, + thus an empty tuple is returned. + + TESTS:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: agg.GrowthGroup('ZZ^x').gens_monomial() + () + """ + return () + + # for exponential growth groups, gens_monomial is an alias of gens: + gens = gens_monomial + + + def gen(self, n=0): + r""" + Return the `n`-th generator of this growth group. + + INPUT: + + - ``n`` -- default: `0`. + + OUTPUT: + + A generator of this growth group. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.GrowthGroup('QQ^x') + sage: P.gen() + Traceback (most recent call last): + ... + ValueError: Growth Group QQ^x has no generators. + """ + raise ValueError("%s has no generators." % (self,)) + + def ngens(self): + r""" + Return the number of generators of this exponential + growth group. + + INPUT: + + Nothing. + + OUTPUT: + + A Python integer. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: P = agg.GrowthGroup('QQ^x') + sage: P.ngens() + 0 + """ + return len(self.gens()) + + class GrowthGroupFactory(sage.structure.factory.UniqueFactory): r""" A factory creating asymptotic growth groups. @@ -1883,11 +2448,6 @@ def create_object(self, version, factors, **kwds): except (TypeError, ValueError): pass - raise ValueError("'%s' is not a valid string describing " - "a growth group." % (factor,)) - # todo: once exponential growth groups are implemented, - # move line above to the bottom of this loop - try: # exponential growth group: 'base^var' groups.append( @@ -1896,6 +2456,9 @@ def create_object(self, version, factors, **kwds): except (TypeError, ValueError): pass + raise ValueError("'%s' is not a valid string describing " + "a growth group." % (factor,)) + if len(groups) == 1: return groups[0] From de47e1a2a146a8ebb3f425c91999174a94445afd Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 14 Aug 2015 11:31:27 +0200 Subject: [PATCH 0391/1872] doctest for converting 0 added --- src/sage/groups/asymptotic_growth_group.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index ea6b0f1861c..8443c4f6b73 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -2206,6 +2206,10 @@ def _convert_(self, data): 2^x sage: P((-333)^x) # indirect doctest (-333)^x + sage: P(0) # indirect doctest + Traceback (most recent call last): + ... + ValueError: Cannot convert 0. :: From f4d16c2b2ae490d1baad5b39e6a26d2e83719de6 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 14 Aug 2015 11:50:13 +0200 Subject: [PATCH 0392/1872] gens_monomial for cartesian products implemented --- src/sage/groups/asymptotic_growth_group.py | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 3e5d42faa39..df6e6d79e1a 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -335,6 +335,37 @@ def _repr_short_(self): return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) + def gens_monomial(self): + r""" + Return a tuple containing generators of this growth group. + + INPUT: + + Nothing. + + OUTPUT: + + A tuple containing elements of this growth group. + + .. NOTE: + + This method calls the ``gens_monomial()`` method on the + individual factors of this cartesian product and + concatenates the respective outputs. + + EXAMPLES:: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ') + sage: G.gens_monomial() + (x, y) + """ + t = () + for factor in self.cartesian_factors(): + t = t + factor.gens_monomial() + return t + + class Element(CartesianProductPosets.Element): def _repr_(self): r""" From ea92f36e3a0b2f41cec39ab8e117685a384c762a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 14 Aug 2015 11:52:40 +0200 Subject: [PATCH 0393/1872] doctest added --- src/sage/groups/asymptotic_growth_group.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 5acba7808b3..c4bd82b5537 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -366,6 +366,9 @@ def gens_monomial(self): sage: G = agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ') sage: G.gens_monomial() (x, y) + sage: G = agg.GrowthGroup('QQ^x * x^ZZ * log(y)^ZZ * QQ^z') + sage: G.gens_monomial() + (x,) """ t = () for factor in self.cartesian_factors(): From eac64d9eb4f8b207000c18eca419c5d2d79b72a0 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 14 Aug 2015 12:35:28 +0200 Subject: [PATCH 0394/1872] added more doctests (exp. growth group in cartesian products), improved module description --- src/sage/groups/asymptotic_growth_group.py | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index c4bd82b5537..9336035e0a0 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -67,8 +67,11 @@ This also enables us to construct *logarithmic growth groups*, e.g. ``log(x)^ZZ``. - This notation will also be extended to *Exponential growth - groups*. + Exponential growth groups, i.e. growth groups representing + elements of the form `\operatorname{base}^\operatorname{variable}` + are denoted as ``base^variable``. For example, ``QQ^x`` denotes + the multiplicative group of exponential expressions `q^x`, where + `q \in \mathbb{Q}^{\times}`. EXAMPLES:: @@ -96,6 +99,17 @@ sage: agg.GrowthGroup('x^ZZ * y^ZZ') is agg.GrowthGroup('y^ZZ * x^ZZ') False + +With the help of the short notation, even complicated growth groups +can be constructed easily:: + + sage: G = agg.GrowthGroup('QQ^x * x^ZZ * log(x)^QQ * y^QQ') + sage: G.an_element() + (1/2)^x * x * log(x)^(1/2) * y^(1/2) + sage: (x, y) = var('x y') + sage: G(2^x * log(x) * y^(1/2)) * G(x^(-5) * 5^x * y^(1/3)) + 10^x * x^(-5) * log(x) * y^(5/6) + """ #***************************************************************************** @@ -215,6 +229,12 @@ class CartesianProductGrowthGroups(CartesianProductPosets): sage: C.an_element() x^(1/2) * log(x) * y^(1/2) + :: + + sage: G = agg.GrowthGroup('QQ^x * x^ZZ * y^ZZ * log(y)^QQ * QQ^z') + sage: G.an_element() + (1/2)^x * x * y * log(y)^(1/2) * (1/2)^z + .. SEEALSO: :class:`~sage.sets.cartesian_product.CartesianProduct`, @@ -2429,6 +2449,8 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): Growth Group x^ZZ * log(x)^ZZ sage: agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ') Growth Group x^ZZ * log(x)^ZZ * y^QQ + sage: agg.GrowthGroup('QQ^x * x^ZZ * y^QQ * QQ^z') + Growth Group QQ^x * x^ZZ * y^QQ * QQ^z """ def create_key_and_extra_args(self, specification, **kwds): r""" From f33ba27b276cb677830a9650f661a7294c97e2f8 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 14 Aug 2015 12:40:53 +0200 Subject: [PATCH 0395/1872] fixed an issue with conversion of log(var) --- src/sage/groups/asymptotic_growth_group.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index df6e6d79e1a..fcd06a8421c 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -245,6 +245,11 @@ def _element_constructor_(self, data): sage: G = GrowthGroup('x^ZZ * y^ZZ') sage: G('x'), G('y') (x, y) + + :: + + sage: G_log(log(x)) + log(x) """ if data == 1: return self.one() @@ -276,9 +281,11 @@ def _element_constructor_(self, data): elif data.parent() is sage.symbolic.ring.SR: import operator from sage.symbolic.operators import mul_vararg - if data.operator() == operator.pow or data.is_symbol(): + op = data.operator() + if op == operator.pow or data.is_symbol() \ + or isinstance(op, sage.functions.log.Function_log): return self([data]) - elif data.operator() == mul_vararg: + elif op == mul_vararg: return self(data.operands()) # room for other parents (e.g. polynomial ring et al.) From 83524299767ee9e123fe4dbed2f63945b154e8f7 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 14 Aug 2015 15:41:09 +0200 Subject: [PATCH 0396/1872] element constructor of cartesian products simplified; helper method implemented --- src/sage/groups/asymptotic_growth_group.py | 72 ++++++++++++++++------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 1c400a69b87..ef9944a1abe 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -254,45 +254,43 @@ def _element_constructor_(self, data): if data == 1: return self.one() + if data is None: + raise ValueError('%s cannot be converted.' % (data,)) + if isinstance(data, list): try: obj = super(CartesianProductGrowthGroups, self)._element_constructor_(data) return obj except ValueError: - factors = self.cartesian_factors() - one = self.one().value - for k in range(len(data)): - for l in range(len(factors)): - try: - conv_data = factors[l](data[k]) - data[k] = self([one[j] if j != l else conv_data - for j in range(len(one))]) - break - except (ValueError, TypeError): - continue - return self.prod(data) - + return self.prod(self(elem) for elem in data) if hasattr(data, 'parent'): - if data.parent() is self: + P = data.parent() + if P is self: return data - elif data.parent() is sage.symbolic.ring.SR: + elif P is sage.symbolic.ring.SR: import operator from sage.symbolic.operators import mul_vararg op = data.operator() if op == operator.pow or data.is_symbol() \ or isinstance(op, sage.functions.log.Function_log): - return self([data]) + return self(self._convert_to_factor_(data)) elif op == mul_vararg: return self(data.operands()) # room for other parents (e.g. polynomial ring et al.) - # final attempt: try to parse the representation string - else: - str_lst = str(data).replace(' ', '').split('*') - return self(str_lst) + # try to convert the input to one of the factors + data_conv = self._convert_to_factor_(data) + if data_conv is not None: + factors = self.cartesian_factors() + return self([data_conv if factor == data_conv.parent() else 1 for + factor in factors]) + + # final attempt: try parsing the representation string + str_lst = str(data).replace(' ', '').split('*') + return self(str_lst) def _repr_(self): @@ -342,6 +340,40 @@ def _repr_short_(self): return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) + def _convert_to_factor_(self, data): + r""" + Helper method. Try to convert some input ``data`` to an + element of one of the cartesian factors of this product. + + INPUT: + + - ``data`` -- some input to be converted. + + OUTPUT: + + An element of an cartesian factor of this product, + or ``None``. + + EXAMPLES:: + + sage: from sage.groups.asymptotic_growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * log(x)^QQ * y^QQ') + sage: e1 = G._convert_to_factor_(x^2) + sage: (e1, e1.parent()) + (x^2, Growth Group x^ZZ * log(x)^QQ) + sage: G._convert_to_factor_('asdf') is None + True + """ + for factor in self.cartesian_factors(): + try: + if hasattr(factor, '_convert_to_factor_'): + return factor(factor._convert_to_factor_(data)) + return factor(data) + except (ValueError, TypeError): + continue + + + def gens_monomial(self): r""" Return a tuple containing generators of this growth group. From 3664687523bd62a0d9f35e317407dc1186f02092 Mon Sep 17 00:00:00 2001 From: Aaron Lauve Date: Fri, 14 Aug 2015 15:38:53 -0500 Subject: [PATCH 0397/1872] 1. Made the changes suggested by jhpalmieri: Two quick comments: first, on line 119 of bialgebras_with_basis.py, there should be a double colon at the end of the line: identity map on group algebra of the symmetric group:: Second, the new docstrings should start with r""", not just """, at least if they contain any backslashes as parts of TeX commands. 2. Added some `import` calls (the absence of which was causing some methods to fail). --- src/sage/categories/bialgebras_with_basis.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index 74b447cedc5..552e1cf0113 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -10,9 +10,11 @@ #****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.modules_with_basis import ModulesWithBasis +from sage.categories.tensor import tensor class BialgebrasWithBasis(CategoryWithAxiom_over_base_ring): - """ + r""" The category of bialgebras with a distinguished basis. EXAMPLES:: @@ -32,7 +34,7 @@ class BialgebrasWithBasis(CategoryWithAxiom_over_base_ring): class ParentMethods: def convolution_product(self, *maps): - """ + r""" Return the convolution product (a map) of the given maps. INPUT: @@ -116,7 +118,7 @@ def convolution_product(self, *maps): 3*m{{1}, {2}, {3}} + 3*m{{1}, {2, 3}} + 3*m{{1, 3}, {2}}] Compute the convolution product of the antipode with itself and the - identity map on group algebra of the symmetric group: + identity map on group algebra of the symmetric group:: sage: G = SymmetricGroup(3) sage: QG = GroupAlgebra(G, QQ) @@ -137,7 +139,7 @@ def convolution_product(self, *maps): class ElementMethods: def adams_operator(self, n): - """ + r""" Compute the `n`-th convolution power of the identity morphism `Id` on ``self``. @@ -206,7 +208,7 @@ def adams_operator(self, n): return self.convolution_product([T] * n) def convolution_product(self, *maps): - """ + r""" Return the image of ``self`` under the convolution product (map) of the maps. @@ -445,6 +447,9 @@ def coproduct_iterated(self, n=1): elif n==1: return self.coproduct() else: + from sage.functions.all import floor, ceil + from sage.rings.all import Integer + # Use coassociativity of `\Delta` to perform many coproducts simultaneously. fn = floor(Integer(n-1)/2); cn = ceil(Integer(n-1)/2) def split(a,b): return tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) From 3a548d9882d963d9740d57d7095ad3ac4df24e03 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 16 Aug 2015 20:31:42 +0200 Subject: [PATCH 0398/1872] trac #19042: Default SAT solver in Sage --- src/doc/en/reference/sat/index.rst | 38 ++++---- src/module_list.py | 3 + src/sage/all.py | 1 + src/sage/sat/all.py | 1 + src/sage/sat/solvers/sat_lp.pyx | 150 +++++++++++++++++++++++++++++ src/sage/sat/solvers/satsolver.pyx | 54 ++++++++++- 6 files changed, 225 insertions(+), 22 deletions(-) create mode 100644 src/sage/sat/all.py create mode 100644 src/sage/sat/solvers/sat_lp.pyx diff --git a/src/doc/en/reference/sat/index.rst b/src/doc/en/reference/sat/index.rst index 37adb48dd03..adfbddcc179 100644 --- a/src/doc/en/reference/sat/index.rst +++ b/src/doc/en/reference/sat/index.rst @@ -18,34 +18,37 @@ should be true, we write:: Solvers ------- -Any SAT solver supporting the DIMACS input format is easily interfaced using the -:class:`sage.sat.solvers.dimacs.DIMACS` blueprint. Sage ships with pre-written interfaces for *RSat* -[RS]_ and *Glucose* [GL]_. Furthermore, Sage provides a C++ interface to the *CryptoMiniSat* [CMS]_ SAT -solver which can be used interchangably with DIMACS-based solvers, but also provides advanced -features. For this, the optional CryptoMiniSat package must be installed, this can be accomplished -by typing:: +By default, Sage solves SAT instances as an Integer Linear Program (see +:mod:`sage.numerical.mip`), but any SAT solver supporting the DIMACS input +format is easily interfaced using the :class:`sage.sat.solvers.dimacs.DIMACS` +blueprint. Sage ships with pre-written interfaces for *RSat* [RS]_ and *Glucose* +[GL]_. Furthermore, Sage provides a C++ interface to the *CryptoMiniSat* [CMS]_ +SAT solver which can be used interchangably with DIMACS-based solvers, but also +provides advanced features. For this last solver, the optional CryptoMiniSat +package must be installed, this can be accomplished by typing:: sage: install_package('cryptominisat') # not tested and by running ``sage -b`` from the shell afterwards to build Sage's CryptoMiniSat extension module. -Since by default Sage does not include any SAT solver, we demonstrate key features by instantiating -a fake DIMACS-based solver. We start with a trivial example:: +We now show how to solve a simple SAT problem. :: (x1 OR x2 OR x3) AND (x1 OR x2 OR (NOT x3)) In Sage's notation:: - sage: from sage.sat.solvers.dimacs import DIMACS - sage: solver = DIMACS(command="sat-solver") + sage: solver = SAT() # random sage: solver.add_clause( ( 1, 2, 3) ) sage: solver.add_clause( ( 1, 2, -3) ) + sage: solver() # random + (None, True, True, False) .. NOTE:: - :meth:`sage.sat.solvers.dimacs.DIMACS.add_clause` creates new variables when necessary. In - particular, it creates *all* variables up to the given index. Hence, adding a literal involving - the variable 1000 creates up to 1000 internal variables. + :meth:`~sage.sat.solvers.dimacs.DIMACS.add_clause` creates new variables + when necessary. When using CryptoMiniSat, it creates *all* variables up to + the given index. Hence, adding a literal involving the variable 1000 creates + up to 1000 internal variables. DIMACS-base solvers can also be used to write DIMACS files:: @@ -77,14 +80,6 @@ Alternatively, there is :meth:`sage.sat.solvers.dimacs.DIMACS.clauses`:: These files can then be passed external SAT solvers. -We demonstrate solving using CryptoMiniSat:: - - sage: from sage.sat.solvers import CryptoMiniSat # optional - cryptominisat - sage: cms = CryptoMiniSat() # optional - cryptominisat - sage: cms.add_clause((1,2,-3)) # optional - cryptominisat - sage: cms() # optional - cryptominisat - (None, True, True, False) - Details on Specific Solvers ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,6 +88,7 @@ Details on Specific Solvers sage/sat/solvers/satsolver sage/sat/solvers/dimacs + sage/sat/solvers/sat_lp .. optional - cryptominisat .. sage/sat/solvers/cryptominisat/cryptominisat .. sage/sat/solvers/cryptominisat/solverconf diff --git a/src/module_list.py b/src/module_list.py index 8958bbf3919..87a6e4bf196 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1622,6 +1622,9 @@ def uname_specific(name, value, alternative): Extension('sage.sat.solvers.satsolver', sources = ['sage/sat/solvers/satsolver.pyx']), + Extension('sage.sat.solvers.sat_lp', + sources = ['sage/sat/solvers/sat_lp.pyx']), + ################################ ## ## sage.schemes diff --git a/src/sage/all.py b/src/sage/all.py index 2158832213a..9cd34294b20 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -106,6 +106,7 @@ from sage.monoids.all import * from sage.algebras.all import * from sage.modular.all import * +from sage.sat.all import * from sage.schemes.all import * from sage.graphs.all import * from sage.groups.all import * diff --git a/src/sage/sat/all.py b/src/sage/sat/all.py new file mode 100644 index 00000000000..63993752958 --- /dev/null +++ b/src/sage/sat/all.py @@ -0,0 +1 @@ +from solvers.satsolver import SAT diff --git a/src/sage/sat/solvers/sat_lp.pyx b/src/sage/sat/solvers/sat_lp.pyx new file mode 100644 index 00000000000..024ddad5a2e --- /dev/null +++ b/src/sage/sat/solvers/sat_lp.pyx @@ -0,0 +1,150 @@ +r""" +Solve SAT problems Integer Linear Programming + +The class defined here is a :class:`~sage.sat.solvers.satsolver.SatSolver` that +solves its instance using :class:`MixedIntegerLinearProgram`. Its performances +can be expected to be slower than when using +:class:`~sage.sat.solvers.cryptominisat.cryptominisat.CryptoMiniSat`. +""" +from satsolver cimport SatSolver +from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + +class SatLP(SatSolver): + def __init__(self, solver=None): + r""" + Initializes the instance + + INPUT: + + - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) + solver to be used. If set to ``None``, the default one is used. For + more information on LP solvers and which default solver is used, see + the method + :meth:`solve ` + of the class + :class:`MixedIntegerLinearProgram `. + + EXAMPLE:: + + sage: S=SAT(solver="LP"); S + an ILP-based SAT Solver + """ + SatSolver.__init__(self) + self._LP = MixedIntegerLinearProgram() + self._vars = self._LP.new_variable(binary=True) + + def var(self): + """ + Return a *new* variable. + + EXAMPLE:: + + sage: S=SAT(solver="LP"); S + an ILP-based SAT Solver + sage: S.var() + 1 + """ + nvars = n = self._LP.number_of_variables() + while nvars==self._LP.number_of_variables(): + n += 1 + self._vars[n] # creates the variable if needed + return n + + def nvars(self): + """ + Return the number of variables. + + EXAMPLE:: + + sage: S=SAT(solver="LP"); S + an ILP-based SAT Solver + sage: S.var() + 1 + sage: S.var() + 2 + sage: S.nvars() + 2 + """ + return self._LP.number_of_variables() + + def add_clause(self, lits): + """ + Add a new clause to set of clauses. + + INPUT: + + - ``lits`` - a tuple of integers != 0 + + .. note:: + + If any element ``e`` in ``lits`` has ``abs(e)`` greater + than the number of variables generated so far, then new + variables are created automatically. + + EXAMPLE:: + + sage: S=SAT(solver="LP"); S + an ILP-based SAT Solver + sage: for u,v in graphs.CycleGraph(6).edges(labels=False): + ....: u,v = u+1,v+1 + ....: S.add_clause((u,v)) + ....: S.add_clause((-u,-v)) + """ + if 0 in lits: + raise ValueError("0 should not appear in the clause: {}".format(lits)) + p = self._LP + p.add_constraint(p.sum(self._vars[x] if x>0 else 1-self._vars[-x] for x in lits) + >=1) + + def __call__(self): + """ + Solve this instance. + + OUTPUT: + + - If this instance is SAT: A tuple of length ``nvars()+1`` + where the ``i``-th entry holds an assignment for the + ``i``-th variables (the ``0``-th entry is always ``None``). + + - If this instance is UNSAT: ``False`` + + - If the solver was interrupted before deciding satisfiability + ``None``. + + EXAMPLE:: + + sage: def is_bipartite_SAT(G): + ....: S=SAT(solver="LP"); S + ....: for u,v in G.edges(labels=False): + ....: u,v = u+1,v+1 + ....: S.add_clause((u,v)) + ....: S.add_clause((-u,-v)) + ....: return S + sage: S = is_bipartite_SAT(graphs.CycleGraph(6)) + sage: S() # random + [None, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0] + sage: True in S() + True + sage: S = is_bipartite_SAT(graphs.CycleGraph(7)) + sage: S() + False + """ + try: + self._LP.solve() + except MIPSolverException: + return False + except KeyboardInterrupt: + return None + + b = self._LP.get_values(self._vars) + n = max(b) + return [None]+[b.get(i,False) for i in range(1,n+1)] + + def __repr__(self): + """ + TESTS:: + + sage: S=SAT(solver="LP"); S + an ILP-based SAT Solver + """ + return "an ILP-based SAT Solver" diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index 102ce003d78..621e742b541 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -33,7 +33,7 @@ cdef class SatSolver: INPUT: - - ``decision`` - is this variable a deicison variable? + - ``decision`` - is this variable a decision variable? EXAMPLE:: @@ -226,3 +226,55 @@ cdef class SatSolver: """ return ["gens"] +def SAT(solver=None): + r""" + Return a :class:`SatSolver` instance. + + Through this class, one can define and solve `SAT + `__ problems. + + INPUT: + + - ``solver`` (string) -- select a solver. Admissible values are: + + - ``"cryptominisat"`` -- note that the cryptominisat package must be + installed. + + - ``"LP"`` -- use :class:`~sage.sat.solvers.sat_lp.SatLP` to solve the + SAT instance. + + - ``None`` (default) -- use CryptoMiniSat if available, and a LP solver + otherwise. + + EXAMPLE:: + + sage: SAT(solver="LP") + an ILP-based SAT Solver + + TESTS:: + + sage: SAT(solver="Wouhouuuuuu") + Traceback (most recent call last): + ... + ValueError: Solver 'Wouhouuuuuu' is not available + + Forcing CryptoMiniSat:: + + sage: SAT(solver="cryptominisat") # optional - cryptominisat + CryptoMiniSat + #vars: 0, #lits: 0, #clauses: 0, #learnt: 0, #assigns: 0 + + """ + from sage.misc.package import is_package_installed + if (solver == 'cryptominisat' or + (solver is None and is_package_installed('cryptominisat'))): + try: + from sage.sat.solvers.cryptominisat.cryptominisat import CryptoMiniSat + except ImportError: + raise ImportError("To enable this feature, run 'sage -i cryptominisat'.") + return CryptoMiniSat() + elif (solver == "LP" or solver is None): + from sat_lp import SatLP + return SatLP() + else: + raise ValueError("Solver '{}' is not available".format(solver)) From d4d3a091c747cf5ed31f02eb10d6f3298445aecd Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Sun, 16 Aug 2015 18:34:03 -0500 Subject: [PATCH 0399/1872] accidentally deleted crucial statement for coercion. I have reinserted it. --- src/sage/combinat/diagram_algebras.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index e8bc530ef13..330d51578d6 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1213,6 +1213,7 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): self._k = k self._base_diagrams = diagrams category = Algebras(base_ring).FiniteDimensional().WithBasis().or_subcategory(category) + KSS = SymmetricGroupAlgebra(base_ring, k) CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) From 186ecfc13db772e1b89ee09b10b7e220b6e9e307 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 17 Aug 2015 13:37:50 +0200 Subject: [PATCH 0400/1872] simplified doctests: removed some unneccessary imports --- src/sage/rings/asymptotic_ring.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index cec35db18f2..5d283493bab 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -496,10 +496,7 @@ def O(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.GrowthGroup('x^ZZ') - sage: AR = AsymptoticRing(MG, ZZ) - sage: x = AR.create_summand('exact', growth=x) + sage: AR. = AsymptoticRing('x^ZZ', ZZ) sage: O(x) O(x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr @@ -656,9 +653,7 @@ def __init__(self, growth_group, coefficient_ring, category=None): TESTS:: - sage: import sage.groups.asymptotic_growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ') - sage: R1 = AsymptoticRing(G, ZZ); R1 + sage: R1 = AsymptoticRing('x^ZZ', ZZ); R1 Asymptotic Ring over Integer Ring sage: R2. = AsymptoticRing('x^QQ', QQ); R2 Asymptotic Ring over Rational Field @@ -667,7 +662,7 @@ def __init__(self, growth_group, coefficient_ring, category=None): :: - sage: R3 = AsymptoticRing(G) + sage: R3 = AsymptoticRing('x^ZZ') Traceback (most recent call last): ... TypeError: __classcall__() takes at least 3 arguments (2 given) @@ -703,9 +698,7 @@ def growth_group(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.GrowthGroup('x^ZZ') - sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) + sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR.growth_group Growth Group x^ZZ """ @@ -719,9 +712,7 @@ def coefficient_ring(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg - sage: MG = agg.GrowthGroup('x^ZZ') - sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) + sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR.coefficient_ring Integer Ring """ @@ -1015,9 +1006,7 @@ def create_summand(self, type, growth, **kwds): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ') - sage: R = AsymptoticRing(G, ZZ) + sage: R = AsymptoticRing('x^ZZ', ZZ) sage: R.create_summand('O', growth=x^2) O(x^2) sage: R.create_summand('exact', growth=x^456, coefficient=123) From 8263e3946d2b5b2e3068aa6e4ed0501b2fac1d6e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 16:20:24 +0200 Subject: [PATCH 0401/1872] include asymptotic ring in reference manual --- src/doc/en/reference/rings/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/reference/rings/index.rst b/src/doc/en/reference/rings/index.rst index 04a82ad65ab..087b475e0d6 100644 --- a/src/doc/en/reference/rings/index.rst +++ b/src/doc/en/reference/rings/index.rst @@ -26,7 +26,7 @@ General Rings, Ideals, and Morphisms sage/rings/fast_arith sage/rings/misc sage/rings/monomials - + sage/rings/asymptotic_ring sage/rings/commutative_algebra sage/rings/commutative_algebra_element From c7560253ed332374e9322a6687404f9dc4b1ae10 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 16:20:46 +0200 Subject: [PATCH 0402/1872] correct broken link --- src/sage/rings/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index cec35db18f2..ac5a8a2b1e4 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -1009,8 +1009,8 @@ def create_summand(self, type, growth, **kwds): .. NOTE:: - This method calls the factory - :class:`~sage.monoids.asymptotic_term_monoid.TermMonoid` + This method calls the factory :class:`TermMonoid + ` with the appropriate arguments. EXAMPLES:: From 22fcbc4db1d5841a7a3fb253e7730c78cb500c2d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 16:21:18 +0200 Subject: [PATCH 0403/1872] rewrite docstring of AsymptoticRing --- src/sage/rings/asymptotic_ring.py | 68 ++++++++++++++++--------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index ac5a8a2b1e4..64b5fd36d41 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -524,13 +524,14 @@ def O(self): class AsymptoticRing(sage.rings.ring.Ring, sage.structure.unique_representation.UniqueRepresentation): r""" - Parent for asymptotic expressions. + A ring consisting of :class:`asymptotic expressions `. INPUT: - - ``growth_group`` -- a partially ordered group (e.g. an instance - of :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`), - or a string describing such a growth group. + - ``growth_group`` -- either a partially ordered group (see + :mod:`~sage.groups.asymptotic_growth_group`) or a string + describing such a growth group (see + :class:`~sage.groups.asymptotic_growth_group.GrowthGroupFactory`). - ``coefficient_ring`` -- the ring which contains the coefficients of the expressions. @@ -542,49 +543,43 @@ class AsymptoticRing(sage.rings.ring.Ring, EXAMPLES: - We begin with the explicit construction of an asymptotic ring, - i.e. by explicitly specifying the underlying growth group:: + We begin with the construction of an asymptotic ring in various + ways. First, we simply pass a string specifying the underlying + growth group:: + + sage: R1_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R1_x + Asymptotic Ring over Rational Field + sage: x + x + + This is equivalent to the following code, which explicitly + specifies the underlying growth group:: sage: import sage.groups.asymptotic_growth_group as agg sage: G_QQ = agg.GrowthGroup('x^QQ') - sage: R_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=QQ); R_x + sage: R2_x. = AsymptoticRing(growth_group=G_QQ, coefficient_ring=QQ); R2_x Asymptotic Ring over Rational Field - Note that the coefficient ring of the asymptotic ring and the + Of course, the coefficient ring of the asymptotic ring and the base ring of the underlying growth group do not need to coincide:: - sage: R_ZZ_x = AsymptoticRing(growth_group=G_QQ, coefficient_ring=ZZ); R_ZZ_x + sage: R_ZZ_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=ZZ); R_ZZ_x Asymptotic Ring over Integer Ring - As mentioned above, the short notation for growth groups can also - be used to specify the underlying growth group. For now, - representation strings of the form ``"variable^base"`` are - allowed, where ``variable`` is some string, and ``base`` is - either ``ZZ`` (for `\mathbb{Z}`), ``QQ`` (for `\mathbb{Q}`), - or ``SR`` (for the symbolic ring). These strings correspond to - monomial growth groups (see - :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`):: - - sage: R2_x = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R2_x - Asymptotic Ring over Rational Field - - Alternatively, the preparser allows us to write:: - - sage: R3_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R3_x - Asymptotic Ring over Rational Field - - Note that this allows us to create logarithmic and polynomial - growth groups:: + Note, we can also create and use logarithmic growth groups:: - sage: R. = AsymptoticRing('x^ZZ', QQ); R - Asymptotic Ring over Rational Field sage: R_log = AsymptoticRing('log(x)^ZZ', QQ); R_log Asymptotic Ring over Rational Field + Other growth groups are available. See :mod:`~sage.rings.asymptotic_ring` for + a lot more examples. + + Below there are some technical details. + According to the conventions for parents, uniqueness is ensured:: - sage: R_x is R2_x is R3_x + sage: R1_x is R2_x True Furthermore, the coercion framework is also involved. Coercion @@ -592,14 +587,21 @@ class AsymptoticRing(sage.rings.ring.Ring, underlying growth groups and coefficient rings are chosen appropriately):: - sage: R_x.has_coerce_map_from(R_ZZ_x) + sage: R1_x.has_coerce_map_from(R_ZZ_x) True Additionally, for the sake of convenience, the coefficient ring also coerces into the asymptotic ring (representing constant quantities):: - sage: R_x.has_coerce_map_from(QQ) + sage: R1_x.has_coerce_map_from(QQ) + True + + TESTS:: + + sage: R3_x = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R3_x + Asymptotic Ring over Rational Field + sage: R1_x is R2_x is R3_x True """ # enable the category framework for elements From acfb983326807c5e1b3723e093820a59d69a7289 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 16:21:38 +0200 Subject: [PATCH 0404/1872] rewrite docstring of AsymptoticExpression --- src/sage/rings/asymptotic_ring.py | 32 +++++++++++-------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 64b5fd36d41..4f46023ccae 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -71,35 +71,25 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): EXAMPLES: - There are several ways to create an asymptotic expression. First, - we construct the corresponding rings/parents:: + There are several ways to create asymptotic expressions; usually this is done by using the corresponding rings/parents:: - sage: R_x. = AsymptoticRing('x^QQ', QQ) - sage: import sage.groups.asymptotic_growth_group as agg - sage: G = agg.GrowthGroup('y^ZZ') - sage: R_y = AsymptoticRing(G, ZZ); y = R_y.gen() + sage: R_x. = AsymptoticRing('x^QQ', QQ); R_x + Asymptotic Ring over Rational Field + sage: R_y. = AsymptoticRing('y^ZZ', ZZ); R_y + Asymptotic Ring over Integer Ring At this point, `x` and `y` are already asymptotic expressions:: - sage: (x, y) - (x, y) - sage: isinstance(x, sage.rings.asymptotic_ring.AsymptoticExpression) - True sage: type(x) - The usual ring operations can be performed:: - - sage: x^2 + 3*(x - x^2) - -2*x^2 + 3*x - sage: (3*x + 2)^3 - 27*x^3 + 54*x^2 + 36*x + 8 - - In addition to that, special powers (determined by the base ring - of the growth group) can also be computed:: + The usual ring operations, but allowing rational exponents (growth + group ``x^QQ``) can be performed:: - sage: (x^(5/2) + x^(1/7)) * x^(-1/5) - x^(23/10) + x^(-2/35) + sage: x^2 + 3*(x - x^(2/5)) + x^2 + 3*x - 3*x^(2/5) + sage: (3*x^(1/3) + 2)^3 + 27*x + 54*x^(2/3) + 36*x^(1/3) + 8 One of the central ideas behind computing with asymptotic expressions is that the `O`-notation (see From fc61df6aaf6950aee2fad9d1f1cc679a280199e1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 16:22:02 +0200 Subject: [PATCH 0405/1872] write module description and introductory examples --- src/sage/rings/asymptotic_ring.py | 154 ++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 4f46023ccae..c8d791a75d0 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -1,21 +1,54 @@ r""" Asymptotic Ring -This module implements the central classes for computing with -asymptotic expressions. It provides the following two classes: +This module implements a ring (called :class:`AsymptoticRing`) for +computations with :class:`asymptotic expressions +`. -- :class:`AsymptoticExpression` -- this class essentially represents - a sum of asymptotic terms (see - :mod:`Asymptotic Terms <~sage.monoids.asymptotic_term_monoid>`). +Definition +========== -- :class:`AsymptoticRing` -- parent structure for - :class:`AsymptoticExpression`. +An asymptotic expression is a sum; its summands are the following: -AUTHORS: +- Exact terms `c\cdot g` with a coefficent `c` and an element `g` of + an :ref:`growth group `. -- Benjamin Hackl (2015-06): initial version -- Benjamin Hackl (2015-07): improvement user interface (short notation) +- `O`-terms `O(g)` (see :wikipedia:`Big_O_notation`) for some + :mod:`growth group element ` + `g` (:ref:`see below `). + +Examples of such elements can found :ref:`below `. + +.. _asymptotic_ring_growth: + +Growth Elements +--------------- + +The elements of a :mod:`growth group +` are equipped with a partial +ordering and usually contains a variable. Examples are (among many +other possibilities) +- elements of the form `z^q` for some integer or rational `q` (growth + groups ``z^ZZ`` or ``z^QQ``), + +- elements of the form `log(z)^q` for some integer or rational `q` (growth + groups ``log(z)^ZZ`` or ``log(z)^QQ``), + +- elements of the form `a^z` for some + rational `a` (growth group ``QQ^z``), or + +- more sophisticated constructions like products `x^r log(x)^s \cdot + a^y \cdot y^q` (this corresponds to an element of the growth group + ``x^QQ * \log(x)^ZZ * QQ^y * y^QQ``). + +The ordering in all these examples is the growth as `x`, `y`, or `z` +(independently) tend to `\infty`. For elements only using the +variable `z` this means, `g_1 \leq g_2` if + +.. MATH:: + + \lim_{z\to\infty} \frac{g_2}{g_1} \leq 1. .. WARNING:: @@ -39,6 +72,107 @@ without a formal deprecation. See http://trac.sagemath.org/17601 for details. sage: R. = AsymptoticRing('x^ZZ', ZZ) + +.. _asymptotic_ring_intro: + +Introductory Examples +===================== + +First, we construct the following (very simple) asymptotic ring in the variable `z`:: + + sage: A. = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ); A + Asymptotic Ring over Integer Ring + +A typical element of this ring is + +:: + + sage: A.an_element() # not tested + -z^(3/2) + O(z^(1/2)) + +This element consists of two summands: the exact term with coefficient +`-1` and growth `x^{3/2}` and the `O`-term `O(x^{1/2})`. Note that the +growth of `x^{3/2}` is larger than the growth of `x^{1/2}` as +`x\to\infty`, thus this expression cannot be simplified (which would +be done automatically, see below). + +Next, we construct a more sophisticated asymptotic ring in the +variables `x` and `y` by + +:: + + sage: B. = AsymptoticRing(growth_group='x^QQ * \log(x)^ZZ * QQ^y * y^QQ', coefficient_ring=QQ); B # not tested + +Again, we can look at a typical element:: + + sage: B.an_element() # not tested + +Arithemtical Operations +----------------------- + +With the asymptotic rings constructed above (or more precisely with +their elements) we can do a lot of different arithmetical +calculations. + +We start our calculations in the ring + +:: + + sage: A + Asymptotic Ring over Integer Ring + +Of course, we can perform the usual ring operations `+` and `*`:: + + sage: z^2 + 3*z*(1 - z) + -2*z^2 + 3*z + sage: (3*z + 2)^3 + 27*z^3 + 54*z^2 + 36*z + 8 + +In addition to that, special powers---our growth group ``z^QQ`` allows +the exponents to be out of `QQ`---can also be computed:: + + sage: (z^(5/2) + z^(1/7)) * z^(-1/5) + z^(23/10) + z^(-2/35) + +The central concepts of computations with asymptotic expressions is +that the `O`-notation can be used. For example, we have + +:: + + sage: z^3 + z^2 + z + O(z^2) + z^3 + O(z^2) + +and more advanced + +:: + + sage: (z + 2*z^2 + 3*z^3 + 4*z^4) * (O(z) + z^2) + 4*z^6 + O(z^5) + +.. TODO:: + + inversions + +.. TODO:: + + arithmetic in the ring + + :: + + sage: B # not tested + +More Examples +============= + +.. TODO:: + + write more examples + +AUTHORS: + +- Benjamin Hackl (2015-06): initial version +- Benjamin Hackl (2015-07): improvement user interface (short notation) +- Daniel Krenn (2015-08): various improvents, review; documentation """ # ***************************************************************************** From 0a13882d1463e1836c3e641a70069a84e8af8af0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 19:21:24 +0200 Subject: [PATCH 0406/1872] improve doctests of _an_element_ --- src/sage/groups/asymptotic_growth_group.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 3b00e015f7d..da021a0c128 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -674,9 +674,12 @@ def _an_element_(self): EXAMPLES:: sage: import sage.groups.asymptotic_growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ); - sage: G.an_element() # indirect doctest + sage: agg.GenericGrowthGroup(ZZ).an_element() # indirect doctest GenericGrowthElement(1) + sage: agg.MonomialGrowthGroup(ZZ, 'z').an_element() # indirect doctest + z + sage: agg.MonomialGrowthGroup(QQ, 'log(z)').an_element() # indirect doctest + log(z)^(1/2) """ return self.element_class(self, self.base().an_element()) From 0f7412aeecc6477b3f080d935f52362fd0e333cf Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 19:21:32 +0200 Subject: [PATCH 0407/1872] some_elements for growth groups --- src/sage/groups/asymptotic_growth_group.py | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index da021a0c128..a1783099656 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -684,6 +684,40 @@ def _an_element_(self): return self.element_class(self, self.base().an_element()) + def some_elements(self, stop=100): + r""" + Return some elements of this growth group. + + See :class:`TestSuite` for a typical use case. + + INPUT: + + - ``stop`` -- (default: ``100``) an integer or ``None``. This + is passed on to :meth:`itertools.islice` and limits the + number of elements. + + OUTPUT: + + An iterator. + + EXAMPLES: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: tuple(agg.MonomialGrowthGroup(ZZ, 'z').some_elements()) + (1, z, 1/z, z^2, z^(-2), z^3, z^(-3), + z^4, z^(-4), z^5, z^(-5), ...) + sage: tuple(agg.MonomialGrowthGroup(QQ, 'z').some_elements()) + (z^(1/2), z^(-1/2), z^2, z^(-2), + 1, z, 1/z, z^42, + z^(2/3), z^(-2/3), z^(3/2), z^(-3/2), + z^(4/5), z^(-4/5), z^(5/4), z^(-5/4), ...) + """ + from itertools import islice + return islice(iter(self.element_class(self, e) + for e in self.base().some_elements()), + stop) + + def le(self, left, right): r""" Return if the growth of ``left`` is at most (less than or From 57d172037a2d0c8096a7d15a86b2d727d9214a42 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 19:22:04 +0200 Subject: [PATCH 0408/1872] product_diagonal iterator --- src/sage/monoids/asymptotic_term_monoid.py | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sage/monoids/asymptotic_term_monoid.py b/src/sage/monoids/asymptotic_term_monoid.py index 152275af21f..a870a649e63 100644 --- a/src/sage/monoids/asymptotic_term_monoid.py +++ b/src/sage/monoids/asymptotic_term_monoid.py @@ -80,6 +80,38 @@ import sage +def product_diagonal(A, B): + r""" + Return an iterator over the product of `A` and `B` which iterates + along the diagonal. + + INPUT: + + - ``A`` and ``B`` -- iterables (over a finite number of elements) + + OUTPUT: + + An iterator over `(a,b)` for `a \in A` and `b \in B`. + + EXAMPLES:: + + sage: from sage.monoids.asymptotic_term_monoid import product_diagonal + sage: tuple(product_diagonal(srange(2), srange(2))) + ((0, 0), (0, 1), (1, 0), (1, 1)) + sage: tuple(product_diagonal(srange(4), srange(2))) + ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) + sage: tuple(product_diagonal(srange(2), srange(3))) + ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) + sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) + ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') + """ + A = tuple(A) + B = tuple(B) + return iter((A[i], B[s-i]) + for s in range(len(A)+len(B)-1) + for i in range(min(len(A), s+1)) if s-i < len(B)) + + def absorption(left, right): r""" Helper method used by From fc20bf8f2a78976c541b02c6aa2a007897bcd65e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 19:22:28 +0200 Subject: [PATCH 0409/1872] improve doctest of term.an_element --- src/sage/monoids/asymptotic_term_monoid.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/monoids/asymptotic_term_monoid.py b/src/sage/monoids/asymptotic_term_monoid.py index a870a649e63..4ad6b1de63e 100644 --- a/src/sage/monoids/asymptotic_term_monoid.py +++ b/src/sage/monoids/asymptotic_term_monoid.py @@ -1672,6 +1672,8 @@ def _an_element_(self): Asymptotic Term with coefficient 1 and growth x sage: atm.ExactTermMonoid(G, ZZ).an_element() # indirect doctest x + sage: atm.ExactTermMonoid(G, QQ).an_element() # indirect doctest + 1/2*x """ return self(self.growth_group.an_element(), self.base_ring.an_element()) From 2ab534bc26e22c53c6247ffc0821bbf1f48522c5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 19:22:43 +0200 Subject: [PATCH 0410/1872] some_elements for terms --- src/sage/monoids/asymptotic_term_monoid.py | 71 ++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/sage/monoids/asymptotic_term_monoid.py b/src/sage/monoids/asymptotic_term_monoid.py index 4ad6b1de63e..2ba050823f5 100644 --- a/src/sage/monoids/asymptotic_term_monoid.py +++ b/src/sage/monoids/asymptotic_term_monoid.py @@ -920,6 +920,35 @@ def _an_element_(self): return self(self.growth_group.an_element()) + def some_elements(self, stop=100): + r""" + Return some elements of this term monoid. + + See :class:`TestSuite` for a typical use case. + + INPUT: + + - ``stop`` -- (default: ``100``) an integer or ``None``. This + is passed on to :meth:`itertools.islice` and limits the + number of elements. + + OUTPUT: + + An iterator. + + EXAMPLES: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.monoids.asymptotic_term_monoid as atm + sage: G = agg.GrowthGroup('x^ZZ') + sage: tuple(atm.OTermMonoid(G).some_elements()) + (O(1), O(x), O(1/x), O(x^2), O(x^(-2)), O(x^3), ...) + """ + from itertools import islice + return islice(iter(self(g) for g in self.growth_group.some_elements()), + stop) + + def le(self, left, right): r""" Return if the term ``left`` is at most (less than or equal @@ -1679,6 +1708,48 @@ def _an_element_(self): self.base_ring.an_element()) + def some_elements(self, stop=100): + r""" + Return some elements of this term with coefficient monoid. + + See :class:`TestSuite` for a typical use case. + + INPUT: + + - ``stop`` -- (default: ``100``) an integer or ``None``. This + is passed on to :meth:`itertools.islice` and limits the + number of elements. + + OUTPUT: + + An iterator. + + EXAMPLES: + + sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.monoids.asymptotic_term_monoid as atm + sage: G = agg.GrowthGroup('z^QQ') + sage: T = atm.ExactTermMonoid(G, ZZ) + sage: tuple(T.some_elements(stop=10)) + (z^(1/2), -z^(1/2), z^(-1/2), 2*z^(1/2), -z^(-1/2), + z^2, -2*z^(1/2), 2*z^(-1/2), -z^2, z^(-2)) + + TESTS:: + + sage: len(tuple(T.some_elements())) + 100 + sage: len(tuple(T.some_elements(stop=None))) + 9900 + sage: len(tuple(T.some_elements(stop=42))) + 42 + """ + from itertools import islice + return islice(iter(self(g, c) for g, c in product_diagonal( + self.growth_group.some_elements(), + iter(c for c in self.base_ring.some_elements() if c != 0))), + stop) + + class ExactTerm(TermWithCoefficient): r""" Class for asymptotic exact terms. These terms primarily consist of From 3e71113f7399c9fc813418a86efd673a3ac83e9e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 19:23:06 +0200 Subject: [PATCH 0411/1872] _an_element_ and some_elements for asymptotic rings --- src/sage/rings/asymptotic_ring.py | 73 ++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index c8d791a75d0..a1976321e67 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -87,7 +87,7 @@ :: - sage: A.an_element() # not tested + sage: A.an_element() -z^(3/2) + O(z^(1/2)) This element consists of two summands: the exact term with coefficient @@ -1040,6 +1040,75 @@ def _repr_(self): return 'Asymptotic Ring %s over %s' % (G, self.coefficient_ring) + def _an_element_(self): + r""" + Return an element of this asymptotic ring. + + INPUT: + + Nothing. + + OUTPUT: + + An :class:`AsymptoticExpression`. + + EXAMPLES:: + + sage: AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ).an_element() + -z^(3/2) + O(z^(1/2)) + sage: AsymptoticRing(growth_group='z^ZZ', coefficient_ring=QQ).an_element() + -1/8*z^3 + O(z) + sage: AsymptoticRing(growth_group='z^QQ', coefficient_ring=QQ).an_element() + -1/8*z^(3/2) + O(z^(1/2)) + """ + from sage.monoids.asymptotic_term_monoid import TermMonoid + E = TermMonoid('exact', self.growth_group, self.coefficient_ring) + O = TermMonoid('O', self.growth_group, self.coefficient_ring) + return -self(E.an_element())**3 + self(O.an_element()) + + + def some_elements(self, stop=100): + r""" + Return some elements of this term monoid. + + See :class:`TestSuite` for a typical use case. + + INPUT: + + - ``stop`` -- (default: ``100``) an integer or ``None``. This + is passed on to :meth:`itertools.islice` and limits the + number of elements. + + OUTPUT: + + An iterator. + + EXAMPLES: + + sage: A = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ) + sage: tuple(A.some_elements(stop=10)) + (-z^(3/2) + O(z^(1/2)), + -z^(3/2) + O(z^(-1/2)), + z^(3/2) + O(z^(1/2)), + O(z^2), + z^(3/2) + O(z^(-1/2)), + O(z^(1/2)), + -z^(3/2) + O(z^(-2)), + O(z^2), + O(z^(-1/2)), + -8*z^(3/2) + O(z^(1/2))) + """ + from itertools import islice + from sage.monoids.asymptotic_term_monoid import product_diagonal + from sage.monoids.asymptotic_term_monoid import TermMonoid + E = TermMonoid('exact', self.growth_group, self.coefficient_ring) + O = TermMonoid('O', self.growth_group, self.coefficient_ring) + return islice(iter(-self(e)**3 + self(o) + for e, o in product_diagonal( + E.some_elements(), O.some_elements())), + stop) + + def gens(self): r""" Return a tuple with generators of this asymptotic ring. @@ -1137,7 +1206,7 @@ def create_summand(self, type, growth, **kwds): This method calls the factory :class:`TermMonoid ` - with the appropriate arguments. + with the appropriate arguments.'exact EXAMPLES:: From 5911564395f1741a514ba5c6a10c91ec252061ff Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 17 Aug 2015 19:50:39 +0200 Subject: [PATCH 0412/1872] typo fixed and line break introduced --- src/sage/rings/asymptotic_ring.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index bfe6cfd62e1..bee0debfd67 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -10,7 +10,7 @@ An asymptotic expression is a sum; its summands are the following: -- Exact terms `c\cdot g` with a coefficent `c` and an element `g` of +- Exact terms `c\cdot g` with a coefficient `c` and an element `g` of an :ref:`growth group `. - `O`-terms `O(g)` (see :wikipedia:`Big_O_notation`) for some @@ -205,7 +205,8 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): EXAMPLES: - There are several ways to create asymptotic expressions; usually this is done by using the corresponding rings/parents:: + There are several ways to create asymptotic expressions; usually + this is done by using the corresponding rings/parents:: sage: R_x. = AsymptoticRing('x^QQ', QQ); R_x Asymptotic Ring over Rational Field From 7aa3e6026848986767a16ead830755e64f1d41f9 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 17 Aug 2015 20:41:24 +0200 Subject: [PATCH 0413/1872] `QQ` --> `\mathbb{Q}` --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index bee0debfd67..1593cbedbf8 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -129,7 +129,7 @@ 27*z^3 + 54*z^2 + 36*z + 8 In addition to that, special powers---our growth group ``z^QQ`` allows -the exponents to be out of `QQ`---can also be computed:: +the exponents to be out of `\mathbb{Q}`---can also be computed:: sage: (z^(5/2) + z^(1/7)) * z^(-1/5) z^(23/10) + z^(-2/35) From 3e2a7b30fc098fd12a092e44b651e667d81080e1 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 17 Aug 2015 20:41:45 +0200 Subject: [PATCH 0414/1872] typo fixed --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 1593cbedbf8..49ab7655f29 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -338,7 +338,7 @@ def summands(self): def __nonzero__(self): r""" - Return if this asymptotic expression is not identially zero. + Return if this asymptotic expression is not identically zero. INPUT: From f11877232543a2d08b45f2a1924793ad129b7576 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 17 Aug 2015 20:41:57 +0200 Subject: [PATCH 0415/1872] some SEEALSO-blocks added --- src/sage/rings/asymptotic_ring.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 49ab7655f29..33a0717547e 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -296,6 +296,12 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): sage: lx = R_log(log(SR.var('x'))) sage: (O(lx) + lx^3)^4 log(x)^12 + O(log(x)^10) + + .. SEEALSO:: + + :mod:`sage.groups.asymptotic_growth_group`, + :mod:`sage.monoids.asymptotic_term_monoid`, + :mod:`sage.data_structures.mutable_poset` """ def __init__(self, parent, summands, simplify=True): r""" @@ -332,6 +338,10 @@ def summands(self): sage: expr = 7 * x^12 + x^5 + O(x^3) sage: expr.summands poset(O(x^3), x^5, 7*x^12) + + .. SEEALSO:: + + :class:`sage.data_structures.mutable_poset.MutablePoset` """ return self._summands_ @@ -635,6 +645,11 @@ def O(self): Traceback (most recent call last): ... ValueError: Cannot build O(0). + + .. SEEALSO:: + + :func:`sage.rings.power_series_ring.PowerSeriesRing`, + :func:`sage.rings.laurent_series_ring.LaurentSeriesRing` """ if not self: raise ValueError('Cannot build O(%s).' % (self,)) @@ -828,6 +843,10 @@ def growth_group(self): sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR.growth_group Growth Group x^ZZ + + .. SEEALSO:: + + :mod:`sage.groups.asymptotic_growth_group` """ return self._growth_group_ From 43fd06d3ba8c57edd75262526c51ab89aabdf27a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 21:08:27 +0200 Subject: [PATCH 0416/1872] delete stop-option from some_elements --- src/sage/groups/asymptotic_growth_group.py | 12 +++----- src/sage/monoids/asymptotic_term_monoid.py | 33 ++++++---------------- src/sage/rings/asymptotic_ring.py | 17 +++++------ 3 files changed, 20 insertions(+), 42 deletions(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index a1783099656..19973d55c98 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -684,7 +684,7 @@ def _an_element_(self): return self.element_class(self, self.base().an_element()) - def some_elements(self, stop=100): + def some_elements(self): r""" Return some elements of this growth group. @@ -692,9 +692,7 @@ def some_elements(self, stop=100): INPUT: - - ``stop`` -- (default: ``100``) an integer or ``None``. This - is passed on to :meth:`itertools.islice` and limits the - number of elements. + Nothing. OUTPUT: @@ -712,10 +710,8 @@ def some_elements(self, stop=100): z^(2/3), z^(-2/3), z^(3/2), z^(-3/2), z^(4/5), z^(-4/5), z^(5/4), z^(-5/4), ...) """ - from itertools import islice - return islice(iter(self.element_class(self, e) - for e in self.base().some_elements()), - stop) + return iter(self.element_class(self, e) + for e in self.base().some_elements()) def le(self, left, right): diff --git a/src/sage/monoids/asymptotic_term_monoid.py b/src/sage/monoids/asymptotic_term_monoid.py index 2ba050823f5..8ef83dea517 100644 --- a/src/sage/monoids/asymptotic_term_monoid.py +++ b/src/sage/monoids/asymptotic_term_monoid.py @@ -920,7 +920,7 @@ def _an_element_(self): return self(self.growth_group.an_element()) - def some_elements(self, stop=100): + def some_elements(self): r""" Return some elements of this term monoid. @@ -928,9 +928,7 @@ def some_elements(self, stop=100): INPUT: - - ``stop`` -- (default: ``100``) an integer or ``None``. This - is passed on to :meth:`itertools.islice` and limits the - number of elements. + Nothing. OUTPUT: @@ -944,9 +942,7 @@ def some_elements(self, stop=100): sage: tuple(atm.OTermMonoid(G).some_elements()) (O(1), O(x), O(1/x), O(x^2), O(x^(-2)), O(x^3), ...) """ - from itertools import islice - return islice(iter(self(g) for g in self.growth_group.some_elements()), - stop) + return iter(self(g) for g in self.growth_group.some_elements()) def le(self, left, right): @@ -1708,7 +1704,7 @@ def _an_element_(self): self.base_ring.an_element()) - def some_elements(self, stop=100): + def some_elements(self): r""" Return some elements of this term with coefficient monoid. @@ -1716,9 +1712,7 @@ def some_elements(self, stop=100): INPUT: - - ``stop`` -- (default: ``100``) an integer or ``None``. This - is passed on to :meth:`itertools.islice` and limits the - number of elements. + Nothing. OUTPUT: @@ -1726,28 +1720,19 @@ def some_elements(self, stop=100): EXAMPLES: + sage: from itertools import islice sage: import sage.groups.asymptotic_growth_group as agg sage: import sage.monoids.asymptotic_term_monoid as atm sage: G = agg.GrowthGroup('z^QQ') sage: T = atm.ExactTermMonoid(G, ZZ) - sage: tuple(T.some_elements(stop=10)) + sage: tuple(islice(T.some_elements(), 10)) (z^(1/2), -z^(1/2), z^(-1/2), 2*z^(1/2), -z^(-1/2), z^2, -2*z^(1/2), 2*z^(-1/2), -z^2, z^(-2)) - TESTS:: - - sage: len(tuple(T.some_elements())) - 100 - sage: len(tuple(T.some_elements(stop=None))) - 9900 - sage: len(tuple(T.some_elements(stop=42))) - 42 """ - from itertools import islice - return islice(iter(self(g, c) for g, c in product_diagonal( + return iter(self(g, c) for g, c in product_diagonal( self.growth_group.some_elements(), - iter(c for c in self.base_ring.some_elements() if c != 0))), - stop) + iter(c for c in self.base_ring.some_elements() if c != 0))) class ExactTerm(TermWithCoefficient): diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index a1976321e67..911420ab6a7 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -1067,7 +1067,7 @@ def _an_element_(self): return -self(E.an_element())**3 + self(O.an_element()) - def some_elements(self, stop=100): + def some_elements(self): r""" Return some elements of this term monoid. @@ -1075,9 +1075,7 @@ def some_elements(self, stop=100): INPUT: - - ``stop`` -- (default: ``100``) an integer or ``None``. This - is passed on to :meth:`itertools.islice` and limits the - number of elements. + Nothing. OUTPUT: @@ -1085,8 +1083,9 @@ def some_elements(self, stop=100): EXAMPLES: + sage: from itertools import islice sage: A = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ) - sage: tuple(A.some_elements(stop=10)) + sage: tuple(islice(A.some_elements(), 10)) (-z^(3/2) + O(z^(1/2)), -z^(3/2) + O(z^(-1/2)), z^(3/2) + O(z^(1/2)), @@ -1098,15 +1097,13 @@ def some_elements(self, stop=100): O(z^(-1/2)), -8*z^(3/2) + O(z^(1/2))) """ - from itertools import islice from sage.monoids.asymptotic_term_monoid import product_diagonal from sage.monoids.asymptotic_term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) - return islice(iter(-self(e)**3 + self(o) - for e, o in product_diagonal( - E.some_elements(), O.some_elements())), - stop) + return iter(-self(e)**3 + self(o) + for e, o in product_diagonal( + E.some_elements(), O.some_elements())) def gens(self): From 4f294ce9023fc4908bb3ad67228f900111826158 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 17 Aug 2015 21:09:00 +0200 Subject: [PATCH 0417/1872] improve product_diagonal so that input is read only when needed --- src/sage/monoids/asymptotic_term_monoid.py | 94 ++++++++++++++++++++-- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/src/sage/monoids/asymptotic_term_monoid.py b/src/sage/monoids/asymptotic_term_monoid.py index 8ef83dea517..9d3f9886274 100644 --- a/src/sage/monoids/asymptotic_term_monoid.py +++ b/src/sage/monoids/asymptotic_term_monoid.py @@ -104,12 +104,96 @@ def product_diagonal(A, B): ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') + + TESTS: + + Check that all pairs are returned:: + + sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n + ....: for m in srange(5) for n in srange(5)) + True + + Check that everthing is loaded in the correct order:: + + sage: def it(s, n): + ....: for i in srange(n): + ....: print '%s loads item number %s' % (s, i) + ....: yield i + sage: for p in product_diagonal(it('A', 2), it('B', 2)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + (1, 1) + sage: for p in product_diagonal(it('A', 3), it('B', 2)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + (1, 1) + A loads item number 2 + (2, 0) + (2, 1) + sage: for p in product_diagonal(it('A', 2), it('B', 4)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + B loads item number 2 + (0, 2) + (1, 1) + B loads item number 3 + (0, 3) + (1, 2) + (1, 3) """ - A = tuple(A) - B = tuple(B) - return iter((A[i], B[s-i]) - for s in range(len(A)+len(B)-1) - for i in range(min(len(A), s+1)) if s-i < len(B)) + # when writing this code I thought the solution would be shorter... + + class iter_as_list(list): + def __init__(self, iterable): + self.it = iter(iterable) + self.newdata = True + def __getitem__(self, i): + self.newdata = False + try: + while len(self) <= i: + self.append(next(self.it)) + self.newdata = True + except StopIteration: + raise + return list.__getitem__(self, i) + + from itertools import count + A = iter_as_list(A) + B = iter_as_list(B) + for s in count(): + for i in range(s+1): + stopped = False + try: + a = A[i] + except StopIteration: + stopped = True + try: + b = B[s-i] + except StopIteration: + stopped = True + if stopped: + continue + yield a, b + if not A.newdata and not B.newdata and s >= len(A) + len(B): + return def absorption(left, right): From 9c1fc0e5ae62f1fdfc59acea333ea9df9637e0b7 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 17 Aug 2015 22:36:23 +0200 Subject: [PATCH 0418/1872] cleanup documentation: strange 'exact removed --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index eb9c0ceb089..45f3101f4e4 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -1214,7 +1214,7 @@ def create_summand(self, type, growth, **kwds): This method calls the factory :class:`TermMonoid ` - with the appropriate arguments.'exact + with the appropriate arguments. EXAMPLES:: From 9305ca5fa737bcea5c728b7156514893b9d33ab1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 18 Aug 2015 13:44:02 +0200 Subject: [PATCH 0419/1872] add . after seealso-lists --- src/sage/rings/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 33a0717547e..8c8bc419995 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -301,7 +301,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): :mod:`sage.groups.asymptotic_growth_group`, :mod:`sage.monoids.asymptotic_term_monoid`, - :mod:`sage.data_structures.mutable_poset` + :mod:`sage.data_structures.mutable_poset`. """ def __init__(self, parent, summands, simplify=True): r""" @@ -649,7 +649,7 @@ def O(self): .. SEEALSO:: :func:`sage.rings.power_series_ring.PowerSeriesRing`, - :func:`sage.rings.laurent_series_ring.LaurentSeriesRing` + :func:`sage.rings.laurent_series_ring.LaurentSeriesRing`. """ if not self: raise ValueError('Cannot build O(%s).' % (self,)) From 50d7166c926186e6aedff82e60aefe016896fe52 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 18 Aug 2015 13:45:58 +0200 Subject: [PATCH 0420/1872] \mathbb{Q} --> \QQ --- src/sage/rings/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 8c8bc419995..c3a8eb7d362 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -129,7 +129,7 @@ 27*z^3 + 54*z^2 + 36*z + 8 In addition to that, special powers---our growth group ``z^QQ`` allows -the exponents to be out of `\mathbb{Q}`---can also be computed:: +the exponents to be out of `\QQ`---can also be computed:: sage: (z^(5/2) + z^(1/7)) * z^(-1/5) z^(23/10) + z^(-2/35) From 2f8146d6905357506ae2b883b18121fd1b65f995 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 18 Aug 2015 13:54:00 +0200 Subject: [PATCH 0421/1872] doctests: add growth_group= and coefficient_ring= to AsymptoticRing(...) generation --- src/sage/rings/asymptotic_ring.py | 54 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index c3a8eb7d362..92dc3056bdf 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -71,7 +71,7 @@ experimental. It, its functionality or its interface might change without a formal deprecation. See http://trac.sagemath.org/17601 for details. - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) .. _asymptotic_ring_intro: @@ -208,9 +208,9 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): There are several ways to create asymptotic expressions; usually this is done by using the corresponding rings/parents:: - sage: R_x. = AsymptoticRing('x^QQ', QQ); R_x + sage: R_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R_x Asymptotic Ring over Rational Field - sage: R_y. = AsymptoticRing('y^ZZ', ZZ); R_y + sage: R_y. = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=ZZ); R_y Asymptotic Ring over Integer Ring At this point, `x` and `y` are already asymptotic expressions:: @@ -292,7 +292,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): also compute with logarithmic terms (simply by constructing the appropriate growth group):: - sage: R_log = AsymptoticRing('log(x)^QQ', QQ) + sage: R_log = AsymptoticRing(growth_group='log(x)^QQ', coefficient_ring=QQ) sage: lx = R_log(log(SR.var('x'))) sage: (O(lx) + lx^3)^4 log(x)^12 + O(log(x)^10) @@ -309,8 +309,8 @@ def __init__(self, parent, summands, simplify=True): TESTS:: - sage: R_x. = AsymptoticRing('x^ZZ', ZZ) - sage: R_y. = AsymptoticRing('y^ZZ', ZZ) + sage: R_x. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) + sage: R_y. = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=ZZ) sage: R_x is R_y False sage: ex1 = x + 2*x^2 + 3*x^3 + 4*x^4 + 5*x^5 @@ -334,7 +334,7 @@ def summands(self): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: expr = 7 * x^12 + x^5 + O(x^3) sage: expr.summands poset(O(x^3), x^5, 7*x^12) @@ -360,7 +360,7 @@ def __nonzero__(self): TESTS:: - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: bool(R(0)) # indirect doctest False sage: bool(x) # indirect doctest @@ -426,7 +426,7 @@ def _repr_(self): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: (5*x^2 + 12*x) * (x^3 + O(x)) # indirect doctest 5*x^5 + 12*x^4 + O(x^3) sage: (5*x^2 - 12*x) * (x^3 + O(x)) # indirect doctest @@ -454,7 +454,7 @@ def _add_(self, other): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1._add_(expr2) x^321 + x^123 @@ -497,7 +497,7 @@ def _sub_(self, other): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: expr1 = x^123; expr2 = x^321 sage: expr1 - expr2 # indirect doctest -x^321 + x^123 @@ -524,7 +524,7 @@ def _mul_term_(self, term): TESTS:: sage: import sage.monoids.asymptotic_term_monoid as atm - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: T = atm.OTermMonoid(R.growth_group) sage: expr = 10*x^2 + O(x) sage: t = T(R.growth_group.gen()) @@ -548,7 +548,7 @@ def _mul_(self, other): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: ex1 = 5*x^12 sage: ex2 = x^3 + O(x) sage: ex1 * ex2 # indirect doctest @@ -580,10 +580,10 @@ def __pow__(self, power): TESTS:: - sage: R_QQ. = AsymptoticRing('x^QQ', QQ) + sage: R_QQ. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ) sage: x^(1/7) x^(1/7) - sage: R_ZZ. = AsymptoticRing('y^ZZ', ZZ) + sage: R_ZZ. = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=ZZ) sage: y^(1/7) Traceback (most recent call last): ... @@ -631,7 +631,7 @@ def O(self): EXAMPLES:: - sage: AR. = AsymptoticRing('x^ZZ', ZZ) + sage: AR. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: O(x) O(x) sage: expr = 42 * x^42 + x^10 + O(x^2); expr @@ -706,7 +706,7 @@ class AsymptoticRing(sage.rings.ring.Ring, Note, we can also create and use logarithmic growth groups:: - sage: R_log = AsymptoticRing('log(x)^ZZ', QQ); R_log + sage: R_log = AsymptoticRing(growth_group='log(x)^ZZ', coefficient_ring=QQ); R_log Asymptotic Ring over Rational Field Other growth groups are available. See :mod:`~sage.rings.asymptotic_ring` for @@ -771,7 +771,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, The bracket notation can only be used if the growth group has a generator:: - sage: AR. = AsymptoticRing('log(x)^ZZ', ZZ) + sage: AR. = AsymptoticRing(growth_group='log(x)^ZZ', coefficient_ring=ZZ) Traceback (most recent call last): ... ValueError: Growth Group log(x)^ZZ does not have a generator. @@ -795,9 +795,9 @@ def __init__(self, growth_group, coefficient_ring, category=None): TESTS:: - sage: R1 = AsymptoticRing('x^ZZ', ZZ); R1 + sage: R1 = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ); R1 Asymptotic Ring over Integer Ring - sage: R2. = AsymptoticRing('x^QQ', QQ); R2 + sage: R2. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R2 Asymptotic Ring over Rational Field sage: R1 is R2 False @@ -914,7 +914,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): TESTS:: - sage: AR = AsymptoticRing('x^ZZ', ZZ) + sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR(5) 5 sage: AR(3*x^2) @@ -998,10 +998,10 @@ def _coerce_map_from_(self, R): TESTS:: - sage: AR_ZZ = AsymptoticRing('x^ZZ', coefficient_ring=ZZ); AR_ZZ + sage: AR_ZZ = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ); AR_ZZ Asymptotic Ring over Integer Ring sage: x_ZZ = AR_ZZ.gen() - sage: AR_QQ = AsymptoticRing('x^QQ', coefficient_ring=QQ); AR_QQ + sage: AR_QQ = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); AR_QQ Asymptotic Ring over Rational Field sage: x_QQ = AR_QQ.gen() sage: AR_QQ.has_coerce_map_from(AR_ZZ) # indirect doctest @@ -1072,7 +1072,7 @@ def gens(self): EXAMPLES:: - sage: AR. = AsymptoticRing('x^ZZ', ZZ) + sage: AR. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR.gens() (x,) """ @@ -1095,7 +1095,7 @@ def gen(self, n=0): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: R.gen() x """ @@ -1116,7 +1116,7 @@ def ngens(self): EXAMPLES:: - sage: AR. = AsymptoticRing('x^ZZ', ZZ) + sage: AR. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR.ngens() 1 """ @@ -1152,7 +1152,7 @@ def create_summand(self, type, growth, **kwds): EXAMPLES:: - sage: R = AsymptoticRing('x^ZZ', ZZ) + sage: R = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: R.create_summand('O', growth=x^2) O(x^2) sage: R.create_summand('exact', growth=x^456, coefficient=123) From 64563002a4d2579b7eb280c1807d108af51e3ea3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 18 Aug 2015 20:12:35 +0200 Subject: [PATCH 0422/1872] minor rewording in docstring --- src/sage/rings/asymptotic_ring.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic_ring.py index 92dc3056bdf..00ff04bef2d 100644 --- a/src/sage/rings/asymptotic_ring.py +++ b/src/sage/rings/asymptotic_ring.py @@ -13,9 +13,10 @@ - Exact terms `c\cdot g` with a coefficient `c` and an element `g` of an :ref:`growth group `. -- `O`-terms `O(g)` (see :wikipedia:`Big_O_notation`) for some - :mod:`growth group element ` - `g` (:ref:`see below `). +- `O`-terms `O(g)` (see :wikipedia:`Big O notation `; + also called *Bachmann--Landau notation*) for some :mod:`growth group + element ` `g` (:ref:`see below + `). Examples of such elements can found :ref:`below `. From 8be310875bb740569adc37d67ea74efa205a9406 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 19 Aug 2015 20:35:18 +0200 Subject: [PATCH 0423/1872] make doctests run again --- src/sage/categories/pushout.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index a57294d1f5d..bf76781026b 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -4,6 +4,12 @@ from sage.misc.lazy_import import lazy_import from functor import Functor, IdentityFunctor_generic +lazy_import('sage.categories.commutative_additive_groups', 'CommutativeAdditiveGroups') +lazy_import('sage.categories.commutative_rings', 'CommutativeRings') +lazy_import('sage.categories.groups', 'Groups') +lazy_import('sage.categories.objects', 'Objects') +lazy_import('sage.categories.rings', 'Rings') + lazy_import('sage.structure.parent', 'CoercionException') # TODO, think through the rankings, and override pushout where necessary. From 4f1b6f9d9204fbda35b4d3fc39cafd5b99bbb817 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 19 Aug 2015 20:35:55 +0200 Subject: [PATCH 0424/1872] use _apply_functor instead of __call__ in one doctest --- src/sage/categories/pushout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index bf76781026b..d667e13dc01 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3229,7 +3229,7 @@ def pushout(R, S): ....: coercion_reversed = True ....: def __init__(self): ....: ConstructionFunctor.__init__(self, Rings(), Rings()) - ....: def __call__(self, R): + ....: def _apply_functor(self, R): ....: return EvenPolynomialRing(R.base(), R.variable_name()) ....: sage: pushout(EvenPolynomialRing(QQ, 'x'), ZZ) From c160090d3294e230ba4f51abcdafd88bb0044836 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 19 Aug 2015 20:36:32 +0200 Subject: [PATCH 0425/1872] add a doctest for a bug --- src/sage/categories/pushout.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index d667e13dc01..707a5725c0f 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3210,6 +3210,19 @@ def pushout(R, S): [1 2 0] [0 0 1] + A bug:: + + sage: from sage.sets.cartesian_product import CartesianProduct + sage: A = CartesianProduct((QQ['z'],), Sets().CartesianProducts()) + sage: B = CartesianProduct((ZZ['t']['z'],), Sets().CartesianProducts()) + sage: pushout(A, B) + The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) + sage: A.construction() + (The cartesian_product functorial construction, + (Univariate Polynomial Ring in z over Rational Field,)) + sage: pushout(A, B) + The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) + Some more tests with ``coercion_reversed = True``:: sage: from sage.categories.pushout import ConstructionFunctor From d0ebeb5c7562bebfcb6c1d989fdef5d488e71c5b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 19 Aug 2015 20:37:51 +0200 Subject: [PATCH 0426/1872] add a lot of doctests to test desired functionality of pushout --- src/sage/categories/pushout.py | 129 +++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 707a5725c0f..d4fbd1624c3 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3269,6 +3269,135 @@ def pushout(R, S): sage: pushout(EvenPolynomialRing(QQ, 'x')^2, RR['x']^2) Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Real Field with 53 bits of precision + Some more tests related to univariate/multivariate + constructions. We construct a parent for a generalization to + polynomials, where we not only specify a coefficient ring `C` but + also an additive monoid `E` for its exponents. Its elements are + then + + .. MATH:: + + \sum_{i=0}^I c_i X^{e_i} + + with `c_i \in C` and `e_i \in E`. We define + :: + + sage: class GPolynomialRing(Parent): + ....: def __init__(self, coefficients, var, exponents): + ....: self.coefficients = coefficients + ....: self.var = var + ....: self.exponents = exponents + ....: super(GPolynomialRing, self).__init__(category=Rings()) + ....: def _repr_(self): + ....: return 'Generalized Polynomial Ring in %s^(%s) over %s' % ( + ....: self.var, self.exponents, self.coefficients) + ....: def construction(self): + ....: return GPolynomialFunctor(self.var, self.exponents), self.coefficients + ....: def _coerce_map_from_(self, R): + ....: return self.coefficients.has_coerce_map_from(R) + + and + :: + + sage: class GPolynomialFunctor(ConstructionFunctor): + ....: rank = 10 + ....: def __init__(self, var, exponents): + ....: self.var = var + ....: self.exponents = exponents + ....: ConstructionFunctor.__init__(self, Rings(), Rings()) + ....: def _repr_(self): + ....: return 'GPoly[%s^(%s)]' % (self.var, self.exponents) + ....: def _apply_functor(self, coefficients): + ....: return GPolynomialRing(coefficients, self.var, self.exponents) + ....: def merge(self, other): + ....: if isinstance(other, GPolynomialFunctor) and self.var == other.var: + ....: exponents = pushout(self.exponents, other.exponents) + ....: return GPolynomialFunctor(self.var, exponents) + + We can construct a parent now in two different ways:: + + sage: GPolynomialRing(QQ, 'X', ZZ) + Generalized Polynomial Ring in X^(Integer Ring) over Rational Field + sage: GP_ZZ = GPolynomialFunctor('X', ZZ); GP_ZZ + GPoly[X^(Integer Ring)] + sage: GP_ZZ(QQ) + Generalized Polynomial Ring in X^(Integer Ring) over Rational Field + + Since the construction + :: + + sage: GP_ZZ(QQ).construction() + (GPoly[X^(Integer Ring)], Rational Field) + + uses the coefficient ring, we have the usual coercion with respect + to this parameter:: + + sage: pushout(GP_ZZ(ZZ), GP_ZZ(QQ)) + Generalized Polynomial Ring in X^(Integer Ring) over Rational Field + sage: pushout(GP_ZZ(ZZ['t']), GP_ZZ(QQ)) + Generalized Polynomial Ring in X^(Integer Ring) over Univariate Polynomial Ring in t over Rational Field + sage: pushout(GP_ZZ(ZZ['a,b']), GP_ZZ(ZZ['b,c'])) + Generalized Polynomial Ring in X^(Integer Ring) + over Multivariate Polynomial Ring in a, b, c over Integer Ring + sage: pushout(GP_ZZ(ZZ['a,b']), GP_ZZ(QQ['b,c'])) + Generalized Polynomial Ring in X^(Integer Ring) + over Multivariate Polynomial Ring in a, b, c over Rational Field + sage: pushout(GP_ZZ(ZZ['a,b']), GP_ZZ(ZZ['c,d'])) + Traceback (most recent call last): + ... + CoercionException: ('Ambiguous Base Extension', ...) + + :: + + sage: GP_QQ = GPolynomialFunctor('X', QQ) + sage: pushout(GP_ZZ(ZZ), GP_QQ(ZZ)) + Generalized Polynomial Ring in X^(Rational Field) over Integer Ring + sage: pushout(GP_QQ(ZZ), GP_ZZ(ZZ)) + Generalized Polynomial Ring in X^(Rational Field) over Integer Ring + + :: + + sage: GP_ZZt = GPolynomialFunctor('X', ZZ['t']) + sage: pushout(GP_ZZt(ZZ), GP_QQ(ZZ)) + Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t + over Rational Field) over Integer Ring + + :: + + sage: pushout(GP_ZZ(ZZ), GP_QQ(QQ)) + Generalized Polynomial Ring in X^(Rational Field) over Rational Field + sage: pushout(GP_ZZ(QQ), GP_QQ(ZZ)) + Generalized Polynomial Ring in X^(Rational Field) over Rational Field + sage: pushout(GP_ZZt(QQ), GP_QQ(ZZ)) + Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t + over Rational Field) over Rational Field + sage: pushout(GP_ZZt(ZZ), GP_QQ(QQ)) + Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t + over Rational Field) over Rational Field + sage: pushout(GP_ZZt(ZZ['a,b']), GP_QQ(ZZ['c,d'])) + Traceback (most recent call last): + ... + CoercionException: ('Ambiguous Base Extension', ...) + sage: pushout(GP_ZZt(ZZ['a,b']), GP_QQ(ZZ['b,c'])) + Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t over Rational Field) + over Multivariate Polynomial Ring in a, b, c over Integer Ring + + Some tests with cartesian products:: + + sage: from sage.sets.cartesian_product import CartesianProduct + sage: A = CartesianProduct((ZZ['x'], QQ['y'], QQ['z']), Sets().CartesianProducts()) + sage: B = CartesianProduct((ZZ['x'], ZZ['y'], ZZ['t']['z']), Sets().CartesianProducts()) + sage: A.construction() + (The cartesian_product functorial construction, + (Univariate Polynomial Ring in x over Integer Ring, + Univariate Polynomial Ring in y over Rational Field, + Univariate Polynomial Ring in z over Rational Field)) + sage: pushout(A, B) + The cartesian product of + (Univariate Polynomial Ring in x over Integer Ring, + Univariate Polynomial Ring in y over Rational Field, + Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field) + AUTHORS: -- Robert Bradshaw From ba34742964ff48074674f87016e7673ca0a5ef82 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 19 Aug 2015 20:38:12 +0200 Subject: [PATCH 0427/1872] new functionality of pushout: check R._pushout_ --- src/sage/categories/pushout.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index d4fbd1624c3..08982ef03a4 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3405,6 +3405,16 @@ def pushout(R, S): if R is S or R == S: return R + if hasattr(R, '_pushout_'): + P = R._pushout_(S) + if P is not None: + return P + + if hasattr(S, '_pushout_'): + P = S._pushout_(R) + if P is not None: + return P + if isinstance(R, type): R = type_to_parent(R) From 36906480db3ef5927041a64873c99d611c0beaf1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 19 Aug 2015 20:38:40 +0200 Subject: [PATCH 0428/1872] doctests for _pushout_ feature --- src/sage/categories/pushout.py | 63 ++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 08982ef03a4..06ee1d14b92 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3398,6 +3398,69 @@ def pushout(R, S): Univariate Polynomial Ring in y over Rational Field, Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field) + + :: + + sage: from sage.categories.pushout import PolynomialFunctor + sage: from sage.sets.cartesian_product import CartesianProduct + sage: class CartesianProductPolys(CartesianProduct): + ....: def __init__(self, polynomial_rings): + ....: sort = sorted(polynomial_rings, key=lambda P: P.variable_name()) + ....: super(CartesianProductPolys, self).__init__(sort, Sets().CartesianProducts()) + ....: def vars(self): + ....: return tuple(P.variable_name() for P in self.cartesian_factors()) + ....: def _pushout_(self, other): + ....: if isinstance(other, CartesianProductPolys): + ....: s_vars = self.vars() + ....: o_vars = other.vars() + ....: if s_vars == o_vars: + ....: return + ....: return pushout(CartesianProductPolys( + ....: self.cartesian_factors() + + ....: tuple(f for f in other.cartesian_factors() + ....: if f.variable_name() not in s_vars)), + ....: CartesianProductPolys( + ....: other.cartesian_factors() + + ....: tuple(f for f in self.cartesian_factors() + ....: if f.variable_name() not in o_vars))) + ....: C = other.construction()[0] + ....: if isinstance(C, PolynomialFunctor): + ....: return pushout(self, CartesianProductPolys((other,))) + + :: + + sage: pushout(CartesianProductPolys((ZZ['x'],)), + ....: CartesianProductPolys((ZZ['y'],))) + The cartesian product of + (Univariate Polynomial Ring in x over Integer Ring, + Univariate Polynomial Ring in y over Integer Ring) + sage: pushout(CartesianProductPolys((ZZ['x'], ZZ['y'])), + ....: CartesianProductPolys((ZZ['x'], ZZ['z']))) + The cartesian product of + (Univariate Polynomial Ring in x over Integer Ring, + Univariate Polynomial Ring in y over Integer Ring, + Univariate Polynomial Ring in z over Integer Ring) + sage: pushout(CartesianProductPolys((QQ['a,b']['x'], QQ['y'])), + ....: CartesianProductPolys((ZZ['b,c']['x'], SR['z']))) + The cartesian product of + (Univariate Polynomial Ring in x over + Multivariate Polynomial Ring in a, b, c over Rational Field, + Univariate Polynomial Ring in y over Rational Field, + Univariate Polynomial Ring in z over Symbolic Ring) + + :: + + sage: pushout(CartesianProductPolys((ZZ['x'],)), ZZ['y']) + The cartesian product of + (Univariate Polynomial Ring in x over Integer Ring, + Univariate Polynomial Ring in y over Integer Ring) + sage: pushout(QQ['b,c']['y'], CartesianProductPolys((ZZ['a,b']['x'],))) + The cartesian product of + (Univariate Polynomial Ring in x over + Multivariate Polynomial Ring in a, b over Integer Ring, + Univariate Polynomial Ring in y over + Multivariate Polynomial Ring in b, c over Rational Field) + AUTHORS: -- Robert Bradshaw From 003180a4444918c5e080960fe6a98b3a1551b903 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 19 Aug 2015 20:38:59 +0200 Subject: [PATCH 0429/1872] improve coercion error message --- src/sage/categories/pushout.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 06ee1d14b92..82655eae49c 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -296,7 +296,7 @@ def expand(self): # See the pushout() function below for explanation. coercion_reversed = False - def common_base(self, other, R_bases, S_bases): + def common_base(self, other, self_bases, other_bases): """ This function is called by :func:`pushout` when no common parent is found in the construction tower. @@ -304,7 +304,11 @@ def common_base(self, other, R_bases, S_bases): The main use is for multivariate construction functors, which use this function to implement recursion for :func:`pushout`. """ - raise CoercionException("No common base") + raise CoercionException( + 'No common base ("join") found for %s(%s) and %s(%s).' % + (self, ', '.join(str(b) for b in self_bases), + other, ', '.join(str(b) for b in other_bases))) + class CompositeConstructionFunctor(ConstructionFunctor): """ @@ -580,20 +584,30 @@ def __mul__(self, other): else: return self + class MultivariateConstructionFunctor(ConstructionFunctor): """ An abstract base class for functors that take multiple inputs (e.g. CartesianProduct) """ - def common_base(self, other_functor, R_bases, S_bases): + def common_base(self, other_functor, self_bases, other_bases): """ """ if self != other_functor: - raise CoercionException("Incompatible multivariate construction functors") - if len(R_bases) != len(S_bases): - raise CoercionException("Multivariate construction functors need the same number of inputs") - Z_bases = tuple(pushout(R, S) for R, S in zip(R_bases, S_bases)) + raise CoercionException( + 'No common base ("join") found for %s(%s) and %s(%s): ' + 'Multivariate functors are inkompatibel.' % + (self, ', '.join(str(b) for b in self_bases), + other, ', '.join(str(b) for b in other_bases))) + if len(self_bases) != len(other_bases): + raise CoercionException( + 'No common base ("join") found for %s(%s) and %s(%s): ' + 'Functors need the same number of arguments.' % + (self, ', '.join(str(b) for b in self_bases), + other, ', '.join(str(b) for b in other_bases))) + Z_bases = tuple(pushout(S, O) for S, O in zip(self_bases, other_bases)) return self(Z_bases) + class PolynomialFunctor(ConstructionFunctor): """ Construction functor for univariate polynomial rings. From 45c0bf3b96a8fef4cdfff57f81d319872d183d05 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 14:18:32 +0200 Subject: [PATCH 0430/1872] write docstrings --- src/sage/sets/cartesian_product.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 9cb13445f02..e88f8ce9d67 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -222,10 +222,37 @@ def _cartesian_product_of_elements(self, elements): return self.element_class(self, elements) def construction(self): + r""" + Return the construction functor and its arguments for this + cartesian product. + + OUTPUT: + + A pair whose first entry is a cartesian product functor and + its second a list of the cartesian factors. + + EXAMPLES:: + + sage: cartesian_product([ZZ, QQ]).construction() + (The cartesian_product functorial construction, + (Integer Ring, Rational Field)) + """ from sage.categories.cartesian_product import cartesian_product return cartesian_product, self.cartesian_factors() def _coerce_map_from_(self, S): + r""" + Return ``True`` if ``S`` coerces into this cartesian product. + + TESTS:: + + sage: Z = cartesian_product([ZZ]) + sage: Q = cartesian_product([QQ]) + sage: Z.has_coerce_map_from(Q) # indirect doctest + False + sage: Q.has_coerce_map_from(Z) # indirect doctest + True + """ if isinstance(S, CartesianProduct): S_factors = S.cartesian_factors() R_factors = self.cartesian_factors() From c9d089226d8c446fbdad6f2e6e436a1d158a3b49 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 14:18:44 +0200 Subject: [PATCH 0431/1872] write more docstrings --- src/sage/categories/cartesian_product.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index f77f0184904..70cbbf3bab5 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -108,6 +108,15 @@ class CartesianProductFunctor(CovariantFunctorialConstruction, MultivariateConst symbol = " (+) " def __init__(self): + r""" + Constructor. See :class:`CartesianProductFunctor` for details. + + TESTS:: + + sage: from sage.categories.cartesian_product import CartesianProductFunctor + sage: CartesianProductFunctor() + The cartesian_product functorial construction + """ CovariantFunctorialConstruction.__init__(self) from sage.categories.sets_cat import Sets MultivariateConstructionFunctor.__init__(self, Sets(), Sets()) From 5be8393cadc7729d3e63013fff8d228dae1521fb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 14:19:15 +0200 Subject: [PATCH 0432/1872] mark a test as indirect to pass coverage --- src/sage/categories/pushout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 82655eae49c..15d84a97307 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -692,7 +692,7 @@ def _apply_functor_to_morphism(self, f): TEST:: sage: P = ZZ['x'].construction()[0] - sage: P(ZZ.hom(GF(3))) + sage: P(ZZ.hom(GF(3))) # indirect doctest Ring morphism: From: Univariate Polynomial Ring in x over Integer Ring To: Univariate Polynomial Ring in x over Finite Field of size 3 From 790a13367e3317d6c7f86ca0b6b77b95975825c3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 14:20:13 +0200 Subject: [PATCH 0433/1872] finalize common_base methods --- src/sage/categories/pushout.py | 141 ++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 18 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 15d84a97307..071c37b7454 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -296,18 +296,86 @@ def expand(self): # See the pushout() function below for explanation. coercion_reversed = False - def common_base(self, other, self_bases, other_bases): - """ + def common_base(self, other_functor, self_bases, other_bases): + r""" This function is called by :func:`pushout` when no common parent is found in the construction tower. - The main use is for multivariate construction functors, which - use this function to implement recursion for :func:`pushout`. + .. NOTE:: + + The main use is for multivariate construction functors, + which use this function to implement recursion for + :func:`pushout`. + + INPUT: + + - ``other_functor`` -- a construction functor. + + - ``self_bases`` -- the arguments passed to this functor. + + - ``other_bases`` -- the arguments passed to the functor + ``other_functor``. + + OUTPUT: + + Raise a :class:`CoercionException`. + + .. NOTE:: + + Overload this function in derived class, see + e.e. :class:`MultivariateConstructionFunctor`. + + TESTS:: + + sage: from sage.categories.pushout import pushout + sage: pushout(QQ, cartesian_product([ZZ])) # indirect doctest + Traceback (most recent call last): + ... + CoercionException: No common base ("join") found for + FractionField(Integer Ring) and CartesianProductFunctor(Integer Ring). """ + self._raise_common_base_exception_( + other_functor, self_bases, other_bases) + + def _raise_common_base_exception_(self, other_functor, + self_bases, other_bases, + reason=None): + r""" + Raise a coercion exception. + + INPUT: + + - ``other_functor`` -- a functor. + + - ``self_bases`` -- the arguments passed to this functor. + + - ``other_bases`` -- the arguments passed to the functor + ``other_functor``. + + - ``reason`` -- a string or ``None`` (default). + + TESTS:: + + sage: from sage.categories.pushout import pushout + sage: pushout(QQ, cartesian_product([QQ])) # indirect doctest + Traceback (most recent call last): + ... + CoercionException: No common base ("join") found for + FractionField(Integer Ring) and CartesianProductFunctor(Rational Field). + """ + if not isinstance(self_bases, (tuple, list)): + self_bases = (self_bases,) + if not isinstance(other_bases, (tuple, list)): + other_bases = (other_bases,) + if reason is None: + reason = '.' + else: + reason = ': ' + reason + '.' raise CoercionException( - 'No common base ("join") found for %s(%s) and %s(%s).' % + 'No common base ("join") found for %s(%s) and %s(%s)%s' % (self, ', '.join(str(b) for b in self_bases), - other, ', '.join(str(b) for b in other_bases))) + other_functor, ', '.join(str(b) for b in other_bases), + reason)) class CompositeConstructionFunctor(ConstructionFunctor): @@ -587,23 +655,60 @@ def __mul__(self, other): class MultivariateConstructionFunctor(ConstructionFunctor): """ - An abstract base class for functors that take multiple inputs (e.g. CartesianProduct) + An abstract base class for functors that take + multiple inputs (e.g. cartesian products). """ def common_base(self, other_functor, self_bases, other_bases): - """ + r""" + This function is called by :func:`pushout` when no common parent + is found in the construction tower. + + INPUT: + + - ``other_functor`` -- a construction functor. + + - ``self_bases`` -- the arguments passed to this functor. + + - ``other_bases`` -- the arguments passed to the functor + ``other_functor``. + + OUTPUT: + + A parent. + + If no common base is found a :class:`CoercionException` is + raised. + + .. NOTE:: + + Overload this function in derived class, see + e.e. :class:`MultivariateConstructionFunctor`. + + TESTS:: + + sage: from sage.categories.pushout import pushout + sage: pushout(cartesian_product([ZZ]), QQ) # indirect doctest + Traceback (most recent call last): + ... + CoercionException: No common base ("join") found for + CartesianProductFunctor(Integer Ring) and FractionField(Integer Ring): + (Multivariate) functors are inkompatibel. + sage: pushout(cartesian_product([ZZ]), cartesian_product([ZZ, QQ])) # indirect doctest + Traceback (most recent call last): + ... + CoercionException: No common base ("join") found for + CartesianProductFunctor(Integer Ring) and + CartesianProductFunctor(Integer Ring, Rational Field): + Functors need the same number of arguments. """ if self != other_functor: - raise CoercionException( - 'No common base ("join") found for %s(%s) and %s(%s): ' - 'Multivariate functors are inkompatibel.' % - (self, ', '.join(str(b) for b in self_bases), - other, ', '.join(str(b) for b in other_bases))) + self._raise_common_base_exception_( + other_functor, self_bases, other_bases, + '(Multivariate) functors are inkompatibel') if len(self_bases) != len(other_bases): - raise CoercionException( - 'No common base ("join") found for %s(%s) and %s(%s): ' - 'Functors need the same number of arguments.' % - (self, ', '.join(str(b) for b in self_bases), - other, ', '.join(str(b) for b in other_bases))) + self._raise_common_base_exception_( + other_functor, self_bases, other_bases, + 'Functors need the same number of arguments') Z_bases = tuple(pushout(S, O) for S, O in zip(self_bases, other_bases)) return self(Z_bases) From fce6e801bc38bd2b9d3d35753e50ad6bcd86fa08 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 14:20:36 +0200 Subject: [PATCH 0434/1872] move bug doctest to top of file --- src/sage/categories/pushout.py | 35 +++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 071c37b7454..e4829f8c68b 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1,5 +1,27 @@ """ Coercion via Construction Functors + +TESTS: + +A bug:: + + sage: from sage.categories.pushout import pushout + sage: from sage.sets.cartesian_product import CartesianProduct + sage: A = CartesianProduct((QQ['z'],), Sets().CartesianProducts()) + sage: B = CartesianProduct((ZZ['t']['z'],), Sets().CartesianProducts()) + sage: pushout(A, B) + The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) + sage: A.construction() + (The cartesian_product functorial construction, + (Univariate Polynomial Ring in z over Rational Field,)) + sage: pushout(A, B) + The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) + +In ``A.construction()`` the functor (``CartesianProductFunctor``) +seems not to be seen as ``ConstructionFunctor``` at the first pass, +although it is inherited from +``MultivariateConstructionFunctor``. Code needs to be more on the top +of the file to be reproduced """ from sage.misc.lazy_import import lazy_import from functor import Functor, IdentityFunctor_generic @@ -3329,19 +3351,6 @@ def pushout(R, S): [1 2 0] [0 0 1] - A bug:: - - sage: from sage.sets.cartesian_product import CartesianProduct - sage: A = CartesianProduct((QQ['z'],), Sets().CartesianProducts()) - sage: B = CartesianProduct((ZZ['t']['z'],), Sets().CartesianProducts()) - sage: pushout(A, B) - The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) - sage: A.construction() - (The cartesian_product functorial construction, - (Univariate Polynomial Ring in z over Rational Field,)) - sage: pushout(A, B) - The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) - Some more tests with ``coercion_reversed = True``:: sage: from sage.categories.pushout import ConstructionFunctor From fe83e886867ea855c583ce00245193e632551f6c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 14:25:43 +0200 Subject: [PATCH 0435/1872] update authors of pushout --- src/sage/categories/pushout.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index e4829f8c68b..b9e8de1b3f7 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3591,7 +3591,11 @@ def pushout(R, S): AUTHORS: - -- Robert Bradshaw + - Robert Bradshaw + - Peter Bruin(Peter Bruin -..- -- + - Simon King + - Daniel Krenn + - David Roe """ if R is S or R == S: return R From 7f56908b5a4a12bb97e649cc971a55eec9152f5a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 14:35:54 +0200 Subject: [PATCH 0436/1872] fix links in docu --- src/sage/categories/pushout.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index b9e8de1b3f7..fbc429c1dff 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -340,7 +340,7 @@ def common_base(self, other_functor, self_bases, other_bases): OUTPUT: - Raise a :class:`CoercionException`. + Raise a :class:`~sage.structure.coerce_exceptions.CoercionException`. .. NOTE:: @@ -698,8 +698,8 @@ def common_base(self, other_functor, self_bases, other_bases): A parent. - If no common base is found a :class:`CoercionException` is - raised. + If no common base is found a :class:`sage.structure.coerce_exceptions.CoercionException` + is raised. .. NOTE:: From 133ffa8160b32d36600666f347d3207f08006652 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 20 Aug 2015 15:41:17 +0200 Subject: [PATCH 0437/1872] implemented __pow__ for cartesian products of growth groups --- src/sage/groups/asymptotic_growth_group.py | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index ef9944a1abe..014a2e245c0 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -406,6 +406,32 @@ def gens_monomial(self): class Element(CartesianProductPosets.Element): + def __pow__(self, power): + r""" + Takes this growth element to the given ``power``. + + INPUT: + + - ``power`` -- a number. This can anything that is valid to be + on the right hand side of ``*`` with an elements of the + parent's base. + + OUTPUT: + + An element of the cartesian product of some growth groups. + + EXAMPLES:: + + sage: from sage.groups.asymptotic_growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * y^QQ') + sage: x, y = G.gens_monomial() + sage: (x^2 * y)^(1/2) + x * y^(1/2) + """ + P = self.parent() + return P.prod(P(f**power) for f in self.value) + + def _repr_(self): r""" A representation string for this cartesian product element. From 74abb1ea7d81a28a4712418762fe9c64fe982ca3 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 20 Aug 2015 15:41:46 +0200 Subject: [PATCH 0438/1872] fixed gens_monomial --- src/sage/groups/asymptotic_growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/groups/asymptotic_growth_group.py index 014a2e245c0..2cda9e1e13c 100644 --- a/src/sage/groups/asymptotic_growth_group.py +++ b/src/sage/groups/asymptotic_growth_group.py @@ -402,7 +402,7 @@ def gens_monomial(self): t = () for factor in self.cartesian_factors(): t = t + factor.gens_monomial() - return t + return tuple(self(gen) for gen in t) class Element(CartesianProductPosets.Element): From c6db8534c85b16c336ea78085975f8b8edc98cec Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 20 Aug 2015 16:02:06 +0200 Subject: [PATCH 0439/1872] trac #19061: Auto-generated thematic index of functions --- src/sage/graphs/graph.py | 250 ++++++++++--------------- src/sage/misc/rest_index_of_methods.py | 169 +++++++++++++++-- 2 files changed, 252 insertions(+), 167 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 526ff02b6ec..33d6b405230 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4,141 +4,7 @@ This module implements functions and operations involving undirected graphs. -**Graph basic operations:** - -.. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - :meth:`~Graph.write_to_eps` | Writes a plot of the graph to ``filename`` in ``eps`` format. - :meth:`~Graph.to_undirected` | Since the graph is already undirected, simply returns a copy of itself. - :meth:`~Graph.to_directed` | Returns a directed version of the graph. - :meth:`~Graph.sparse6_string` | Returns the sparse6 representation of the graph as an ASCII string. - :meth:`~Graph.graph6_string` | Returns the graph6 representation of the graph as an ASCII string. - :meth:`~Graph.bipartite_sets` | Returns `(X,Y)` where X and Y are the nodes in each bipartite set of graph. - :meth:`~Graph.bipartite_color` | Returns a dictionary with vertices as the keys and the color class as the values. - :meth:`~Graph.is_directed` | Since graph is undirected, returns False. - :meth:`~Graph.join` | Returns the join of self and other. - - -**Distances:** - -.. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - :meth:`~Graph.centrality_closeness` | Returns the closeness centrality (1/average distance to all vertices) - :meth:`~Graph.centrality_degree` | Returns the degree centrality - - -**Graph properties:** - -.. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - :meth:`~Graph.is_asteroidal_triple_free` | Tests whether the current graph is asteroidal triple free. - :meth:`~Graph.is_prime` | Tests whether the current graph is prime. - :meth:`~Graph.is_split` | Returns ``True`` if the graph is a Split graph, ``False`` otherwise. - :meth:`~Graph.is_triangle_free` | Returns whether ``self`` is triangle-free. - :meth:`~Graph.is_bipartite` | Returns True if graph G is bipartite, False if not. - :meth:`~Graph.is_line_graph` | Tests wether the graph is a line graph. - :meth:`~Graph.is_odd_hole_free` | Tests whether ``self`` contains an induced odd hole. - :meth:`~Graph.is_even_hole_free` | Tests whether ``self`` contains an induced even hole. - :meth:`~Graph.is_cartesian_product` | Tests whether ``self`` is a cartesian product of graphs. - :meth:`~Graph.is_long_hole_free` | Tests whether ``self`` contains an induced cycle of length at least 5. - :meth:`~Graph.is_long_antihole_free` | Tests whether ``self`` contains an induced anticycle of length at least 5. - :meth:`~Graph.is_weakly_chordal` | Tests whether ``self`` is weakly chordal. - :meth:`~Graph.is_strongly_regular` | Tests whether ``self`` is strongly regular. - :meth:`~Graph.is_distance_regular` | Tests whether ``self`` is distance-regular. - :meth:`~Graph.is_tree` | Return True if the graph is a tree. - :meth:`~Graph.is_forest` | Return True if the graph is a forest, i.e. a disjoint union of trees. - :meth:`~Graph.is_overfull` | Tests whether the current graph is overfull. - :meth:`~Graph.odd_girth` | Returns the odd girth of ``self``. - :meth:`~Graph.is_edge_transitive` | Returns true if self is edge-transitive. - :meth:`~Graph.is_arc_transitive` | Returns true if self is arc-transitive. - :meth:`~Graph.is_half_transitive` | Returns true if self is a half-transitive graph. - :meth:`~Graph.is_semi_symmetric` | Returns true if self is a semi-symmetric graph. - -**Connectivity, orientations, trees:** - -.. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - :meth:`~Graph.gomory_hu_tree` | Returns a Gomory-Hu tree of self. - :meth:`~Graph.minimum_outdegree_orientation` | Returns an orientation of ``self`` with the smallest possible maximum outdegree - :meth:`~Graph.bounded_outdegree_orientation` | Computes an orientation of ``self`` such that every vertex `v` has out-degree less than `b(v)` - :meth:`~Graph.strong_orientation` | Returns a strongly connected orientation of the current graph. - :meth:`~Graph.degree_constrained_subgraph` | Returns a degree-constrained subgraph. - :meth:`~Graph.bridges` | Returns the list of all bridges. - :meth:`~Graph.spanning_trees` | Returns the list of all spanning trees. - :meth:`~Graph.random_spanning_tree` | Returns a random spanning tree. - -**Clique-related methods:** - -.. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - :meth:`~Graph.clique_complex` | Returns the clique complex of self - :meth:`~Graph.cliques_containing_vertex` | Returns the cliques containing each vertex - :meth:`~Graph.cliques_vertex_clique_number` | Returns a dictionary of sizes of the largest maximal cliques containing each vertex - :meth:`~Graph.cliques_get_clique_bipartite` | Returns a bipartite graph constructed such that maximal cliques are the right vertices and the left vertices are retained from the given graph - :meth:`~Graph.cliques_get_max_clique_graph` | Returns a graph constructed with maximal cliques as vertices, and edges between maximal cliques sharing vertices. - :meth:`~Graph.cliques_number_of` | Returns a dictionary of the number of maximal cliques containing each vertex, keyed by vertex. - :meth:`~Graph.clique_number` | Returns the order of the largest clique of the graph. - :meth:`~Graph.clique_maximum` | Returns the vertex set of a maximal order complete subgraph. - :meth:`~Graph.cliques_maximum` | Returns the list of all maximum cliques - :meth:`~Graph.cliques_maximal` | Returns the list of all maximal cliques - :meth:`~Graph.clique_polynomial` | Returns the clique polynomial - -**Algorithmically hard stuff:** - -.. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - :meth:`~Graph.vertex_cover` | Returns a minimum vertex cover. - :meth:`~Graph.independent_set` | Returns a maximum independent set. - :meth:`~Graph.topological_minor` | Returns a topological `H`-minor of ``self`` if one exists. - :meth:`~Graph.convexity_properties` | Returns a ``ConvexityProperties`` object corresponding to ``self``. - :meth:`~Graph.matching_polynomial` | Computes the matching polynomial. - :meth:`~Graph.rank_decomposition` | Returns an rank-decomposition of ``self`` achieving optiml rank-width. - :meth:`~Graph.minor` | Returns the vertices of a minor isomorphic to `H`. - :meth:`~Graph.independent_set_of_representatives` | Returns an independent set of representatives. - :meth:`~Graph.coloring` | Returns the first (optimal) proper vertex-coloring found. - :meth:`~Graph.has_homomorphism_to` | Checks whether there is a morphism between two graphs. - :meth:`~Graph.chromatic_number` | Returns the minimal number of colors needed to color the vertices. - :meth:`~Graph.chromatic_polynomial` | Returns the chromatic polynomial. - :meth:`~Graph.chromatic_symmetric_function` | Return the chromatic symmetric function. - :meth:`~Graph.tutte_polynomial` | Returns the Tutte polynomial. - :meth:`~Graph.is_perfect` | Tests whether the graph is perfect. - :meth:`~Graph.treewidth` | Computes the tree-width and provides a decomposition. - - -**Leftovers:** - -.. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - :meth:`~Graph.cores` | Returns the core number for each vertex in an ordered list. - :meth:`~Graph.matching` | Returns a maximum weighted matching of the graph - :meth:`~Graph.fractional_chromatic_index` | Computes the fractional chromatic index. - :meth:`~Graph.lovasz_theta` | Returns the Lovasz number (a.k.a theta). - :meth:`~Graph.kirchhoff_symanzik_polynomial` | Returns the Kirchhoff-Symanzik polynomial. - :meth:`~Graph.modular_decomposition` | Returns the modular decomposition. - :meth:`~Graph.maximum_average_degree` | Returns the Maximum Average Degree (MAD). - :meth:`~Graph.two_factor_petersen` | Returns a decomposition of the graph into 2-factors. - :meth:`~Graph.ihara_zeta_function_inverse` | Returns the inverse of the zeta function. +{INDEX_OF_METHODS} AUTHORS: @@ -550,7 +416,7 @@ from sage.graphs.digraph import DiGraph from sage.graphs.independent_sets import IndependentSets from sage.combinat.combinatorial_map import combinatorial_map - +from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index class Graph(GenericGraph): r""" @@ -1603,6 +1469,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self._immutable = True ### Formats + + @doc_index("Basic methods") def graph6_string(self): """ Returns the graph6 representation of the graph as an ASCII string. @@ -1630,6 +1498,7 @@ def graph6_string(self): else: return generic_graph_pyx.small_integer_to_graph6(n) + generic_graph_pyx.binary_string_to_graph6(self._bit_vector()) + @doc_index("Basic methods") def sparse6_string(self): r""" Returns the sparse6 representation of the graph as an ASCII string. @@ -1718,6 +1587,7 @@ def sparse6_string(self): ### Attributes @combinatorial_map(name="partition of connected components") + @doc_index("Deprecated") def to_partition(self): """ Return the partition of connected components of ``self``. @@ -1738,6 +1608,7 @@ def to_partition(self): from sage.combinat.partition import Partition return Partition(sorted([len(y) for y in self.connected_components()], reverse=True)) + @doc_index("Basic methods") def is_directed(self): """ Since graph is undirected, returns False. @@ -1749,6 +1620,7 @@ def is_directed(self): """ return False + @doc_index("Connectivity, orientations, trees") def bridges(self): r""" Returns a list of the bridges (or cut edges). @@ -1774,6 +1646,7 @@ def bridges(self): bridges.extend(gs.edge_boundary(scc)) return bridges + @doc_index("Connectivity, orientations, trees") def spanning_trees(self): """ Returns a list of all spanning trees. @@ -1859,6 +1732,7 @@ def _recursive_spanning_trees(G,forest): return [] ### Properties + @doc_index("Graph properties") def is_tree(self, certificate=False, output='vertex'): """ Tests if the graph is a tree @@ -1989,6 +1863,7 @@ def vertices_to_edges(x): else: return self.num_verts() == self.num_edges() + 1 + @doc_index("Graph properties") def is_forest(self, certificate=False, output='vertex'): """ Tests if the graph is a forest, i.e. a disjoint union of trees. @@ -2040,6 +1915,7 @@ def is_forest(self, certificate=False, output='vertex'): if not isit: return (False, cycle) + @doc_index("Graph properties") def is_overfull(self): r""" Tests whether the current graph is overfull. @@ -2139,6 +2015,7 @@ def is_overfull(self): return (self.order() % 2 == 1) and ( 2 * self.size() > max(self.degree()) * (self.order() - 1)) + @doc_index("Graph properties") def is_even_hole_free(self, certificate = False): r""" Tests whether ``self`` contains an induced even hole. @@ -2247,6 +2124,7 @@ def is_even_hole_free(self, certificate = False): return True + @doc_index("Graph properties") def is_odd_hole_free(self, certificate = False): r""" Tests whether ``self`` contains an induced odd hole. @@ -2326,6 +2204,7 @@ def is_odd_hole_free(self, certificate = False): return True + @doc_index("Graph properties") def is_bipartite(self, certificate = False): """ Returns ``True`` if graph `G` is bipartite, ``False`` if not. @@ -2406,6 +2285,7 @@ def is_bipartite(self, certificate = False): else: return True + @doc_index("Graph properties") def is_triangle_free(self, algorithm='bitset'): r""" Returns whether ``self`` is triangle-free @@ -2497,6 +2377,7 @@ def is_triangle_free(self, algorithm='bitset'): else: raise ValueError("Algorithm '%s' not yet implemented. Please contribute." %(algorithm)) + @doc_index("Graph properties") def is_split(self): r""" Returns ``True`` if the graph is a Split graph, ``False`` otherwise. @@ -2570,6 +2451,7 @@ def is_split(self): return left == right + @doc_index("Algorithmically hard stuff") def treewidth(self,k=None,certificate=False): r""" Computes the tree-width of `G` (and provides a decomposition) @@ -2784,6 +2666,7 @@ def rec(cut,cc): return G + @doc_index("Algorithmically hard stuff") def is_perfect(self, certificate = False): r""" Tests whether the graph is perfect. @@ -2912,6 +2795,7 @@ def is_perfect(self, certificate = False): return self_complement.is_odd_hole_free(certificate = certificate) + @doc_index("Graph properties") def odd_girth(self): r""" Returns the odd girth of self. @@ -2979,6 +2863,7 @@ def odd_girth(self): return Infinity + @doc_index("Graph properties") def is_edge_transitive(self): """ Returns true if self is an edge transitive graph. @@ -3025,6 +2910,7 @@ def is_edge_transitive(self): return gap("OrbitLength("+str(A._gap_())+",Set(" + str(e) + "),OnSets);") == self.size() + @doc_index("Graph properties") def is_arc_transitive(self): """ Returns true if self is an arc-transitive graph @@ -3067,6 +2953,7 @@ def is_arc_transitive(self): return gap("OrbitLength("+str(A._gap_())+",Set(" + str(e) + "),OnTuples);") == 2*self.size() + @doc_index("Graph properties") def is_half_transitive(self): """ Returns true if self is a half-transitive graph. @@ -3106,6 +2993,7 @@ def is_half_transitive(self): self.is_vertex_transitive() and not self.is_arc_transitive()) + @doc_index("Graph properties") def is_semi_symmetric(self): """ Returns true if self is semi-symmetric. @@ -3150,6 +3038,7 @@ def is_semi_symmetric(self): self.is_edge_transitive() and not self.is_vertex_transitive()) + @doc_index("Connectivity, orientations, trees") def degree_constrained_subgraph(self, bounds=None, solver=None, verbose=0): r""" Returns a degree-constrained subgraph. @@ -3248,6 +3137,7 @@ def degree_constrained_subgraph(self, bounds=None, solver=None, verbose=0): ### Orientations + @doc_index("Connectivity, orientations, trees") def strong_orientation(self): r""" Returns a strongly connected orientation of the current graph. See @@ -3354,6 +3244,7 @@ def strong_orientation(self): return d + @doc_index("Connectivity, orientations, trees") def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verbose=0): r""" Returns an orientation of ``self`` with the smallest possible maximum @@ -3462,6 +3353,7 @@ def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verb return O + @doc_index("Connectivity, orientations, trees") def bounded_outdegree_orientation(self, bound): r""" Computes an orientation of ``self`` such that every vertex `v` @@ -3619,6 +3511,7 @@ def bounded_outdegree_orientation(self, bound): ### Coloring + @doc_index("Basic methods") def bipartite_color(self): """ Returns a dictionary with vertices as the keys and the color class @@ -3640,6 +3533,7 @@ def bipartite_color(self): else: raise RuntimeError("Graph is not bipartite.") + @doc_index("Basic methods") def bipartite_sets(self): """ Returns `(X,Y)` where `X` and `Y` are the nodes in each bipartite set of @@ -3666,6 +3560,7 @@ def bipartite_sets(self): return left, right + @doc_index("Algorithmically hard stuff") def chromatic_number(self, algorithm="DLX", verbose = 0): r""" Returns the minimal number of colors needed to color the vertices @@ -3765,6 +3660,7 @@ def chromatic_number(self, algorithm="DLX", verbose = 0): else: raise ValueError("The 'algorithm' keyword must be set to either 'DLX', 'MILP' or 'CP'.") + @doc_index("Algorithmically hard stuff") def coloring(self, algorithm="DLX", hex_colors=False, verbose = 0): r""" Returns the first (optimal) proper vertex-coloring found. @@ -3839,6 +3735,7 @@ def coloring(self, algorithm="DLX", hex_colors=False, verbose = 0): else: raise ValueError("The 'algorithm' keyword must be set to either 'DLX' or 'MILP'.") + @doc_index("Algorithmically hard stuff") def chromatic_symmetric_function(self, R=None): r""" Return the chromatic symmetric function of ``self``. @@ -3912,6 +3809,7 @@ def chromatic_symmetric_function(self, R=None): ret += (-1)**len(F) * p[la] return ret + @doc_index("Leftovers") def matching(self, value_only=False, algorithm="Edmonds", use_edge_labels=True, solver=None, verbose=0): r""" Returns a maximum weighted matching of the graph @@ -4052,6 +3950,7 @@ def matching(self, value_only=False, algorithm="Edmonds", use_edge_labels=True, else: raise ValueError('algorithm must be set to either "Edmonds" or "LP"') + @doc_index("Algorithmically hard stuff") def has_homomorphism_to(self, H, core = False, solver = None, verbose = 0): r""" Checks whether there is a homomorphism between two graphs. @@ -4159,6 +4058,7 @@ def has_homomorphism_to(self, H, core = False, solver = None, verbose = 0): except MIPSolverException: return False + @doc_index("Leftovers") def fractional_chromatic_index(self, solver = None, verbose_constraints = 0, verbose = 0): r""" Computes the fractional chromatic index of ``self`` @@ -4279,6 +4179,7 @@ def fractional_chromatic_index(self, solver = None, verbose_constraints = 0, ver # Accomplished ! return obj + @doc_index("Leftovers") def maximum_average_degree(self, value_only=True, solver = None, verbose = 0): r""" Returns the Maximum Average Degree (MAD) of the current graph. @@ -4384,6 +4285,7 @@ def maximum_average_degree(self, value_only=True, solver = None, verbose = 0): else: return g_mad + @doc_index("Algorithmically hard stuff") def independent_set_of_representatives(self, family, solver=None, verbose=0): r""" Returns an independent set of representatives. @@ -4512,6 +4414,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0): return repr + @doc_index("Algorithmically hard stuff") def minor(self, H, solver=None, verbose=0): r""" Returns the vertices of a minor isomorphic to `H` in the current graph. @@ -4677,6 +4580,7 @@ def minor(self, H, solver=None, verbose=0): ### Convexity + @doc_index("Algorithmically hard stuff") def convexity_properties(self): r""" Returns a ``ConvexityProperties`` object corresponding to ``self``. @@ -4718,6 +4622,7 @@ def convexity_properties(self): return ConvexityProperties(self) # Centrality + @doc_index("Distances") def centrality_degree(self, v=None): r""" Returns the degree centrality of a vertex. @@ -4763,6 +4668,7 @@ def centrality_degree(self, v=None): else: return self.degree(v)/n_minus_one + @doc_index("Distances") def centrality_closeness(self, v=None): r""" Returns the closeness centrality of a vertex. @@ -4814,6 +4720,7 @@ def centrality_closeness(self, v=None): ### Constructors + @doc_index("Basic methods") def to_directed(self, implementation='c_graph', data_structure=None, sparse=None): """ @@ -4884,6 +4791,7 @@ def to_directed(self, implementation='c_graph', data_structure=None, return D + @doc_index("Basic methods") def to_undirected(self): """ Since the graph is already undirected, simply returns a copy of @@ -4896,6 +4804,7 @@ def to_undirected(self): """ return self.copy() + @doc_index("Basic methods") def join(self, other, verbose_relabel=None, labels="pairs"): """ Returns the join of self and other. @@ -4966,6 +4875,7 @@ def join(self, other, verbose_relabel=None, labels="pairs"): ### Visualization + @doc_index("Basic methods") def write_to_eps(self, filename, **options): r""" Writes a plot of the graph to ``filename`` in ``eps`` format. @@ -4998,6 +4908,7 @@ def write_to_eps(self, filename, **options): f.write( print_graph_eps(self.vertices(), self.edge_iterator(), pos) ) f.close() + @doc_index("Algorithmically hard stuff") def topological_minor(self, H, vertices = False, paths = False, solver=None, verbose=0): r""" Returns a topological `H`-minor from ``self`` if one exists. @@ -5229,6 +5140,7 @@ def topological_minor(self, H, vertices = False, paths = False, solver=None, ver ### Cliques + @doc_index("Clique-related methods") def cliques_maximal(self, algorithm = "native"): """ Returns the list of all maximal cliques, with each clique represented @@ -5304,6 +5216,7 @@ def cliques_maximal(self, algorithm = "native"): else: raise ValueError("Algorithm must be equal to 'native' or to 'NetworkX'.") + @doc_index("Clique-related methods") def clique_maximum(self, algorithm="Cliquer"): """ Returns the vertex set of a maximal order complete subgraph. @@ -5374,6 +5287,7 @@ def clique_maximum(self, algorithm="Cliquer"): else: raise NotImplementedError("Only 'MILP', 'Cliquer' and 'mcqd' are supported.") + @doc_index("Clique-related methods") def clique_number(self, algorithm="Cliquer", cliques=None): r""" Returns the order of the largest clique of the graph (the clique @@ -5464,6 +5378,7 @@ def clique_number(self, algorithm="Cliquer", cliques=None): else: raise NotImplementedError("Only 'networkx' 'MILP' 'Cliquer' and 'mcqd' are supported.") + @doc_index("Clique-related methods") def cliques_number_of(self, vertices=None, cliques=None): """ Returns a dictionary of the number of maximal cliques containing each @@ -5514,6 +5429,7 @@ def cliques_number_of(self, vertices=None, cliques=None): import networkx return networkx.number_of_cliques(self.networkx_graph(copy=False), vertices, cliques) + @doc_index("Clique-related methods") def cliques_get_max_clique_graph(self, name=''): """ Returns a graph constructed with maximal cliques as vertices, and @@ -5545,6 +5461,7 @@ def cliques_get_max_clique_graph(self, name=''): import networkx return Graph(networkx.make_max_clique_graph(self.networkx_graph(copy=False), name=name, create_using=networkx.MultiGraph())) + @doc_index("Clique-related methods") def cliques_get_clique_bipartite(self, **kwds): """ Returns a bipartite graph constructed such that maximal cliques are the @@ -5572,6 +5489,7 @@ def cliques_get_clique_bipartite(self, **kwds): import networkx return BipartiteGraph(networkx.make_clique_bipartite(self.networkx_graph(copy=False), **kwds)) + @doc_index("Algorithmically hard stuff") def independent_set(self, algorithm = "Cliquer", value_only = False, reduction_rules = True, solver = None, verbosity = 0): r""" Returns a maximum independent set. @@ -5661,6 +5579,7 @@ def independent_set(self, algorithm = "Cliquer", value_only = False, reduction_r return [u for u in self.vertices() if not u in my_cover] + @doc_index("Algorithmically hard stuff") def vertex_cover(self, algorithm = "Cliquer", value_only = False, reduction_rules = True, solver = None, verbosity = 0): r""" @@ -5945,6 +5864,7 @@ def vertex_cover(self, algorithm = "Cliquer", value_only = False, cover_g.sort() return cover_g + @doc_index("Clique-related methods") def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None, cliques=None): """ @@ -6016,6 +5936,7 @@ def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None, else: raise NotImplementedError("Only 'networkx' and 'cliquer' are supported.") + @doc_index("Clique-related methods") def cliques_containing_vertex(self, vertices=None, cliques=None): """ Returns the cliques containing each vertex, represented as a dictionary @@ -6066,6 +5987,7 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): import networkx return networkx.cliques_containing_node(self.networkx_graph(copy=False),vertices, cliques) + @doc_index("Clique-related methods") def clique_complex(self): """ Returns the clique complex of self. This is the largest simplicial complex on @@ -6097,6 +6019,7 @@ def clique_complex(self): C._graph = self return C + @doc_index("Clique-related methods") def clique_polynomial(self, t = None): """ Returns the clique polynomial of self. @@ -6128,6 +6051,7 @@ def clique_polynomial(self, t = None): ### Miscellaneous + @doc_index("Leftovers") def cores(self, k = None, with_labels=False): """ Returns the core number for each vertex in an ordered list. @@ -6285,6 +6209,7 @@ def cores(self, k = None, with_labels=False): else: return core.values() + @doc_index("Leftovers") def modular_decomposition(self): r""" Returns the modular decomposition of the current graph. @@ -6427,6 +6352,7 @@ def modular_decomposition(self): return relabel(D) + @doc_index("Graph properties") def is_prime(self): r""" Tests whether the current graph is prime. @@ -6554,6 +6480,7 @@ def _gomory_hu_tree(self, vertices, method="FF"): return g + @doc_index("Connectivity, orientations, trees") def gomory_hu_tree(self, method="FF"): r""" Returns a Gomory-Hu tree of self. @@ -6648,6 +6575,7 @@ def gomory_hu_tree(self, method="FF"): g.set_pos(dict(self.get_pos())) return g + @doc_index("Leftovers") def two_factor_petersen(self): r""" Returns a decomposition of the graph into 2-factors. @@ -6717,6 +6645,7 @@ def two_factor_petersen(self): return classes_b + @doc_index("Leftovers") def kirchhoff_symanzik_polynomial(self, name='t'): """ Return the Kirchhoff-Symanzik polynomial of a graph. @@ -6816,6 +6745,7 @@ def kirchhoff_symanzik_polynomial(self, name='t'): D = matrix.diagonal(PolynomialRing(ZZ, name, self.size()).gens()) return (circuit_mtrx.transpose() * D * circuit_mtrx).determinant() + @doc_index("Leftovers") def ihara_zeta_function_inverse(self): """ Compute the inverse of the Ihara zeta function of the graph @@ -6890,43 +6820,63 @@ def ihara_zeta_function_inverse(self): import types import sage.graphs.weakly_chordal -Graph.is_long_hole_free = types.MethodType(sage.graphs.weakly_chordal.is_long_hole_free, None, Graph) -Graph.is_long_antihole_free = types.MethodType(sage.graphs.weakly_chordal.is_long_antihole_free, None, Graph) -Graph.is_weakly_chordal = types.MethodType(sage.graphs.weakly_chordal.is_weakly_chordal, None, Graph) +Graph.is_long_hole_free = types.MethodType(sage.graphs.weakly_chordal.is_long_hole_free, None, Graph) +Graph.is_long_antihole_free = types.MethodType(sage.graphs.weakly_chordal.is_long_antihole_free, None, Graph) +Graph.is_weakly_chordal = types.MethodType(sage.graphs.weakly_chordal.is_weakly_chordal, None, Graph) import sage.graphs.asteroidal_triples Graph.is_asteroidal_triple_free = types.MethodType(sage.graphs.asteroidal_triples.is_asteroidal_triple_free, None, Graph) import sage.graphs.chrompoly -Graph.chromatic_polynomial = types.MethodType(sage.graphs.chrompoly.chromatic_polynomial, None, Graph) +Graph.chromatic_polynomial = types.MethodType(sage.graphs.chrompoly.chromatic_polynomial, None, Graph) import sage.graphs.graph_decompositions.rankwidth -Graph.rank_decomposition = types.MethodType(sage.graphs.graph_decompositions.rankwidth.rank_decomposition, None, Graph) +Graph.rank_decomposition = types.MethodType(sage.graphs.graph_decompositions.rankwidth.rank_decomposition, None, Graph) import sage.graphs.matchpoly -Graph.matching_polynomial = types.MethodType(sage.graphs.matchpoly.matching_polynomial, None, Graph) +Graph.matching_polynomial = types.MethodType(sage.graphs.matchpoly.matching_polynomial, None, Graph) import sage.graphs.cliquer -Graph.cliques_maximum = types.MethodType(sage.graphs.cliquer.all_max_clique, None, Graph) +Graph.cliques_maximum = types.MethodType(sage.graphs.cliquer.all_max_clique, None, Graph) import sage.graphs.spanning_tree -Graph.random_spanning_tree = types.MethodType(sage.graphs.spanning_tree.random_spanning_tree, None, Graph) +Graph.random_spanning_tree = types.MethodType(sage.graphs.spanning_tree.random_spanning_tree, None, Graph) import sage.graphs.graph_decompositions.graph_products -Graph.is_cartesian_product = types.MethodType(sage.graphs.graph_decompositions.graph_products.is_cartesian_product, None, Graph) +Graph.is_cartesian_product = types.MethodType(sage.graphs.graph_decompositions.graph_products.is_cartesian_product, None, Graph) import sage.graphs.distances_all_pairs -Graph.is_distance_regular = types.MethodType(sage.graphs.distances_all_pairs.is_distance_regular, None, Graph) +Graph.is_distance_regular = types.MethodType(sage.graphs.distances_all_pairs.is_distance_regular, None, Graph) import sage.graphs.base.static_dense_graph -Graph.is_strongly_regular = types.MethodType(sage.graphs.base.static_dense_graph.is_strongly_regular, None, Graph) +Graph.is_strongly_regular = types.MethodType(sage.graphs.base.static_dense_graph.is_strongly_regular, None, Graph) # From Python modules import sage.graphs.line_graph -Graph.is_line_graph = sage.graphs.line_graph.is_line_graph +Graph.is_line_graph = sage.graphs.line_graph.is_line_graph from sage.graphs.tutte_polynomial import tutte_polynomial -Graph.tutte_polynomial = tutte_polynomial +Graph.tutte_polynomial = tutte_polynomial from sage.graphs.lovasz_theta import lovasz_theta -Graph.lovasz_theta = lovasz_theta +Graph.lovasz_theta = lovasz_theta + +_additional_categories = { + Graph.is_long_hole_free : "Graph properties", + Graph.is_long_antihole_free : "Graph properties", + Graph.is_weakly_chordal : "Graph properties", + Graph.is_asteroidal_triple_free : "Graph properties", + Graph.chromatic_polynomial : "Algorithmically hard stuff", + Graph.rank_decomposition : "Algorithmically hard stuff", + Graph.matching_polynomial : "Algorithmically hard stuff", + Graph.cliques_maximum : "Clique-related methods", + Graph.random_spanning_tree : "Connectivity, orientations, trees", + Graph.is_cartesian_product : "Graph properties", + Graph.is_distance_regular : "Graph properties", + Graph.is_strongly_regular : "Graph properties", + Graph.is_line_graph : "Graph properties", + Graph.tutte_polynomial : "Algorithmically hard stuff", + Graph.lovasz_theta : "Leftovers", + } + +__doc__ = __doc__.replace("{INDEX_OF_METHODS}",gen_thematic_rest_table_index(Graph,_additional_categories)) diff --git a/src/sage/misc/rest_index_of_methods.py b/src/sage/misc/rest_index_of_methods.py index 6c74764b983..7a4f19f69d1 100644 --- a/src/sage/misc/rest_index_of_methods.py +++ b/src/sage/misc/rest_index_of_methods.py @@ -7,7 +7,7 @@ {INDEX_OF_FUNCTIONS} """ -def gen_rest_table_index(list_of_entries, sort=True, only_local_functions=True): +def gen_rest_table_index(list_of_entries, names=None, sort=True, only_local_functions=True): r""" Return a ReST table describing a list of functions. @@ -24,6 +24,10 @@ def gen_rest_table_index(list_of_entries, sort=True, only_local_functions=True): deprecated or those starting with an underscore. In the case of a class, note that inherited methods are not displayed. + - ``names`` -- a dictionary associating a name to a function. Takes + precedence over the automatically computed name for the functions. Only + used when ``list_of_entries`` is a list. + - ``sort`` (boolean; ``True``) -- whether to sort the list of methods lexicographically. @@ -51,7 +55,12 @@ def gen_rest_table_index(list_of_entries, sort=True, only_local_functions=True): :widths: 30, 70 :delim: | - :func:`~sage.misc.rest_index_of_methods.gen_rest_table_index` | Return a ReST table describing a list of functions... + :func:`~sage.misc.rest_index_of_methods.doc_index` | Attribute an index name to a function. + :func:`~sage.misc.rest_index_of_methods.gen_rest_table_index` | Return a ReST table describing a list of functions. + :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` | Return a ReST string of thematically sorted function (or methods) of a module (or class). + :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` | Returns the functions (resp. methods) of a given module (resp. class) with their names. + + The table of a class:: @@ -85,33 +94,43 @@ def gen_rest_table_index(list_of_entries, sort=True, only_local_functions=True): :widths: 30, 70 :delim: | - :func:`~sage.misc.rest_index_of_methods.gen_rest_table_index` | Return a ReST table describing a list of functions... + :func:`~sage.misc.rest_index_of_methods.doc_index` | Attribute an index name to a function. + :func:`~sage.misc.rest_index_of_methods.gen_rest_table_index` | Return a ReST table describing a list of functions. + :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` | Return a ReST string of thematically sorted function (or methods) of a module (or class). + :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` | Returns the functions (resp. methods) of a given module (resp. class) with their names. + + sage: print gen_rest_table_index(sage.misc.rest_index_of_methods, only_local_functions=False) .. csv-table:: :class: contentstable :widths: 30, 70 :delim: | + + :func:`~sage.misc.rest_index_of_methods.doc_index` | Attribute an index name to a function. + :func:`~sage.misc.rest_index_of_methods.gen_thematic_rest_table_index` | Return a ReST string of thematically sorted function (or methods) of a module (or class). + :func:`~sage.misc.rest_index_of_methods.list_of_subfunctions` | Returns the functions (resp. methods) of a given module (resp. class) with their names. + A function that is imported into a class under a different name is listed + under its 'new' name:: + + sage: 'cliques_maximum' in gen_rest_table_index(Graph) + True + sage: 'all_max_cliques`' in gen_rest_table_index(Graph) + False """ import inspect + if names is None: + names = {} # If input is a class/module, we list all its non-private and methods/functions if (inspect.isclass(list_of_entries) or inspect.ismodule(list_of_entries)): root = list_of_entries - def local_filter(f,name): - if only_local_functions: - return inspect.getmodule(root) == inspect.getmodule(f) - else: - return inspect.isclass(list_of_entries) or not (f is gen_rest_table_index) - list_of_entries = [getattr(root,name) for name,f in root.__dict__.items() if - (not name.startswith('_') and # private functions - not hasattr(f,'trac_number') and # deprecated functions - not inspect.isclass(f) and # classes - local_filter(f,name) # possibly filter imported functions - )] + list_of_entries,names = list_of_subfunctions(root, only_local_functions=only_local_functions) + + fname = lambda x:names.get(x,getattr(x,"__name__","")) assert isinstance(list_of_entries,list) @@ -121,14 +140,14 @@ def local_filter(f,name): " :delim: |\n\n") if sort: - list_of_entries.sort(key=lambda x:getattr(x,'__name__','')) + list_of_entries.sort(key=fname) for e in list_of_entries: if inspect.ismethod(e): - link = ":meth:`~"+str(e.im_class.__module__)+"."+str(e.im_class.__name__)+"."+e.__name__+"`" + link = ":meth:`~"+str(e.im_class.__module__)+"."+str(e.im_class.__name__)+"."+fname(e)+"`" elif inspect.isfunction(e): - link = ":func:`~"+str(e.__module__)+"."+str(e.__name__)+"`" + link = ":func:`~"+str(e.__module__)+"."+fname(e)+"`" else: continue @@ -143,4 +162,120 @@ def local_filter(f,name): return s+'\n' +def list_of_subfunctions(root, only_local_functions=True): + r""" + Returns the functions (resp. methods) of a given module (resp. class) with their names. + + INPUT: + + - ``root`` -- the module, or class, whose elements are to be listed. + + - ``only_local_functions`` (boolean; ``True``) -- if ``root`` is a module, + ``only_local_functions = True`` means that imported functions will be + filtered out. This can be useful to disable for making indexes of + e.g. catalog modules such as :mod:`sage.coding.codes_catalog`. + + OUTPUT: + + A pair ``(list,dict)`` where ``list`` is a list of function/methods and + ``dict`` associates to every function/method the name under which it appears + in ``root``. + + EXAMPLE:: + + sage: from sage.misc.rest_index_of_methods import list_of_subfunctions + sage: l = list_of_subfunctions(Graph)[0] + sage: Graph.bipartite_color in l + True + """ + import inspect + if inspect.ismodule(root): + ismodule = True + elif inspect.isclass(root): + ismodule = False + superclasses = inspect.getmro(root)[1:] + else: + raise ValueError("'root' must be a module or a class.") + + def local_filter(f,name): + if only_local_functions: + if ismodule: + return inspect.getmodule(root) == inspect.getmodule(f) + else: + return not any(hasattr(s,name) for s in superclasses) + else: + return inspect.isclass(root) or not (f is gen_rest_table_index) + + functions = {getattr(root,name):name for name,f in root.__dict__.items() if + (not name.startswith('_') and # private functions + not hasattr(f,'trac_number') and # deprecated functions + not inspect.isclass(f) and # classes + callable(f) and # e.g. GenericGraph.graphics_array_defaults + local_filter(f,name)) # possibly filter imported functions + } + return functions.keys(),functions + +def gen_thematic_rest_table_index(root,additional_categories=None,only_local_functions=True): + r""" + Return a ReST string of thematically sorted function (or methods) of a module (or class). + + INPUT: + + - ``root`` -- the module, or class, whose elements are to be listed. + + - ``additional_categories`` -- a dictionary associating a category (given as + a string) to a function's name. Can be used when the decorator + :func:`doc_index` does not work on a function. + + - ``only_local_functions`` (boolean; ``True``) -- if ``root`` is a module, + ``only_local_functions = True`` means that imported functions will be + filtered out. This can be useful to disable for making indexes of + e.g. catalog modules such as :mod:`sage.coding.codes_catalog`. + + EXAMPLE:: + + sage: from sage.misc.rest_index_of_methods import gen_thematic_rest_table_index, list_of_subfunctions + sage: l = list_of_subfunctions(Graph)[0] + sage: Graph.bipartite_color in l + True + """ + from collections import defaultdict + if additional_categories is None: + additional_categories = {} + + functions,names = list_of_subfunctions(root,only_local_functions=only_local_functions) + theme_to_function = defaultdict(list) + for f in functions: + theme_to_function[getattr(f,"doc_index",additional_categories.get(f,"Unsorted"))].append(f) + s = ["**"+theme+"**\n\n"+gen_rest_table_index(list_of_functions,names=names) + for theme, list_of_functions in sorted(theme_to_function.items())] + return "\n\n".join(s) + +def doc_index(name): + r""" + Attribute an index name to a function. + + This decorator can be applied to a function/method in order to specify in + which index it must appear, in the index generated by + :func:`gen_thematic_rest_table_index`. + + INPUT: + + - ``name`` -- a string, which will become the title of the index in which + this function/method will appear. + + EXAMPLE:: + + sage: from sage.misc.rest_index_of_methods import doc_index + sage: @doc_index("Wouhouuuuu") + ....: def a(): + ....: print "Hey" + sage: a.doc_index + 'Wouhouuuuu' + """ + def hey(f): + setattr(f,"doc_index",name) + return f + return hey + __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index([gen_rest_table_index])) From 0bd214d4c5a76390a4d463f51ad6c1d4ea898af2 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 20 Aug 2015 17:47:34 +0200 Subject: [PATCH 0440/1872] collect asymptotic code in one directory --- .../asymptotic/growth_group.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/sage/{groups/asymptotic_growth_group.py => rings/asymptotic/growth_group.py} (100%) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/rings/asymptotic/growth_group.py similarity index 100% rename from src/sage/groups/asymptotic_growth_group.py rename to src/sage/rings/asymptotic/growth_group.py From 729998144922ac5dabf8e699818b1f3fe738ccce Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 20 Aug 2015 17:48:58 +0200 Subject: [PATCH 0441/1872] collect asymptotic code in one directory --- .../asymptotic/growth_group.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/sage/{groups/asymptotic_growth_group.py => rings/asymptotic/growth_group.py} (100%) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/rings/asymptotic/growth_group.py similarity index 100% rename from src/sage/groups/asymptotic_growth_group.py rename to src/sage/rings/asymptotic/growth_group.py From a2c8a6f72f9cca4f9ffab729d163e9733bdb1dc6 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 20 Aug 2015 17:56:34 +0200 Subject: [PATCH 0442/1872] collect asymptotic code in one directory --- src/sage/rings/{ => asymptotic}/asymptotic_ring.py | 0 .../asymptotic/growth_group.py} | 0 .../asymptotic_term_monoid.py => rings/asymptotic/term_monoid.py} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/sage/rings/{ => asymptotic}/asymptotic_ring.py (100%) rename src/sage/{groups/asymptotic_growth_group.py => rings/asymptotic/growth_group.py} (100%) rename src/sage/{monoids/asymptotic_term_monoid.py => rings/asymptotic/term_monoid.py} (100%) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py similarity index 100% rename from src/sage/rings/asymptotic_ring.py rename to src/sage/rings/asymptotic/asymptotic_ring.py diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/rings/asymptotic/growth_group.py similarity index 100% rename from src/sage/groups/asymptotic_growth_group.py rename to src/sage/rings/asymptotic/growth_group.py diff --git a/src/sage/monoids/asymptotic_term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py similarity index 100% rename from src/sage/monoids/asymptotic_term_monoid.py rename to src/sage/rings/asymptotic/term_monoid.py From f6c4d80aa67e622a0b3ef576b2abe29565cbf88e Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 20 Aug 2015 19:08:50 +0200 Subject: [PATCH 0443/1872] doctests fixed --- src/sage/rings/all.py | 2 +- src/sage/rings/asymptotic/all.py | 1 + src/sage/rings/asymptotic/asymptotic_ring.py | 52 ++++++++++---------- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index a7a19b490f6..aa03245686a 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -184,4 +184,4 @@ from sage.rings.contfrac import (CFF, ContinuedFractionField) # asymptotic ring -from asymptotic_ring import AsymptoticRing \ No newline at end of file +from asymptotic.all import AsymptoticRing \ No newline at end of file diff --git a/src/sage/rings/asymptotic/all.py b/src/sage/rings/asymptotic/all.py index e69de29bb2d..554d02cc4d7 100644 --- a/src/sage/rings/asymptotic/all.py +++ b/src/sage/rings/asymptotic/all.py @@ -0,0 +1 @@ +from asymptotic_ring import AsymptoticRing diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 33a0717547e..17aedfef6b5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -14,7 +14,7 @@ an :ref:`growth group `. - `O`-terms `O(g)` (see :wikipedia:`Big_O_notation`) for some - :mod:`growth group element ` + :mod:`growth group element ` `g` (:ref:`see below `). Examples of such elements can found :ref:`below `. @@ -25,7 +25,7 @@ --------------- The elements of a :mod:`growth group -` are equipped with a partial +` are equipped with a partial ordering and usually contains a variable. Examples are (among many other possibilities) @@ -59,8 +59,8 @@ TESTS:: - sage: import sage.groups.asymptotic_growth_group as agg - sage: import sage.monoids.asymptotic_term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.MonomialGrowthGroup(ZZ, 'x') doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change @@ -216,7 +216,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): At this point, `x` and `y` are already asymptotic expressions:: sage: type(x) - + The usual ring operations, but allowing rational exponents (growth group ``x^QQ``) can be performed:: @@ -299,8 +299,8 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): .. SEEALSO:: - :mod:`sage.groups.asymptotic_growth_group`, - :mod:`sage.monoids.asymptotic_term_monoid`, + :mod:`sage.rings.asymptotic.growth_group`, + :mod:`sage.rings.asymptotic.term_monoid`, :mod:`sage.data_structures.mutable_poset` """ def __init__(self, parent, summands, simplify=True): @@ -396,8 +396,8 @@ def _simplify_(self): TESTS:: - sage: import sage.groups.asymptotic_growth_group as agg - sage: import sage.monoids.asymptotic_term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: OT = atm.TermMonoid('O', G); ET = atm.TermMonoid('exact', G, ZZ) sage: R = AsymptoticRing(G, ZZ) @@ -515,7 +515,7 @@ def _mul_term_(self, term): INPUT: - ``term`` -- an asymptotic term (see - :mod:`~sage.monoids.asymptotic_term_monoid`). + :mod:`~sage.rings.asymptotic.term_monoid`). OUTPUT: @@ -523,7 +523,7 @@ def _mul_term_(self, term): TESTS:: - sage: import sage.monoids.asymptotic_term_monoid as atm + sage: import sage.rings.asymptotic.term_monoid as atm sage: R. = AsymptoticRing('x^ZZ', ZZ) sage: T = atm.OTermMonoid(R.growth_group) sage: expr = 10*x^2 + O(x) @@ -605,7 +605,7 @@ def __pow__(self, power): 'to the power of %s.' % (P.growth_group, self, power)) - from sage.monoids.asymptotic_term_monoid import TermWithCoefficient + from sage.rings.asymptotic.term_monoid import TermWithCoefficient expr = self.summands.elements().next() if isinstance(expr, TermWithCoefficient): new_growth = expr.growth**power @@ -666,9 +666,9 @@ class AsymptoticRing(sage.rings.ring.Ring, INPUT: - ``growth_group`` -- either a partially ordered group (see - :mod:`~sage.groups.asymptotic_growth_group`) or a string + :mod:`~sage.rings.asymptotic.growth_group`) or a string describing such a growth group (see - :class:`~sage.groups.asymptotic_growth_group.GrowthGroupFactory`). + :class:`~sage.rings.asymptotic.growth_group.GrowthGroupFactory`). - ``coefficient_ring`` -- the ring which contains the coefficients of the expressions. @@ -692,7 +692,7 @@ class AsymptoticRing(sage.rings.ring.Ring, This is equivalent to the following code, which explicitly specifies the underlying growth group:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: G_QQ = agg.GrowthGroup('x^QQ') sage: R2_x. = AsymptoticRing(growth_group=G_QQ, coefficient_ring=QQ); R2_x Asymptotic Ring over Rational Field @@ -709,7 +709,7 @@ class AsymptoticRing(sage.rings.ring.Ring, sage: R_log = AsymptoticRing('log(x)^ZZ', QQ); R_log Asymptotic Ring over Rational Field - Other growth groups are available. See :mod:`~sage.rings.asymptotic_ring` for + Other growth groups are available. See :mod:`~sage.rings.asymptotic.asymptotic_ring` for a lot more examples. Below there are some technical details. @@ -761,7 +761,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, are unique. Also, this enables the use of the generation framework:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: MG = agg.GrowthGroup('x^ZZ') sage: AR1 = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: AR2. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) @@ -777,7 +777,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, ValueError: Growth Group log(x)^ZZ does not have a generator. """ if isinstance(growth_group, str): - from sage.groups.asymptotic_growth_group import GrowthGroup + from sage.rings.asymptotic.growth_group import GrowthGroup growth_group = GrowthGroup(growth_group) if names is not None and not growth_group.gens_monomial(): @@ -846,7 +846,7 @@ def growth_group(self): .. SEEALSO:: - :mod:`sage.groups.asymptotic_growth_group` + :mod:`sage.rings.asymptotic.growth_group` """ return self._growth_group_ @@ -885,7 +885,7 @@ def _create_empty_summands_(): poset() """ from sage.data_structures.mutable_poset import MutablePoset - from sage.monoids.asymptotic_term_monoid import \ + from sage.rings.asymptotic.term_monoid import \ can_absorb, absorption return MutablePoset(key=lambda element: element.growth, can_merge=can_absorb, @@ -941,7 +941,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): if isinstance(data, AsymptoticExpression): return self.element_class(self, data.summands, simplify=simplify) - from sage.monoids.asymptotic_term_monoid import GenericTerm + from sage.rings.asymptotic.term_monoid import GenericTerm if isinstance(data, GenericTerm): data = (data,) @@ -1038,7 +1038,7 @@ def _repr_(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: MG = agg.GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: repr(AR) # indirect doctest @@ -1076,7 +1076,7 @@ def gens(self): sage: AR.gens() (x,) """ - from sage.groups.asymptotic_growth_group import MonomialGrowthGroup + from sage.rings.asymptotic.growth_group import MonomialGrowthGroup if isinstance(self.growth_group, MonomialGrowthGroup): return self.create_summand('exact', growth=self.growth_group.gen(), coefficient=1), @@ -1120,7 +1120,7 @@ def ngens(self): sage: AR.ngens() 1 """ - from sage.groups.asymptotic_growth_group import MonomialGrowthGroup + from sage.rings.asymptotic.growth_group import MonomialGrowthGroup if isinstance(self.growth_group, MonomialGrowthGroup): return 1 else: @@ -1147,7 +1147,7 @@ def create_summand(self, type, growth, **kwds): .. NOTE:: This method calls the factory :class:`TermMonoid - ` + ` with the appropriate arguments. EXAMPLES:: @@ -1158,7 +1158,7 @@ def create_summand(self, type, growth, **kwds): sage: R.create_summand('exact', growth=x^456, coefficient=123) 123*x^456 """ - from sage.monoids.asymptotic_term_monoid import TermMonoid + from sage.rings.asymptotic.term_monoid import TermMonoid TM = TermMonoid(type, self.growth_group, self.coefficient_ring) if type == 'exact' and kwds.get('coefficient') == 0: From c7afc80e1ff9218390aa501b8f1a94a517e0bab9 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 20 Aug 2015 19:09:01 +0200 Subject: [PATCH 0444/1872] building documentation fixed --- src/doc/en/reference/rings/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/reference/rings/index.rst b/src/doc/en/reference/rings/index.rst index 1171ec5aefb..7581608f295 100644 --- a/src/doc/en/reference/rings/index.rst +++ b/src/doc/en/reference/rings/index.rst @@ -26,7 +26,6 @@ General Rings, Ideals, and Morphisms sage/rings/fast_arith sage/rings/misc sage/rings/monomials - sage/rings/asymptotic_ring sage/rings/commutative_algebra sage/rings/commutative_algebra_element @@ -46,6 +45,7 @@ General Rings, Ideals, and Morphisms sage/rings/asymptotic/growth_group sage/rings/asymptotic/term_monoid + sage/rings/asymptotic/asymptotic_ring .. include:: ../footer.txt From 00175a1bd4d9a1868313c2f7b15f209bb01d7c08 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 20:40:30 +0200 Subject: [PATCH 0445/1872] collect asymptotic code in one directory --- .../asymptotic/growth_group.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/sage/{groups/asymptotic_growth_group.py => rings/asymptotic/growth_group.py} (100%) diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/rings/asymptotic/growth_group.py similarity index 100% rename from src/sage/groups/asymptotic_growth_group.py rename to src/sage/rings/asymptotic/growth_group.py From f959f4bff48f4b0b46857a6e43e06aa2ea809657 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 20:52:58 +0200 Subject: [PATCH 0446/1872] fix doctests after merge --- src/sage/rings/asymptotic/growth_group.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ecc4ffeb3b3..8ed00304fed 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -52,7 +52,7 @@ By using the following short notation for growth groups, their creation is very simple: *Monomial growth groups* (i.e. the group for powers of a fixed symbol; - :class:`~sage.groups.asymptotic_growth_group.MonomialGrowthGroup`) + :class:`~sage.rings.asymptotic.growth_group.MonomialGrowthGroup`) are denoted as ``variable^base``, e.g. ``x^ZZ`` and ``y^QQ`` for the group of integer powers of `x`, and the group of rational powers of `y`, respectively. @@ -65,7 +65,7 @@ EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: G_x = agg.GrowthGroup('x^ZZ'); repr(G_x) 'Growth Group x^ZZ' sage: G_xy = agg.GrowthGroup('x^ZZ * y^ZZ'); G_xy @@ -189,7 +189,7 @@ class CartesianProductGrowthGroups(CartesianProductPosets): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.MonomialGrowthGroup(QQ, 'x') sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') sage: C = cartesian_product([P, L], order='lex'); C @@ -221,7 +221,7 @@ def _element_constructor_(self, data): EXAMPLES:: - sage: from sage.groups.asymptotic_growth_group import GrowthGroup + sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ * y^ZZ') sage: G_log = GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ') @@ -307,7 +307,7 @@ def _repr_(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.MonomialGrowthGroup(QQ, 'x') sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') sage: cartesian_product([P, L], order='lex')._repr_() @@ -331,7 +331,7 @@ def _repr_short_(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.MonomialGrowthGroup(QQ, 'x') sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') sage: cartesian_product([P, L], order='lex')._repr_short_() @@ -356,7 +356,7 @@ def _convert_to_factor_(self, data): EXAMPLES:: - sage: from sage.groups.asymptotic_growth_group import GrowthGroup + sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ * log(x)^QQ * y^QQ') sage: e1 = G._convert_to_factor_(x^2) sage: (e1, e1.parent()) @@ -394,7 +394,7 @@ def gens_monomial(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ') sage: G.gens_monomial() (x, y) @@ -420,7 +420,7 @@ def _repr_(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.MonomialGrowthGroup(QQ, 'x') sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') sage: cartesian_product([P, L], order='lex').an_element()._repr_() From 67711dc98f7d3ba93666bd6ec9b43b0d44889ee3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 20 Aug 2015 20:58:24 +0200 Subject: [PATCH 0447/1872] move cartesian products to separate file --- src/sage/rings/asymptotic/growth_group.py | 254 +-------------- .../asymptotic/growth_group_cartesian.py | 295 ++++++++++++++++++ 2 files changed, 296 insertions(+), 253 deletions(-) create mode 100644 src/sage/rings/asymptotic/growth_group_cartesian.py diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 8ed00304fed..02e48ac097a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -103,6 +103,7 @@ #***************************************************************************** import sage +from sage.rings.asymptotic.growth_group_cartesian import CartesianProductGrowthGroups def repr_short_to_parent(s): r""" @@ -182,259 +183,6 @@ def parent_to_repr_short(P): return rep -from sage.sets.cartesian_product import CartesianProductPosets -class CartesianProductGrowthGroups(CartesianProductPosets): - r""" - A cartesian product of growth groups. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') - sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') - sage: C = cartesian_product([P, L], order='lex'); C - Growth Group x^QQ * log(x)^ZZ - sage: C.an_element() - x^(1/2) * log(x) - - :: - - sage: Px = agg.MonomialGrowthGroup(QQ, 'x') - sage: Lx = agg.MonomialGrowthGroup(ZZ, 'log(x)') - sage: Cx = cartesian_product([Px, Lx], order='lex') - sage: Py = agg.MonomialGrowthGroup(QQ, 'y') - sage: C = cartesian_product([Cx, Py], order='components'); C - Growth Group x^QQ * log(x)^ZZ * y^QQ - sage: C.an_element() - x^(1/2) * log(x) * y^(1/2) - - .. SEEALSO: - - :class:`~sage.sets.cartesian_product.CartesianProduct`, - :class:`~sage.sets.cartesian_product.CartesianProductPosets`. - """ - - def _element_constructor_(self, data): - r""" - Converts the given object to an element of this cartesian - product. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('x^ZZ * y^ZZ') - sage: G_log = GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ') - - Conversion from the symbolic ring works:: - - sage: x,y = var('x y') - sage: G(x^-3 * y^2) - x^(-3) * y^2 - sage: G(x^4), G(y^2) - (x^4, y^2) - sage: G(1) - 1 - - Even more complex expressions can be parsed:: - - sage: G_log(x^42 * log(x)^-42 * y^42) - x^42 * log(x)^(-42) * y^42 - - TESTS:: - - sage: G = GrowthGroup('x^ZZ * y^ZZ') - sage: G('x'), G('y') - (x, y) - - :: - - sage: G_log(log(x)) - log(x) - """ - if data == 1: - return self.one() - - if data is None: - raise ValueError('%s cannot be converted.' % (data,)) - - if isinstance(data, list): - try: - obj = super(CartesianProductGrowthGroups, - self)._element_constructor_(data) - return obj - except ValueError: - return self.prod(self(elem) for elem in data) - - if hasattr(data, 'parent'): - P = data.parent() - if P is self: - return data - - elif P is sage.symbolic.ring.SR: - import operator - from sage.symbolic.operators import mul_vararg - op = data.operator() - if op == operator.pow or data.is_symbol() \ - or isinstance(op, sage.functions.log.Function_log): - return self(self._convert_to_factor_(data)) - elif op == mul_vararg: - return self(data.operands()) - # room for other parents (e.g. polynomial ring et al.) - - # try to convert the input to one of the factors - data_conv = self._convert_to_factor_(data) - if data_conv is not None: - factors = self.cartesian_factors() - return self([data_conv if factor == data_conv.parent() else 1 for - factor in factors]) - - # final attempt: try parsing the representation string - str_lst = str(data).replace(' ', '').split('*') - return self(str_lst) - - - def _repr_(self): - r""" - A representation string for this cartesian product of growth groups. - - INPUT: - - Nothing. - - OUTPUT: - - A string. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') - sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') - sage: cartesian_product([P, L], order='lex')._repr_() - 'Growth Group x^QQ * log(x)^ZZ' - """ - return 'Growth Group ' + self._repr_short_() - - - def _repr_short_(self): - r""" - A short (shorter than :meth:`._repr_`) representation string - for this cartesian product of growth groups. - - INPUT: - - Nothing. - - OUTPUT: - - A string. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') - sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') - sage: cartesian_product([P, L], order='lex')._repr_short_() - 'x^QQ * log(x)^ZZ' - """ - return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) - - - def _convert_to_factor_(self, data): - r""" - Helper method. Try to convert some input ``data`` to an - element of one of the cartesian factors of this product. - - INPUT: - - - ``data`` -- some input to be converted. - - OUTPUT: - - An element of an cartesian factor of this product, - or ``None``. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('x^ZZ * log(x)^QQ * y^QQ') - sage: e1 = G._convert_to_factor_(x^2) - sage: (e1, e1.parent()) - (x^2, Growth Group x^ZZ * log(x)^QQ) - sage: G._convert_to_factor_('asdf') is None - True - """ - for factor in self.cartesian_factors(): - try: - if hasattr(factor, '_convert_to_factor_'): - return factor(factor._convert_to_factor_(data)) - return factor(data) - except (ValueError, TypeError): - continue - - - - def gens_monomial(self): - r""" - Return a tuple containing generators of this growth group. - - INPUT: - - Nothing. - - OUTPUT: - - A tuple containing elements of this growth group. - - .. NOTE: - - This method calls the ``gens_monomial()`` method on the - individual factors of this cartesian product and - concatenates the respective outputs. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ') - sage: G.gens_monomial() - (x, y) - """ - t = () - for factor in self.cartesian_factors(): - t = t + factor.gens_monomial() - return t - - - class Element(CartesianProductPosets.Element): - def _repr_(self): - r""" - A representation string for this cartesian product element. - - INPUT: - - Nothing. - - OUTPUT: - - A string. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') - sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') - sage: cartesian_product([P, L], order='lex').an_element()._repr_() - 'x^(1/2) * log(x)' - """ - s = ' * '.join(repr(v) for v in self.value if not v.is_one()) - if s == '': - return '1' - return s - - -CartesianProductGrowthGroups.CartesianProduct = CartesianProductGrowthGroups - - class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): r""" An abstract implementation of a generic growth element. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py new file mode 100644 index 00000000000..fcce0f109f7 --- /dev/null +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -0,0 +1,295 @@ +r""" +Growth Groups as Cartesian Products + +AUTHORS: + +- Daniel Krenn (2015-06-02): cartesian products +- Benjamin Hackl (2015-07) + +.. WARNING:: + + As this code is experimental, warnings are thrown when a growth + group is created for the first time in a session (see + :class:`sage.misc.superseded.experimental`). + + TESTS:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GenericGrowthGroup(ZZ); G + 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/17601 for details. + Growth Group Generic(ZZ) + sage: G = agg.MonomialGrowthGroup(ZZ, 'x'); G + 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/17601 for details. + Growth Group x^ZZ +""" + +#***************************************************************************** +# Copyright (C) 2014--2015 Benjamin Hackl +# 2014--2015 Daniel Krenn +# +# 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/ +#***************************************************************************** + +import sage + +from sage.sets.cartesian_product import CartesianProductPosets +class CartesianProductGrowthGroups(CartesianProductPosets): + r""" + A cartesian product of growth groups. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: C = cartesian_product([P, L], order='lex'); C + Growth Group x^QQ * log(x)^ZZ + sage: C.an_element() + x^(1/2) * log(x) + + :: + + sage: Px = agg.MonomialGrowthGroup(QQ, 'x') + sage: Lx = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: Cx = cartesian_product([Px, Lx], order='lex') + sage: Py = agg.MonomialGrowthGroup(QQ, 'y') + sage: C = cartesian_product([Cx, Py], order='components'); C + Growth Group x^QQ * log(x)^ZZ * y^QQ + sage: C.an_element() + x^(1/2) * log(x) * y^(1/2) + + .. SEEALSO: + + :class:`~sage.sets.cartesian_product.CartesianProduct`, + :class:`~sage.sets.cartesian_product.CartesianProductPosets`. + """ + + def _element_constructor_(self, data): + r""" + Converts the given object to an element of this cartesian + product. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * y^ZZ') + sage: G_log = GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ') + + Conversion from the symbolic ring works:: + + sage: x,y = var('x y') + sage: G(x^-3 * y^2) + x^(-3) * y^2 + sage: G(x^4), G(y^2) + (x^4, y^2) + sage: G(1) + 1 + + Even more complex expressions can be parsed:: + + sage: G_log(x^42 * log(x)^-42 * y^42) + x^42 * log(x)^(-42) * y^42 + + TESTS:: + + sage: G = GrowthGroup('x^ZZ * y^ZZ') + sage: G('x'), G('y') + (x, y) + + :: + + sage: G_log(log(x)) + log(x) + """ + if data == 1: + return self.one() + + if data is None: + raise ValueError('%s cannot be converted.' % (data,)) + + if isinstance(data, list): + try: + obj = super(CartesianProductGrowthGroups, + self)._element_constructor_(data) + return obj + except ValueError: + return self.prod(self(elem) for elem in data) + + if hasattr(data, 'parent'): + P = data.parent() + if P is self: + return data + + elif P is sage.symbolic.ring.SR: + import operator + from sage.symbolic.operators import mul_vararg + op = data.operator() + if op == operator.pow or data.is_symbol() \ + or isinstance(op, sage.functions.log.Function_log): + return self(self._convert_to_factor_(data)) + elif op == mul_vararg: + return self(data.operands()) + # room for other parents (e.g. polynomial ring et al.) + + # try to convert the input to one of the factors + data_conv = self._convert_to_factor_(data) + if data_conv is not None: + factors = self.cartesian_factors() + return self([data_conv if factor == data_conv.parent() else 1 for + factor in factors]) + + # final attempt: try parsing the representation string + str_lst = str(data).replace(' ', '').split('*') + return self(str_lst) + + + def _repr_(self): + r""" + A representation string for this cartesian product of growth groups. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: cartesian_product([P, L], order='lex')._repr_() + 'Growth Group x^QQ * log(x)^ZZ' + """ + return 'Growth Group ' + self._repr_short_() + + + def _repr_short_(self): + r""" + A short (shorter than :meth:`._repr_`) representation string + for this cartesian product of growth groups. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: cartesian_product([P, L], order='lex')._repr_short_() + 'x^QQ * log(x)^ZZ' + """ + return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) + + + def _convert_to_factor_(self, data): + r""" + Helper method. Try to convert some input ``data`` to an + element of one of the cartesian factors of this product. + + INPUT: + + - ``data`` -- some input to be converted. + + OUTPUT: + + An element of an cartesian factor of this product, + or ``None``. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * log(x)^QQ * y^QQ') + sage: e1 = G._convert_to_factor_(x^2) + sage: (e1, e1.parent()) + (x^2, Growth Group x^ZZ * log(x)^QQ) + sage: G._convert_to_factor_('asdf') is None + True + """ + for factor in self.cartesian_factors(): + try: + if hasattr(factor, '_convert_to_factor_'): + return factor(factor._convert_to_factor_(data)) + return factor(data) + except (ValueError, TypeError): + continue + + + + def gens_monomial(self): + r""" + Return a tuple containing generators of this growth group. + + INPUT: + + Nothing. + + OUTPUT: + + A tuple containing elements of this growth group. + + .. NOTE: + + This method calls the ``gens_monomial()`` method on the + individual factors of this cartesian product and + concatenates the respective outputs. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ') + sage: G.gens_monomial() + (x, y) + """ + t = () + for factor in self.cartesian_factors(): + t = t + factor.gens_monomial() + return t + + + class Element(CartesianProductPosets.Element): + def _repr_(self): + r""" + A representation string for this cartesian product element. + + INPUT: + + Nothing. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: cartesian_product([P, L], order='lex').an_element()._repr_() + 'x^(1/2) * log(x)' + """ + s = ' * '.join(repr(v) for v in self.value if not v.is_one()) + if s == '': + return '1' + return s + + +CartesianProductGrowthGroups.CartesianProduct = CartesianProductGrowthGroups From 6122b083c484cb580e61040fade56fded6da9a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 20 Aug 2015 22:26:11 +0200 Subject: [PATCH 0448/1872] trac #18937 now 2.4.0, still trying to switch to new style spkg --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- build/pkgs/patchbot/spkg-install | 11 +++-------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index 73aec48e51f..62ffca027aa 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=338e924734df1228427a03fbf82ea65ec345b420 -md5=aaf9ee33455656a47f687e553d401cac -cksum=1478772629 +sha1=25e1f2a8bbe84a01e2b5157cfeffc02218a6e7ab +md5=d2b2fde69496db246d2fe3b086ad20d5 +cksum=532828853 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 5aa7c523257..197c4d5c2d7 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.3.9 +2.4.0 diff --git a/build/pkgs/patchbot/spkg-install b/build/pkgs/patchbot/spkg-install index 657ce96695c..787152c6d9c 100755 --- a/build/pkgs/patchbot/spkg-install +++ b/build/pkgs/patchbot/spkg-install @@ -6,16 +6,11 @@ if [ "$SAGE_LOCAL" = "" ]; then exit 1 fi -# Move any currently exising patchbot out of the way. +# Delete any currently existing patchbot if [ -e "$SAGE_LOCAL/bin/patchbot" ]; then - i=0 - while [ -e "$SAGE_LOCAL/bin/patchbot-old-$i" ]; do - i=$(( $i + 1 )) - done - echo "Renaming existing patchbot directory to patchbot-old-$i" - mv "$SAGE_LOCAL/bin/patchbot" "$SAGE_LOCAL/bin/patchbot-old-$i" + rm -rf "$SAGE_LOCAL/bin/patchbot" fi # Copy into final location. -# The sage-sage script knows how to call this... +# The sage-patchbot script knows how to call this... cp -Rv src "$SAGE_LOCAL/bin/patchbot" From 8ca4e61b21030bd0c78b889d58a9dae9cbf5d0c6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 08:42:41 +0200 Subject: [PATCH 0449/1872] class for a growth group Variable --- src/sage/rings/asymptotic/growth_group.py | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 02e48ac097a..ca76fb0a21b 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -183,6 +183,106 @@ def parent_to_repr_short(P): return rep +class Variable(sage.structure.sage_object.SageObject): + r""" + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: v = Variable('x'); repr(v), v.variable_names() + ('x', ('x',)) + sage: v = Variable('x1'); repr(v), v.variable_names() + ('x1', ('x1',)) + sage: v = Variable('x_42'); repr(v), v.variable_names() + ('x_42', ('x_42',)) + sage: v = Variable(' x'); repr(v), v.variable_names() + ('x', ('x',)) + sage: v = Variable('x '); repr(v), v.variable_names() + ('x', ('x',)) + sage: v = Variable('x '); repr(v), v.variable_names() + ('x', ('x',)) + + :: + + sage: v = Variable(('x', 'y')); repr(v), v.variable_names() + ('x, y', ('x', 'y')) + sage: v = Variable(('x', 'log(y)')); repr(v), v.variable_names() + ('x, log(y)', ('x', 'y')) + sage: v = Variable(('x', 'log(x)')); repr(v), v.variable_names() + Traceback (most recent call last): + ... + ValueError: Variable names ('x', 'x') are not pairwise distinct. + + :: + + sage: v = Variable('log(x)'); repr(v), v.variable_names() + ('log(x)', ('x',)) + sage: v = Variable('log(log(x))'); repr(v), v.variable_names() + ('log(log(x))', ('x',)) + + :: + + sage: v = Variable('x', repr='log(x)'); repr(v), v.variable_names() + ('log(x)', ('x',)) + """ + def __init__(self, var, repr=None): + from sage.symbolic.ring import isidentifier + + if not isinstance(var, (list, tuple)): + var = (var,) + var = tuple(str(v).strip() for v in var) + + if repr is None: + var_bases = tuple( + self.extract_variable_name(v) + if not isidentifier(v) else v + for v in var) + var_repr = ', '.join(var) + else: + for v in var: + if not isidentifier(v): + raise ValueError("'%s' is not a valid name for a variable." % (v,)) + var_bases = var + var_repr = str(repr).strip() + + if len(var_bases) != len(set(var_bases)): + raise ValueError('Variable names %s are not pairwise distinct.' % + (var_bases,)) + self.var_bases = var_bases + self.var_repr = var_repr + + + def _repr_(self): + return self.var_repr + + + def variable_names(self): + return self.var_bases + + + @staticmethod + def extract_variable_name(s): + from sage.symbolic.ring import isidentifier + s = s.strip() + + def strip_fct(s): + op = s.find('(') + cl = s.rfind(')') + if op == -1 and cl == -1: + return s + if (op == -1) != (cl == -1): + raise ValueError("Unbalanced parentheses in '%s'." % (s,)) + return s[op+1:cl] + + s_old = '' + while s != s_old: + s_old = s + s = strip_fct(s) + + if not isidentifier(s): + raise ValueError("'%s' is not a valid name for a variable." % (s,)) + return s + + class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): r""" An abstract implementation of a generic growth element. From c50776236b5dffa3e42853a1871e6e1842f893da Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 08:42:53 +0200 Subject: [PATCH 0450/1872] small improvment of code --- src/sage/rings/asymptotic/growth_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ca76fb0a21b..bf58eb19fca 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1650,7 +1650,8 @@ def gens_monomial(self): sage: agg.MonomialGrowthGroup(QQ, 'log(x)').gens_monomial() () """ - if self._var_.startswith('log(') and self._var_.endswith(')'): + from sage.symbolic.ring import isidentifier + if not isidentifier(self._var_): return () return (self(raw_element=self.base().one()),) From 13b814d1f4ab1a54e6e60cb2bf359db6292c3ce7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 08:44:15 +0200 Subject: [PATCH 0451/1872] cartesian product factory and separate classes for univariate/multivariate --- .../asymptotic/growth_group_cartesian.py | 72 ++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index fcce0f109f7..ef5d8e64173 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -42,8 +42,56 @@ import sage + +class CartesianProductFactory(sage.structure.factory.UniqueFactory): + def create_key_and_extra_args(self, growth_groups, **kwds): + return tuple(growth_groups), kwds + + def create_object(self, version, growth_groups, **kwds): + order = kwds.pop('order') + if order is not None: + return GenericProduct(growth_groups, order=order, **kwds) + + # check if all groups have a variable + if not all(g.variable_names() for g in growth_groups): + raise NotImplementedError('Growth groups %s have no variable.' % + tuple(g for g in growth_groups + if not g.variable_names())) + + # check if all are univariate + first_var = growth_groups[0].variable_names() + if len(first_var) == 1 and all(g.variable_names() == first_var + for g in growth_groups): + return UnivariateProduct(growth_groups, **kwds) + + # check if multivariate and all have distinct single variables + vg = tuple((g.variable_names(), g) for g in growth_groups) + vars = add(iter(v for v, _ in vg), tuple()) + if len(vars) != len(set(vars)): + raise ValueError('Growth groups %s do not have distinct variables.' % + growth_groups) + if any(len(v) != 1 for v, _ in vg): + raise NotImplementedError('Cannot build cartesian product since growth ' + 'groups %s do not have single variables.' % + tuple(g for v, g in vg if len(v) != 1)) + + vg = sorted(vg, key=lambda k: k[0]) + from itertools import groupby + sorted_groups = list() + for v, gs in groupby(vg, key=lambda k: k[0]): + gs = tuple(gs) + if len(gs) > 1: + raise ValueError('Growth groups %s do not have distinct variables.' % + gs) + sorted_groups.append(gs[0]) + return MultivariateProduct(sorted_groups, **kwds) + + +CartesianProductGrowthGroups = CartesianProductFactory('CartesianProductGrowthGroups') + + from sage.sets.cartesian_product import CartesianProductPosets -class CartesianProductGrowthGroups(CartesianProductPosets): +class GenericProduct(CartesianProductPosets): r""" A cartesian product of growth groups. @@ -119,7 +167,7 @@ def _element_constructor_(self, data): if isinstance(data, list): try: - obj = super(CartesianProductGrowthGroups, + obj = super(GenericProduct, self)._element_constructor_(data) return obj except ValueError: @@ -292,4 +340,22 @@ def _repr_(self): return s -CartesianProductGrowthGroups.CartesianProduct = CartesianProductGrowthGroups + CartesianProduct = CartesianProductGrowthGroups + + +class UnivariateProduct(GenericProduct): + def __init__(self, sets, category, **kwargs): + super(CartesianProductUnivariateGrowthGroups, self).__init__( + sets, category, order='lex', **kwargs) + + + CartesianProduct = CartesianProductGrowthGroups + + +class MultivariateProduct(GenericProduct): + def __init__(self, sets, category, **kwargs): + super(CartesianProductUnivariateGrowthGroups, self).__init__( + sets, category, order='components', **kwargs) + + + CartesianProduct = CartesianProductGrowthGroups From a87f4a61f16eeb915ca664a7ba13121ed80565a1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 09:15:06 +0200 Subject: [PATCH 0452/1872] use new Variable class --- src/sage/rings/asymptotic/growth_group.py | 71 ++++++++++++++--------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index bf58eb19fca..007bf407b45 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -105,6 +105,7 @@ import sage from sage.rings.asymptotic.growth_group_cartesian import CartesianProductGrowthGroups + def repr_short_to_parent(s): r""" Helper method for the growth group factory, which converts a short @@ -183,7 +184,8 @@ def parent_to_repr_short(P): return rep -class Variable(sage.structure.sage_object.SageObject): +class Variable(sage.structure.unique_representation.CachedRepresentation, + sage.structure.sage_object.SageObject): r""" TESTS:: @@ -200,6 +202,10 @@ class Variable(sage.structure.sage_object.SageObject): ('x', ('x',)) sage: v = Variable('x '); repr(v), v.variable_names() ('x', ('x',)) + sage: v = Variable(''); repr(v), v.variable_names() + Traceback (most recent call last): + ... + ValueError: '' is not a valid name for a variable. :: @@ -251,6 +257,14 @@ def __init__(self, var, repr=None): self.var_repr = var_repr + def __hash__(self): + return hash((self.var_repr,) + self.var_bases) + + + def __eq__(self, other): + return self.var_repr == other.var_repr and self.var_bases == other.var_bases + + def _repr_(self): return self.var_repr @@ -259,6 +273,10 @@ def variable_names(self): return self.var_bases + def is_monomial(self): + return len(self.var_bases) == 1 and self.var_bases[0] == self.var_repr + + @staticmethod def extract_variable_name(s): from sage.symbolic.ring import isidentifier @@ -1151,16 +1169,17 @@ def _repr_(self): """ from sage.rings.integer_ring import ZZ + var = repr(self.parent()._var_) if self.exponent == 0: return '1' elif self.exponent == 1: - return self.parent()._var_ + return var elif self.exponent == -1: - return '1/' + self.parent()._var_ + return '1/' + var elif self.exponent in ZZ and self.exponent > 0: - return self.parent()._var_ + '^' + str(self.exponent) + return var + '^' + str(self.exponent) else: - return self.parent()._var_ + '^(' + str(self.exponent) + ')' + return var + '^(' + str(self.exponent) + ')' def _mul_(self, other): @@ -1363,7 +1382,8 @@ def __classcall__(cls, base, var, category=None): sage: L1 is L2 True """ - var = str(var).strip() + if not isinstance(var, Variable): + var = Variable(var) return super(MonomialGrowthGroup, cls).__classcall__( cls, base, var, category) @@ -1390,17 +1410,13 @@ def __init__(self, base, var, category): sage: agg.MonomialGrowthGroup('x', ZZ) Traceback (most recent call last): ... + ValueError: 'Integer Ring' is not a valid name for a variable. + sage: agg.MonomialGrowthGroup('x', 'y') + Traceback (most recent call last): + ... TypeError: x is not a valid base """ - if not var: - raise ValueError('Empty var is not allowed.') - if var[0] in '0123456789=+-*/^%': - # This restriction is mainly for optical reasons on the - # representation. Feel free to relax this if needed. - raise ValueError("The variable name '%s' is inappropriate." % - (var,)) self._var_ = var - super(MonomialGrowthGroup, self).__init__(category=category, base=base) @@ -1543,19 +1559,20 @@ def _convert_(self, data): """ if data == 1: return self.base().zero() - if str(data) == self._var_: + var = repr(self._var_) + if str(data) == var: return self.base().one() try: P = data.parent() except AttributeError: - if self._var_ not in str(data): + if var not in str(data): return # this has to end here - elif str(data) == '1/' + self._var_: + elif str(data) == '1/' + var: return self.base()(-1) - elif str(data).startswith(self._var_ + '^'): - return self.base()(str(data).replace(self._var_ + '^', '') + elif str(data).startswith(var + '^'): + return self.base()(str(data).replace(var + '^', '') .replace('(', '').replace(')', '')) else: return # end of parsing @@ -1570,19 +1587,19 @@ def _convert_(self, data): if P is SR: if data.operator() == operator.pow: base, exponent = data.operands() - if str(base) == self._var_: + if str(base) == var: return exponent elif isinstance(P, (PolynomialRing_general, MPolynomialRing_generic)): if data.is_monomial() and len(data.variables()) == 1: - if self._var_ == str(data.variables()[0]): + if var == str(data.variables()[0]): return data.degree() elif isinstance(P, PowerSeriesRing_generic): if hasattr(data, 'variables') and len(data.variables()) == 1: from sage.rings.integer_ring import ZZ if data.is_monomial() and data.precision_absolute() not in ZZ: - if self._var_ == str(data.variables()[0]): + if var == str(data.variables()[0]): return data.degree() - elif self._var_ == str(data.variable()[0]): + elif var == str(data.variable()[0]): from sage.rings.integer_ring import ZZ if data.is_monomial() and data.precision_absolute() not in ZZ: return data.degree() @@ -1650,9 +1667,8 @@ def gens_monomial(self): sage: agg.MonomialGrowthGroup(QQ, 'log(x)').gens_monomial() () """ - from sage.symbolic.ring import isidentifier - if not isidentifier(self._var_): - return () + if not self._var_.is_monomial(): + return tuple() return (self(raw_element=self.base().one()),) @@ -1842,7 +1858,7 @@ def create_object(self, version, factors, **kwds): equal_var_groups = [] vars = [] for group in groups: - var = group._var_ + var = repr(group._var_) if not vars or '(' + vars[-1] + ')' not in var: vars.append(var) equal_var_groups.append([group]) @@ -1862,4 +1878,5 @@ def create_object(self, version, factors, **kwds): return cartesian_product(equal_var_groups, order='components') + GrowthGroup = GrowthGroupFactory("GrowthGroup") From 18a292a1329bc788e22212e59608f5b86290a852 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 09:35:02 +0200 Subject: [PATCH 0453/1872] docstrings of Variable and i small improvment on error output --- src/sage/rings/asymptotic/growth_group.py | 129 +++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 007bf407b45..1150e7dbda6 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -187,6 +187,18 @@ def parent_to_repr_short(P): class Variable(sage.structure.unique_representation.CachedRepresentation, sage.structure.sage_object.SageObject): r""" + A class managing the variable of a growth group. + + INPUT: + + - ``var`` -- an object whose representation string is used as the + variable. It has to be a valid Python identifier. ``var`` can + also be a tuple (or other iterable of such objects). + + - ``repr`` (default: ``None``) -- if specified, then this string + will be displayed instead of ``var``. Use this to get + e.g. ``log(x)^ZZ``: ``var`` is then used to specify the variable `x`. + TESTS:: sage: from sage.rings.asymptotic.growth_group import Variable @@ -231,6 +243,17 @@ class Variable(sage.structure.unique_representation.CachedRepresentation, ('log(x)', ('x',)) """ def __init__(self, var, repr=None): + r""" + See :class:`Variable` for details. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable('blub') + blub + sage: Variable('blub') is Variable('blub') + True + """ from sage.symbolic.ring import isidentifier if not isinstance(var, (list, tuple)): @@ -258,27 +281,131 @@ def __init__(self, var, repr=None): def __hash__(self): + r""" + Return the hash if this variable. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: hash(Variable('blub')) # random + -123456789 + """ return hash((self.var_repr,) + self.var_bases) def __eq__(self, other): + r""" + Compares if this variable equals ``other``. + + INPUT: + + - ``other`` -- another variable. + + OUTPUT: + + A boolean. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable('x') == Variable('x') + True + sage: Variable('x') == Variable('y') + False + """ return self.var_repr == other.var_repr and self.var_bases == other.var_bases def _repr_(self): + r""" + Return a representation string of this variable. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable('blub') # indirect doctest + blub + """ return self.var_repr def variable_names(self): + r""" + Return the names of the variables. + + OUTPUT: + + A tuple of strings. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable('x').variable_names() + ('x',) + sage: Variable('log(x)').variable_names() + ('x',) + """ return self.var_bases def is_monomial(self): + r""" + Returns if this is a monomial variable. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable('x').is_monomial() + True + sage: Variable('log(x)').is_monomial() + False + """ return len(self.var_bases) == 1 and self.var_bases[0] == self.var_repr @staticmethod def extract_variable_name(s): + r""" + Finds the name of the variable for the given string. + + INPUT: + + - ``s`` -- a string. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable.extract_variable_name('x') + 'x' + sage: Variable.extract_variable_name('exp(x)') + 'x' + sage: Variable.extract_variable_name('sin(cos(ln(x)))') + 'x' + sage: Variable.extract_variable_name('log(77)') + Traceback (most recent call last): + .... + ValueError: '77' is not a valid name for a variable. + sage: Variable.extract_variable_name('log(x') + Traceback (most recent call last): + .... + ValueError: Unbalanced parentheses in 'log(x'. + sage: Variable.extract_variable_name('x)') + Traceback (most recent call last): + .... + ValueError: Unbalanced parentheses in 'x)'. + sage: Variable.extract_variable_name('log)x(') + Traceback (most recent call last): + .... + ValueError: Unbalanced parentheses in 'log)x('. + """ from sage.symbolic.ring import isidentifier s = s.strip() @@ -287,7 +414,7 @@ def strip_fct(s): cl = s.rfind(')') if op == -1 and cl == -1: return s - if (op == -1) != (cl == -1): + if (op == -1) != (cl == -1) or op > cl: raise ValueError("Unbalanced parentheses in '%s'." % (s,)) return s[op+1:cl] From 62756e97c33ed9b8cbc04f5e50da0a9f71771f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 21 Aug 2015 09:40:52 +0200 Subject: [PATCH 0454/1872] trac #18937 simplify spkg-install --- build/pkgs/patchbot/spkg-install | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/pkgs/patchbot/spkg-install b/build/pkgs/patchbot/spkg-install index 787152c6d9c..5dcc96f4629 100755 --- a/build/pkgs/patchbot/spkg-install +++ b/build/pkgs/patchbot/spkg-install @@ -7,9 +7,7 @@ if [ "$SAGE_LOCAL" = "" ]; then fi # Delete any currently existing patchbot -if [ -e "$SAGE_LOCAL/bin/patchbot" ]; then - rm -rf "$SAGE_LOCAL/bin/patchbot" -fi +rm -rf "$SAGE_LOCAL/bin/patchbot" # Copy into final location. # The sage-patchbot script knows how to call this... From f43d197138ea76993d297212189c59576bd1d94e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 09:55:10 +0200 Subject: [PATCH 0455/1872] variable_names --- src/sage/rings/asymptotic/growth_group.py | 36 +++++++++++++++++++ .../asymptotic/growth_group_cartesian.py | 23 +++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 1150e7dbda6..2643102b497 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1213,6 +1213,23 @@ def gens_monomial(self): " implementations.") + def variable_names(self): + r""" + Return the names of the variables. + + OUTPUT: + + A tuple of strings. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: agg.GenericGrowthGroup(ZZ).variable_names() + () + """ + return tuple() + + CartesianProduct = CartesianProductGrowthGroups @@ -1870,6 +1887,25 @@ def ngens(self): return len(self.gens()) + def variable_names(self): + r""" + Return the names of the variables. + + OUTPUT: + + A tuple of strings. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ').variable_names() + ('x',) + sage: GrowthGroup('log(x)^ZZ').variable_names() + ('x',) + """ + return self._var_.variable_names() + + class GrowthGroupFactory(sage.structure.factory.UniqueFactory): r""" A factory creating asymptotic growth groups. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index ef5d8e64173..62d7784a02b 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -66,7 +66,7 @@ def create_object(self, version, growth_groups, **kwds): # check if multivariate and all have distinct single variables vg = tuple((g.variable_names(), g) for g in growth_groups) - vars = add(iter(v for v, _ in vg), tuple()) + vars = sum(iter(v for v, _ in vg), tuple()) if len(vars) != len(set(vars)): raise ValueError('Growth groups %s do not have distinct variables.' % growth_groups) @@ -313,6 +313,27 @@ def gens_monomial(self): return t + def variable_names(self): + r""" + Return the names of the variables. + + OUTPUT: + + A tuple of strings. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ').variable_names() + ('x', 'y', 'z') + """ + vars = sum(iter(factor.variable_names() + for factor in self.cartesian_factors()), + tuple()) + from itertools import groupby + return tuple(v for v, _ in groupby(vars)) + + class Element(CartesianProductPosets.Element): def _repr_(self): r""" From 18158472423b2a373dc670efb85ddf5c16b04d67 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 12:28:06 +0200 Subject: [PATCH 0456/1872] two minor modifications of docstrings --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 2643102b497..6a9ca5019c1 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -195,7 +195,7 @@ class Variable(sage.structure.unique_representation.CachedRepresentation, variable. It has to be a valid Python identifier. ``var`` can also be a tuple (or other iterable of such objects). - - ``repr`` (default: ``None``) -- if specified, then this string + - ``repr`` -- (default: ``None``) if specified, then this string will be displayed instead of ``var``. Use this to get e.g. ``log(x)^ZZ``: ``var`` is then used to specify the variable `x`. @@ -1941,7 +1941,7 @@ def create_key_and_extra_args(self, specification, **kwds): Given the arguments and keyword, create a key that uniquely determines this object. - EXAMPLES:: + TESTS:: sage: import sage.rings.asymptotic.growth_group as agg sage: agg.GrowthGroup.create_key_and_extra_args('x^ZZ') From 6e33615c572f44c0c6bac4ca75749cb8824b8807 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 12:29:53 +0200 Subject: [PATCH 0457/1872] modify to to make things running... --- .../asymptotic/growth_group_cartesian.py | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 62d7784a02b..e6b2c5af1c2 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -44,13 +44,15 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): - def create_key_and_extra_args(self, growth_groups, **kwds): - return tuple(growth_groups), kwds + def create_key_and_extra_args(self, growth_groups, category, **kwds): + return (tuple(growth_groups), category), kwds - def create_object(self, version, growth_groups, **kwds): - order = kwds.pop('order') + + def create_object(self, version, args, **kwds): + growth_groups, category = args + order = kwds.pop('order', None) if order is not None: - return GenericProduct(growth_groups, order=order, **kwds) + return GenericProduct(growth_groups, category, order=order, **kwds) # check if all groups have a variable if not all(g.variable_names() for g in growth_groups): @@ -62,14 +64,14 @@ def create_object(self, version, growth_groups, **kwds): first_var = growth_groups[0].variable_names() if len(first_var) == 1 and all(g.variable_names() == first_var for g in growth_groups): - return UnivariateProduct(growth_groups, **kwds) + return UnivariateProduct(growth_groups, category, **kwds) # check if multivariate and all have distinct single variables vg = tuple((g.variable_names(), g) for g in growth_groups) vars = sum(iter(v for v, _ in vg), tuple()) if len(vars) != len(set(vars)): - raise ValueError('Growth groups %s do not have distinct variables.' % - growth_groups) + raise ValueError('Growth groups %s do not have pairwise distinct variables.' % + (growth_groups,)) if any(len(v) != 1 for v, _ in vg): raise NotImplementedError('Cannot build cartesian product since growth ' 'groups %s do not have single variables.' % @@ -78,13 +80,13 @@ def create_object(self, version, growth_groups, **kwds): vg = sorted(vg, key=lambda k: k[0]) from itertools import groupby sorted_groups = list() - for v, gs in groupby(vg, key=lambda k: k[0]): + for _, gs in groupby(vg, key=lambda k: k[0]): gs = tuple(gs) if len(gs) > 1: - raise ValueError('Growth groups %s do not have distinct variables.' % + raise ValueError('Growth groups %s do not have pairwise distinct variables.' % gs) - sorted_groups.append(gs[0]) - return MultivariateProduct(sorted_groups, **kwds) + sorted_groups.append(gs[0][1]) + return MultivariateProduct(tuple(sorted_groups), category, **kwds) CartesianProductGrowthGroups = CartesianProductFactory('CartesianProductGrowthGroups') @@ -366,7 +368,7 @@ def _repr_(self): class UnivariateProduct(GenericProduct): def __init__(self, sets, category, **kwargs): - super(CartesianProductUnivariateGrowthGroups, self).__init__( + super(UnivariateProduct, self).__init__( sets, category, order='lex', **kwargs) @@ -375,7 +377,7 @@ def __init__(self, sets, category, **kwargs): class MultivariateProduct(GenericProduct): def __init__(self, sets, category, **kwargs): - super(CartesianProductUnivariateGrowthGroups, self).__init__( + super(MultivariateProduct, self).__init__( sets, category, order='components', **kwargs) From 62fc735ddb22e45ef8ef01e651c33ba062f17e56 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 12:30:12 +0200 Subject: [PATCH 0458/1872] write docstings of cartesian factory --- .../asymptotic/growth_group_cartesian.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index e6b2c5af1c2..d742fe87344 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -44,11 +44,83 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): + r""" + Creates various types of cartesian products depending on its input. + + INPUT: + + - ``growth_groups`` -- a tuple (or other iterable) of growth groups. + + - ``order`` -- (default: ``None``) if specified, then this order + is taken for comparing two cartesian product elements. If ``order`` is + ``None`` this is determined automatically. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: A = GrowthGroup('x^ZZ'); A + Growth Group x^ZZ + sage: B = GrowthGroup('log(x)^ZZ'); B + Growth Group log(x)^ZZ + sage: C = cartesian_product([A, B]); C + Growth Group x^ZZ * log(x)^ZZ + sage: C._le_ == C.le_lex + True + sage: D = GrowthGroup('y^ZZ'); D + Growth Group y^ZZ + sage: E = cartesian_product([A, D]); E + Growth Group x^ZZ * y^ZZ + sage: E._le_ == E.le_components + True + sage: F = cartesian_product([C, D]); F + Growth Group x^ZZ * log(x)^ZZ * y^ZZ + sage: F._le_ == F.le_components + True + sage: cartesian_product([A, E]); G + Traceback (most recent call last): + ... + ValueError: Growth groups (Growth Group x^ZZ, Growth Group x^ZZ * y^ZZ) + do not have pairwise distinct variables. + sage: cartesian_product([A, B, D]) + Traceback (most recent call last): + ... + ValueError: Growth groups + (Growth Group x^ZZ, Growth Group log(x)^ZZ, Growth Group y^ZZ) + do not have pairwise distinct variables. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group_cartesian import CartesianProductFactory + sage: CartesianProductFactory('factory')([A, B], category=Sets()) + Growth Group x^ZZ * log(x)^ZZ + """ def create_key_and_extra_args(self, growth_groups, category, **kwds): + r""" + Given the arguments and keywords, create a key that uniquely + determines this object. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group_cartesian import CartesianProductFactory + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: A = GrowthGroup('x^ZZ') + sage: CartesianProductFactory('factory').create_key_and_extra_args( + ....: [A], category=Sets(), order='blub') + (((Growth Group x^ZZ,), Category of sets), {'order': 'blub'}) + """ return (tuple(growth_groups), category), kwds def create_object(self, version, args, **kwds): + r""" + Create an object from the given arguments. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: cartesian_product([GrowthGroup('x^ZZ')]) # indirect doctest + Growth Group x^ZZ + """ growth_groups, category = args order = kwds.pop('order', None) if order is not None: From ddbd90a6f04f220ee831c7d71155948681193033 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 13:01:59 +0200 Subject: [PATCH 0459/1872] collect asymptotic code in one directory --- src/sage/rings/{ => asymptotic}/asymptotic_ring.py | 0 .../asymptotic/growth_group.py} | 0 .../asymptotic_term_monoid.py => rings/asymptotic/term_monoid.py} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/sage/rings/{ => asymptotic}/asymptotic_ring.py (100%) rename src/sage/{groups/asymptotic_growth_group.py => rings/asymptotic/growth_group.py} (100%) rename src/sage/{monoids/asymptotic_term_monoid.py => rings/asymptotic/term_monoid.py} (100%) diff --git a/src/sage/rings/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py similarity index 100% rename from src/sage/rings/asymptotic_ring.py rename to src/sage/rings/asymptotic/asymptotic_ring.py diff --git a/src/sage/groups/asymptotic_growth_group.py b/src/sage/rings/asymptotic/growth_group.py similarity index 100% rename from src/sage/groups/asymptotic_growth_group.py rename to src/sage/rings/asymptotic/growth_group.py diff --git a/src/sage/monoids/asymptotic_term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py similarity index 100% rename from src/sage/monoids/asymptotic_term_monoid.py rename to src/sage/rings/asymptotic/term_monoid.py From 2a111cf3d6f70c42f07b4bb7e0e2698afb0c1389 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 13:09:12 +0200 Subject: [PATCH 0460/1872] doctests fixed --- src/sage/rings/asymptotic/growth_group.py | 66 +++++++++++------------ 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c4ebe591d8d..07d8d02270e 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1947,7 +1947,7 @@ class ExponentialGrowthElement(GenericGrowthElement): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('ZZ^x') sage: e1 = P(1); e1 1 @@ -1968,7 +1968,7 @@ def base(self): EXAMPLES: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('ZZ^x') sage: P(42^x).base 42 @@ -1990,7 +1990,7 @@ def _repr_(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('QQ^x') sage: P(1)._repr_() '1' @@ -2006,12 +2006,13 @@ def _repr_(self): """ from sage.rings.integer_ring import ZZ + var = repr(self.parent()._var_) if self.base == 1: return '1' elif self.base in ZZ and self.base > 0 or str(self.base).startswith('sqrt'): - return str(self.base) + '^' + self.parent()._var_ + return str(self.base) + '^' + var else: - return '(' + str(self.base) + ')^' + self.parent()._var_ + return '(' + str(self.base) + ')^' + var def _mul_(self, other): @@ -2033,7 +2034,7 @@ def _mul_(self, other): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('ZZ^x') sage: a = P(2^x) sage: b = P(3^x) @@ -2061,7 +2062,7 @@ def __invert__(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('ZZ^x') sage: e1 = P(raw_element=2) sage: e2 = e1.__invert__(); e2 @@ -2094,7 +2095,7 @@ def __pow__(self, power): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('ZZ^x') sage: a = P(7^x); a 7^x @@ -2136,7 +2137,7 @@ def _le_(self, other): TESTS:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P_ZZ = agg.GrowthGroup('ZZ^x') sage: P_SR = agg.GrowthGroup('SR^x') sage: P_ZZ(2^x) <= P_SR(sqrt(3)^x)^2 # indirect doctest @@ -2174,7 +2175,7 @@ class ExponentialGrowthGroup(GenericGrowthGroup): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.ExponentialGrowthGroup(QQ, 'x'); P Growth Group QQ^x @@ -2197,7 +2198,7 @@ def __classcall__(cls, base, var, category=None): TESTS:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P1 = agg.ExponentialGrowthGroup(QQ, 'x') sage: P2 = agg.ExponentialGrowthGroup(QQ, ZZ['x'].gen()) sage: P3 = agg.ExponentialGrowthGroup(QQ, SR.var('x')) @@ -2210,7 +2211,8 @@ def __classcall__(cls, base, var, category=None): sage: P1 is P5 True """ - var = str(var).strip() + if not isinstance(var, Variable): + var = Variable(var) return super(ExponentialGrowthGroup, cls).__classcall__( cls, base, var, category) @@ -2222,7 +2224,7 @@ def __init__(self, base, var, category): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: agg.ExponentialGrowthGroup(QQ, 'x') Growth Group QQ^x sage: agg.ExponentialGrowthGroup(SR, ZZ['y'].gen()) @@ -2233,17 +2235,13 @@ def __init__(self, base, var, category): sage: agg.ExponentialGrowthGroup('x', ZZ) Traceback (most recent call last): ... + ValueError: 'Integer Ring' is not a valid name for a variable. + sage: agg.ExponentialGrowthGroup('x', 'y') + Traceback (most recent call last): + ... TypeError: x is not a valid base """ - if not var: - raise ValueError('Empty var is not allowed.') - if var[0] in '0123456789=+-*/^%': - # This restriction is mainly for optical reasons on the - # representation. Feel free to relax this if needed. - raise ValueError("The variable name '%s' is inappropriate." % - (var,)) self._var_ = var - super(ExponentialGrowthGroup, self).__init__(category=category, base=base) @@ -2261,7 +2259,7 @@ def _repr_short_(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: agg.ExponentialGrowthGroup(QQ, 'a') # indirect doctest Growth Group QQ^a @@ -2290,7 +2288,7 @@ def __hash__(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') sage: hash(P) # random -1234567890123456789 @@ -2314,7 +2312,7 @@ def _convert_(self, data): TESTS:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') sage: P._convert_('icecream') is None True @@ -2351,16 +2349,16 @@ def _convert_(self, data): """ if data == 1 or data == '1': return self.base().one() - + var = repr(self._var_) try: P = data.parent() except AttributeError: import re - if self._var_ not in str(data): + if var not in str(data): return # this has to end here - elif str(data).endswith('^' + self._var_): - return self.base()(str(data).replace('^' + self._var_, '') + elif str(data).endswith('^' + var): + return self.base()(str(data).replace('^' + var, '') .replace('(', '').replace(')', '')) else: return # end of parsing @@ -2372,10 +2370,10 @@ def _convert_(self, data): if P is SR: if data.operator() == operator.pow: base, exponent = data.operands() - if str(exponent) == self._var_: + if str(exponent) == var: return base elif exponent.operator() == mul_vararg: - return base ** (exponent / SR(self._var_)) + return base ** (exponent / SR(var)) def _coerce_map_from_(self, S): @@ -2392,7 +2390,7 @@ def _coerce_map_from_(self, S): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P_x_ZZ = agg.GrowthGroup('ZZ^x') sage: P_x_QQ = agg.GrowthGroup('QQ^x') sage: bool(P_x_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest @@ -2433,7 +2431,7 @@ def gens_monomial(self): TESTS:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: agg.GrowthGroup('ZZ^x').gens_monomial() () """ @@ -2457,7 +2455,7 @@ def gen(self, n=0): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('QQ^x') sage: P.gen() Traceback (most recent call last): @@ -2481,7 +2479,7 @@ def ngens(self): EXAMPLES:: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('QQ^x') sage: P.ngens() 0 From 3a44a01c5f3d39c51071d57f7ae5648ba63dbba8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 13:10:49 +0200 Subject: [PATCH 0461/1872] fix imports to make doctests pass --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 +++--- src/sage/rings/asymptotic/growth_group.py | 2 +- src/sage/rings/asymptotic/term_monoid.py | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b6ec87c88f3..1cc9acac3a5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1073,7 +1073,7 @@ def _an_element_(self): sage: AsymptoticRing(growth_group='z^QQ', coefficient_ring=QQ).an_element() -1/8*z^(3/2) + O(z^(1/2)) """ - from sage.monoids.asymptotic_term_monoid import TermMonoid + from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) return -self(E.an_element())**3 + self(O.an_element()) @@ -1109,8 +1109,8 @@ def some_elements(self): O(z^(-1/2)), -8*z^(3/2) + O(z^(1/2))) """ - from sage.monoids.asymptotic_term_monoid import product_diagonal - from sage.monoids.asymptotic_term_monoid import TermMonoid + from sage.rings.asymptotic.term_monoid import product_diagonal + from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) return iter(-self(e)**3 + self(o) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cd2434b7bd1..c939436a784 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -700,7 +700,7 @@ def some_elements(self): EXAMPLES: - sage: import sage.groups.asymptotic_growth_group as agg + sage: import sage.rings.asymptotic.growth_group as agg sage: tuple(agg.MonomialGrowthGroup(ZZ, 'z').some_elements()) (1, z, 1/z, z^2, z^(-2), z^3, z^(-3), z^4, z^(-4), z^5, z^(-5), ...) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 88ac1f73a4c..7a48645a433 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -95,7 +95,7 @@ def product_diagonal(A, B): EXAMPLES:: - sage: from sage.monoids.asymptotic_term_monoid import product_diagonal + sage: from sage.rings.asymptotic.term_monoid import product_diagonal sage: tuple(product_diagonal(srange(2), srange(2))) ((0, 0), (0, 1), (1, 0), (1, 1)) sage: tuple(product_diagonal(srange(4), srange(2))) @@ -1020,8 +1020,8 @@ def some_elements(self): EXAMPLES: - sage: import sage.groups.asymptotic_growth_group as agg - sage: import sage.monoids.asymptotic_term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: tuple(atm.OTermMonoid(G).some_elements()) (O(1), O(x), O(1/x), O(x^2), O(x^(-2)), O(x^3), ...) @@ -1805,8 +1805,8 @@ def some_elements(self): EXAMPLES: sage: from itertools import islice - sage: import sage.groups.asymptotic_growth_group as agg - sage: import sage.monoids.asymptotic_term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('z^QQ') sage: T = atm.ExactTermMonoid(G, ZZ) sage: tuple(islice(T.some_elements(), 10)) From 1374150241da50a1d5b83ab7ed8ab2d8d4b9dc0d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 14:05:06 +0200 Subject: [PATCH 0462/1872] extend cartesian product factory --- .../asymptotic/growth_group_cartesian.py | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index d742fe87344..7e51e280bb5 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -80,19 +80,19 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): Traceback (most recent call last): ... ValueError: Growth groups (Growth Group x^ZZ, Growth Group x^ZZ * y^ZZ) - do not have pairwise distinct variables. + do not have pairwise disjoint variables. sage: cartesian_product([A, B, D]) - Traceback (most recent call last): - ... - ValueError: Growth groups - (Growth Group x^ZZ, Growth Group log(x)^ZZ, Growth Group y^ZZ) - do not have pairwise distinct variables. + Growth Group x^ZZ * log(x)^ZZ * y^ZZ TESTS:: sage: from sage.rings.asymptotic.growth_group_cartesian import CartesianProductFactory sage: CartesianProductFactory('factory')([A, B], category=Sets()) Growth Group x^ZZ * log(x)^ZZ + sage: CartesianProductFactory('factory')([], category=Sets()) + Traceback (most recent call last): + ... + TypeError: Cannot create cartesian product without factors. """ def create_key_and_extra_args(self, growth_groups, category, **kwds): r""" @@ -122,43 +122,45 @@ def create_object(self, version, args, **kwds): Growth Group x^ZZ """ growth_groups, category = args + if not growth_groups: + raise TypeError('Cannot create cartesian product without factors.') order = kwds.pop('order', None) if order is not None: return GenericProduct(growth_groups, category, order=order, **kwds) + vg = tuple((g.variable_names(), g) for g in growth_groups) + # check if all groups have a variable - if not all(g.variable_names() for g in growth_groups): + if not all(v for v, _ in vg): raise NotImplementedError('Growth groups %s have no variable.' % tuple(g for g in growth_groups if not g.variable_names())) - # check if all are univariate - first_var = growth_groups[0].variable_names() - if len(first_var) == 1 and all(g.variable_names() == first_var - for g in growth_groups): - return UnivariateProduct(growth_groups, category, **kwds) - - # check if multivariate and all have distinct single variables - vg = tuple((g.variable_names(), g) for g in growth_groups) - vars = sum(iter(v for v, _ in vg), tuple()) - if len(vars) != len(set(vars)): - raise ValueError('Growth groups %s do not have pairwise distinct variables.' % - (growth_groups,)) - if any(len(v) != 1 for v, _ in vg): - raise NotImplementedError('Cannot build cartesian product since growth ' - 'groups %s do not have single variables.' % - tuple(g for v, g in vg if len(v) != 1)) - - vg = sorted(vg, key=lambda k: k[0]) - from itertools import groupby - sorted_groups = list() - for _, gs in groupby(vg, key=lambda k: k[0]): - gs = tuple(gs) + # sort by variables + from itertools import groupby, product + vgs = tuple((v, tuple(gs)) for v, gs in + groupby(sorted(vg, key=lambda k: k[0]), key=lambda k: k[0])) + + # check if variables are pairwise disjoint + for u, w in product(iter(v for v, _ in vgs), repeat=2): + if u != w and set(u).intersection(set(w)): + raise ValueError('Growth groups %s do not have pairwise disjoint ' + 'variables.' % (growth_groups,)) + + # build cartesian products + u_groups = list() + for _, gs in vgs: + gs = tuple(g for _, g in gs) if len(gs) > 1: - raise ValueError('Growth groups %s do not have pairwise distinct variables.' % - gs) - sorted_groups.append(gs[0][1]) - return MultivariateProduct(tuple(sorted_groups), category, **kwds) + u_groups.append(UnivariateProduct(gs, category, **kwds)) + else: + u_groups.append(gs[0]) + + if len(u_groups) > 1: + m_group = MultivariateProduct(tuple(u_groups), category, **kwds) + else: + m_group = u_groups[0] + return m_group CartesianProductGrowthGroups = CartesianProductFactory('CartesianProductGrowthGroups') From b634767d664ef623b7d2bc94db3fc132f10d3fa9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 14:13:23 +0200 Subject: [PATCH 0463/1872] change output of extract_variable_names --- src/sage/rings/asymptotic/growth_group.py | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6a9ca5019c1..866fc5a7895 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -261,10 +261,10 @@ def __init__(self, var, repr=None): var = tuple(str(v).strip() for v in var) if repr is None: - var_bases = tuple( - self.extract_variable_name(v) - if not isidentifier(v) else v - for v in var) + var_bases = sum(iter( + self.extract_variable_names(v) + if not isidentifier(v) else (v,) + for v in var), tuple()) var_repr = ', '.join(var) else: for v in var: @@ -368,7 +368,7 @@ def is_monomial(self): @staticmethod - def extract_variable_name(s): + def extract_variable_names(s): r""" Finds the name of the variable for the given string. @@ -378,30 +378,30 @@ def extract_variable_name(s): OUTPUT: - A string. + A tuple of strings. EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import Variable - sage: Variable.extract_variable_name('x') - 'x' - sage: Variable.extract_variable_name('exp(x)') - 'x' - sage: Variable.extract_variable_name('sin(cos(ln(x)))') - 'x' - sage: Variable.extract_variable_name('log(77)') + sage: Variable.extract_variable_names('x') + ('x',) + sage: Variable.extract_variable_names('exp(x)') + ('x',) + sage: Variable.extract_variable_names('sin(cos(ln(x)))') + ('x',) + sage: Variable.extract_variable_names('log(77)') Traceback (most recent call last): .... ValueError: '77' is not a valid name for a variable. - sage: Variable.extract_variable_name('log(x') + sage: Variable.extract_variable_names('log(x') Traceback (most recent call last): .... ValueError: Unbalanced parentheses in 'log(x'. - sage: Variable.extract_variable_name('x)') + sage: Variable.extract_variable_names('x)') Traceback (most recent call last): .... ValueError: Unbalanced parentheses in 'x)'. - sage: Variable.extract_variable_name('log)x(') + sage: Variable.extract_variable_names('log)x(') Traceback (most recent call last): .... ValueError: Unbalanced parentheses in 'log)x('. @@ -425,7 +425,7 @@ def strip_fct(s): if not isidentifier(s): raise ValueError("'%s' is not a valid name for a variable." % (s,)) - return s + return (s,) class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): From 9c59fe1e190c0c8a961677f21984539016fb2ba4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 15:26:07 +0200 Subject: [PATCH 0464/1872] lazy import instead of import --- src/sage/rings/asymptotic/growth_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 866fc5a7895..3e13a5414fd 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -103,7 +103,8 @@ #***************************************************************************** import sage -from sage.rings.asymptotic.growth_group_cartesian import CartesianProductGrowthGroups +from sage.misc.lazy_import import lazy_import +lazy_import('sage.rings.asymptotic.growth_group_cartesian', 'CartesianProductGrowthGroups') def repr_short_to_parent(s): From 3fe816a00c0225cf99372c6366933b4b845a7f96 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 15:26:33 +0200 Subject: [PATCH 0465/1872] extend extraction of variable names --- src/sage/rings/asymptotic/growth_group.py | 84 ++++++++++++++++++----- 1 file changed, 65 insertions(+), 19 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 3e13a5414fd..bed13a58282 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -216,9 +216,7 @@ class Variable(sage.structure.unique_representation.CachedRepresentation, sage: v = Variable('x '); repr(v), v.variable_names() ('x', ('x',)) sage: v = Variable(''); repr(v), v.variable_names() - Traceback (most recent call last): - ... - ValueError: '' is not a valid name for a variable. + ('', ()) :: @@ -384,16 +382,21 @@ def extract_variable_names(s): EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable.extract_variable_names('') + () sage: Variable.extract_variable_names('x') ('x',) sage: Variable.extract_variable_names('exp(x)') ('x',) sage: Variable.extract_variable_names('sin(cos(ln(x)))') ('x',) - sage: Variable.extract_variable_names('log(77)') + + :: + + sage: Variable.extract_variable_names('log(77w)') Traceback (most recent call last): .... - ValueError: '77' is not a valid name for a variable. + ValueError: '77w' is not a valid name for a variable. sage: Variable.extract_variable_names('log(x') Traceback (most recent call last): .... @@ -406,27 +409,70 @@ def extract_variable_names(s): Traceback (most recent call last): .... ValueError: Unbalanced parentheses in 'log)x('. + + :: + + sage: Variable.extract_variable_names('a + b') + ('a', 'b') + sage: Variable.extract_variable_names('a+b') + ('a', 'b') + sage: Variable.extract_variable_names('a +b') + ('a', 'b') + sage: Variable.extract_variable_names('+a') + ('a',) + sage: Variable.extract_variable_names('a+') + ('a',) + sage: Variable.extract_variable_names('b!') + ('b',) + sage: Variable.extract_variable_names('-a') + ('a',) + sage: Variable.extract_variable_names('a*b') + ('a', 'b') + sage: Variable.extract_variable_names('2^q') + ('q',) + sage: Variable.extract_variable_names('77') + () """ from sage.symbolic.ring import isidentifier - s = s.strip() + import re + numbers = re.compile(r"\d+$") + vars = [] - def strip_fct(s): + def strip(s): + s = s.strip() + if not s: + return + + # parentheses (...) + # functions f(...) op = s.find('(') cl = s.rfind(')') - if op == -1 and cl == -1: - return s if (op == -1) != (cl == -1) or op > cl: raise ValueError("Unbalanced parentheses in '%s'." % (s,)) - return s[op+1:cl] - - s_old = '' - while s != s_old: - s_old = s - s = strip_fct(s) - - if not isidentifier(s): - raise ValueError("'%s' is not a valid name for a variable." % (s,)) - return (s,) + if cl == len(s) - 1: + strip(s[op+1:cl]) + return + + # unary +a, a+, ... + # binary a+b, a*b, ... + for operator in ('**', '+', '-', '*', '/', '^', '!'): + a, o, b = s.partition(operator) + if o: + strip(a) + strip(b) + return + + # a number + if numbers.match(s) is not None: + return + + # else: a variable + if not isidentifier(s): + raise ValueError("'%s' is not a valid name for a variable." % (s,)) + vars.append(s) + + strip(s) + return tuple(vars) class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): From 9f65f8b18c3f30840e38c92d4bbf68b674086e43 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 16:13:48 +0200 Subject: [PATCH 0466/1872] delete .one, since provided by categories --- src/sage/rings/asymptotic/growth_group.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index bed13a58282..a0fa38b7002 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1053,29 +1053,6 @@ def le(self, left, right): return self(left) <= self(right) - def one(self): - r""" - Return the neutral element of this growth group. - - INPUT: - - Nothing. - - OUTPUT: - - An element of this group. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: e1 = agg.MonomialGrowthGroup(ZZ, 'x').one(); e1 - 1 - sage: e1.is_idempotent() - True - """ - return self(1) - - def _element_constructor_(self, data, raw_element=None): r""" Converts a given object to this growth group. From 08f10df920872e4a409e02a00582657df62ea7d0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 16:14:22 +0200 Subject: [PATCH 0467/1872] inherite cartesian product from growth group as well --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- src/sage/rings/asymptotic/growth_group_cartesian.py | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index a0fa38b7002..eabe6859673 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -835,8 +835,8 @@ def _le_(self, other): class GenericGrowthGroup( - sage.structure.parent.Parent, - sage.structure.unique_representation.UniqueRepresentation): + sage.structure.unique_representation.UniqueRepresentation, + sage.structure.parent.Parent): r""" An abstract implementation for growth groups. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 7e51e280bb5..6f5455ddaa2 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -167,7 +167,8 @@ def create_object(self, version, args, **kwds): from sage.sets.cartesian_product import CartesianProductPosets -class GenericProduct(CartesianProductPosets): +from sage.rings.asymptotic.growth_group import GenericGrowthGroup +class GenericProduct(CartesianProductPosets, GenericGrowthGroup): r""" A cartesian product of growth groups. @@ -357,6 +358,9 @@ def _convert_to_factor_(self, data): continue + def _coerce_map_from_(self, S): + pass + def gens_monomial(self): r""" From bea6f0d865d768a1eb73638e591f038ae9fd708b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 16:15:44 +0200 Subject: [PATCH 0468/1872] fixed negative powers of O-Terms --- src/sage/rings/asymptotic/asymptotic_ring.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index acc42983787..792d2179f32 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -591,6 +591,13 @@ def __pow__(self, power): ValueError: Growth Group y^ZZ disallows taking y to the power of 1/7. sage: (x^(1/2) + O(x^0))^15 x^(15/2) + O(x^7) + + :: + + sage: O(x)^(-1) + Traceback (most recent call last): + ... + NotImplementedError: Negative powers are not implemented for the term O(x). """ if len(self.summands) > 1: from sage.rings.integer_ring import ZZ @@ -613,8 +620,12 @@ def __pow__(self, power): new_coeff = expr.coefficient**power return P(expr.parent()(new_growth, new_coeff)) else: - new_growth = expr.growth**power - return P(expr.parent()(new_growth)) + if power >= 0: + new_growth = expr.growth**power + return P(expr.parent()(new_growth)) + else: + raise NotImplementedError('Negative powers are not implemented' + ' for the term %s.' % (self, )) From 5d1d3c0a1f13bfaff7d92ac14d7a0b67b61d2c65 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 16:16:51 +0200 Subject: [PATCH 0469/1872] new property default_prec implemented --- src/sage/rings/asymptotic/asymptotic_ring.py | 41 +++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 792d2179f32..0e650a23ef2 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -685,6 +685,9 @@ class AsymptoticRing(sage.rings.ring.Ring, - ``coefficient_ring`` -- the ring which contains the coefficients of the expressions. + - ``default_prec`` -- a positive integer. This is the number of + summands that are kept before truncating an infinite series. + - ``category`` -- the category of the parent can be specified in order to broaden the base structure. It has to be a subcategory of ``Category of rings``. This is also the default @@ -759,7 +762,7 @@ class AsymptoticRing(sage.rings.ring.Ring, @staticmethod def __classcall__(cls, growth_group, coefficient_ring, names=None, - category=None): + category=None, default_prec=None): r""" Normalizes the input in order to ensure a unique representation of the parent. @@ -795,13 +798,19 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, if names is not None and not growth_group.gens_monomial(): raise ValueError("%s does not have a generator." % (growth_group,)) - return super(AsymptoticRing, cls).__classcall__(cls, growth_group, - coefficient_ring, - category) + if default_prec is None: + from sage.misc.defaults import series_precision + default_prec = series_precision() + + return super(AsymptoticRing, + cls).__classcall__(cls, growth_group, coefficient_ring, + category=category, + default_prec=default_prec) @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, growth_group, coefficient_ring, category=None): + def __init__(self, growth_group, coefficient_ring, category=None, + default_prec=None): r""" See :class:`AsymptoticRing` for more information. @@ -841,6 +850,7 @@ def __init__(self, growth_group, coefficient_ring, category=None): self._coefficient_ring_ = coefficient_ring self._growth_group_ = growth_group + self._default_prec_ = default_prec super(AsymptoticRing, self).__init__(base=coefficient_ring, category=category) @@ -877,6 +887,27 @@ def coefficient_ring(self): return self._coefficient_ring_ + @property + def default_prec(self): + r""" + The default precision of this asymptotic ring. + + This is the parameter used to determine how many summands + are kept before truncating an infinite series (which occur + when inverting asymptotic expressions). + + EXAMPLES:: + + sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) + sage: AR.default_prec + 20 + sage: AR = AsymptoticRing('x^ZZ', ZZ, default_prec=123) + sage: AR.default_prec + 123 + """ + return self._default_prec_ + + @staticmethod def _create_empty_summands_(): r""" From f67cb030cc42b1595a14f95dad9555dcf8c5b604 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 16:20:23 +0200 Subject: [PATCH 0470/1872] simplify and adapt gens_monomial() --- src/sage/rings/asymptotic/growth_group.py | 15 +++------------ .../rings/asymptotic/growth_group_cartesian.py | 9 ++++----- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index eabe6859673..e98ce4aca80 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1217,24 +1217,15 @@ def gens_monomial(self): OUTPUT: - An element of this growth group or ``None``. - - .. NOTE:: - - This method is only implemented for concrete growth - group implementations. + An empty tuple. TESTS:: sage: import sage.rings.asymptotic.growth_group as agg sage: agg.GenericGrowthGroup(ZZ).gens_monomial() - Traceback (most recent call last): - ... - NotImplementedError: Only implemented for concrete growth group - implementations. + () """ - raise NotImplementedError("Only implemented for concrete growth group" - " implementations.") + return tuple() def variable_names(self): diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 6f5455ddaa2..27c2b0954b7 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -298,7 +298,7 @@ def _repr_(self): sage: cartesian_product([P, L], order='lex')._repr_() 'Growth Group x^QQ * log(x)^ZZ' """ - return 'Growth Group ' + self._repr_short_() + return GenericGrowthGroup._repr_(self) def _repr_short_(self): @@ -387,10 +387,9 @@ def gens_monomial(self): sage: G.gens_monomial() (x, y) """ - t = () - for factor in self.cartesian_factors(): - t = t + factor.gens_monomial() - return t + return sum(iter(factor.gens_monomial() + for factor in self.cartesian_factors()), + tuple()) def variable_names(self): From 925d700f3c0b44fbf15acbc1cda7ba77dd83b336 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 16:22:01 +0200 Subject: [PATCH 0471/1872] pass flags of repr --- src/sage/rings/asymptotic/growth_group_cartesian.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 27c2b0954b7..eb61743b415 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -278,13 +278,15 @@ def _element_constructor_(self, data): return self(str_lst) - def _repr_(self): + def _repr_(self, condense=False): r""" - A representation string for this cartesian product of growth groups. + A representation string of this cartesian product of growth groups. INPUT: - Nothing. + - ``condense`` -- (default: ``False``) if set, then a shorter + output is returned, e.g. the prefix-string ``Growth Group`` + is not show in this case. OUTPUT: @@ -298,7 +300,7 @@ def _repr_(self): sage: cartesian_product([P, L], order='lex')._repr_() 'Growth Group x^QQ * log(x)^ZZ' """ - return GenericGrowthGroup._repr_(self) + return GenericGrowthGroup._repr_(self, condense) def _repr_short_(self): From 68643c40c9f1fd8819ff282fb2d88a8227fe9f67 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 18:11:52 +0200 Subject: [PATCH 0472/1872] better parsing variables --- src/sage/rings/asymptotic/growth_group.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index e98ce4aca80..334736b09cd 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -409,6 +409,8 @@ def extract_variable_names(s): Traceback (most recent call last): .... ValueError: Unbalanced parentheses in 'log)x('. + sage: Variable.extract_variable_names('log(x)+y') + ('x', 'y') :: @@ -438,6 +440,18 @@ def extract_variable_names(s): numbers = re.compile(r"\d+$") vars = [] + def find_next_outer_parentheses(s): + op = s.find('(') + level = 1 + for i, c in enumerate(s[op+1:]): + if c == ')': + level -= 1 + if c == '(': + level += 1 + if level == 0: + return op, op+i+1 + return op, -1 + def strip(s): s = s.strip() if not s: @@ -445,12 +459,12 @@ def strip(s): # parentheses (...) # functions f(...) - op = s.find('(') - cl = s.rfind(')') + op, cl = find_next_outer_parentheses(s) if (op == -1) != (cl == -1) or op > cl: raise ValueError("Unbalanced parentheses in '%s'." % (s,)) - if cl == len(s) - 1: + if cl != -1: strip(s[op+1:cl]) + strip(s[cl+1:]) return # unary +a, a+, ... From 58dbda77f94dde572dce7d1ccaa47f87aa70f1c6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 18:12:06 +0200 Subject: [PATCH 0473/1872] better parsing growth group factory --- src/sage/rings/asymptotic/growth_group.py | 41 +++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 334736b09cd..4bac7dc5f5e 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1979,10 +1979,47 @@ def create_key_and_extra_args(self, specification, **kwds): Traceback (most recent call last): ... ValueError: 'asdf' is not a valid string describing a growth group. + sage: agg.GrowthGroup.create_key_and_extra_args('log(x)^ZZ * y^QQ') + (('log(x)^ZZ', 'y^QQ'), {}) + sage: agg.GrowthGroup.create_key_and_extra_args('log(x)**ZZ * y**QQ') + (('log(x)**ZZ', 'y**QQ'), {}) + sage: agg.GrowthGroup.create_key_and_extra_args('a^b * * c^d') + Traceback (most recent call last): + ... + ValueError: 'a^b * * c^d' is invalid since a '*' follows a '*' + sage: agg.GrowthGroup.create_key_and_extra_args('a^b * (c*d^e)') + (('a^b', 'c*d^e'), {}) """ - factors = tuple(s.strip() for s in specification.split('*')) + factors = list() + balanced = True + if specification and specification[0] == '*': + raise ValueError("'%s' is invalid since it starts with a '*'." % + (specification,)) + for s in specification.split('*'): + if not s: + factors[-1] += '*' + balanced = False + continue + if not s.strip(): + raise ValueError("'%s' is invalid since a '*' follows a '*'" % + (specification,)) + if not balanced: + s = factors.pop() + '*' + s + balanced = s.count('(') == s.count(')') + factors.append(s) + + def strip(s): + s = s.strip() + if not s: + return s + if s[0] == '(' and s[-1] == ')': + s = s[1:-1] + return s.strip() + + factors = tuple(strip(f) for f in factors) + for f in factors: - if '^' not in f: + if '^' not in f and '**' not in f: raise ValueError("'%s' is not a valid string describing " "a growth group." % (f,)) From ab9ae6fe6125c823c08beffb7a8ecedf6af0922b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 18:46:46 +0200 Subject: [PATCH 0474/1872] division implemented --- src/sage/rings/asymptotic/asymptotic_ring.py | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0e650a23ef2..0404fca3173 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -567,6 +567,28 @@ def _mul_(self, other): term_other in other.summands.elements())) + def _div_(self, other): + r""" + Divide this element through ``other``. + + INPUT: + + - ``other`` -- an asymptotic expression. + + OUTPUT: + + An asymptotic expression. + + EXAMPLES:: + + sage: R. = AsymptoticRing('x^ZZ', QQ) + sage: 1/x^42 + x^(-42) + sage: x^2 / (1 + x) # not tested + ... + """ + return self * other._invert_() + def __pow__(self, power): r""" Takes this element to the given ``power``. From 095b98740f4428ae47e057fc4367a532aca045e2 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 18:47:06 +0200 Subject: [PATCH 0475/1872] inversion and truncation implemented --- src/sage/rings/asymptotic/asymptotic_ring.py | 100 +++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0404fca3173..a6fc98cf3e9 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -589,6 +589,106 @@ def _div_(self, other): """ return self * other._invert_() + + def _invert_(self): + r""" + Return the multiplicative inverse of this element. + + INPUT: + + Nothing. + + OUTPUT: + + An asymptotic expression. + + .. WARNING:: + + Due to truncation of infinite expansions, the element + returned by this method might not fulfill + ``el * el._invert_() == 1``. + + EXAMPLES:: + + sage: R. = AsymptoticRing('x^ZZ', QQ) + sage: x._invert_() + 1/x + sage: (x^42)._invert_() + x^(-42) + sage: (1 + x)._invert_() + asdf + sage: (1 + O(1/x))._invert_() + asdf + """ + if len(self.summands) == 0: + raise ZeroDivisionError('Dividing by zero is not allowed.') + + elif len(self.summands) == 1: + return self**(-1) + + max_elem = list(self.summands.maximal_elements()) + if len(max_elem) != 1: + raise ValueError('Expression %s cannot be inverted: ' + 'there are multiple maximal elements.' % (self, )) + + max_elem = self.parent()(max_elem[0]) + + geom = 1 - self / max_elem + expanding = True + result = 1 + while expanding: + new_result = (geom * result + 1).truncate() + if new_result == result: + expanding = False + result = new_result + return result / max_elem + + + def truncate(self, prec=None): + r""" + Truncate this asymptotic expression. + + INPUT: + + - ``prec`` -- a positive integer or ``None``. Number of + summands that are kept. If ``None`` (default value) is + given, then ``default_prec`` from the parent is used. + + OUTPUT: + + An asymptotic expression. + + .. NOTE:: + + For example, truncating an asymptotic expression with + ``prec=20`` does not yield an expression with exactly 20 + summands! Rather than that, it keeps the 20 summands + with the largest growth, and adds an appropriate + `O`-Term. + + EXAMPLES:: + + sage: R. = AsymptoticRing('x^ZZ', QQ) + sage: ex = sum(x^k for k in range(5)); ex + x^4 + x^3 + x^2 + x + 1 + sage: ex.truncate(prec=2) + x^4 + x^3 + O(x^2) + sage: ex.truncate(prec=0) + O(x^4) + sage: ex.truncate() + x^4 + x^3 + x^2 + x + 1 + """ + if prec is None: + prec = self.parent().default_prec + + if len(self.summands) <= prec: + return self + else: + g = self.summands.elements_topological(reverse=True) + main_part = self.parent()([g.next() for _ in range(prec)]) + return main_part + (self - main_part).O() + + def __pow__(self, power): r""" Takes this element to the given ``power``. From d258eb9ec1e9d797cbfb168921cda361b56df077 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 19:38:11 +0200 Subject: [PATCH 0476/1872] two types of equality for asymptotic expressions implemented; is_equal_term for exact terms and O-Terms implemented --- src/sage/rings/asymptotic/asymptotic_ring.py | 105 ++++++++++++++ src/sage/rings/asymptotic/term_monoid.py | 137 +++++++++++++++++++ 2 files changed, 242 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index a6fc98cf3e9..fd2489176f6 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -372,6 +372,111 @@ def __nonzero__(self): return bool(self._summands_) + def __eq__(self, other): + r""" + Return if this asymptotic expression is equal to ``other``. + + INPUT: + + - ``other`` -- an object. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This function uses the coercion model to find a common + parent for the two operands. + + EXAMPLES:: + + sage: R. = AsymptoticRing('x^ZZ', QQ) + sage: (1 + 2*x + 3*x^2) == (3*x^2 + 2*x + 1) # indirect doctest + True + sage: O(x) == O(x) + False + """ + return (self - other) == 0 + + + def has_same_summands(self, other): + r""" + Return if this asymptotic expression and ``other`` have the + same summands. + + INPUT: + + - ``other`` -- an asymptotic expression. + + OUTPUT: + + A boolean. + + .. NOTE:: + + While for example ``O(x) == O(x)`` yields ``False``, + these expressions *do* have the same summands. + + Also, this method uses the coercion model in order to + find a common parent for this asymptotic expression and + ``other``. The method :meth:`_has_same_summands_` is + then used for the actual comparison. + + EXAMPLES:: + + sage: R_ZZ. = AsymptoticRing('x^ZZ', ZZ) + sage: R_QQ. = AsymptoticRing('x^ZZ', QQ) + sage: sum(x_ZZ^k for k in range(5)) == sum(x_QQ^k for k in range(5)) # indirect doctest + True + sage: O(x_ZZ) == O(x_QQ) + False + """ + from sage.structure.element import have_same_parent + + if have_same_parent(self, other): + return self._has_same_summands_(other) + + from sage.structure.element import get_coercion_model + + return get_coercion_model().bin_op(self, other, + lambda self, other: + self._has_same_summands_(other)) + + + def _has_same_summands_(self, other): + r""" + Return, if this :class:`AsymptoticExpression` has the same + summands as ``other``. + + INPUT: + + - ``other`` -- an :class:`AsymptoticExpression`. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method compares two :class:`AsymptoticExpression` + with the same parent. + + EXAMPLES:: + + sage: R. = AsymptoticRing('x^ZZ', QQ) + sage: O(x).has_same_summands(O(x)) + True + sage: (1 + x + 2*x^2).has_same_summands(2*x^2 + O(x)) # indirect doctest + False + """ + if len(self.summands) != len(other.summands): + return False + pairs = zip(self.summands.elements_topological(), + other.summands.elements_topological()) + return all(p[0].is_same_term(p[1]) for p in pairs) + + def _simplify_(self): r""" Simplify this asymptotic expression. diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 68724cc23ef..6dfe6cd787d 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -600,6 +600,75 @@ def _le_(self, other): return self.growth <= other.growth + def is_same_term(self, other): + r""" + Return if this :class:`ExactTerm` is the same as ``other``. + + INPUT: + + - ``other`` -- an object. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This function uses the coercion model to find a common + parent for the two operands. + + EXAMPLES:: + + sage: # todo + """ + from sage.structure.element import have_same_parent + + if have_same_parent(self, other): + return self._is_same_term_(other) + + from sage.structure.element import get_coercion_model + + return get_coercion_model().bin_op(self, other, + lambda self, other: + self._is_same_term_(other)) + + + def _is_same_term_(self, other): + r""" + Return if this asymptotic term is the same as ``other``. + + INPUT: + + - ``other`` -- an asymptotic term. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method gets called by the coercion framework, so it + can be assumed that this asymptotic term is from the + same parent as ``other``. + + Only implemented in classes that are used within + :mod:`sage.rings.asymptotic.asymptotic_ring`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: T = GenericTermMonoid(GrowthGroup('x^ZZ')) + sage: t = T.an_element() + sage: t.is_same_term(t) + Traceback (most recent call last): + ... + NotImplementedError: Only implemented for terms used in the asymptotic ring. + """ + raise NotImplementedError('Only implemented for terms used in the ' + 'asymptotic ring.') + + def _repr_(self): r""" A representation string for this generic term. @@ -1058,6 +1127,39 @@ def _absorb_(self, other): return self + def _is_same_term_(self, other): + r""" + Return if this :class:`OTerm` is the same as ``other``. + + INPUT: + + - ``other`` -- an :class:`OTerm`. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method gets called by the coercion model, so it can + be assumed that this :class:`OTerm` and ``other`` come + from the same parent. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import OTermMonoid + sage: OT = OTermMonoid(GrowthGroup('x^ZZ')) + sage: t = OT.an_element(); t + O(x) + sage: t.is_same_term(OT(x)) + True + sage: t.is_same_term(OT(x^2)) + False + """ + return self.growth == other.growth + + class OTermMonoid(GenericTermMonoid): r""" Parent for asymptotic big `O`-terms. @@ -1841,6 +1943,41 @@ def _absorb_(self, other): return self.parent()(self.growth, coeff_new) + def _is_same_term_(self, other): + r""" + Return if this :class:`ExactTerm` is the same as ``other``. + + INPUT: + + - ``other`` -- an :class:`ExactTerm`. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method gets called by the coercion model, so it can + be assumed that this :class:`ExactTerm` and ``other`` + come from the same parent. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import ExactTermMonoid + sage: ET = ExactTermMonoid(GrowthGroup('x^ZZ'), ZZ) + sage: t = ET.an_element(); t + x + sage: t.is_same_term(ET(x)) + True + sage: t.is_same_term(ET(2*x)) + False + sage: t.is_same_term(ET(x^2)) + False + """ + return self.growth == other.growth and self.coefficient == other.coefficient + + class ExactTermMonoid(TermWithCoefficientMonoid): r""" Parent for asymptotic exact terms, implemented in From f326e4f7ef681faf97df2af7aacb414894a36633 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 19:52:03 +0200 Subject: [PATCH 0477/1872] fixed endless recursion in __eq__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index fd2489176f6..af4c1a27ba5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -397,7 +397,7 @@ def __eq__(self, other): sage: O(x) == O(x) False """ - return (self - other) == 0 + return not bool(self - other) def has_same_summands(self, other): From 8eb21a6b28a73f28d5d6f490c1f3c59b6ee70d56 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 19:52:16 +0200 Subject: [PATCH 0478/1872] used correct type of equality in truncate --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index af4c1a27ba5..91e588cd9a0 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -743,7 +743,7 @@ def _invert_(self): result = 1 while expanding: new_result = (geom * result + 1).truncate() - if new_result == result: + if new_result.has_same_summands(result): expanding = False result = new_result return result / max_elem From d72a173f0bee5a0831b05bd3e93f0f619791aeff Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 19:52:32 +0200 Subject: [PATCH 0479/1872] fixed doctests --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 91e588cd9a0..3d3b9248b73 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -715,15 +715,15 @@ def _invert_(self): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', QQ) + sage: R. = AsymptoticRing('x^ZZ', QQ, default_prec=4) sage: x._invert_() 1/x sage: (x^42)._invert_() x^(-42) sage: (1 + x)._invert_() - asdf + 1/x - x^(-2) + x^(-3) - x^(-4) + O(x^(-5)) sage: (1 + O(1/x))._invert_() - asdf + 1 + O(1/x) """ if len(self.summands) == 0: raise ZeroDivisionError('Dividing by zero is not allowed.') From b7bb595cc37bab9e00165273de63a725590a684d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 21 Aug 2015 20:20:54 +0200 Subject: [PATCH 0480/1872] rewrite factory to use previous enhancements --- src/sage/rings/asymptotic/growth_group.py | 42 +++++------------------ 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 4bac7dc5f5e..27062a1f965 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -84,11 +84,17 @@ sage: e1 <= e2 or e2 <= e1 False -In terms of uniqueness, the order of factors in the cartesian -product matters:: +In terms of uniqueness, we have the following behaviour:: sage: agg.GrowthGroup('x^ZZ * y^ZZ') is agg.GrowthGroup('y^ZZ * x^ZZ') + True + +The above is ``True`` since the order of the factors does not play a role here; they use different variables. But when using the same variable, it plays a role:: + + sage: agg.GrowthGroup('x^ZZ * log(x)^ZZ') is agg.GrowthGroup('log(x)^ZZ * x^ZZ') False + +(Note that it is mathematically nonsense to make ``log(x)`` larger than ``x``.) """ #***************************************************************************** @@ -2074,38 +2080,8 @@ def create_object(self, version, factors, **kwds): if len(groups) == 1: return groups[0] - # otherwise, a cartesian product is created. the growth elements - # in this products are - # - ordered lexicographically (over the same variable (or a - # function thereof) - # - ordered component-wise (for different variables) - - if len(set(groups)) != len(groups): - raise ValueError('The cartesian product of equal growth ' - 'groups is not supported') - - equal_var_groups = [] - vars = [] - for group in groups: - var = repr(group._var_) - if not vars or '(' + vars[-1] + ')' not in var: - vars.append(var) - equal_var_groups.append([group]) - else: - equal_var_groups[-1].append(group) - from sage.categories.cartesian_product import cartesian_product - for k in range(len(equal_var_groups)): - if len(equal_var_groups[k]) > 1: - equal_var_groups[k] = cartesian_product(equal_var_groups[k], - order='lex') - else: - equal_var_groups[k] = equal_var_groups[k][0] - - if len(equal_var_groups) == 1: - return equal_var_groups[0] - - return cartesian_product(equal_var_groups, order='components') + return cartesian_product(groups) GrowthGroup = GrowthGroupFactory("GrowthGroup") From fec5796f1240ac0813432226a38f330878f9e5d9 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 20:25:20 +0200 Subject: [PATCH 0481/1872] _is_same_term_ moved to TermWithCoefficient --- src/sage/rings/asymptotic/term_monoid.py | 72 ++++++++++++------------ 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 16b3d9655d9..b5e8164a784 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1468,6 +1468,43 @@ def _le_(self, other): return super(TermWithCoefficient, self)._le_(other) + def _is_same_term_(self, other): + r""" + Return if this :class:`TermWithCoefficient` is the same as + ``other``. + + INPUT: + + - ``other`` -- an :class:`TermWithCoefficient`. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method gets called by the coercion model, so it can + be assumed that this :class:`TermWithCoefficient` and + ``other`` come from the same parent. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), ZZ) + sage: t = T.an_element(); t + Asymptotic Term with coefficient 1 and growth x + sage: t.is_same_term(T(x, 1)) + True + sage: t.is_same_term(T(x, 2)) + False + sage: t.is_same_term(T(x^2, 1)) + False + """ + return self.growth == other.growth and self.coefficient == other.coefficient + + + class TermWithCoefficientMonoid(GenericTermMonoid): r""" This class implements the base structure for parents of @@ -1943,41 +1980,6 @@ def _absorb_(self, other): return self.parent()(self.growth, coeff_new) - def _is_same_term_(self, other): - r""" - Return if this :class:`ExactTerm` is the same as ``other``. - - INPUT: - - - ``other`` -- an :class:`ExactTerm`. - - OUTPUT: - - A boolean. - - .. NOTE:: - - This method gets called by the coercion model, so it can - be assumed that this :class:`ExactTerm` and ``other`` - come from the same parent. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: from sage.rings.asymptotic.term_monoid import ExactTermMonoid - sage: ET = ExactTermMonoid(GrowthGroup('x^ZZ'), ZZ) - sage: t = ET.an_element(); t - x - sage: t.is_same_term(ET(x)) - True - sage: t.is_same_term(ET(2*x)) - False - sage: t.is_same_term(ET(x^2)) - False - """ - return self.growth == other.growth and self.coefficient == other.coefficient - - class ExactTermMonoid(TermWithCoefficientMonoid): r""" Parent for asymptotic exact terms, implemented in From b8ccae1d811fddcc2f48cdff202824200256e44e Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 20:26:42 +0200 Subject: [PATCH 0482/1872] documentation adapted --- src/sage/rings/asymptotic/term_monoid.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index b5e8164a784..3d743174780 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -651,8 +651,7 @@ def _is_same_term_(self, other): can be assumed that this asymptotic term is from the same parent as ``other``. - Only implemented in classes that are used within - :mod:`sage.rings.asymptotic.asymptotic_ring`. + Only implemented in concrete realizations. EXAMPLES:: @@ -663,10 +662,9 @@ def _is_same_term_(self, other): sage: t.is_same_term(t) Traceback (most recent call last): ... - NotImplementedError: Only implemented for terms used in the asymptotic ring. + NotImplementedError: Only implemented in concrete realizations. """ - raise NotImplementedError('Only implemented for terms used in the ' - 'asymptotic ring.') + raise NotImplementedError('Only implemented in concrete realizations.') def _repr_(self): From 0346e60a53cd1915be0c2c21d2a2af7465414196 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 20:36:02 +0200 Subject: [PATCH 0483/1872] refactored: is_same_term --> is_same --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/term_monoid.py | 26 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 3d3b9248b73..bc9a23d28d7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -474,7 +474,7 @@ def _has_same_summands_(self, other): return False pairs = zip(self.summands.elements_topological(), other.summands.elements_topological()) - return all(p[0].is_same_term(p[1]) for p in pairs) + return all(p[0].is_same(p[1]) for p in pairs) def _simplify_(self): diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 3d743174780..a1faa35f118 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -600,9 +600,9 @@ def _le_(self, other): return self.growth <= other.growth - def is_same_term(self, other): + def is_same(self, other): r""" - Return if this :class:`ExactTerm` is the same as ``other``. + Return if this asymptotic term is the same as ``other``. INPUT: @@ -624,16 +624,16 @@ def is_same_term(self, other): from sage.structure.element import have_same_parent if have_same_parent(self, other): - return self._is_same_term_(other) + return self._is_same_(other) from sage.structure.element import get_coercion_model return get_coercion_model().bin_op(self, other, lambda self, other: - self._is_same_term_(other)) + self._is_same_(other)) - def _is_same_term_(self, other): + def _is_same_(self, other): r""" Return if this asymptotic term is the same as ``other``. @@ -659,7 +659,7 @@ def _is_same_term_(self, other): sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid sage: T = GenericTermMonoid(GrowthGroup('x^ZZ')) sage: t = T.an_element() - sage: t.is_same_term(t) + sage: t.is_same(t) Traceback (most recent call last): ... NotImplementedError: Only implemented in concrete realizations. @@ -1125,7 +1125,7 @@ def _absorb_(self, other): return self - def _is_same_term_(self, other): + def _is_same_(self, other): r""" Return if this :class:`OTerm` is the same as ``other``. @@ -1150,9 +1150,9 @@ def _is_same_term_(self, other): sage: OT = OTermMonoid(GrowthGroup('x^ZZ')) sage: t = OT.an_element(); t O(x) - sage: t.is_same_term(OT(x)) + sage: t.is_same(OT(x)) # indirect doctest True - sage: t.is_same_term(OT(x^2)) + sage: t.is_same(OT(x^2)) # indirect doctest False """ return self.growth == other.growth @@ -1466,7 +1466,7 @@ def _le_(self, other): return super(TermWithCoefficient, self)._le_(other) - def _is_same_term_(self, other): + def _is_same_(self, other): r""" Return if this :class:`TermWithCoefficient` is the same as ``other``. @@ -1492,11 +1492,11 @@ def _is_same_term_(self, other): sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), ZZ) sage: t = T.an_element(); t Asymptotic Term with coefficient 1 and growth x - sage: t.is_same_term(T(x, 1)) + sage: t.is_same(T(x, 1)) True - sage: t.is_same_term(T(x, 2)) + sage: t.is_same(T(x, 2)) False - sage: t.is_same_term(T(x^2, 1)) + sage: t.is_same(T(x^2, 1)) False """ return self.growth == other.growth and self.coefficient == other.coefficient From 56e3816bacb3439ded1b2be8d1bd7ad0a9776852 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 20:36:16 +0200 Subject: [PATCH 0484/1872] added doctests for is_same --- src/sage/rings/asymptotic/term_monoid.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index a1faa35f118..eda233d53c1 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -619,7 +619,25 @@ def is_same(self, other): EXAMPLES:: - sage: # todo + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, + ....: ExactTermMonoid, OTermMonoid) + sage: GT = GenericTermMonoid(GrowthGroup('x^ZZ')) + sage: ET = ExactTermMonoid(GrowthGroup('x^ZZ'), ZZ) + sage: OT = OTermMonoid(GrowthGroup('x^ZZ')) + sage: g = GT.an_element(); e = ET.an_element(); o = OT.an_element() + sage: g, e, o + (Generic Term with growth x, x, O(x)) + sage: g.is_same(g^2) + Traceback (most recent call last): + ... + NotImplementedError: Only implemented in concrete realizations. + sage: e.is_same(e^2) + False + sage: e.is_same(ET(x,1)) + True + sage: o.is_same(OT(x^2)) + False """ from sage.structure.element import have_same_parent From 03c28332d5da7c7b59886d031e2eb618406a27cf Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 20:45:14 +0200 Subject: [PATCH 0485/1872] doctests for _div_ and _invert_ improved --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index bc9a23d28d7..7e66787ea77 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -686,11 +686,15 @@ def _div_(self, other): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', QQ) + sage: R. = AsymptoticRing('x^ZZ', QQ, default_prec=5) sage: 1/x^42 x^(-42) - sage: x^2 / (1 + x) # not tested + sage: (1 + 4*x) / (x + 2*x^2) + 2*1/x - 1/2*x^(-2) + 1/4*x^(-3) - 1/8*x^(-4) + 1/16*x^(-5) + O(x^(-6)) + sage: x / O(x) + Traceback (most recent call last): ... + NotImplementedError: Negative powers are not implemented for the term O(x). """ return self * other._invert_() @@ -720,8 +724,10 @@ def _invert_(self): 1/x sage: (x^42)._invert_() x^(-42) - sage: (1 + x)._invert_() + sage: ex = (1 + x)._invert_(); ex 1/x - x^(-2) + x^(-3) - x^(-4) + O(x^(-5)) + sage: ex * (1 + x) + 1 + O(x^(-4)) sage: (1 + O(1/x))._invert_() 1 + O(1/x) """ From 97f15e6f5b8728996a33e818671153c938fa974a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 21 Aug 2015 20:57:00 +0200 Subject: [PATCH 0486/1872] mentioned inversion in the module description --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 7e66787ea77..ad5e9930fbb 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -150,9 +150,13 @@ sage: (z + 2*z^2 + 3*z^3 + 4*z^4) * (O(z) + z^2) 4*z^6 + O(z^5) -.. TODO:: +The division of asymptotic expressions is implemented as well:: - inversions + sage: A. = AsymptoticRing('z^QQ', QQ, default_prec=10) + sage: 1/(z - 1) + 1/z + z^(-2) + z^(-3) + z^(-4) + ... + z^(-10) + O(z^(-11)) + sage: (1 + 4*z)/(z + z^2 + z^3) + 4*z^(-2) - 3*z^(-3) - z^(-4) + 4*z^(-5) - 3*z^(-6) - ... - z^(-16) + O(z^(-17)) .. TODO:: From 132fec81ca41f5e448632882dd38ab5b104a788a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 08:23:09 +0200 Subject: [PATCH 0487/1872] write variable_names --- src/sage/rings/asymptotic/growth_group.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cae808b38b3..2085bf14d60 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2521,6 +2521,25 @@ def ngens(self): return len(self.gens()) + def variable_names(self): + r""" + Return the names of the variables. + + OUTPUT: + + A tuple of strings. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('QQ^x').variable_names() + ('x',) + sage: GrowthGroup('QQ^(x*log(x))').variable_names() + ('x',) + """ + return self._var_.variable_names() + + class GrowthGroupFactory(sage.structure.factory.UniqueFactory): r""" A factory creating asymptotic growth groups. From d57e99b9da556f1bda8ac74d6db2ef5e705d51d2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 08:44:20 +0200 Subject: [PATCH 0488/1872] move methods to GenericGrowthGroup --- src/sage/rings/asymptotic/growth_group.py | 124 +++++++++++----------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 2085bf14d60..ac03f57bada 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -912,6 +912,42 @@ class GenericGrowthGroup( Element = GenericGrowthElement + @staticmethod + def __classcall__(cls, base, var, category=None): + r""" + Normalizes the input in order to ensure a unique + representation. + + For more information see :class:`MonomialGrowthGroup`. + + TESTS:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P1 = agg.MonomialGrowthGroup(ZZ, 'x') + sage: P2 = agg.MonomialGrowthGroup(ZZ, ZZ['x'].gen()) + sage: P3 = agg.MonomialGrowthGroup(ZZ, SR.var('x')) + sage: P1 is P2 and P2 is P3 + True + sage: P4 = agg.MonomialGrowthGroup(ZZ, buffer('xylophone', 0, 1)) + sage: P1 is P4 + True + sage: P5 = agg.MonomialGrowthGroup(ZZ, 'x ') + sage: P1 is P5 + True + + :: + + sage: L1 = agg.MonomialGrowthGroup(QQ, log(x)) + sage: L2 = agg.MonomialGrowthGroup(QQ, 'log(x)') + sage: L1 is L2 + True + """ + if not isinstance(var, Variable): + var = Variable(var) + return super(MonomialGrowthGroup, cls).__classcall__( + cls, base, var, category) + + @sage.misc.superseded.experimental(trac_number=17601) def __init__(self, base, category=None): r""" @@ -1269,6 +1305,32 @@ def gens_monomial(self): return tuple() + def gens(self): + r""" + Return a tuple of all generators of this monomial growth + group, even if the growth group is logarithmic. + + INPUT: + + Nothing. + + OUTPUT: + + A tuple whose entries are instances of + :class:`MonomialGrowthElement`. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: P.gens() + (x,) + sage: agg.MonomialGrowthGroup(ZZ, 'log(x)').gens() + (log(x),) + """ + return (self(raw_element=self.base().one()),) + + def variable_names(self): r""" Return the names of the variables. @@ -1552,42 +1614,6 @@ class MonomialGrowthGroup(GenericGrowthGroup): Element = MonomialGrowthElement - @staticmethod - def __classcall__(cls, base, var, category=None): - r""" - Normalizes the input in order to ensure a unique - representation. - - For more information see :class:`MonomialGrowthGroup`. - - TESTS:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P1 = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P2 = agg.MonomialGrowthGroup(ZZ, ZZ['x'].gen()) - sage: P3 = agg.MonomialGrowthGroup(ZZ, SR.var('x')) - sage: P1 is P2 and P2 is P3 - True - sage: P4 = agg.MonomialGrowthGroup(ZZ, buffer('xylophone', 0, 1)) - sage: P1 is P4 - True - sage: P5 = agg.MonomialGrowthGroup(ZZ, 'x ') - sage: P1 is P5 - True - - :: - - sage: L1 = agg.MonomialGrowthGroup(QQ, log(x)) - sage: L2 = agg.MonomialGrowthGroup(QQ, 'log(x)') - sage: L1 is L2 - True - """ - if not isinstance(var, Variable): - var = Variable(var) - return super(MonomialGrowthGroup, cls).__classcall__( - cls, base, var, category) - - @sage.misc.superseded.experimental(trac_number=17601) def __init__(self, base, var, category): r""" @@ -1872,32 +1898,6 @@ def gens_monomial(self): return (self(raw_element=self.base().one()),) - def gens(self): - r""" - Return a tuple of all generators of this monomial growth - group, even if the growth group is logarithmic. - - INPUT: - - Nothing. - - OUTPUT: - - A tuple whose entries are instances of - :class:`MonomialGrowthElement`. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P.gens() - (x,) - sage: agg.MonomialGrowthGroup(ZZ, 'log(x)').gens() - (log(x),) - """ - return (self(raw_element=self.base().one()),) - - def gen(self, n=0): r""" Return the `n`-th generator of this growth group. From ac0083a658aca03b924465af22827b0add19def5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 09:04:30 +0200 Subject: [PATCH 0489/1872] merge parent methods of growth groups --- src/sage/rings/asymptotic/growth_group.py | 564 ++++++++-------------- 1 file changed, 199 insertions(+), 365 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ac03f57bada..2fa7db8e2e3 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -913,7 +913,7 @@ class GenericGrowthGroup( @staticmethod - def __classcall__(cls, base, var, category=None): + def __classcall__(cls, base, var=None, category=None): r""" Normalizes the input in order to ensure a unique representation. @@ -942,14 +942,16 @@ def __classcall__(cls, base, var, category=None): sage: L1 is L2 True """ - if not isinstance(var, Variable): + if var is None: + var = Variable('') + elif not isinstance(var, Variable): var = Variable(var) - return super(MonomialGrowthGroup, cls).__classcall__( + return super(GenericGrowthGroup, cls).__classcall__( cls, base, var, category) @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, base, category=None): + def __init__(self, base, var, category=None): r""" See :class:`GenericGrowthElement` for more information. @@ -979,6 +981,49 @@ def __init__(self, base, category=None): Traceback (most recent call last): ... TypeError: 42 is not a valid base + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: agg.MonomialGrowthGroup(ZZ, 'x') + Growth Group x^ZZ + sage: agg.MonomialGrowthGroup(QQ, SR.var('n')) + Growth Group n^QQ + sage: agg.MonomialGrowthGroup(ZZ, ZZ['y'].gen()) + Growth Group y^ZZ + sage: agg.MonomialGrowthGroup(QQ, 'log(x)') + Growth Group log(x)^QQ + + TESTS:: + + sage: agg.MonomialGrowthGroup('x', ZZ) + Traceback (most recent call last): + ... + ValueError: 'Integer Ring' is not a valid name for a variable. + sage: agg.MonomialGrowthGroup('x', 'y') + Traceback (most recent call last): + ... + TypeError: x is not a valid base + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: agg.ExponentialGrowthGroup(QQ, 'x') + Growth Group QQ^x + sage: agg.ExponentialGrowthGroup(SR, ZZ['y'].gen()) + Growth Group SR^y + + TESTS:: + + sage: agg.ExponentialGrowthGroup('x', ZZ) + Traceback (most recent call last): + ... + ValueError: 'Integer Ring' is not a valid name for a variable. + sage: agg.ExponentialGrowthGroup('x', 'y') + Traceback (most recent call last): + ... + TypeError: x is not a valid base + """ if not isinstance(base, sage.structure.parent.Parent): raise TypeError('%s is not a valid base' % (base,)) @@ -994,6 +1039,8 @@ def __init__(self, base, category=None): category): raise ValueError('%s is not a subcategory of %s' % (category, Groups() & Posets())) + + self._var_ = var super(GenericGrowthGroup, self).__init__(category=category, base=base) @@ -1069,8 +1116,22 @@ def __hash__(self): sage: import sage.rings.asymptotic.growth_group as agg sage: hash(agg.GenericGrowthGroup(ZZ)) # random 4242424242424242 + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: hash(P) # random + -1234567890123456789 + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') + sage: hash(P) # random + -1234567890123456789 """ - return hash((self.__class__, self.base())) + return hash((self.__class__, self.base(), self._var_)) def _an_element_(self): @@ -1263,12 +1324,6 @@ def _coerce_map_from_(self, S): A boolean. - .. NOTE:: - - Another growth group ``S`` coerces into this growth group - if and only if the base of ``S`` coerces into the base of - this growth group. - EXAMPLES:: sage: import sage.rings.asymptotic.growth_group as agg @@ -1278,8 +1333,46 @@ def _coerce_map_from_(self, S): False sage: bool(G_QQ.has_coerce_map_from(G_ZZ)) # indirect doctest True + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P_x_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') + sage: P_x_QQ = agg.MonomialGrowthGroup(QQ, 'x') + sage: bool(P_x_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + False + sage: bool(P_x_QQ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + True + sage: P_y_ZZ = agg.MonomialGrowthGroup(ZZ, 'y') + sage: bool(P_y_ZZ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + False + sage: bool(P_x_ZZ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + False + sage: bool(P_y_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + False + sage: bool(P_x_QQ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + False + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P_x_ZZ = agg.GrowthGroup('ZZ^x') + sage: P_x_QQ = agg.GrowthGroup('QQ^x') + sage: bool(P_x_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + False + sage: bool(P_x_QQ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + True + sage: P_y_ZZ = agg.GrowthGroup('ZZ^y') + sage: bool(P_y_ZZ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + False + sage: bool(P_x_ZZ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + False + sage: bool(P_y_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + False + sage: bool(P_x_QQ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + False """ - if isinstance(S, GenericGrowthGroup): + if isinstance(S, GenericGrowthGroup) and self._var_ == S._var_: if self.base().has_coerce_map_from(S.base()): return True @@ -1301,14 +1394,20 @@ def gens_monomial(self): sage: import sage.rings.asymptotic.growth_group as agg sage: agg.GenericGrowthGroup(ZZ).gens_monomial() () + + TESTS:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: agg.GrowthGroup('ZZ^x').gens_monomial() + () """ return tuple() def gens(self): r""" - Return a tuple of all generators of this monomial growth - group, even if the growth group is logarithmic. + Return a tuple of all generators (as a group) of this growth + group. INPUT: @@ -1316,8 +1415,7 @@ def gens(self): OUTPUT: - A tuple whose entries are instances of - :class:`MonomialGrowthElement`. + A tuple whose entries are growth elements. EXAMPLES:: @@ -1331,6 +1429,66 @@ def gens(self): return (self(raw_element=self.base().one()),) + def gen(self, n=0): + r""" + Return the `n`-th generator (as a group) of this growth group. + + INPUT: + + - ``n`` -- default: `0`. + + OUTPUT: + + A :class:`MonomialGrowthElement`. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: P.gen() + x + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.GrowthGroup('QQ^x') + sage: P.gen() + () + """ + return self.gens()[n] + + + def ngens(self): + r""" + Return the number of generators (as a group) of this growth group. + + INPUT: + + Nothing. + + OUTPUT: + + A Python integer. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: P.ngens() + 1 + sage: agg.MonomialGrowthGroup(ZZ, 'log(x)').ngens() + 1 + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: P = agg.GrowthGroup('QQ^x') + sage: P.ngens() + 0 + """ + return len(self.gens()) + + def variable_names(self): r""" Return the names of the variables. @@ -1344,8 +1502,24 @@ def variable_names(self): sage: import sage.rings.asymptotic.growth_group as agg sage: agg.GenericGrowthGroup(ZZ).variable_names() () + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ').variable_names() + ('x',) + sage: GrowthGroup('log(x)^ZZ').variable_names() + ('x',) + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('QQ^x').variable_names() + ('x',) + sage: GrowthGroup('QQ^(x*log(x))').variable_names() + ('x',) """ - return tuple() + return self._var_.variable_names() CartesianProduct = CartesianProductGrowthGroups @@ -1614,38 +1788,6 @@ class MonomialGrowthGroup(GenericGrowthGroup): Element = MonomialGrowthElement - @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, base, var, category): - r""" - For more information see :class:`MonomialGrowthGroup`. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.MonomialGrowthGroup(ZZ, 'x') - Growth Group x^ZZ - sage: agg.MonomialGrowthGroup(QQ, SR.var('n')) - Growth Group n^QQ - sage: agg.MonomialGrowthGroup(ZZ, ZZ['y'].gen()) - Growth Group y^ZZ - sage: agg.MonomialGrowthGroup(QQ, 'log(x)') - Growth Group log(x)^QQ - - TESTS:: - - sage: agg.MonomialGrowthGroup('x', ZZ) - Traceback (most recent call last): - ... - ValueError: 'Integer Ring' is not a valid name for a variable. - sage: agg.MonomialGrowthGroup('x', 'y') - Traceback (most recent call last): - ... - TypeError: x is not a valid base - """ - self._var_ = var - super(MonomialGrowthGroup, self).__init__(category=category, base=base) - - def _repr_short_(self): r""" A short representation string of this monomial growth group. @@ -1677,28 +1819,6 @@ def _repr_short_(self): return '%s^%s' % (self._var_, parent_to_repr_short(self.base())) - def __hash__(self): - r""" - Return the hash of this group. - - INPUT: - - Nothing. - - OUTPUT: - - An integer. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') - sage: hash(P) # random - -1234567890123456789 - """ - return hash((super(MonomialGrowthGroup, self).__hash__(), self._var_)) - - def _convert_(self, data): r""" Converts ``data`` to something the constructor of the @@ -1831,42 +1951,6 @@ def _convert_(self, data): return data.degree() - def _coerce_map_from_(self, S): - r""" - Return if ``S`` coerces into this growth group. - - INPUT: - - - ``S`` -- a parent. - - OUTPUT: - - A boolean. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P_x_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P_x_QQ = agg.MonomialGrowthGroup(QQ, 'x') - sage: bool(P_x_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest - False - sage: bool(P_x_QQ.has_coerce_map_from(P_x_ZZ)) # indirect doctest - True - sage: P_y_ZZ = agg.MonomialGrowthGroup(ZZ, 'y') - sage: bool(P_y_ZZ.has_coerce_map_from(P_x_ZZ)) # indirect doctest - False - sage: bool(P_x_ZZ.has_coerce_map_from(P_y_ZZ)) # indirect doctest - False - sage: bool(P_y_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest - False - sage: bool(P_x_QQ.has_coerce_map_from(P_y_ZZ)) # indirect doctest - False - """ - if super(MonomialGrowthGroup, self)._coerce_map_from_(S): - if self._var_ == S._var_: - return True - - def gens_monomial(self): r""" Return a tuple containing generators of this growth group. @@ -1898,70 +1982,6 @@ def gens_monomial(self): return (self(raw_element=self.base().one()),) - def gen(self, n=0): - r""" - Return the `n`-th generator of this growth group. - - INPUT: - - - ``n`` -- default: `0`. - - OUTPUT: - - A :class:`MonomialGrowthElement`. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P.gen() - x - """ - return self.gens()[n] - - def ngens(self): - r""" - Return the number of generators of this monomial growth group. - - INPUT: - - Nothing. - - OUTPUT: - - A Python integer. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P.ngens() - 1 - sage: agg.MonomialGrowthGroup(ZZ, 'log(x)').ngens() - 1 - """ - return len(self.gens()) - - - def variable_names(self): - r""" - Return the names of the variables. - - OUTPUT: - - A tuple of strings. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: GrowthGroup('x^ZZ').variable_names() - ('x',) - sage: GrowthGroup('log(x)^ZZ').variable_names() - ('x',) - """ - return self._var_.variable_names() - - class ExponentialGrowthElement(GenericGrowthElement): r""" An implementation of exponential growth elements. @@ -2222,63 +2242,6 @@ class ExponentialGrowthGroup(GenericGrowthGroup): Element = ExponentialGrowthElement - @staticmethod - def __classcall__(cls, base, var, category=None): - r""" - Normalizes the input in order to ensure a unique - representation. - - For more information see :class:`ExponentialGrowthGroup`. - - TESTS:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P1 = agg.ExponentialGrowthGroup(QQ, 'x') - sage: P2 = agg.ExponentialGrowthGroup(QQ, ZZ['x'].gen()) - sage: P3 = agg.ExponentialGrowthGroup(QQ, SR.var('x')) - sage: P1 is P2 and P2 is P3 - True - sage: P4 = agg.ExponentialGrowthGroup(QQ, buffer('xylophone', 0, 1)) - sage: P1 is P4 - True - sage: P5 = agg.ExponentialGrowthGroup(QQ, 'x ') - sage: P1 is P5 - True - """ - if not isinstance(var, Variable): - var = Variable(var) - return super(ExponentialGrowthGroup, cls).__classcall__( - cls, base, var, category) - - - @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, base, var, category): - r""" - For more information see :class:`ExponentialGrowthGroup`. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.ExponentialGrowthGroup(QQ, 'x') - Growth Group QQ^x - sage: agg.ExponentialGrowthGroup(SR, ZZ['y'].gen()) - Growth Group SR^y - - TESTS:: - - sage: agg.ExponentialGrowthGroup('x', ZZ) - Traceback (most recent call last): - ... - ValueError: 'Integer Ring' is not a valid name for a variable. - sage: agg.ExponentialGrowthGroup('x', 'y') - Traceback (most recent call last): - ... - TypeError: x is not a valid base - """ - self._var_ = var - super(ExponentialGrowthGroup, self).__init__(category=category, base=base) - - def _repr_short_(self): r""" A short representation string of this exponential growth group. @@ -2308,28 +2271,6 @@ def _repr_short_(self): return '%s^%s' % (parent_to_repr_short(self.base()), self._var_) - def __hash__(self): - r""" - Return the hash of this group. - - INPUT: - - Nothing. - - OUTPUT: - - An integer. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') - sage: hash(P) # random - -1234567890123456789 - """ - return hash((super(ExponentialGrowthGroup, self).__hash__(), self._var_)) - - def _convert_(self, data): r""" Converts given ``data`` to something the constructor of the @@ -2410,98 +2351,10 @@ def _convert_(self, data): return base ** (exponent / SR(var)) - def _coerce_map_from_(self, S): - r""" - Return if ``S`` coerces into this growth group. - - INPUT: - - - ``S`` -- a parent. - - OUTPUT: - - A boolean. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P_x_ZZ = agg.GrowthGroup('ZZ^x') - sage: P_x_QQ = agg.GrowthGroup('QQ^x') - sage: bool(P_x_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest - False - sage: bool(P_x_QQ.has_coerce_map_from(P_x_ZZ)) # indirect doctest - True - sage: P_y_ZZ = agg.GrowthGroup('ZZ^y') - sage: bool(P_y_ZZ.has_coerce_map_from(P_x_ZZ)) # indirect doctest - False - sage: bool(P_x_ZZ.has_coerce_map_from(P_y_ZZ)) # indirect doctest - False - sage: bool(P_y_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest - False - sage: bool(P_x_QQ.has_coerce_map_from(P_y_ZZ)) # indirect doctest - False - """ - if super(ExponentialGrowthGroup, self)._coerce_map_from_(S): - if self._var_ == S._var_: - return True - - - def gens_monomial(self): - r""" - Return a tuple containing generators of this growth group. - - INPUT: - - Nothing. - - OUTPUT: - - A tuple containing elements of this growth group. - - .. NOTE:: - - A :class:`ExponentialGrowthGroup` has no generators, - thus an empty tuple is returned. - - TESTS:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GrowthGroup('ZZ^x').gens_monomial() - () - """ - return () - - # for exponential growth groups, gens_monomial is an alias of gens: - gens = gens_monomial - - - def gen(self, n=0): - r""" - Return the `n`-th generator of this growth group. - - INPUT: - - - ``n`` -- default: `0`. - - OUTPUT: - - A generator of this growth group. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('QQ^x') - sage: P.gen() - Traceback (most recent call last): - ... - ValueError: Growth Group QQ^x has no generators. - """ - raise ValueError("%s has no generators." % (self,)) - - def ngens(self): + def gens(self): r""" - Return the number of generators of this exponential - growth group. + Return a tuple of all generators (as a group) of this growth + group. INPUT: @@ -2509,35 +2362,16 @@ def ngens(self): OUTPUT: - A Python integer. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('QQ^x') - sage: P.ngens() - 0 - """ - return len(self.gens()) - - - def variable_names(self): - r""" - Return the names of the variables. - - OUTPUT: - - A tuple of strings. + A tuple whose entries are growth elements. EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: GrowthGroup('QQ^x').variable_names() - ('x',) - sage: GrowthGroup('QQ^(x*log(x))').variable_names() - ('x',) + sage: E = GrowthGroup('ZZ^x') + sage: E.gens() + () """ - return self._var_.variable_names() + return tuple() class GrowthGroupFactory(sage.structure.factory.UniqueFactory): From 383f71375312e6814061528a3256116b7bf9bb86 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 11:29:00 +0200 Subject: [PATCH 0490/1872] deal with categories: CartesianProductPosets should be in Posets() --- src/sage/sets/cartesian_product.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 19b84870fc6..0334889e6fd 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -332,6 +332,15 @@ class CartesianProductPosets(CartesianProduct): sage: Cs((1, 1)) <= Cs((2, 0)) True + TESTS:: + + sage: Cc.category() + Join of Category of finite posets and + Category of Cartesian products of finite enumerated sets + sage: Cs.category() + Join of Category of finite posets and + Category of Cartesian products of finite enumerated sets + .. SEEALSO: :class:`CartesianProduct` @@ -360,6 +369,8 @@ def __init__(self, sets, category, order, **kwargs): super(CartesianProductPosets, self).__init__( sets, category, **kwargs) + from sage.categories.posets import Posets + self._refine_category_(Posets()) def le(self, left, right): From febf3729e563ee427ecda7a5269d6507a9c2aea2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 11:30:42 +0200 Subject: [PATCH 0491/1872] make everything work again --- .../asymptotic/growth_group_cartesian.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index eb61743b415..0167c1f53d8 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -199,6 +199,28 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): :class:`~sage.sets.cartesian_product.CartesianProductPosets`. """ + @staticmethod + def __classcall__(cls, *args, **kwds): + return CartesianProductPosets.__classcall__(cls, *args, **kwds) + + def __init__(self, sets, category, **kwds): + order = kwds.pop('order') + CartesianProductPosets.__init__(self, sets, category, order, **kwds) + + vars = sum(iter(factor.variable_names() + for factor in self.cartesian_factors()), + tuple()) + from itertools import groupby + from sage.rings.asymptotic.growth_group import Variable + Vars = Variable(tuple(v for v, _ in groupby(vars))) + + GenericGrowthGroup.__init__(self, sets[0], Vars, self.category(), **kwds) + + + def __hash__(self): + return CartesianProductPosets.__hash__(self) + + def _element_constructor_(self, data): r""" Converts the given object to an element of this cartesian From 5acd44418d715b07de2c9a44ff54c71191a865ce Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 11:30:53 +0200 Subject: [PATCH 0492/1872] fix doctests --- src/sage/rings/asymptotic/growth_group.py | 19 +++++++------------ .../asymptotic/growth_group_cartesian.py | 10 +++++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 2fa7db8e2e3..fb273f43758 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -33,26 +33,19 @@ TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ); G + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup, GrowthGroup + sage: GenericGrowthGroup(ZZ) 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/17601 for details. Growth Group Generic(ZZ) - sage: G = agg.MonomialGrowthGroup(ZZ, 'x'); G - 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/17601 for details. - Growth Group x^ZZ - sage: G = agg.ExponentialGrowthGroup(QQ, 'x'); G + sage: GrowthGroup('x^ZZ * log(x)^ZZ') 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/17601 for details. - Growth Group QQ^x - + Growth Group x^ZZ * log(x)^ZZ .. NOTE:: @@ -1453,7 +1446,9 @@ def gen(self, n=0): sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('QQ^x') sage: P.gen() - () + Traceback (most recent call last): + ... + IndexError: tuple index out of range """ return self.gens()[n] diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 0167c1f53d8..0a587fc9345 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -14,19 +14,19 @@ TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ); G + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup, GrowthGroup + sage: GenericGrowthGroup(ZZ) 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/17601 for details. Growth Group Generic(ZZ) - sage: G = agg.MonomialGrowthGroup(ZZ, 'x'); G + sage: GrowthGroup('x^ZZ * log(x)^ZZ') 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/17601 for details. - Growth Group x^ZZ + Growth Group x^ZZ * log(x)^ZZ """ #***************************************************************************** @@ -87,7 +87,7 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): TESTS:: sage: from sage.rings.asymptotic.growth_group_cartesian import CartesianProductFactory - sage: CartesianProductFactory('factory')([A, B], category=Sets()) + sage: CartesianProductFactory('factory')([A, B], category=Groups() & Posets()) Growth Group x^ZZ * log(x)^ZZ sage: CartesianProductFactory('factory')([], category=Sets()) Traceback (most recent call last): From ef15d6c3f9f78452897b760fdf6d828353c0b8c1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 11:29:00 +0200 Subject: [PATCH 0493/1872] deal with categories: CartesianProductPosets should be in Posets() --- src/sage/sets/cartesian_product.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 895289dfe9c..ccf0410dc5f 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -332,6 +332,15 @@ class CartesianProductPosets(CartesianProduct): sage: Cs((1, 1)) <= Cs((2, 0)) True + TESTS:: + + sage: Cc.category() + Join of Category of finite posets and + Category of Cartesian products of finite enumerated sets + sage: Cs.category() + Join of Category of finite posets and + Category of Cartesian products of finite enumerated sets + .. SEEALSO: :class:`CartesianProduct` @@ -360,6 +369,8 @@ def __init__(self, sets, category, order, **kwargs): super(CartesianProductPosets, self).__init__( sets, category, **kwargs) + from sage.categories.posets import Posets + self._refine_category_(Posets()) def le(self, left, right): From 7ce6c0bdcc2dbcfaf1b3983455f2f4aaf5b74501 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 11:43:37 +0200 Subject: [PATCH 0494/1872] deal with _repr_ --- src/sage/rings/asymptotic/growth_group.py | 25 ++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index fb273f43758..e6fb0d41baf 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -585,12 +585,18 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ) sage: G(raw_element=42) # indirect doctest GenericGrowthElement(42) + sage: H = GenericGrowthGroup(ZZ, 'h') + sage: H(raw_element=42) # indirect doctest + GenericGrowthElement(42, h) """ - return 'GenericGrowthElement(%s)' % (self._raw_element_,) + vars = ', '.join(self.parent()._var_.variable_names()) + if vars: + vars = ', ' + vars + return 'GenericGrowthElement(%s%s)' % (self._raw_element_, vars) def __hash__(self): @@ -1052,13 +1058,18 @@ def _repr_short_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GenericGrowthGroup(QQ)._repr_short_() + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: GenericGrowthGroup(QQ)._repr_short_() 'Generic(QQ)' - sage: agg.GenericGrowthGroup(QQ) + sage: GenericGrowthGroup(QQ) Growth Group Generic(QQ) + sage: GenericGrowthGroup(QQ, ('a', 'b')) + Growth Group Generic(QQ, a, b) """ - return 'Generic(%s)' % (parent_to_repr_short(self.base()),) + vars = ', '.join(self._var_.variable_names()) + if vars: + vars = ', ' + vars + return 'Generic(%s%s)' % (parent_to_repr_short(self.base()), vars) def _repr_(self, condense=False): From 1428b6989f7b091753464374aea43406fc540f26 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 11:45:27 +0200 Subject: [PATCH 0495/1872] post-class-merge doctest cleanup --- src/sage/rings/asymptotic/growth_group.py | 60 +++++++++++------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index e6fb0d41baf..7e5a7004c2a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -960,6 +960,26 @@ def __init__(self, base, var, category=None): sage: agg.GenericGrowthGroup(ZZ).category() Join of Category of groups and Category of posets + :: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: agg.MonomialGrowthGroup(ZZ, 'x') + Growth Group x^ZZ + sage: agg.MonomialGrowthGroup(QQ, SR.var('n')) + Growth Group n^QQ + sage: agg.MonomialGrowthGroup(ZZ, ZZ['y'].gen()) + Growth Group y^ZZ + sage: agg.MonomialGrowthGroup(QQ, 'log(x)') + Growth Group log(x)^QQ + + :: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: agg.ExponentialGrowthGroup(QQ, 'x') + Growth Group QQ^x + sage: agg.ExponentialGrowthGroup(SR, ZZ['y'].gen()) + Growth Group SR^y + TESTS:: sage: import sage.rings.asymptotic.growth_group as agg @@ -981,19 +1001,7 @@ def __init__(self, base, var, category=None): ... TypeError: 42 is not a valid base - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.MonomialGrowthGroup(ZZ, 'x') - Growth Group x^ZZ - sage: agg.MonomialGrowthGroup(QQ, SR.var('n')) - Growth Group n^QQ - sage: agg.MonomialGrowthGroup(ZZ, ZZ['y'].gen()) - Growth Group y^ZZ - sage: agg.MonomialGrowthGroup(QQ, 'log(x)') - Growth Group log(x)^QQ - - TESTS:: + :: sage: agg.MonomialGrowthGroup('x', ZZ) Traceback (most recent call last): @@ -1004,15 +1012,7 @@ def __init__(self, base, var, category=None): ... TypeError: x is not a valid base - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.ExponentialGrowthGroup(QQ, 'x') - Growth Group QQ^x - sage: agg.ExponentialGrowthGroup(SR, ZZ['y'].gen()) - Growth Group SR^y - - TESTS:: + :: sage: agg.ExponentialGrowthGroup('x', ZZ) Traceback (most recent call last): @@ -1121,14 +1121,14 @@ def __hash__(self): sage: hash(agg.GenericGrowthGroup(ZZ)) # random 4242424242424242 - EXAMPLES:: + :: sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.MonomialGrowthGroup(ZZ, 'x') sage: hash(P) # random -1234567890123456789 - EXAMPLES:: + :: sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') @@ -1338,7 +1338,7 @@ def _coerce_map_from_(self, S): sage: bool(G_QQ.has_coerce_map_from(G_ZZ)) # indirect doctest True - EXAMPLES:: + :: sage: import sage.rings.asymptotic.growth_group as agg sage: P_x_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') @@ -1357,7 +1357,7 @@ def _coerce_map_from_(self, S): sage: bool(P_x_QQ.has_coerce_map_from(P_y_ZZ)) # indirect doctest False - EXAMPLES:: + :: sage: import sage.rings.asymptotic.growth_group as agg sage: P_x_ZZ = agg.GrowthGroup('ZZ^x') @@ -1452,7 +1452,7 @@ def gen(self, n=0): sage: P.gen() x - EXAMPLES:: + :: sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('QQ^x') @@ -1485,7 +1485,7 @@ def ngens(self): sage: agg.MonomialGrowthGroup(ZZ, 'log(x)').ngens() 1 - EXAMPLES:: + :: sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('QQ^x') @@ -1509,7 +1509,7 @@ def variable_names(self): sage: agg.GenericGrowthGroup(ZZ).variable_names() () - EXAMPLES:: + :: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: GrowthGroup('x^ZZ').variable_names() @@ -1517,7 +1517,7 @@ def variable_names(self): sage: GrowthGroup('log(x)^ZZ').variable_names() ('x',) - EXAMPLES:: + :: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: GrowthGroup('QQ^x').variable_names() From 02d2a7da139b863d607edb6745c878b54223a90a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 12:25:47 +0200 Subject: [PATCH 0496/1872] __ne__ for Variables --- src/sage/rings/asymptotic/growth_group.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 7e5a7004c2a..116c13d4b04 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -335,6 +335,29 @@ def __eq__(self, other): return self.var_repr == other.var_repr and self.var_bases == other.var_bases + def __ne__(self, other): + r""" + Compares if this variable does not equal ``other``. + + INPUT: + + - ``other`` -- another variable. + + OUTPUT: + + A boolean. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable('x') != Variable('x') + False + sage: Variable('x') != Variable('y') + True + """ + return not self.__eq__(other) + + def _repr_(self): r""" Return a representation string of this variable. From 2c842ca6b186cf0a141890b8746260ee4a3df7e4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 12:26:06 +0200 Subject: [PATCH 0497/1872] functors for constructions --- src/sage/rings/asymptotic/growth_group.py | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 116c13d4b04..343921f7bd1 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1553,6 +1553,39 @@ def variable_names(self): CartesianProduct = CartesianProductGrowthGroups +from sage.categories.pushout import ConstructionFunctor +class AbstractGrowthGroupFunctor(ConstructionFunctor): + r""" + """ + _functor_name = 'AbstractGrowthGroup' + rank = 13 + + def __init__(self, var, domain): + if var is None: + var = Variable('') + elif not isinstance(var, Variable): + var = Variable(var) + self.var = var + super(ConstructionFunctor, self).__init__( + domain, sage.categories.groups.Groups()) + + + def _repr_(self): + return '%s[%s]' % (self._functor_name, self.var) + + + def merge(self, other): + if self == other: + return self + + + def __eq__(self, other): + return type(self) == type(other) and self.var == other.var + + + def __ne__(self, other): + return not self.__eq__(other) + class MonomialGrowthElement(GenericGrowthElement): r""" @@ -2011,6 +2044,23 @@ def gens_monomial(self): return (self(raw_element=self.base().one()),) + +class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): + r""" + """ + + _functor_name = 'MonomialGrowthGroup' + + + def __init__(self, var): + super(MonomialGrowthGroupFunctor, self).__init__(var, + sage.categories.commutative_additive_groups.CommutativeAdditiveGroups()) + + + def _apply_functor(self, base): + return MonomialGrowthGroup(base, self.var) + + class ExponentialGrowthElement(GenericGrowthElement): r""" An implementation of exponential growth elements. @@ -2403,6 +2453,23 @@ def gens(self): return tuple() + +class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): + r""" + """ + + _functor_name = 'ExponentialGrowthGroup' + + + def __init__(self, var): + super(ExponentialGrowthGroupFunctor, self).__init__(var, + sage.categories.groups.Groups()) + + + def _apply_functor(self, base): + return ExponentialGrowthGroup(base, self.var) + + class GrowthGroupFactory(sage.structure.factory.UniqueFactory): r""" A factory creating asymptotic growth groups. From 546153ebe1febcf529aca75c212217bc1809622e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 12:26:11 +0200 Subject: [PATCH 0498/1872] constructions --- src/sage/rings/asymptotic/growth_group.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 343921f7bd1..257c384b83e 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1553,6 +1553,7 @@ def variable_names(self): CartesianProduct = CartesianProductGrowthGroups + from sage.categories.pushout import ConstructionFunctor class AbstractGrowthGroupFunctor(ConstructionFunctor): r""" @@ -2044,6 +2045,16 @@ def gens_monomial(self): return (self(raw_element=self.base().one()),) + def construction(self): + r""" + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ').construction() + (MonomialGrowthGroup[x], Integer Ring) + """ + return MonomialGrowthGroupFunctor(self._var_), self.base() + class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" @@ -2453,6 +2464,16 @@ def gens(self): return tuple() + def construction(self): + r""" + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('QQ^x').construction() + (ExponentialGrowthGroup[x], Rational Field) + """ + return ExponentialGrowthGroupFunctor(self._var_), self.base() + class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" From 65166c8c5a15744e0f845e14ce4f29eff8d3836f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 12:33:19 +0200 Subject: [PATCH 0499/1872] use relative paths for imports --- src/sage/rings/asymptotic/growth_group_cartesian.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 0a587fc9345..2ded0bb5d30 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -167,7 +167,7 @@ def create_object(self, version, args, **kwds): from sage.sets.cartesian_product import CartesianProductPosets -from sage.rings.asymptotic.growth_group import GenericGrowthGroup +from growth_group import GenericGrowthGroup class GenericProduct(CartesianProductPosets, GenericGrowthGroup): r""" A cartesian product of growth groups. @@ -211,7 +211,7 @@ def __init__(self, sets, category, **kwds): for factor in self.cartesian_factors()), tuple()) from itertools import groupby - from sage.rings.asymptotic.growth_group import Variable + from growth_group import Variable Vars = Variable(tuple(v for v, _ in groupby(vars))) GenericGrowthGroup.__init__(self, sets[0], Vars, self.category(), **kwds) From 8c8c1b5201001e527c9cae95eae5d87de40b5c6c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 12:45:01 +0200 Subject: [PATCH 0500/1872] fix doctest coverage --- src/sage/rings/asymptotic/growth_group.py | 2 +- .../asymptotic/growth_group_cartesian.py | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 27062a1f965..4363b8aa3bd 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2039,7 +2039,7 @@ def create_object(self, version, factors, **kwds): TESTS:: sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GrowthGroup('as^df') + sage: agg.GrowthGroup('as^df') # indirect doctest Traceback (most recent call last): ... ValueError: 'as^df' is not a valid string describing a growth group. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index eb61743b415..97268d92699 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -361,6 +361,15 @@ def _convert_to_factor_(self, data): def _coerce_map_from_(self, S): + r""" + Return ``True if there is a coercion from ``S`` + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ * log(x)^ZZ').has_coerce_map_from(QQ) # indirect doctest + False + """ pass @@ -447,6 +456,15 @@ def _repr_(self): class UnivariateProduct(GenericProduct): def __init__(self, sets, category, **kwargs): + r""" + A cartesian product of growth groups with the same variables. + + TEST:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: type(GrowthGroup('x^ZZ * log(x)^ZZ')) # indirect doctest + + """ super(UnivariateProduct, self).__init__( sets, category, order='lex', **kwargs) @@ -456,6 +474,15 @@ def __init__(self, sets, category, **kwargs): class MultivariateProduct(GenericProduct): def __init__(self, sets, category, **kwargs): + r""" + A cartesian product of growth groups with the pairwise different variables. + + TEST:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: type(GrowthGroup('x^ZZ * y^ZZ')) # indirect doctest + + """ super(MultivariateProduct, self).__init__( sets, category, order='components', **kwargs) From 65faee543a33262fad19bc407e251d3fa1387387 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 12:51:05 +0200 Subject: [PATCH 0501/1872] fix doctest coverage --- .../asymptotic/growth_group_cartesian.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index c56d44fddb0..ef27b270822 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -201,9 +201,29 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): @staticmethod def __classcall__(cls, *args, **kwds): + r""" + Normalizes the input in order to ensure a unique + representation. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ * y^ZZ') # indirect doctest + Growth Group x^ZZ * y^ZZ + """ return CartesianProductPosets.__classcall__(cls, *args, **kwds) + def __init__(self, sets, category, **kwds): + r""" + See :class:`GenericProduct` for details. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ * y^ZZ') # indirect doctest + Growth Group x^ZZ * y^ZZ + """ order = kwds.pop('order') CartesianProductPosets.__init__(self, sets, category, order, **kwds) @@ -218,6 +238,19 @@ def __init__(self, sets, category, **kwds): def __hash__(self): + r""" + Return a hash value for this cartesian product. + + OUTPUT: + + An integer. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: hash(GrowthGroup('x^ZZ * y^ZZ')) # indirect doctest, random + -1 + """ return CartesianProductPosets.__hash__(self) From 24373bb4a7b8fb56002e2c647dfa0d2b7f16741a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 14:30:33 +0200 Subject: [PATCH 0502/1872] Groups() --> Monoids() ...since nothing more needed --- src/sage/rings/asymptotic/growth_group.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 224f5f9b9b3..f07d42985be 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -981,7 +981,7 @@ def __init__(self, base, var, category=None): sage: import sage.rings.asymptotic.growth_group as agg sage: agg.GenericGrowthGroup(ZZ).category() - Join of Category of groups and Category of posets + Join of Category of monoids and Category of posets :: @@ -1015,7 +1015,7 @@ def __init__(self, base, var, category=None): sage: G3 = agg.GenericGrowthGroup(ZZ, category=Rings()) Traceback (most recent call last): ... - ValueError: (Category of rings,) is not a subcategory of Join of Category of groups and Category of posets + ValueError: (Category of rings,) is not a subcategory of Join of Category of monoids and Category of posets :: @@ -1049,18 +1049,18 @@ def __init__(self, base, var, category=None): """ if not isinstance(base, sage.structure.parent.Parent): raise TypeError('%s is not a valid base' % (base,)) - from sage.categories.groups import Groups + from sage.categories.monoids import Monoids from sage.categories.posets import Posets if category is None: - category = Groups() & Posets() + category = Monoids() & Posets() else: if not isinstance(category, tuple): category = (category,) - if not any(cat.is_subcategory(Groups() & Posets()) for cat in + if not any(cat.is_subcategory(Monoids() & Posets()) for cat in category): raise ValueError('%s is not a subcategory of %s' - % (category, Groups() & Posets())) + % (category, Monoids() & Posets())) self._var_ = var super(GenericGrowthGroup, self).__init__(category=category, @@ -1568,7 +1568,7 @@ def __init__(self, var, domain): var = Variable(var) self.var = var super(ConstructionFunctor, self).__init__( - domain, sage.categories.groups.Groups()) + domain, sage.categories.monoids.Monoids() & sage.categories.posets.Posets()) def _repr_(self): @@ -2065,7 +2065,7 @@ class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): def __init__(self, var): super(MonomialGrowthGroupFunctor, self).__init__(var, - sage.categories.commutative_additive_groups.CommutativeAdditiveGroups()) + sage.categories.commutative_additive_monoids.CommutativeAdditiveMonoids()) def _apply_functor(self, base): @@ -2484,7 +2484,7 @@ class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): def __init__(self, var): super(ExponentialGrowthGroupFunctor, self).__init__(var, - sage.categories.groups.Groups()) + sage.categories.monoids.Monoids()) def _apply_functor(self, base): From 2f3aa8d6f049e96ee99826f81c7d7e997d825503 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 14:30:48 +0200 Subject: [PATCH 0503/1872] simplify some doctests: remove bool(...) --- src/sage/rings/asymptotic/growth_group.py | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index f07d42985be..c9f9d1973c0 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1356,9 +1356,9 @@ def _coerce_map_from_(self, S): sage: import sage.rings.asymptotic.growth_group as agg sage: G_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') sage: G_QQ = agg.MonomialGrowthGroup(QQ, 'x') - sage: bool(G_ZZ.has_coerce_map_from(G_QQ)) # indirect doctest + sage: G_ZZ.has_coerce_map_from(G_QQ) # indirect doctest False - sage: bool(G_QQ.has_coerce_map_from(G_ZZ)) # indirect doctest + sage: G_QQ.has_coerce_map_from(G_ZZ) # indirect doctest True :: @@ -1366,18 +1366,18 @@ def _coerce_map_from_(self, S): sage: import sage.rings.asymptotic.growth_group as agg sage: P_x_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') sage: P_x_QQ = agg.MonomialGrowthGroup(QQ, 'x') - sage: bool(P_x_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + sage: P_x_ZZ.has_coerce_map_from(P_x_QQ) # indirect doctest False - sage: bool(P_x_QQ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + sage: P_x_QQ.has_coerce_map_from(P_x_ZZ) # indirect doctest True sage: P_y_ZZ = agg.MonomialGrowthGroup(ZZ, 'y') - sage: bool(P_y_ZZ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + sage: P_y_ZZ.has_coerce_map_from(P_x_ZZ) # indirect doctest False - sage: bool(P_x_ZZ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + sage: P_x_ZZ.has_coerce_map_from(P_y_ZZ) # indirect doctest False - sage: bool(P_y_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + sage: P_y_ZZ.has_coerce_map_from(P_x_QQ) # indirect doctest False - sage: bool(P_x_QQ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + sage: P_x_QQ.has_coerce_map_from(P_y_ZZ) # indirect doctest False :: @@ -1385,18 +1385,18 @@ def _coerce_map_from_(self, S): sage: import sage.rings.asymptotic.growth_group as agg sage: P_x_ZZ = agg.GrowthGroup('ZZ^x') sage: P_x_QQ = agg.GrowthGroup('QQ^x') - sage: bool(P_x_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + sage: P_x_ZZ.has_coerce_map_from(P_x_QQ) # indirect doctest False - sage: bool(P_x_QQ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + sage: P_x_QQ.has_coerce_map_from(P_x_ZZ) # indirect doctest True sage: P_y_ZZ = agg.GrowthGroup('ZZ^y') - sage: bool(P_y_ZZ.has_coerce_map_from(P_x_ZZ)) # indirect doctest + sage: P_y_ZZ.has_coerce_map_from(P_x_ZZ) # indirect doctest False - sage: bool(P_x_ZZ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + sage: P_x_ZZ.has_coerce_map_from(P_y_ZZ) # indirect doctest False - sage: bool(P_y_ZZ.has_coerce_map_from(P_x_QQ)) # indirect doctest + sage: P_y_ZZ.has_coerce_map_from(P_x_QQ) # indirect doctest False - sage: bool(P_x_QQ.has_coerce_map_from(P_y_ZZ)) # indirect doctest + sage: P_x_QQ.has_coerce_map_from(P_y_ZZ) # indirect doctest False """ if isinstance(S, GenericGrowthGroup) and self._var_ == S._var_: From 3187c52c4233d94dbdd42fcdb529145fc70aff33 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 14:31:26 +0200 Subject: [PATCH 0504/1872] simplify code when using methods from inherited class --- .../asymptotic/growth_group_cartesian.py | 66 ++----------------- 1 file changed, 4 insertions(+), 62 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index ef27b270822..b845097b247 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -199,19 +199,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): :class:`~sage.sets.cartesian_product.CartesianProductPosets`. """ - @staticmethod - def __classcall__(cls, *args, **kwds): - r""" - Normalizes the input in order to ensure a unique - representation. - - TESTS:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: GrowthGroup('x^ZZ * y^ZZ') # indirect doctest - Growth Group x^ZZ * y^ZZ - """ - return CartesianProductPosets.__classcall__(cls, *args, **kwds) + __classcall__ = CartesianProductPosets.__classcall__ def __init__(self, sets, category, **kwds): @@ -237,21 +225,7 @@ def __init__(self, sets, category, **kwds): GenericGrowthGroup.__init__(self, sets[0], Vars, self.category(), **kwds) - def __hash__(self): - r""" - Return a hash value for this cartesian product. - - OUTPUT: - - An integer. - - TESTS:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: hash(GrowthGroup('x^ZZ * y^ZZ')) # indirect doctest, random - -1 - """ - return CartesianProductPosets.__hash__(self) + __hash__ = CartesianProductPosets.__hash__ def _element_constructor_(self, data): @@ -333,29 +307,7 @@ def _element_constructor_(self, data): return self(str_lst) - def _repr_(self, condense=False): - r""" - A representation string of this cartesian product of growth groups. - - INPUT: - - - ``condense`` -- (default: ``False``) if set, then a shorter - output is returned, e.g. the prefix-string ``Growth Group`` - is not show in this case. - - OUTPUT: - - A string. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') - sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') - sage: cartesian_product([P, L], order='lex')._repr_() - 'Growth Group x^QQ * log(x)^ZZ' - """ - return GenericGrowthGroup._repr_(self, condense) + _repr_ = GenericGrowthGroup._repr_ def _repr_short_(self): @@ -415,17 +367,7 @@ def _convert_to_factor_(self, data): continue - def _coerce_map_from_(self, S): - r""" - Return ``True if there is a coercion from ``S`` - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: GrowthGroup('x^ZZ * log(x)^ZZ').has_coerce_map_from(QQ) # indirect doctest - False - """ - pass + _coerce_map_from_ = CartesianProductPosets._coerce_map_from_ def gens_monomial(self): From c625a77f9b60178e617947c4e7eb970894fdafaf Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 14:31:41 +0200 Subject: [PATCH 0505/1872] doctests for functors --- src/sage/rings/asymptotic/growth_group.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c9f9d1973c0..2899044337f 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2058,6 +2058,15 @@ def construction(self): class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup, MonomialGrowthGroupFunctor + sage: cm = sage.structure.element.get_coercion_model() + sage: A = GrowthGroup('x^QQ') + sage: B = MonomialGrowthGroupFunctor('x')(ZZ['t']) + sage: cm.common_parent(A, B) + Growth Group x^(Univariate Polynomial Ring in t over Rational Field) """ _functor_name = 'MonomialGrowthGroup' @@ -2477,6 +2486,15 @@ def construction(self): class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup, ExponentialGrowthGroupFunctor + sage: cm = sage.structure.element.get_coercion_model() + sage: A = GrowthGroup('QQ^x') + sage: B = ExponentialGrowthGroupFunctor('x')(ZZ['t']) + sage: cm.common_parent(A, B) + Growth Group (Univariate Polynomial Ring in t over Rational Field)^x """ _functor_name = 'ExponentialGrowthGroup' From a1c88cd9e1ea87e3e405784fee4da3b5d8c2ec82 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 14:31:49 +0200 Subject: [PATCH 0506/1872] some coercion doctests --- .../asymptotic/growth_group_cartesian.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index b845097b247..39a0df4f792 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -27,6 +27,44 @@ without a formal deprecation. See http://trac.sagemath.org/17601 for details. Growth Group x^ZZ * log(x)^ZZ + +TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: A = GrowthGroup('QQ^x * x^ZZ'); A + Growth Group QQ^x * x^ZZ + sage: A.construction() + (The cartesian_product functorial construction, + (Growth Group QQ^x, Growth Group x^ZZ)) + sage: A.construction()[1][0].construction() + (ExponentialGrowthGroup[x], Rational Field) + sage: A.construction()[1][1].construction() + (MonomialGrowthGroup[x], Integer Ring) + sage: B = GrowthGroup('x^ZZ * y^ZZ'); B + Growth Group x^ZZ * y^ZZ + sage: B.construction() + (The cartesian_product functorial construction, + (Growth Group x^ZZ, Growth Group y^ZZ)) + sage: C = GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ'); C + Growth Group x^ZZ * log(x)^ZZ * y^ZZ + sage: C.construction() + (The cartesian_product functorial construction, + (Growth Group x^ZZ * log(x)^ZZ, Growth Group y^ZZ)) + sage: C.construction()[1][0].construction() + (The cartesian_product functorial construction, + (Growth Group x^ZZ, Growth Group log(x)^ZZ)) + sage: C.construction()[1][1].construction() + (MonomialGrowthGroup[y], Integer Ring) + +:: + + sage: cm = sage.structure.element.get_coercion_model() + sage: D = GrowthGroup('QQ^x * x^QQ') + sage: cm.common_parent(A, D) + Growth Group QQ^x * x^QQ + sage: E = GrowthGroup('ZZ^x * x^QQ') + sage: cm.common_parent(A, E) + Growth Group QQ^x * x^QQ """ #***************************************************************************** From 1226db2b3663ee067c6e6105dc3f8e309084cacd Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 20:41:46 +0200 Subject: [PATCH 0507/1872] correct bug in _coerce_map_from --- src/sage/rings/asymptotic/growth_group.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 2899044337f..33bbed6108d 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1398,8 +1398,13 @@ def _coerce_map_from_(self, S): False sage: P_x_QQ.has_coerce_map_from(P_y_ZZ) # indirect doctest False + + :: + + sage: agg.GrowthGroup('x^QQ').has_coerce_map_from(agg.GrowthGroup('QQ^x')) + False """ - if isinstance(S, GenericGrowthGroup) and self._var_ == S._var_: + if isinstance(S, type(self)) and self._var_ == S._var_: if self.base().has_coerce_map_from(S.base()): return True From 0ee54e8841db6efb66f6aa314305617785eb8d44 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 20:42:57 +0200 Subject: [PATCH 0508/1872] helper function for merging overlapping lists --- .../asymptotic/growth_group_cartesian.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 39a0df4f792..207b9acf477 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -81,6 +81,106 @@ import sage +def merge_overlapping(A, B, key=None): + r""" + Merge the two overlapping tuples/lists. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group_cartesian import merge_overlapping + sage: def f(L, s): + ....: return list((ell, s) for ell in L) + sage: key = lambda k: k[0] + sage: merge_overlapping(f([0..3], 'a'), f([5..7], 'b'), key) + Traceback (most recent call last): + ... + ValueError: Input does not have an overlap. + sage: merge_overlapping(f([0..2], 'a'), f([4..7], 'b'), key) + Traceback (most recent call last): + ... + ValueError: Input does not have an overlap. + sage: merge_overlapping(f([4..7], 'a'), f([0..2], 'b'), key) + Traceback (most recent call last): + ... + ValueError: Input does not have an overlap. + sage: merge_overlapping(f([0..3], 'a'), f([3..4], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a'), (4, 'b')], + [(0, 'a'), (1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]) + sage: merge_overlapping(f([3..4], 'a'), f([0..3], 'b'), key) + ([(0, 'b'), (1, 'b'), (2, 'b'), (3, 'a'), (4, 'a')], + [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b'), (4, 'a')]) + sage: merge_overlapping(f([0..1], 'a'), f([0..4], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'b'), (3, 'b'), (4, 'b')], + [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b'), (4, 'b')]) + sage: merge_overlapping(f([0..3], 'a'), f([0..1], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], + [(0, 'b'), (1, 'b'), (2, 'a'), (3, 'a')]) + sage: merge_overlapping(f([0..3], 'a'), f([1..3], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], + [(0, 'a'), (1, 'b'), (2, 'b'), (3, 'b')]) + sage: merge_overlapping(f([1..3], 'a'), f([0..3], 'b'), key) + ([(0, 'b'), (1, 'a'), (2, 'a'), (3, 'a')], + [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b')]) + sage: merge_overlapping(f([0..6], 'a'), f([3..4], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a'), (4, 'a'), (5, 'a'), (6, 'a')], + [(0, 'a'), (1, 'a'), (2, 'a'), (3, 'b'), (4, 'b'), (5, 'a'), (6, 'a')]) + sage: merge_overlapping(f([0..3], 'a'), f([1..2], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], + [(0, 'a'), (1, 'b'), (2, 'b'), (3, 'a')]) + sage: merge_overlapping(f([1..2], 'a'), f([0..3], 'b'), key) + ([(0, 'b'), (1, 'a'), (2, 'a'), (3, 'b')], + [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b')]) + sage: merge_overlapping(f([1..3], 'a'), f([1..3], 'b'), key) + ([(1, 'a'), (2, 'a'), (3, 'a')], + [(1, 'b'), (2, 'b'), (3, 'b')]) + """ + if key is None: + key = lambda k: k + + def find_overlapping_index(A, B): + if len(B) > len(A) - 2: + raise StopIteration + matches = iter(i for i in xrange(1, len(A) - len(B)) + if all(key(a) == key(b) for a, b in zip(A[i:i+len(B)], B))) + return next(matches) + + def find_mergedoverlapping_index(A, B): + """ + Return in index i where to merge two overlapping tuples/lists ``A`` and ``B``. + + Then ``A + B[i:]`` or ``A[:-i] + B`` are the merged tuples/lists. + + Adapted from http://stackoverflow.com/a/30056066/1052778. + """ + matches = iter(i for i in xrange(min(len(A), len(B)), 0, -1) + if all(key(a) == key(b) for a, b in zip(A[-i:], B[:i]))) + return next(matches, 0) + + i = find_mergedoverlapping_index(A, B) + if i > 0: + return A + B[i:], A[:-i] + B + + i = find_mergedoverlapping_index(B, A) + if i > 0: + return B[:-i] + A, B + A[i:] + + try: + i = find_overlapping_index(A, B) + except StopIteration: + pass + else: + return A, A[:i] + B + A[i+len(B):] + + try: + i = find_overlapping_index(B, A) + except StopIteration: + pass + else: + return B[:i] + A + B[i+len(A):], B + + raise ValueError('Input does not have an overlap.') + + class CartesianProductFactory(sage.structure.factory.UniqueFactory): r""" Creates various types of cartesian products depending on its input. From 25b628a8c26fccac15148f3523528c232f1c6283 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 20:43:20 +0200 Subject: [PATCH 0509/1872] refine variable for cartesian products --- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 207b9acf477..3061236e90c 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -358,7 +358,7 @@ def __init__(self, sets, category, **kwds): tuple()) from itertools import groupby from growth_group import Variable - Vars = Variable(tuple(v for v, _ in groupby(vars))) + Vars = Variable(tuple(v for v, _ in groupby(vars)), repr=self._repr_short_()) GenericGrowthGroup.__init__(self, sets[0], Vars, self.category(), **kwds) From b15a5c8001aa9f51f667ba4b45a5c5601b9c2af1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 20:45:02 +0200 Subject: [PATCH 0510/1872] _coerce_map_from_ for cartesian products --- .../asymptotic/growth_group_cartesian.py | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 3061236e90c..f819db45a91 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -505,7 +505,41 @@ def _convert_to_factor_(self, data): continue - _coerce_map_from_ = CartesianProductPosets._coerce_map_from_ + def _coerce_map_from_(self, S): + r""" + Return if ``S`` coerces into this growth group. + + INPUT: + + - ``S`` -- a parent. + + OUTPUT: + + A boolean. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: A = GrowthGroup('QQ^x * x^QQ') + sage: B = GrowthGroup('QQ^x * x^ZZ') + sage: A.has_coerce_map_from(B) + True + sage: B.has_coerce_map_from(A) + False + """ + if CartesianProductPosets.has_coerce_map_from(self, S): + return True + + elif isinstance(S, GenericProduct): + factors = S.cartesian_factors() + else: + factors = (S,) + + if all(any(g.has_coerce_map_from(f) for g in self.cartesian_factors()) + for f in factors): + return True + + def gens_monomial(self): From 658e937b2254af20dc9f7ec0e2a79b71dba66533 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 20:46:20 +0200 Subject: [PATCH 0511/1872] minor docstring change --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 33bbed6108d..8b16f7632e7 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1351,7 +1351,7 @@ def _coerce_map_from_(self, S): A boolean. - EXAMPLES:: + TESTS:: sage: import sage.rings.asymptotic.growth_group as agg sage: G_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') From e0c47c9cdbd58120a99086a65e4b4363b960bade Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 20:46:38 +0200 Subject: [PATCH 0512/1872] write _pushout_ --- .../asymptotic/growth_group_cartesian.py | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index f819db45a91..0debb7e3756 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -540,6 +540,159 @@ def _coerce_map_from_(self, S): return True + def _pushout_(self, other): + r""" + Construct the pushout of this and the other growth group. This is called by + :func:`sage.categories.pushout.pushout`. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.categories.pushout import pushout + sage: cm = sage.structure.element.get_coercion_model() + sage: A = GrowthGroup('QQ^x * x^ZZ') + sage: B = GrowthGroup('x^ZZ * log(x)^ZZ') + sage: A._pushout_(B) + Growth Group QQ^x * x^ZZ * log(x)^ZZ + sage: pushout(A, B) + Growth Group QQ^x * x^ZZ * log(x)^ZZ + sage: cm.discover_coercion(A, B) + ((map internal to coercion system -- copy before use) + Conversion map: + From: Growth Group QQ^x * x^ZZ + To: Growth Group QQ^x * x^ZZ * log(x)^ZZ, + (map internal to coercion system -- copy before use) + Conversion map: + From: Growth Group x^ZZ * log(x)^ZZ + To: Growth Group QQ^x * x^ZZ * log(x)^ZZ) + sage: cm.common_parent(A, B) + Growth Group QQ^x * x^ZZ * log(x)^ZZ + + :: + + sage: C = GrowthGroup('QQ^x * x^QQ * y^ZZ') + sage: D = GrowthGroup('x^ZZ * log(x)^QQ * QQ^z') + sage: C._pushout_(D) + Growth Group QQ^x * x^QQ * log(x)^QQ * y^ZZ * QQ^z + sage: cm.common_parent(C, D) + Growth Group QQ^x * x^QQ * log(x)^QQ * y^ZZ * QQ^z + sage: A._pushout_(D) + Growth Group QQ^x * x^ZZ * log(x)^QQ * QQ^z + sage: cm.common_parent(A, D) + Growth Group QQ^x * x^ZZ * log(x)^QQ * QQ^z + sage: cm.common_parent(B, D) + Growth Group x^ZZ * log(x)^QQ * QQ^z + sage: cm.common_parent(A, C) + Growth Group QQ^x * x^QQ * y^ZZ + sage: E = GrowthGroup('log(x)^ZZ * y^ZZ') + sage: cm.common_parent(A, E) + Traceback (most recent call last): + ... + TypeError: no common canonical parent for objects with parents: + 'Growth Group QQ^x * x^ZZ' and 'Growth Group log(x)^ZZ * y^ZZ' + """ + def pushout_univariate_factors(self, other, var, Sfactors, Ofactors): + try: + return merge_overlapping( + Sfactors, Ofactors, + lambda f: (type(f), f._var_.var_repr)) + except ValueError: + pass + + #print "search common", Sfactors, Ofactors + cm = sage.structure.element.get_coercion_model() + try: + Z = cm.common_parent(*Sfactors+Ofactors) + #print "found common", Z + return (Z,), (Z,) + except TypeError: + pass + + def subfactors(F): + for f in F: + if isinstance(f, GenericProduct): + for g in subfactors(f.cartesian_factors()): + yield g + else: + yield f + + try: + return merge_overlapping( + tuple(subfactors(Sfactors)), tuple(subfactors(Ofactors)), + lambda f: (type(f), f._var_.var_repr)) + except ValueError: + pass + + from sage.structure.coerce_exceptions import CoercionException + raise CoercionException( + 'Cannot construct the pushout of %s and %s: The factors ' + 'with variables %s are not overlapping, ' + 'no common parent was found, and ' + 'splitting the factors was unsuccessful.' % (self, other, var)) + + + if isinstance(other, GenericProduct): + class it: + def __init__(self, it): + self.it = it + self.var = None + self.factors = None + def next(self): + try: + self.var, factors = next(self.it) + self.factors = tuple(factors) + except StopIteration: + self.var = None + self.factors = tuple() + + from itertools import groupby + S = it(groupby(self.cartesian_factors(), key=lambda k: k.variable_names())) + O = it(groupby(other.cartesian_factors(), key=lambda k: k.variable_names())) + + newS = [] + newO = [] + + S.next() + O.next() + while S.var is not None or O.var is not None: + #print S.var, S.factors, newS, O.var, O.factors, newO + if S.var is not None and S.var < O.var: + newS.extend(S.factors) + newO.extend(S.factors) + S.next() + elif O.var is not None and S.var > O.var: + newS.extend(O.factors) + newO.extend(O.factors) + O.next() + else: + SL, OL = pushout_univariate_factors(self, other, S.var, + S.factors, O.factors) + newS.extend(SL) + newO.extend(OL) + S.next() + O.next() + + #print 'done', S.var, S.factors, newS, O.var, O.factors, newO + assert(len(newS) == len(newO)) + + if (len(self.cartesian_factors()) == len(newS) and + len(other.cartesian_factors()) == len(newO)): + # We had already all factors in each of the self and + # other, thus splitting it in subproblems (one for + # each factor) is the strategy to use. If a pushout is + # possible :func:`sage.categories.pushout.pushout` + # will manage this by itself. + return + + from sage.categories.pushout import pushout + from sage.categories.cartesian_product import cartesian_product + return pushout(cartesian_product(newS), cartesian_product(newO)) + + + #C = other.construction()[0] + #if isinstance(C, PolynomialFunctor): + # return pushout(self, CartesianProductPolys((other,))) + def gens_monomial(self): From d1e64daef069761e63148f63152553f4a51e2de6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 20:57:33 +0200 Subject: [PATCH 0513/1872] some code rewriting and changing of indent --- .../asymptotic/growth_group_cartesian.py | 116 +++++++++--------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 0debb7e3756..e12a0cc125d 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -591,6 +591,10 @@ def _pushout_(self, other): TypeError: no common canonical parent for objects with parents: 'Growth Group QQ^x * x^ZZ' and 'Growth Group log(x)^ZZ * y^ZZ' """ + from growth_group import GenericGrowthGroup + if not isinstance(other, GenericGrowthGroup): + return + def pushout_univariate_factors(self, other, var, Sfactors, Ofactors): try: return merge_overlapping( @@ -599,11 +603,9 @@ def pushout_univariate_factors(self, other, var, Sfactors, Ofactors): except ValueError: pass - #print "search common", Sfactors, Ofactors cm = sage.structure.element.get_coercion_model() try: Z = cm.common_parent(*Sfactors+Ofactors) - #print "found common", Z return (Z,), (Z,) except TypeError: pass @@ -631,62 +633,62 @@ def subfactors(F): 'splitting the factors was unsuccessful.' % (self, other, var)) - if isinstance(other, GenericProduct): - class it: - def __init__(self, it): - self.it = it + if not isinstance(other, GenericProduct): + return + + class it: + def __init__(self, it): + self.it = it + self.var = None + self.factors = None + def next(self): + try: + self.var, factors = next(self.it) + self.factors = tuple(factors) + except StopIteration: self.var = None - self.factors = None - def next(self): - try: - self.var, factors = next(self.it) - self.factors = tuple(factors) - except StopIteration: - self.var = None - self.factors = tuple() - - from itertools import groupby - S = it(groupby(self.cartesian_factors(), key=lambda k: k.variable_names())) - O = it(groupby(other.cartesian_factors(), key=lambda k: k.variable_names())) - - newS = [] - newO = [] - - S.next() - O.next() - while S.var is not None or O.var is not None: - #print S.var, S.factors, newS, O.var, O.factors, newO - if S.var is not None and S.var < O.var: - newS.extend(S.factors) - newO.extend(S.factors) - S.next() - elif O.var is not None and S.var > O.var: - newS.extend(O.factors) - newO.extend(O.factors) - O.next() - else: - SL, OL = pushout_univariate_factors(self, other, S.var, - S.factors, O.factors) - newS.extend(SL) - newO.extend(OL) - S.next() - O.next() - - #print 'done', S.var, S.factors, newS, O.var, O.factors, newO - assert(len(newS) == len(newO)) - - if (len(self.cartesian_factors()) == len(newS) and - len(other.cartesian_factors()) == len(newO)): - # We had already all factors in each of the self and - # other, thus splitting it in subproblems (one for - # each factor) is the strategy to use. If a pushout is - # possible :func:`sage.categories.pushout.pushout` - # will manage this by itself. - return - - from sage.categories.pushout import pushout - from sage.categories.cartesian_product import cartesian_product - return pushout(cartesian_product(newS), cartesian_product(newO)) + self.factors = tuple() + + from itertools import groupby + S = it(groupby(self.cartesian_factors(), key=lambda k: k.variable_names())) + O = it(groupby(other.cartesian_factors(), key=lambda k: k.variable_names())) + + newS = [] + newO = [] + + S.next() + O.next() + while S.var is not None or O.var is not None: + if S.var is not None and S.var < O.var: + newS.extend(S.factors) + newO.extend(S.factors) + S.next() + elif O.var is not None and S.var > O.var: + newS.extend(O.factors) + newO.extend(O.factors) + O.next() + else: + SL, OL = pushout_univariate_factors(self, other, S.var, + S.factors, O.factors) + newS.extend(SL) + newO.extend(OL) + S.next() + O.next() + + assert(len(newS) == len(newO)) + + if (len(self.cartesian_factors()) == len(newS) and + len(other.cartesian_factors()) == len(newO)): + # We had already all factors in each of the self and + # other, thus splitting it in subproblems (one for + # each factor) is the strategy to use. If a pushout is + # possible :func:`sage.categories.pushout.pushout` + # will manage this by itself. + return + + from sage.categories.pushout import pushout + from sage.categories.cartesian_product import cartesian_product + return pushout(cartesian_product(newS), cartesian_product(newO)) #C = other.construction()[0] From d40ea73ac68fa952e4208e65859f202b848331d7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 21:02:48 +0200 Subject: [PATCH 0514/1872] extend pushout --- .../asymptotic/growth_group_cartesian.py | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index e12a0cc125d..8900fa4432a 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -590,11 +590,26 @@ def _pushout_(self, other): ... TypeError: no common canonical parent for objects with parents: 'Growth Group QQ^x * x^ZZ' and 'Growth Group log(x)^ZZ * y^ZZ' + + :: + + sage: F = GrowthGroup('z^QQ') + sage: pushout(C, F) + Growth Group QQ^x * x^QQ * y^ZZ * z^QQ """ - from growth_group import GenericGrowthGroup - if not isinstance(other, GenericGrowthGroup): + from growth_group import GenericGrowthGroup, AbstractGrowthGroupFunctor + + if isinstance(other, GenericProduct): + Ofactors = other.cartesian_factors() + elif isinstance(other, GenericGrowthGroup): + Ofactors = (other,) + elif (other.construction() is not None and + isinstance(other.construction()[0], AbstractGrowthGroupFunctor)): + Ofactors = (other,) + else: return + def pushout_univariate_factors(self, other, var, Sfactors, Ofactors): try: return merge_overlapping( @@ -633,9 +648,6 @@ def subfactors(F): 'splitting the factors was unsuccessful.' % (self, other, var)) - if not isinstance(other, GenericProduct): - return - class it: def __init__(self, it): self.it = it @@ -651,7 +663,7 @@ def next(self): from itertools import groupby S = it(groupby(self.cartesian_factors(), key=lambda k: k.variable_names())) - O = it(groupby(other.cartesian_factors(), key=lambda k: k.variable_names())) + O = it(groupby(Ofactors, key=lambda k: k.variable_names())) newS = [] newO = [] From 777f99757870e8338edc66430e2e793956b1c9de Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Aug 2015 21:14:03 +0200 Subject: [PATCH 0515/1872] more pushouts --- src/sage/rings/asymptotic/growth_group.py | 36 +++++++++++++++++++ .../asymptotic/growth_group_cartesian.py | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 8b16f7632e7..ad4828fc564 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1409,6 +1409,42 @@ def _coerce_map_from_(self, S): return True + def _pushout_(self, other): + r""" + Construct the pushout of this and the other growth group. This is called by + :func:`sage.categories.pushout.pushout`. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.categories.pushout import pushout + sage: cm = sage.structure.element.get_coercion_model() + sage: A = GrowthGroup('QQ^x') + sage: B = GrowthGroup('y^ZZ') + sage: A._pushout_(B) + Growth Group QQ^x * y^ZZ + sage: cm.common_parent(A, B) + Growth Group QQ^x * y^ZZ + sage: C = GrowthGroup('x^QQ') + sage: cm.common_parent(A, C) + Traceback (most recent call last): + ... + TypeError: no common canonical parent for objects with parents: + 'Growth Group QQ^x' and 'Growth Group x^QQ' + """ + if isinstance(other, GenericGrowthGroup): + pass + if (other.construction() is not None and + isinstance(other.construction()[0], AbstractGrowthGroupFunctor)): + pass + else: + return + + if set(self.variable_names()).isdisjoint(set(other.variable_names())): + from sage.categories.cartesian_product import cartesian_product + return cartesian_product([self, other]) + + def gens_monomial(self): r""" Return a generator of this growth group, in case one exists. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 8900fa4432a..d224e17ea79 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -281,7 +281,7 @@ def create_object(self, version, args, **kwds): # check if variables are pairwise disjoint for u, w in product(iter(v for v, _ in vgs), repeat=2): - if u != w and set(u).intersection(set(w)): + if u != w and not set(u).isdisjoint(set(w)): raise ValueError('Growth groups %s do not have pairwise disjoint ' 'variables.' % (growth_groups,)) From 3cacc5261fb5c13c43e6ba96dbbe9b3863a0399d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 23 Aug 2015 10:04:28 +0200 Subject: [PATCH 0516/1872] change recursive pushout to common_parent (to take care of direct coercions) --- src/sage/categories/pushout.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index fbc429c1dff..d36f1a9a114 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -731,7 +731,9 @@ def common_base(self, other_functor, self_bases, other_bases): self._raise_common_base_exception_( other_functor, self_bases, other_bases, 'Functors need the same number of arguments') - Z_bases = tuple(pushout(S, O) for S, O in zip(self_bases, other_bases)) + from sage.structure.element import get_coercion_model + Z_bases = tuple(get_coercion_model().common_parent(S, O) + for S, O in zip(self_bases, other_bases)) return self(Z_bases) From 4662eed90bade7fadb0a0b9b64789ff127bf0c86 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 23 Aug 2015 10:05:14 +0200 Subject: [PATCH 0517/1872] bug kind of solved (called now directly by cartesian_product); move doctest --- src/sage/categories/pushout.py | 36 +++++++++++++--------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index d36f1a9a114..640f030645f 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1,27 +1,5 @@ """ Coercion via Construction Functors - -TESTS: - -A bug:: - - sage: from sage.categories.pushout import pushout - sage: from sage.sets.cartesian_product import CartesianProduct - sage: A = CartesianProduct((QQ['z'],), Sets().CartesianProducts()) - sage: B = CartesianProduct((ZZ['t']['z'],), Sets().CartesianProducts()) - sage: pushout(A, B) - The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) - sage: A.construction() - (The cartesian_product functorial construction, - (Univariate Polynomial Ring in z over Rational Field,)) - sage: pushout(A, B) - The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) - -In ``A.construction()`` the functor (``CartesianProductFunctor``) -seems not to be seen as ``ConstructionFunctor``` at the first pass, -although it is inherited from -``MultivariateConstructionFunctor``. Code needs to be more on the top -of the file to be reproduced """ from sage.misc.lazy_import import lazy_import from functor import Functor, IdentityFunctor_generic @@ -679,6 +657,20 @@ class MultivariateConstructionFunctor(ConstructionFunctor): """ An abstract base class for functors that take multiple inputs (e.g. cartesian products). + + TESTS:: + + sage: from sage.categories.pushout import pushout + sage: from sage.sets.cartesian_product import CartesianProduct + sage: A = cartesian_product((QQ['z'],)) + sage: B = cartesian_product((ZZ['t']['z'],)) + sage: pushout(A, B) + The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) + sage: A.construction() + (The cartesian_product functorial construction, + (Univariate Polynomial Ring in z over Rational Field,)) + sage: pushout(A, B) + The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) """ def common_base(self, other_functor, self_bases, other_bases): r""" From 23354db861047e7c01ce11abf8d4aa4ad75b2772 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 23 Aug 2015 10:41:10 +0200 Subject: [PATCH 0518/1872] add missing test and fix broken tests --- src/sage/categories/groups.py | 1 + src/sage/categories/modules.py | 16 +++++++++++++++- src/sage/categories/monoids.py | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index eaa0ed868e8..0970c056ccd 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -914,6 +914,7 @@ def lift(i, gen): # Infinitely generated # This does not return a good output, but it is "correct" # TODO: Figure out a better way to do things + from sage.categories.cartesian_product import cartesian_product gens_prod = cartesian_product([Family(G.group_generators(), lambda g: (i, g)) for i,G in enumerate(F)]) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 3cb262126b8..e8cd6357c80 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -598,10 +598,24 @@ def extra_super_categories(self): sage: Modules(ZZ).CartesianProducts().extra_super_categories() [Category of modules over Integer Ring] sage: Modules(ZZ).CartesianProducts().super_categories() - [Category of modules over Integer Ring, Category of Cartesian products of monoids] + [Category of Cartesian products of commutative additive groups, + Category of modules over Integer Ring] """ return [self.base_category()] class ParentMethods: def base_ring(self): + """ + Return the base ring this cartesian product. + + EXAMPLES:: + + sage: E = CombinatorialFreeModule(ZZ, [1,2,3]) + sage: F = CombinatorialFreeModule(ZZ, [2,3,4]) + sage: C = cartesian_product([E, F]); C + Free module generated by {1, 2, 3} over Integer Ring (+) + Free module generated by {2, 3, 4} over Integer Ring + sage: C.base_ring() + Integer Ring + """ return self._sets[0].base_ring() diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index 72359024a97..8bcd6676a12 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -588,6 +588,7 @@ def lift(i, gen): # Infinitely generated # This does not return a good output, but it is "correct" # TODO: Figure out a better way to do things + from sage.categories.cartesian_product import cartesian_product gens_prod = cartesian_product([Family(M.monoid_generators(), lambda g: (i, g)) for i,M in enumerate(F)]) From a1d962ac30c6d5c8280a2f509900ff462210759c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 23 Aug 2015 22:50:56 +0000 Subject: [PATCH 0519/1872] pyflakes cleanup of bialgebras.py. --- src/sage/categories/bialgebras.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index b592b700569..50129155bb8 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -11,10 +11,6 @@ from sage.categories.category_types import Category_over_base_ring from sage.categories.all import Algebras, Coalgebras -from sage.categories.tensor import tensor -from sage.functions.other import floor, ceil -from sage.rings.integer import Integer -from sage.categories.modules_with_basis import ModulesWithBasis from sage.misc.lazy_import import LazyImport class Bialgebras(Category_over_base_ring): @@ -67,4 +63,5 @@ class ParentMethods: class ElementMethods: pass - WithBasis = LazyImport('sage.categories.bialgebras_with_basis', 'BialgebrasWithBasis') \ No newline at end of file + WithBasis = LazyImport('sage.categories.bialgebras_with_basis', 'BialgebrasWithBasis') + From 50ecfe4cbfb07f3c681979860f2d69b8508ffd25 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 24 Aug 2015 00:39:49 +0000 Subject: [PATCH 0520/1872] Reviewer changes for #18678. - Documentation changes. - Moved coproduct_iterated to coalgebras (with basis). - Updated doctests due to changes in the category heirarchy. --- src/sage/categories/bialgebras_with_basis.py | 210 +++++++----------- src/sage/categories/coalgebras_with_basis.py | 65 +++++- ...inite_dimensional_bialgebras_with_basis.py | 3 +- .../graded_bialgebras_with_basis.py | 3 +- .../categories/hopf_algebras_with_basis.py | 3 +- 5 files changed, 148 insertions(+), 136 deletions(-) diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index 552e1cf0113..d0fd23e870f 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -37,26 +37,35 @@ def convolution_product(self, *maps): r""" Return the convolution product (a map) of the given maps. - INPUT: + Let `A` and `B` be bialgebras over a commutative ring `R`. + Given maps `f_i : A \to B` for `1 \leq i < n`, define the + convolution product - - ``maps`` -- any number `n \geq 0` of linear maps `R, S, \dots, - T` on ``self``; or a single ``list`` or ``tuple`` of such maps. + .. MATH:: - OUTPUT: + (f_1 * f_2 * \cdots * f_n) := \mu^{(n-1)} \circ (f_1 \otimes + f_2 \otimes \cdots \otimes f_n) \circ \Delta^{(n-1)}, - - the new map `R * S * \cdots * T` representing their convolution - product. + where `\Delta^{(k)} := \bigl(\Delta \otimes + \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, + with `\Delta^{(1)} = \Delta` (the ordinary coproduct in `A`) and + `\Delta^{(0)} = \mathrm{Id}`; and with `\mu^{(k)} := \mu \circ + \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` + (the ordinary product in `B`). See [Sw1969]_. - .. MATH:: + (In the literature, one finds, e.g., `\Delta^{(2)}` for what we + denote above as `\Delta^{(1)}`. See [KMN2012]_.) - (R*S*\cdots*T) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}, + INPUT: + + - ``maps`` -- any number `n \geq 0` of linear maps `f_1, f_2, + \ldots, f_n` on ``self``; or a single ``list`` or ``tuple`` + of such maps - where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, - with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; - and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` - (the ordinary product). See [Sw1969]_. + OUTPUT: - (In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.) + - the new map `f_1 * f_2 * \cdots * f_2` representing their + convolution product .. SEEALSO:: @@ -64,9 +73,7 @@ def convolution_product(self, *maps): AUTHORS: - Aaron Lauve - 12 June 2015 - Sage Days 65 - - based off of .adams_operator() code in sage-trac ticket #18350 - - by Jean-Baptiste Priez + - Aaron Lauve - 12 June 2015 - Sage Days 65 .. TODO:: @@ -128,40 +135,39 @@ def convolution_product(self, *maps): sage: T(x) 2*[1, 3, 2] + [2, 1, 3] + 2*[2, 3, 1] + 3*[3, 1, 2] + 3*[3, 2, 1] """ - H = self - # TYPE-CHECK: - if not H in ModulesWithBasis: - raise AttributeError('`self` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `self` instead.' % H._repr_()) - - onbasis = lambda x: H.term(x).convolution_product(*maps) - return H.module_morphism(on_basis=onbasis, codomain=H) + onbasis = lambda x: self.term(x).convolution_product(*maps) + return self.module_morphism(on_basis=onbasis, codomain=self) class ElementMethods: def adams_operator(self, n): r""" - Compute the `n`-th convolution power of the identity morphism `Id` - on ``self``. + Compute the `n`-th convolution power of the identity morphism + `\mathrm{Id}` on ``self``. INPUT: - - ``n`` -- a nonnegative integer. + - ``n`` -- a nonnegative integer OUTPUT: - - the image of ``self`` under the convolution power `Id^{*n}`. + - the image of ``self`` under the convolution power `\mathrm{Id}^{*n}` - .. SEEALSO:: + .. NOTE:: + + In the literature, this is also called a Hopf power or + Sweedler power, cf. [AL2015]_. - :mod:`sage.categories.bialgebras.ElementMethods.convolution_product` + .. SEEALSO:: - (In the literature, this is also called a Hopf power or Sweedler power, cf. [AL2015]_.) + :meth:`sage.categories.bialgebras.ElementMethods.convolution_product` REFERENCES: - .. [AL2015] The characteristic polynomial of the Adams operators on graded connected Hopf algebras. - Marcelo Aguiar and Aaron Lauve. - Algebra Number Theory, v.9, 2015, n.3, 2015. + .. [AL2015] *The characteristic polynomial of the Adams operators + on graded connected Hopf algebras*. + Marcelo Aguiar and Aaron Lauve. + Algebra Number Theory, v.9, 2015, n.3, 2015. .. TODO:: @@ -195,14 +201,13 @@ def adams_operator(self, n): sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: m[[1,3],[2]].adams_operator(-2) 3*m{{1}, {2, 3}} + 3*m{{1, 2}, {3}} + 6*m{{1, 2, 3}} - 2*m{{1, 3}, {2}} - """ if n < 0: if hasattr(self, 'antipode'): T = lambda x: x.antipode() n = abs(n) else: - raise ValueError("`self` has no antipode, hence cannot take negative convolution powers of identity_map: %s < 0" % str(n)) + raise ValueError("antipode not defined; cannot take negative convolution powers: {} < 0".format(n)) else: T = lambda x: x return self.convolution_product([T] * n) @@ -212,40 +217,48 @@ def convolution_product(self, *maps): Return the image of ``self`` under the convolution product (map) of the maps. - INPUT: + Let `A` and `B` be bialgebras over a commutative ring `R`. + Given maps `f_i : A \to B` for `1 \leq i < n`, define the + convolution product - - ``maps`` -- any number `n \geq 0` of linear maps `R, S, \dots, - T` on ``self.parent()``; or a single ``list`` or ``tuple`` of - such maps. + .. MATH:: - OUTPUT: + (f_1 * f_2 * \cdots * f_n) := \mu^{(n-1)} \circ (f_1 \otimes + f_2 \otimes \cdots \otimes f_n) \circ \Delta^{(n-1)}, - - `(R * S * \cdots * T)` applied to ``self``. + where `\Delta^{(k)} := \bigl(\Delta \otimes + \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, + with `\Delta^{(1)} = \Delta` (the ordinary coproduct in `A`) and + `\Delta^{(0)} = \mathrm{Id}`; and with `\mu^{(k)} := \mu \circ + \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` + (the ordinary product in `B`). See [Sw1969]_. - .. MATH:: + (In the literature, one finds, e.g., `\Delta^{(2)}` for what we + denote above as `\Delta^{(1)}`. See [KMN2012]_.) - (R*S*\cdots*T)(h) := \mu^{(n-1)} \circ (R \otimes S \otimes\cdot\otimes T) \circ \Delta^{(n-1)}(h), + INPUT: + + - ``maps`` -- any number `n \geq 0` of linear maps `f_1, f_2, + \ldots, f_n` on ``self.parent()``; or a single ``list`` or + ``tuple`` of such maps - where `\Delta^{(k)} := \bigl(\Delta \otimes \mathrm{Id}^{\otimes(k-1)}\bigr) \circ \Delta^{(k-1)}`, - with `\Delta^{(1)} = \Delta` (the ordinary coproduct) and `\Delta^{(0)} = \mathrm{Id}`; - and with `\mu^{(k)} := \mu \circ \bigl(\mu^{(k-1)} \otimes \mathrm{Id})` and `\mu^{(1)} = \mu` - (the ordinary product). See [Sw1969]_. + OUTPUT: - (In the literature, one finds, e.g., `\Delta^{(2)}` for what we denote above as `\Delta^{(1)}`. See [KMN2012]_.) + - the convolution product of ``maps`` applied to ``self`` REFERENCES: .. [KMN2012] On the trace of the antipode and higher indicators. - Yevgenia Kashina and Susan Montgomery and Richard Ng. - Israel J. Math., v.188, 2012. + Yevgenia Kashina and Susan Montgomery and Richard Ng. + Israel J. Math., v.188, 2012. .. [Sw1969] Hopf algebras. - Moss Sweedler. - W.A. Benjamin, Math Lec Note Ser., 1969. + Moss Sweedler. + W.A. Benjamin, Math Lec Note Ser., 1969. AUTHORS: - Amy Pang - 12 June 2015 - Sage Days 65 + - Amy Pang - 12 June 2015 - Sage Days 65 .. TODO:: @@ -301,7 +314,6 @@ def convolution_product(self, *maps): sage: x.convolution_product([Id]*6) 9*[1, 2, 3] - TESTS:: sage: Id = lambda x: x @@ -323,7 +335,8 @@ def convolution_product(self, *maps): sage: S = NonCommutativeSymmetricFunctions(QQ).S() sage: S[4].convolution_product([Id]*5) - 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] + 5*S[1, 1, 1, 1] + 10*S[1, 1, 2] + 10*S[1, 2, 1] + 10*S[1, 3] + + 10*S[2, 1, 1] + 10*S[2, 2] + 10*S[3, 1] + 5*S[4] :: @@ -360,7 +373,6 @@ def convolution_product(self, *maps): sage: s[3,2].counit().parent() == s[3,2].convolution_product().parent() False - """ # Be flexible on how the maps are entered: accept a list/tuple of # maps as well as multiple arguments @@ -370,87 +382,27 @@ def convolution_product(self, *maps): T = maps H = self.parent() - # TYPE-CHECK: - if not H in ModulesWithBasis: - raise AttributeError('`parent` (%s) must belong to ModulesWithBasis. Try defining convolution product on a basis of `parent` instead.' % H._repr_()) n = len(T) if n == 0: return H.one() * self.counit() - elif n == 1: + if n == 1: return T[0](self) - else: - # We apply the maps T_i and products concurrently with coproducts, as this - # seems to be faster than applying a composition of maps, e.g., (H.nfold_product) * tensor(T) * (H.nfold_coproduct). - i = 0 - out = tensor((H.one(),self)) - HH = tensor((H,H)) + # We apply the maps T_i and products concurrently with coproducts, as this + # seems to be faster than applying a composition of maps, e.g., (H.nfold_product) * tensor(T) * (H.nfold_coproduct). + + out = tensor((H.one(),self)) + HH = tensor((H,H)) + for mor in T[:-1]: #ALGORITHM: #`split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. - split_convolve = lambda (x,y): (((xy1,y2),c*d) for ((y1,y2),d) in H.term(y).coproduct() for (xy1,c) in H.term(x)*T[i](H.term(y1))) - while i < n-1: - out = HH.module_morphism(on_basis=lambda t: HH.sum_of_terms(split_convolve(t)), codomain = HH)(out) - i += 1 - - #Apply final map `T_n` to last term, `y`, and multiply. - out = HH.module_morphism(on_basis=lambda (x,y): H.term(x)*T[n-1](H.term(y)), codomain=H)(out) + split_convolve = lambda (x,y): ( ((xy1,y2),c*d) + for ((y1,y2),d) in H.term(y).coproduct() + for (xy1,c) in H.term(x)*mor(H.term(y1)) ) + out = HH.module_morphism(on_basis=lambda t: HH.sum_of_terms(split_convolve(t)), codomain=HH)(out) - return out - - - def coproduct_iterated(self, n=1): - r""" - Apply `n` coproducts to ``self``. - - .. TODO:: - - Remove dependency on ``modules_with_basis`` methods. - - EXAMPLES:: - - sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,2].coproduct_iterated(0) - Psi[2, 2] - sage: Psi[2,2].coproduct_iterated(2) - Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2] + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[] - - TESTS:: - - sage: p = SymmetricFunctions(QQ).p() - sage: p[5,2,2].coproduct_iterated() - p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5] + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[] - sage: p([]).coproduct_iterated(3) - p[] # p[] # p[] # p[] - - :: - - sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() - sage: Psi[2,2].coproduct_iterated(0) - Psi[2, 2] - sage: Psi[2,2].coproduct_iterated(3) - Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2] + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[] + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[] + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[] - - :: - - sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() - sage: m[[1,3],[2]].coproduct_iterated(2) - m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}} + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{} + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{} + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{} + m{{1, 3}, {2}} # m{} # m{} - sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) - (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) - """ - if n < 0: - raise ValueError("cannot take fewer than 0 coproduct iterations: %s < 0" % str(n)) - if n==0: - return self - elif n==1: - return self.coproduct() - else: - from sage.functions.all import floor, ceil - from sage.rings.all import Integer + #Apply final map `T_n` to last term, `y`, and multiply. + return HH.module_morphism(on_basis=lambda (x,y): H.term(x)*T[-1](H.term(y)), codomain=H)(out) - # Use coassociativity of `\Delta` to perform many coproducts simultaneously. - fn = floor(Integer(n-1)/2); cn = ceil(Integer(n-1)/2) - def split(a,b): return tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) - return (self.coproduct()).apply_multilinear_morphism(split) \ No newline at end of file diff --git a/src/sage/categories/coalgebras_with_basis.py b/src/sage/categories/coalgebras_with_basis.py index 0b9ff24f0ec..1c51fcca887 100644 --- a/src/sage/categories/coalgebras_with_basis.py +++ b/src/sage/categories/coalgebras_with_basis.py @@ -127,5 +127,68 @@ def counit(self): return self.module_morphism(self.counit_on_basis,codomain=self.base_ring()) class ElementMethods: - pass + def coproduct_iterated(self, n=1): + r""" + Apply ``n`` coproducts to ``self``. + + .. TODO:: + + Remove dependency on ``modules_with_basis`` methods. + + EXAMPLES:: + + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() + sage: Psi[2,2].coproduct_iterated(0) + Psi[2, 2] + sage: Psi[2,2].coproduct_iterated(2) + Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2] + + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2] + + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[] + + TESTS:: + + sage: p = SymmetricFunctions(QQ).p() + sage: p[5,2,2].coproduct_iterated() + p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5] + + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[] + sage: p([]).coproduct_iterated(3) + p[] # p[] # p[] # p[] + + :: + + sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() + sage: Psi[2,2].coproduct_iterated(0) + Psi[2, 2] + sage: Psi[2,2].coproduct_iterated(3) + Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2] + + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2] + + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[] + + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[] + + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[] + + :: + + sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() + sage: m[[1,3],[2]].coproduct_iterated(2) + m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}} + + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{} + + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{} + + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{} + + m{{1, 3}, {2}} # m{} # m{} + sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) + (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) + """ + if n < 0: + raise ValueError("cannot take fewer than 0 coproduct iterations: %s < 0" % str(n)) + if n == 0: + return self + if n == 1: + return self.coproduct() + from sage.functions.all import floor, ceil + from sage.rings.all import Integer + + # Use coassociativity of `\Delta` to perform many coproducts simultaneously. + fn = floor(Integer(n-1)/2); cn = ceil(Integer(n-1)/2) + split = lambda a,b: tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) + return self.coproduct().apply_multilinear_morphism(split) diff --git a/src/sage/categories/finite_dimensional_bialgebras_with_basis.py b/src/sage/categories/finite_dimensional_bialgebras_with_basis.py index f276371d25f..086892237e6 100644 --- a/src/sage/categories/finite_dimensional_bialgebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_bialgebras_with_basis.py @@ -18,8 +18,7 @@ def FiniteDimensionalBialgebrasWithBasis(base_ring): sage: C = FiniteDimensionalBialgebrasWithBasis(QQ); C Category of finite dimensional bialgebras with basis over Rational Field sage: sorted(C.super_categories(), key=str) - [Category of bialgebras over Rational Field, - Category of coalgebras with basis over Rational Field, + [Category of bialgebras with basis over Rational Field, Category of finite dimensional algebras with basis over Rational Field] sage: C is Bialgebras(QQ).WithBasis().FiniteDimensional() True diff --git a/src/sage/categories/graded_bialgebras_with_basis.py b/src/sage/categories/graded_bialgebras_with_basis.py index 171de5b99e7..8b9ff21acdf 100644 --- a/src/sage/categories/graded_bialgebras_with_basis.py +++ b/src/sage/categories/graded_bialgebras_with_basis.py @@ -18,8 +18,7 @@ def GradedBialgebrasWithBasis(base_ring): sage: C = GradedBialgebrasWithBasis(QQ); C Join of Category of ... sage: sorted(C.super_categories(), key=str) - [Category of bialgebras over Rational Field, - Category of coalgebras with basis over Rational Field, + [Category of bialgebras with basis over Rational Field, Category of graded algebras with basis over Rational Field] TESTS:: diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index 3a2f8a1dbd2..68dd66b3e64 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -27,8 +27,7 @@ class HopfAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): Category of hopf algebras with basis over Rational Field sage: C.super_categories() [Category of hopf algebras over Rational Field, - Category of algebras with basis over Rational Field, - Category of coalgebras with basis over Rational Field] + Category of bialgebras with basis over Rational Field] We now show how to use a simple Hopf algebra, namely the group algebra of the dihedral group (see also AlgebrasWithBasis):: From 6b0151cc5fad704e614799092273ffe58304fee4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 17:17:20 +0200 Subject: [PATCH 0521/1872] pushout: correct str/repr (switch to be constistent with remaining Sage) --- src/sage/categories/pushout.py | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index fbc429c1dff..9d3b060a5e9 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -199,7 +199,7 @@ def __cmp__(self, other): """ return cmp(type(self), type(other)) - def __str__(self): + def _repr_(self): """ NOTE: @@ -220,25 +220,6 @@ def __str__(self): import re return re.sub("<.*'.*\.([^.]*)'>", "\\1", s) - def _repr_(self): - """ - NOTE: - - By default, it returns the name of the construction functor's class. - Usually, this method will be overloaded. - - TEST:: - - sage: F = QQ.construction()[0] - sage: F # indirect doctest - FractionField - sage: Q = ZZ.quo(2).construction()[0] - sage: Q # indirect doctest - QuotientFunctor - - """ - return str(self) - def merge(self, other): """ Merge ``self`` with another construction functor, or return None. From 584a2ccbe9a519ce772003789aa21b45932bd676 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 17:20:14 +0200 Subject: [PATCH 0522/1872] move parsing of growth group factory expression to separate function --- src/sage/rings/asymptotic/growth_group.py | 101 +++++++++++++--------- 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ad4828fc564..2d5c325a87f 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -204,6 +204,67 @@ def parent_to_repr_short(P): return rep +def split_str_by_mul(string): + r""" + Split the given string into a tuple of substrings arising by + splitting by '*' and taking care of parentheses. + + INPUT: + + - ``string`` - a string. + + OUTPUT: + + A tuple of strings. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import split_str_by_mul + sage: split_str_by_mul('x^ZZ') + ('x^ZZ',) + sage: split_str_by_mul('log(x)^ZZ * y^QQ') + ('log(x)^ZZ', 'y^QQ') + sage: split_str_by_mul('log(x)**ZZ * y**QQ') + ('log(x)**ZZ', 'y**QQ') + sage: split_str_by_mul('a^b * * c^d') + Traceback (most recent call last): + ... + ValueError: 'a^b * * c^d' is invalid since a '*' follows a '*' + sage: split_str_by_mul('a^b * (c*d^e)') + ('a^b', 'c*d^e') + """ + factors = list() + balanced = True + if string and string[0] == '*': + raise ValueError("'%s' is invalid since it starts with a '*'." % + (string,)) + for s in string.split('*'): + if not s: + factors[-1] += '*' + balanced = False + continue + if not s.strip(): + raise ValueError("'%s' is invalid since a '*' follows a '*'" % + (string,)) + if not balanced: + s = factors.pop() + '*' + s + balanced = s.count('(') == s.count(')') + factors.append(s) + + if not balanced: + raise ValueError("Parentheses in '%s' are not balanced" % (string,)) + + def strip(s): + s = s.strip() + if not s: + return s + if s[0] == '(' and s[-1] == ')': + s = s[1:-1] + return s.strip() + + return tuple(strip(f) for f in factors) + + class Variable(sage.structure.unique_representation.CachedRepresentation, sage.structure.sage_object.SageObject): r""" @@ -2590,50 +2651,12 @@ def create_key_and_extra_args(self, specification, **kwds): TESTS:: sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GrowthGroup.create_key_and_extra_args('x^ZZ') - (('x^ZZ',), {}) sage: agg.GrowthGroup.create_key_and_extra_args('asdf') Traceback (most recent call last): ... ValueError: 'asdf' is not a valid string describing a growth group. - sage: agg.GrowthGroup.create_key_and_extra_args('log(x)^ZZ * y^QQ') - (('log(x)^ZZ', 'y^QQ'), {}) - sage: agg.GrowthGroup.create_key_and_extra_args('log(x)**ZZ * y**QQ') - (('log(x)**ZZ', 'y**QQ'), {}) - sage: agg.GrowthGroup.create_key_and_extra_args('a^b * * c^d') - Traceback (most recent call last): - ... - ValueError: 'a^b * * c^d' is invalid since a '*' follows a '*' - sage: agg.GrowthGroup.create_key_and_extra_args('a^b * (c*d^e)') - (('a^b', 'c*d^e'), {}) """ - factors = list() - balanced = True - if specification and specification[0] == '*': - raise ValueError("'%s' is invalid since it starts with a '*'." % - (specification,)) - for s in specification.split('*'): - if not s: - factors[-1] += '*' - balanced = False - continue - if not s.strip(): - raise ValueError("'%s' is invalid since a '*' follows a '*'" % - (specification,)) - if not balanced: - s = factors.pop() + '*' + s - balanced = s.count('(') == s.count(')') - factors.append(s) - - def strip(s): - s = s.strip() - if not s: - return s - if s[0] == '(' and s[-1] == ')': - s = s[1:-1] - return s.strip() - - factors = tuple(strip(f) for f in factors) + factors = split_str_by_mul(specification) for f in factors: if '^' not in f and '**' not in f: From f4d419b9dfa8e38061cbaaf79dc948d6c3c1bfac Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 17:21:39 +0200 Subject: [PATCH 0523/1872] rewrite text for exception --- src/sage/rings/asymptotic/growth_group.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 2d5c325a87f..b4a382124c7 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1332,7 +1332,7 @@ def _element_constructor_(self, data, raw_element=None): sage: G_ZZ('blub') Traceback (most recent call last): ... - ValueError: Cannot convert blub. + ValueError: blub is not in Growth Group Generic(ZZ). sage: G_ZZ('x', raw_element=42) Traceback (most recent call last): ... @@ -1345,7 +1345,7 @@ def _element_constructor_(self, data, raw_element=None): sage: G_y(x) Traceback (most recent call last): ... - ValueError: Cannot convert x. + ValueError: x is not in Growth Group y^ZZ. """ if raw_element is None: if type(data) == self.element_class and data.parent() == self: @@ -1353,7 +1353,7 @@ def _element_constructor_(self, data, raw_element=None): elif isinstance(data, self.element_class): try: if self._var_ != data.parent()._var_: - raise ValueError('Cannot convert %s.' % (data,)) + raise ValueError('%s is not in %s.' % (data, self)) except AttributeError: pass raw_element = data._raw_element_ @@ -1362,7 +1362,7 @@ def _element_constructor_(self, data, raw_element=None): else: raw_element = self._convert_(data) if raw_element is None: - raise ValueError('Cannot convert %s.' % (data,)) + raise ValueError('%s is not in %s.' % (data, self)) elif type(data) != int or data != 0: raise ValueError('Input is ambigous: ' '%s as well as raw_element=%s ' @@ -2018,7 +2018,7 @@ def _convert_(self, data): sage: P(log(x)^2) # indirect doctest Traceback (most recent call last): ... - ValueError: Cannot convert log(x)^2. + ValueError: log(x)^2 is not in Growth Group x^ZZ. :: @@ -2035,7 +2035,7 @@ def _convert_(self, data): sage: P(x^12 + O(x^17)) Traceback (most recent call last): ... - ValueError: Cannot convert x^12 + O(x^17). + ValueError: x^12 + O(x^17) is not in Growth Group x^ZZ. :: @@ -2045,7 +2045,7 @@ def _convert_(self, data): sage: P(w^4242) # indirect doctest Traceback (most recent call last): ... - ValueError: Cannot convert w^4242. + ValueError: w^4242 is not in Growth Group x^ZZ. :: @@ -2055,7 +2055,7 @@ def _convert_(self, data): sage: P(w^7) # indirect doctest Traceback (most recent call last): ... - ValueError: Cannot convert w^7. + ValueError: w^7 is not in Growth Group x^ZZ. :: @@ -2506,7 +2506,7 @@ def _convert_(self, data): sage: P(0) # indirect doctest Traceback (most recent call last): ... - ValueError: Cannot convert 0. + ValueError: 0 is not in Growth Group ZZ^x. :: From ec865bc00845ee879de888d6ee87db7fd243201f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 18:04:32 +0200 Subject: [PATCH 0524/1872] more doctests --- src/sage/rings/asymptotic/growth_group.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index b4a382124c7..34676ab23f4 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -76,6 +76,8 @@ sage: G_xy.an_element() x * y sage: x = G_xy('x'); y = G_xy('y') + sage: x^2 + x^2 sage: elem = x^21 * y^21; elem^2 x^42 * y^42 @@ -1492,6 +1494,15 @@ def _pushout_(self, other): ... TypeError: no common canonical parent for objects with parents: 'Growth Group QQ^x' and 'Growth Group x^QQ' + sage: cm.common_parent(GrowthGroup('x^ZZ'), GrowthGroup('y^ZZ')) + Growth Group x^ZZ * y^ZZ + + :: + + sage: cm.record_exceptions() + sage: cm.common_parent(GrowthGroup('x^ZZ'), GrowthGroup('y^ZZ')) + Growth Group x^ZZ * y^ZZ + sage: sage.structure.element.coercion_traceback() """ if isinstance(other, GenericGrowthGroup): pass From 63007c224018098138bc6734c3ada39263abd876 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 18:07:00 +0200 Subject: [PATCH 0525/1872] cartesian_injection --- .../asymptotic/growth_group_cartesian.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index d224e17ea79..04f3e311516 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -503,6 +503,29 @@ def _convert_to_factor_(self, data): return factor(data) except (ValueError, TypeError): continue + def cartesian_injection(self, factor, element): + r""" + Injects the given element into this cartesian product at the given factor. + + INPUT: + + - ``factor`` -- a growth group (a factor of this cartesian product). + + - ``element`` -- an element of ``factor``. + + OUTPUT: + + An element of this cartesian product. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * y^QQ') + sage: G.cartesian_injection(G.cartesian_factors()[1], 'y^7') + y^7 + """ + return self(tuple((f.one() if f != factor else element) + for f in self.cartesian_factors())) def _coerce_map_from_(self, S): From 225e24012a895cdde9bd33892a1a7002e85cd7f1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 18:08:01 +0200 Subject: [PATCH 0526/1872] new element constructor for cartesian products --- .../asymptotic/growth_group_cartesian.py | 118 +++++++++++------- 1 file changed, 75 insertions(+), 43 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 04f3e311516..8e9e08fd49b 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -65,6 +65,13 @@ sage: E = GrowthGroup('ZZ^x * x^QQ') sage: cm.common_parent(A, E) Growth Group QQ^x * x^QQ + +:: + + sage: A.an_element() + (1/2)^x * x + sage: tuple(E.an_element()) + (1, x^(1/2)) """ #***************************************************************************** @@ -402,47 +409,60 @@ def _element_constructor_(self, data): sage: G_log(log(x)) log(x) + + :: + + sage: G(G.cartesian_factors()[0].gen()) + x + + :: + + sage: GrowthGroup('QQ^x * x^QQ')(['x^(1/2)']) + Traceback (most recent call last): + ... + ValueError: ('x^(1/2)',) should be of length 2 + sage: l = GrowthGroup('x^ZZ * log(x)^ZZ')(['x', 'log(x)']); l + x * log(x) + sage: type(l) + """ if data == 1: return self.one() - if data is None: + elif data is None: raise ValueError('%s cannot be converted.' % (data,)) - if isinstance(data, list): + elif type(data) == self.element_class and data.parent() == self: + return data + + elif isinstance(data, self.element_class): + return self.element_class(self, data) + + elif isinstance(data, (tuple, list, + sage.sets.cartesian_product.CartesianProduct.Element)): try: - obj = super(GenericProduct, - self)._element_constructor_(data) - return obj + return super(GenericProduct, self)._element_constructor_(data) except ValueError: - return self.prod(self(elem) for elem in data) + raise + + elif isinstance(data, str): + from growth_group import split_str_by_mul + return self._convert_factors_(split_str_by_mul(data)) - if hasattr(data, 'parent'): + elif hasattr(data, 'parent'): P = data.parent() + if P is self: return data elif P is sage.symbolic.ring.SR: - import operator from sage.symbolic.operators import mul_vararg - op = data.operator() - if op == operator.pow or data.is_symbol() \ - or isinstance(op, sage.functions.log.Function_log): - return self(self._convert_to_factor_(data)) - elif op == mul_vararg: - return self(data.operands()) - # room for other parents (e.g. polynomial ring et al.) + if data.operator() == mul_vararg: + return self._convert_factors_(data.operands()) - # try to convert the input to one of the factors - data_conv = self._convert_to_factor_(data) - if data_conv is not None: - factors = self.cartesian_factors() - return self([data_conv if factor == data_conv.parent() else 1 for - factor in factors]) + # room for other parents (e.g. polynomial ring et al.) - # final attempt: try parsing the representation string - str_lst = str(data).replace(' ', '').split('*') - return self(str_lst) + return self._convert_factors_((data,)) _repr_ = GenericGrowthGroup._repr_ @@ -472,37 +492,42 @@ def _repr_short_(self): return ' * '.join(S._repr_short_() for S in self.cartesian_factors()) - def _convert_to_factor_(self, data): + def _convert_factors_(self, factors): r""" - Helper method. Try to convert some input ``data`` to an - element of one of the cartesian factors of this product. + Helper method. Try to convert some ``factors`` to an + element of one of the cartesian factors and returns the product of + all these factors. INPUT: - - ``data`` -- some input to be converted. + - ``factors`` -- a tuple or other iterable. OUTPUT: - An element of an cartesian factor of this product, - or ``None``. + An element of this cartesian product. EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ * log(x)^QQ * y^QQ') - sage: e1 = G._convert_to_factor_(x^2) + sage: e1 = G._convert_factors_([x^2]) sage: (e1, e1.parent()) - (x^2, Growth Group x^ZZ * log(x)^QQ) - sage: G._convert_to_factor_('asdf') is None - True + (x^2, Growth Group x^ZZ * log(x)^QQ * y^QQ) """ - for factor in self.cartesian_factors(): - try: - if hasattr(factor, '_convert_to_factor_'): - return factor(factor._convert_to_factor_(data)) - return factor(data) - except (ValueError, TypeError): - continue + from sage.misc.misc_c import prod + + def get_factor(data): + for factor in self.cartesian_factors(): + try: + return factor, factor(data) + except (ValueError, TypeError): + pass + raise ValueError('%s is not in %s' % (data, self)) + + return prod(list(self.cartesian_injection(*get_factor(f)) + for f in factors)) + + def cartesian_injection(self, factor, element): r""" Injects the given element into this cartesian product at the given factor. @@ -756,9 +781,15 @@ def gens_monomial(self): sage: G = agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ') sage: G.gens_monomial() (x, y) + + TESTS:: + + sage: all(g.parent() == G for g in G.gens_monomial()) + True """ - return sum(iter(factor.gens_monomial() - for factor in self.cartesian_factors()), + return sum(iter( + tuple(self.cartesian_injection(factor, g) for g in factor.gens_monomial()) + for factor in self.cartesian_factors()), tuple()) @@ -784,6 +815,7 @@ def variable_names(self): class Element(CartesianProductPosets.Element): + def _repr_(self): r""" A representation string for this cartesian product element. From 296f432edc11311691e20fe5efcadcd5ce0d7db4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:33:58 +0200 Subject: [PATCH 0527/1872] combine_exceptions function --- src/sage/rings/asymptotic/growth_group.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 34676ab23f4..11e044906c4 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -267,6 +267,23 @@ def strip(s): return tuple(strip(f) for f in factors) +def combine_exceptions(e, f): + r""" + Helper function which combines the messages of the two given exceptions. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import combine_exceptions + sage: raise combine_exceptions(ValueError('Outer.'), TypeError('Inner.')) + Traceback (most recent call last): + ... + ValueError: Outer. + previous: TypeError: Inner. + """ + e.args = ("%s\nprevious: %s: %s" % (e.args[0], f.__class__.__name__, str(f)),) + return e + + class Variable(sage.structure.unique_representation.CachedRepresentation, sage.structure.sage_object.SageObject): r""" From 68988a8cb9afd52b57aad02e36d989c313276c58 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:34:33 +0200 Subject: [PATCH 0528/1872] fix a bug in element_constructor and rewrite it --- .../asymptotic/growth_group_cartesian.py | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 8e9e08fd49b..fcece0707b2 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -86,7 +86,7 @@ #***************************************************************************** import sage - +from growth_group import combine_exceptions def merge_overlapping(A, B, key=None): r""" @@ -418,14 +418,31 @@ def _element_constructor_(self, data): :: sage: GrowthGroup('QQ^x * x^QQ')(['x^(1/2)']) - Traceback (most recent call last): - ... - ValueError: ('x^(1/2)',) should be of length 2 + x^(1/2) sage: l = GrowthGroup('x^ZZ * log(x)^ZZ')(['x', 'log(x)']); l x * log(x) sage: type(l) + sage: GrowthGroup('QQ^x * x^QQ')(['2^log(x)']) + Traceback (most recent call last): + ... + ValueError: ['2^log(x)'] is not in Growth Group QQ^x * x^QQ. + previous: ValueError: 2^log(x) is not in any of the factors of + Growth Group QQ^x * x^QQ + sage: GrowthGroup('QQ^x * x^QQ')(['2^log(x)', 'x^55']) + Traceback (most recent call last): + ... + ValueError: ['2^log(x)', 'x^55'] is not in Growth Group QQ^x * x^QQ. + previous: ValueError: 2^log(x) is not in any of the factors of + Growth Group QQ^x * x^QQ """ + def convert_factors(data, raw_data): + try: + return self._convert_factors_(data) + except ValueError as e: + raise combine_exceptions( + ValueError('%s is not in %s.' % (raw_data, self)), e) + if data == 1: return self.one() @@ -443,11 +460,13 @@ def _element_constructor_(self, data): try: return super(GenericProduct, self)._element_constructor_(data) except ValueError: - raise + pass + + return convert_factors(data, data) elif isinstance(data, str): from growth_group import split_str_by_mul - return self._convert_factors_(split_str_by_mul(data)) + return convert_factors(split_str_by_mul(data), data) elif hasattr(data, 'parent'): P = data.parent() @@ -458,11 +477,11 @@ def _element_constructor_(self, data): elif P is sage.symbolic.ring.SR: from sage.symbolic.operators import mul_vararg if data.operator() == mul_vararg: - return self._convert_factors_(data.operands()) + return convert_factors(data.operands(), data) # room for other parents (e.g. polynomial ring et al.) - return self._convert_factors_((data,)) + return convert_factors((data,), data) _repr_ = GenericGrowthGroup._repr_ @@ -522,7 +541,7 @@ def get_factor(data): return factor, factor(data) except (ValueError, TypeError): pass - raise ValueError('%s is not in %s' % (data, self)) + raise ValueError('%s is not in any of the factors of %s' % (data, self)) return prod(list(self.cartesian_injection(*get_factor(f)) for f in factors)) From 7cd601817818edaa80ac05d71d71cbec128b495f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:38:22 +0200 Subject: [PATCH 0529/1872] rewrite repr of term --- src/sage/rings/asymptotic/term_monoid.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index ed96b2361cd..3e6e2dac1fe 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1748,15 +1748,16 @@ def _repr_(self): sage: ET(x^0, 42) 42 """ - if self.growth._raw_element_ == 0: - return '%s' % self.coefficient + g = repr(self.growth) + c = repr(self.coefficient) + if g == '1': + return c + elif c == '1': + return '%s' % (g,) + elif c == '-1': + return '-%s' % (g,) else: - if self.coefficient == 1: - return '%s' % self.growth - elif self.coefficient == -1: - return '-%s' % self.growth - else: - return '%s*%s' % (self.coefficient, self.growth) + return '%s*%s' % (c, g) def _can_absorb_(self, other): From 1b73481e613994499992aeb15814f3aa2b5684f8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:39:37 +0200 Subject: [PATCH 0530/1872] correct a bug in term constructor --- src/sage/rings/asymptotic/term_monoid.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 3e6e2dac1fe..01bf03aada9 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -194,14 +194,11 @@ def __init__(self, parent, growth): if parent is None: raise ValueError('The parent must be provided') - if growth is None or not isinstance(growth, GenericGrowthElement): - raise ValueError('The growth must be provided and must inherit ' - 'from GenericGrowthElement') - elif growth not in parent.growth_group: - raise ValueError("%s is not in the parent's " - "specified growth group" % growth) - - self.growth = growth + try: + self.growth = parent.growth_group(growth) + except ValueError, TypeError: + raise ValueError("%s is not in %s" % (growth, self.growth_group)) + super(GenericTerm, self).__init__(parent=parent) @@ -1553,7 +1550,10 @@ def _element_constructor_(self, data, coefficient=None): try: if coefficient is not None: data = self.growth_group(data) - return self.element_class(self, data, coefficient) + try: + return self.element_class(self, data, coefficient) + except: + raise else: P = data.parent() from sage.symbolic.ring import SR From 1cd896bf321ed574dcd6d533bec976d69052899a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:40:21 +0200 Subject: [PATCH 0531/1872] extend has coercion --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index acc42983787..18ef6e7ee95 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1019,6 +1019,8 @@ def _coerce_map_from_(self, R): """ if self.coefficient_ring.has_coerce_map_from(R): return True + if self.growth_group.has_coerce_map_from(R): + return True elif isinstance(R, AsymptoticRing): if self.growth_group.has_coerce_map_from(R.growth_group) and \ self.coefficient_ring.has_coerce_map_from(R.coefficient_ring): From 287c0ae51c831b208f10158de864e73ebc39e051 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:40:56 +0200 Subject: [PATCH 0532/1872] make asymptotic ring a poset (Part I) --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 18ef6e7ee95..564823823cf 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -820,7 +820,7 @@ def __init__(self, growth_group, coefficient_ring, category=None): raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) if category is None: - category = Rings() + category = Rings() & sage.categories.posets.Posets() else: if not isinstance(category, tuple): category = (category,) From 3030d88f4489797037d2befd59366292b064cf9b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:41:12 +0200 Subject: [PATCH 0533/1872] variable_names --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 564823823cf..d982c50d243 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1168,3 +1168,9 @@ def create_summand(self, type, growth, **kwds): return self(kwds['coefficient']) return self(TM(growth, **kwds)) + + + def variable_names(self): + return self.growth_group.variable_names() + + From 74f2db0d5b4a3a2574eccb6373a05b00e001644b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:41:47 +0200 Subject: [PATCH 0534/1872] more cleanup and using generalizing methods for cartesian product --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d982c50d243..830b73a0b96 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1078,10 +1078,14 @@ def gens(self): sage: AR. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR.gens() (x,) + sage: B. = AsymptoticRing(growth_group='y^ZZ * z^ZZ', coefficient_ring=QQ) + sage: B.gens() + (y, z) """ - from sage.rings.asymptotic.growth_group import MonomialGrowthGroup - if isinstance(self.growth_group, MonomialGrowthGroup): - return self.create_summand('exact', growth=self.growth_group.gen(), coefficient=1), + return tuple(self.create_summand('exact', + growth=g, + coefficient=self.coefficient_ring(1)) + for g in self.growth_group.gens_monomial()) def gen(self, n=0): @@ -1123,11 +1127,7 @@ def ngens(self): sage: AR.ngens() 1 """ - from sage.rings.asymptotic.growth_group import MonomialGrowthGroup - if isinstance(self.growth_group, MonomialGrowthGroup): - return 1 - else: - return 0 + return len(self.growth_group.gens_monomial()) def create_summand(self, type, growth, **kwds): From a23d36e27626c71270bc645aee281fa061fb5a65 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 24 Aug 2015 19:42:18 +0200 Subject: [PATCH 0535/1872] construction and functor and doctests --- src/sage/rings/asymptotic/asymptotic_ring.py | 70 ++++++++++++++++++-- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 830b73a0b96..549a0176610 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -60,19 +60,19 @@ TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ') 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/17601 for details. - sage: T = atm.ExactTermMonoid(G, ZZ) + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('exact', G, ZZ) 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/17601 for details. - sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) + sage: R. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) .. _asymptotic_ring_intro: @@ -1174,3 +1174,63 @@ def variable_names(self): return self.growth_group.variable_names() + def construction(self): + return AsymptoticRingFunctor(self.growth_group), self.coefficient_ring + + +from sage.categories.pushout import ConstructionFunctor +from growth_group import Variable +class AsymptoticRingFunctor(ConstructionFunctor): + r""" + + TESTS:: + + sage: X = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ) + sage: Y = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ) + sage: cm = sage.structure.element.get_coercion_model() + sage: cm.record_exceptions() + sage: cm.common_parent(X, Y) + Asymptotic Ring over Rational Field + sage: sage.structure.element.coercion_traceback() + """ + rank = 13 + + def __init__(self, growth_group): + self.growth_group = growth_group + super(ConstructionFunctor, self).__init__( + sage.categories.rings.Rings(), + sage.categories.rings.Rings() & sage.categories.posets.Posets()) + + + def _repr_(self): + return 'AsymptoticRing<%s>' % (self.growth_group._repr_(condense=True),) + + + def _apply_functor(self, coefficients): + return AsymptoticRing(growth_group=self.growth_group, + coefficient_ring=coefficients) + + + def merge(self, other): + if self == other: + return self + + if isinstance(other, AsymptoticRingFunctor): + cm = sage.structure.element.get_coercion_model() + try: + G = cm.common_parent(self.growth_group, other.growth_group) + except TypeError: + pass + else: + return AsymptoticRingFunctor(G) + + + def __eq__(self, other): + return type(self) == type(other) and \ + self.growth_group == other.growth_group and \ + self.var == other.var + + + def __ne__(self, other): + return not self.__eq__(other) + From fad78622358f6fe9bc5cbe8efffe6b893e5e3969 Mon Sep 17 00:00:00 2001 From: Rob Beezer Date: Mon, 24 Aug 2015 16:05:53 -0700 Subject: [PATCH 0536/1872] Trac 11968: improve documentation of random matrix construction --- src/sage/matrix/constructor.py | 41 +++++++++++++++++----------------- src/sage/matrix/matrix2.pyx | 30 ++++++++++++++----------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/sage/matrix/constructor.py b/src/sage/matrix/constructor.py index e9357bf611b..8635f40e526 100644 --- a/src/sage/matrix/constructor.py +++ b/src/sage/matrix/constructor.py @@ -1000,8 +1000,8 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds) the matrix will have. See examples below for possible additional arguments. - - ``randomize`` - randomize the elements of the matrix, possibly - controlling the density of non-zero entries. + - ``randomize`` - create a matrix of random elements from the + base ring, possibly controlling the density of non-zero entries. - ``echelon_form`` - creates a matrix in echelon form @@ -1043,15 +1043,12 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds) additional properties (i.e. when ``algorithm='randomize'``), most of the randomness is controlled by the ``random_element`` method for elements of the base ring of the matrix, so the - documentation of that method may be relevant or useful. Also, - the default is to not create zero entries, unless the - ``density`` keyword is set to something strictly less than - one. + documentation of that method may be relevant or useful. EXAMPLES: Random integer matrices. With no arguments, the majority of the entries - are -1 and 1, never zero, and rarely "large." :: + are zero, -1, and 1, and rarely "large." :: sage: random_matrix(ZZ, 5, 5) [ -8 2 0 0 1] @@ -1061,7 +1058,7 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds) [ 4 -4 -6 5 0] The ``distribution`` keyword set to ``uniform`` will limit values - between -2 and 2, and never zero. :: + between -2 and 2. :: sage: random_matrix(ZZ, 5, 5, distribution='uniform') [ 1 0 -2 1 1] @@ -1071,8 +1068,8 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds) [ 0 -2 -1 0 0] The ``x`` and ``y`` keywords can be used to distribute entries uniformly. - When both are used ``x`` is the minimum and ``y`` is one greater than the the maximum. - But still entries are never zero, even if the range contains zero. :: + When both are used ``x`` is the minimum and ``y`` is one greater than + the maximum. :: sage: random_matrix(ZZ, 4, 8, x=70, y=100) [81 82 70 81 78 71 79 94] @@ -1085,7 +1082,8 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds) [ 3 3 0 3 -5 -2 1] [ 0 -2 -2 2 -3 -4 -2] - If only ``x`` is given, then it is used as the upper bound of a range starting at 0. :: + If only ``x`` is given, then it is used as the upper bound of a range + starting at 0. :: sage: random_matrix(ZZ, 5, 5, x=25) [20 16 8 3 8] @@ -1094,10 +1092,12 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds) [19 16 17 15 7] [ 0 24 3 17 24] - To allow, and control, zero entries use the ``density`` keyword at a value - strictly below the default of 1.0, even if distributing entries across an - interval that does not contain zero already. Note that for a square matrix it - is only necessary to set a single dimension. :: + To control the number of nonzero entries, use the ``density`` keyword + at a value strictly below the default of 1.0. The ``density`` keyword + is used to compute the number of entries that will be nonzero, but the + same entry may be selected more than once. So the value provided will + be an upper bound for the density of the created matrix. Note that for + a square matrix it is only necessary to set a single dimension. :: sage: random_matrix(ZZ, 5, x=-10, y=10, density=0.75) [-6 1 0 0 0] @@ -1113,8 +1113,8 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds) [ 0 28 22 0 0] [ 0 0 0 26 24] - It is possible to construct sparse matrices, where it may now be advisable - (but not required) to control the density of nonzero entries. :: + For a matrix with low density it may be advisable to insist on a sparse + representation, as this representation is not selected automatically. :: sage: A=random_matrix(ZZ, 5, 5) sage: A.is_sparse() @@ -1140,10 +1140,9 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds) generation of random elements, by specifying limits on the absolute value of numerators and denominators (respectively). Entries will be positive and negative (map the absolute value function through the entries to get all - positive values), and zeros are avoided unless the density is set. If either - the numerator or denominator bound (or both) is not used, then the values - default to the distribution for `ZZ` described above that is most frequently - positive or negative one. :: + positive values). If either the numerator or denominator bound (or both) + is not used, then the values default to the distribution for ``ZZ`` + described above. :: sage: random_matrix(QQ, 2, 8, num_bound=20, den_bound=4) [ -1/2 6 13 -12 -2/3 -1/4 5 5] diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 50e162809b8..4f8ad1f39c1 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -7842,22 +7842,26 @@ cdef class Matrix(matrix1.Matrix): def randomize(self, density=1, nonzero=False, *args, **kwds): """ - Randomize density proportion of the entries of this matrix, leaving - the rest unchanged. + Replace a proportion of the entries of a matrix by random elements, + leaving the remaining entries unchanged. .. note:: - We actually choose at random ``density`` proportion of entries of - the matrix and set them to random elements. It's possible that the - same position can be chosen multiple times, especially for a very - small matrix. + The locations of the entries of the matrix to change are + determined randomly, with the total number of locations + determined by the ``density`` keyword. These locations + are not guaranteed to be distinct. So it is possible + that the same position can be chosen multiple times, + especially for a very small matrix. The exception is + when ``density = 1``, in which case every entry of the + matrix will be changed. INPUT: - - ``density`` - ``float`` (default: 1); rough measure of the - proportion of nonzero entries in the random matrix - - ``nonzero`` - Bool (default: ``False``); whether the new entries - have to be non-zero + - ``density`` - ``float`` (default: ``1``); upper bound for the + proportion of entries that are changed + - ``nonzero`` - Bool (default: ``False``); if ``True``, then new + entries will be nonzero - ``*args, **kwds`` - Remaining parameters may be passed to the ``random_element`` function of the base ring @@ -7894,9 +7898,9 @@ cdef class Matrix(matrix1.Matrix): [0 0] [0 0] - Then we randomize it; the x and y parameters, which determine the - size of the random elements, are passed onto the ZZ random_element - method. + Then we randomize it; the ``x`` and ``y`` keywords, which determine the + size of the random elements, are passed on to the ``random_element`` + method for ``ZZ``. :: From 2adcfeffa5d87f137ee9010fb69087a2b76e98a7 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Mon, 24 Aug 2015 21:19:44 -0500 Subject: [PATCH 0537/1872] oops! Didn't completely merge --- src/sage/combinat/diagram_algebras.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index aa9c2e380ca..d8a013347c3 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -34,7 +34,6 @@ from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.combinat.permutation import Permutations from sage.combinat.combinat import (bell_number, catalan_number) ->>>>>>> t/18720/change_diagram_algebra_basis_set_partitions_from_list_to_generator from sage.sets.set import Set from sage.graphs.graph import Graph from sage.misc.cachefunc import cached_method From 27601babfdee8690174b47275edcf430b2f634ce Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 08:46:20 +0200 Subject: [PATCH 0538/1872] fix missing docs --- src/sage/rings/asymptotic/growth_group.py | 180 ++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 11e044906c4..f2082090e61 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1687,11 +1687,36 @@ def variable_names(self): from sage.categories.pushout import ConstructionFunctor class AbstractGrowthGroupFunctor(ConstructionFunctor): r""" + A base class for the functors constructing growth groups. + + INPUT: + + - ``var`` -- a string or list of strings (or anything else + :class:`Variable` accepts). + + - ``domain`` -- a category. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('z^QQ').construction()[0] # indirect doctest + MonomialGrowthGroup[z] """ + _functor_name = 'AbstractGrowthGroup' + rank = 13 def __init__(self, var, domain): + r""" + See :class:`AbstractGrowthGroupFunctor` for details. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import AbstractGrowthGroupFunctor + sage: AbstractGrowthGroupFunctor('x', Groups()) + AbstractGrowthGroup[x] + """ if var is None: var = Variable('') elif not isinstance(var, Variable): @@ -1702,19 +1727,95 @@ def __init__(self, var, domain): def _repr_(self): + r""" + Return a representation string of this functor. + + OUTPUT: + + A string. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('QQ^t').construction()[0] # indirect doctest + ExponentialGrowthGroup[t] + """ return '%s[%s]' % (self._functor_name, self.var) def merge(self, other): + r""" + Merge this functor with ``other`` of possible. + + INPUT: + + - ``other`` -- a functor. + + OUTPUT: + + A functor or ``None``. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: F = GrowthGroup('QQ^t').construction()[0] + sage: G = GrowthGroup('t^QQ').construction()[0] + sage: F.merge(F) + ExponentialGrowthGroup[t] + sage: F.merge(G) is None + True + """ if self == other: return self def __eq__(self, other): + r""" + Return if this functor is equal to ``other``. + + INPUT: + + - ``other`` -- a functor. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: F = GrowthGroup('QQ^t').construction()[0] + sage: G = GrowthGroup('t^QQ').construction()[0] + sage: F == F + True + sage: F == G + False + """ return type(self) == type(other) and self.var == other.var def __ne__(self, other): + r""" + Return if this functor is not equal to ``other``. + + INPUT: + + - ``other`` -- a functor. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: F = GrowthGroup('QQ^t').construction()[0] + sage: G = GrowthGroup('t^QQ').construction()[0] + sage: F != F + False + sage: F != G + True + """ return not self.__eq__(other) @@ -2188,6 +2289,18 @@ def construction(self): class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" + A construction functor for :class:`monomial growth groups `. + + INPUT: + + - ``var`` -- a string or list of strings (or anything else + :class:`Variable` accepts). + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup, MonomialGrowthGroupFunctor + sage: GrowthGroup('z^QQ').construction()[0] + MonomialGrowthGroup[z] TESTS:: @@ -2203,11 +2316,38 @@ class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): def __init__(self, var): + r""" + See :class:`MonomialGrowthGroupFunctor` for details. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroupFunctor + sage: MonomialGrowthGroupFunctor('x') + MonomialGrowthGroup[x] + """ super(MonomialGrowthGroupFunctor, self).__init__(var, sage.categories.commutative_additive_monoids.CommutativeAdditiveMonoids()) def _apply_functor(self, base): + r""" + Apply this functor to the given ``base``. + + INPUT: + + - ``base`` - anything :class:`MonomialGrowthGroup` accepts. + + OUTPUT: + + A monomial growth group. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: F, R = GrowthGroup('z^QQ').construction() + sage: F(R) # indirect doctest + Growth Group z^QQ + """ return MonomialGrowthGroup(base, self.var) @@ -2616,6 +2756,19 @@ def construction(self): class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" + A construction functor for + :class:`exponential growth groups `. + + INPUT: + + - ``var`` -- a string or list of strings (or anything else + :class:`Variable` accepts). + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup, ExponentialGrowthGroupFunctor + sage: GrowthGroup('QQ^z').construction()[0] + ExponentialGrowthGroup[z] TESTS:: @@ -2631,11 +2784,38 @@ class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): def __init__(self, var): + r""" + See :class:`ExponentialGrowthGroupFunctor` for details. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroupFunctor + sage: ExponentialGrowthGroupFunctor('x') + ExponentialGrowthGroup[x] + """ super(ExponentialGrowthGroupFunctor, self).__init__(var, sage.categories.monoids.Monoids()) def _apply_functor(self, base): + r""" + Apply this functor to the given ``base``. + + INPUT: + + - ``base`` - anything :class:`ExponentialGrowthGroup` accepts. + + OUTPUT: + + An exponential growth group. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: F, R = GrowthGroup('QQ^z').construction() + sage: F(R) # indirect doctest + Growth Group QQ^z + """ return ExponentialGrowthGroup(base, self.var) From e1acc40f64dd67d21b4ead41df2dc592b4173b31 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 09:37:25 +0200 Subject: [PATCH 0539/1872] improve docs (seealso, links, etc) --- src/sage/rings/asymptotic/growth_group.py | 49 +++++++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index f2082090e61..60807e6955e 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1519,7 +1519,7 @@ def _pushout_(self, other): sage: cm.record_exceptions() sage: cm.common_parent(GrowthGroup('x^ZZ'), GrowthGroup('y^ZZ')) Growth Group x^ZZ * y^ZZ - sage: sage.structure.element.coercion_traceback() + sage: sage.structure.element.coercion_traceback() # not tested """ if isinstance(other, GenericGrowthGroup): pass @@ -1701,6 +1701,14 @@ class AbstractGrowthGroupFunctor(ConstructionFunctor): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: GrowthGroup('z^QQ').construction()[0] # indirect doctest MonomialGrowthGroup[z] + + .. SEEALSO:: + + :mod:`sage.rings.asymptotic.asymptotic_ring`, + :class:`ExponentialGrowthGroupFunctor`, + :class:`MonomialGrowthGroupFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.categories.pushout.ConstructionFunctor`. """ _functor_name = 'AbstractGrowthGroup' @@ -2278,18 +2286,27 @@ def gens_monomial(self): def construction(self): r""" + Return the construction of this growth group. + + OUTPUT: + + A pair whose first entry is a + :class:`monomial construction functor ` + and its second entry the base. + EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: GrowthGroup('x^ZZ').construction() (MonomialGrowthGroup[x], Integer Ring) - """ + """ return MonomialGrowthGroupFunctor(self._var_), self.base() class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" - A construction functor for :class:`monomial growth groups `. + A :class:`construction functor ` + for :class:`monomial growth groups `. INPUT: @@ -2302,6 +2319,14 @@ class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): sage: GrowthGroup('z^QQ').construction()[0] MonomialGrowthGroup[z] + .. SEEALSO:: + + :mod:`sage.rings.asymptotic.asymptotic_ring`, + :class:`AbstractGrowthGroupFunctor`, + :class:`ExponentialGrowthGroupFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.categories.pushout.ConstructionFunctor`. + TESTS:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup, MonomialGrowthGroupFunctor @@ -2745,6 +2770,14 @@ def gens(self): def construction(self): r""" + Return the construction of this growth group. + + OUTPUT: + + A pair whose first entry is an + :class:`exponential construction functor ` + and its second entry the base. + EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup @@ -2756,7 +2789,7 @@ def construction(self): class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" - A construction functor for + A :class:`construction functor ` :class:`exponential growth groups `. INPUT: @@ -2770,6 +2803,14 @@ class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): sage: GrowthGroup('QQ^z').construction()[0] ExponentialGrowthGroup[z] + .. SEEALSO:: + + :mod:`sage.rings.asymptotic.asymptotic_ring`, + :class:`AbstractGrowthGroupFunctor`, + :class:`MonomialGrowthGroupFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.categories.pushout.ConstructionFunctor`. + TESTS:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup, ExponentialGrowthGroupFunctor From 98e8860dcddd159b4489fda2b7f657d1bae60a11 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 09:38:08 +0200 Subject: [PATCH 0540/1872] make doctest coverage 100% (asymptotic_ring) --- src/sage/rings/asymptotic/asymptotic_ring.py | 178 ++++++++++++++++++- 1 file changed, 173 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 549a0176610..fb57930a05a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -73,6 +73,10 @@ without a formal deprecation. See http://trac.sagemath.org/17601 for details. sage: R. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + 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/17601 for details. .. _asymptotic_ring_intro: @@ -1171,10 +1175,45 @@ def create_summand(self, type, growth, **kwds): def variable_names(self): + r""" + Return the names of the variables. + + OUTPUT: + + A tuple of strings. + + EXAMPLES:: + + sage: A = AsymptoticRing(growth_group='x^ZZ * QQ^y', coefficient_ring=QQ) + sage: A.variable_names() + ('x', 'y') + """ return self.growth_group.variable_names() def construction(self): + r""" + Return the construction of this asymptotic ring. + + OUTPUT: + + A pair whose first entry is an + :class:`asymptotic ring construction functor ` + and its second entry the coefficient ring. + + EXAMPLES:: + + sage: A = AsymptoticRing(growth_group='x^ZZ * QQ^y', coefficient_ring=QQ) + sage: A.construction() + (AsymptoticRing, Rational Field) + + .. SEEALSO:: + + :mod:`sage.rings.asymptotic.asymptotic_ring`, + :class:`AsymptoticRing`, + :class:`AsymptoticRingFunctor`. + """ + return AsymptoticRingFunctor(self.growth_group), self.coefficient_ring @@ -1182,6 +1221,28 @@ def construction(self): from growth_group import Variable class AsymptoticRingFunctor(ConstructionFunctor): r""" + A :class:`construction functor ` + for :class:`asymptotic rings `. + + INPUT: + + - ``growth_group`` -- a partially ordered group (see + :class:`AsymptoticRing` or + mod:`~sage.rings.asymptotic.growth_group` for details). + + EXAMPLES:: + + sage: AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ).construction() # indirect doctest + (AsymptoticRing, Rational Field) + + .. SEEALSO:: + + :mod:`sage.rings.asymptotic.asymptotic_ring`, + :class:`AsymptoticRing`, + :class:`sage.rings.asymptotic.growth_group.AbstractGrowthGroupFunctor`, + :class:`sage.rings.asymptotic.growth_group.ExponentialGrowthGroupFunctor`, + :class:`sage.rings.asymptotic.growth_group.MonomialGrowthGroupFunctor`, + :class:`sage.categories.pushout.ConstructionFunctor`. TESTS:: @@ -1191,11 +1252,23 @@ class AsymptoticRingFunctor(ConstructionFunctor): sage: cm.record_exceptions() sage: cm.common_parent(X, Y) Asymptotic Ring over Rational Field - sage: sage.structure.element.coercion_traceback() + sage: sage.structure.element.coercion_traceback() # not tested """ + rank = 13 + def __init__(self, growth_group): + r""" + See :class:`AsymptoticRingFunctor` for details. + + TESTS:: + + sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticRingFunctor + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: AsymptoticRingFunctor(GrowthGroup('x^ZZ')) + AsymptoticRing + """ self.growth_group = growth_group super(ConstructionFunctor, self).__init__( sage.categories.rings.Rings(), @@ -1203,15 +1276,67 @@ def __init__(self, growth_group): def _repr_(self): + r""" + Return a representation string of this functor. + + OUTPUT: + + A string. + + TESTS:: + + sage: AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ).construction()[0] # indirect doctest + AsymptoticRing + """ return 'AsymptoticRing<%s>' % (self.growth_group._repr_(condense=True),) - def _apply_functor(self, coefficients): + def _apply_functor(self, coefficient_ring): + r""" + Apply this functor to the given ``coefficient_ring``. + + INPUT: + + - ``base`` - anything :class:`MonomialGrowthGroup` accepts. + + OUTPUT: + + An :class:`AsymptoticRing`. + + EXAMPLES:: + + sage: A = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ) + sage: F, C = A.construction() + sage: F(C) # indirect doctest + Asymptotic Ring over Rational Field + """ return AsymptoticRing(growth_group=self.growth_group, - coefficient_ring=coefficients) + coefficient_ring=coefficient_ring) def merge(self, other): + r""" + Merge this functor with ``other`` of possible. + + INPUT: + + - ``other`` -- a functor. + + OUTPUT: + + A functor or ``None``. + + EXAMPLES:: + + sage: X = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ) + sage: Y = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ) + sage: F_X = X.construction()[0] + sage: F_Y = Y.construction()[0] + sage: F_X.merge(F_X) + AsymptoticRing + sage: F_X.merge(F_Y) + AsymptoticRing + """ if self == other: return self @@ -1226,11 +1351,54 @@ def merge(self, other): def __eq__(self, other): + r""" + Return if this functor is equal to ``other``. + + INPUT: + + - ``other`` -- a functor. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: X = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ) + sage: Y = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ) + sage: F_X = X.construction()[0] + sage: F_Y = Y.construction()[0] + sage: F_X == F_X + True + sage: F_X == F_Y + False + """ return type(self) == type(other) and \ - self.growth_group == other.growth_group and \ - self.var == other.var + self.growth_group == other.growth_group def __ne__(self, other): + r""" + Return if this functor is not equal to ``other``. + + INPUT: + + - ``other`` -- a functor. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: X = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ) + sage: Y = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ) + sage: F_X = X.construction()[0] + sage: F_Y = Y.construction()[0] + sage: F_X != F_X + False + sage: F_X != F_Y + True + """ return not self.__eq__(other) From e9acd0ea452a0b410fb9804e68fc6c3e7cda5233 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 09:39:46 +0200 Subject: [PATCH 0541/1872] cleanup (remove a comment) --- src/sage/rings/asymptotic/growth_group_cartesian.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index fcece0707b2..e90dbb3618f 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -770,12 +770,6 @@ def next(self): return pushout(cartesian_product(newS), cartesian_product(newO)) - #C = other.construction()[0] - #if isinstance(C, PolynomialFunctor): - # return pushout(self, CartesianProductPolys((other,))) - - - def gens_monomial(self): r""" Return a tuple containing generators of this growth group. From 14318cc34e2b3aca452344e76255ca333292902a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 11:24:15 +0200 Subject: [PATCH 0542/1872] improve conversion repr_short to parents --- src/sage/rings/asymptotic/growth_group.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 8f9d21e10b3..17a9956d255 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -157,15 +157,14 @@ def repr_short_to_parent(s): Traceback (most recent call last): ... ValueError: Cannot create a parent out of 'abcdef'. + previous: NameError: name 'abcdef' is not defined """ - if s == 'ZZ': - return sage.rings.integer_ring.ZZ - elif s == 'QQ': - return sage.rings.rational_field.QQ - elif s == 'SR': - return sage.symbolic.ring.SR - else: - raise ValueError("Cannot create a parent out of '%s'." % s) + from sage.misc.sage_eval import sage_eval + try: + return sage_eval(s) + except Exception as e: + raise combine_exceptions( + ValueError("Cannot create a parent out of '%s'." % (s,)), e) def parent_to_repr_short(P): From 08a8cde6a7734c0a6ae5eb4fcf056c77e483aefa Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 12:56:44 +0200 Subject: [PATCH 0543/1872] check of repr_sort_to_parent creates a parent --- src/sage/rings/asymptotic/growth_group.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 17a9956d255..6563c374613 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -161,10 +161,14 @@ def repr_short_to_parent(s): """ from sage.misc.sage_eval import sage_eval try: - return sage_eval(s) + P = sage_eval(s) except Exception as e: raise combine_exceptions( ValueError("Cannot create a parent out of '%s'." % (s,)), e) + from sage.structure.parent import is_Parent + if not is_Parent(P): + raise ValueError("'%s' does not describe a parent." % (s,)) + return P def parent_to_repr_short(P): @@ -2963,7 +2967,6 @@ def create_object(self, version, factors, **kwds): ... ValueError: Cannot decode x^y^z. """ - groups = [] for factor in factors: b_and_e = factor.split('^') From c5df5543aec6ab4cade751aed9414ebea76a0fcf Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 14:10:11 +0200 Subject: [PATCH 0544/1872] extend combine_exceptions --- src/sage/rings/asymptotic/growth_group.py | 31 ++++++++++++++++--- .../asymptotic/growth_group_cartesian.py | 4 +-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6563c374613..1aa67b3c5bb 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -157,7 +157,7 @@ def repr_short_to_parent(s): Traceback (most recent call last): ... ValueError: Cannot create a parent out of 'abcdef'. - previous: NameError: name 'abcdef' is not defined + > *previous* NameError: name 'abcdef' is not defined """ from sage.misc.sage_eval import sage_eval try: @@ -270,9 +270,9 @@ def strip(s): return tuple(strip(f) for f in factors) -def combine_exceptions(e, f): +def combine_exceptions(e, *f): r""" - Helper function which combines the messages of the two given exceptions. + Helper function which combines the messages of the given exceptions. EXAMPLES:: @@ -281,9 +281,30 @@ def combine_exceptions(e, f): Traceback (most recent call last): ... ValueError: Outer. - previous: TypeError: Inner. + > *previous* TypeError: Inner. + sage: raise combine_exceptions(ValueError('Outer.'), + ....: TypeError('Inner1.'), TypeError('Inner2.')) + Traceback (most recent call last): + ... + ValueError: Outer. + > *previous* TypeError: Inner1. + > *and* TypeError: Inner2. + sage: raise combine_exceptions(ValueError('Outer.'), + ....: combine_exceptions(TypeError('Middle.'), + ....: TypeError('Inner.'))) + Traceback (most recent call last): + ... + ValueError: Outer. + > *previous* TypeError: Middle. + >> *previous* TypeError: Inner. """ - e.args = ("%s\nprevious: %s: %s" % (e.args[0], f.__class__.__name__, str(f)),) + import re + msg = ('\n *previous* ' + + '\n *and* '.join("%s: %s" % (ff.__class__.__name__, str(ff)) for ff in f)) + msg = re.sub(r'^([>]* \*previous\*)', r'>\1', msg, flags=re.MULTILINE) + msg = re.sub(r'^([>]* \*and\*)', r'>\1', msg, flags=re.MULTILINE) + msg = str(e.args if len(e.args) > 1 else e.args[0]) + msg + e.args = (msg,) return e diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index e90dbb3618f..53d3ea404c0 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -427,13 +427,13 @@ def _element_constructor_(self, data): Traceback (most recent call last): ... ValueError: ['2^log(x)'] is not in Growth Group QQ^x * x^QQ. - previous: ValueError: 2^log(x) is not in any of the factors of + > *previous* ValueError: 2^log(x) is not in any of the factors of Growth Group QQ^x * x^QQ sage: GrowthGroup('QQ^x * x^QQ')(['2^log(x)', 'x^55']) Traceback (most recent call last): ... ValueError: ['2^log(x)', 'x^55'] is not in Growth Group QQ^x * x^QQ. - previous: ValueError: 2^log(x) is not in any of the factors of + > *previous* ValueError: 2^log(x) is not in any of the factors of Growth Group QQ^x * x^QQ """ def convert_factors(data, raw_data): From 6263bcf560ab21eca49bfba01422d6e96f97fa4e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 14:16:17 +0200 Subject: [PATCH 0545/1872] extend parsing in growth group factory --- src/sage/rings/asymptotic/growth_group.py | 50 +++++++++++++---------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 1aa67b3c5bb..892feb6e306 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2963,6 +2963,7 @@ def create_key_and_extra_args(self, specification, **kwds): ValueError: 'asdf' is not a valid string describing a growth group. """ factors = split_str_by_mul(specification) + factors = tuple(f.replace('**', '^') for f in factors) for f in factors: if '^' not in f and '**' not in f: @@ -2983,36 +2984,43 @@ def create_object(self, version, factors, **kwds): Traceback (most recent call last): ... ValueError: 'as^df' is not a valid string describing a growth group. + > *previous* ValueError: Cannot create a parent out of 'as'. + >> *previous* SyntaxError: unexpected EOF while parsing (, line 1) + > *and* ValueError: Cannot create a parent out of 'df'. + >> *previous* NameError: name 'df' is not defined sage: agg.GrowthGroup('x^y^z') Traceback (most recent call last): ... - ValueError: Cannot decode x^y^z. + ValueError: 'x^y^z' is not a valid string describing a growth group. + > *previous* ValueError: Cannot create a parent out of 'x'. + >> *previous* NameError: name 'x' is not defined + > *and* ValueError: Cannot create a parent out of 'y^z'. + >> *previous* NameError: name 'y' is not defined """ groups = [] for factor in factors: - b_and_e = factor.split('^') - if len(b_and_e) != 2: - raise ValueError('Cannot decode %s.' % (factor,)) - (b, e) = b_and_e + b, _, e = factor.partition('^') try: - # monomial growth group: 'var^base' - groups.append( - MonomialGrowthGroup(repr_short_to_parent(e), b, **kwds)) - continue - except (TypeError, ValueError): - pass - + B = repr_short_to_parent(b) + except ValueError as exc_b: + B = None try: - # exponential growth group: 'base^var' - groups.append( - ExponentialGrowthGroup(repr_short_to_parent(b), e, **kwds)) - continue - except (TypeError, ValueError): - pass - - raise ValueError("'%s' is not a valid string describing " - "a growth group." % (factor,)) + E = repr_short_to_parent(e) + except ValueError as exc_e: + E = None + + if B is None and E is None: + raise combine_exceptions( + ValueError("'%s' is not a valid string describing " + "a growth group." % (factor,)), exc_b, exc_e) + elif B is None and E is not None: + groups.append(MonomialGrowthGroup(E, b, **kwds)) + elif B is not None and E is None: + groups.append(ExponentialGrowthGroup(B, e, **kwds)) + else: + raise ValueError("'%s' is an ambigous string of a growth group " + "description." % (factor,)) if len(groups) == 1: return groups[0] From 509c51662421f2a287cae501c7ed30f7d667f5e5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 14:49:28 +0200 Subject: [PATCH 0546/1872] correct some typos in docstring --- src/sage/rings/asymptotic/asymptotic_ring.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 40c6a524c6a..2bb179778e3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -41,7 +41,7 @@ - more sophisticated constructions like products `x^r log(x)^s \cdot a^y \cdot y^q` (this corresponds to an element of the growth group - ``x^QQ * \log(x)^ZZ * QQ^y * y^QQ``). + ``x^QQ * log(x)^ZZ * QQ^y * y^QQ``). The ordering in all these examples is the growth as `x`, `y`, or `z` (independently) tend to `\infty`. For elements only using the @@ -96,9 +96,9 @@ -z^(3/2) + O(z^(1/2)) This element consists of two summands: the exact term with coefficient -`-1` and growth `x^{3/2}` and the `O`-term `O(x^{1/2})`. Note that the -growth of `x^{3/2}` is larger than the growth of `x^{1/2}` as -`x\to\infty`, thus this expression cannot be simplified (which would +`-1` and growth `z^{3/2}` and the `O`-term `O(z^{1/2})`. Note that the +growth of `z^{3/2}` is larger than the growth of `z^{1/2}` as +`z\to\infty`, thus this expression cannot be simplified (which would be done automatically, see below). Next, we construct a more sophisticated asymptotic ring in the @@ -106,7 +106,7 @@ :: - sage: B. = AsymptoticRing(growth_group='x^QQ * \log(x)^ZZ * QQ^y * y^QQ', coefficient_ring=QQ); B # not tested + sage: B. = AsymptoticRing(growth_group='x^QQ * log(x)^ZZ * QQ^y * y^QQ', coefficient_ring=QQ); B # not tested Again, we can look at a typical element:: From 5e0e8aca24473ce4be8e80af78337270de4266e9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 15:32:28 +0200 Subject: [PATCH 0547/1872] handle __pow__ and __invert__ in growth group correctly --- src/sage/rings/asymptotic/growth_group.py | 57 ++++++----------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 28dd7f3883b..8a792abed45 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -274,61 +274,32 @@ def _mul_(self, other): raise NotImplementedError('Only implemented in concrete realizations.') - def _div_(self, other): + def __invert__(self): r""" - Divide this growth element by another one. - - INPUT: - - - ``other`` -- an instance of :class:`GenericGrowthElement`. + Return the inverse of this growth element. OUTPUT: An instance of :class:`GenericGrowthElement`. - .. NOTE:: - - This method is called by the coercion framework, thus, it can be - assumed that this element, as well as ``other`` are of the same - type. The output will have this type. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') - sage: e1 = P(raw_element=2) - sage: e2 = e1._div_(P.gen()); e2 - x - sage: e2 == e1 / P.gen() - True - """ - return self._mul_(~other) - - - def __pow__(self, power): - r""" - Takes this growth element to the given ``power``. - - INPUT: - - - ``power`` -- a number. This can anything that is valid to be - on the right hand side of ``*`` with an elements of the - parent's base. - - OUTPUT: - - The result of this exponentiation a :class:`MonomialGrowthElement`. - - EXAMPLES:: + TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ) + sage: ~G.an_element() + Traceback (most recent call last): + ... + NotImplementedError: Inversion of GenericGrowthElement(1) not implemented. sage: G.an_element()^7 Traceback (most recent call last): ... NotImplementedError: Only implemented in concrete realizations. + sage: P = GrowthGroup('x^ZZ') + sage: ~P.an_element() + 1/x """ - raise NotImplementedError('Only implemented in concrete realizations.') + raise NotImplementedError('Inversion of %s not implemented.' % (self,)) def __eq__(self, other): From 47badc1b7322077ffbf2f89ab6ad2acc2dce18b4 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Tue, 25 Aug 2015 16:10:54 +0200 Subject: [PATCH 0548/1872] Move fallback algorithm to category UFD --- .../unique_factorization_domains.py | 81 ++++++++++++++++ .../rings/polynomial/polynomial_element.pyx | 93 ++++--------------- 2 files changed, 97 insertions(+), 77 deletions(-) diff --git a/src/sage/categories/unique_factorization_domains.py b/src/sage/categories/unique_factorization_domains.py index 50c6fd107a4..ddedb674d3b 100644 --- a/src/sage/categories/unique_factorization_domains.py +++ b/src/sage/categories/unique_factorization_domains.py @@ -124,6 +124,87 @@ def is_unique_factorization_domain(self, proof=True): """ return True + def _gcd_univariate_polynomial(self, f, g): + """ + Return the greatest common divisor of ``f`` and ``g``. + + INPUT: + + - ``f``, ``g`` -- two polynomials defined over this UFD. + + .. NOTE:: + + This is a helper method for + :meth:`sage.rings.polynomial.polynomial_element.Polynomial.gcd`. + + ALGORITHM: + + Algorithm 3.3.1 in [GTM138]_, based on pseudo-division. + + EXAMPLES:: + + sage: R. = PolynomialRing(ZZ, sparse=True) + sage: S. = R[] + sage: p = (-3*x^2 - x)*T^3 - 3*x*T^2 + (x^2 - x)*T + 2*x^2 + 3*x - 2 + sage: q = (-x^2 - 4*x - 5)*T^2 + (6*x^2 + x + 1)*T + 2*x^2 - x + sage: quo,rem=p.pseudo_quo_rem(q); quo,rem + ((3*x^4 + 13*x^3 + 19*x^2 + 5*x)*T + 18*x^4 + 12*x^3 + 16*x^2 + 16*x, + (-113*x^6 - 106*x^5 - 133*x^4 - 101*x^3 - 42*x^2 - 41*x)*T - 34*x^6 + 13*x^5 + 54*x^4 + 126*x^3 + 134*x^2 - 5*x - 50) + sage: (-x^2 - 4*x - 5)^(3-2+1) * p == quo*q + rem + True + + REFERENCES: + + .. [GTM138] Henri Cohen. A Course in Computational Number Theory. + Graduate Texts in Mathematics, vol. 138. Springer, 1993. + """ + if f.degree() < g.degree(): + A,B = g, f + else: + A,B = f, g + + if B.is_zero(): + return A + + a = b = self.zero() + for c in A.coefficients(): + a = a.gcd(c) + if a.is_one(): + break + for c in B.coefficients(): + b = b.gcd(c) + if b.is_one(): + break + + parent = f.parent() + + d = a.gcd(b) + A = parent(A/a) + B = parent(B/b) + g = h = 1 + + delta = A.degree()-B.degree() + _,R = A.pseudo_quo_rem(B) + + while R.degree() > 0: + A = B + B = parent(R/(g*h**delta)) + g = A.leading_coefficient() + h = self(h*g**delta/h**delta) + delta = A.degree() - B.degree() + _, R = A.pseudo_quo_rem(B) + + if R.is_zero(): + b = self.zero() + for c in B.coefficients(): + b = b.gcd(c) + if b.is_one(): + break + + return parent(d*B/b) + + return d + class ElementMethods: # prime? # squareFree diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index a8a4f321be3..8d41a70e6f9 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3909,12 +3909,7 @@ cdef class Polynomial(CommutativeAlgebraElement): The actual algorithm for computing greatest common divisors depends on the base ring underlying the polynomial ring. If the base ring defines a method ``_gcd_univariate_polynomial``, then this method - will be called (see examples below). If no such method exists, a - fallback algorithm is used. - - ALGORITHM: - - The fallback algorithm is Algorithm 3.3.1 in [GTM138]_. + will be called (see examples below). EXAMPLES:: @@ -3926,84 +3921,28 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: (2*x).gcd(0) x - A fallback algorithm is implemented for rings that have no method + One can easily add gcd functionality to new rings by providing a method ``_gcd_univariate_polynomial``:: - sage: R. = ZZ[] - sage: S. = PolynomialRing(R, sparse=True) - sage: p = (-3*x^2 - x)*y^3 - 3*x*y^2 + (x^2 - x)*y + 2*x^2 + 3*x - 2 - sage: q = (-x^2 - 4*x - 5)*y^2 + (6*x^2 + x + 1)*y + 2*x^2 - x + sage: O = ZZ[-sqrt(5)] + sage: R. = O[] + sage: a = O.1 + sage: p = x + a + sage: q = x^2 - 5 sage: p.gcd(q) - 1 - sage: r = (1 + x)*y^2 + (x - 1)*y + 2*x + 3 - sage: (p*r).gcd(q*r) - (x + 1)*y^2 + (x - 1)*y + 2*x + 3 - - One can easily provide a specialized gcd function for rings by providing - a method ``_gcd_univariate_polynomial``:: - - sage: T. = QQ[] - sage: R._gcd_univariate_polynomial = lambda f,g: S(T(f).gcd(g)) - sage: (p*r).gcd(q*r) - (x + 1)*y^2 + (x - 1)*y + 2*x + 3 - sage: del R._gcd_univariate_polynomial - - REFERENCES: - - .. [GTM138] Henri Cohen. A Course in Computational Number Theory. - Graduate Texts in Mathematics, vol. 138. Springer, 1993. + Traceback (most recent call last): + ... + NotImplementedError: Order in Number Field in a with defining polynomial x^2 - 5 does not provide a gcd implementation for univariate polynomials + sage: S. = O.number_field()[] + sage: O._gcd_univariate_polynomial = lambda f,g : R(S(f).gcd(S(g))) + sage: p.gcd(q) + x + a + sage: del O._gcd_univariate_polynomial """ if hasattr(self.base_ring(), '_gcd_univariate_polynomial'): return self.base_ring()._gcd_univariate_polynomial(self, other) - - # Fallback algorithm: Algorithm 3.3.1 in Cohen [GTM 138] - if not self.parent().base_ring().is_unique_factorization_domain(): - raise ValueError("The base ring must be a unique factorization domain") - - if self.degree() < other.degree(): - A,B = other, self else: - A,B = self, other - - if B.is_zero(): - return A - - a = b = self.base_ring().zero() - for c in A.coefficients(): - a = a.gcd(c) - if a.is_one(): - break - for c in B.coefficients(): - b = b.gcd(c) - if b.is_one(): - break - - d = a.gcd(b) - A = self.parent()(A/a) - B = self.parent()(B/b) - g = h = 1 - - delta = A.degree()-B.degree() - _,R = A.pseudo_quo_rem(B) - - while R.degree() > 0: - A = B - B = self.parent()(R/(g*h**delta)) - g = A.leading_coefficient() - h = self.parent().base_ring()(h*g**delta/h**delta) - delta = A.degree() - B.degree() - _, R = A.pseudo_quo_rem(B) - - if R.is_zero(): - b = self.base_ring().zero() - for c in B.coefficients(): - b = b.gcd(c) - if b.is_one(): - break - - return self.parent()(d*B/b) - - return d + raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials"%self.base_ring()) @coerce_binop def lcm(self, other): From 2d86d7e8398daba552d3c45b9f523fc31ea815fe Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 16:39:43 +0200 Subject: [PATCH 0549/1872] small change in error message --- src/sage/rings/asymptotic/growth_group.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 8a792abed45..fc777d9102d 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -290,7 +290,8 @@ def __invert__(self): sage: ~G.an_element() Traceback (most recent call last): ... - NotImplementedError: Inversion of GenericGrowthElement(1) not implemented. + NotImplementedError: Inversion of GenericGrowthElement(1) not implemented + (in this abstract method). sage: G.an_element()^7 Traceback (most recent call last): ... @@ -299,7 +300,8 @@ def __invert__(self): sage: ~P.an_element() 1/x """ - raise NotImplementedError('Inversion of %s not implemented.' % (self,)) + raise NotImplementedError('Inversion of %s not implemented ' + '(in this abstract method).' % (self,)) def __eq__(self, other): From 08682395a1597a74f0fd6f7d9c0d6167f33b15aa Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 16:40:37 +0200 Subject: [PATCH 0550/1872] div/invert for terms --- src/sage/rings/asymptotic/term_monoid.py | 80 +++++++++++++++++++++++- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index eda233d53c1..150a824dbc3 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -207,7 +207,7 @@ def __init__(self, parent, growth): def _mul_(self, other): r""" - Abstract multiplication method for generic terms. + Multiplication of this term by another. INPUT: @@ -215,8 +215,7 @@ def _mul_(self, other): OUTPUT: - A :class:`GenericTerm` representing the product of ``self`` - and ``other``. + A :class:`GenericTerm`. .. NOTE:: @@ -239,6 +238,68 @@ def _mul_(self, other): return self.parent()(self.growth * other.growth) + def __div__(self, other): + r""" + Division of this term by another. + + INPUT: + + - ``other`` -- an asymptotic term. + + OUTPUT: + + A :class:`GenericTerm`. + + .. NOTE:: + + This function uses the coercion model to find a common + parent for the two operands. + + The comparison of two elements with the same parent is done in + :meth:`_div_`. + """ + from sage.structures.element import have_same_parent + if have_same_parent(self, other): + return self._div_(other) + + from sage.structure.element import get_coercion_model + import operator + return get_coercion_model().bin_op(self, other, operator.div) + + + def _div_(self, other): + r""" + Division of this term by another. + + INPUT: + + - ``other`` -- an asymptotic term. + + OUTPUT: + + A :class:`GenericTerm`. + + .. NOTE:: + + This method is called by the coercion framework, thus, + it can be assumed that this element, as well as ``other`` + are from a common parent. + """ + return self * ~other + + + def __invert__(self): + r""" + Invert this term. + + OUTPUT: + + A :class:`GenericTerm`. + """ + raise NotImplementedError('Inversion of %s not implemented ' + '(in this abstract method).' % (self,)) + + def can_absorb(self, other): r""" Check, whether this asymptotic term is able to absorb @@ -1071,6 +1132,10 @@ def _repr_(self): return 'O(%s)' % self.growth + def __invert__(self): + raise ZeroDivisionError('Cannot invert %s.' % (self,)) + + def _can_absorb_(self, other): r""" Check, whether this `O`-term can absorb ``other``. @@ -1914,6 +1979,15 @@ def _repr_(self): return '%s*%s' % (self.coefficient, self.growth) + def __invert__(self): + try: + c = ~self.coefficient + except ZeroDivisionError: + raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' + 'cannot be inverted.' % (self, self.coefficient)) + return self.parent()(~self.growth, self.coefficient) + + def _can_absorb_(self, other): r""" Check, whether this exact term can absorb ``other``. From 354f1ec31bc4d71197183304fe56a7a4c64fcecf Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 16:42:27 +0200 Subject: [PATCH 0551/1872] begin adapting invert of ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index ad5e9930fbb..1161719c384 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -700,10 +700,10 @@ def _div_(self, other): ... NotImplementedError: Negative powers are not implemented for the term O(x). """ - return self * other._invert_() + return self * ~other - def _invert_(self): + def __invert__(self): r""" Return the multiplicative inverse of this element. @@ -724,15 +724,15 @@ def _invert_(self): EXAMPLES:: sage: R. = AsymptoticRing('x^ZZ', QQ, default_prec=4) - sage: x._invert_() + sage: ~x 1/x - sage: (x^42)._invert_() + sage: ~(x^42) x^(-42) - sage: ex = (1 + x)._invert_(); ex + sage: ex = ~(1 + x); ex 1/x - x^(-2) + x^(-3) - x^(-4) + O(x^(-5)) sage: ex * (1 + x) 1 + O(x^(-4)) - sage: (1 + O(1/x))._invert_() + sage: ~(1 + O(1/x)) 1 + O(1/x) """ if len(self.summands) == 0: From f9089369482cc589372b0f3a7461d633d9540964 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Tue, 25 Aug 2015 16:51:04 +0200 Subject: [PATCH 0552/1872] Simplify GCD for sparse polynomials --- .../polynomial/polynomial_element_generic.py | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 26487f33b05..4fdbc4663ab 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -728,25 +728,24 @@ def quo_rem(self, other): def gcd(self,other,algorithm=None): """ - Return the gcd of ``self`` and ``other`` + Return the gcd of this polynomial and ``other`` INPUT: - - ``other`` -- a polynomial defined over the same ring as ``self`` + - ``other`` -- a polynomial defined over the same ring as this + polynomial. - Three algorithms are available: + ALGORITHM: - - "dense": The polynomials are converted to the dense representation, - their gcd are computed and is converted back to the sparse - representation. - - "fraction_field": The polynomials are coerced to the ring of - polynomials over the fraction field of their base ring. It won't - work with non integral domain as base rings. The gcd method is - called with the "dense" algorithm, in case there is no specific - sparse gcd method for the fraction field. - - "pseudo-division": Uses the gcd method of the class Polynomial. + Two algorithms are provided: - Default is "dense" for polynomials over ZZ and "pseudo-division" in the + - ``generic``: Uses the generic implementation, which depends on the + base ring being a UFD or a field. + - ``dense``: The polynomials are converted to the dense representation, + their gcd is computed and is converted back to the sparse + representation. + + Default is ``dense`` for polynomials over ZZ and ``generic`` in the other cases. EXAMPLES:: @@ -758,14 +757,12 @@ def gcd(self,other,algorithm=None): x^2 + x + 1 sage: gcd(p, q, algorithm = "dense") x^2 + x + 1 - sage: gcd(p, q, algorithm = "fraction_field") - x^2 + x + 1 - sage: gcd(p, q, algorithm = "pseudo-division") + sage: gcd(p, q, algorithm = "generic") x^2 + x + 1 - - AUTHORS: - - - Bruno Grenet (2014-06-25) + sage: gcd(p, q, algorithm = "foobar") + Traceback (most recent call last): + ... + ValueError: Unknown algorithm 'foobar' """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -775,7 +772,7 @@ def gcd(self,other,algorithm=None): if self.base_ring() == ZZ: algorithm = "dense" else: - algorithm = "pseudo-division" + algorithm = "generic" if algorithm=="dense": S = self.parent() # FLINT is faster but a bug makes the conversion extremely slow, @@ -791,14 +788,7 @@ def gcd(self,other,algorithm=None): D = PolynomialRing(S.base_ring(),'x',implementation=implementation) g = D(self).gcd(D(other)) return S(g) - if algorithm=="fraction_field": - R = self.parent().base_ring() - F = R.fraction_field() - S = PolynomialRing(F,'x',sparse=True) - g = S(self).gcd(S(other),algorithm="dense") - d = lcm([gg.denominator() for gg in g.coefficients()]) - return self.parent()(d*g) - if algorithm=="pseudo-division": + elif algorithm=="generic": return Polynomial.gcd(self,other) else: raise ValueError("Unknown algorithm '%s'" % algorithm) From 4ce91b14c2d876701543a25c68be15b8797e48b7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 17:53:44 +0200 Subject: [PATCH 0553/1872] fix bug in term monoid (invert) --- src/sage/rings/asymptotic/term_monoid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 150a824dbc3..eac6b2bcfce 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1985,7 +1985,7 @@ def __invert__(self): except ZeroDivisionError: raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' 'cannot be inverted.' % (self, self.coefficient)) - return self.parent()(~self.growth, self.coefficient) + return self.parent()(~self.growth, c) def _can_absorb_(self, other): From 0332c0713c78e7daac3c5ffef049120964371e9e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 17:55:55 +0200 Subject: [PATCH 0554/1872] rewrite inversion for ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 43 ++++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 1161719c384..64254222535 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -698,7 +698,7 @@ def _div_(self, other): sage: x / O(x) Traceback (most recent call last): ... - NotImplementedError: Negative powers are not implemented for the term O(x). + ZeroDivisionError: Cannot invert O(x). """ return self * ~other @@ -736,27 +736,29 @@ def __invert__(self): 1 + O(1/x) """ if len(self.summands) == 0: - raise ZeroDivisionError('Dividing by zero is not allowed.') + raise ZeroDivisionError('Division by zero in %s.' % (self,)) elif len(self.summands) == 1: - return self**(-1) + return self.parent()(~next(self.summands.elements())) - max_elem = list(self.summands.maximal_elements()) + max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: - raise ValueError('Expression %s cannot be inverted: ' - 'there are multiple maximal elements.' % (self, )) + raise ValueError('Expression %s cannot be inverted, since there ' + 'are several maximal elements: %s.' % (self, max_elem)) - max_elem = self.parent()(max_elem[0]) + max_elem = max_elem[0] + imax_elem = ~max_elem + one = self.parent().one() + geom = one - self._mul_term_(imax_elem) - geom = 1 - self / max_elem expanding = True - result = 1 + result = one while expanding: - new_result = (geom * result + 1).truncate() + new_result = (geom * result + one).truncate() if new_result.has_same_summands(result): expanding = False result = new_result - return result / max_elem + return result._mul_term_(imax_elem) def truncate(self, prec=None): @@ -834,16 +836,21 @@ def __pow__(self, power): sage: O(x)^(-1) Traceback (most recent call last): ... - NotImplementedError: Negative powers are not implemented for the term O(x). + ZeroDivisionError: Cannot invert O(x). """ - if len(self.summands) > 1: - from sage.rings.integer_ring import ZZ - if power not in ZZ: - raise NotImplementedError('Taking the sum %s to the ' - 'non-integer power %s not ' - 'implemented.' % (self, power)) + from sage.rings.integer_ring import ZZ + try: + power = ZZ(power) + except (TypeError, ValueError): + pass + else: return super(AsymptoticExpression, self).__pow__(power) + if len(self.summands) > 1: + raise NotImplementedError('Taking the sum %s to the ' + 'non-integer power %s not ' + 'implemented.' % (self, power)) + P = self.parent() if power not in P.growth_group.base(): raise ValueError('%s disallows taking %s ' From a3d8fd1a375d2418d1b558609d42ec1d333707a9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 18:05:00 +0200 Subject: [PATCH 0555/1872] doctests for 100% coverage --- src/sage/rings/asymptotic/term_monoid.py | 76 +++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index eac6b2bcfce..2fc959d43a5 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -223,7 +223,7 @@ def _mul_(self, other): it can be assumed that this element, as well as ``other`` are from a common parent. - EXAMPLES:: + TESTS:: sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg @@ -257,8 +257,21 @@ def __div__(self, other): The comparison of two elements with the same parent is done in :meth:`_div_`. + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() + sage: T = atm.GenericTermMonoid(G) + sage: t1 = T(x); t2 = T(x^2) + sage: t1 / t2 # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: Inversion of Generic Term with growth x^2 + not implemented (in this abstract method). """ - from sage.structures.element import have_same_parent + from sage.structure.element import have_same_parent if have_same_parent(self, other): return self._div_(other) @@ -284,6 +297,19 @@ def _div_(self, other): This method is called by the coercion framework, thus, it can be assumed that this element, as well as ``other`` are from a common parent. + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() + sage: T = atm.GenericTermMonoid(G) + sage: t1 = T(x); t2 = T(x^2) + sage: t1 / t2 # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: Inversion of Generic Term with growth x^2 + not implemented (in this abstract method). """ return self * ~other @@ -295,6 +321,18 @@ def __invert__(self): OUTPUT: A :class:`GenericTerm`. + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() + sage: T = atm.GenericTermMonoid(G) + sage: ~T(x) # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: Inversion of Generic Term with growth x + not implemented (in this abstract method). """ raise NotImplementedError('Inversion of %s not implemented ' '(in this abstract method).' % (self,)) @@ -1133,6 +1171,24 @@ def _repr_(self): def __invert__(self): + r""" + Invert this term. + + OUTPUT: + + A :class:`ZeroDivisionError` since `O`-terms cannot be inverted. + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() + sage: T = atm.OTermMonoid(G) + sage: ~T(x) # indirect doctest + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot invert O(x). + """ raise ZeroDivisionError('Cannot invert %s.' % (self,)) @@ -1980,6 +2036,22 @@ def _repr_(self): def __invert__(self): + r""" + Invert this term. + + OUTPUT: + + A term. + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() + sage: T = atm.ExactTermMonoid(G, QQ) + sage: ~T(x, 1/2) # indirect doctest + 2*1/x + """ try: c = ~self.coefficient except ZeroDivisionError: From e2447a9364f3fdd7c9852454e8a6e3131d3a40f1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 18:33:02 +0200 Subject: [PATCH 0556/1872] start with extending doc of module (invert) --- src/sage/rings/asymptotic/asymptotic_ring.py | 42 ++++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 199158dddb0..a05a066c58f 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -106,11 +106,13 @@ :: - sage: B. = AsymptoticRing(growth_group='x^QQ * log(x)^ZZ * QQ^y * y^QQ', coefficient_ring=QQ); B # not tested + sage: B. = AsymptoticRing(growth_group='x^QQ * log(x)^ZZ * QQ^y * y^QQ', coefficient_ring=QQ); B + Asymptotic Ring over Rational Field -Again, we can look at a typical element:: +Again, we can look at a typical (nontrivial) element:: - sage: B.an_element() # not tested + sage: B.an_element() + -1/8*x^(3/2) * log(x)^3 * (1/8)^y * y^(3/2) + O(x^(1/2) * log(x) * (1/2)^y * y^(1/2)) Arithemtical Operations ----------------------- @@ -147,28 +149,44 @@ sage: z^3 + z^2 + z + O(z^2) z^3 + O(z^2) -and more advanced +where the result is simplified automatically. More advanced :: sage: (z + 2*z^2 + 3*z^3 + 4*z^4) * (O(z) + z^2) 4*z^6 + O(z^5) -The division of asymptotic expressions is implemented as well:: +The asymptotic expressions support division. For example, we get can +expand `1/(1-z)` to a geometric series:: - sage: A. = AsymptoticRing('z^QQ', QQ, default_prec=10) sage: 1/(z - 1) - 1/z + z^(-2) + z^(-3) + z^(-4) + ... + z^(-10) + O(z^(-11)) + 1/z + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21)) + +Since there is a default precision (parameter ``default_prec``) +defined, only the first `20` summands are calculated. Here, we can +work with more complicated expressions as well:: + sage: (1 + 4*z)/(z + z^2 + z^3) - 4*z^(-2) - 3*z^(-3) - z^(-4) + 4*z^(-5) - 3*z^(-6) - ... - z^(-16) + O(z^(-17)) + 4*z^(-2) - 3*z^(-3) - z^(-4) + 4*z^(-5) - 3*z^(-6) - ... - z^(-31) + O(z^(-32)) -.. TODO:: +Note that not all elements are invertible, for instance, + +:: - arithmetic in the ring + sage: 1/O(z) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot invert O(z). + +is not invertible, since it includes `0`. + +Now let us move on to arithmetic in the multivariate ring + +:: - :: + sage: B + Asymptotic Ring over Rational Field - sage: B # not tested More Examples ============= From 7b81c08b7fcab195dcaff9796872f3998f29eada Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 18:42:40 +0200 Subject: [PATCH 0557/1872] change : to :: in docstrings --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/growth_group.py | 2 +- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index a05a066c58f..c61c936051e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1403,7 +1403,7 @@ def some_elements(self): An iterator. - EXAMPLES: + EXAMPLES:: sage: from itertools import islice sage: A = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 5102035fc7a..ee44c2ef126 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1277,7 +1277,7 @@ def some_elements(self): An iterator. - EXAMPLES: + EXAMPLES:: sage: import sage.rings.asymptotic.growth_group as agg sage: tuple(agg.MonomialGrowthGroup(ZZ, 'z').some_elements()) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index fc7cb4b92ae..34ca49d2864 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1199,7 +1199,7 @@ def some_elements(self): An iterator. - EXAMPLES: + EXAMPLES:: sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm @@ -2078,7 +2078,7 @@ def some_elements(self): An iterator. - EXAMPLES: + EXAMPLES:: sage: from itertools import islice sage: import sage.rings.asymptotic.growth_group as agg From 158550a8bd6f6fec76d1249bbfc84cb82493d8ad Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 18:45:59 +0200 Subject: [PATCH 0558/1872] remove agg, atm of doctests and replace them by something more readable --- src/sage/rings/asymptotic/asymptotic_ring.py | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index c61c936051e..105e1d0ec5a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -528,10 +528,10 @@ def _simplify_(self): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: OT = atm.TermMonoid('O', G); ET = atm.TermMonoid('exact', G, ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ') + sage: OT = TermMonoid('O', G); ET = TermMonoid('exact', G, ZZ) sage: R = AsymptoticRing(G, ZZ) sage: lst = [ET(x,1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] sage: expr = R(lst, simplify=False); expr # indirect doctest @@ -655,9 +655,9 @@ def _mul_term_(self, term): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.term_monoid import OTermMonoid sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) - sage: T = atm.OTermMonoid(R.growth_group) + sage: T = OTermMonoid(R.growth_group) sage: expr = 10*x^2 + O(x) sage: t = T(R.growth_group.gen()) sage: expr._mul_term_(t) @@ -973,8 +973,8 @@ class AsymptoticRing(sage.rings.ring.Ring, This is equivalent to the following code, which explicitly specifies the underlying growth group:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_QQ = agg.GrowthGroup('x^QQ') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_QQ = GrowthGroup('x^QQ') sage: R2_x. = AsymptoticRing(growth_group=G_QQ, coefficient_ring=QQ); R2_x Asymptotic Ring over Rational Field @@ -1042,8 +1042,8 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, are unique. Also, this enables the use of the generation framework:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: MG = agg.GrowthGroup('x^ZZ') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: MG = GrowthGroup('x^ZZ') sage: AR1 = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: AR2. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: AR1 is AR2 @@ -1349,8 +1349,8 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: MG = agg.GrowthGroup('x^ZZ') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: MG = GrowthGroup('x^ZZ') sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) sage: repr(AR) # indirect doctest 'Asymptotic Ring over Integer Ring' From 1990cc082d222210e54a4653e2328767c141b40a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:32:22 +0200 Subject: [PATCH 0559/1872] add a doctest to sage.rings.big_oh --- src/sage/rings/big_oh.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 95b8f764597..b2a44ac8789 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -71,6 +71,16 @@ def O(*x, **kwds): sage: K(11^-12, 15) 11^-12 + O(11^15) + We can also work with :mod:`asymptotic expressions + `:: + + sage: A. = AsymptoticRing(growth_group='QQ^n * n^QQ * log(n)^QQ', coefficient_ring=QQ); A + doctest:...: FutureWarning: + This class/method/function is marked as experimental. ... + Asymptotic Ring over Rational Field + sage: O(n) + O(n) + TESTS:: sage: var('x, y') From 76a357616459005ba71cd2ddda1497cd46aa7a6b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:34:12 +0200 Subject: [PATCH 0560/1872] rewrite module description of growth_group --- src/sage/rings/asymptotic/growth_group.py | 133 ++++++++++++++++------ 1 file changed, 98 insertions(+), 35 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ee44c2ef126..fe56933c828 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1,29 +1,43 @@ r""" (Asymptotic) Growth Groups -This module adds support for (asymptotic) growth groups. Such groups -are equipped with a partial order: the elements can be seen as -functions, and their behavior as the argument(s) get large (tend to -`\infty`) is compared. +This module provides support for (asymptotic) growth groups. -Besides an abstract base class :class:`GenericGrowthGroup`, this module -contains concrete realizations of growth groups. At the moment there -is +Such groups are equipped with a partial order: the elements can be +seen as functions, and the behavior as their argument (or arguments) +gets large (tend to `\infty`) is compared. -- :class:`MonomialGrowthGroup` (whose elements are powers of a fixed symbol). +Growth groups are used for the calculations done in the +:mod:`asymptotic ring `. -More complex growth groups can be constructed via cartesian products. +A Formal Definition +=================== -These growth groups are used behind the scenes when performing -calculations in an asymptotic ring (to be implemented). +The elements of a :mod:`growth group +` are equipped with a partial +ordering and usually contain a variable. Examples are (among many +other possibilities) -AUTHORS: +- elements of the form `z^q` for some integer or rational `q` (growth + groups ``z^ZZ`` or ``z^QQ``), -- Benjamin Hackl (2015-01): initial version -- Daniel Krenn (2015-05-29): initial version and review -- Daniel Krenn (2015-06-02): cartesian products -- Benjamin Hackl (2015-07): growth group factory -- Benjamin Hackl (2015-08): exponential growth group, initial version +- elements of the form `log(z)^q` for some integer or rational `q` (growth + groups ``log(z)^ZZ`` or ``log(z)^QQ``), + +- elements of the form `a^z` for some + rational `a` (growth group ``QQ^z``), or + +- more sophisticated constructions like products `x^r log(x)^s \cdot + a^y \cdot y^q` (this corresponds to an element of the growth group + ``x^QQ * log(x)^ZZ * QQ^y * y^QQ``). + +The ordering in all these examples is the growth as `x`, `y`, or `z` +(independently) tend to `\infty`. For elements only using the +variable `z` this means, `g_1 \leq g_2` if + +.. MATH:: + + \lim_{z\to\infty} \frac{g_2}{g_1} \leq 1. .. WARNING:: @@ -47,24 +61,65 @@ See http://trac.sagemath.org/17601 for details. Growth Group x^ZZ * log(x)^ZZ -.. NOTE:: +Overview +======== + +For many purposes the factory ``GrowthGroup`` (see +:class:`GrowthGroupFactory`) is the most convenient way to generate a +growth group. + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + +Here are some examples:: + + sage: GrowthGroup('z^ZZ') + sage: GrowthGroup('z^QQ') + +Each of these two generated groups is a :class:`MonomialGrowthGroup`, +whose elements are powers of a fixed symbol (above ``'z'``). + +Similarly, we can construct logarithmic factors by:: + + sage: GrowthGroup('log(z)^QQ') + +which again creates a +:class:`MonomialGrowthGroup`. An :class:`ExponentialGrowthGroup` is generated in the same way. Our factory gives +:: - By using the following short notation for growth groups, their - creation is very simple: *Monomial growth groups* (i.e. the - group for powers of a fixed symbol; - :class:`~sage.rings.asymptotic.growth_group.MonomialGrowthGroup`) - are denoted as ``variable^base``, e.g. ``x^ZZ`` and ``y^QQ`` for - the group of integer powers of `x`, and the group of rational - powers of `y`, respectively. + sage: E = GrowthGroup('QQ^z'); E - This also enables us to construct *logarithmic growth groups*, - e.g. ``log(x)^ZZ``. +and a typical element looks like this:: - Exponential growth groups, i.e. growth groups representing - elements of the form `\operatorname{base}^\operatorname{variable}` - are denoted as ``base^variable``. For example, ``QQ^x`` denotes - the multiplicative group of exponential expressions `q^x`, where - `q \in \mathbb{Q}^{\times}`. + sage: E.an_element() + +More complex groups are created in a similar fashion. For example + + sage: C = GrowthGroup('QQ^z * z^QQ * log(z)^QQ') + +This contains elements of the form + + sage: C.an_element() + +The group `C` itself is a cartesian product; to be precise a +:class:`~sage.rings.asymptotic.growth_group_cartesian.UnivariateProduct`. We +can see its factors:: + + sage: C.cartesian_factors() + +Multivariate constructions are also possible:: + + sage: GrowthGroup('x^QQ * y^QQ') + +This gives a +:class:`~sage.rings.asymptotic.growth_group_cartesian.MultivariateProduct`. + +Both these cartesian products are derived from the class +:class:`~sage.rings.asymptotic.growth_group_cartesian.GenericProduct`. Moreover +all growth groups have the abstract base class +:class:`GenericGrowthGroup` in common. + +Some Examples +^^^^^^^^^^^^^ EXAMPLES:: @@ -110,6 +165,14 @@ sage: (x, y) = var('x y') sage: G(2^x * log(x) * y^(1/2)) * G(x^(-5) * 5^x * y^(1/3)) 10^x * x^(-5) * log(x) * y^(5/6) + +AUTHORS: + +- Benjamin Hackl (2015-01): initial version +- Daniel Krenn (2015-05-29): initial version and review +- Daniel Krenn (2015-06-02): cartesian products +- Benjamin Hackl (2015-07): growth group factory +- Benjamin Hackl (2015-08): exponential growth group, initial version """ #***************************************************************************** @@ -1737,7 +1800,7 @@ class AbstractGrowthGroupFunctor(ConstructionFunctor): :mod:`sage.rings.asymptotic.asymptotic_ring`, :class:`ExponentialGrowthGroupFunctor`, :class:`MonomialGrowthGroupFunctor`, - :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, :class:`sage.categories.pushout.ConstructionFunctor`. """ @@ -2354,7 +2417,7 @@ class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): :mod:`sage.rings.asymptotic.asymptotic_ring`, :class:`AbstractGrowthGroupFunctor`, :class:`ExponentialGrowthGroupFunctor`, - :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, :class:`sage.categories.pushout.ConstructionFunctor`. TESTS:: @@ -2838,7 +2901,7 @@ class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): :mod:`sage.rings.asymptotic.asymptotic_ring`, :class:`AbstractGrowthGroupFunctor`, :class:`MonomialGrowthGroupFunctor`, - :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, :class:`sage.categories.pushout.ConstructionFunctor`. TESTS:: From 263598c8695a5127fc71aa21b7ecc2117e39a648 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:34:30 +0200 Subject: [PATCH 0561/1872] some doc fixes in term_moniod --- src/sage/rings/asymptotic/term_monoid.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 34ca49d2864..138c24ae997 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3,7 +3,7 @@ This module implements asymptotic term monoids. The elements of these monoids are used behind the scenes when performing calculations in an -asymptotic ring (to be implemented). +:mod:`asymptotic ring `. The monoids build upon the (asymptotic) growth groups. While growth elements only model the growth of a function as it tends towards @@ -199,7 +199,7 @@ def __getitem__(self, i): def absorption(left, right): r""" Helper method used by - :class:`~sage.rings.asymptotic_ring.AsymptoticExpression`. + :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpression`. INPUT: @@ -231,7 +231,7 @@ def absorption(left, right): def can_absorb(left, right): r""" Helper method used by - :class:`~sage.rings.asymptotic_ring.AsymptoticExpression`. + :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpression`. INPUT: @@ -464,11 +464,6 @@ def can_absorb(self, other): A boolean. - .. NOTE:: - - This method calls :meth:`_can_absorb_`, which is has to be - implemented/overridden in inherited class. - EXAMPLES: We want to show step by step which terms can be absorbed @@ -1460,7 +1455,7 @@ class OTermMonoid(GenericTermMonoid): Asymptotic O-Term Monoid y^QQ `O`-term monoids can also be created by using the - :class:`term factory `:: + :class:`term factory `:: sage: atm.TermMonoid('O', G_x_ZZ) is OT_x_ZZ True From a3826567960d4efbaff921c26591681326620fad Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:34:47 +0200 Subject: [PATCH 0562/1872] add a link in growth_group_factory --- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 53d3ea404c0..98ddc22034c 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1,6 +1,8 @@ r""" Growth Groups as Cartesian Products +See :mod:`sage.rings.asymptotic.growth_group` for a description. + AUTHORS: - Daniel Krenn (2015-06-02): cartesian products From c549344fd698a57d87f026fc9f97c3f70d8f7ec3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:36:01 +0200 Subject: [PATCH 0563/1872] some improvments in the module description of the asymptotic ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 30 ++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 105e1d0ec5a..214bb5b0b6e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1,9 +1,8 @@ r""" Asymptotic Ring -This module implements a ring (called :class:`AsymptoticRing`) for -computations with :class:`asymptotic expressions -`. +This module provides a ring (called :class:`AsymptoticRing`) for +computations with asymptotic expressions. Definition ========== @@ -15,7 +14,7 @@ - `O`-terms `O(g)` (see :wikipedia:`Big O notation `; also called *Bachmann--Landau notation*) for some :mod:`growth group - element ` `g` (:ref:`see below + element ` `g` (:ref:`see below `). Examples of such elements can found :ref:`below `. @@ -27,7 +26,7 @@ The elements of a :mod:`growth group ` are equipped with a partial -ordering and usually contains a variable. Examples are (among many +ordering and usually contain a variable. Examples are (among many other possibilities) - elements of the form `z^q` for some integer or rational `q` (growth @@ -121,6 +120,9 @@ their elements) we can do a lot of different arithmetical calculations. +The Ring Operations Plus and Times +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + We start our calculations in the ring :: @@ -156,6 +158,9 @@ sage: (z + 2*z^2 + 3*z^3 + 4*z^4) * (O(z) + z^2) 4*z^6 + O(z^5) +Division +^^^^^^^^ + The asymptotic expressions support division. For example, we get can expand `1/(1-z)` to a geometric series:: @@ -180,6 +185,9 @@ is not invertible, since it includes `0`. +Multivariate Arithemtic +^^^^^^^^^^^^^^^^^^^^^^^ + Now let us move on to arithmetic in the multivariate ring :: @@ -195,6 +203,13 @@ write more examples +Selected Technical Details +========================== + +Coercions and Functorial Constructions +-------------------------------------- + + AUTHORS: - Benjamin Hackl (2015-06): initial version @@ -444,10 +459,9 @@ def has_same_summands(self, other): While for example ``O(x) == O(x)`` yields ``False``, these expressions *do* have the same summands. - Also, this method uses the coercion model in order to + Moreover, this method uses the coercion model in order to find a common parent for this asymptotic expression and - ``other``. The method :meth:`_has_same_summands_` is - then used for the actual comparison. + ``other``. EXAMPLES:: From 45549cdcd7e130ae1d551da53916e871cd8118a1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:36:42 +0200 Subject: [PATCH 0564/1872] big_oh: some seealso --- src/sage/rings/big_oh.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index b2a44ac8789..9e3080fe190 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -1,5 +1,12 @@ """ Big O for various types (power series, p-adics, etc.) + +.. SEEALSO:: + + - :mod:`asymptotic expressions ` + - `p-adic numbers <../../../padics/index.html>`_ + - `power series <../../../power_series/index.html>`_ + - `polynomials <../../../polynomial_rings/index.html>`_ """ import sage.rings.arith as arith From 0bf978156db3435d6183f0174b7a38fe783b79e2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:54:53 +0200 Subject: [PATCH 0565/1872] fix doctests --- src/sage/rings/asymptotic/growth_group.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index fe56933c828..58766197482 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -73,7 +73,9 @@ Here are some examples:: sage: GrowthGroup('z^ZZ') + Growth Group z^ZZ sage: GrowthGroup('z^QQ') + Growth Group z^QQ Each of these two generated groups is a :class:`MonomialGrowthGroup`, whose elements are powers of a fixed symbol (above ``'z'``). @@ -81,34 +83,41 @@ Similarly, we can construct logarithmic factors by:: sage: GrowthGroup('log(z)^QQ') + Growth Group log(z)^QQ which again creates a :class:`MonomialGrowthGroup`. An :class:`ExponentialGrowthGroup` is generated in the same way. Our factory gives :: sage: E = GrowthGroup('QQ^z'); E + Growth Group QQ^z and a typical element looks like this:: sage: E.an_element() + (1/2)^z More complex groups are created in a similar fashion. For example - sage: C = GrowthGroup('QQ^z * z^QQ * log(z)^QQ') + sage: C = GrowthGroup('QQ^z * z^QQ * log(z)^QQ'); C + Growth Group QQ^z * z^QQ * log(z)^QQ This contains elements of the form sage: C.an_element() + (1/2)^z * z^(1/2) * log(z)^(1/2) The group `C` itself is a cartesian product; to be precise a :class:`~sage.rings.asymptotic.growth_group_cartesian.UnivariateProduct`. We can see its factors:: sage: C.cartesian_factors() + (Growth Group QQ^z, Growth Group z^QQ, Growth Group log(z)^QQ) Multivariate constructions are also possible:: sage: GrowthGroup('x^QQ * y^QQ') + Growth Group x^QQ * y^QQ This gives a :class:`~sage.rings.asymptotic.growth_group_cartesian.MultivariateProduct`. From 223c1e3b15422e5f81d61ed9350fd0d6c298f3eb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:55:13 +0200 Subject: [PATCH 0566/1872] move parts in documentation-tree --- src/doc/en/reference/groups/index.rst | 3 +++ src/doc/en/reference/monoids/index.rst | 2 ++ src/doc/en/reference/rings/index.rst | 5 +---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/doc/en/reference/groups/index.rst b/src/doc/en/reference/groups/index.rst index 3ef8d105455..4132441b85a 100644 --- a/src/doc/en/reference/groups/index.rst +++ b/src/doc/en/reference/groups/index.rst @@ -56,6 +56,9 @@ Groups sage/groups/perm_gps/partn_ref sage/groups/perm_gps/partn_ref2 + sage/rings/asymptotic/growth_group + sage/rings/asymptotic/growth_group_cartesian + Internals --------- diff --git a/src/doc/en/reference/monoids/index.rst b/src/doc/en/reference/monoids/index.rst index de4db62002d..2584fd9bc77 100644 --- a/src/doc/en/reference/monoids/index.rst +++ b/src/doc/en/reference/monoids/index.rst @@ -20,4 +20,6 @@ finite number of indeterminates. sage/monoids/string_ops + sage/rings/asymptotic/term_monoid + .. include:: ../footer.txt diff --git a/src/doc/en/reference/rings/index.rst b/src/doc/en/reference/rings/index.rst index 7581608f295..9d0771d5468 100644 --- a/src/doc/en/reference/rings/index.rst +++ b/src/doc/en/reference/rings/index.rst @@ -18,6 +18,7 @@ General Rings, Ideals, and Morphisms sage/rings/quotient_ring_element sage/rings/invariant_theory + sage/rings/asymptotic/asymptotic_ring sage/rings/bernmm sage/rings/bernoulli_mod_p sage/rings/big_oh @@ -43,9 +44,5 @@ General Rings, Ideals, and Morphisms sage/rings/principal_ideal_domain_element sage/rings/ring_element - sage/rings/asymptotic/growth_group - sage/rings/asymptotic/term_monoid - sage/rings/asymptotic/asymptotic_ring - .. include:: ../footer.txt From adc92360f97d6ef430cbe302a21f8b63679281ea Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 20:56:05 +0200 Subject: [PATCH 0567/1872] write doc on used data structures --- src/sage/rings/asymptotic/asymptotic_ring.py | 40 ++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 214bb5b0b6e..438be05bbd2 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -209,6 +209,46 @@ Coercions and Functorial Constructions -------------------------------------- +Data Structures +--------------- + +The summands of an +:class:`asymptotic expression ' are wrapped +:mod:`growth group elements `. +This wrapping is done by the +:mod:`term monoid module `. +However, inside an +:class:`asymptotic expression ' these summands +(terms) are stored together with their growth-relationship, i.e., each +summand knows its direct predecessors and successors. As a data +structure a special poset (namely a +:mod:`mutable poset `) +is used. We can have a look at this:: + + sage: b = x^3*y + x^2*y + x*y^2 + O(x) + O(y) + sage: print b.summands.repr_full(reverse=True) + poset(x * y^2, x^3 * y, x^2 * y, O(x), O(y)) + +-- oo + | +-- no successors + | +-- predecessors: x * y^2, x^3 * y + +-- x * y^2 + | +-- successors: oo + | +-- predecessors: O(x), O(y) + +-- x^3 * y + | +-- successors: oo + | +-- predecessors: x^2 * y + +-- x^2 * y + | +-- successors: x^3 * y + | +-- predecessors: O(x), O(y) + +-- O(x) + | +-- successors: x * y^2, x^2 * y + | +-- predecessors: null + +-- O(y) + | +-- successors: x * y^2, x^2 * y + | +-- predecessors: null + +-- null + | +-- successors: O(x), O(y) + | +-- no predecessors AUTHORS: From 42a5c1ee4060bd75a9825b22a2fe22bcab269e82 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Aug 2015 21:00:04 +0200 Subject: [PATCH 0568/1872] two more headlines --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 438be05bbd2..46e03891927 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -250,11 +250,17 @@ | +-- successors: O(x), O(y) | +-- no predecessors +Various +======= + AUTHORS: - Benjamin Hackl (2015-06): initial version - Benjamin Hackl (2015-07): improvement user interface (short notation) - Daniel Krenn (2015-08): various improvents, review; documentation + +Methods +======= """ # ***************************************************************************** From d1f4611120f3209e5c8e8f21aafee11d7b90a426 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 08:00:33 +0200 Subject: [PATCH 0569/1872] fix docbuild (wrong apostrophe) --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 46e03891927..12c6cdb64d7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -213,12 +213,12 @@ --------------- The summands of an -:class:`asymptotic expression ' are wrapped +:class:`asymptotic expression ` are wrapped :mod:`growth group elements `. This wrapping is done by the :mod:`term monoid module `. However, inside an -:class:`asymptotic expression ' these summands +:class:`asymptotic expression ` these summands (terms) are stored together with their growth-relationship, i.e., each summand knows its direct predecessors and successors. As a data structure a special poset (namely a From 97cdf1644bb8abb579007481590b94854890fbb0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 09:07:57 +0200 Subject: [PATCH 0570/1872] small change in division example --- src/sage/rings/asymptotic/asymptotic_ring.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 12c6cdb64d7..adee8573789 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -168,11 +168,12 @@ 1/z + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21)) Since there is a default precision (parameter ``default_prec``) -defined, only the first `20` summands are calculated. Here, we can -work with more complicated expressions as well:: +defined, only the first `20` summands are calculated. - sage: (1 + 4*z)/(z + z^2 + z^3) - 4*z^(-2) - 3*z^(-3) - z^(-4) + 4*z^(-5) - 3*z^(-6) - ... - z^(-31) + O(z^(-32)) +Of course, we can work with more complicated expressions as well:: + + sage: (4*z + 1) / (z^3 + z^2 + z + O(A(1))) + 4*z^(-2) - 3*z^(-3) - z^(-4) + O(z^(-5)) Note that not all elements are invertible, for instance, From c197b13e248fbc1f0b929479f7ae3030bf5df9e5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 14:02:11 +0200 Subject: [PATCH 0571/1872] some spacings in doc --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index adee8573789..a92338dd394 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -164,7 +164,7 @@ The asymptotic expressions support division. For example, we get can expand `1/(1-z)` to a geometric series:: - sage: 1/(z - 1) + sage: 1 / (z - 1) 1/z + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21)) Since there is a default precision (parameter ``default_prec``) @@ -179,7 +179,7 @@ :: - sage: 1/O(z) + sage: 1 / O(z) Traceback (most recent call last): ... ZeroDivisionError: Cannot invert O(z). From d759c8e8b86ee29b5c88e1dddfa848162f973687 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 14:02:25 +0200 Subject: [PATCH 0572/1872] allow O(0) --- src/sage/rings/asymptotic/asymptotic_ring.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index a92338dd394..72a7cdacd55 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -977,21 +977,16 @@ def O(self): 42*x^42 + x^10 + O(x^2) sage: expr.O() O(x^42) - - TESTS:: - sage: O(AR(0)) - Traceback (most recent call last): - ... - ValueError: Cannot build O(0). + 0 + sage: (2*x).O() + O(x) .. SEEALSO:: :func:`sage.rings.power_series_ring.PowerSeriesRing`, :func:`sage.rings.laurent_series_ring.LaurentSeriesRing`. """ - if not self: - raise ValueError('Cannot build O(%s).' % (self,)) return sum(self.parent().create_summand('O', growth=element) for element in self.summands.maximal_elements()) From ab05e752a104896a49a48085479fbdc2568dc383 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 14:03:14 +0200 Subject: [PATCH 0573/1872] extend error messages in element_constructor and test for nonzeroness --- src/sage/rings/asymptotic/asymptotic_ring.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 72a7cdacd55..2180e370ee0 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1291,7 +1291,8 @@ def _element_constructor_(self, data, summands=None, simplify=True): sage: y = ZZ['y'].gen(); AR(y) Traceback (most recent call last): ... - TypeError: Cannot convert y to an asymptotic expression. + TypeError: Cannot convert y to an asymptotic expression + in Asymptotic Ring over Integer Ring. """ if summands is not None: if type(data) != int or data != 0: @@ -1313,12 +1314,13 @@ def _element_constructor_(self, data, summands=None, simplify=True): if isinstance(data, (list, tuple)): if not all(isinstance(elem, GenericTerm) for elem in data): raise TypeError('Not all list entries of %s ' - 'are asymptotic terms.' % (data,)) + 'are asymptotic terms, so cannot create an ' + 'asymptotic expression in %s.' % (data, self)) summands = AsymptoticRing._create_empty_summands_() summands.union_update(data) return self.element_class(self, summands, simplify=simplify) - if data == 0: + if not data or data == 0: summands = AsymptoticRing._create_empty_summands_() return self.element_class(self, summands, simplify=simplify) @@ -1337,7 +1339,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): return self.create_summand('exact', growth=1, coefficient=coefficient) raise TypeError('Cannot convert %s to an asymptotic ' - 'expression.' % (data,)) + 'expression in %s.' % (data, self)) def _coerce_map_from_(self, R): From 4bb85a5810918b0abf788d85d75029c19d6b6542 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 14:04:53 +0200 Subject: [PATCH 0574/1872] rewrite element_constructor of terms --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 + src/sage/rings/asymptotic/term_monoid.py | 179 +++++++++++-------- 2 files changed, 117 insertions(+), 70 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 2180e370ee0..4bf04c39190 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1592,6 +1592,14 @@ def create_summand(self, type, growth, **kwds): O(x^2) sage: R.create_summand('exact', growth=x^456, coefficient=123) 123*x^456 + + TESTS:: + + sage: R.create_summand('O', growth=42*x^2) + Traceback (most recent call last): + ... + ValueError: Growth 42*x^2 is not in O-Term Monoid x^ZZ. + > *previous* ValueError: 42*x^2 is not in Growth Group x^ZZ. """ from sage.rings.asymptotic.term_monoid import TermMonoid TM = TermMonoid(type, self.growth_group, self.coefficient_ring) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 138c24ae997..442aad2a0ed 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1110,9 +1110,9 @@ def _element_constructor_(self, data): EXAMPLES:: sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.GrowthGroup('x^ZZ') - sage: G_QQ = agg.GrowthGroup('x^QQ') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_ZZ = GrowthGroup('x^ZZ') + sage: G_QQ = GrowthGroup('x^QQ') sage: T_ZZ = atm.GenericTermMonoid(growth_group=G_ZZ) sage: T_QQ = atm.GenericTermMonoid(growth_group=G_QQ) sage: term1 = T_ZZ(G_ZZ.gen()) @@ -1138,7 +1138,19 @@ def _element_constructor_(self, data): sage: T_ZZ(10 * x^2) Traceback (most recent call last): ... - ValueError: Input is ambiguous: cannot convert 10*x^2 to a generic term. + ValueError: Growth 10*x^2 is not in Generic Term Monoid x^ZZ. + > *previous* ValueError: 10*x^2 is not in Growth Group x^ZZ. + + TESTS:: + + sage: O_ZZ = atm.OTermMonoid(growth_group=G_ZZ) + sage: O_ZZ(x^11) + O(x^11) + sage: O_ZZ(2*x^11) + Traceback (most recent call last): + ... + ValueError: Growth 2*x^11 is not in O-Term Monoid x^ZZ. + > *previous* ValueError: 2*x^11 is not in Growth Group x^ZZ. """ if type(data) == self.element_class and data.parent() == self: return data @@ -1147,12 +1159,13 @@ def _element_constructor_(self, data): elif type(data) == int and data == 0: raise ValueError('No input specified. Cannot continue.') else: + from growth_group import combine_exceptions try: data = self.growth_group(data) return self.element_class(self, data) - except: - raise ValueError('Input is ambiguous: cannot convert %s to a ' - 'generic term.' % (data,)) + except (ValueError, TypeError) as e: + raise combine_exceptions( + ValueError('Growth %s is not in %s.' % (data, self)), e) def _an_element_(self): @@ -1450,9 +1463,9 @@ class OTermMonoid(GenericTermMonoid): sage: G_x_ZZ = agg.GrowthGroup('x^ZZ') sage: G_y_QQ = agg.GrowthGroup('y^QQ') sage: OT_x_ZZ = atm.OTermMonoid(G_x_ZZ); OT_x_ZZ - Asymptotic O-Term Monoid x^ZZ + O-Term Monoid x^ZZ sage: OT_y_QQ = atm.OTermMonoid(G_y_QQ); OT_y_QQ - Asymptotic O-Term Monoid y^QQ + O-Term Monoid y^QQ `O`-term monoids can also be created by using the :class:`term factory `:: @@ -1460,7 +1473,7 @@ class OTermMonoid(GenericTermMonoid): sage: atm.TermMonoid('O', G_x_ZZ) is OT_x_ZZ True sage: atm.TermMonoid('O', agg.GrowthGroup('x^QQ')) - Asymptotic O-Term Monoid x^QQ + O-Term Monoid x^QQ """ # enable the category framework for elements Element = OTerm @@ -1538,9 +1551,9 @@ def _repr_(self): sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() sage: atm.OTermMonoid(G)._repr_() - 'Asymptotic O-Term Monoid x^ZZ' + 'O-Term Monoid x^ZZ' """ - return 'Asymptotic O-Term Monoid %s' % (self.growth_group._repr_short_(),) + return 'O-Term Monoid %s' % (self.growth_group._repr_short_(),) class TermWithCoefficient(GenericTerm): @@ -1589,7 +1602,8 @@ def __init__(self, parent, growth, coefficient): sage: t = CT_ZZ(x, 1/2) Traceback (most recent call last): ... - ValueError: 1/2 is not in Integer Ring + ValueError: 1/2 is not a coefficient in + Term Monoid x^ZZ with coefficients from Integer Ring. sage: t = CT_QQ(x, 1/2); t Asymptotic Term with coefficient 1/2 and growth x @@ -1598,7 +1612,8 @@ def __init__(self, parent, growth, coefficient): sage: t = CT_ZZ(x^42, 0) Traceback (most recent call last): ... - ValueError: 0 is not a valid coefficient. + ValueError: Zero coefficient 0 is not allowed in + Term Monoid x^ZZ with coefficients from Integer Ring. The conversion of growth elements also works for the creation of terms with coefficient:: @@ -1608,13 +1623,16 @@ def __init__(self, parent, growth, coefficient): sage: CT_ZZ(x^42, 42) Asymptotic Term with coefficient 42 and growth x^42 """ - if coefficient not in parent.base_ring: - raise ValueError('%s is not in %s' % (coefficient, - parent.base_ring)) - elif coefficient == 0: - raise ValueError('0 is not a valid coefficient') - - self.coefficient = parent.base_ring(coefficient) + try: + coefficient = parent.base_ring(coefficient) + except (ValueError, TypeError): + raise ValueError('%s is not a coefficient in %s.' % + (coefficient, parent)) + if coefficient == 0: + raise ValueError('Zero coefficient %s is not allowed in %s.' % + (coefficient, parent)) + + self.coefficient = coefficient super(TermWithCoefficient, self).__init__(parent=parent, growth=growth) @@ -1932,9 +1950,7 @@ def _element_constructor_(self, data, coefficient=None): sage: T(5 * x^5) Asymptotic Term with coefficient 5 and growth x^5 sage: T(G.gen()^10) - Traceback (most recent call last): - ... - ValueError: Coefficient is not specified. Cannot continue. + Asymptotic Term with coefficient 1 and growth x^10 sage: T(G.gen()^10, coefficient=10) Asymptotic Term with coefficient 10 and growth x^10 sage: T(x^123) @@ -1957,53 +1973,76 @@ def _element_constructor_(self, data, coefficient=None): elif isinstance(data, TermWithCoefficient): return self.element_class(self, data.growth, data.coefficient) elif type(data) == int and data == 0: - raise ValueError('No input specified. Cannot continue.') + raise ValueError('No input specified. Cannot continue ' + 'creating an element of %s.' % (self,)) - try: - if coefficient is not None: + from growth_group import combine_exceptions + if coefficient is not None: + try: data = self.growth_group(data) - try: - return self.element_class(self, data, coefficient) - except: - raise + except (ValueError, TypeError) as e: + raise combine_exceptions( + ValueError('Growth %s is not in %s.' % (data, self)), e) + return self.element_class(self, data, coefficient) + + try: + growth, coefficient = self._split_growth_and_coefficient_(data) + except ValueError as e: + raise combine_exceptions( + ValueError('%s is not in %s.' % (data, self)), e) + + return self.element_class(self, growth, coefficient) + + + def _split_growth_and_coefficient_(self, data): + factors = self._get_factors_(data) + + growth_group = self.growth_group + coefficient_ring = self.base_ring + + coefficient = coefficient_ring.one() + growth = self.growth_group.one() + for f in factors: + try: + g = growth_group(f) + except (ValueError, TypeError): + pass + else: + growth *= g + continue + try: + c = coefficient_ring(f) + except (ValueError, TypeError): + pass else: - P = data.parent() - from sage.symbolic.ring import SR - import operator - from sage.symbolic.operators import mul_vararg - if P is SR: - op = data.operator() - if op == mul_vararg: - data, coef_tmp = data.operands() - data = self.growth_group(data) - elif op in (operator.pow, None) or\ - isinstance(op, sage.functions.log.Function_log): - coef_tmp = 1 - data = self.growth_group(data) - else: - coeffs = data.coefficients() - if type(coeffs) == list: - # (multivariate) polynomial ring - coef_tmp = coeffs[0] - data = self.growth_group(data / coef_tmp) - elif type(coeffs) == dict: - # power series ring - coef_tmp = coeffs.values()[0] - data = self.growth_group(data / coef_tmp) - - return self.element_class(self, data, coef_tmp) - except (ValueError, AttributeError): - if coefficient is None: - raise ValueError('Coefficient is not specified. ' - 'Cannot continue.') - elif coefficient not in self.base_ring: - raise ValueError('%s is not in %s' - % (coefficient, self.base_ring)) - elif coefficient == 0: - raise ValueError('0 is not a valid coefficient.') - raise ValueError('Input is ambiguous: cannot convert %s with ' - 'coefficient %s to a term with coefficient.' - % (data, coefficient)) + coefficient *= c + continue + raise ValueError('Factor %s of %s is neither a coefficient (in %s) ' + 'nor growth (in %s).' % + (f, data, coefficient_ring, growth_group)) + + return (growth, coefficient) + + + def _get_factors_(self, data): + + if isinstance(data, str): + from growth_group import split_str_by_mul + return split_str_by_mul(data) + + try: + P = data.parent() + except AttributeError: + return (data,) + + from sage.symbolic.ring import SR + if P is SR: + from sage.symbolic.operators import mul_vararg + op = data.operator() + if op == mul_vararg: + return data.operands() + + return (data,) def _repr_(self): @@ -2406,7 +2445,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: OT = atm.TermMonoid('O', G); OT - Asymptotic O-Term Monoid x^ZZ + O-Term Monoid x^ZZ sage: ET = atm.TermMonoid('exact', G, ZZ); ET Exact Term Monoid x^ZZ with coefficients from Integer Ring """ @@ -2456,7 +2495,7 @@ def create_object(self, version, key, **kwds): sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: atm.TermMonoid('O', G) # indirect doctest - Asymptotic O-Term Monoid x^ZZ + O-Term Monoid x^ZZ sage: atm.TermMonoid('exact', G, ZZ) # indirect doctest Exact Term Monoid x^ZZ with coefficients from Integer Ring """ From da0a68aa4e63d45d9b656e0256d12a4b9386e601 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 14:32:20 +0200 Subject: [PATCH 0575/1872] term: rename base_ring to coefficient_ring --- src/sage/rings/asymptotic/term_monoid.py | 70 ++++++++++++------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 442aad2a0ed..eca673f3e3b 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -21,7 +21,7 @@ - :class:`TermWithCoefficient` -- abstract base class for asymptotic terms with coefficients. - :class:`ExactTerm` -- this class represents a growth element - multiplied with some non-zero coefficient from a base ring. + multiplied with some non-zero coefficient from a coefficient ring. A characteristic property of asymptotic terms is that some terms are able to "absorb" other terms (see @@ -474,7 +474,7 @@ def can_absorb(self, other): sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() sage: OT = atm.OTermMonoid(growth_group=G) - sage: ET = atm.ExactTermMonoid(growth_group=G, base_ring=QQ) + sage: ET = atm.ExactTermMonoid(growth_group=G, coefficient_ring=QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: et1 = ET(x^2, 2) @@ -576,7 +576,7 @@ def absorb(self, other, check=True): sage: import sage.rings.asymptotic.growth_group as agg sage: G_QQ = agg.GrowthGroup('x^QQ'); x = G_QQ.gen() sage: OT = atm.OTermMonoid(G_QQ) - sage: ET = atm.ExactTermMonoid(growth_group=G_QQ, base_ring=QQ) + sage: ET = atm.ExactTermMonoid(growth_group=G_QQ, coefficient_ring=QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: et1 = ET(x, 100); et2 = ET(x^2, 2) sage: et3 = ET(x^2, 1); et4 = ET(x^2, -2) @@ -1568,7 +1568,7 @@ class TermWithCoefficient(GenericTerm): - ``growth`` -- an asymptotic growth element of the parent's growth group. - - ``coefficient`` -- an element of the parent's base ring. + - ``coefficient`` -- an element of the parent's coefficient ring. EXAMPLES:: @@ -1597,7 +1597,7 @@ def __init__(self, parent, growth, coefficient): sage: CT_ZZ = atm.TermWithCoefficientMonoid(G, ZZ) sage: CT_QQ = atm.TermWithCoefficientMonoid(G, QQ) - The coefficients have to be from the given base ring:: + The coefficients have to be from the given coefficient ring:: sage: t = CT_ZZ(x, 1/2) Traceback (most recent call last): @@ -1624,7 +1624,7 @@ def __init__(self, parent, growth, coefficient): Asymptotic Term with coefficient 42 and growth x^42 """ try: - coefficient = parent.base_ring(coefficient) + coefficient = parent.coefficient_ring(coefficient) except (ValueError, TypeError): raise ValueError('%s is not a coefficient in %s.' % (coefficient, parent)) @@ -1809,7 +1809,7 @@ class TermWithCoefficientMonoid(GenericTermMonoid): of ``Join of Category of monoids and Category of posets``. This is also the default category if ``None`` is specified. - - ``base_ring`` -- the ring which contains the + - ``coefficient_ring`` -- the ring which contains the coefficients of the elements. EXAMPLES:: @@ -1834,7 +1834,7 @@ class TermWithCoefficientMonoid(GenericTermMonoid): Element = TermWithCoefficient @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, growth_group, base_ring, category=None): + def __init__(self, growth_group, coefficient_ring, category=None): r""" For more information see :class:`TermWithCoefficientMonoid`. @@ -1850,16 +1850,16 @@ def __init__(self, growth_group, base_ring, category=None): sage: T_QQ.category() Join of Category of monoids and Category of posets """ - if base_ring is None: - raise ValueError('Base ring is not specified.') - self._base_ring_ = base_ring + if coefficient_ring is None: + raise ValueError('Coefficient ring is not specified.') + self._coefficient_ring_ = coefficient_ring super(TermWithCoefficientMonoid, self).__init__(growth_group=growth_group, category=category) @property - def base_ring(self): + def coefficient_ring(self): r""" - The base ring of this term monoid, i.e. the ring where + The coefficient ring of this term monoid, i.e. the ring where the coefficients are from. EXAMPLES:: @@ -1867,10 +1867,10 @@ def base_ring(self): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.ExactTermMonoid(G, ZZ).base_ring # indirect doctest + sage: atm.ExactTermMonoid(G, ZZ).coefficient_ring # indirect doctest Integer Ring """ - return self._base_ring_ + return self._coefficient_ring_ def _coerce_map_from_(self, S): @@ -1888,8 +1888,8 @@ def _coerce_map_from_(self, S): .. NOTE:: Another term monoid ``S`` coerces into this exact term - monoid if both, the base ring as well as the growth - group underlying ``S`` coerce into the base ring and the + monoid if both, the coefficient ring as well as the growth + group underlying ``S`` coerce into the coefficient ring and the growth group underlying this term monoid. EXAMPLES:: @@ -1909,7 +1909,7 @@ def _coerce_map_from_(self, S): """ if isinstance(S, TermWithCoefficientMonoid): return (super(TermWithCoefficientMonoid, self)._coerce_map_from_(S) and - self.base_ring.has_coerce_map_from(S.base_ring)) + self.coefficient_ring.has_coerce_map_from(S.coefficient_ring)) def _element_constructor_(self, data, coefficient=None): @@ -1922,7 +1922,7 @@ def _element_constructor_(self, data, coefficient=None): - ``data`` -- a growth element or an object representing the element to be initialized. - - ``coefficient`` -- an element of the base ring. + - ``coefficient`` -- an element of the coefficient ring. OUTPUT: @@ -1998,7 +1998,7 @@ def _split_growth_and_coefficient_(self, data): factors = self._get_factors_(data) growth_group = self.growth_group - coefficient_ring = self.base_ring + coefficient_ring = self.coefficient_ring coefficient = coefficient_ring.one() growth = self.growth_group.one() @@ -2067,7 +2067,7 @@ def _repr_(self): 'Term Monoid x^ZZ with coefficients from Integer Ring' """ return 'Term Monoid %s with coefficients from ' \ - '%s' % (self.growth_group._repr_short_(), self.base_ring) + '%s' % (self.growth_group._repr_short_(), self.coefficient_ring) def _an_element_(self): @@ -2095,7 +2095,7 @@ def _an_element_(self): 1/2*x """ return self(self.growth_group.an_element(), - self.base_ring.an_element()) + self.coefficient_ring.an_element()) def some_elements(self): @@ -2126,7 +2126,7 @@ def some_elements(self): """ return iter(self(g, c) for g, c in product_diagonal( self.growth_group.some_elements(), - iter(c for c in self.base_ring.some_elements() if c != 0))) + iter(c for c in self.coefficient_ring.some_elements() if c != 0))) class ExactTerm(TermWithCoefficient): @@ -2142,7 +2142,7 @@ class ExactTerm(TermWithCoefficient): - ``growth`` -- an asymptotic growth element from ``parent.growth_group``. - - ``coefficient`` -- an element from ``parent.base_ring``. + - ``coefficient`` -- an element from ``parent.coefficient_ring``. EXAMPLES:: @@ -2365,7 +2365,7 @@ class ExactTermMonoid(TermWithCoefficientMonoid): of ``Join of Category of monoids and Category of posets``. This is also the default category if ``None`` is specified. - - ``base_ring`` -- the ring which contains the coefficients of + - ``coefficient_ring`` -- the ring which contains the coefficients of the elements. EXAMPLES:: @@ -2414,7 +2414,7 @@ def _repr_(self): 'Exact Term Monoid x^ZZ with coefficients from Rational Field' """ return 'Exact Term Monoid %s with coefficients from %s' % \ - (self.growth_group._repr_short_(), self.base_ring) + (self.growth_group._repr_short_(), self.coefficient_ring) class TermMonoidFactory(sage.structure.factory.UniqueFactory): @@ -2433,7 +2433,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): - ``growth_group`` -- a growth group. - - ``base_ring`` -- the base ring for coefficients. + - ``coefficient_ring`` -- a ring. OUTPUT: @@ -2449,7 +2449,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: ET = atm.TermMonoid('exact', G, ZZ); ET Exact Term Monoid x^ZZ with coefficients from Integer Ring """ - def create_key_and_extra_args(self, term, growth_group, base_ring=None, + def create_key_and_extra_args(self, term, growth_group, coefficient_ring=None, **kwds): r""" Given the arguments and keyword, create a key that uniquely @@ -2467,7 +2467,7 @@ def create_key_and_extra_args(self, term, growth_group, base_ring=None, sage: atm.TermMonoid.create_key_and_extra_args('exact', G) Traceback (most recent call last): ... - ValueError: A base ring has to be specified + ValueError: A coefficient ring has to be specified """ if term not in ['O', 'exact']: raise ValueError("%s has to be either 'exact' or 'O'" % term) @@ -2477,12 +2477,12 @@ def create_key_and_extra_args(self, term, growth_group, base_ring=None, raise ValueError("%s has to be an asymptotic growth group" % growth_group) - if term == 'exact' and base_ring is None: - raise ValueError("A base ring has to be specified") + if term == 'exact' and coefficient_ring is None: + raise ValueError("A coefficient ring has to be specified") elif term == 'O': - base_ring = None + coefficient_ring = None - return (term, growth_group, base_ring), kwds + return (term, growth_group, coefficient_ring), kwds def create_object(self, version, key, **kwds): @@ -2500,11 +2500,11 @@ def create_object(self, version, key, **kwds): Exact Term Monoid x^ZZ with coefficients from Integer Ring """ - term, growth_group, base_ring = key + term, growth_group, coefficient_ring = key if term == 'O': return OTermMonoid(growth_group, **kwds) else: - return ExactTermMonoid(growth_group, base_ring, **kwds) + return ExactTermMonoid(growth_group, coefficient_ring, **kwds) TermMonoid = TermMonoidFactory("TermMonoid") From ffe1db8583dded9de193a08e14704cf4ab87122a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 15:20:51 +0200 Subject: [PATCH 0576/1872] make it working again and fix doctests --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 +- src/sage/rings/asymptotic/term_monoid.py | 326 ++++++++----------- 2 files changed, 143 insertions(+), 195 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 4bf04c39190..b186140072a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -65,12 +65,8 @@ experimental. It, its functionality or its interface might change without a formal deprecation. See http://trac.sagemath.org/17601 for details. - sage: from sage.rings.asymptotic.term_monoid import TermMonoid - sage: T = TermMonoid('exact', G, ZZ) - 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/17601 for details. + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: T = GenericTermMonoid(G, ZZ) sage: R. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change @@ -592,7 +588,7 @@ def _simplify_(self): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: G = GrowthGroup('x^ZZ') - sage: OT = TermMonoid('O', G); ET = TermMonoid('exact', G, ZZ) + sage: OT = TermMonoid('O', G, ZZ); ET = TermMonoid('exact', G, ZZ) sage: R = AsymptoticRing(G, ZZ) sage: lst = [ET(x,1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] sage: expr = R(lst, simplify=False); expr # indirect doctest @@ -718,7 +714,7 @@ def _mul_term_(self, term): sage: from sage.rings.asymptotic.term_monoid import OTermMonoid sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) - sage: T = OTermMonoid(R.growth_group) + sage: T = OTermMonoid(R.growth_group, ZZ) sage: expr = 10*x^2 + O(x) sage: t = T(R.growth_group.gen()) sage: expr._mul_term_(t) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index eca673f3e3b..4f67b6001f0 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -59,11 +59,7 @@ experimental. It, its functionality or its interface might change without a formal deprecation. See http://trac.sagemath.org/17601 for details. - sage: T = atm.TermWithCoefficientMonoid(G, ZZ) - 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/17601 for details. + sage: T = atm.GenericTermMonoid(G, ZZ) """ # ***************************************************************************** @@ -216,7 +212,7 @@ def absorption(left, right): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') - sage: T = atm.TermMonoid('O', G) + sage: T = atm.TermMonoid('O', G, ZZ) sage: atm.absorption(T(x^2), T(x^3)) O(x^3) sage: atm.absorption(T(x^3), T(x^2)) @@ -253,7 +249,7 @@ def can_absorb(left, right): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') - sage: T = atm.TermMonoid('O', G) + sage: T = atm.TermMonoid('O', G, ZZ) sage: atm.can_absorb(T(x^2), T(x^3)) True sage: atm.can_absorb(T(x^3), T(x^2)) @@ -278,7 +274,7 @@ class GenericTerm(sage.structure.element.MonoidElement): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2); (t1, t2) (Generic Term with growth x, Generic Term with growth x^2) sage: t1 * t2 @@ -302,7 +298,7 @@ def __init__(self, parent, growth): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, ZZ) sage: T(x^2) Generic Term with growth x^2 """ @@ -341,7 +337,7 @@ def _mul_(self, other): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, ZZ) sage: t1 = T(x); t2 = T(x^2) sage: t1, t2 (Generic Term with growth x, Generic Term with growth x^2) @@ -376,7 +372,7 @@ def __div__(self, other): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2) sage: t1 / t2 # indirect doctest Traceback (most recent call last): @@ -416,7 +412,7 @@ def _div_(self, other): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2) sage: t1 / t2 # indirect doctest Traceback (most recent call last): @@ -440,7 +436,7 @@ def __invert__(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: ~T(x) # indirect doctest Traceback (most recent call last): ... @@ -473,8 +469,8 @@ def can_absorb(self, other): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(growth_group=G) - sage: ET = atm.ExactTermMonoid(growth_group=G, coefficient_ring=QQ) + sage: OT = atm.OTermMonoid(G, ZZ) + sage: ET = atm.ExactTermMonoid(G, coefficient_ring=QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: et1 = ET(x^2, 2) @@ -529,7 +525,7 @@ def _can_absorb_(self, other): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GenericGrowthGroup(ZZ) - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: g1 = G(raw_element=21); g2 = G(raw_element=42) sage: t1 = T(g1); t2 = T(g2) sage: t1.can_absorb(t2) # indirect doctest @@ -575,8 +571,8 @@ def absorb(self, other, check=True): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G_QQ = agg.GrowthGroup('x^QQ'); x = G_QQ.gen() - sage: OT = atm.OTermMonoid(G_QQ) - sage: ET = atm.ExactTermMonoid(growth_group=G_QQ, coefficient_ring=QQ) + sage: OT = atm.OTermMonoid(G_QQ, ZZ) + sage: ET = atm.ExactTermMonoid(G_QQ, coefficient_ring=QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: et1 = ET(x, 100); et2 = ET(x^2, 2) sage: et3 = ET(x^2, 1); et4 = ET(x^2, -2) @@ -680,7 +676,7 @@ def _absorb_(self, other): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2) When it comes to absorption, note that the method @@ -717,8 +713,8 @@ def __le__(self, other): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: GT = atm.GenericTermMonoid(G) - sage: OT = atm.OTermMonoid(G) + sage: GT = atm.GenericTermMonoid(G, QQ) + sage: OT = atm.OTermMonoid(G, QQ) sage: ET_ZZ = atm.ExactTermMonoid(G, ZZ) sage: ET_QQ = atm.ExactTermMonoid(G, QQ) sage: g1 = GT(x); g2 = GT(x^2); g1, g2 @@ -796,7 +792,7 @@ def _le_(self, other): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: t1 = T(x^-2); t2 = T(x^5); t1, t2 (Generic Term with growth x^(-2), Generic Term with growth x^5) sage: t1._le_(t2) @@ -829,9 +825,9 @@ def is_same(self, other): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, ....: ExactTermMonoid, OTermMonoid) - sage: GT = GenericTermMonoid(GrowthGroup('x^ZZ')) + sage: GT = GenericTermMonoid(GrowthGroup('x^ZZ'), QQ) sage: ET = ExactTermMonoid(GrowthGroup('x^ZZ'), ZZ) - sage: OT = OTermMonoid(GrowthGroup('x^ZZ')) + sage: OT = OTermMonoid(GrowthGroup('x^ZZ'), QQ) sage: g = GT.an_element(); e = ET.an_element(); o = OT.an_element() sage: g, e, o (Generic Term with growth x, x, O(x)) @@ -882,7 +878,7 @@ def _is_same_(self, other): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid - sage: T = GenericTermMonoid(GrowthGroup('x^ZZ')) + sage: T = GenericTermMonoid(GrowthGroup('x^ZZ'), QQ) sage: t = T.an_element() sage: t.is_same(t) Traceback (most recent call last): @@ -909,7 +905,7 @@ def _repr_(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(growth_group=G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: T(x)._repr_() 'Generic Term with growth x' sage: T(x^7)._repr_() @@ -928,6 +924,9 @@ class GenericTermMonoid(sage.structure.parent.Parent, - ``growth_group`` -- a partially ordered group (e.g. an instance of :class:`~sage.rings.asymptotic.growth_group.GenericGrowthGroup`). + - ``coefficient_ring`` -- a ring which contains the (maybe implicit) + coefficients of the elements. + - ``category`` -- The category of the parent can be specified in order to broaden the base structure. It has to be a subcategory of ``Join of Category of Monoids and Category of posets``. This @@ -949,18 +948,19 @@ class GenericTermMonoid(sage.structure.parent.Parent, sage: import sage.rings.asymptotic.growth_group as agg sage: G_x = agg.GrowthGroup('x^ZZ'); x = G_x.gen() sage: G_y = agg.GrowthGroup('y^QQ'); y = G_y.gen() - sage: T_x_ZZ = atm.GenericTermMonoid(G_x); T_y_QQ = atm.GenericTermMonoid(G_y) + sage: T_x_ZZ = atm.GenericTermMonoid(G_x, QQ) + sage: T_y_QQ = atm.GenericTermMonoid(G_y, QQ) sage: T_x_ZZ - Generic Term Monoid x^ZZ + Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field sage: T_y_QQ - Generic Term Monoid y^QQ + Generic Term Monoid y^QQ with (implicit) coefficients from Rational Field """ # enable the category framework for elements Element = GenericTerm @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, growth_group, category=None): + def __init__(self, growth_group, coefficient_ring, category=None): r""" See :class:`GenericTermMonoid` for more information. @@ -969,22 +969,34 @@ def __init__(self, growth_group, category=None): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G_x = agg.GrowthGroup('x^ZZ') - sage: T_x = atm.GenericTermMonoid(G_x); T_x - Generic Term Monoid x^ZZ + sage: T_x = atm.GenericTermMonoid(G_x, QQ); T_x + Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field sage: T_x.growth_group Growth Group x^ZZ sage: G_y = agg.GrowthGroup('y^QQ') - sage: T_y = atm.GenericTermMonoid(G_y); T_y - Generic Term Monoid y^QQ + sage: T_y = atm.GenericTermMonoid(G_y, QQ); T_y + Generic Term Monoid y^QQ with (implicit) coefficients from Rational Field sage: T_x is T_y False :: - sage: atm.GenericTermMonoid(None) + sage: atm.GenericTermMonoid(None, None) Traceback (most recent call last): ... ValueError: Growth Group has to be specified + + :: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() + sage: T_ZZ = atm.TermWithCoefficientMonoid(G, ZZ); T_ZZ + Generic Term Monoid x^ZZ with (implicit) coefficients from Integer Ring + sage: T_QQ = atm.TermWithCoefficientMonoid(G, QQ); T_QQ + Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field + sage: T_QQ.category() + Join of Category of monoids and Category of posets """ from sage.categories.monoids import Monoids from sage.categories.posets import Posets @@ -999,6 +1011,7 @@ def __init__(self, growth_group, category=None): category): raise ValueError('%s is not a subcategory of %s' % (category, Monoids() & Posets())) + if growth_group is None: raise ValueError('Growth Group has to be specified') else: @@ -1006,8 +1019,14 @@ def __init__(self, growth_group, category=None): raise ValueError('%s does not inherit from %s' % (growth_group, GenericGrowthGroup())) self._growth_group_ = growth_group + + if coefficient_ring is None: + raise ValueError('Coefficient ring is not specified.') + self._coefficient_ring_ = coefficient_ring + super(GenericTermMonoid, self).__init__(category=category) + @property def growth_group(self): r""" @@ -1024,6 +1043,23 @@ def growth_group(self): return self._growth_group_ + @property + def coefficient_ring(self): + r""" + The coefficient ring of this term monoid, i.e. the ring where + the coefficients are from. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: import sage.rings.asymptotic.term_monoid as atm + sage: G = agg.GrowthGroup('x^ZZ') + sage: atm.GenericTermMonoid(G, ZZ).coefficient_ring + Integer Ring + """ + return self._coefficient_ring_ + + def _repr_(self): r""" A representation string for this generic term monoid. @@ -1041,13 +1077,14 @@ def _repr_(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GenericGrowthGroup(ZZ) - sage: atm.GenericTermMonoid(G)._repr_() - 'Generic Term Monoid Generic(ZZ)' + sage: atm.GenericTermMonoid(G, QQ)._repr_() + 'Generic Term Monoid Generic(ZZ) with (implicit) coefficients from Rational Field' sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.GenericTermMonoid(growth_group=G)._repr_() - 'Generic Term Monoid x^ZZ' + sage: atm.GenericTermMonoid(G, QQ)._repr_() + 'Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field' """ - return 'Generic Term Monoid %s' % (self.growth_group._repr_short_(), ) + return 'Generic Term Monoid %s with (implicit) coefficients from %s' % \ + (self.growth_group._repr_short_(), self.coefficient_ring) def _coerce_map_from_(self, S): @@ -1074,16 +1111,32 @@ def _coerce_map_from_(self, S): sage: import sage.rings.asymptotic.growth_group as agg sage: G_ZZ = agg.GrowthGroup('x^ZZ') sage: G_ZZ = agg.GrowthGroup('x^ZZ') - sage: T_ZZ = atm.GenericTermMonoid(growth_group=G_ZZ); T_ZZ - Generic Term Monoid x^ZZ + sage: T_ZZ = atm.GenericTermMonoid(G_ZZ, QQ); T_ZZ + Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field sage: G_QQ = agg.GrowthGroup('x^QQ') - sage: T_QQ = atm.GenericTermMonoid(growth_group=G_QQ); T_QQ - Generic Term Monoid x^QQ + sage: T_QQ = atm.GenericTermMonoid(G_QQ, QQ); T_QQ + Generic Term Monoid x^QQ with (implicit) coefficients from Rational Field sage: T_QQ.has_coerce_map_from(T_ZZ) # indirect doctest True + + :: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: G_ZZ = agg.GrowthGroup('x^ZZ') + sage: G_QQ = agg.GrowthGroup('x^QQ') + sage: TC_ZZ = atm.TermWithCoefficientMonoid(G_ZZ, ZZ); TC_ZZ + Generic Term Monoid x^ZZ with (implicit) coefficients from Integer Ring + sage: TC_QQ = atm.TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ + Generic Term Monoid x^QQ with (implicit) coefficients from Rational Field + sage: TC_QQ.has_coerce_map_from(TC_ZZ) # indirect doctest + True + sage: TC_ZZ.has_coerce_map_from(TC_QQ) # indirect doctest + False """ if isinstance(S, self.__class__): - if self.growth_group.has_coerce_map_from(S.growth_group): + if self.growth_group.has_coerce_map_from(S.growth_group) and \ + self.coefficient_ring.has_coerce_map_from(S.coefficient_ring): return True @@ -1113,8 +1166,8 @@ def _element_constructor_(self, data): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G_ZZ = GrowthGroup('x^ZZ') sage: G_QQ = GrowthGroup('x^QQ') - sage: T_ZZ = atm.GenericTermMonoid(growth_group=G_ZZ) - sage: T_QQ = atm.GenericTermMonoid(growth_group=G_QQ) + sage: T_ZZ = atm.GenericTermMonoid(G_ZZ, QQ) + sage: T_QQ = atm.GenericTermMonoid(G_QQ, QQ) sage: term1 = T_ZZ(G_ZZ.gen()) sage: term2 = T_QQ(G_QQ.gen()^2) sage: term1 <= term2 # in order for two terms to be compared, @@ -1138,12 +1191,13 @@ def _element_constructor_(self, data): sage: T_ZZ(10 * x^2) Traceback (most recent call last): ... - ValueError: Growth 10*x^2 is not in Generic Term Monoid x^ZZ. + ValueError: Growth 10*x^2 is not in Generic Term Monoid x^ZZ + with (implicit) coefficients from Rational Field. > *previous* ValueError: 10*x^2 is not in Growth Group x^ZZ. TESTS:: - sage: O_ZZ = atm.OTermMonoid(growth_group=G_ZZ) + sage: O_ZZ = atm.OTermMonoid(G_ZZ, QQ) sage: O_ZZ(x^11) O(x^11) sage: O_ZZ(2*x^11) @@ -1185,9 +1239,9 @@ def _an_element_(self): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.OTermMonoid(G).an_element() # indirect doctest + sage: atm.OTermMonoid(G, QQ).an_element() # indirect doctest O(x) - sage: atm.GenericTermMonoid(G).an_element() # indirect doctest + sage: atm.GenericTermMonoid(G, QQ).an_element() # indirect doctest Generic Term with growth x """ return self(self.growth_group.an_element()) @@ -1212,7 +1266,7 @@ def some_elements(self): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') - sage: tuple(atm.OTermMonoid(G).some_elements()) + sage: tuple(atm.OTermMonoid(G, QQ).some_elements()) (O(1), O(x), O(1/x), O(x^2), O(x^(-2)), O(x^3), ...) """ return iter(self(g) for g in self.growth_group.some_elements()) @@ -1238,7 +1292,7 @@ def le(self, left, right): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(growth_group=G) + sage: T = atm.GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2) sage: T.le(t1, t2) True @@ -1265,7 +1319,7 @@ class OTerm(GenericTerm): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(G) + sage: OT = atm.OTermMonoid(G, QQ) sage: t1 = OT(x^-7); t2 = OT(x^5); t3 = OT(x^42) sage: t1, t2, t3 (O(x^(-7)), O(x^5), O(x^42)) @@ -1306,7 +1360,7 @@ def _repr_(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(G) + sage: OT = atm.OTermMonoid(G, QQ) sage: t1 = OT(x); t2 = OT(x^2); t3 = OT(x^3) sage: t1._repr_(), t2._repr_() ('O(x)', 'O(x^2)') @@ -1329,7 +1383,7 @@ def __invert__(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.OTermMonoid(G) + sage: T = atm.OTermMonoid(G, QQ) sage: ~T(x) # indirect doctest Traceback (most recent call last): ... @@ -1359,7 +1413,7 @@ def _can_absorb_(self, other): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm - sage: OT = atm.TermMonoid('O', agg.GrowthGroup('x^ZZ')) + sage: OT = atm.TermMonoid('O', agg.GrowthGroup('x^ZZ'), QQ) sage: t1 = OT(x^21); t2 = OT(x^42) sage: t1.can_absorb(t2) # indirect doctest False @@ -1396,7 +1450,7 @@ def _absorb_(self, other): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(growth_group=G) + sage: OT = atm.OTermMonoid(G, QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: ot1.absorb(ot1) O(x) @@ -1432,7 +1486,7 @@ def _is_same_(self, other): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import OTermMonoid - sage: OT = OTermMonoid(GrowthGroup('x^ZZ')) + sage: OT = OTermMonoid(GrowthGroup('x^ZZ'), QQ) sage: t = OT.an_element(); t O(x) sage: t.is_same(OT(x)) # indirect doctest @@ -1462,17 +1516,17 @@ class OTermMonoid(GenericTermMonoid): sage: import sage.rings.asymptotic.growth_group as agg sage: G_x_ZZ = agg.GrowthGroup('x^ZZ') sage: G_y_QQ = agg.GrowthGroup('y^QQ') - sage: OT_x_ZZ = atm.OTermMonoid(G_x_ZZ); OT_x_ZZ + sage: OT_x_ZZ = atm.OTermMonoid(G_x_ZZ, QQ); OT_x_ZZ O-Term Monoid x^ZZ - sage: OT_y_QQ = atm.OTermMonoid(G_y_QQ); OT_y_QQ + sage: OT_y_QQ = atm.OTermMonoid(G_y_QQ, QQ); OT_y_QQ O-Term Monoid y^QQ `O`-term monoids can also be created by using the :class:`term factory `:: - sage: atm.TermMonoid('O', G_x_ZZ) is OT_x_ZZ + sage: atm.TermMonoid('O', G_x_ZZ, QQ) is OT_x_ZZ True - sage: atm.TermMonoid('O', agg.GrowthGroup('x^QQ')) + sage: atm.TermMonoid('O', agg.GrowthGroup('x^QQ'), QQ) O-Term Monoid x^QQ """ # enable the category framework for elements @@ -1509,8 +1563,8 @@ def _coerce_map_from_(self, S): sage: import sage.rings.asymptotic.growth_group as agg sage: G_ZZ = agg.GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() sage: G_QQ = agg.GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() - sage: OT_ZZ = atm.OTermMonoid(G_ZZ) - sage: OT_QQ = atm.OTermMonoid(G_QQ) + sage: OT_ZZ = atm.OTermMonoid(G_ZZ, QQ) + sage: OT_QQ = atm.OTermMonoid(G_QQ, QQ) sage: ET = atm.ExactTermMonoid(G_ZZ, ZZ) Now, the :class:`OTermMonoid` whose growth group is over the @@ -1550,7 +1604,7 @@ def _repr_(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: atm.OTermMonoid(G)._repr_() + sage: atm.OTermMonoid(G, QQ)._repr_() 'O-Term Monoid x^ZZ' """ return 'O-Term Monoid %s' % (self.growth_group._repr_short_(),) @@ -1603,7 +1657,7 @@ def __init__(self, parent, growth, coefficient): Traceback (most recent call last): ... ValueError: 1/2 is not a coefficient in - Term Monoid x^ZZ with coefficients from Integer Ring. + Generic Term Monoid x^ZZ with (implicit) coefficients from Integer Ring. sage: t = CT_QQ(x, 1/2); t Asymptotic Term with coefficient 1/2 and growth x @@ -1613,7 +1667,7 @@ def __init__(self, parent, growth, coefficient): Traceback (most recent call last): ... ValueError: Zero coefficient 0 is not allowed in - Term Monoid x^ZZ with coefficients from Integer Ring. + Generic Term Monoid x^ZZ with (implicit) coefficients from Integer Ring. The conversion of growth elements also works for the creation of terms with coefficient:: @@ -1819,98 +1873,20 @@ class TermWithCoefficientMonoid(GenericTermMonoid): sage: G_ZZ = agg.GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() sage: G_QQ = agg.GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() sage: TC_ZZ = atm.TermWithCoefficientMonoid(G_ZZ, QQ); TC_ZZ - Term Monoid x^ZZ with coefficients from Rational Field + Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field sage: TC_QQ = atm.TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ - Term Monoid x^QQ with coefficients from Rational Field + Generic Term Monoid x^QQ with (implicit) coefficients from Rational Field sage: TC_ZZ == TC_QQ or TC_ZZ is TC_QQ False sage: TC_QQ.coerce_map_from(TC_ZZ) Conversion map: - From: Term Monoid x^ZZ with coefficients from Rational Field - To: Term Monoid x^QQ with coefficients from Rational Field + From: Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field + To: Generic Term Monoid x^QQ with (implicit) coefficients from Rational Field """ # enable the category framework for elements Element = TermWithCoefficient - @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, growth_group, coefficient_ring, category=None): - r""" - For more information see :class:`TermWithCoefficientMonoid`. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T_ZZ = atm.TermWithCoefficientMonoid(G, ZZ); T_ZZ - Term Monoid x^ZZ with coefficients from Integer Ring - sage: T_QQ = atm.TermWithCoefficientMonoid(G, QQ); T_QQ - Term Monoid x^ZZ with coefficients from Rational Field - sage: T_QQ.category() - Join of Category of monoids and Category of posets - """ - if coefficient_ring is None: - raise ValueError('Coefficient ring is not specified.') - self._coefficient_ring_ = coefficient_ring - super(TermWithCoefficientMonoid, - self).__init__(growth_group=growth_group, category=category) - - @property - def coefficient_ring(self): - r""" - The coefficient ring of this term monoid, i.e. the ring where - the coefficients are from. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.ExactTermMonoid(G, ZZ).coefficient_ring # indirect doctest - Integer Ring - """ - return self._coefficient_ring_ - - - def _coerce_map_from_(self, S): - r""" - Return if ``S`` coerces into this term monoid. - - INPUT: - - - ``S`` -- a parent. - - OUTPUT: - - A boolean. - - .. NOTE:: - - Another term monoid ``S`` coerces into this exact term - monoid if both, the coefficient ring as well as the growth - group underlying ``S`` coerce into the coefficient ring and the - growth group underlying this term monoid. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.GrowthGroup('x^ZZ') - sage: G_QQ = agg.GrowthGroup('x^QQ') - sage: TC_ZZ = atm.TermWithCoefficientMonoid(G_ZZ, ZZ); TC_ZZ - Term Monoid x^ZZ with coefficients from Integer Ring - sage: TC_QQ = atm.TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ - Term Monoid x^QQ with coefficients from Rational Field - sage: TC_QQ.has_coerce_map_from(TC_ZZ) # indirect doctest - True - sage: TC_ZZ.has_coerce_map_from(TC_QQ) # indirect doctest - False - """ - if isinstance(S, TermWithCoefficientMonoid): - return (super(TermWithCoefficientMonoid, self)._coerce_map_from_(S) and - self.coefficient_ring.has_coerce_map_from(S.coefficient_ring)) - def _element_constructor_(self, data, coefficient=None): r""" @@ -2045,31 +2021,6 @@ def _get_factors_(self, data): return (data,) - def _repr_(self): - r""" - A representation string for this monoid of terms with - coefficient. - - INPUT: - - Nothing. - - OUTPUT: - - A string. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.TermWithCoefficientMonoid(G, ZZ)._repr_() - 'Term Monoid x^ZZ with coefficients from Integer Ring' - """ - return 'Term Monoid %s with coefficients from ' \ - '%s' % (self.growth_group._repr_short_(), self.coefficient_ring) - - def _an_element_(self): r""" Return an element of this term with coefficient monoid. @@ -2161,7 +2112,7 @@ class ExactTerm(TermWithCoefficient): They may also be multiplied with `O`-terms:: - sage: OT = atm.OTermMonoid(G) + sage: OT = atm.OTermMonoid(G, QQ) sage: ET(x^2, 42) * OT(x) O(x^3) @@ -2444,7 +2395,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') - sage: OT = atm.TermMonoid('O', G); OT + sage: OT = atm.TermMonoid('O', G, QQ); OT O-Term Monoid x^ZZ sage: ET = atm.TermMonoid('exact', G, ZZ); ET Exact Term Monoid x^ZZ with coefficients from Integer Ring @@ -2460,14 +2411,15 @@ def create_key_and_extra_args(self, term, growth_group, coefficient_ring=None, sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.TermMonoid.create_key_and_extra_args('O', G) - (('O', Growth Group x^ZZ, None), {}) + sage: atm.TermMonoid.create_key_and_extra_args('O', G, QQ) + (('O', Growth Group x^ZZ, Rational Field), {}) sage: atm.TermMonoid.create_key_and_extra_args('exact', G, ZZ) (('exact', Growth Group x^ZZ, Integer Ring), {}) sage: atm.TermMonoid.create_key_and_extra_args('exact', G) Traceback (most recent call last): ... ValueError: A coefficient ring has to be specified + to create a term monoid of type 'exact' """ if term not in ['O', 'exact']: raise ValueError("%s has to be either 'exact' or 'O'" % term) @@ -2477,10 +2429,9 @@ def create_key_and_extra_args(self, term, growth_group, coefficient_ring=None, raise ValueError("%s has to be an asymptotic growth group" % growth_group) - if term == 'exact' and coefficient_ring is None: - raise ValueError("A coefficient ring has to be specified") - elif term == 'O': - coefficient_ring = None + if coefficient_ring is None: + raise ValueError("A coefficient ring has to be specified to " + "create a term monoid of type '%s'" % (term,)) return (term, growth_group, coefficient_ring), kwds @@ -2494,7 +2445,7 @@ def create_object(self, version, key, **kwds): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.TermMonoid('O', G) # indirect doctest + sage: atm.TermMonoid('O', G, QQ) # indirect doctest O-Term Monoid x^ZZ sage: atm.TermMonoid('exact', G, ZZ) # indirect doctest Exact Term Monoid x^ZZ with coefficients from Integer Ring @@ -2502,9 +2453,10 @@ def create_object(self, version, key, **kwds): term, growth_group, coefficient_ring = key if term == 'O': - return OTermMonoid(growth_group, **kwds) - else: - return ExactTermMonoid(growth_group, coefficient_ring, **kwds) + C = OTermMonoid + elif term == 'exact': + C = ExactTermMonoid + return C(growth_group, coefficient_ring, **kwds) TermMonoid = TermMonoidFactory("TermMonoid") From ff7fb300a5ecad77c79de5dad931f53400667132 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 15:24:48 +0200 Subject: [PATCH 0577/1872] change _repr_ of monoids --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +- src/sage/rings/asymptotic/term_monoid.py | 58 ++++++++++---------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b186140072a..6b9ff682bf1 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1594,7 +1594,8 @@ def create_summand(self, type, growth, **kwds): sage: R.create_summand('O', growth=42*x^2) Traceback (most recent call last): ... - ValueError: Growth 42*x^2 is not in O-Term Monoid x^ZZ. + ValueError: Growth 42*x^2 is not in O-Term Monoid x^ZZ + with implicit coefficients in Integer Ring. > *previous* ValueError: 42*x^2 is not in Growth Group x^ZZ. """ from sage.rings.asymptotic.term_monoid import TermMonoid diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 4f67b6001f0..6cf86d2d0cf 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -951,9 +951,9 @@ class GenericTermMonoid(sage.structure.parent.Parent, sage: T_x_ZZ = atm.GenericTermMonoid(G_x, QQ) sage: T_y_QQ = atm.GenericTermMonoid(G_y, QQ) sage: T_x_ZZ - Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: T_y_QQ - Generic Term Monoid y^QQ with (implicit) coefficients from Rational Field + Generic Term Monoid y^QQ with (implicit) coefficients in Rational Field """ # enable the category framework for elements @@ -970,12 +970,12 @@ def __init__(self, growth_group, coefficient_ring, category=None): sage: import sage.rings.asymptotic.growth_group as agg sage: G_x = agg.GrowthGroup('x^ZZ') sage: T_x = atm.GenericTermMonoid(G_x, QQ); T_x - Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: T_x.growth_group Growth Group x^ZZ sage: G_y = agg.GrowthGroup('y^QQ') sage: T_y = atm.GenericTermMonoid(G_y, QQ); T_y - Generic Term Monoid y^QQ with (implicit) coefficients from Rational Field + Generic Term Monoid y^QQ with (implicit) coefficients in Rational Field sage: T_x is T_y False @@ -992,9 +992,9 @@ def __init__(self, growth_group, coefficient_ring, category=None): sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() sage: T_ZZ = atm.TermWithCoefficientMonoid(G, ZZ); T_ZZ - Generic Term Monoid x^ZZ with (implicit) coefficients from Integer Ring + Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring sage: T_QQ = atm.TermWithCoefficientMonoid(G, QQ); T_QQ - Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: T_QQ.category() Join of Category of monoids and Category of posets """ @@ -1078,12 +1078,12 @@ def _repr_(self): sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GenericGrowthGroup(ZZ) sage: atm.GenericTermMonoid(G, QQ)._repr_() - 'Generic Term Monoid Generic(ZZ) with (implicit) coefficients from Rational Field' + 'Generic Term Monoid Generic(ZZ) with (implicit) coefficients in Rational Field' sage: G = agg.GrowthGroup('x^ZZ') sage: atm.GenericTermMonoid(G, QQ)._repr_() - 'Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field' + 'Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field' """ - return 'Generic Term Monoid %s with (implicit) coefficients from %s' % \ + return 'Generic Term Monoid %s with (implicit) coefficients in %s' % \ (self.growth_group._repr_short_(), self.coefficient_ring) @@ -1112,10 +1112,10 @@ def _coerce_map_from_(self, S): sage: G_ZZ = agg.GrowthGroup('x^ZZ') sage: G_ZZ = agg.GrowthGroup('x^ZZ') sage: T_ZZ = atm.GenericTermMonoid(G_ZZ, QQ); T_ZZ - Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: G_QQ = agg.GrowthGroup('x^QQ') sage: T_QQ = atm.GenericTermMonoid(G_QQ, QQ); T_QQ - Generic Term Monoid x^QQ with (implicit) coefficients from Rational Field + Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field sage: T_QQ.has_coerce_map_from(T_ZZ) # indirect doctest True @@ -1126,9 +1126,9 @@ def _coerce_map_from_(self, S): sage: G_ZZ = agg.GrowthGroup('x^ZZ') sage: G_QQ = agg.GrowthGroup('x^QQ') sage: TC_ZZ = atm.TermWithCoefficientMonoid(G_ZZ, ZZ); TC_ZZ - Generic Term Monoid x^ZZ with (implicit) coefficients from Integer Ring + Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring sage: TC_QQ = atm.TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ - Generic Term Monoid x^QQ with (implicit) coefficients from Rational Field + Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field sage: TC_QQ.has_coerce_map_from(TC_ZZ) # indirect doctest True sage: TC_ZZ.has_coerce_map_from(TC_QQ) # indirect doctest @@ -1192,7 +1192,7 @@ def _element_constructor_(self, data): Traceback (most recent call last): ... ValueError: Growth 10*x^2 is not in Generic Term Monoid x^ZZ - with (implicit) coefficients from Rational Field. + with (implicit) coefficients in Rational Field. > *previous* ValueError: 10*x^2 is not in Growth Group x^ZZ. TESTS:: @@ -1203,7 +1203,8 @@ def _element_constructor_(self, data): sage: O_ZZ(2*x^11) Traceback (most recent call last): ... - ValueError: Growth 2*x^11 is not in O-Term Monoid x^ZZ. + ValueError: Growth 2*x^11 is not in O-Term Monoid x^ZZ + with implicit coefficients in Rational Field. > *previous* ValueError: 2*x^11 is not in Growth Group x^ZZ. """ if type(data) == self.element_class and data.parent() == self: @@ -1517,9 +1518,9 @@ class OTermMonoid(GenericTermMonoid): sage: G_x_ZZ = agg.GrowthGroup('x^ZZ') sage: G_y_QQ = agg.GrowthGroup('y^QQ') sage: OT_x_ZZ = atm.OTermMonoid(G_x_ZZ, QQ); OT_x_ZZ - O-Term Monoid x^ZZ + O-Term Monoid x^ZZ with implicit coefficients in Rational Field sage: OT_y_QQ = atm.OTermMonoid(G_y_QQ, QQ); OT_y_QQ - O-Term Monoid y^QQ + O-Term Monoid y^QQ with implicit coefficients in Rational Field `O`-term monoids can also be created by using the :class:`term factory `:: @@ -1527,7 +1528,7 @@ class OTermMonoid(GenericTermMonoid): sage: atm.TermMonoid('O', G_x_ZZ, QQ) is OT_x_ZZ True sage: atm.TermMonoid('O', agg.GrowthGroup('x^QQ'), QQ) - O-Term Monoid x^QQ + O-Term Monoid x^QQ with implicit coefficients in Rational Field """ # enable the category framework for elements Element = OTerm @@ -1605,9 +1606,10 @@ def _repr_(self): sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() sage: atm.OTermMonoid(G, QQ)._repr_() - 'O-Term Monoid x^ZZ' + 'O-Term Monoid x^ZZ with implicit coefficients in Rational Field' """ - return 'O-Term Monoid %s' % (self.growth_group._repr_short_(),) + return 'O-Term Monoid %s with implicit coefficients in %s' % \ + (self.growth_group._repr_short_(), self.coefficient_ring) class TermWithCoefficient(GenericTerm): @@ -1657,7 +1659,7 @@ def __init__(self, parent, growth, coefficient): Traceback (most recent call last): ... ValueError: 1/2 is not a coefficient in - Generic Term Monoid x^ZZ with (implicit) coefficients from Integer Ring. + Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring. sage: t = CT_QQ(x, 1/2); t Asymptotic Term with coefficient 1/2 and growth x @@ -1667,7 +1669,7 @@ def __init__(self, parent, growth, coefficient): Traceback (most recent call last): ... ValueError: Zero coefficient 0 is not allowed in - Generic Term Monoid x^ZZ with (implicit) coefficients from Integer Ring. + Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring. The conversion of growth elements also works for the creation of terms with coefficient:: @@ -1873,15 +1875,15 @@ class TermWithCoefficientMonoid(GenericTermMonoid): sage: G_ZZ = agg.GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() sage: G_QQ = agg.GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() sage: TC_ZZ = atm.TermWithCoefficientMonoid(G_ZZ, QQ); TC_ZZ - Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: TC_QQ = atm.TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ - Generic Term Monoid x^QQ with (implicit) coefficients from Rational Field + Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field sage: TC_ZZ == TC_QQ or TC_ZZ is TC_QQ False sage: TC_QQ.coerce_map_from(TC_ZZ) Conversion map: - From: Generic Term Monoid x^ZZ with (implicit) coefficients from Rational Field - To: Generic Term Monoid x^QQ with (implicit) coefficients from Rational Field + From: Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field + To: Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field """ # enable the category framework for elements @@ -2396,7 +2398,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: OT = atm.TermMonoid('O', G, QQ); OT - O-Term Monoid x^ZZ + O-Term Monoid x^ZZ with implicit coefficients in Rational Field sage: ET = atm.TermMonoid('exact', G, ZZ); ET Exact Term Monoid x^ZZ with coefficients from Integer Ring """ @@ -2446,7 +2448,7 @@ def create_object(self, version, key, **kwds): sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: atm.TermMonoid('O', G, QQ) # indirect doctest - O-Term Monoid x^ZZ + O-Term Monoid x^ZZ with implicit coefficients in Rational Field sage: atm.TermMonoid('exact', G, ZZ) # indirect doctest Exact Term Monoid x^ZZ with coefficients from Integer Ring """ From 819661d309420c1b76e757ba9335061e7a2001f9 Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Wed, 26 Aug 2015 16:21:01 +0200 Subject: [PATCH 0578/1872] Changed variables name : set_nproc to set_nproc_tensor, get_nproc to get_nproc_tensor --- src/sage/tensor/modules/all.py | 3 +- src/sage/tensor/modules/comp.py | 28 +++++++++---------- src/sage/tensor/modules/parallel_utilities.py | 26 ++++++++--------- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/sage/tensor/modules/all.py b/src/sage/tensor/modules/all.py index c06e7e8d2b4..0501792b752 100644 --- a/src/sage/tensor/modules/all.py +++ b/src/sage/tensor/modules/all.py @@ -1,3 +1,2 @@ from finite_rank_free_module import FiniteRankFreeModule -from parallel_utilities import set_nproc, get_nproc - +from parallel_utilities import set_nproc_tensor, get_nproc_tensor diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index fa96f82c8e4..3a6d8f74786 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1285,7 +1285,7 @@ def __add__(self, other): Parallel computation:: - sage: set_nproc(2); print get_nproc() + sage: set_nproc_tensor(2); print get_nproc_tensor() 2 sage: s = a.__add__(b) ; s 1-index components w.r.t. [1, 2, 3] @@ -1293,7 +1293,7 @@ def __add__(self, other): [5, 5, 3] sage: s == a+b True - sage: set_nproc(1) + sage: set_nproc_tensor(1) """ if other == 0: @@ -1401,7 +1401,7 @@ def __sub__(self, other): Parallel computation:: - sage: set_nproc(2); print get_nproc() + sage: set_nproc_tensor(2); print get_nproc_tensor() 2 sage: s = a.__sub__(b) ; s 1-index components w.r.t. [1, 2, 3] @@ -1409,7 +1409,7 @@ def __sub__(self, other): [-3, -5, -9] sage: s == a - b True - sage: set_nproc(1) + sage: set_nproc_tensor(1) """ if other == 0: @@ -1474,7 +1474,7 @@ def __mul__(self, other): True Parallel computation:: - sage: set_nproc(2);print get_nproc() + sage: set_nproc_tensor(2);print get_nproc_tensor() 2 sage: s = a.__mul__(b) ; s 2-indices components w.r.t. [1, 2, 3] @@ -1484,7 +1484,7 @@ def __mul__(self, other): [-12 -15 -18] sage: s == a*b True - sage: set_nproc(1);print get_nproc() + sage: set_nproc_tensor(1);print get_nproc_tensor() 1 """ @@ -1775,7 +1775,7 @@ def contract(self, *args): Parallel computation:: - sage: set_nproc(2); print get_nproc() + sage: set_nproc_tensor(2); print get_nproc_tensor() 2 sage: s = a.contract(0, b, 0) ; s 1-index components w.r.t. [ @@ -1787,7 +1787,7 @@ def contract(self, *args): [28, 32, 36] sage: s = a.contract(0, b, 1) ; s[:] [12, 24, 36] - sage: set_nproc(1) + sage: set_nproc_tensor(1) Contraction on 2 indices:: @@ -1812,7 +1812,7 @@ def contract(self, *args): Parallel computation:: - sage: set_nproc(2); print get_nproc() + sage: set_nproc_tensor(2); print get_nproc_tensor() 2 sage: c = a*b ; c 3-indices components w.r.t. [ @@ -1828,7 +1828,7 @@ def contract(self, *args): ] sage: s[:] [-285, 570, 855] - sage: set_nproc(1) + sage: set_nproc_tensor(1) Consistency check with :meth:`trace`:: @@ -3225,7 +3225,7 @@ def __mul__(self, other): True Parallel computation:: - sage: set_nproc(2);print get_nproc() + sage: set_nproc_tensor(2);print get_nproc_tensor() 2 sage: s = a.__mul__(b) ; s 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) @@ -3243,7 +3243,7 @@ def __mul__(self, other): True sage: s == a*c True - sage: set_nproc(1);print get_nproc() + sage: set_nproc_tensor(1);print get_nproc_tensor() 1 """ @@ -4549,7 +4549,7 @@ def __add__(self, other): Parallel computation:: - sage: set_nproc(2); print get_nproc() + sage: set_nproc_tensor(2); print get_nproc_tensor() 2 sage: s = a.__add__(c) ; s # the symmetry is lost 2-indices components w.r.t. (1, 2, 3) @@ -4559,7 +4559,7 @@ def __add__(self, other): [-7 5 0] sage: s == a + c True - sage: set_nproc(1) + sage: set_nproc_tensor(1) """ diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py index 3549832ca17..100145aebc5 100644 --- a/src/sage/tensor/modules/parallel_utilities.py +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -6,7 +6,7 @@ - the singleton class :class:`TensorParallelCompute` to gather the information relative to the parallelization of tensor algebra (basically the number of processes to be used) -- the global functions :func:`set_nproc` and :func:`get_nproc` to be used in +- the global functions :func:`set_nproc` and :func:`get_nproc_tensor` to be used in a Sage session for managing the number of processes involved in the parallelization. @@ -130,7 +130,7 @@ def set(self, nproc=None): self._use_paral = True if self._nproc!=1 else False -def set_nproc(nproc=None): +def set_nproc_tensor(nproc=None): r""" Set the number of processes for parallelizing computations relative to tensor algebra. @@ -145,25 +145,25 @@ def set_nproc(nproc=None): The default is a single processor (no parallelization):: - sage: get_nproc() + sage: get_nproc_tensor() 1 Asking for parallelization on 4 cores:: - sage: set_nproc(4) - sage: get_nproc() + sage: set_nproc_tensor(4) + sage: get_nproc_tensor() 4 Using all the cores available on the computer:: - sage: set_nproc() - sage: get_nproc() # random + sage: set_nproc_tensor() + sage: get_nproc_tensor() # random 8 Switching off the parallelization:: - sage: set_nproc(1) - sage: get_nproc() + sage: set_nproc_tensor(1) + sage: get_nproc_tensor() 1 See :meth:`sage.tensor.modules.comp.Components.contract` for a concrete @@ -172,7 +172,7 @@ def set_nproc(nproc=None): """ TensorParallelCompute().set(nproc) -def get_nproc(): +def get_nproc_tensor(): r""" Return the number of processes used in parallelized tensorial computations. @@ -181,13 +181,13 @@ def get_nproc(): The default is a single processor (no parallelization):: - sage: get_nproc() + sage: get_nproc_tensor() 1 Asking for parallelization on 4 cores:: - sage: set_nproc(4) - sage: get_nproc() + sage: set_nproc_tensor(4) + sage: get_nproc_tensor() 4 """ From 29ed6b37c67e462dbb495014eb39b6c373023d6d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 16:24:42 +0200 Subject: [PATCH 0579/1872] move element_construction to GenericTermMonoid --- src/sage/rings/asymptotic/asymptotic_ring.py | 24 +- src/sage/rings/asymptotic/term_monoid.py | 265 +++++++++---------- 2 files changed, 138 insertions(+), 151 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 6b9ff682bf1..7ada7368b01 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1558,7 +1558,7 @@ def ngens(self): return len(self.growth_group.gens_monomial()) - def create_summand(self, type, growth, **kwds): + def create_summand(self, type, data=None, **kwds): r""" Create a simple asymptotic expression consisting of a single summand. @@ -1567,10 +1567,17 @@ def create_summand(self, type, growth, **kwds): - ``type`` -- 'O' or 'exact'. + - ``data`` -- the element out of which a summand has to be created. + - ``growth`` -- an element of the :meth:`growth_group`. - ``coefficient`` -- an element of the :meth:`coefficient_ring`. + .. NOTE:: + + Either ``growth`` and ``coefficient`` or ``data`` have to + be specified. + OUTPUT: An asymptotic expression. @@ -1584,27 +1591,32 @@ def create_summand(self, type, growth, **kwds): EXAMPLES:: sage: R = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) - sage: R.create_summand('O', growth=x^2) + sage: R.create_summand('O', x^2) O(x^2) sage: R.create_summand('exact', growth=x^456, coefficient=123) 123*x^456 TESTS:: - sage: R.create_summand('O', growth=42*x^2) + sage: R.create_summand('O', growth=42*x^2, coefficient=1) Traceback (most recent call last): ... - ValueError: Growth 42*x^2 is not in O-Term Monoid x^ZZ - with implicit coefficients in Integer Ring. + ValueError: Growth 42*x^2 is not in O-Term Monoid x^ZZ with implicit coefficients in Integer Ring. > *previous* ValueError: 42*x^2 is not in Growth Group x^ZZ. """ from sage.rings.asymptotic.term_monoid import TermMonoid TM = TermMonoid(type, self.growth_group, self.coefficient_ring) + if data is None: + try: + data = kwds.pop('growth') + except KeyError: + raise TypeError("Neither 'data' nor 'growth' are specified.") + if type == 'exact' and kwds.get('coefficient') == 0: return self(kwds['coefficient']) - return self(TM(growth, **kwds)) + return self(TM(data, **kwds)) def variable_names(self): diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 6cf86d2d0cf..e0b1923964e 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1140,26 +1140,22 @@ def _coerce_map_from_(self, S): return True - def _element_constructor_(self, data): + def _element_constructor_(self, data, coefficient=None): r""" Convert the given object to this term monoid. INPUT: - - ``data`` -- an object representing the element to be - initialized. + - ``data`` -- a growth element or an object representing the + element to be initialized. + + - ``coefficient`` -- (default: ``None``) + an element of the coefficient ring. OUTPUT: An element of this term monoid. - .. NOTE:: - - The object ``data`` is either an asymptotic term that is - to be coerced into this term monoid, or an asymptotic - growth element that is used for creating an element - of this term monoid. - EXAMPLES:: sage: import sage.rings.asymptotic.term_monoid as atm @@ -1195,6 +1191,15 @@ def _element_constructor_(self, data): with (implicit) coefficients in Rational Field. > *previous* ValueError: 10*x^2 is not in Growth Group x^ZZ. + :: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: import sage.rings.asymptotic.growth_group as agg + sage: G = agg.GrowthGroup('x^ZZ') + sage: T = atm.TermWithCoefficientMonoid(G, ZZ) + sage: t1 = T(x^2, 5); t1 # indirect doctest + Asymptotic Term with coefficient 5 and growth x^2 + TESTS:: sage: O_ZZ = atm.OTermMonoid(G_ZZ, QQ) @@ -1206,21 +1211,116 @@ def _element_constructor_(self, data): ValueError: Growth 2*x^11 is not in O-Term Monoid x^ZZ with implicit coefficients in Rational Field. > *previous* ValueError: 2*x^11 is not in Growth Group x^ZZ. + + :: + + sage: T(5 * x^5) + Asymptotic Term with coefficient 5 and growth x^5 + sage: T(G.gen()^10) + Asymptotic Term with coefficient 1 and growth x^10 + sage: T(G.gen()^10, coefficient=10) + Asymptotic Term with coefficient 10 and growth x^10 + sage: T(x^123) + Asymptotic Term with coefficient 1 and growth x^123 + + :: + + sage: T(x) + Asymptotic Term with coefficient 1 and growth x + + :: + + sage: G_log = agg.GrowthGroup('log(x)^ZZ') + sage: T_log = atm.TermWithCoefficientMonoid(G_log, ZZ) + sage: T_log(log(x)) + Asymptotic Term with coefficient 1 and growth log(x) + """ if type(data) == self.element_class and data.parent() == self: return data + elif isinstance(data, TermWithCoefficient): + return self._create_element_(data.growth, data.coefficient) elif isinstance(data, GenericTerm): - return self.element_class(self, data.growth) + return self._create_element_(data.growth, None) elif type(data) == int and data == 0: - raise ValueError('No input specified. Cannot continue.') - else: - from growth_group import combine_exceptions + raise ValueError('No input specified. Cannot continue ' + 'creating an element of %s.' % (self,)) + + from growth_group import combine_exceptions + if coefficient is not None: try: data = self.growth_group(data) - return self.element_class(self, data) except (ValueError, TypeError) as e: raise combine_exceptions( ValueError('Growth %s is not in %s.' % (data, self)), e) + return self._create_element_(data, coefficient) + + try: + growth, coefficient = self._split_growth_and_coefficient_(data) + except ValueError as e: + raise combine_exceptions( + ValueError('%s is not in %s.' % (data, self)), e) + + return self._create_element_(growth, coefficient) + + + def _create_element_(self, growth, coefficient): + if coefficient is not None and coefficient != self.coefficient_ring.one(): + raise ValueError('Coefficient %s is not 1, but %s does not ' + 'support coefficients.' % (coefficient, self)) + return self.element_class(self, growth) + + + def _split_growth_and_coefficient_(self, data): + factors = self._get_factors_(data) + + growth_group = self.growth_group + coefficient_ring = self.coefficient_ring + + coefficients = [] + growths = [] + for f in factors: + try: + growths.append(growth_group(f)) + continue + except (ValueError, TypeError): + pass + + try: + coefficients.append(coefficient_ring(f)) + continue + except (ValueError, TypeError): + pass + + raise ValueError('Factor %s of %s is neither a coefficient (in %s) ' + 'nor growth (in %s).' % + (f, data, coefficient_ring, growth_group)) + + from sage.misc.misc_c import prod + growth = prod(growths) if growths else growth_group.one() + coefficient = prod(coefficients) if coefficients else coefficient_ring.one() + return (growth, coefficient) + + + def _get_factors_(self, data): + + if isinstance(data, str): + from growth_group import split_str_by_mul + return split_str_by_mul(data) + + try: + P = data.parent() + except AttributeError: + return (data,) + + from sage.symbolic.ring import SR + if P is SR: + from sage.symbolic.operators import mul_vararg + op = data.operator() + if op == mul_vararg: + return data.operands() + + return (data,) def _an_element_(self): @@ -1534,6 +1634,10 @@ class OTermMonoid(GenericTermMonoid): Element = OTerm + def _create_element_(self, growth, coefficient): + return self.element_class(self, growth) + + def _coerce_map_from_(self, S): r""" Return if ``S`` coerces into this term monoid. @@ -1890,139 +1994,10 @@ class TermWithCoefficientMonoid(GenericTermMonoid): Element = TermWithCoefficient - def _element_constructor_(self, data, coefficient=None): - r""" - Construct an asymptotic term with coefficient or convert - the given object ``data`` to this term monoid. - - INPUT: - - - ``data`` -- a growth element or an object representing the - element to be initialized. - - - ``coefficient`` -- an element of the coefficient ring. - - OUTPUT: - - An asymptotic term. - - .. NOTE:: - - The object ``data`` is either an asymptotic term with - coefficient that is to be coerced into this term monoid, - or an asymptotic growth element that is used together - with ``coefficient`` in order to create an element of - this term monoid. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ') - sage: T = atm.TermWithCoefficientMonoid(G, ZZ) - sage: t1 = T(x^2, 5); t1 # indirect doctest - Asymptotic Term with coefficient 5 and growth x^2 - - TESTS:: - - sage: T(5 * x^5) - Asymptotic Term with coefficient 5 and growth x^5 - sage: T(G.gen()^10) - Asymptotic Term with coefficient 1 and growth x^10 - sage: T(G.gen()^10, coefficient=10) - Asymptotic Term with coefficient 10 and growth x^10 - sage: T(x^123) - Asymptotic Term with coefficient 1 and growth x^123 - - :: - - sage: T(x) - Asymptotic Term with coefficient 1 and growth x - - :: - - sage: G_log = agg.GrowthGroup('log(x)^ZZ') - sage: T_log = atm.TermWithCoefficientMonoid(G_log, ZZ) - sage: T_log(log(x)) - Asymptotic Term with coefficient 1 and growth log(x) - """ - if type(data) == self.element_class and data.parent() == self: - return data - elif isinstance(data, TermWithCoefficient): - return self.element_class(self, data.growth, data.coefficient) - elif type(data) == int and data == 0: - raise ValueError('No input specified. Cannot continue ' - 'creating an element of %s.' % (self,)) - - from growth_group import combine_exceptions - if coefficient is not None: - try: - data = self.growth_group(data) - except (ValueError, TypeError) as e: - raise combine_exceptions( - ValueError('Growth %s is not in %s.' % (data, self)), e) - return self.element_class(self, data, coefficient) - - try: - growth, coefficient = self._split_growth_and_coefficient_(data) - except ValueError as e: - raise combine_exceptions( - ValueError('%s is not in %s.' % (data, self)), e) - + def _create_element_(self, growth, coefficient): return self.element_class(self, growth, coefficient) - def _split_growth_and_coefficient_(self, data): - factors = self._get_factors_(data) - - growth_group = self.growth_group - coefficient_ring = self.coefficient_ring - - coefficient = coefficient_ring.one() - growth = self.growth_group.one() - for f in factors: - try: - g = growth_group(f) - except (ValueError, TypeError): - pass - else: - growth *= g - continue - try: - c = coefficient_ring(f) - except (ValueError, TypeError): - pass - else: - coefficient *= c - continue - raise ValueError('Factor %s of %s is neither a coefficient (in %s) ' - 'nor growth (in %s).' % - (f, data, coefficient_ring, growth_group)) - - return (growth, coefficient) - - - def _get_factors_(self, data): - - if isinstance(data, str): - from growth_group import split_str_by_mul - return split_str_by_mul(data) - - try: - P = data.parent() - except AttributeError: - return (data,) - - from sage.symbolic.ring import SR - if P is SR: - from sage.symbolic.operators import mul_vararg - op = data.operator() - if op == mul_vararg: - return data.operands() - - return (data,) - - def _an_element_(self): r""" Return an element of this term with coefficient monoid. From 1ac20d751f48bd7bb310402295f05b492ded4804 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 18:12:26 +0200 Subject: [PATCH 0580/1872] rewrite element_constructor of AsymptoticRing to accept SR and polynomials --- src/sage/rings/asymptotic/asymptotic_ring.py | 79 +++++++++++++++++--- src/sage/rings/asymptotic/term_monoid.py | 42 ++++------- 2 files changed, 83 insertions(+), 38 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 7ada7368b01..d61128b1300 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1287,8 +1287,22 @@ def _element_constructor_(self, data, summands=None, simplify=True): sage: y = ZZ['y'].gen(); AR(y) Traceback (most recent call last): ... - TypeError: Cannot convert y to an asymptotic expression - in Asymptotic Ring over Integer Ring. + ValueError: Growth y is not in Exact Term Monoid x^ZZ + with coefficients in Integer Ring. + > *previous* ValueError: y is not in Growth Group x^ZZ. + + :: + + sage: A = AsymptoticRing(growth_group='p^ZZ', coefficient_ring=QQ) + sage: P.

= QQ[] + sage: A(p) + p + sage: A(p^11) + p^11 + sage: A(2*p^11) + 2*p^11 + sage: A(3*p^4 + 7/3*p - 8) + 3*p^4 + 7/3*p - 8 """ if summands is not None: if type(data) != int or data != 0: @@ -1321,21 +1335,68 @@ def _element_constructor_(self, data, summands=None, simplify=True): return self.element_class(self, summands, simplify=simplify) try: - summand = self.create_summand('exact', growth=data) + P = data.parent() + except AttributeError: + return self._create_exact_summand_(data) + + from growth_group import combine_exceptions + if P is sage.symbolic.ring.SR: + from sage.symbolic.operators import add_vararg + if data.operator() == add_vararg: + summands = [] + for summand in data.operands(): + # TODO: check if summand is an O-Term here + try: + summands.append(self._create_exact_summand_(summand)) + except ValueError as e: + raise combine_exceptions( + ValueError('Symbolic expression %s is not in %s.' % + (data, self)), e) + return sum(summands) + + elif sage.rings.polynomial.polynomial_ring.is_PolynomialRing(P): + p = P.gen() + return sum(self.create_summand('exact', growth=p**i, coefficient=c) + for i, c in enumerate(data)) + + elif sage.rings.polynomial.multi_polynomial_ring_generic.is_MPolynomialRing(P): + return sum(self.create_summand('exact', growth=g, coefficient=c) + for c, g in iter(data)) + + elif sage.rings.power_series_ring.is_PowerSeriesRing(P): + raise NotImplementedError( + 'Cannot convert %s from the %s to an asymptotic expression ' + 'in %s, since growths at other points than +oo are not yet ' + 'supported.' % (data, P, self)) + # Delete lines above as soon as we can deal with growths + # other than the that at going to +oo. + p = P.gen() + result = self(data.polynomial()) + prec = data.precision_absolute() + if prec < sage.rings.infinity.PlusInfinity(): + result += self.create_summand('O', growth=p**prec) + return result + + return self._create_exact_summand_(data) + + + def _create_exact_summand_(self, data): + try: + coefficient = self.coefficient_ring(data) except (TypeError, ValueError): pass else: - return summand + return self.create_summand('exact', + growth=self.growth_group.one(), + coefficient=coefficient) try: - coefficient = self.coefficient_ring(data) + return self.create_summand('exact', data) except (TypeError, ValueError): pass - else: - return self.create_summand('exact', growth=1, coefficient=coefficient) - raise TypeError('Cannot convert %s to an asymptotic ' - 'expression in %s.' % (data, self)) + raise ValueError('Cannot convert %s to an exact summand in an ' + 'asymptotic expression in %s.' % (data, self)) def _coerce_map_from_(self, R): diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index e0b1923964e..5f8fc7ac6bd 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1187,9 +1187,10 @@ def _element_constructor_(self, data, coefficient=None): sage: T_ZZ(10 * x^2) Traceback (most recent call last): ... - ValueError: Growth 10*x^2 is not in Generic Term Monoid x^ZZ + ValueError: 10*x^2 is not in Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field. - > *previous* ValueError: 10*x^2 is not in Growth Group x^ZZ. + > *previous* ValueError: Factor 10*x^2 of 10*x^2 is neither a + coefficient (in Rational Field) nor growth (in Growth Group x^ZZ). :: @@ -1205,17 +1206,9 @@ def _element_constructor_(self, data, coefficient=None): sage: O_ZZ = atm.OTermMonoid(G_ZZ, QQ) sage: O_ZZ(x^11) O(x^11) - sage: O_ZZ(2*x^11) - Traceback (most recent call last): - ... - ValueError: Growth 2*x^11 is not in O-Term Monoid x^ZZ - with implicit coefficients in Rational Field. - > *previous* ValueError: 2*x^11 is not in Growth Group x^ZZ. :: - sage: T(5 * x^5) - Asymptotic Term with coefficient 5 and growth x^5 sage: T(G.gen()^10) Asymptotic Term with coefficient 1 and growth x^10 sage: T(G.gen()^10, coefficient=10) @@ -1316,8 +1309,7 @@ def _get_factors_(self, data): from sage.symbolic.ring import SR if P is SR: from sage.symbolic.operators import mul_vararg - op = data.operator() - if op == mul_vararg: + if data.operator() == mul_vararg: return data.operands() return (data,) @@ -2120,14 +2112,6 @@ class ExactTerm(TermWithCoefficient): Symbolic Ring sage: ET(5*x^2) 5*x^2 - sage: x = ZZ['x'].gen(); x.parent() - Univariate Polynomial Ring in x over Integer Ring - sage: ET(5*x^2) - 5*x^2 - sage: x = ZZ[['x']].gen(); x.parent() - Power Series Ring in x over Integer Ring - sage: ET(5*x^2) - 5*x^2 """ def _repr_(self): @@ -2303,20 +2287,20 @@ class ExactTermMonoid(TermWithCoefficientMonoid): sage: G_ZZ = agg.GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() sage: G_QQ = agg.GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() sage: ET_ZZ = atm.ExactTermMonoid(G_ZZ, ZZ); ET_ZZ - Exact Term Monoid x^ZZ with coefficients from Integer Ring + Exact Term Monoid x^ZZ with coefficients in Integer Ring sage: ET_QQ = atm.ExactTermMonoid(G_QQ, QQ); ET_QQ - Exact Term Monoid x^QQ with coefficients from Rational Field + Exact Term Monoid x^QQ with coefficients in Rational Field sage: ET_QQ.coerce_map_from(ET_ZZ) Conversion map: - From: Exact Term Monoid x^ZZ with coefficients from Integer Ring - To: Exact Term Monoid x^QQ with coefficients from Rational Field + From: Exact Term Monoid x^ZZ with coefficients in Integer Ring + To: Exact Term Monoid x^QQ with coefficients in Rational Field Exact term monoids can also be created using the term factory:: sage: atm.TermMonoid('exact', G_ZZ, ZZ) is ET_ZZ True sage: atm.TermMonoid('exact', agg.GrowthGroup('x^ZZ'), QQ) - Exact Term Monoid x^ZZ with coefficients from Rational Field + Exact Term Monoid x^ZZ with coefficients in Rational Field """ # enable the category framework for elements Element = ExactTerm @@ -2339,9 +2323,9 @@ def _repr_(self): sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() sage: atm.ExactTermMonoid(G, QQ)._repr_() - 'Exact Term Monoid x^ZZ with coefficients from Rational Field' + 'Exact Term Monoid x^ZZ with coefficients in Rational Field' """ - return 'Exact Term Monoid %s with coefficients from %s' % \ + return 'Exact Term Monoid %s with coefficients in %s' % \ (self.growth_group._repr_short_(), self.coefficient_ring) @@ -2375,7 +2359,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: OT = atm.TermMonoid('O', G, QQ); OT O-Term Monoid x^ZZ with implicit coefficients in Rational Field sage: ET = atm.TermMonoid('exact', G, ZZ); ET - Exact Term Monoid x^ZZ with coefficients from Integer Ring + Exact Term Monoid x^ZZ with coefficients in Integer Ring """ def create_key_and_extra_args(self, term, growth_group, coefficient_ring=None, **kwds): @@ -2425,7 +2409,7 @@ def create_object(self, version, key, **kwds): sage: atm.TermMonoid('O', G, QQ) # indirect doctest O-Term Monoid x^ZZ with implicit coefficients in Rational Field sage: atm.TermMonoid('exact', G, ZZ) # indirect doctest - Exact Term Monoid x^ZZ with coefficients from Integer Ring + Exact Term Monoid x^ZZ with coefficients in Integer Ring """ term, growth_group, coefficient_ring = key From 15ba65edda635975fb34b19bd949dbe5b25d5fb8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 18:35:38 +0200 Subject: [PATCH 0581/1872] correct a bug in growth_group_cartesian._element_constructor_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 5 +++++ .../rings/asymptotic/growth_group_cartesian.py | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d61128b1300..48f5db07e8e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1303,6 +1303,11 @@ def _element_constructor_(self, data, summands=None, simplify=True): 2*p^11 sage: A(3*p^4 + 7/3*p - 8) 3*p^4 + 7/3*p - 8 + :: + + sage: A. = AsymptoticRing('a^ZZ * b^ZZ', QQ) + sage: 1/a + 1/a """ if summands is not None: if type(data) != int or data != 0: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 98ddc22034c..2d1dcb70154 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -457,15 +457,6 @@ def convert_factors(data, raw_data): elif isinstance(data, self.element_class): return self.element_class(self, data) - elif isinstance(data, (tuple, list, - sage.sets.cartesian_product.CartesianProduct.Element)): - try: - return super(GenericProduct, self)._element_constructor_(data) - except ValueError: - pass - - return convert_factors(data, data) - elif isinstance(data, str): from growth_group import split_str_by_mul return convert_factors(split_str_by_mul(data), data) @@ -483,6 +474,15 @@ def convert_factors(data, raw_data): # room for other parents (e.g. polynomial ring et al.) + else: + try: + return super(GenericProduct, self)._element_constructor_(data) + except ValueError: + pass + if isinstance(data, (tuple, list, + sage.sets.cartesian_product.CartesianProduct.Element)): + return convert_factors(tuple(data), data) + return convert_factors((data,), data) From 4bbe5f3177b44ca4702586e1632e0d622408df9f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 18:35:49 +0200 Subject: [PATCH 0582/1872] add a doctest to convert from SR --- src/sage/rings/asymptotic/asymptotic_ring.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 48f5db07e8e..4a366a6eddd 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1303,6 +1303,17 @@ def _element_constructor_(self, data, summands=None, simplify=True): 2*p^11 sage: A(3*p^4 + 7/3*p - 8) 3*p^4 + 7/3*p - 8 + + :: + + sage: S = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=QQ) + sage: var('x, y') + (x, y) + sage: S(x + y) + x + y + sage: S(2*x - 4*x*y^6) + -4*x * y^6 + 2*x + :: sage: A. = AsymptoticRing('a^ZZ * b^ZZ', QQ) From c7c4de97939f9a490f106a6cc9ebb74895c508af Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 26 Aug 2015 16:00:28 +0200 Subject: [PATCH 0583/1872] __ne__ implemented for growth group elements --- src/sage/rings/asymptotic/growth_group.py | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 58766197482..96331427019 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -972,6 +972,40 @@ def _eq_(self, other): return self._raw_element_ == other._raw_element_ + def __ne__(self, other): + r""" + Return if this growth element is not equal to ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This function uses the coercion model to find a common + parent for the two operands. + + The comparison of two elements with the same parent is done in + :meth:`_eq_`. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ') + sage: G.one() != G(1) + False + sage: G.one() != G.one() + False + sage: G(1) != G(1) + False + """ + return not self.__eq__(other) + + def __le__(self, other): r""" Return if this growth element is at most (less than or equal From 549a155c4b5c878ebc5854b731ab7f1db7ab3412 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 26 Aug 2015 16:01:05 +0200 Subject: [PATCH 0584/1872] dummy implementations of log for monomial and exponential growth groups --- src/sage/rings/asymptotic/growth_group.py | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 96331427019..cd44f69a036 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1080,6 +1080,46 @@ def _le_(self, other): raise NotImplementedError('Only implemented in concrete realizations.') + def log(self, base=None): + r""" + The logarithm of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the logarithm is the natural + logarithm. + + OUTPUT: + + A growth element. + + .. NOTE:: + + The logarithm is only implemented for elements from a + Cartesian product of growth groups, see + :meth:`~sage.rings.asymptotic.growth_group_cartesian.GenericProduct.Element.log`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import (GrowthGroup, GenericGrowthGroup) + sage: x = GenericGrowthGroup(ZZ).an_element() + sage: log(x) # indirect doctest + Traceback (most recent call last): + ... + ArithmeticError: building log(GenericGrowthElement(1)) is not possible. + + :: + + sage: x = GrowthGroup('x^ZZ').an_element() + sage: log(x) + Traceback (most recent call last): + ... + ArithmeticError: building log(x) is not possible. + """ + raise ArithmeticError('building log(%s) is not possible.' % (self,)) + + class GenericGrowthGroup( sage.structure.unique_representation.UniqueRepresentation, sage.structure.parent.Parent): From ec04d5ec6666d10a42625612976b50f41ba85e1b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 26 Aug 2015 16:02:03 +0200 Subject: [PATCH 0585/1872] exponential element constructor: exp(...) covered --- src/sage/rings/asymptotic/growth_group.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cd44f69a036..5a809564c77 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2891,6 +2891,10 @@ def _convert_(self, data): sqrt(3)^x sage: P((3^(1/3))^x) (3^(1/3))^x + sage: P(e^x) + e^x + sage: P(exp(2*x)) + (e^2)^x """ if data == 1 or data == '1': return self.base().one() @@ -2913,12 +2917,21 @@ def _convert_(self, data): import operator from sage.symbolic.operators import mul_vararg if P is SR: - if data.operator() == operator.pow: + op = data.operator() + if op == operator.pow: base, exponent = data.operands() if str(exponent) == var: return base elif exponent.operator() == mul_vararg: return base ** (exponent / SR(var)) + elif isinstance(op, sage.functions.log.Function_exp): + from sage.functions.log import exp + base = exp(1) + exponent = data.operands()[0] + if str(exponent) == var: + return base + elif exponent.operator() == mul_vararg: + return base ** (exponent / SR(var)) def gens(self): From 16514c053493472e29140e411419327d92559364 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 26 Aug 2015 16:02:21 +0200 Subject: [PATCH 0586/1872] exponential growth elements: representation string simplified --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 5a809564c77..046ce9b9afe 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2633,7 +2633,7 @@ def _repr_(self): var = repr(self.parent()._var_) if self.base == 1: return '1' - elif self.base in ZZ and self.base > 0 or str(self.base).startswith('sqrt'): + elif not any(s in str(self.base) for s in '-/^'): return str(self.base) + '^' + var else: return '(' + str(self.base) + ')^' + var From 5f04fd5354903519608351807d0f1d98696c52e9 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 26 Aug 2015 17:37:10 +0200 Subject: [PATCH 0587/1872] implemented factor for cartesian product elements --- .../asymptotic/growth_group_cartesian.py | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 2d1dcb70154..b07a3906c6c 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -857,6 +857,64 @@ def _repr_(self): return s + def factor(self): + r""" + Return a factorization of this element into growth + elements from atomic growth groups. + + INPUT: + + Nothing. + + OUTPUT: + + A list of growth elements. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ') + sage: x, y = G.gens_monomial() + sage: x.factor() + [x] + sage: f = (x * y).factor(); f + [x, y] + sage: [factor.parent() for factor in f] + [Growth Group x^ZZ, Growth Group y^ZZ] + sage: f = (x * log(x)).factor(); f + [x, log(x)] + sage: [factor.parent() for factor in f] + [Growth Group x^ZZ, Growth Group log(x)^ZZ] + + :: + + sage: G = GrowthGroup('x^ZZ * log(x)^ZZ * log(log(x))^ZZ * y^QQ') + sage: x, y = G.gens_monomial() + sage: f = (x * log(x) * y).factor(); f + [x, log(x), y] + sage: [factor.parent() for factor in f] + [Growth Group x^ZZ, Growth Group log(x)^ZZ, Growth Group y^QQ] + + :: + + sage: G.one().factor() + Traceback (most recent call last): + ... + ValueError: 1 does not have a factorization. + """ + components = [] + for (component, factor) in zip(self.value, + self.parent().cartesian_factors()): + if component != factor.one(): + if hasattr(component, 'factor'): + components = components + component.factor() + else: + components.append(component) + + if components: + return components + raise ValueError('%s does not have a factorization.' % (self,)) + CartesianProduct = CartesianProductGrowthGroups From 6498396768b14e51c083a8c69c07ac1a56e9fff2 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 26 Aug 2015 18:06:08 +0200 Subject: [PATCH 0588/1872] implemented log_factor --- .../asymptotic/growth_group_cartesian.py | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index b07a3906c6c..8bb6f950d8d 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -915,6 +915,93 @@ def factor(self): return components raise ValueError('%s does not have a factorization.' % (self,)) + def log_factor(self, base=None): + r""" + Return the logarithm of the factorization of this + element. + + In particular, this function yields a list of pairs + consisting of the growth and the corresponding + coefficient resulting from taking the logarithm of every + atomic factor of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the logarithm is the natural + logarithm. + + OUTPUT: + + A list. + + .. SEEALSO:: + + :meth:`factor`, + :meth:`log`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ') + sage: x, y = G.gens_monomial() + sage: (x * y).log_factor() + [[log(x), 1], [log(y), 1]] + sage: (x^123).log_factor() + [[log(x), 123]] + sage: (G('2^x') * x^2).log_factor(base=2) + [[x, 1], [log(x), 2/log(2)]] + + :: + + sage: G(1).log_factor() + Traceback (most recent call last): + ... + ValueError: 1 does not have a factorization. + + :: + + sage: log(x).log_factor() + Traceback (most recent call last): + ... + ValueError: Logarithm of log(x) cannot be constructed in Growth + Group QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ. + """ + P = self.parent() + factors = self.factor() + log_factors = [] + from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup, \ + MonomialGrowthGroup + from sage.functions.log import log + + for factor in factors: + try: + FP = factor.parent() + if isinstance(FP, MonomialGrowthGroup): + if base is None: + coef = factor._raw_element_ + else: + coef = factor._raw_element_ / log(base) + growth = P('log(' + repr(FP._var_) + ')') + log_factors.append([growth, coef]) + + elif isinstance(FP, ExponentialGrowthGroup): + coef = log(factor._raw_element_, base=base) + growth = P(repr(FP._var_)) + log_factors.append([growth, coef]) + + else: + raise NotImplementedError('Taking the Logarithm of %s ' + 'is not implemented.' % + (factor,)) + + except (ValueError, TypeError): + raise ValueError('Logarithm of %s cannot be ' + 'constructed in %s.' % (factor, P)) + + return log_factors + + CartesianProduct = CartesianProductGrowthGroups From 187442bad2d50b6ce10911a2638b9cb5d7412918 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 26 Aug 2015 18:06:16 +0200 Subject: [PATCH 0589/1872] implemented log for growth groups --- .../rings/asymptotic/growth_group_cartesian.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 8bb6f950d8d..ddc4809d3be 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -856,6 +856,24 @@ def _repr_(self): return '1' return s + def log(self, base=None): + r""" + The logarithm of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the logarithm is the natural + logarithm. + + OUTPUT: + + A growth element. + + """ + lf = self.log_factor(base=base) + if len(lf) == 1 and lf[0][1] == 1: + return lf[0][0] def factor(self): r""" From c9582371dc7ed79f717999ebbe7a38b794ea015a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 20:07:12 +0200 Subject: [PATCH 0590/1872] docs and doctests for 100% --- src/sage/rings/asymptotic/asymptotic_ring.py | 19 ++++ src/sage/rings/asymptotic/term_monoid.py | 108 ++++++++++++++++++- 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 4a366a6eddd..de2c396a5f0 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1397,6 +1397,25 @@ def _element_constructor_(self, data, summands=None, simplify=True): def _create_exact_summand_(self, data): + r""" + Create an exact summand. + + This helper method is used in the element constructor. + + INPUT: + + - ``data`` -- an element. + + OUTPUT: + + An asymptotic expression. + + TESTS:: + + sage: A. = AsymptoticRing('a^ZZ', QQ) + sage: A._create_exact_summand_(38) + 38 + """ try: coefficient = self.coefficient_ring(data) except (TypeError, ValueError): diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 5f8fc7ac6bd..960f6914226 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1258,6 +1258,28 @@ def _element_constructor_(self, data, coefficient=None): def _create_element_(self, growth, coefficient): + r""" + Helper method which creates an element by using the ``element_class``. + + INPUT: + + - ``growth`` -- a growth element. + + - ``coefficient`` -- an element of the coefficient ring. + + OUTPUT: + + A term. + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_ZZ = GrowthGroup('x^ZZ') + sage: T_ZZ = atm.GenericTermMonoid(G_ZZ, QQ) + sage: T_ZZ(G_ZZ.gen()) # indirect doctest + Generic Term with growth x + """ if coefficient is not None and coefficient != self.coefficient_ring.one(): raise ValueError('Coefficient %s is not 1, but %s does not ' 'support coefficients.' % (coefficient, self)) @@ -1265,6 +1287,26 @@ def _create_element_(self, growth, coefficient): def _split_growth_and_coefficient_(self, data): + r""" + Split given ``data`` into a growth element and a coefficient. + + INPUT: + + ``data`` -- an element. + + OUTPUT: + + A pair ``(growth, coefficient``). + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_ZZ = GrowthGroup('x^ZZ') + sage: T_ZZ = atm.ExactTermMonoid(G_ZZ, QQ) + sage: T_ZZ._split_growth_and_coefficient_('2*x^3') + (x^3, 2) + """ factors = self._get_factors_(data) growth_group = self.growth_group @@ -1296,7 +1338,26 @@ def _split_growth_and_coefficient_(self, data): def _get_factors_(self, data): + r""" + Split given ``data`` into separate factors. + + INPUT: + + - ``data`` -- an object. + + OUTPUT: + + A tuple. + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_ZZ = GrowthGroup('x^ZZ') + sage: T_ZZ = atm.ExactTermMonoid(G_ZZ, QQ) + sage: T_ZZ._get_factors_(x^2 * log(x)) + (x^2, log(x)) + """ if isinstance(data, str): from growth_group import split_str_by_mul return split_str_by_mul(data) @@ -1310,7 +1371,7 @@ def _get_factors_(self, data): if P is SR: from sage.symbolic.operators import mul_vararg if data.operator() == mul_vararg: - return data.operands() + return tuple(data.operands()) return (data,) @@ -1627,6 +1688,29 @@ class OTermMonoid(GenericTermMonoid): def _create_element_(self, growth, coefficient): + r""" + Helper method which creates an element by using the ``element_class``. + + INPUT: + + - ``growth`` -- a growth element. + + - ``coefficient`` -- an element of the coefficient ring (will be + ignored since we create an O-Term). + + OUTPUT: + + An O-term. + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_ZZ = GrowthGroup('x^ZZ') + sage: T_ZZ = atm.OTermMonoid(G_ZZ, QQ) + sage: T_ZZ(G_ZZ.gen()) # indirect doctest + O(x) + """ return self.element_class(self, growth) @@ -1987,6 +2071,28 @@ class TermWithCoefficientMonoid(GenericTermMonoid): def _create_element_(self, growth, coefficient): + r""" + Helper method which creates an element by using the ``element_class``. + + INPUT: + + - ``growth`` -- a growth element. + + - ``coefficient`` -- an element of the coefficient ring. + + OUTPUT: + + A term. + + TESTS:: + + sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_ZZ = GrowthGroup('x^ZZ') + sage: T_ZZ = atm.ExactTermMonoid(G_ZZ, QQ) + sage: T_ZZ(G_ZZ.gen(), 4/3) # indirect doctest + 4/3*x + """ return self.element_class(self, growth, coefficient) From b8ebe8145602f1721d2f82fec8c1a80626ff97ad Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 20:21:50 +0200 Subject: [PATCH 0591/1872] ' * ' to '*' in elements --- src/sage/rings/asymptotic/asymptotic_ring.py | 50 +++++++++---------- src/sage/rings/asymptotic/growth_group.py | 28 +++++------ .../asymptotic/growth_group_cartesian.py | 20 ++++---- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index de2c396a5f0..7801dc87060 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -107,7 +107,7 @@ Again, we can look at a typical (nontrivial) element:: sage: B.an_element() - -1/8*x^(3/2) * log(x)^3 * (1/8)^y * y^(3/2) + O(x^(1/2) * log(x) * (1/2)^y * y^(1/2)) + -1/8*x^(3/2)*log(x)^3*(1/8)^y*y^(3/2) + O(x^(1/2)*log(x)*(1/2)^y*y^(1/2)) Arithemtical Operations ----------------------- @@ -128,7 +128,7 @@ Of course, we can perform the usual ring operations `+` and `*`:: - sage: z^2 + 3*z*(1 - z) + sage: z^2 + 3*z*(1-z) -2*z^2 + 3*z sage: (3*z + 2)^3 27*z^3 + 54*z^2 + 36*z + 8 @@ -136,7 +136,7 @@ In addition to that, special powers---our growth group ``z^QQ`` allows the exponents to be out of `\QQ`---can also be computed:: - sage: (z^(5/2) + z^(1/7)) * z^(-1/5) + sage: (z^(5/2)+z^(1/7)) * z^(-1/5) z^(23/10) + z^(-2/35) The central concepts of computations with asymptotic expressions is @@ -151,7 +151,7 @@ :: - sage: (z + 2*z^2 + 3*z^3 + 4*z^4) * (O(z) + z^2) + sage: (z+2*z^2+3*z^3+4*z^4) * (O(z)+z^2) 4*z^6 + O(z^5) Division @@ -160,7 +160,7 @@ The asymptotic expressions support division. For example, we get can expand `1/(1-z)` to a geometric series:: - sage: 1 / (z - 1) + sage: 1 / (z-1) 1/z + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21)) Since there is a default precision (parameter ``default_prec``) @@ -168,7 +168,7 @@ Of course, we can work with more complicated expressions as well:: - sage: (4*z + 1) / (z^3 + z^2 + z + O(A(1))) + sage: (4*z+1) / (z^3+z^2+z+O(A(1))) 4*z^(-2) - 3*z^(-3) - z^(-4) + O(z^(-5)) Note that not all elements are invertible, for instance, @@ -224,24 +224,24 @@ sage: b = x^3*y + x^2*y + x*y^2 + O(x) + O(y) sage: print b.summands.repr_full(reverse=True) - poset(x * y^2, x^3 * y, x^2 * y, O(x), O(y)) + poset(x*y^2, x^3*y, x^2*y, O(x), O(y)) +-- oo | +-- no successors - | +-- predecessors: x * y^2, x^3 * y - +-- x * y^2 + | +-- predecessors: x*y^2, x^3*y + +-- x*y^2 | +-- successors: oo | +-- predecessors: O(x), O(y) - +-- x^3 * y + +-- x^3*y | +-- successors: oo - | +-- predecessors: x^2 * y - +-- x^2 * y - | +-- successors: x^3 * y + | +-- predecessors: x^2*y + +-- x^2*y + | +-- successors: x^3*y | +-- predecessors: O(x), O(y) +-- O(x) - | +-- successors: x * y^2, x^2 * y + | +-- successors: x*y^2, x^2*y | +-- predecessors: null +-- O(y) - | +-- successors: x * y^2, x^2 * y + | +-- successors: x*y^2, x^2*y | +-- predecessors: null +-- null | +-- successors: O(x), O(y) @@ -315,7 +315,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): expressions is that the `O`-notation (see :wikipedia:`Big_O_notation`) can be used. For example, we have:: - sage: (x + 2*x^2 + 3*x^3 + 4*x^4) * (O(x) + x^2) + sage: (x+2*x^2+3*x^3+4*x^4) * (O(x)+x^2) 4*x^6 + O(x^5) In particular, :meth:`~sage.rings.big_oh.O` can be used to @@ -420,7 +420,7 @@ def summands(self): EXAMPLES:: sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) - sage: expr = 7 * x^12 + x^5 + O(x^3) + sage: expr = 7*x^12 + x^5 + O(x^3) sage: expr.summands poset(O(x^3), x^5, 7*x^12) @@ -450,7 +450,7 @@ def __nonzero__(self): False sage: bool(x) # indirect doctest True - sage: bool(7 * x^12 + x^5 + O(x^3)) # indirect doctest + sage: bool(7*x^12 + x^5 + O(x^3)) # indirect doctest True """ return bool(self._summands_) @@ -616,9 +616,9 @@ def _repr_(self): EXAMPLES:: sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) - sage: (5*x^2 + 12*x) * (x^3 + O(x)) # indirect doctest + sage: (5*x^2+12*x) * (x^3+O(x)) # indirect doctest 5*x^5 + 12*x^4 + O(x^3) - sage: (5*x^2 - 12*x) * (x^3 + O(x)) # indirect doctest + sage: (5*x^2-12*x) * (x^3+O(x)) # indirect doctest 5*x^5 - 12*x^4 + O(x^3) """ s = ' + '.join(repr(elem) for elem in @@ -693,7 +693,7 @@ def _sub_(self, other): sage: O(x) - O(x) O(x) """ - return self + (-1) * other + return self + (-1)*other def _mul_term_(self, term): @@ -809,7 +809,7 @@ def __invert__(self): x^(-42) sage: ex = ~(1 + x); ex 1/x - x^(-2) + x^(-3) - x^(-4) + O(x^(-5)) - sage: ex * (1 + x) + sage: ex * (1+x) 1 + O(x^(-4)) sage: ~(1 + O(1/x)) 1 + O(1/x) @@ -833,7 +833,7 @@ def __invert__(self): expanding = True result = one while expanding: - new_result = (geom * result + one).truncate() + new_result = (geom*result + one).truncate() if new_result.has_same_summands(result): expanding = False result = new_result @@ -969,7 +969,7 @@ def O(self): sage: AR. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: O(x) O(x) - sage: expr = 42 * x^42 + x^10 + O(x^2); expr + sage: expr = 42*x^42 + x^10 + O(x^2); expr 42*x^42 + x^10 + O(x^2) sage: expr.O() O(x^42) @@ -1312,7 +1312,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): sage: S(x + y) x + y sage: S(2*x - 4*x*y^6) - -4*x * y^6 + 2*x + -4*x*y^6 + 2*x :: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 58766197482..74f03c52419 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -105,7 +105,7 @@ This contains elements of the form sage: C.an_element() - (1/2)^z * z^(1/2) * log(z)^(1/2) + (1/2)^z*z^(1/2)*log(z)^(1/2) The group `C` itself is a cartesian product; to be precise a :class:`~sage.rings.asymptotic.growth_group_cartesian.UnivariateProduct`. We @@ -138,18 +138,18 @@ sage: G_xy = agg.GrowthGroup('x^ZZ * y^ZZ'); G_xy Growth Group x^ZZ * y^ZZ sage: G_xy.an_element() - x * y + x*y sage: x = G_xy('x'); y = G_xy('y') sage: x^2 x^2 - sage: elem = x^21 * y^21; elem^2 - x^42 * y^42 + sage: elem = x^21*y^21; elem^2 + x^42*y^42 A monomial growth group itself is totally ordered, all elements are comparable. However, this does **not** hold for cartesian products:: - sage: e1 = x^2 * y; e2 = x * y^2 + sage: e1 = x^2*y; e2 = x*y^2 sage: e1 <= e2 or e2 <= e1 False @@ -170,10 +170,10 @@ sage: G = agg.GrowthGroup('QQ^x * x^ZZ * log(x)^QQ * y^QQ') sage: G.an_element() - (1/2)^x * x * log(x)^(1/2) * y^(1/2) + (1/2)^x*x*log(x)^(1/2)*y^(1/2) sage: (x, y) = var('x y') - sage: G(2^x * log(x) * y^(1/2)) * G(x^(-5) * 5^x * y^(1/3)) - 10^x * x^(-5) * log(x) * y^(5/6) + sage: G(2^x*log(x)*y^(1/2)) * G(x^(-5)*5^x*y^(1/3)) + 10^x*x^(-5)*log(x)*y^(5/6) AUTHORS: @@ -842,7 +842,7 @@ def _mul_(self, other): sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GenericGrowthGroup(ZZ) sage: g = G.an_element() - sage: g * g + sage: g*g Traceback (most recent call last): ... NotImplementedError: Only implemented in concrete realizations. @@ -964,7 +964,7 @@ def _eq_(self, other): sage: e1._eq_(P.gen()) True sage: e2 = e1^4 - sage: e2 == e1^2 * e1 * e1 + sage: e2 == e1^2*e1*e1 True sage: e2 == e1 False @@ -2047,9 +2047,9 @@ def _mul_(self, other): sage: b = P(x^3) sage: c = a._mul_(b); c x^5 - sage: c == a * b + sage: c == a*b True - sage: a * b * a # indirect doctest + sage: a*b*a # indirect doctest x^7 """ return self.parent()(raw_element=self.exponent + other.exponent) @@ -2590,9 +2590,9 @@ def _mul_(self, other): sage: b = P(3^x) sage: c = a._mul_(b); c 6^x - sage: c == a * b + sage: c == a*b True - sage: a * b * a # indirect doctest + sage: a*b*a # indirect doctest 12^x """ return self.parent()(raw_element=self.base * other.base) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 2d1dcb70154..483221e864f 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -71,7 +71,7 @@ :: sage: A.an_element() - (1/2)^x * x + (1/2)^x*x sage: tuple(E.an_element()) (1, x^(1/2)) """ @@ -327,7 +327,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): sage: C = cartesian_product([P, L], order='lex'); C Growth Group x^QQ * log(x)^ZZ sage: C.an_element() - x^(1/2) * log(x) + x^(1/2)*log(x) :: @@ -338,7 +338,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): sage: C = cartesian_product([Cx, Py], order='components'); C Growth Group x^QQ * log(x)^ZZ * y^QQ sage: C.an_element() - x^(1/2) * log(x) * y^(1/2) + x^(1/2)*log(x)*y^(1/2) .. SEEALSO: @@ -389,8 +389,8 @@ def _element_constructor_(self, data): Conversion from the symbolic ring works:: sage: x,y = var('x y') - sage: G(x^-3 * y^2) - x^(-3) * y^2 + sage: G(x^-3*y^2) + x^(-3)*y^2 sage: G(x^4), G(y^2) (x^4, y^2) sage: G(1) @@ -398,8 +398,8 @@ def _element_constructor_(self, data): Even more complex expressions can be parsed:: - sage: G_log(x^42 * log(x)^-42 * y^42) - x^42 * log(x)^(-42) * y^42 + sage: G_log(x^42*log(x)^-42*y^42) + x^42*log(x)^(-42)*y^42 TESTS:: @@ -422,7 +422,7 @@ def _element_constructor_(self, data): sage: GrowthGroup('QQ^x * x^QQ')(['x^(1/2)']) x^(1/2) sage: l = GrowthGroup('x^ZZ * log(x)^ZZ')(['x', 'log(x)']); l - x * log(x) + x*log(x) sage: type(l) sage: GrowthGroup('QQ^x * x^QQ')(['2^log(x)']) @@ -849,9 +849,9 @@ def _repr_(self): sage: P = agg.MonomialGrowthGroup(QQ, 'x') sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') sage: cartesian_product([P, L], order='lex').an_element()._repr_() - 'x^(1/2) * log(x)' + 'x^(1/2)*log(x)' """ - s = ' * '.join(repr(v) for v in self.value if not v.is_one()) + s = '*'.join(repr(v) for v in self.value if not v.is_one()) if s == '': return '1' return s From 8e0428e823c5da2ae12e053c3b59331aa89d876c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 20:26:31 +0200 Subject: [PATCH 0592/1872] remove special treating of 1/x in _repr_ (due to inconsitency) --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++++------ src/sage/rings/asymptotic/growth_group.py | 12 +++++------- src/sage/rings/asymptotic/term_monoid.py | 8 ++++---- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 7801dc87060..170f15d273d 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -161,7 +161,7 @@ expand `1/(1-z)` to a geometric series:: sage: 1 / (z-1) - 1/z + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21)) + z^(-1) + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21)) Since there is a default precision (parameter ``default_prec``) defined, only the first `20` summands are calculated. @@ -773,7 +773,7 @@ def _div_(self, other): sage: 1/x^42 x^(-42) sage: (1 + 4*x) / (x + 2*x^2) - 2*1/x - 1/2*x^(-2) + 1/4*x^(-3) - 1/8*x^(-4) + 1/16*x^(-5) + O(x^(-6)) + 2*x^(-1) - 1/2*x^(-2) + 1/4*x^(-3) - 1/8*x^(-4) + 1/16*x^(-5) + O(x^(-6)) sage: x / O(x) Traceback (most recent call last): ... @@ -804,15 +804,15 @@ def __invert__(self): sage: R. = AsymptoticRing('x^ZZ', QQ, default_prec=4) sage: ~x - 1/x + x^(-1) sage: ~(x^42) x^(-42) sage: ex = ~(1 + x); ex - 1/x - x^(-2) + x^(-3) - x^(-4) + O(x^(-5)) + x^(-1) - x^(-2) + x^(-3) - x^(-4) + O(x^(-5)) sage: ex * (1+x) 1 + O(x^(-4)) sage: ~(1 + O(1/x)) - 1 + O(1/x) + 1 + O(x^(-1)) """ if len(self.summands) == 0: raise ZeroDivisionError('Division by zero in %s.' % (self,)) @@ -1318,7 +1318,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): sage: A. = AsymptoticRing('a^ZZ * b^ZZ', QQ) sage: 1/a - 1/a + a^(-1) """ if summands is not None: if type(data) != int or data != 0: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 74f03c52419..ea94ab5e3d5 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -874,7 +874,7 @@ def __invert__(self): NotImplementedError: Only implemented in concrete realizations. sage: P = GrowthGroup('x^ZZ') sage: ~P.an_element() - 1/x + x^(-1) """ raise NotImplementedError('Inversion of %s not implemented ' '(in this abstract method).' % (self,)) @@ -1353,11 +1353,11 @@ def some_elements(self): sage: import sage.rings.asymptotic.growth_group as agg sage: tuple(agg.MonomialGrowthGroup(ZZ, 'z').some_elements()) - (1, z, 1/z, z^2, z^(-2), z^3, z^(-3), + (1, z, z^(-1), z^2, z^(-2), z^3, z^(-3), z^4, z^(-4), z^5, z^(-5), ...) sage: tuple(agg.MonomialGrowthGroup(QQ, 'z').some_elements()) (z^(1/2), z^(-1/2), z^2, z^(-2), - 1, z, 1/z, z^42, + 1, z, z^(-1), z^42, z^(2/3), z^(-2/3), z^(3/2), z^(-3/2), z^(4/5), z^(-4/5), z^(5/4), z^(-5/4), ...) """ @@ -2003,7 +2003,7 @@ def _repr_(self): TESTS:: sage: P(x^-1) # indirect doctest - 1/x + x^(-1) sage: P(x^-42) # indirect doctest x^(-42) """ @@ -2014,8 +2014,6 @@ def _repr_(self): return '1' elif self.exponent == 1: return var - elif self.exponent == -1: - return '1/' + var elif self.exponent in ZZ and self.exponent > 0: return var + '^' + str(self.exponent) else: @@ -2301,7 +2299,7 @@ def _convert_(self, data): sage: P('x^7') x^7 sage: P('1/x') - 1/x + x^(-1) sage: P('x^(-2)') x^(-2) sage: P('x^-2') diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 960f6914226..4aa007aad6f 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -720,7 +720,7 @@ def __le__(self, other): sage: g1 = GT(x); g2 = GT(x^2); g1, g2 (Generic Term with growth x, Generic Term with growth x^2) sage: o1 = OT(x^-1); o2 = OT(x^3); o1, o2 - (O(1/x), O(x^3)) + (O(x^(-1)), O(x^3)) sage: t1 = ET_ZZ(x^2, 5); t2 = ET_QQ(x^3, 2/7); t1, t2 (5*x^2, 2/7*x^3) @@ -732,7 +732,7 @@ def __le__(self, other): sage: g1 <= g2 True sage: o1, g1 - (O(1/x), Generic Term with growth x) + (O(x^(-1)), Generic Term with growth x) sage: o1 <= g1 False @@ -1421,7 +1421,7 @@ def some_elements(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: tuple(atm.OTermMonoid(G, QQ).some_elements()) - (O(1), O(x), O(1/x), O(x^2), O(x^(-2)), O(x^3), ...) + (O(1), O(x), O(x^(-1)), O(x^2), O(x^(-2)), O(x^3), ...) """ return iter(self(g) for g in self.growth_group.some_elements()) @@ -2277,7 +2277,7 @@ def __invert__(self): sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() sage: T = atm.ExactTermMonoid(G, QQ) sage: ~T(x, 1/2) # indirect doctest - 2*1/x + 2*x^(-1) """ try: c = ~self.coefficient From bf9e17698fec2637f483d938f4f83eb6e51d010d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 26 Aug 2015 20:33:31 +0200 Subject: [PATCH 0593/1872] extend error messages --- src/sage/rings/asymptotic/asymptotic_ring.py | 38 +++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 170f15d273d..9cf79b416c6 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1287,9 +1287,11 @@ def _element_constructor_(self, data, summands=None, simplify=True): sage: y = ZZ['y'].gen(); AR(y) Traceback (most recent call last): ... - ValueError: Growth y is not in Exact Term Monoid x^ZZ - with coefficients in Integer Ring. - > *previous* ValueError: y is not in Growth Group x^ZZ. + ValueError: Polynomial y is not in + Asymptotic Ring over Integer Ring + > *previous* ValueError: Growth y is not in + Exact Term Monoid x^ZZ with coefficients in Integer Ring. + >> *previous* ValueError: y is not in Growth Group x^ZZ. :: @@ -1372,12 +1374,21 @@ def _element_constructor_(self, data, summands=None, simplify=True): elif sage.rings.polynomial.polynomial_ring.is_PolynomialRing(P): p = P.gen() - return sum(self.create_summand('exact', growth=p**i, coefficient=c) - for i, c in enumerate(data)) + try: + return sum(self.create_summand('exact', growth=p**i, + coefficient=c) + for i, c in enumerate(data)) + except ValueError as e: + raise combine_exceptions( + ValueError('Polynomial %s is not in %s' % (data, self)), e) elif sage.rings.polynomial.multi_polynomial_ring_generic.is_MPolynomialRing(P): - return sum(self.create_summand('exact', growth=g, coefficient=c) - for c, g in iter(data)) + try: + return sum(self.create_summand('exact', growth=g, coefficient=c) + for c, g in iter(data)) + except ValueError as e: + raise combine_exceptions( + ValueError('Polynomial %s is not in %s' % (data, self)), e) elif sage.rings.power_series_ring.is_PowerSeriesRing(P): raise NotImplementedError( @@ -1387,10 +1398,19 @@ def _element_constructor_(self, data, summands=None, simplify=True): # Delete lines above as soon as we can deal with growths # other than the that at going to +oo. p = P.gen() - result = self(data.polynomial()) + try: + result = self(data.polynomial()) + except ValueError as e: + raise combine_exceptions( + ValueError('Powerseries %s is not in %s' % (data, self)), e) prec = data.precision_absolute() if prec < sage.rings.infinity.PlusInfinity(): - result += self.create_summand('O', growth=p**prec) + try: + result += self.create_summand('O', growth=p**prec) + except ValueError as e: + raise combine_exceptions( + ValueError('Powerseries %s is not in %s' % + (data, self)), e) return result return self._create_exact_summand_(data) From 737dc935e3fde541c840f9f03debbaa274d9c0ed Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 26 Aug 2015 22:11:07 +0200 Subject: [PATCH 0594/1872] rpow and exp implemented. --- .../asymptotic/growth_group_cartesian.py | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index ddc4809d3be..9dbdf51a5a7 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1019,6 +1019,118 @@ def log_factor(self, base=None): return log_factors + def rpow(self, base): + r""" + Take ``base`` to the power of this element. + + In other words, this is the exponential function with + ``base`` as its base. + + INPUT: + + - ``base`` -- the base of the exponential function. + + OUTPUT: + + A growth element. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x * x^ZZ') + sage: x, = G.gens_monomial() + sage: x.rpow(2) + 2^x + sage: x.rpow(1/2) + (1/2)^x + + :: + + sage: x.rpow(0) + Traceback (most recent call last): + ... + ValueError: 0 is not an allowed base. + sage: (x^2).rpow(2) + Traceback (most recent call last): + ... + ValueError: Cannot construct 2^(x^2) in Growth Group QQ^x * x^ZZ. + + :: + + sage: G = GrowthGroup('QQ^(x * log(x)) * x^ZZ * log(x)^ZZ') + sage: x, = G.gens_monomial() + sage: (x * log(x)).rpow(2) + 2^(x * log(x)) + """ + P = self.parent() + factors = self.factor() + if base == 0: + raise ValueError('%s is not an allowed base.' % (base,)) + + from sage.rings.asymptotic.growth_group import MonomialGrowthGroup + if len(factors) == 1: + fp = factors[0].parent() + if isinstance(fp, MonomialGrowthGroup) and repr(fp._var_).startswith('log('): + if factors[0]._raw_element_ == 1: + from sage.functions.log import log + new_elem = P(repr(fp._var_)[4:-1]) + if base == 'e': + return new_elem + base_ring = new_elem.factor()[0].base_ring() + return new_elem ** log(base_ring(base)) + + from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup + new_var = repr(self) + if '*' in new_var or '^' in new_var: + new_var = '(' + new_var + ')' + + def check_factor(factor): + return new_var == repr(factor._var_) and \ + isinstance(factor, ExponentialGrowthGroup) + + for cf in P.cartesian_factors(): + if hasattr(cf, 'cartesian_factors'): + for ccf in cf.cartesian_factors(): + if check_factor(ccf): + return P(ccf(raw_element=ccf.base_ring()(base))) + else: + if check_factor(cf): + return P(cf(raw_element=cf.base_ring()(base))) + + raise ValueError('Cannot construct %s^%s in %s.' % (base, new_var, P)) + + + def exp(self): + r""" + The exponential function of this element. + + INPUT: + + Nothing. + + OUTPUT: + + A growth element. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * log(x)^ZZ * log(log(x))^ZZ') + sage: x, = G.gens_monomial() + sage: exp(log(x)) + x + sage: exp(log(log(x))) + log(x) + + :: + + sage: exp(x) + Traceback (most recent call last): + ... + ValueError: Cannot construct e^x in Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ. + """ + return self.rpow('e') + CartesianProduct = CartesianProductGrowthGroups From 78baf4d4228ff42a3cc5724042144f5257b5dba8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 08:19:58 +0200 Subject: [PATCH 0595/1872] propagate a parent change during inversion group -> term -> ring --- src/sage/rings/asymptotic/growth_group.py | 23 +++++++++----- .../asymptotic/growth_group_cartesian.py | 30 +++++++++++++++++++ src/sage/rings/asymptotic/term_monoid.py | 15 +++++++--- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ea94ab5e3d5..ef279e9fe31 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2076,6 +2076,13 @@ def __invert__(self): True """ return self.parent()(raw_element=-self.exponent) + new_element = -self.exponent + try: + return self.parent()(raw_element=new_element) + except (ValueError, TypeError): + new_parent = self.parent().__class__(new_element.parent(), + self.parent()._var_) + return new_parent(raw_element=new_element) def __pow__(self, power): @@ -2610,21 +2617,23 @@ def __invert__(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('ZZ^x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('ZZ^x') sage: e1 = P(raw_element=2) sage: e2 = e1.__invert__(); e2 (1/2)^x sage: e2 == ~e1 True + sage: e2.parent() + Growth Group QQ^x """ - new_base = 1 / self.base + new_element = 1 / self.base try: - return self.parent()(raw_element=new_base) + return self.parent()(raw_element=new_element) except (ValueError, TypeError): - new_parent = ExponentialGrowthGroup(new_base.parent(), - self.parent()._var_) - return new_parent(raw_element=new_base) + new_parent = self.parent().__class__(new_element.parent(), + self.parent()._var_) + return new_parent(raw_element=new_element) def __pow__(self, power): diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 483221e864f..c3e955664e5 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -857,6 +857,36 @@ def _repr_(self): return s + def __invert__(self): + r""" + Return the multiplicative inverse of this cartesian product. + + OUTPUT: + + An growth element. + + .. NOTE:: + + The result may live in a larger parent than we started with. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('ZZ^x * x^ZZ') + sage: g = G('2^x * x^3') + sage: (~g).parent() + Growth Group QQ^x * x^ZZ + """ + new_element = tuple(~x for x in self.cartesian_factors()) + try: + return self.parent()(new_element) + except (ValueError, TypeError): + from sage.categories.cartesian_product import cartesian_product + new_parent = cartesian_product( + tuple(x.parent() for x in new_element)) + return new_parent(new_element) + + CartesianProduct = CartesianProductGrowthGroups diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 4aa007aad6f..044d60c4106 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2275,16 +2275,23 @@ def __invert__(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.ExactTermMonoid(G, QQ) - sage: ~T(x, 1/2) # indirect doctest - 2*x^(-1) + sage: T = atm.ExactTermMonoid(G, ZZ) + sage: ~T(x, 2) # indirect doctest + 1/2*x^(-1) + sage: (~T(x, 2)).parent() + Exact Term Monoid x^ZZ with coefficients in Rational Field """ try: c = ~self.coefficient except ZeroDivisionError: raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' 'cannot be inverted.' % (self, self.coefficient)) - return self.parent()(~self.growth, c) + g = ~self.growth + try: + return self.parent()(g, c) + except (ValueError, TypeError): + new_parent = self.parent().__class__(g.parent(), c.parent()) + return new_parent(g, c) def _can_absorb_(self, other): From 683caa6a4f4e51347909aeb1fd216210791280f1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 08:24:10 +0200 Subject: [PATCH 0596/1872] doc: explain coercions of asymptotic ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 9cf79b416c6..f511cc3d22f 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -206,6 +206,31 @@ Coercions and Functorial Constructions -------------------------------------- +The :class:`AsymptoticRing` fully supports +`coercion <../../../../coercion/index.html>`_. For example, the coefficient ring is automatically extended when needed:: + + sage: A + Asymptotic Ring over Integer Ring + sage: (z + 1/2).parent() + Asymptotic Ring over Rational Field + +Here, the coefficient ring was extended to allow `1/2` as a +coefficent. Another example is +:: + + sage: C. = AsymptoticRing(growth_group='c^ZZ', coefficient_ring=ZZ['e']) + sage: C.an_element() + -e^3*c^3 + O(c) + sage: C.an_element() / 7 + -e^3/7*c^3 + O(c) + +Here the result's coefficient ring is the newly found +:: + + sage: (C.an_element() / 7).parent() + Asymptotic Ring over + Univariate Polynomial Ring in e over Integer Ring + Data Structures --------------- From 1ce45abe0da9db62c4af4c3f4a98f647865a9efa Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 08:26:52 +0200 Subject: [PATCH 0597/1872] insert some empty lines for better separation of sections in doc --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index f511cc3d22f..27bbd655177 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -4,6 +4,7 @@ This module provides a ring (called :class:`AsymptoticRing`) for computations with asymptotic expressions. + Definition ========== @@ -21,6 +22,7 @@ .. _asymptotic_ring_growth: + Growth Elements --------------- @@ -73,6 +75,7 @@ without a formal deprecation. See http://trac.sagemath.org/17601 for details. + .. _asymptotic_ring_intro: Introductory Examples @@ -109,6 +112,7 @@ sage: B.an_element() -1/8*x^(3/2)*log(x)^3*(1/8)^y*y^(3/2) + O(x^(1/2)*log(x)*(1/2)^y*y^(1/2)) + Arithemtical Operations ----------------------- @@ -116,6 +120,7 @@ their elements) we can do a lot of different arithmetical calculations. + The Ring Operations Plus and Times ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,6 +159,7 @@ sage: (z+2*z^2+3*z^3+4*z^4) * (O(z)+z^2) 4*z^6 + O(z^5) + Division ^^^^^^^^ @@ -182,6 +188,7 @@ is not invertible, since it includes `0`. + Multivariate Arithemtic ^^^^^^^^^^^^^^^^^^^^^^^ @@ -200,9 +207,11 @@ write more examples + Selected Technical Details ========================== + Coercions and Functorial Constructions -------------------------------------- @@ -231,6 +240,7 @@ Asymptotic Ring over Univariate Polynomial Ring in e over Integer Ring + Data Structures --------------- @@ -272,6 +282,7 @@ | +-- successors: O(x), O(y) | +-- no predecessors + Various ======= @@ -281,6 +292,7 @@ - Benjamin Hackl (2015-07): improvement user interface (short notation) - Daniel Krenn (2015-08): various improvents, review; documentation + Methods ======= """ From 53c248cd5f915134eb63e96050b0c5b5f9e47996 Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Thu, 27 Aug 2015 10:29:10 +0200 Subject: [PATCH 0598/1872] Parallelization: corrected doc --- src/sage/tensor/modules/comp.py | 18 +++++++++--------- src/sage/tensor/modules/parallel_utilities.py | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 3a6d8f74786..0816a5a7cba 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1285,7 +1285,7 @@ def __add__(self, other): Parallel computation:: - sage: set_nproc_tensor(2); print get_nproc_tensor() + sage: set_nproc_tensor(2); get_nproc_tensor() 2 sage: s = a.__add__(b) ; s 1-index components w.r.t. [1, 2, 3] @@ -1401,7 +1401,7 @@ def __sub__(self, other): Parallel computation:: - sage: set_nproc_tensor(2); print get_nproc_tensor() + sage: set_nproc_tensor(2); get_nproc_tensor() 2 sage: s = a.__sub__(b) ; s 1-index components w.r.t. [1, 2, 3] @@ -1474,7 +1474,7 @@ def __mul__(self, other): True Parallel computation:: - sage: set_nproc_tensor(2);print get_nproc_tensor() + sage: set_nproc_tensor(2); get_nproc_tensor() 2 sage: s = a.__mul__(b) ; s 2-indices components w.r.t. [1, 2, 3] @@ -1484,7 +1484,7 @@ def __mul__(self, other): [-12 -15 -18] sage: s == a*b True - sage: set_nproc_tensor(1);print get_nproc_tensor() + sage: set_nproc_tensor(1); get_nproc_tensor() 1 """ @@ -1775,7 +1775,7 @@ def contract(self, *args): Parallel computation:: - sage: set_nproc_tensor(2); print get_nproc_tensor() + sage: set_nproc_tensor(2); get_nproc_tensor() 2 sage: s = a.contract(0, b, 0) ; s 1-index components w.r.t. [ @@ -1812,7 +1812,7 @@ def contract(self, *args): Parallel computation:: - sage: set_nproc_tensor(2); print get_nproc_tensor() + sage: set_nproc_tensor(2); get_nproc_tensor() 2 sage: c = a*b ; c 3-indices components w.r.t. [ @@ -3225,7 +3225,7 @@ def __mul__(self, other): True Parallel computation:: - sage: set_nproc_tensor(2);print get_nproc_tensor() + sage: set_nproc_tensor(2); get_nproc_tensor() 2 sage: s = a.__mul__(b) ; s 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) @@ -3243,7 +3243,7 @@ def __mul__(self, other): True sage: s == a*c True - sage: set_nproc_tensor(1);print get_nproc_tensor() + sage: set_nproc_tensor(1); get_nproc_tensor() 1 """ @@ -4549,7 +4549,7 @@ def __add__(self, other): Parallel computation:: - sage: set_nproc_tensor(2); print get_nproc_tensor() + sage: set_nproc_tensor(2); get_nproc_tensor() 2 sage: s = a.__add__(c) ; s # the symmetry is lost 2-indices components w.r.t. (1, 2, 3) diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py index 100145aebc5..fa7310333da 100644 --- a/src/sage/tensor/modules/parallel_utilities.py +++ b/src/sage/tensor/modules/parallel_utilities.py @@ -6,7 +6,7 @@ - the singleton class :class:`TensorParallelCompute` to gather the information relative to the parallelization of tensor algebra (basically the number of processes to be used) -- the global functions :func:`set_nproc` and :func:`get_nproc_tensor` to be used in +- the global functions :func:`set_nproc_tensor` and :func:`get_nproc_tensor` to be used in a Sage session for managing the number of processes involved in the parallelization. From 35e2e50d85c85d6a71674d78f41ce2ba52f4c286 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 27 Aug 2015 10:32:43 +0200 Subject: [PATCH 0599/1872] Restructure IntegerListsLex code --- src/doc/en/reference/combinat/module_list.rst | 4 +- src/sage/algebras/weyl_algebra.py | 3 +- src/sage/combinat/all.py | 5 +- src/sage/combinat/composition.py | 2 +- src/sage/combinat/enumerated_sets.py | 2 +- src/sage/combinat/integer_list.py | 2407 +---------------- src/sage/combinat/integer_lists/__init__.py | 6 + src/sage/combinat/integer_lists/base.pxd | 15 + src/sage/combinat/integer_lists/base.pyx | 700 +++++ src/sage/combinat/integer_lists/invlex.pxd | 3 + src/sage/combinat/integer_lists/invlex.pyx | 1661 ++++++++++++ src/sage/combinat/integer_lists/lists.py | 282 ++ src/sage/combinat/integer_lists/nn.py | 43 + src/sage/combinat/integer_matrices.py | 2 +- src/sage/combinat/integer_vector.py | 26 +- src/sage/combinat/partition.py | 2 +- src/sage/combinat/words/words.py | 5 +- 17 files changed, 2745 insertions(+), 2423 deletions(-) create mode 100644 src/sage/combinat/integer_lists/__init__.py create mode 100644 src/sage/combinat/integer_lists/base.pxd create mode 100644 src/sage/combinat/integer_lists/base.pyx create mode 100644 src/sage/combinat/integer_lists/invlex.pxd create mode 100644 src/sage/combinat/integer_lists/invlex.pyx create mode 100644 src/sage/combinat/integer_lists/lists.py create mode 100644 src/sage/combinat/integer_lists/nn.py diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 22e73970903..8dbac09bded 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -115,7 +115,9 @@ Comprehensive Module list sage/combinat/graph_path sage/combinat/gray_codes sage/combinat/hall_polynomial - sage/combinat/integer_list + sage/combinat/integer_lists/base + sage/combinat/integer_lists/lists + sage/combinat/integer_lists/invlex sage/combinat/integer_matrices sage/combinat/integer_vector sage/combinat/integer_vector_weighted diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 366b6bd99f2..1fcd43d97dc 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -695,8 +695,7 @@ def basis(self): dx^2, dx*dy, dy^2, x^3, x^2*y, x^2*dx, x^2*dy, x*y^2] """ n = self._n - # TODO in #17927: use IntegerVectors(length=2*n) - from sage.combinat.integer_list import IntegerListsNN + from sage.combinat.integer_lists.nn import IntegerListsNN I = IntegerListsNN(length=n*2) one = self.base_ring().one() f = lambda x: self.element_class(self, {(tuple(x[:n]),tuple(x[n:])): one}) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 1031746c30b..fa76fad7df8 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -46,9 +46,8 @@ #PerfectMatchings from perfect_matching import PerfectMatching, PerfectMatchings -# Integer lists lex - -from integer_list import IntegerListsLex as IntegerListsLex +# Integer lists +from integer_lists import IntegerListsLex #Compositions from composition import Composition, Compositions diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 1ccbbee4cfe..9fcf1524d7b 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -36,7 +36,7 @@ from sage.rings.all import ZZ from combinat import CombinatorialElement from cartesian_product import CartesianProduct -from integer_list import IntegerListsLex +from integer_lists import IntegerListsLex import __builtin__ from sage.rings.integer import Integer from sage.combinat.combinatorial_map import combinatorial_map diff --git a/src/sage/combinat/enumerated_sets.py b/src/sage/combinat/enumerated_sets.py index a39220a900e..f07071a3960 100644 --- a/src/sage/combinat/enumerated_sets.py +++ b/src/sage/combinat/enumerated_sets.py @@ -123,7 +123,7 @@ - :ref:`sage.combinat.dlx` - :ref:`sage.combinat.matrices.dlxcpp` - :ref:`sage.combinat.species` -- :class:`~sage.combinat.integer_list.IntegerListsLex` +- :class:`~sage.combinat.integer_lists.IntegerListsLex` - :class:`~sage.combinat.integer_vectors_mod_permgroup.IntegerVectorsModPermutationGroup` Low level enumerated sets diff --git a/src/sage/combinat/integer_list.py b/src/sage/combinat/integer_list.py index d37523b6e8a..136d7baa95f 100644 --- a/src/sage/combinat/integer_list.py +++ b/src/sage/combinat/integer_list.py @@ -1,2398 +1,15 @@ -r""" -Enumerated set of lists of integers with constraints, in inverse lexicographic order - -- :class:`IntegerListsLex`: the enumerated set of lists of nonnegative - integers with specified constraints, in inverse lexicographic order. - -- :class:`Envelope`: a utility class for upper (lower) envelope of a - function under constraints. - -HISTORY: - -This generic tool was originally written by Hivert and Thiery in -MuPAD-Combinat in 2000 and ported over to Sage by Mike Hansen in -2007. It was then completely rewritten in 2015 by Gillespie, -Schilling, and Thiery, with the help of many, to deal with -limitations and lack of robustness w.r.t. input. """ -#***************************************************************************** -# Copyright (C) 2015 Bryan Gillespie -# Nicolas M. Thiery -# Anne Schilling -# -# 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 inspect import ismethod -from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall -from sage.misc.constant_function import ConstantFunction -from sage.misc.cachefunc import cached_method -from sage.categories.enumerated_sets import EnumeratedSets -from sage.structure.list_clone import ClonableArray -from sage.structure.parent import Parent -from sage.sets.family import Family -from sage.rings.integer_ring import ZZ - -Infinity = float('+inf') - -class IntegerListsLex(Parent): - r""" - Lists of nonnegative integers with constraints, in inverse lexicographic order. - - An *integer list* is a list `l` of nonnegative integers, its *parts*. The - slope (at position `i`) is the difference ``l[i+1]-l[i]`` between two - consecutive parts. - - This class allows to construct the set `S` of all integer lists - `l` satisfying specified bounds on the sum, the length, the slope, - and the individual parts, enumerated in *inverse* lexicographic - order, that is from largest to smallest in lexicographic - order. Note that, to admit such an enumeration, `S` is almost - necessarily finite (see :ref:`IntegerListsLex_finiteness`). - - The main purpose is to provide a generic iteration engine for all the - enumerated sets like :class:`Partitions`, :class:`Compositions`, - :class:`IntegerVectors`. It can also be used to generate many other - combinatorial objects like Dyck paths, Motzkin paths, etc. Mathematically - speaking, this is a special case of set of integral points of a polytope (or - union thereof, when the length is not fixed). - - INPUT: - - - ``min_sum`` -- a nonnegative integer (default: 0): - a lower bound on ``sum(l)``. - - - ``max_sum`` -- a nonnegative integer or `\infty` (default: `\infty`): - an upper bound on ``sum(l)``. - - - ``n`` -- a nonnegative integer (optional): if specified, this - overrides ``min_sum`` and ``max_sum``. - - - ``min_length`` -- a nonnegative integer (default: `0`): a lower - bound on ``len(l)``. - - - ``max_length`` -- a nonnegative integer or `\infty` (default: - `\infty`): an upper bound on ``len(l)``. - - - ``length`` -- an integer (optional); overrides ``min_length`` - and ``max_length`` if specified; - - - ``min_part`` -- a nonnegative integer: a lower bounds on all - parts: ``min_part <= l[i]`` for ``0 <= i < len(l)``. - - - ``floor`` -- a list of nonnegative integers or a function: lower - bounds on the individual parts `l[i]`. - - If ``floor`` is a list of integers, then ``floor<=l[i]`` for ``0 - <= i < min(len(l), len(floor)``. Similarly, if ``floor`` is a - function, then ``floor(i) <= l[i]`` for ``0 <= i < len(l)``. - - - ``max_part`` -- a nonnegative integer or `\infty`: an upper - bound on all parts: ``l[i] <= max_part`` for ``0 <= i < len(l)``. - - - ``ceiling`` -- upper bounds on the individual parts ``l[i]``; - this takes the same type of input as ``floor``, except that - `\infty` is allowed in addition to integers, and the default - value is `\infty`. - - - ``min_slope`` -- an integer or `-\infty` (default: `-\infty`): - an lower bound on the slope between consecutive parts: - ``min_slope <= l[i+1]-l[i]`` for ``0 <= i < len(l)-1`` - - - ``max_slope`` -- an integer or `+\infty` (defaults: `+\infty`) - an upper bound on the slope between consecutive parts: - ``l[i+1]-l[i] <= max_slope`` for ``0 <= i < len(l)-1`` - - - ``category`` -- a category (default: :class:`FiniteEnumeratedSets`) - - - ``check`` -- boolean (default: ``True``): whether to display the - warnings raised when functions are given as input to ``floor`` - or ``ceiling`` and the errors raised when there is no proper - enumeration. - - - ``name`` -- a string or ``None`` (default: ``None``) if set, - this will be passed down to :meth:`Parent.rename` to specify the - name of ``self``. It is recommented to use directly the rename - method as this feature may become deprecated. - - - ``element_constructor`` -- a function (or callable) that creates - elements of ``self`` from a list. See also :class:`Parent`. - - - ``element_class`` -- a class for the elements of ``self`` - (default: `ClonableArray`). This merely sets the attribute - ``self.Element``. See the examples for details. - - - ``global_options`` -- a :class:`~sage.structure.global_options.GlobalOptions` - object that will be assigned to the attribute - ``_global_options``; for internal use only (subclasses, ...). - - - .. NOTE:: - - When several lists satisfying the constraints differ only by - trailing zeroes, only the shortest one is enumerated (and - therefore counted). The others are still considered valid. - See the examples below. - - This feature is questionable. It is recommended not to rely on - it, as it may eventually be discontinued. - - EXAMPLES: - - We create the enumerated set of all lists of nonnegative integers - of length `3` and sum `2`:: - - sage: C = IntegerListsLex(2, length=3) - sage: C - Integer lists of sum 2 satisfying certain constraints - sage: C.cardinality() - 6 - sage: [p for p in C] - [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] - - sage: [2, 0, 0] in C - True - sage: [2, 0, 1] in C - False - sage: "a" in C - False - sage: ["a"] in C - False - sage: C.first() - [2, 0, 0] - - One can specify lower and upper bounds on each part:: - - sage: list(IntegerListsLex(5, length=3, floor=[1,2,0], ceiling=[3,2,3])) - [[3, 2, 0], [2, 2, 1], [1, 2, 2]] - - When the length is fixed as above, one can also use - :class:`IntegerVectors`:: - - sage: IntegerVectors(2,3).list() - [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] - - Using the slope condition, one can generate integer partitions - (but see :class:`Partitions`):: - - sage: list(IntegerListsLex(4, max_slope=0)) - [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] - - The following is the list of all partitions of `7` with parts at least `2`:: - - sage: list(IntegerListsLex(7, max_slope=0, min_part=2)) - [[7], [5, 2], [4, 3], [3, 2, 2]] - - - .. RUBRIC:: floor and ceiling conditions - - Next we list all partitions of `5` of length at most `3` which are - bounded below by ``[2,1,1]``:: - - sage: list(IntegerListsLex(5, max_slope=0, max_length=3, floor=[2,1,1])) - [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1]] - - Note that ``[5]`` is considered valid, because the floor - constraints only apply to existing positions in the list. To - obtain instead the partitions containing ``[2,1,1]``, one needs to - use ``min_length`` or ``length``:: - - sage: list(IntegerListsLex(5, max_slope=0, length=3, floor=[2,1,1])) - [[3, 1, 1], [2, 2, 1]] - - Here is the list of all partitions of `5` which are contained in - ``[3,2,2]``:: - - sage: list(IntegerListsLex(5, max_slope=0, max_length=3, ceiling=[3,2,2])) - [[3, 2], [3, 1, 1], [2, 2, 1]] - - This is the list of all compositions of `4` (but see :class:`Compositions`):: - - sage: list(IntegerListsLex(4, min_part=1)) - [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] - - This is the list of all integer vectors of sum `4` and length `3`:: - - sage: list(IntegerListsLex(4, length=3)) - [[4, 0, 0], [3, 1, 0], [3, 0, 1], [2, 2, 0], [2, 1, 1], - [2, 0, 2], [1, 3, 0], [1, 2, 1], [1, 1, 2], [1, 0, 3], - [0, 4, 0], [0, 3, 1], [0, 2, 2], [0, 1, 3], [0, 0, 4]] - - For whatever it is worth, the ``floor`` and ``min_part`` - constraints can be combined:: - - sage: L = IntegerListsLex(5, floor=[2,0,2], min_part=1) - sage: L.list() - [[5], [4, 1], [3, 2], [2, 3], [2, 1, 2]] - - This is achieved by updating the floor upon constructing ``L``:: - - sage: [L._floor(i) for i in range(5)] - [2, 1, 2, 1, 1] - - Similarly, the ``ceiling`` and ``max_part`` constraints can be - combined:: - - sage: L = IntegerListsLex(4, ceiling=[2,3,1], max_part=2, length=3) - sage: L.list() - [[2, 2, 0], [2, 1, 1], [1, 2, 1]] - sage: [L._ceiling(i) for i in range(5)] - [2, 2, 1, 2, 2] - - - This can be used to generate Motzkin words (see - :wikipedia:`Motzkin_number`):: - - sage: def motzkin_words(n): - ....: return IntegerListsLex(length=n+1, min_slope=-1, max_slope=1, - ....: ceiling=[0]+[+oo for i in range(n-1)]+[0]) - sage: motzkin_words(4).list() - [[0, 1, 2, 1, 0], - [0, 1, 1, 1, 0], - [0, 1, 1, 0, 0], - [0, 1, 0, 1, 0], - [0, 1, 0, 0, 0], - [0, 0, 1, 1, 0], - [0, 0, 1, 0, 0], - [0, 0, 0, 1, 0], - [0, 0, 0, 0, 0]] - sage: [motzkin_words(n).cardinality() for n in range(8)] - [1, 1, 2, 4, 9, 21, 51, 127] - sage: oeis(_) # optional -- internet - 0: A001006: Motzkin numbers: number of ways of drawing any number - of nonintersecting chords joining n (labeled) points on a circle. - - or Dyck words (see also :class:`DyckWords`), through the bijection - with paths from `(0,0)` to `(n,n)` with left and up steps that remain - below the diagonal:: - - sage: def dyck_words(n): - ....: return IntegerListsLex(length=n, ceiling=range(n+1), min_slope=0) - sage: [dyck_words(n).cardinality() for n in range(8)] - [1, 1, 2, 5, 14, 42, 132, 429] - sage: dyck_words(3).list() - [[0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 0]] - - - .. _IntegerListsLex_finiteness: - - .. RUBRIC:: On finiteness and inverse lexicographic enumeration - - The set of all lists of integers cannot be enumerated in inverse - lexicographic order, since there is no largest list (take `[n]` - for `n` as large as desired):: - - sage: IntegerListsLex().first() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - Here is a variant which could be enumerated in lexicographic order - but not in inverse lexicographic order:: - - sage: L = IntegerListsLex(length=2, ceiling=[Infinity, 0], floor=[0,1]) - sage: for l in L: print l - Traceback (most recent call last): - ... - ValueError: infinite upper bound for values of m - - Even when the sum is specified, it is not necessarily possible to - enumerate *all* elements in inverse lexicographic order. In the - following example, the list ``[1, 1, 1]`` will never appear in the - enumeration:: - - sage: IntegerListsLex(3).first() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - If one wants to proceed anyway, one can sign a waiver by setting - ``check=False`` (again, be warned that some valid lists may never appear):: - - sage: L = IntegerListsLex(3, check=False) - sage: it = iter(L) - sage: [next(it) for i in range(6)] - [[3], [2, 1], [2, 0, 1], [2, 0, 0, 1], [2, 0, 0, 0, 1], [2, 0, 0, 0, 0, 1]] - - In fact, being inverse lexicographically enumerable is almost - equivalent to being finite. The only infinity that can occur would - be from a tail of numbers `0,1` as in the previous example, where - the `1` moves further and further to the right. If there is any - list that is inverse lexicographically smaller than such a - configuration, the iterator would not reach it and hence would not - be considered iterable. Given that the infinite cases are very - specific, at this point only the finite cases are supported - (without signing the waiver). - - The finiteness detection is not complete yet, so some finite cases - may not be supported either, at least not without disabling the - checks. Practical examples of such are welcome. - - .. RUBRIC:: On trailing zeroes, and their caveats - - As mentioned above, when several lists satisfying the constraints - differ only by trailing zeroes, only the shortest one is listed:: - - sage: L = IntegerListsLex(max_length=4, max_part=1) - sage: L.list() - [[1, 1, 1, 1], - [1, 1, 1], - [1, 1, 0, 1], - [1, 1], - [1, 0, 1, 1], - [1, 0, 1], - [1, 0, 0, 1], - [1], - [0, 1, 1, 1], - [0, 1, 1], - [0, 1, 0, 1], - [0, 1], - [0, 0, 1, 1], - [0, 0, 1], - [0, 0, 0, 1], - []] - - and counted:: - - sage: L.cardinality() - 16 - - Still, the others are considered as elements of `L`:: - - sage: L = IntegerListsLex(4,min_length=3,max_length=4) - sage: L.list() - [..., [2, 2, 0], ...] - - sage: [2, 2, 0] in L # in L.list() - True - sage: [2, 2, 0, 0] in L # not in L.list() ! - True - sage: [2, 2, 0, 0, 0] in L - False - - .. RUBRIC:: Specifying functions as input for the floor or ceiling - - We construct all lists of sum `4` and length `4` such that ``l[i] <= i``:: - - sage: list(IntegerListsLex(4, length=4, ceiling=lambda i: i, check=False)) - [[0, 1, 2, 1], [0, 1, 1, 2], [0, 1, 0, 3], [0, 0, 2, 2], [0, 0, 1, 3]] - - .. WARNING:: - - When passing a function as ``floor`` or ``ceiling``, it may - become undecidable to detect improper inverse lexicographic - enumeration. For example, the following example has a finite - enumeration:: - - sage: L = IntegerListsLex(3, floor=lambda i: 1 if i>=2 else 0, check=False) - sage: L.list() - [[3], - [2, 1], - [2, 0, 1], - [1, 2], - [1, 1, 1], - [1, 0, 2], - [1, 0, 1, 1], - [0, 3], - [0, 2, 1], - [0, 1, 2], - [0, 1, 1, 1], - [0, 0, 3], - [0, 0, 2, 1], - [0, 0, 1, 2], - [0, 0, 1, 1, 1]] - - but one cannot decide whether the following has an improper - inverse lexicographic enumeration without computing the floor - all the way to ``Infinity``:: - - sage: L = IntegerListsLex(3, floor=lambda i: 0, check=False) - sage: it = iter(L) - sage: [next(it) for i in range(6)] - [[3], [2, 1], [2, 0, 1], [2, 0, 0, 1], [2, 0, 0, 0, 1], [2, 0, 0, 0, 0, 1]] - - Hence a warning is raised when a function is specified as - input, unless the waiver is signed by setting ``check=False``:: - - sage: L = IntegerListsLex(3, floor=lambda i: 1 if i>=2 else 0) - doctest:... - A function has been given as input of the floor=[...] or ceiling=[...] - arguments of IntegerListsLex. Please see the documentation for the caveats. - If you know what you are doing, you can set check=False to skip this warning. - - Similarly, the algorithm may need to search forever for a - solution when the ceiling is ultimately zero:: - - sage: L = IntegerListsLex(2,ceiling=lambda i:0, check=False) - sage: L.first() # not tested: will hang forever - sage: L = IntegerListsLex(2,ceiling=lambda i:0 if i<20 else 1, check=False) - sage: it = iter(L) - sage: next(it) - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] - sage: next(it) - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1] - sage: next(it) - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1] - - - .. RUBRIC:: Tip: using disjoint union enumerated sets for additional flexibility - - Sometimes, specifying a range for the sum or the length may be too - restrictive. One would want instead to specify a list, or - iterable `L`, of acceptable values. This is easy to achieve using - a :class:`disjoint union of enumerated sets `. - Here we want to accept the values `n=0,2,3`:: - - sage: C = DisjointUnionEnumeratedSets(Family([0,2,3], - ....: lambda n: IntegerListsLex(n, length=2))) - sage: C - Disjoint union of Finite family - {0: Integer lists of sum 0 satisfying certain constraints, - 2: Integer lists of sum 2 satisfying certain constraints, - 3: Integer lists of sum 3 satisfying certain constraints} - sage: C.list() - [[0, 0], - [2, 0], [1, 1], [0, 2], - [3, 0], [2, 1], [1, 2], [0, 3]] - - The price to pay is that the enumeration order is now *graded - lexicographic* instead of lexicographic: first choose the value - according to the order specified by `L`, and use lexicographic - order within each value. Here is we reverse `L`:: - - sage: DisjointUnionEnumeratedSets(Family([3,2,0], - ....: lambda n: IntegerListsLex(n, length=2))).list() - [[3, 0], [2, 1], [1, 2], [0, 3], - [2, 0], [1, 1], [0, 2], - [0, 0]] - - Note that if a given value appears several times, the - corresponding elements will be enumerated several times, which - may, or not, be what one wants:: - - sage: DisjointUnionEnumeratedSets(Family([2,2], - ....: lambda n: IntegerListsLex(n, length=2))).list() - [[2, 0], [1, 1], [0, 2], [2, 0], [1, 1], [0, 2]] - - Here is a variant where we specify acceptable values for the - length:: - - sage: DisjointUnionEnumeratedSets(Family([0,1,3], - ....: lambda l: IntegerListsLex(2, length=l))).list() - [[2], - [2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] - - - This technique can also be useful to obtain a proper enumeration - on infinite sets by using a graded lexicographic enumeration:: - - sage: C = DisjointUnionEnumeratedSets(Family(NN, - ....: lambda n: IntegerListsLex(n, length=2))) - sage: C - Disjoint union of Lazy family ((i))_{i in Non negative integer semiring} - sage: it = iter(C) - sage: [next(it) for i in range(10)] - [[0, 0], - [1, 0], [0, 1], - [2, 0], [1, 1], [0, 2], - [3, 0], [2, 1], [1, 2], [0, 3]] - - - .. RUBRIC:: Specifying how to construct elements - - This is the list of all monomials of degree `4` which divide the - monomial `x^3y^1z^2` (a monomial being identified with its - exponent vector):: - - sage: R. = QQ[] - sage: m = [3,1,2] - sage: def term(exponents): - ....: return x^exponents[0] * y^exponents[1] * z^exponents[2] - sage: list( IntegerListsLex(4, length=len(m), ceiling=m, element_constructor=term) ) - [x^3*y, x^3*z, x^2*y*z, x^2*z^2, x*y*z^2] - - Note the use of the ``element_constructor`` option to specify how - to construct elements from a plain list. - - A variant is to specify a class for the elements. With the default - element constructor, this class should take as input the parent - ``self`` and a list. Here we want the elements to be constructed - in the class :class:`Partition`:: - - sage: IntegerListsLex(3, max_slope=0, element_class=Partition, global_options=Partitions.global_options).list() - [[3], [2, 1], [1, 1, 1]] - - Note that the :class:`Partition` further assumes the existence of - an attribute ``_global_options`` in the parent, hence the use of the - ``global_options`` parameter. - - .. WARNING:: - - The protocol for specifying the element class and constructor - is subject to changes. - - ALGORITHM: - - The iteration algorithm uses a depth first search through the - prefix tree of the list of integers (see also - :ref:`section-generic-integerlistlex`). While doing so, it does - some lookahead heuristics to attempt to cut dead branches. - - In most practical use cases, most dead branches are cut. Then, - roughly speaking, the time needed to iterate through all the - elements of `S` is proportional to the number of elements, where - the proportion factor is controlled by the length `l` of the - longest element of `S`. In addition, the memory usage is also - controlled by `l`, which is to say negligible in practice. - - Still, there remains much room for efficiency improvements; see - :trac:`18055`, :trac:`18056`. - - .. NOTE:: - - The generation algorithm could in principle be extended to - deal with non-constant slope constraints and with negative - parts. - - TESTS: - - This example from the combinatorics tutorial used to fail before - :trac:`17979` because the floor conditions did not satisfy the - slope conditions:: - - sage: I = IntegerListsLex(16, min_length=2, max_slope=-1, floor=[5,3,3]) - sage: I.list() - [[13, 3], [12, 4], [11, 5], [10, 6], [9, 7], [9, 4, 3], [8, 5, 3], [8, 4, 3, 1], - [7, 6, 3], [7, 5, 4], [7, 5, 3, 1], [7, 4, 3, 2], [6, 5, 4, 1], [6, 5, 3, 2], - [6, 4, 3, 2, 1]] - - :: - - sage: Partitions(2, max_slope=-1, length=2).list() - [] - sage: list(IntegerListsLex(0, floor=ConstantFunction(1), min_slope=0)) - [[]] - sage: list(IntegerListsLex(0, floor=ConstantFunction(1), min_slope=0, max_slope=0)) - [[]] - sage: list(IntegerListsLex(0, max_length=0, floor=ConstantFunction(1), min_slope=0, max_slope=0)) - [[]] - sage: list(IntegerListsLex(0, max_length=0, floor=ConstantFunction(0), min_slope=0, max_slope=0)) - [[]] - sage: list(IntegerListsLex(0, min_part=1, min_slope=0)) - [[]] - sage: list(IntegerListsLex(1, min_part=1, min_slope=0)) - [[1]] - sage: list(IntegerListsLex(0, min_length=1, min_part=1, min_slope=0)) - [] - sage: list(IntegerListsLex(0, min_length=1, min_slope=0)) - [[0]] - sage: list(IntegerListsLex(3, max_length=2)) - [[3], [2, 1], [1, 2], [0, 3]] - sage: partitions = {"min_part": 1, "max_slope": 0} - sage: partitions_min_2 = {"floor": ConstantFunction(2), "max_slope": 0} - sage: compositions = {"min_part": 1} - sage: integer_vectors = lambda l: {"length": l} - sage: lower_monomials = lambda c: {"length": c, "floor": lambda i: c[i]} - sage: upper_monomials = lambda c: {"length": c, "ceiling": lambda i: c[i]} - sage: constraints = { "min_part":1, "min_slope": -1, "max_slope": 0} - sage: list(IntegerListsLex(6, **partitions)) - [[6], - [5, 1], - [4, 2], - [4, 1, 1], - [3, 3], - [3, 2, 1], - [3, 1, 1, 1], - [2, 2, 2], - [2, 2, 1, 1], - [2, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1]] - sage: list(IntegerListsLex(6, **constraints)) - [[6], - [3, 3], - [3, 2, 1], - [2, 2, 2], - [2, 2, 1, 1], - [2, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1]] - sage: list(IntegerListsLex(1, **partitions_min_2)) - [] - sage: list(IntegerListsLex(2, **partitions_min_2)) - [[2]] - sage: list(IntegerListsLex(3, **partitions_min_2)) - [[3]] - sage: list(IntegerListsLex(4, **partitions_min_2)) - [[4], [2, 2]] - sage: list(IntegerListsLex(5, **partitions_min_2)) - [[5], [3, 2]] - sage: list(IntegerListsLex(6, **partitions_min_2)) - [[6], [4, 2], [3, 3], [2, 2, 2]] - sage: list(IntegerListsLex(7, **partitions_min_2)) - [[7], [5, 2], [4, 3], [3, 2, 2]] - sage: list(IntegerListsLex(9, **partitions_min_2)) - [[9], [7, 2], [6, 3], [5, 4], [5, 2, 2], [4, 3, 2], [3, 3, 3], [3, 2, 2, 2]] - sage: list(IntegerListsLex(10, **partitions_min_2)) - [[10], - [8, 2], - [7, 3], - [6, 4], - [6, 2, 2], - [5, 5], - [5, 3, 2], - [4, 4, 2], - [4, 3, 3], - [4, 2, 2, 2], - [3, 3, 2, 2], - [2, 2, 2, 2, 2]] - sage: list(IntegerListsLex(4, **compositions)) - [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] - sage: list(IntegerListsLex(6, min_length=1, floor=[7])) - [] - sage: L = IntegerListsLex(10**100,length=1) - sage: L.list() - [[10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]] - - Noted on :trac:`17898`:: - - sage: list(IntegerListsLex(4, min_part=1, length=3, min_slope=1)) - [] - sage: IntegerListsLex(6, ceiling=[4,2], floor=[3,3]).list() - [] - sage: IntegerListsLex(6, min_part=1, max_part=3, max_slope=-4).list() - [] - - Noted in :trac:`17548`, which are now fixed:: - - sage: IntegerListsLex(10, min_part=2, max_slope=-1).list() - [[10], [8, 2], [7, 3], [6, 4], [5, 3, 2]] - sage: IntegerListsLex(5, min_slope=1, floor=[2,1,1], max_part=2).list() - [] - sage: IntegerListsLex(4, min_slope=0, max_slope=0).list() - [[4], [2, 2], [1, 1, 1, 1]] - sage: IntegerListsLex(6, min_slope=-1, max_slope=-1).list() - [[6], [3, 2, 1]] - sage: IntegerListsLex(6, min_length=3, max_length=2, min_part=1).list() - [] - sage: I = IntegerListsLex(3, max_length=2, min_part=1) - sage: I.list() - [[3], [2, 1], [1, 2]] - sage: [1,1,1] in I - False - sage: I=IntegerListsLex(10, ceiling=[4], max_length=1, min_part=1) - sage: I.list() - [] - sage: [4,6] in I - False - sage: I = IntegerListsLex(4, min_slope=1, min_part=1, max_part=2) - sage: I.list() - [] - sage: I = IntegerListsLex(7, min_slope=1, min_part=1, max_part=4) - sage: I.list() - [[3, 4], [1, 2, 4]] - sage: I = IntegerListsLex(4, floor=[2,1], ceiling=[2,2], max_length=2, min_slope=0) - sage: I.list() - [[2, 2]] - sage: I = IntegerListsLex(10, min_part=1, max_slope=-1) - sage: I.list() - [[10], [9, 1], [8, 2], [7, 3], [7, 2, 1], [6, 4], [6, 3, 1], [5, 4, 1], - [5, 3, 2], [4, 3, 2, 1]] - - - .. RUBRIC:: TESTS from comments on :trac:`17979` - - Comment 191:: - - sage: list(IntegerListsLex(1, min_length=2, min_slope=0, max_slope=0)) - [] - - Comment 240:: - - sage: L = IntegerListsLex(min_length=2, max_part=0) - sage: L.list() - [[0, 0]] - - .. RUBRIC:: Tests on the element constructor feature and mutability - - Internally, the iterator works on a single list that is mutated - along the way. The following test makes sure that we actually make a copy of - this list before passing it to ``element_constructor`` in order to - avoid reference effects:: - - sage: from sage.misc.c3_controlled import identity - sage: P = IntegerListsLex(n=3, max_slope=0, min_part=1, element_constructor=identity) - sage: list(P) - [[3], [2, 1], [1, 1, 1]] - - Same, step by step:: - - sage: it = iter(P) - sage: a = next(it); a - [3] - sage: b = next(it); b - [2, 1] - sage: a - [3] - sage: a is b - False - - Tests from `MuPAD-Combinat `_:: - - sage: IntegerListsLex(7, min_length=2, max_length=6, floor=[0,0,2,0,0,1], ceiling=[3,2,3,2,1,2]).cardinality() - 83 - sage: IntegerListsLex(7, min_length=2, max_length=6, floor=[0,0,2,0,1,1], ceiling=[3,2,3,2,1,2]).cardinality() - 53 - sage: IntegerListsLex(5, min_length=2, max_length=6, floor=[0,0,2,0,0,0], ceiling=[2,2,2,2,2,2]).cardinality() - 30 - sage: IntegerListsLex(5, min_length=2, max_length=6, floor=[0,0,1,1,0,0], ceiling=[2,2,2,2,2,2]).cardinality() - 43 - - sage: IntegerListsLex(0, min_length=0, max_length=7, floor=[1,1,0,0,1,0], ceiling=[4,3,2,3,2,2,1]).first() - [] - - sage: IntegerListsLex(0, min_length=1, max_length=7, floor=[0,1,0,0,1,0], ceiling=[4,3,2,3,2,2,1]).first() - [0] - sage: IntegerListsLex(0, min_length=1, max_length=7, floor=[1,1,0,0,1,0], ceiling=[4,3,2,3,2,2,1]).cardinality() - 0 - - sage: IntegerListsLex(2, min_length=0, max_length=7, floor=[1,1,0,0,0,0], ceiling=[4,3,2,3,2,2,1]).first() # Was [1,1], due to slightly different specs - [2] - sage: IntegerListsLex(1, min_length=1, max_length=7, floor=[1,1,0,0,0,0], ceiling=[4,3,2,3,2,2,1]).first() - [1] - sage: IntegerListsLex(1, min_length=2, max_length=7, floor=[1,1,0,0,0,0], ceiling=[4,3,2,3,2,2,1]).cardinality() - 0 - sage: IntegerListsLex(2, min_length=5, max_length=7, floor=[1,1,0,0,0,0], ceiling=[4,3,2,3,2,2,1]).first() - [1, 1, 0, 0, 0] - sage: IntegerListsLex(2, min_length=5, max_length=7, floor=[1,1,0,0,0,1], ceiling=[4,3,2,3,2,2,1]).first() - [1, 1, 0, 0, 0] - sage: IntegerListsLex(2, min_length=5, max_length=7, floor=[1,1,0,0,1,0], ceiling=[4,3,2,3,2,2,1]).cardinality() - 0 - - sage: IntegerListsLex(4, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).cardinality() - 0 - sage: IntegerListsLex(5, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).first() - [2, 1, 2] - sage: IntegerListsLex(6, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).first() - [3, 1, 2] - sage: IntegerListsLex(12, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).first() - [3, 1, 2, 3, 2, 1] - sage: IntegerListsLex(13, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).first() - [3, 1, 2, 3, 2, 2] - sage: IntegerListsLex(14, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).cardinality() - 0 - - This used to hang (see comment 389 and fix in :meth:`Envelope.__init__`):: - - sage: IntegerListsLex(7, max_part=0, ceiling=lambda i:i, check=False).list() - [] - """ - __metaclass__ = ClasscallMetaclass - - @staticmethod - def __classcall_private__(cls, n=None, **kwargs): - r""" - Return a disjoint union if ``n`` is a list or iterable. - - TESTS: - - Specifying a list or iterable as argument is deprecated:: - - sage: IntegerListsLex([2,2], length=2).list() - doctest:...: DeprecationWarning: Calling IntegerListsLex with n an iterable is deprecated. Please use DisjointUnionEnumeratedSets or the min_sum and max_sum arguments instead - See http://trac.sagemath.org/17979 for details. - [[2, 0], [1, 1], [0, 2], [2, 0], [1, 1], [0, 2]] - sage: IntegerListsLex(NN, max_length=3) - Disjoint union of Lazy family ((i))_{i in Non negative integer semiring} - """ - import collections - if isinstance(n, collections.Iterable): - from sage.misc.superseded import deprecation - deprecation(17979, 'Calling IntegerListsLex with n an iterable is deprecated. Please use DisjointUnionEnumeratedSets or the min_sum and max_sum arguments instead') - from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets - return DisjointUnionEnumeratedSets(Family(n, lambda i: IntegerListsLex(i, **kwargs))) - else: - return typecall(cls, n=n, **kwargs) - - def __init__(self, - n=None, - length=None, min_length=0, max_length=Infinity, - floor=None, ceiling=None, - min_part=0, max_part=Infinity, - min_slope=-Infinity, max_slope=Infinity, - min_sum=0, max_sum=Infinity, - name=None, - category=None, - element_constructor=None, element_class=None, - global_options=None, - check=True): - """ - Initialize ``self``. - - TESTS:: - - sage: C = IntegerListsLex(2, length=3) - sage: C == loads(dumps(C)) - True - sage: C == loads(dumps(C)) # this did fail at some point, really! - True - sage: C is loads(dumps(C)) # todo: not implemented - True - sage: C.cardinality().parent() is ZZ - True - sage: TestSuite(C).run() - - sage: IntegerListsLex(min_sum=Infinity).list() - Traceback (most recent call last): - ... - TypeError: unable to coerce to an integer - sage: IntegerListsLex(min_sum=1.4).list() - Traceback (most recent call last): - ... - TypeError: Attempt to coerce non-integral RealNumber to Integer - """ - if category is None: - category = EnumeratedSets().Finite() - - self._check = check - - if n is not None: - min_sum = n - max_sum = n - self._min_sum = ZZ(min_sum) - self._max_sum = ZZ(max_sum) if max_sum != Infinity else Infinity - - if length is not None: - min_length = length - max_length = length - self._min_length = max(ZZ(min_length), 0) - self._max_length = ZZ(max_length) if max_length != Infinity else Infinity - - self._min_slope = ZZ(min_slope) if min_slope != -Infinity else -Infinity - self._max_slope = ZZ(max_slope) if max_slope != Infinity else Infinity - - self._min_part = ZZ(min_part) - if self._min_part < 0: - raise NotImplementedError("strictly negative min_part") - self._max_part = ZZ(max_part) if max_part != Infinity else Infinity - - # self._floor_or_ceiling_is_function will be set to ``True`` - # if a function is given as input for floor or ceiling; in - # this case a warning will be emitted, unless the user sets - # check=False. See the documentation. - self._floor_or_ceiling_is_function = False - if floor is None: - floor = 0 - elif isinstance(floor, (list, tuple)): - floor = tuple(ZZ(i) for i in floor) - if not all(i >= 0 for i in floor): - raise NotImplementedError("negative parts in floor={}".format(floor)) - elif callable(floor): - self._floor_or_ceiling_is_function = True - else: - raise TypeError("floor should be a list, tuple, or function") - self._floor = Envelope(floor, sign=-1, - min_part= self._min_part, max_part= self._max_part, - min_slope= self._min_slope, max_slope=self._max_slope, - min_length=self._min_length) - - if ceiling is None: - ceiling = Infinity - elif isinstance(ceiling, (list, tuple)): - ceiling = tuple(ZZ(i) if i != Infinity else Infinity - for i in ceiling) - if not all(i >= 0 for i in ceiling): - raise NotImplementedError("negative parts in ceiling={}".format(ceiling)) - elif callable(ceiling): - self._floor_or_ceiling_is_function = True - else: - raise ValueError("Unable to parse value of parameter ceiling") - self._ceiling = Envelope(ceiling, sign=1, - min_part= self._min_part, max_part= self._max_part, - min_slope= self._min_slope, max_slope=self._max_slope, - min_length=self._min_length) - - if name is not None: - self.rename(name) - - if self._floor_or_ceiling_is_function and self._check: - from warnings import warn - warn(""" -A function has been given as input of the floor=[...] or ceiling=[...] -arguments of IntegerListsLex. Please see the documentation for the caveats. -If you know what you are doing, you can set check=False to skip this warning.""") - - # Customization of the class and constructor for the elements - - # We set the following attribute to True if the element - # constructor is known to be safe and does not claim ownership - # on the input list. In this case, we can save a copy in Iter.next. - self._element_constructor_is_copy_safe = False - if element_class is not None: - self.Element = element_class - if element_constructor is not None: - if element_constructor is list or element_constructor is tuple: - self._element_constructor_is_copy_safe = True - elif issubclass(self.Element, ClonableArray): - # Not all element class support check=False - element_constructor = self._element_constructor_nocheck - self._element_constructor_is_copy_safe = True - if global_options is not None: - self.global_options = global_options - - Parent.__init__(self, element_constructor=element_constructor, - category=category) - - @cached_method - def _check_finiteness(self): - """ - Check that the constraints define a finite set. - - As mentioned in the description of this class, being finite is - almost equivalent to being inverse lexicographic iterable, - which is what we really care about. - - This set is finite if and only if: - - #. For each `i` such that there exists a list of length at - least `i+1` satisfying the constraints, there exists a - direct or indirect upper bound on the `i`-th part, that - is ``self._ceiling(i)`` is finite. - - #. There exists a global upper bound on the length. - - Failures for 1. are detected and reported later, during the - iteration, namely the first time a prefix including the `i`-th - part is explored. - - This method therefore focuses on 2., namely trying to prove - the existence of an upper bound on the length. It may fail - to do so even when the set is actually finite. - - OUTPUT: ``None`` if this method finds a proof that there - exists an upper bound on the length. Otherwise a - ``ValueError`` is raised. - - EXAMPLES:: - - sage: L = IntegerListsLex(4, max_length=4) - sage: L._check_finiteness() - - The following example is infinite:: - - sage: L = IntegerListsLex(4) - sage: L._check_finiteness() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - Indeed:: - - sage: it = iter(IntegerListsLex(4, check=False)) - sage: for _ in range(10): print next(it) - [4] - [3, 1] - [3, 0, 1] - [3, 0, 0, 1] - [3, 0, 0, 0, 1] - [3, 0, 0, 0, 0, 1] - [3, 0, 0, 0, 0, 0, 1] - [3, 0, 0, 0, 0, 0, 0, 1] - [3, 0, 0, 0, 0, 0, 0, 0, 1] - [3, 0, 0, 0, 0, 0, 0, 0, 0, 1] - - Unless ``check=False`, :meth:`_check_finiteness` is called as - soon as an iteration is attempted:: - - sage: iter(L) - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - Some other infinite examples:: - - sage: L = IntegerListsLex(ceiling=[0], min_slope=1, max_slope=2) - sage: L.list() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - sage: L = IntegerListsLex(ceiling=[0], min_slope=1, max_slope=1) - sage: L.list() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - sage: IntegerListsLex(ceiling=[0], min_slope=1, max_slope=1).list() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - The following example is actually finite, but not detected as such:: - - sage: IntegerListsLex(7, floor=[4], max_part=4, min_slope=-1).list() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - This is sad because the following equivalent example works just fine:: - - sage: IntegerListsLex(7, floor=[4,3], max_part=4, min_slope=-1).list() - [[4, 3]] - - Detecting this properly would require some deeper lookahead, - and the difficulty is to decide how far this lookahead should - search. Until this is fixed, one can disable the checks:: - - sage: IntegerListsLex(7, floor=[4], max_part=4, min_slope=-1, check=False).list() - [[4, 3]] - - If the ceiling or floor is a function, it is much more likely - that a finite set will not be detected as such:: - - sage: IntegerListsLex(ceiling=lambda i: max(3-i,0))._check_finiteness() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - sage: IntegerListsLex(7, ceiling=lambda i:0).list() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - The next example shows a case that is finite because we remove - trailing zeroes:: - - sage: list(IntegerListsLex(ceiling=[0], max_slope=0)) - [[]] - sage: L = IntegerListsLex(ceiling=[1], min_slope=1, max_slope=1) - sage: L.list() - Traceback (most recent call last): - ... - ValueError: Could not prove that the specified constraints yield a finite set - - In the next examples, there is either no solution, or the region - is bounded:: - - sage: IntegerListsLex(min_sum=10, max_sum=5).list() - [] - sage: IntegerListsLex(max_part=1, min_slope=10).list() - [[1], []] - sage: IntegerListsLex(max_part=100, min_slope=10).first() - [100] - sage: IntegerListsLex(ceiling=[1,Infinity], max_part=2, min_slope=1).list() - [[1, 2], [1], [0, 2], [0, 1, 2], [0, 1], []] - sage: IntegerListsLex(min_sum=1, floor=[1,2], max_part=1).list() - [[1]] - - sage: IntegerListsLex(min_length=2, max_length=1).list() - [] - sage: IntegerListsLex(min_length=-2, max_length=-1).list() - [] - sage: IntegerListsLex(min_length=-1, max_length=-2).list() - [] - sage: IntegerListsLex(min_length=2, max_slope=0, min_slope=1).list() - [] - sage: IntegerListsLex(min_part=2, max_part=1).list() - [[]] - - sage: IntegerListsLex(floor=[0,2], ceiling=[3,1]).list() - [[3], [2], [1], []] - sage: IntegerListsLex(7, ceiling=[2], floor=[4]).list() - [] - sage: IntegerListsLex(7, max_part=0).list() - [] - sage: IntegerListsLex(5, max_part=0, min_slope=0).list() - [] - sage: IntegerListsLex(max_part=0).list() - [[]] - sage: IntegerListsLex(max_sum=1, min_sum=4, min_slope=0).list() - [] - """ - # Trivial cases - if self._max_length < Infinity: - return - if self._max_sum < self._min_sum: - return - if self._min_slope > self._max_slope: - return - if self._max_slope < 0: - return - if self._ceiling.limit() < self._floor.limit(): - return - if self._ceiling.limit() == 0: - # This assumes no trailing zeroes - return - if self._min_slope > 0 and self._ceiling.limit() < Infinity: - return - - # Compute a lower bound on the sum of floor(i) for i=1 to infinity - if self._floor.limit() > 0 or self._min_slope > 0: - floor_sum_lower_bound = Infinity - elif self._floor.limit_start() < Infinity: - floor_sum_lower_bound = sum(self._floor(i) for i in range(self._floor.limit_start())) - else: - floor_sum_lower_bound = 0 - if floor_sum_lower_bound > 0 and self._min_slope >= 0: - floor_sum_lower_bound = Infinity - - if self._max_sum < floor_sum_lower_bound: - return - if self._max_sum == floor_sum_lower_bound and self._max_sum < Infinity: - # This assumes no trailing zeroes - return - - # Variant on ceiling.limit() ==0 where we actually discover that the ceiling limit is 0 - if self._max_slope == 0 and \ - (self._max_sum < Infinity or - (self._ceiling.limit_start() < Infinity and - any(self._ceiling(i) == 0 for i in range(self._ceiling.limit_start()+1)))): - return - - limit_start = max(self._ceiling.limit_start(), self._floor.limit_start()) - if limit_start < Infinity: - for i in range(limit_start+1): - if self._ceiling(i) < self._floor(i): - return - - raise ValueError("Could not prove that the specified constraints yield a finite set") - - - @staticmethod - def _list_function(l, default): - r""" - Generate a function on the nonnegative integers from input. - - This method generates a function on the nonnegative integers - whose values are taken from ``l`` when the input is a valid index - in the list ``l``, and has a default value ``default`` otherwise. - - INPUT: - - - ``l`` -- a list to use as a source of values - - - ``default`` -- a default value to use for indices outside of the list +Deprecated integer list module - OUTPUT: +TESTS:: - A function on the nonnegative integers. - - EXAMPLES:: - - sage: C = IntegerListsLex(2, length=3) - sage: f = C._list_function([1,2], Infinity) - sage: f(1) - 2 - sage: f(3) - +Infinity - """ - return lambda i: l[i] if i < len(l) else default - - def __eq__(self, other): - r""" - Return whether ``self == other``. - - EXAMPLES:: - - sage: C = IntegerListsLex(2, length=3) - sage: D = IntegerListsLex(2, length=3); L = D.list(); - sage: E = IntegerListsLex(2, min_length=3) - sage: F = IntegerListsLex(2, length=3, element_constructor=list) - sage: G = IntegerListsLex(4, length=3) - sage: C == C - True - sage: C == D - True - sage: C == E - False - sage: C == F - False - sage: C == None - False - sage: C == G - False - - This is a minimal implementation enabling pickling tests. It - is safe, but one would want the two following objects to be - detected as equal:: - - sage: C = IntegerListsLex(2, ceiling=[1,1,1]) - sage: D = IntegerListsLex(2, ceiling=[1,1,1]) - sage: C == D - False - - TESTS: - - This used to fail due to poor equality testing. See - :trac:`17979`, comment 433:: - - sage: DisjointUnionEnumeratedSets(Family([2,2], - ....: lambda n: IntegerListsLex(n, length=2))).list() - [[2, 0], [1, 1], [0, 2], [2, 0], [1, 1], [0, 2]] - sage: DisjointUnionEnumeratedSets(Family([2,2], - ....: lambda n: IntegerListsLex(n, length=1))).list() - [[2], [2]] - """ - if self.__class__ != other.__class__: - return False - for key in ["_min_length", "_max_length", "_floor", "_ceiling", "_min_part", "_max_part", "_min_sum", "_max_sum", "Element"]: - if getattr(self, key) != getattr(other, key): - return False - a = self._element_constructor - b = other._element_constructor - if ismethod(a): - a = a.__func__ - if ismethod(b): - b = b.__func__ - return a == b - - def __ne__(self, other): - r""" - Return whether ``self != other``. - - EXAMPLES:: - - sage: C = IntegerListsLex(2, length=3) - sage: D = IntegerListsLex(2, length=3); L = D.list(); - sage: E = IntegerListsLex(2, max_length=3) - sage: C != D - False - sage: C != E - True - """ - return not self == other - - def _repr_(self): - """ - Return the name of this enumerated set. - - EXAMPLES:: - - sage: C = IntegerListsLex(2, length=3) - sage: C # indirect doctest - Integer lists of sum 2 satisfying certain constraints - - sage: C = IntegerListsLex(2, length=3, name="A given name") - sage: C - A given name - """ - if self._min_sum == self._max_sum: - return "Integer lists of sum {} satisfying certain constraints".format(self._min_sum) - elif self._max_sum == Infinity: - if self._min_sum == 0: - return "Integer lists with arbitrary sum satisfying certain constraints" - else: - return "Integer lists of sum at least {} satisfying certain constraints".format(self._min_sum) - else: - return "Integer lists of sum between {} and {} satisfying certain constraints".format(self._min_sum,self._max_sum) - - def __contains__(self, comp): - """ - Return ``True`` if ``comp`` meets the constraints imposed by the arguments. - - EXAMPLES:: - - sage: C = IntegerListsLex(n=2, max_length=3, min_slope=0) - sage: all([l in C for l in C]) - True - """ - if len(comp) < self._min_length or len(comp) > self._max_length: - return False - n = sum(comp) - if n < self._min_sum or n > self._max_sum: - return False - for i in range(len(comp)): - if comp[i] < self._floor(i): - return False - if comp[i] > self._ceiling(i): - return False - for i in range(len(comp)-1): - slope = comp[i+1] - comp[i] - if slope < self._min_slope or slope > self._max_slope: - return False - return True - - - def __iter__(self): - """ - Return an iterator for the elements of ``self``. - - EXAMPLES:: - - sage: C = IntegerListsLex(2, length=3) - sage: list(C) # indirect doctest - [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] - """ - if self._check: - self._check_finiteness() - return IntegerListsLexIter(self) - - def _element_constructor_nocheck(self, l): - r""" - A variant of the standard element constructor that passes - ``check=False`` to the element class. - - EXAMPLES:: - - sage: L = IntegerListsLex(4, max_slope=0) - sage: L._element_constructor_nocheck([1,2,3]) - [1, 2, 3] - - When relevant, this is assigned to - ``self._element_constructor`` by :meth:`__init__`, to avoid - overhead when constructing elements from trusted data in the - iterator:: - - sage: L._element_constructor - - sage: L._element_constructor([1,2,3]) - [1, 2, 3] - """ - return self.element_class(self, l, check=False) - - class Element(ClonableArray): - """ - Element class for :class:`IntegerListsLex`. - """ - def check(self): - """ - Check to make sure this is a valid element in its - :class:`IntegerListsLex` parent. - - EXAMPLES:: - - sage: C = IntegerListsLex(4) - sage: C([4]).check() - True - sage: C([5]).check() # not implemented - False - """ - return self.parent().__contains__(self) - - -# Constants for IntegerListsLexIter._next_state -LOOKAHEAD = 5 -PUSH = 4 -ME = 3 -DECREASE = 2 -POP = 1 -STOP = 0 - -class IntegerListsLexIter: - r""" - Iterator class for IntegerListsLex. - - Let ``T`` be the prefix tree of all lists of nonnegative - integers that satisfy all constraints except possibly for - ``min_length`` and ``min_sum``; let the children of a list - be sorted decreasingly according to their last part. - - The iterator is based on a depth-first search exploration of a - subtree of this tree, trying to cut branches that do not - contain a valid list. Each call of ``next`` iterates through - the nodes of this tree until it finds a valid list to return. - - Here are the attributes describing the current state of the - iterator, and their invariants: - - - ``_parent`` -- the :class:`IntegerListsLex` object this is - iterating on; - - - ``_current_list`` -- the list corresponding to the current - node of the tree; - - - ``_j`` -- the index of the last element of ``_current_list``: - ``self._j == len(self._current_list) - 1``; - - - ``_current_sum`` -- the sum of the parts of ``_current_list``; - - - ``_search_ranges`` -- a list of same length as - ``_current_list``: the range for each part. - - Furthermore, we assume that there is no obvious contradiction - in the contraints: - - - ``self._parent._min_length <= self._parent._max_length``; - - ``self._parent._min_slope <= self._parent._max_slope`` - unless ``self._parent._min_length <= 1``. - - Along this iteration, ``next`` switches between the following - states: - - - LOOKAHEAD: determine whether the current list could be a - prefix of a valid list; - - PUSH: go deeper into the prefix tree by appending the - largest possible part to the current list; - - ME: check whether the current list is valid and if yes return it - - DECREASE: decrease the last part; - - POP: pop the last part of the current list; - - STOP: the iteration is finished. - - The attribute ``_next_state`` contains the next state ``next`` - should enter in. - """ - def __init__(self, parent): - """ - TESTS:: - - sage: from sage.combinat.integer_list import IntegerListsLexIter - sage: C = IntegerListsLex(2, length=3) - sage: I = IntegerListsLexIter(C) - sage: I._search_ranges - [] - sage: I._current_list - [] - sage: I._j - -1 - sage: I._current_sum - 0 - """ - self._parent = parent - - self._search_ranges = [] - self._current_list = [] - self._j = -1 # index of last element of _current_list - self._current_sum = 0 # sum of parts in _current_list - - # Make sure that some invariants are respected in the iterator - if parent._min_length <= parent._max_length and \ - (parent._min_slope <= parent._max_slope or parent._min_length <= 1): - self._next_state = PUSH - else: - self._next_state = STOP - - def __iter__(self): - """ - Return ``self`` as per the iterator protocol. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import IntegerListsLexIter - sage: C = IntegerListsLex(2, length=3) - sage: it = IntegerListsLexIter(C) - sage: it.__iter__() is it - True - """ - return self - - def _push_search(self): - """ - Push search forward, resetting attributes. - - The push may fail if it is discovered that - ``self._current_list`` cannot be extended in a valid way. - - OUTPUT: a boolean: whether the push succeeded - - EXAMPLES:: - - sage: C = IntegerListsLex(2, length=3) - sage: I = C.__iter__() - sage: I._j - -1 - sage: I._search_ranges - [] - sage: I._current_list - [] - sage: I._current_sum - 0 - sage: I._push_search() - True - sage: I._j - 0 - sage: I._search_ranges - [(0, 2)] - sage: I._current_list - [2] - sage: I._current_sum - 2 - sage: I._push_search() - True - sage: I._j - 1 - sage: I._search_ranges - [(0, 2), (0, 0)] - sage: I._current_list - [2, 0] - sage: I._current_sum - 2 - """ - p = self._parent - max_sum = p._max_sum - min_length = p._min_length - max_length = p._max_length - if self._j+1 >= max_length: - return False - if self._j+1 >= min_length and self._current_sum == max_sum: - # Cannot add trailing zeroes - return False - - if self._j >= 0: - prev = self._current_list[self._j] - else: - prev = None - interval = self._m_interval(self._j+1, self._parent._max_sum - self._current_sum, prev) - if interval[0] > interval[1]: - return False - - self._j += 1 - m = interval[1] - self._search_ranges.append(interval) - self._current_list.append(m) - self._current_sum += m - return True - - def _pop_search(self): - """ - Go back in search tree. Resetting attributes. - - EXAMPLES:: - - sage: C = IntegerListsLex(2, length=3) - sage: I = C.__iter__() - sage: I._push_search() - True - sage: I._j - 0 - sage: I._search_ranges - [(0, 2)] - sage: I._current_sum - 2 - sage: I._current_list - [2] - sage: I._pop_search() - sage: I._j - -1 - sage: I._search_ranges - [] - sage: I._current_sum - 0 - sage: I._current_list - [] - """ - if self._j >= 0: # TODO: get rid of this condition - self._j -= 1 - self._search_ranges.pop() - self._current_sum -= self._current_list[-1] - self._current_list.pop() - - def next(self): - r""" - Return the next element in the iteration. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import IntegerListsLexIter - sage: C = IntegerListsLex(2, length=3) - sage: I = IntegerListsLexIter(C) - sage: next(I) - [2, 0, 0] - sage: next(I) - [1, 1, 0] - """ - p = self._parent - min_sum = p._min_sum - max_length = p._max_length - search_ranges = self._search_ranges - - while True: - assert self._j == len(self._current_list) - 1 - assert self._j == len(self._search_ranges) - 1 - - # LOOK AHEAD - if self._next_state == LOOKAHEAD: - if self._lookahead(): - self._next_state = PUSH - else: - # We should reuse information about the - # reasons for this failure, to avoid when - # possible retrying with smaller values. - # We just do a special case for now: - if self._j + 1 == max_length and self._current_sum < min_sum: - self._next_state = POP - else: - self._next_state = DECREASE - - # PUSH - if self._next_state == PUSH: - if self._push_search(): - self._next_state = LOOKAHEAD - continue - self._next_state = ME - - # ME - if self._next_state == ME: - if self._j == -1: - self._next_state = STOP - else: - self._next_state = DECREASE - if self._internal_list_valid(): - return p._element_constructor( - self._current_list - if p._element_constructor_is_copy_safe - else self._current_list[:]) - - # DECREASE - if self._next_state == DECREASE: - self._current_list[-1] -= 1 - self._current_sum -= 1 - if self._current_list[-1] >= search_ranges[self._j][0]: - self._next_state = LOOKAHEAD - continue - self._next_state = POP - - # POP - if self._next_state == POP: - self._pop_search() - self._next_state = ME - continue - - # STOP - if self._next_state == STOP: - raise StopIteration() - - assert False - - def _internal_list_valid(self): - """ - Return whether the current list in the iteration variable ``self._current_list`` is a valid list. - - This method checks whether the sum of the parts in ``self._current_list`` - is in the right range, whether its length is in the - required range, and whether there are trailing zeroes. It does not check all of the - necessary conditions to verify that an arbitrary list satisfies the - constraints from the corresponding ``IntegerListsLex`` object, and should - not be used except internally in the iterator class. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import IntegerListsLexIter - sage: C = IntegerListsLex(2, length=3) - sage: I = IntegerListsLexIter(C) - sage: I._current_list - [] - sage: I._internal_list_valid() - False - sage: next(I) - [2, 0, 0] - sage: I._current_list - [2, 0, 0] - sage: I._internal_list_valid() - True - """ - p = self._parent - mu = self._current_list - nu = self._current_sum - l = self._j + 1 - good_sum = (nu >= p._min_sum and nu <= p._max_sum) - good_length = (l >= p._min_length and l <= p._max_length) - no_trailing_zeros = (l <= max(p._min_length,0) or mu[-1] != 0) - return good_sum and good_length and no_trailing_zeros - - def _m_interval(self, i, max_sum, prev=None): - r""" - Return coarse lower and upper bounds for the part ``m`` at position ``i``. - - INPUT: - - - ``i`` -- a nonnegative integer (position) - - - ``max_sum`` -- a nonnegative integer or ``+oo`` - - - ``prev`` -- a nonnegative integer or ``None`` - - Return coarse lower and upper bounds for the value ``m`` - of the part at position ``i`` so that there could exists - some list suffix `v_i,\ldots,v_k` of sum bounded by - ``max_sum`` and satisfying the floor and upper bound - constraints. If ``prev`` is specified, then the slope - conditions between ``v[i-1]=prev`` and ``v[i]=m`` should - also be satisfied. - - Additionally, this raises an error if it can be detected - that some part is neither directly nor indirectly bounded - above, which implies that the constraints possibly do not allow for - an inverse lexicographic iterator. - - OUTPUT: - - A tuple of two integers ``(lower_bound, upper_bound)``. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import IntegerListsLexIter - sage: C = IntegerListsLex(2, length=3) - sage: I = IntegerListsLexIter(C) - sage: I._m_interval(1,2) - (0, 2) - - The second part is not bounded above, hence we can not - iterate lexicographically through all the elements:: - - sage: IntegerListsLex(ceiling=[2,infinity,3], max_length=3).first() - Traceback (most recent call last): - ... - ValueError: infinite upper bound for values of m - - Same here:: - - sage: IntegerListsLex(ceiling=[2,infinity,2], max_length=3, min_slope=-1).cardinality() - Traceback (most recent call last): - ... - ValueError: infinite upper bound for values of m - - In the following examples however, all parts are - indirectly bounded above:: - - sage: IntegerListsLex(ceiling=[2,infinity,2], length=3, min_slope=-1).cardinality() - 24 - sage: IntegerListsLex(ceiling=[2,infinity,2], max_length=3, max_slope=1).cardinality() - 24 - - sage: IntegerListsLex(max_part=2, max_length=3).cardinality() - 27 - sage: IntegerListsLex(3, max_length=3).cardinality() # parts bounded by n - 10 - sage: IntegerListsLex(max_length=0, min_length=1).list() # no part! - [] - sage: IntegerListsLex(length=0).list() # no part! - [[]] - """ - p = self._parent - - lower_bound = max(0, p._floor(i)) - upper_bound = min(max_sum, p._ceiling(i)) - if prev != None: - lower_bound = max(lower_bound, prev + p._min_slope) - upper_bound = min(upper_bound, prev + p._max_slope) - - ## check for infinite upper bound, in case max_sum is infinite - if p._check and upper_bound == Infinity: - # This assumes that there exists a valid list (which - # is not yet always guaranteed). Then we just - # discovered that part 'i' of this list can be made as - # large as desired, which implies that `self._parent` - # cannot be iterated in inverse lexicographic order - raise ValueError("infinite upper bound for values of m") - - return (lower_bound, upper_bound) - - def _lookahead(self): - r""" - Return whether the current list can possibly be a prefix of a valid list. - - OUTPUT: ``False`` if it is guaranteed that the current - list cannot be a prefix of a valid list and ``True`` - otherwise. - - EXAMPLES:: - - sage: it = iter(IntegerListsLex(length=3, min_sum=2, max_sum=2)) - sage: it._current_list = [0,1] # don't do this at home, kids - sage: it._current_sum = 1 - sage: it._j = 1 - sage: it._lookahead() - True - - sage: it = iter(IntegerListsLex(length=3, min_sum=3, max_sum=2)) - sage: it._current_list = [0,1] - sage: it._current_sum = 1 - sage: it._j = 1 - sage: it._lookahead() - False - - sage: it = iter(IntegerListsLex(min_length=2, max_part=0)) - sage: it._current_list = [0] - sage: it._current_sum = 0 - sage: it._j = 0 - sage: it._lookahead() - True - sage: it._current_list = [0, 0] - sage: it._j = 1 - sage: it._lookahead() - True - sage: it._current_list = [0, 0, 0] - sage: it._j = 2 - sage: it._lookahead() - False - - sage: n = 10**100 - sage: it = iter(IntegerListsLex(n, length=1)) - sage: it._current_list = [n-1] - sage: it._current_sum = n-1 - sage: it._j = 0 - sage: it._lookahead() - False - - sage: it = iter(IntegerListsLex(n=3, min_part=2, min_sum=3, max_sum=3)) - sage: it._current_list = [2] - sage: it._current_sum = 2 - sage: it._j = 0 - sage: it._lookahead() - False - - ALGORITHM: - - Let ``j=self._j`` be the position of the last part `m` of - ``self._current_list``. The current algorithm computes, - for `k=j,j+1,\ldots`, a lower bound `l_k` and an upper - bound `u_k` for `v_0+\dots+v_k`, and stops if none of the - invervals `[l_k, u_k]` intersect ``[min_sum, max_sum]``. - - The lower bound `l_k` is given by the area below - `v_0,\dots,v_{j-1}` prolongated by the lower envelope - between `j` and `k` and starting at `m`. The upper bound - `u_k` is given similarly using the upper envelope. - - The complexity of this algorithm is bounded above by - ``O(max_length)``. When ``max_length=oo``, the algorithm - is guaranteed to terminate, unless ``floor`` is a function - which is eventually constant with value `0`, or which - reaches the value `0` while ``max_slope=0``. - - Indeed, the lower bound `l_k` is increasing with `k`; in - fact it is strictly increasing, unless the local lower bound - at `k` is `0`. Furthermore as soon as ``l_k >= min_sum``, - we can conclude; we can also conclude if we know that the - floor is eventually constant with value `0`, or there is a - local lower bound at `k` is `0` and ``max_slope=0``. - - .. RUBRIC:: Room for improvement - - Improved prediction: the lower bound `l_k` does not take - the slope conditions into account, except for those imposed - by the value `m` at `j`. Similarly for `u_k`. - - Improved speed: given that `l_k` is increasing with `k`, - possibly some dichotomy could be used to search for `k`, - with appropriate caching / fast calculation of the partial - sums. Also, some of the information gained at depth `j` - could be reused at depth `j+1`. - - TESTS:: - - sage: it = iter(IntegerListsLex(1, min_length=2, min_slope=0, max_slope=0, min_sum=1, max_sum=1)) - sage: it._current_list = [0] - sage: it._current_sum = 0 - sage: it._j = 0 - sage: it._lookahead() - False - """ - # Check code for various termination conditions. Possible cases: - # 0. interval [lower, upper] intersects interval [min_sum, max_sum] -- terminate True - # 1. lower sum surpasses max_sum -- terminate False - # 2. iteration surpasses max_length -- terminate False - # 3. upper envelope is smaller than lower envelope -- terminate False - # 4. max_slope <= 0 -- terminate False after upper passes 0 - # 5. ceiling_limit == 0 -- terminate False after reaching larger limit point - # 6. (uncomputable) ceiling function == 0 for all but finitely many input values -- terminate False after reaching (unknown) limit point -- currently hangs - - m = self._current_list[-1] - j = self._j - min_sum = self._parent._min_sum - (self._current_sum-m) - max_sum = self._parent._max_sum - (self._current_sum-m) - - if min_sum > max_sum: - return False - - p = self._parent - - # Beware that without slope conditions, the functions below - # currently forget about the value m at k! - lower_envelope = self._parent._floor.adapt(m,j) - upper_envelope = self._parent._ceiling.adapt(m,j) - lower = 0 # The lower bound `l_k` - upper = 0 # The upper bound `u_k` - - assert j >= 0 - # get to smallest valid number of parts - for k in range(j, p._min_length-1): - # We are looking at lists `v_j,...,v_k` - lo = m if k == j else lower_envelope(k) - up = m if k == j else upper_envelope(k) - if lo > up: - return False - lower += lo - upper += up - - if j < p._min_length and min_sum <= upper and lower <= max_sum: - # There could exist a valid list `v_j,\dots,v_{min_length-1}` - return True - - k = max(p._min_length-1,j) - # Check if any of the intervals intersect the target interval - while k < p._max_length: - lo = m if k == j else lower_envelope(k) - up = m if k == j else upper_envelope(k) - if lo > up: - # There exists no valid list of length >= k - return False - lower += lo - upper += up - assert lower <= upper - - if lower > max_sum: - # There cannot exist a valid list `v_j,\dots,v_l` with l>=k - return False - - if (p._max_slope <= 0 and up <= 0) or \ - (p._ceiling.limit() == 0 and k > p._ceiling.limit_start()): - # This implies v_l=0 for l>=k: that is we would be generating - # a list with trailing zeroes - return False - - if min_sum <= upper and lower <= max_sum: - # There could exist a valid list `v_j,\dots,v_k` - return True - - k += 1 - - return False - - -class Envelope(object): - """ - The (currently approximated) upper (lower) envelope of a function - under the specified constraints. - - INPUT: - - - ``f`` -- a function, list, or tuple; if ``f`` is a list, it is - considered as the function ``f(i)=f[i]``, completed for larger - `i` with ``f(i)=max_part``. - - - ``min_part``, ``max_part``, ``min_slope``, ``max_slope``, ... - as for :class:`IntegerListsLex` (please consult for details). - - - ``sign`` -- (+1 or -1) multiply the input values with ``sign`` - and multiply the output with ``sign``. Setting this to `-1` can - be used to implement a lower envelope. - - The *upper envelope* `U(f)` of `f` is the (pointwise) largest - function which is bounded above by `f` and satisfies the - ``max_part`` and ``max_slope`` conditions. Furthermore, for - ``i,i+1 inf, - '_f_limit_start': 0, - '_max_part': -3, - '_max_slope': inf, - '_min_slope': 1, - '_precomputed': [-6, -5, -4, -3], - '_sign': -1} - sage: TestSuite(f).run(skip="_test_pickling") - sage: Envelope(3, sign=1/3, max_slope=-1, min_length=4) - Traceback (most recent call last): - ... - TypeError: no conversion of this rational to integer - sage: Envelope(3, sign=-2, max_slope=-1, min_length=4) - Traceback (most recent call last): - ... - ValueError: sign should be +1 or -1 - """ - # self._sign = sign for the output values (the sign change for - # f is handled here in __init__) - self._sign = ZZ(sign) - if self._sign == 1: - self._max_part = max_part - self._min_slope = min_slope - self._max_slope = max_slope - if max_part == 0: - # This uses that all entries are nonnegative. - # This is not for speed optimization but for - # setting the limit start and avoid hangs. - # See #17979: comment 389 - f = 0 - elif self._sign == -1: - self._max_part = -min_part - self._min_slope = -max_slope - self._max_slope = -min_slope - else: - raise ValueError("sign should be +1 or -1") - - # Handle different types of f and multiply f with sign - if f == Infinity or f == -Infinity or f in ZZ: - limit_start = 0 - self._max_part = min(self._sign * f, self._max_part) - f = ConstantFunction(Infinity) - elif isinstance(f, (list, tuple)): - limit_start = len(f) - f_tab = [self._sign * i for i in f] - f = lambda k: f_tab[k] if k < len(f_tab) else Infinity - else: - g = f - f = lambda k: self._sign * g(k) - # At this point, this is not really used - limit_start = Infinity - - self._f = f - # For i >= limit_start, f is constant - # This does not necessarily means that self is constant! - self._f_limit_start = limit_start - self._precomputed = [] - - if min_length > 0: - self(min_length-1) - for i in range(min_length-1,0,-1): - self._precomputed[i-1] = min(self._precomputed[i-1], self._precomputed[i] - self._min_slope) - - def __eq__(self, other): - r""" - Return whether ``self == other``. - - This is a minimal implementation enabling pickling tests. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import Envelope - sage: f = Envelope([3,2,2]) - sage: g = Envelope([3,2,2]) - sage: h = Envelope([3,2,2], min_part=2) - sage: f == f, f == h, f == None - (True, False, False) - - This would be desirable:: - - sage: f == g # todo: not implemented - True - """ - return self.__class__ == other.__class__ and self.__dict__ == other.__dict__ - - def __ne__(self, other): - r""" - Return whether ``self != other``. - - This is a minimal implementation enabling pickling tests. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import Envelope - sage: f = Envelope([3,2,2]) - sage: g = Envelope([3,2,2]) - sage: h = Envelope([3,2,2], min_part=2) - sage: f != f, f != h, f != None - (False, True, True) - - This would be desirable:: - - sage: f != g # todo: not implemented - False - """ - return not self == other - - def limit_start(self): - """ - Return from which `i` on the bound returned by ``limit`` holds. - - .. SEEALSO:: :meth:`limit` for the precise specifications. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import Envelope - sage: Envelope([4,1,5]).limit_start() - 3 - sage: Envelope([4,1,5], sign=-1).limit_start() - 3 - - sage: Envelope([4,1,5], max_part=2).limit_start() - 3 - - sage: Envelope(4).limit_start() - 0 - sage: Envelope(4, sign=-1).limit_start() - 0 - - sage: Envelope(lambda x: 3).limit_start() == Infinity - True - sage: Envelope(lambda x: 3, max_part=2).limit_start() == Infinity - True - - sage: Envelope(lambda x: 3, sign=-1, min_part=2).limit_start() == Infinity - True - - """ - return self._f_limit_start - - def limit(self): - """ - Return a bound on the limit of ``self``. - - OUTPUT: a nonnegative integer or `\infty` - - This returns some upper bound for the accumulation points of - this upper envelope. For a lower envelope, a lower bound is - returned instead. - - In particular this gives a bound for the value of ``self`` at - `i` for `i` large enough. Special case: for a lower envelop, - and when the limit is `\infty`, the envelope is guaranteed to - tend to `\infty` instead. - - When ``s=self.limit_start()`` is finite, this bound is - guaranteed to be valid for `i>=s`. - - Sometimes it's better to have a loose bound that starts early; - sometimes the converse holds. At this point which specific - bound and starting point is returned is not set in stone, in - order to leave room for later optimizations. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import Envelope - sage: Envelope([4,1,5]).limit() - inf - sage: Envelope([4,1,5], max_part=2).limit() - 2 - sage: Envelope([4,1,5], max_slope=0).limit() - 1 - sage: Envelope(lambda x: 3, max_part=2).limit() - 2 - - Lower envelopes:: - - sage: Envelope(lambda x: 3, min_part=2, sign=-1).limit() - 2 - sage: Envelope([4,1,5], min_slope=0, sign=-1).limit() - 5 - sage: Envelope([4,1,5], sign=-1).limit() - 0 - - .. SEEALSO:: :meth:`limit_start` - """ - if self.limit_start() < Infinity and self._max_slope <= 0: - return self(self.limit_start()) - else: - return self._max_part * self._sign - - def __call__(self, k): - """ - Return the value of this envelope at `k`. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import Envelope - sage: f = Envelope([4,1,5,3,5]) - sage: f.__call__(2) - 5 - sage: [f(i) for i in range(10)] - [4, 1, 5, 3, 5, inf, inf, inf, inf, inf] - - .. NOTE:: - - See the documentation of :class:`Envelope` for tests and - examples. - """ - if k >= len(self._precomputed): - for i in range(len(self._precomputed), k+1): - value = min(self._f(i), self._max_part) - if i>0: - value = min(value, self._precomputed[i-1] + self._max_slope) - self._precomputed.append(value) - return self._precomputed[k] * self._sign - - def adapt(self, m, j): - """ - Return this envelope adapted to an additional local constraint. - - INPUT: - - - ``m`` -- a nonnegative integer (starting value) - - - ``j`` -- a nonnegative integer (position) - - This method adapts this envelope to the additional local - constraint imposed by having a part `m` at position `j`. - Namely, this returns a function which computes, for any `i>j`, - the minimum of the ceiling function and the value restriction - given by the slope conditions. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import Envelope - sage: f = Envelope(3) - sage: g = f.adapt(1,1) - sage: g is f - True - sage: [g(i) for i in range(10)] - [3, 3, 3, 3, 3, 3, 3, 3, 3, 3] - - sage: f = Envelope(3, max_slope=1) - sage: g = f.adapt(1,1) - sage: [g(i) for i in range(10)] - [0, 1, 2, 3, 3, 3, 3, 3, 3, 3] - - Note that, in both cases above, the adapted envelope is only - guaranteed to be valid for `i>j`! This is to leave potential - room in the future for sharing similar adapted envelopes:: - - sage: g = f.adapt(0,0) - sage: [g(i) for i in range(10)] - [0, 1, 2, 3, 3, 3, 3, 3, 3, 3] - - sage: g = f.adapt(2,2) - sage: [g(i) for i in range(10)] - [0, 1, 2, 3, 3, 3, 3, 3, 3, 3] - - sage: g = f.adapt(3,3) - sage: [g(i) for i in range(10)] - [0, 1, 2, 3, 3, 3, 3, 3, 3, 3] - - Now with a lower envelope:: - - sage: f = Envelope(1, sign=-1, min_slope=-1) - sage: g = f.adapt(2,2) - sage: [g(i) for i in range(10)] - [4, 3, 2, 1, 1, 1, 1, 1, 1, 1] - sage: g = f.adapt(1,3) - sage: [g(i) for i in range(10)] - [4, 3, 2, 1, 1, 1, 1, 1, 1, 1] - """ - if self._max_slope == Infinity: - return self - m *= self._sign - m = m - j * self._max_slope - return lambda i: self._sign * min(m + i*self._max_slope, self._sign*self(i) ) - - -def IntegerListsNN(**kwds): - """ - Lists of nonnegative integers with constraints. - - This function returns the union of ``IntegerListsLex(n, **kwds)`` - where `n` ranges over all nonnegative integers. - - .. WARNING:: this function is likely to disappear in :trac:`17927`. - - EXAMPLES:: - - sage: from sage.combinat.integer_list import IntegerListsNN - sage: L = IntegerListsNN(max_length=3, max_slope=-1) - sage: L - Disjoint union of Lazy family ((i))_{i in Non negative integer semiring} - sage: it = iter(L) - sage: for _ in range(20): - ....: print next(it) - [] - [1] - [2] - [3] - [2, 1] - [4] - [3, 1] - [5] - [4, 1] - [3, 2] - [6] - [5, 1] - [4, 2] - [3, 2, 1] - [7] - [6, 1] - [5, 2] - [4, 3] - [4, 2, 1] - [8] - """ - from sage.rings.semirings.non_negative_integer_semiring import NN - from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets - return DisjointUnionEnumeratedSets(Family(NN, lambda i: IntegerListsLex(i, **kwds))) + sage: from sage.combinat.integer_list import IntegerListsLex + sage: IntegerListsLex(3) + doctest:...: DeprecationWarning: + Importing IntegerListsLex from here is deprecated. If you need to use it, please import it directly from sage.combinat.integer_lists + See http://trac.sagemath.org/18109 for details. + Integer lists of sum 3 satisfying certain constraints +""" +from sage.misc.lazy_import import lazy_import +lazy_import('sage.combinat.integer_list_old', '*', deprecation=18109) +lazy_import('sage.combinat.integer_lists', '*', deprecation=18109) diff --git a/src/sage/combinat/integer_lists/__init__.py b/src/sage/combinat/integer_lists/__init__.py new file mode 100644 index 00000000000..e69886d8799 --- /dev/null +++ b/src/sage/combinat/integer_lists/__init__.py @@ -0,0 +1,6 @@ +from base import IntegerListsBackend, Envelope +from lists import IntegerLists +from invlex import IntegerListsLex + +from sage.structure.sage_object import register_unpickle_override +register_unpickle_override('sage.combinat.integer_list', 'IntegerListsLex', IntegerListsLex) diff --git a/src/sage/combinat/integer_lists/base.pxd b/src/sage/combinat/integer_lists/base.pxd new file mode 100644 index 00000000000..d7850331ffe --- /dev/null +++ b/src/sage/combinat/integer_lists/base.pxd @@ -0,0 +1,15 @@ +cdef class Envelope(object): + cdef readonly sign + cdef f + cdef f_limit_start + cdef list precomputed + cdef readonly max_part + cdef readonly min_slope, max_slope + +cdef class IntegerListsBackend(object): + cdef readonly min_sum, max_sum + cdef readonly min_length, max_length + cdef readonly min_part, max_part + cdef readonly min_slope, max_slope + cdef readonly Envelope floor, ceiling + cdef public dict __cached_methods # Support cached_method diff --git a/src/sage/combinat/integer_lists/base.pyx b/src/sage/combinat/integer_lists/base.pyx new file mode 100644 index 00000000000..d8ea14382c1 --- /dev/null +++ b/src/sage/combinat/integer_lists/base.pyx @@ -0,0 +1,700 @@ +r""" +Enumerated set of lists of integers with constraints: base classes + +- :class:`IntegerListsBackend`: base class for the Cython back-end of + an enumerated set of lists of integers with specified constraints. + +- :class:`Envelope`: a utility class for upper (lower) envelope of a + function under constraints. +""" + +#***************************************************************************** +# Copyright (C) 2015 Bryan Gillespie +# Nicolas M. Thiery +# Anne Schilling +# Jeroen Demeyer +# +# 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 Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE +from sage.misc.constant_function import ConstantFunction +from sage.structure.element cimport RingElement +from sage.rings.integer cimport Integer + +Infinity = float('+inf') + + +cdef class IntegerListsBackend(object): + """ + Base class for the Cython back-end of an enumerated set of lists of + integers with specified constraints. + + This base implements the basic operations, including checking for + containment using :meth:`_contains`, but not iteration. For + iteration, subclass this class and implement an ``_iter()`` method. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.base import IntegerListsBackend + sage: L = IntegerListsBackend(6, max_slope=-1) + sage: L._contains([3,2,1]) + True + """ + def __init__(self, + n=None, length=None, *, + min_length=0, max_length=Infinity, + floor=None, ceiling=None, + min_part=0, max_part=Infinity, + min_slope=-Infinity, max_slope=Infinity, + min_sum=0, max_sum=Infinity): + """ + Initialize ``self``. + + TESTS:: + + sage: from sage.combinat.integer_lists.base import IntegerListsBackend + sage: C = IntegerListsBackend(2, length=3) + sage: C = IntegerListsBackend(min_sum=1.4) + Traceback (most recent call last): + ... + TypeError: Attempt to coerce non-integral RealNumber to Integer + sage: C = IntegerListsBackend(min_sum=Infinity) + Traceback (most recent call last): + ... + TypeError: unable to coerce to an integer + """ + if n is not None: + min_sum = n + max_sum = n + self.min_sum = Integer(min_sum) if min_sum != -Infinity else -Infinity + self.max_sum = Integer(max_sum) if max_sum != Infinity else Infinity + + if length is not None: + min_length = length + max_length = length + self.min_length = Integer(max(min_length, 0)) + self.max_length = Integer(max_length) if max_length != Infinity else Infinity + + self.min_slope = Integer(min_slope) if min_slope != -Infinity else -Infinity + self.max_slope = Integer(max_slope) if max_slope != Infinity else Infinity + + self.min_part = Integer(min_part) if min_part != -Infinity else -Infinity + self.max_part = Integer(max_part) if max_part != Infinity else Infinity + + if isinstance(floor, Envelope): + self.floor = floor + else: + if floor is None: + floor = -Infinity + elif isinstance(floor, (list, tuple)): + floor = tuple(Integer(i) for i in floor) + elif callable(floor): + pass + else: + raise TypeError("floor should be a list, tuple, or function") + self.floor = Envelope(floor, sign=-1, + min_part=self.min_part, max_part=self.max_part, + min_slope=self.min_slope, max_slope=self.max_slope, + min_length=self.min_length) + + if isinstance(ceiling, Envelope): + self.ceiling = ceiling + else: + if ceiling is None: + ceiling = Infinity + elif isinstance(ceiling, (list, tuple)): + ceiling = tuple(Integer(i) if i != Infinity else Infinity + for i in ceiling) + elif callable(ceiling): + pass + else: + raise ValueError("Unable to parse value of parameter ceiling") + self.ceiling = Envelope(ceiling, sign=1, + min_part=self.min_part, max_part=self.max_part, + min_slope=self.min_slope, max_slope=self.max_slope, + min_length=self.min_length) + + def __richcmp__(self, other, int op): + r""" + Basic comparison function, supporting only checking for + equality. + + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3).backend + sage: D = IntegerListsLex(2, length=3).backend; L = list(D._iter()) + sage: E = IntegerListsLex(2, min_length=3).backend + sage: G = IntegerListsLex(4, length=3).backend + sage: C >= C + True + sage: C == D + True + sage: C != D + False + sage: C == E + False + sage: C != E + True + sage: C == None + False + sage: C == G + False + sage: C <= G + Traceback (most recent call last): + ... + TypeError: IntegerListsBackend can only be compared for equality + """ + cdef IntegerListsBackend left = self + cdef IntegerListsBackend right = other + equal = (type(left) is type(other) and + left.min_length == right.min_length and + left.max_length == right.max_length and + left.min_sum == right.min_sum and + left.max_sum == right.max_sum and + left.min_slope == right.min_slope and + left.max_slope == right.max_slope and + left.floor == right.floor and + left.ceiling == right.ceiling) + if equal: + return (op == Py_EQ or op == Py_LE or op == Py_GE) + if op == Py_EQ: + return False + if op == Py_NE: + return True + else: + raise TypeError("IntegerListsBackend can only be compared for equality") + + def _repr_(self): + """ + Return the name of this enumerated set. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.base import IntegerListsBackend + sage: C = IntegerListsBackend(2, length=3) + sage: C._repr_() + 'Integer lists of sum 2 satisfying certain constraints' + """ + if self.min_sum == self.max_sum: + return "Integer lists of sum {} satisfying certain constraints".format(self.min_sum) + elif self.max_sum == Infinity: + if self.min_sum == 0: + return "Integer lists with arbitrary sum satisfying certain constraints" + else: + return "Integer lists of sum at least {} satisfying certain constraints".format(self.min_sum) + else: + return "Integer lists of sum between {} and {} satisfying certain constraints".format(self.min_sum, self.max_sum) + + def _contains(self, comp): + """ + Return ``True`` if ``comp`` meets the constraints imposed by the arguments. + + EXAMPLES:: + + sage: C = IntegerListsLex(n=2, max_length=3, min_slope=0) + sage: all([l in C for l in C]) # indirect doctest + True + """ + if len(comp) < self.min_length or len(comp) > self.max_length: + return False + n = sum(comp) + if n < self.min_sum or n > self.max_sum: + return False + for i in range(len(comp)): + if comp[i] < self.floor(i): + return False + if comp[i] > self.ceiling(i): + return False + for i in range(len(comp)-1): + slope = comp[i+1] - comp[i] + if slope < self.min_slope or slope > self.max_slope: + return False + return True + + def __getstate__(self): + """ + Pickle ``self``. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.base import IntegerListsBackend + sage: C = IntegerListsBackend(2, length=3) + sage: C.__getstate__() + {'ceiling': , + 'floor': , + 'max_length': 3, + 'max_part': inf, + 'max_slope': inf, + 'max_sum': 2, + 'min_length': 3, + 'min_part': 0, + 'min_slope': -inf, + 'min_sum': 2} + """ + return {"min_sum": self.min_sum, + "max_sum": self.max_sum, + "min_length": self.min_length, + "max_length": self.max_length, + "min_part": self.min_part, + "max_part": self.max_part, + "min_slope": self.min_slope, + "max_slope": self.max_slope, + "floor": self.floor, + "ceiling": self.ceiling} + + def __setstate__(self, state): + """ + Unpickle ``self`` from the state ``state``. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.base import IntegerListsBackend + sage: C = IntegerListsBackend(2, length=3) + sage: C == loads(dumps(C)) + True + sage: C == loads(dumps(C)) # this did fail at some point, really! + True + sage: C is loads(dumps(C)) # todo: not implemented + True + """ + self.__init__(**state) + + +cdef class Envelope(object): + """ + The (currently approximated) upper (lower) envelope of a function + under the specified constraints. + + INPUT: + + - ``f`` -- a function, list, or tuple; if ``f`` is a list, it is + considered as the function ``f(i)=f[i]``, completed for larger + `i` with ``f(i)=max_part``. + + - ``min_part``, ``max_part``, ``min_slope``, ``max_slope``, ... + as for :class:`IntegerListsLex` (please consult for details). + + - ``sign`` -- (+1 or -1) multiply the input values with ``sign`` + and multiply the output with ``sign``. Setting this to `-1` can + be used to implement a lower envelope. + + The *upper envelope* `U(f)` of `f` is the (pointwise) largest + function which is bounded above by `f` and satisfies the + ``max_part`` and ``max_slope`` conditions. Furthermore, for + ``i,i+1= limit_start, f is constant + # This does not necessarily means that self is constant! + self.f_limit_start = limit_start + self.precomputed = [] + + if min_length > 0: + self(min_length-1) + for i in range(min_length-1,0,-1): + self.precomputed[i-1] = min(self.precomputed[i-1], self.precomputed[i] - self.min_slope) + + def __richcmp__(self, other, int op): + r""" + Basic comparison function, supporting only checking for + equality. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists import Envelope + sage: f = Envelope([3,2,2]) + sage: g = Envelope([3,2,2]) + sage: h = Envelope([3,2,2], min_part=2) + sage: f == f, f == h, f == None + (True, False, False) + sage: f < f, f != h, f != None + (False, True, True) + + This would be desirable:: + + sage: f == g # todo: not implemented + True + """ + cdef Envelope left = self + cdef Envelope right = other + equal = (type(left) is type(other) and + left.sign == right.sign and + left.f == right.f and + left.f_limit_start == right.f_limit_start and + left.max_part == right.max_part and + left.min_slope == right.min_slope and + left.max_slope == right.max_slope) + if equal: + return (op == Py_EQ or op == Py_LE or op == Py_GE) + if op == Py_EQ: + return False + if op == Py_NE: + return True + else: + raise TypeError("Envelopes can only be compared for equality") + + def limit_start(self): + """ + Return from which `i` on the bound returned by ``limit`` holds. + + .. SEEALSO:: :meth:`limit` for the precise specifications. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists import Envelope + sage: Envelope([4,1,5]).limit_start() + 3 + sage: Envelope([4,1,5], sign=-1).limit_start() + 3 + + sage: Envelope([4,1,5], max_part=2).limit_start() + 3 + + sage: Envelope(4).limit_start() + 0 + sage: Envelope(4, sign=-1).limit_start() + 0 + + sage: Envelope(lambda x: 3).limit_start() == Infinity + True + sage: Envelope(lambda x: 3, max_part=2).limit_start() == Infinity + True + + sage: Envelope(lambda x: 3, sign=-1, min_part=2).limit_start() == Infinity + True + + """ + return self.f_limit_start + + def limit(self): + """ + Return a bound on the limit of ``self``. + + OUTPUT: a nonnegative integer or `\infty` + + This returns some upper bound for the accumulation points of + this upper envelope. For a lower envelope, a lower bound is + returned instead. + + In particular this gives a bound for the value of ``self`` at + `i` for `i` large enough. Special case: for a lower envelop, + and when the limit is `\infty`, the envelope is guaranteed to + tend to `\infty` instead. + + When ``s=self.limit_start()`` is finite, this bound is + guaranteed to be valid for `i>=s`. + + Sometimes it's better to have a loose bound that starts early; + sometimes the converse holds. At this point which specific + bound and starting point is returned is not set in stone, in + order to leave room for later optimizations. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists import Envelope + sage: Envelope([4,1,5]).limit() + inf + sage: Envelope([4,1,5], max_part=2).limit() + 2 + sage: Envelope([4,1,5], max_slope=0).limit() + 1 + sage: Envelope(lambda x: 3, max_part=2).limit() + 2 + + Lower envelopes:: + + sage: Envelope(lambda x: 3, min_part=2, sign=-1).limit() + 2 + sage: Envelope([4,1,5], min_slope=0, sign=-1).limit() + 5 + sage: Envelope([4,1,5], sign=-1).limit() + 0 + + .. SEEALSO:: :meth:`limit_start` + """ + if self.limit_start() < Infinity and self.max_slope <= 0: + return self(self.limit_start()) + else: + return self.max_part * self.sign + + def __call__(self, Py_ssize_t k): + """ + Return the value of this envelope at `k`. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists import Envelope + sage: f = Envelope([4,1,5,3,5]) + sage: f.__call__(2) + 5 + sage: [f(i) for i in range(10)] + [4, 1, 5, 3, 5, inf, inf, inf, inf, inf] + + .. NOTE:: + + See the documentation of :class:`Envelope` for tests and + examples. + """ + if k >= len(self.precomputed): + for i in range(len(self.precomputed), k+1): + value = min(self.f(i), self.max_part) + if i > 0: + value = min(value, self.precomputed[i-1] + self.max_slope) + self.precomputed.append(value) + return self.precomputed[k] * self.sign + + def adapt(self, m, j): + """ + Return this envelope adapted to an additional local constraint. + + INPUT: + + - ``m`` -- a nonnegative integer (starting value) + + - ``j`` -- a nonnegative integer (position) + + This method adapts this envelope to the additional local + constraint imposed by having a part `m` at position `j`. + Namely, this returns a function which computes, for any `i>j`, + the minimum of the ceiling function and the value restriction + given by the slope conditions. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists import Envelope + sage: f = Envelope(3) + sage: g = f.adapt(1,1) + sage: g is f + True + sage: [g(i) for i in range(10)] + [3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + + sage: f = Envelope(3, max_slope=1) + sage: g = f.adapt(1,1) + sage: [g(i) for i in range(10)] + [0, 1, 2, 3, 3, 3, 3, 3, 3, 3] + + Note that, in both cases above, the adapted envelope is only + guaranteed to be valid for `i>j`! This is to leave potential + room in the future for sharing similar adapted envelopes:: + + sage: g = f.adapt(0,0) + sage: [g(i) for i in range(10)] + [0, 1, 2, 3, 3, 3, 3, 3, 3, 3] + + sage: g = f.adapt(2,2) + sage: [g(i) for i in range(10)] + [0, 1, 2, 3, 3, 3, 3, 3, 3, 3] + + sage: g = f.adapt(3,3) + sage: [g(i) for i in range(10)] + [0, 1, 2, 3, 3, 3, 3, 3, 3, 3] + + Now with a lower envelope:: + + sage: f = Envelope(1, sign=-1, min_slope=-1) + sage: g = f.adapt(2,2) + sage: [g(i) for i in range(10)] + [4, 3, 2, 1, 1, 1, 1, 1, 1, 1] + sage: g = f.adapt(1,3) + sage: [g(i) for i in range(10)] + [4, 3, 2, 1, 1, 1, 1, 1, 1, 1] + """ + if self.max_slope == Infinity: + return self + m *= self.sign + m = m - j * self.max_slope + return lambda i: self.sign * min(m + i*self.max_slope, self.sign*self(i) ) + + def __reduce__(self): + """ + Pickle ``self``. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists import Envelope + sage: h = Envelope(3, min_part=2) + sage: loads(dumps(h)) == h + True + """ + args = (type(self), + self.sign, self.f, self.f_limit_start, self.precomputed, + self.max_part, self.min_slope, self.max_slope) + return _unpickle_Envelope, args + + +def _unpickle_Envelope(type t, _sign, _f, _f_limit_start, _precomputed, + _max_part, _min_slope, _max_slope): + """ + Internal function to support pickling for :class:`Envelope`. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.base import Envelope, _unpickle_Envelope + sage: _unpickle_Envelope(Envelope, + ....: 1, lambda i:i, Infinity, [], 4, -1, 3) + + """ + cdef Envelope self = t.__new__(t) + self.sign = _sign + self.f = _f + self.f_limit_start = _f_limit_start + self.precomputed = _precomputed + self.max_part = _max_part + self.min_slope = _min_slope + self.max_slope = _max_slope + return self diff --git a/src/sage/combinat/integer_lists/invlex.pxd b/src/sage/combinat/integer_lists/invlex.pxd new file mode 100644 index 00000000000..143306b4448 --- /dev/null +++ b/src/sage/combinat/integer_lists/invlex.pxd @@ -0,0 +1,3 @@ +from sage.combinat.integer_lists.base cimport IntegerListsBackend +cdef class IntegerListsBackend_invlex(IntegerListsBackend): + cdef public bint check diff --git a/src/sage/combinat/integer_lists/invlex.pyx b/src/sage/combinat/integer_lists/invlex.pyx new file mode 100644 index 00000000000..f42fff09167 --- /dev/null +++ b/src/sage/combinat/integer_lists/invlex.pyx @@ -0,0 +1,1661 @@ +r""" +Enumerated set of lists of integers with constraints, in inverse lexicographic order + +- :class:`IntegerListsLex`: the enumerated set of lists of nonnegative + integers with specified constraints, in inverse lexicographic order. + +- :class:`IntegerListsBackend_invlex`: Cython back-end for + :class:`IntegerListsLex`. + +HISTORY: + +This generic tool was originally written by Hivert and Thiery in +MuPAD-Combinat in 2000 and ported over to Sage by Mike Hansen in +2007. It was then completely rewritten in 2015 by Gillespie, +Schilling, and Thiery, with the help of many, to deal with +limitations and lack of robustness w.r.t. input. +""" + +#***************************************************************************** +# Copyright (C) 2015 Bryan Gillespie +# Nicolas M. Thiery +# Anne Schilling +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + + +from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall +from sage.misc.cachefunc import cached_method +from sage.combinat.integer_lists.base cimport IntegerListsBackend +from sage.combinat.integer_lists.lists import IntegerLists +from sage.combinat.integer_lists.base import Infinity + + +class IntegerListsLex(IntegerLists): + r""" + Lists of nonnegative integers with constraints, in inverse lexicographic order. + + An *integer list* is a list `l` of nonnegative integers, its *parts*. The + slope (at position `i`) is the difference ``l[i+1]-l[i]`` between two + consecutive parts. + + This class allows to construct the set `S` of all integer lists + `l` satisfying specified bounds on the sum, the length, the slope, + and the individual parts, enumerated in *inverse* lexicographic + order, that is from largest to smallest in lexicographic + order. Note that, to admit such an enumeration, `S` is almost + necessarily finite (see :ref:`IntegerListsLex_finiteness`). + + The main purpose is to provide a generic iteration engine for all the + enumerated sets like :class:`Partitions`, :class:`Compositions`, + :class:`IntegerVectors`. It can also be used to generate many other + combinatorial objects like Dyck paths, Motzkin paths, etc. Mathematically + speaking, this is a special case of set of integral points of a polytope (or + union thereof, when the length is not fixed). + + INPUT: + + - ``min_sum`` -- a nonnegative integer (default: 0): + a lower bound on ``sum(l)``. + + - ``max_sum`` -- a nonnegative integer or `\infty` (default: `\infty`): + an upper bound on ``sum(l)``. + + - ``n`` -- a nonnegative integer (optional): if specified, this + overrides ``min_sum`` and ``max_sum``. + + - ``min_length`` -- a nonnegative integer (default: `0`): a lower + bound on ``len(l)``. + + - ``max_length`` -- a nonnegative integer or `\infty` (default: + `\infty`): an upper bound on ``len(l)``. + + - ``length`` -- an integer (optional); overrides ``min_length`` + and ``max_length`` if specified; + + - ``min_part`` -- a nonnegative integer: a lower bounds on all + parts: ``min_part <= l[i]`` for ``0 <= i < len(l)``. + + - ``floor`` -- a list of nonnegative integers or a function: lower + bounds on the individual parts `l[i]`. + + If ``floor`` is a list of integers, then ``floor<=l[i]`` for ``0 + <= i < min(len(l), len(floor)``. Similarly, if ``floor`` is a + function, then ``floor(i) <= l[i]`` for ``0 <= i < len(l)``. + + - ``max_part`` -- a nonnegative integer or `\infty`: an upper + bound on all parts: ``l[i] <= max_part`` for ``0 <= i < len(l)``. + + - ``ceiling`` -- upper bounds on the individual parts ``l[i]``; + this takes the same type of input as ``floor``, except that + `\infty` is allowed in addition to integers, and the default + value is `\infty`. + + - ``min_slope`` -- an integer or `-\infty` (default: `-\infty`): + an lower bound on the slope between consecutive parts: + ``min_slope <= l[i+1]-l[i]`` for ``0 <= i < len(l)-1`` + + - ``max_slope`` -- an integer or `+\infty` (defaults: `+\infty`) + an upper bound on the slope between consecutive parts: + ``l[i+1]-l[i] <= max_slope`` for ``0 <= i < len(l)-1`` + + - ``category`` -- a category (default: :class:`FiniteEnumeratedSets`) + + - ``check`` -- boolean (default: ``True``): whether to display the + warnings raised when functions are given as input to ``floor`` + or ``ceiling`` and the errors raised when there is no proper + enumeration. + + - ``name`` -- a string or ``None`` (default: ``None``) if set, + this will be passed down to :meth:`Parent.rename` to specify the + name of ``self``. It is recommented to use directly the rename + method as this feature may become deprecated. + + - ``element_constructor`` -- a function (or callable) that creates + elements of ``self`` from a list. See also :class:`Parent`. + + - ``element_class`` -- a class for the elements of ``self`` + (default: `ClonableArray`). This merely sets the attribute + ``self.Element``. See the examples for details. + + - ``global_options`` -- a :class:`~sage.structure.global_options.GlobalOptions` + object that will be assigned to the attribute + ``_global_options``; for internal use only (subclasses, ...). + + + .. NOTE:: + + When several lists satisfying the constraints differ only by + trailing zeroes, only the shortest one is enumerated (and + therefore counted). The others are still considered valid. + See the examples below. + + This feature is questionable. It is recommended not to rely on + it, as it may eventually be discontinued. + + EXAMPLES: + + We create the enumerated set of all lists of nonnegative integers + of length `3` and sum `2`:: + + sage: C = IntegerListsLex(2, length=3) + sage: C + Integer lists of sum 2 satisfying certain constraints + sage: C.cardinality() + 6 + sage: [p for p in C] + [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] + + sage: [2, 0, 0] in C + True + sage: [2, 0, 1] in C + False + sage: "a" in C + False + sage: ["a"] in C + False + sage: C.first() + [2, 0, 0] + + One can specify lower and upper bounds on each part:: + + sage: list(IntegerListsLex(5, length=3, floor=[1,2,0], ceiling=[3,2,3])) + [[3, 2, 0], [2, 2, 1], [1, 2, 2]] + + When the length is fixed as above, one can also use + :class:`IntegerVectors`:: + + sage: IntegerVectors(2,3).list() + [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] + + Using the slope condition, one can generate integer partitions + (but see :class:`Partitions`):: + + sage: list(IntegerListsLex(4, max_slope=0)) + [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] + + The following is the list of all partitions of `7` with parts at least `2`:: + + sage: list(IntegerListsLex(7, max_slope=0, min_part=2)) + [[7], [5, 2], [4, 3], [3, 2, 2]] + + + .. RUBRIC:: floor and ceiling conditions + + Next we list all partitions of `5` of length at most `3` which are + bounded below by ``[2,1,1]``:: + + sage: list(IntegerListsLex(5, max_slope=0, max_length=3, floor=[2,1,1])) + [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1]] + + Note that ``[5]`` is considered valid, because the floor + constraints only apply to existing positions in the list. To + obtain instead the partitions containing ``[2,1,1]``, one needs to + use ``min_length`` or ``length``:: + + sage: list(IntegerListsLex(5, max_slope=0, length=3, floor=[2,1,1])) + [[3, 1, 1], [2, 2, 1]] + + Here is the list of all partitions of `5` which are contained in + ``[3,2,2]``:: + + sage: list(IntegerListsLex(5, max_slope=0, max_length=3, ceiling=[3,2,2])) + [[3, 2], [3, 1, 1], [2, 2, 1]] + + This is the list of all compositions of `4` (but see :class:`Compositions`):: + + sage: list(IntegerListsLex(4, min_part=1)) + [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] + + This is the list of all integer vectors of sum `4` and length `3`:: + + sage: list(IntegerListsLex(4, length=3)) + [[4, 0, 0], [3, 1, 0], [3, 0, 1], [2, 2, 0], [2, 1, 1], + [2, 0, 2], [1, 3, 0], [1, 2, 1], [1, 1, 2], [1, 0, 3], + [0, 4, 0], [0, 3, 1], [0, 2, 2], [0, 1, 3], [0, 0, 4]] + + For whatever it is worth, the ``floor`` and ``min_part`` + constraints can be combined:: + + sage: L = IntegerListsLex(5, floor=[2,0,2], min_part=1) + sage: L.list() + [[5], [4, 1], [3, 2], [2, 3], [2, 1, 2]] + + This is achieved by updating the floor upon constructing ``L``:: + + sage: [L.floor(i) for i in range(5)] + [2, 1, 2, 1, 1] + + Similarly, the ``ceiling`` and ``max_part`` constraints can be + combined:: + + sage: L = IntegerListsLex(4, ceiling=[2,3,1], max_part=2, length=3) + sage: L.list() + [[2, 2, 0], [2, 1, 1], [1, 2, 1]] + sage: [L.ceiling(i) for i in range(5)] + [2, 2, 1, 2, 2] + + + This can be used to generate Motzkin words (see + :wikipedia:`Motzkin_number`):: + + sage: def motzkin_words(n): + ....: return IntegerListsLex(length=n+1, min_slope=-1, max_slope=1, + ....: ceiling=[0]+[+oo for i in range(n-1)]+[0]) + sage: motzkin_words(4).list() + [[0, 1, 2, 1, 0], + [0, 1, 1, 1, 0], + [0, 1, 1, 0, 0], + [0, 1, 0, 1, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 1, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 0]] + sage: [motzkin_words(n).cardinality() for n in range(8)] + [1, 1, 2, 4, 9, 21, 51, 127] + sage: oeis(_) # optional -- internet + 0: A001006: Motzkin numbers: number of ways of drawing any number + of nonintersecting chords joining n (labeled) points on a circle. + + or Dyck words (see also :class:`DyckWords`), through the bijection + with paths from `(0,0)` to `(n,n)` with left and up steps that remain + below the diagonal:: + + sage: def dyck_words(n): + ....: return IntegerListsLex(length=n, ceiling=range(n+1), min_slope=0) + sage: [dyck_words(n).cardinality() for n in range(8)] + [1, 1, 2, 5, 14, 42, 132, 429] + sage: dyck_words(3).list() + [[0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 0]] + + + .. _IntegerListsLex_finiteness: + + .. RUBRIC:: On finiteness and inverse lexicographic enumeration + + The set of all lists of integers cannot be enumerated in inverse + lexicographic order, since there is no largest list (take `[n]` + for `n` as large as desired):: + + sage: IntegerListsLex().first() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + Here is a variant which could be enumerated in lexicographic order + but not in inverse lexicographic order:: + + sage: L = IntegerListsLex(length=2, ceiling=[Infinity, 0], floor=[0,1]) + sage: for l in L: print l + Traceback (most recent call last): + ... + ValueError: infinite upper bound for values of m + + Even when the sum is specified, it is not necessarily possible to + enumerate *all* elements in inverse lexicographic order. In the + following example, the list ``[1, 1, 1]`` will never appear in the + enumeration:: + + sage: IntegerListsLex(3).first() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + If one wants to proceed anyway, one can sign a waiver by setting + ``check=False`` (again, be warned that some valid lists may never appear):: + + sage: L = IntegerListsLex(3, check=False) + sage: it = iter(L) + sage: [next(it) for i in range(6)] + [[3], [2, 1], [2, 0, 1], [2, 0, 0, 1], [2, 0, 0, 0, 1], [2, 0, 0, 0, 0, 1]] + + In fact, being inverse lexicographically enumerable is almost + equivalent to being finite. The only infinity that can occur would + be from a tail of numbers `0,1` as in the previous example, where + the `1` moves further and further to the right. If there is any + list that is inverse lexicographically smaller than such a + configuration, the iterator would not reach it and hence would not + be considered iterable. Given that the infinite cases are very + specific, at this point only the finite cases are supported + (without signing the waiver). + + The finiteness detection is not complete yet, so some finite cases + may not be supported either, at least not without disabling the + checks. Practical examples of such are welcome. + + .. RUBRIC:: On trailing zeroes, and their caveats + + As mentioned above, when several lists satisfying the constraints + differ only by trailing zeroes, only the shortest one is listed:: + + sage: L = IntegerListsLex(max_length=4, max_part=1) + sage: L.list() + [[1, 1, 1, 1], + [1, 1, 1], + [1, 1, 0, 1], + [1, 1], + [1, 0, 1, 1], + [1, 0, 1], + [1, 0, 0, 1], + [1], + [0, 1, 1, 1], + [0, 1, 1], + [0, 1, 0, 1], + [0, 1], + [0, 0, 1, 1], + [0, 0, 1], + [0, 0, 0, 1], + []] + + and counted:: + + sage: L.cardinality() + 16 + + Still, the others are considered as elements of `L`:: + + sage: L = IntegerListsLex(4,min_length=3,max_length=4) + sage: L.list() + [..., [2, 2, 0], ...] + + sage: [2, 2, 0] in L # in L.list() + True + sage: [2, 2, 0, 0] in L # not in L.list() ! + True + sage: [2, 2, 0, 0, 0] in L + False + + .. RUBRIC:: Specifying functions as input for the floor or ceiling + + We construct all lists of sum `4` and length `4` such that ``l[i] <= i``:: + + sage: list(IntegerListsLex(4, length=4, ceiling=lambda i: i, check=False)) + [[0, 1, 2, 1], [0, 1, 1, 2], [0, 1, 0, 3], [0, 0, 2, 2], [0, 0, 1, 3]] + + .. WARNING:: + + When passing a function as ``floor`` or ``ceiling``, it may + become undecidable to detect improper inverse lexicographic + enumeration. For example, the following example has a finite + enumeration:: + + sage: L = IntegerListsLex(3, floor=lambda i: 1 if i>=2 else 0, check=False) + sage: L.list() + [[3], + [2, 1], + [2, 0, 1], + [1, 2], + [1, 1, 1], + [1, 0, 2], + [1, 0, 1, 1], + [0, 3], + [0, 2, 1], + [0, 1, 2], + [0, 1, 1, 1], + [0, 0, 3], + [0, 0, 2, 1], + [0, 0, 1, 2], + [0, 0, 1, 1, 1]] + + but one cannot decide whether the following has an improper + inverse lexicographic enumeration without computing the floor + all the way to ``Infinity``:: + + sage: L = IntegerListsLex(3, floor=lambda i: 0, check=False) + sage: it = iter(L) + sage: [next(it) for i in range(6)] + [[3], [2, 1], [2, 0, 1], [2, 0, 0, 1], [2, 0, 0, 0, 1], [2, 0, 0, 0, 0, 1]] + + Hence a warning is raised when a function is specified as + input, unless the waiver is signed by setting ``check=False``:: + + sage: L = IntegerListsLex(3, floor=lambda i: 1 if i>=2 else 0) + doctest:... + A function has been given as input of the floor=[...] or ceiling=[...] + arguments of IntegerListsLex. Please see the documentation for the caveats. + If you know what you are doing, you can set check=False to skip this warning. + + Similarly, the algorithm may need to search forever for a + solution when the ceiling is ultimately zero:: + + sage: L = IntegerListsLex(2,ceiling=lambda i:0, check=False) + sage: L.first() # not tested: will hang forever + sage: L = IntegerListsLex(2,ceiling=lambda i:0 if i<20 else 1, check=False) + sage: it = iter(L) + sage: next(it) + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] + sage: next(it) + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1] + sage: next(it) + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1] + + + .. RUBRIC:: Tip: using disjoint union enumerated sets for additional flexibility + + Sometimes, specifying a range for the sum or the length may be too + restrictive. One would want instead to specify a list, or + iterable `L`, of acceptable values. This is easy to achieve using + a :class:`disjoint union of enumerated sets `. + Here we want to accept the values `n=0,2,3`:: + + sage: C = DisjointUnionEnumeratedSets(Family([0,2,3], + ....: lambda n: IntegerListsLex(n, length=2))) + sage: C + Disjoint union of Finite family + {0: Integer lists of sum 0 satisfying certain constraints, + 2: Integer lists of sum 2 satisfying certain constraints, + 3: Integer lists of sum 3 satisfying certain constraints} + sage: C.list() + [[0, 0], + [2, 0], [1, 1], [0, 2], + [3, 0], [2, 1], [1, 2], [0, 3]] + + The price to pay is that the enumeration order is now *graded + lexicographic* instead of lexicographic: first choose the value + according to the order specified by `L`, and use lexicographic + order within each value. Here is we reverse `L`:: + + sage: DisjointUnionEnumeratedSets(Family([3,2,0], + ....: lambda n: IntegerListsLex(n, length=2))).list() + [[3, 0], [2, 1], [1, 2], [0, 3], + [2, 0], [1, 1], [0, 2], + [0, 0]] + + Note that if a given value appears several times, the + corresponding elements will be enumerated several times, which + may, or not, be what one wants:: + + sage: DisjointUnionEnumeratedSets(Family([2,2], + ....: lambda n: IntegerListsLex(n, length=2))).list() + [[2, 0], [1, 1], [0, 2], [2, 0], [1, 1], [0, 2]] + + Here is a variant where we specify acceptable values for the + length:: + + sage: DisjointUnionEnumeratedSets(Family([0,1,3], + ....: lambda l: IntegerListsLex(2, length=l))).list() + [[2], + [2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] + + + This technique can also be useful to obtain a proper enumeration + on infinite sets by using a graded lexicographic enumeration:: + + sage: C = DisjointUnionEnumeratedSets(Family(NN, + ....: lambda n: IntegerListsLex(n, length=2))) + sage: C + Disjoint union of Lazy family ((i))_{i in Non negative integer semiring} + sage: it = iter(C) + sage: [next(it) for i in range(10)] + [[0, 0], + [1, 0], [0, 1], + [2, 0], [1, 1], [0, 2], + [3, 0], [2, 1], [1, 2], [0, 3]] + + + .. RUBRIC:: Specifying how to construct elements + + This is the list of all monomials of degree `4` which divide the + monomial `x^3y^1z^2` (a monomial being identified with its + exponent vector):: + + sage: R. = QQ[] + sage: m = [3,1,2] + sage: def term(exponents): + ....: return x^exponents[0] * y^exponents[1] * z^exponents[2] + sage: list( IntegerListsLex(4, length=len(m), ceiling=m, element_constructor=term) ) + [x^3*y, x^3*z, x^2*y*z, x^2*z^2, x*y*z^2] + + Note the use of the ``element_constructor`` option to specify how + to construct elements from a plain list. + + A variant is to specify a class for the elements. With the default + element constructor, this class should take as input the parent + ``self`` and a list. Here we want the elements to be constructed + in the class :class:`Partition`:: + + sage: IntegerListsLex(3, max_slope=0, element_class=Partition, global_options=Partitions.global_options).list() + [[3], [2, 1], [1, 1, 1]] + + Note that the :class:`Partition` further assumes the existence of + an attribute ``_global_options`` in the parent, hence the use of the + ``global_options`` parameter. + + .. WARNING:: + + The protocol for specifying the element class and constructor + is subject to changes. + + ALGORITHM: + + The iteration algorithm uses a depth first search through the + prefix tree of the list of integers (see also + :ref:`section-generic-integerlistlex`). While doing so, it does + some lookahead heuristics to attempt to cut dead branches. + + In most practical use cases, most dead branches are cut. Then, + roughly speaking, the time needed to iterate through all the + elements of `S` is proportional to the number of elements, where + the proportion factor is controlled by the length `l` of the + longest element of `S`. In addition, the memory usage is also + controlled by `l`, which is to say negligible in practice. + + Still, there remains much room for efficiency improvements; see + :trac:`18055`, :trac:`18056`. + + .. NOTE:: + + The generation algorithm could in principle be extended to + deal with non-constant slope constraints and with negative + parts. + + TESTS: + + This example from the combinatorics tutorial used to fail before + :trac:`17979` because the floor conditions did not satisfy the + slope conditions:: + + sage: I = IntegerListsLex(16, min_length=2, max_slope=-1, floor=[5,3,3]) + sage: I.list() + [[13, 3], [12, 4], [11, 5], [10, 6], [9, 7], [9, 4, 3], [8, 5, 3], [8, 4, 3, 1], + [7, 6, 3], [7, 5, 4], [7, 5, 3, 1], [7, 4, 3, 2], [6, 5, 4, 1], [6, 5, 3, 2], + [6, 4, 3, 2, 1]] + + :: + + sage: Partitions(2, max_slope=-1, length=2).list() + [] + sage: list(IntegerListsLex(0, floor=ConstantFunction(1), min_slope=0)) + [[]] + sage: list(IntegerListsLex(0, floor=ConstantFunction(1), min_slope=0, max_slope=0)) + [[]] + sage: list(IntegerListsLex(0, max_length=0, floor=ConstantFunction(1), min_slope=0, max_slope=0)) + [[]] + sage: list(IntegerListsLex(0, max_length=0, floor=ConstantFunction(0), min_slope=0, max_slope=0)) + [[]] + sage: list(IntegerListsLex(0, min_part=1, min_slope=0)) + [[]] + sage: list(IntegerListsLex(1, min_part=1, min_slope=0)) + [[1]] + sage: list(IntegerListsLex(0, min_length=1, min_part=1, min_slope=0)) + [] + sage: list(IntegerListsLex(0, min_length=1, min_slope=0)) + [[0]] + sage: list(IntegerListsLex(3, max_length=2)) + [[3], [2, 1], [1, 2], [0, 3]] + sage: partitions = {"min_part": 1, "max_slope": 0} + sage: partitions_min_2 = {"floor": ConstantFunction(2), "max_slope": 0} + sage: compositions = {"min_part": 1} + sage: integer_vectors = lambda l: {"length": l} + sage: lower_monomials = lambda c: {"length": c, "floor": lambda i: c[i]} + sage: upper_monomials = lambda c: {"length": c, "ceiling": lambda i: c[i]} + sage: constraints = { "min_part":1, "min_slope": -1, "max_slope": 0} + sage: list(IntegerListsLex(6, **partitions)) + [[6], + [5, 1], + [4, 2], + [4, 1, 1], + [3, 3], + [3, 2, 1], + [3, 1, 1, 1], + [2, 2, 2], + [2, 2, 1, 1], + [2, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1]] + sage: list(IntegerListsLex(6, **constraints)) + [[6], + [3, 3], + [3, 2, 1], + [2, 2, 2], + [2, 2, 1, 1], + [2, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1]] + sage: list(IntegerListsLex(1, **partitions_min_2)) + [] + sage: list(IntegerListsLex(2, **partitions_min_2)) + [[2]] + sage: list(IntegerListsLex(3, **partitions_min_2)) + [[3]] + sage: list(IntegerListsLex(4, **partitions_min_2)) + [[4], [2, 2]] + sage: list(IntegerListsLex(5, **partitions_min_2)) + [[5], [3, 2]] + sage: list(IntegerListsLex(6, **partitions_min_2)) + [[6], [4, 2], [3, 3], [2, 2, 2]] + sage: list(IntegerListsLex(7, **partitions_min_2)) + [[7], [5, 2], [4, 3], [3, 2, 2]] + sage: list(IntegerListsLex(9, **partitions_min_2)) + [[9], [7, 2], [6, 3], [5, 4], [5, 2, 2], [4, 3, 2], [3, 3, 3], [3, 2, 2, 2]] + sage: list(IntegerListsLex(10, **partitions_min_2)) + [[10], + [8, 2], + [7, 3], + [6, 4], + [6, 2, 2], + [5, 5], + [5, 3, 2], + [4, 4, 2], + [4, 3, 3], + [4, 2, 2, 2], + [3, 3, 2, 2], + [2, 2, 2, 2, 2]] + sage: list(IntegerListsLex(4, **compositions)) + [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] + sage: list(IntegerListsLex(6, min_length=1, floor=[7])) + [] + sage: L = IntegerListsLex(10**100,length=1) + sage: L.list() + [[10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]] + + Noted on :trac:`17898`:: + + sage: list(IntegerListsLex(4, min_part=1, length=3, min_slope=1)) + [] + sage: IntegerListsLex(6, ceiling=[4,2], floor=[3,3]).list() + [] + sage: IntegerListsLex(6, min_part=1, max_part=3, max_slope=-4).list() + [] + + Noted in :trac:`17548`, which are now fixed:: + + sage: IntegerListsLex(10, min_part=2, max_slope=-1).list() + [[10], [8, 2], [7, 3], [6, 4], [5, 3, 2]] + sage: IntegerListsLex(5, min_slope=1, floor=[2,1,1], max_part=2).list() + [] + sage: IntegerListsLex(4, min_slope=0, max_slope=0).list() + [[4], [2, 2], [1, 1, 1, 1]] + sage: IntegerListsLex(6, min_slope=-1, max_slope=-1).list() + [[6], [3, 2, 1]] + sage: IntegerListsLex(6, min_length=3, max_length=2, min_part=1).list() + [] + sage: I = IntegerListsLex(3, max_length=2, min_part=1) + sage: I.list() + [[3], [2, 1], [1, 2]] + sage: [1,1,1] in I + False + sage: I=IntegerListsLex(10, ceiling=[4], max_length=1, min_part=1) + sage: I.list() + [] + sage: [4,6] in I + False + sage: I = IntegerListsLex(4, min_slope=1, min_part=1, max_part=2) + sage: I.list() + [] + sage: I = IntegerListsLex(7, min_slope=1, min_part=1, max_part=4) + sage: I.list() + [[3, 4], [1, 2, 4]] + sage: I = IntegerListsLex(4, floor=[2,1], ceiling=[2,2], max_length=2, min_slope=0) + sage: I.list() + [[2, 2]] + sage: I = IntegerListsLex(10, min_part=1, max_slope=-1) + sage: I.list() + [[10], [9, 1], [8, 2], [7, 3], [7, 2, 1], [6, 4], [6, 3, 1], [5, 4, 1], + [5, 3, 2], [4, 3, 2, 1]] + + + .. RUBRIC:: TESTS from comments on :trac:`17979` + + Comment 191:: + + sage: list(IntegerListsLex(1, min_length=2, min_slope=0, max_slope=0)) + [] + + Comment 240:: + + sage: L = IntegerListsLex(min_length=2, max_part=0) + sage: L.list() + [[0, 0]] + + .. RUBRIC:: Tests on the element constructor feature and mutability + + Internally, the iterator works on a single list that is mutated + along the way. Therefore, you need to make sure that the + ``element_constructor`` actually **copies** its input. This example + shows what can go wrong:: + + sage: P = IntegerListsLex(n=3, max_slope=0, min_part=1, element_constructor=lambda x: x) + sage: list(P) + [[], [], []] + + However, specifying ``list()`` as constructor solves this problem:: + + sage: P = IntegerListsLex(n=3, max_slope=0, min_part=1, element_constructor=list) + sage: list(P) + [[3], [2, 1], [1, 1, 1]] + + Same, step by step:: + + sage: it = iter(P) + sage: a = next(it); a + [3] + sage: b = next(it); b + [2, 1] + sage: a + [3] + sage: a is b + False + + Tests from `MuPAD-Combinat `_:: + + sage: IntegerListsLex(7, min_length=2, max_length=6, floor=[0,0,2,0,0,1], ceiling=[3,2,3,2,1,2]).cardinality() + 83 + sage: IntegerListsLex(7, min_length=2, max_length=6, floor=[0,0,2,0,1,1], ceiling=[3,2,3,2,1,2]).cardinality() + 53 + sage: IntegerListsLex(5, min_length=2, max_length=6, floor=[0,0,2,0,0,0], ceiling=[2,2,2,2,2,2]).cardinality() + 30 + sage: IntegerListsLex(5, min_length=2, max_length=6, floor=[0,0,1,1,0,0], ceiling=[2,2,2,2,2,2]).cardinality() + 43 + + sage: IntegerListsLex(0, min_length=0, max_length=7, floor=[1,1,0,0,1,0], ceiling=[4,3,2,3,2,2,1]).first() + [] + + sage: IntegerListsLex(0, min_length=1, max_length=7, floor=[0,1,0,0,1,0], ceiling=[4,3,2,3,2,2,1]).first() + [0] + sage: IntegerListsLex(0, min_length=1, max_length=7, floor=[1,1,0,0,1,0], ceiling=[4,3,2,3,2,2,1]).cardinality() + 0 + + sage: IntegerListsLex(2, min_length=0, max_length=7, floor=[1,1,0,0,0,0], ceiling=[4,3,2,3,2,2,1]).first() # Was [1,1], due to slightly different specs + [2] + sage: IntegerListsLex(1, min_length=1, max_length=7, floor=[1,1,0,0,0,0], ceiling=[4,3,2,3,2,2,1]).first() + [1] + sage: IntegerListsLex(1, min_length=2, max_length=7, floor=[1,1,0,0,0,0], ceiling=[4,3,2,3,2,2,1]).cardinality() + 0 + sage: IntegerListsLex(2, min_length=5, max_length=7, floor=[1,1,0,0,0,0], ceiling=[4,3,2,3,2,2,1]).first() + [1, 1, 0, 0, 0] + sage: IntegerListsLex(2, min_length=5, max_length=7, floor=[1,1,0,0,0,1], ceiling=[4,3,2,3,2,2,1]).first() + [1, 1, 0, 0, 0] + sage: IntegerListsLex(2, min_length=5, max_length=7, floor=[1,1,0,0,1,0], ceiling=[4,3,2,3,2,2,1]).cardinality() + 0 + + sage: IntegerListsLex(4, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).cardinality() + 0 + sage: IntegerListsLex(5, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).first() + [2, 1, 2] + sage: IntegerListsLex(6, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).first() + [3, 1, 2] + sage: IntegerListsLex(12, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).first() + [3, 1, 2, 3, 2, 1] + sage: IntegerListsLex(13, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).first() + [3, 1, 2, 3, 2, 2] + sage: IntegerListsLex(14, min_length=3, max_length=6, floor=[2, 1, 2, 1, 1, 1], ceiling=[3, 1, 2, 3, 2, 2]).cardinality() + 0 + + This used to hang (see comment 389 and fix in :meth:`Envelope.__init__`):: + + sage: IntegerListsLex(7, max_part=0, ceiling=lambda i:i, check=False).list() + [] + """ + backend_class = IntegerListsBackend_invlex + + __metaclass__ = ClasscallMetaclass + + @staticmethod + def __classcall_private__(cls, n=None, **kwargs): + r""" + Return a disjoint union if ``n`` is a list or iterable. + + TESTS: + + Specifying a list or iterable as argument is deprecated:: + + sage: IntegerListsLex([2,2], length=2).list() + doctest:...: DeprecationWarning: Calling IntegerListsLex with n an iterable is deprecated. Please use DisjointUnionEnumeratedSets or the min_sum and max_sum arguments instead + See http://trac.sagemath.org/17979 for details. + [[2, 0], [1, 1], [0, 2], [2, 0], [1, 1], [0, 2]] + sage: IntegerListsLex(NN, max_length=3) + Disjoint union of Lazy family (<...>(i))_{i in Non negative integer semiring} + """ + import collections + if isinstance(n, collections.Iterable): + from sage.misc.superseded import deprecation + deprecation(17979, 'Calling IntegerListsLex with n an iterable is deprecated. Please use DisjointUnionEnumeratedSets or the min_sum and max_sum arguments instead') + from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets + from sage.sets.family import Family + return DisjointUnionEnumeratedSets(Family(n, lambda i: IntegerListsLex(i, **kwargs))) + else: + return typecall(cls, n=n, **kwargs) + + +cdef class IntegerListsBackend_invlex(IntegerListsBackend): + def __init__(self, *args, check=True, **kwds): + """ + Initialize ``self``. + + TESTS:: + + sage: C = IntegerListsLex(2, length=3) + sage: C == loads(dumps(C)) + True + sage: C.cardinality().parent() is ZZ + True + sage: TestSuite(C).run() + sage: IntegerListsLex(min_part=-1) + Traceback (most recent call last): + ... + NotImplementedError: strictly negative min_part + """ + IntegerListsBackend.__init__(self, *args, **kwds) + + self.check = check + + if self.min_part < 0: + raise NotImplementedError("strictly negative min_part") + + if self.check and ( + self.floor.limit_start() == Infinity or + self.ceiling.limit_start() == Infinity): + from warnings import warn + warn(""" +A function has been given as input of the floor=[...] or ceiling=[...] +arguments of IntegerListsLex. Please see the documentation for the caveats. +If you know what you are doing, you can set check=False to skip this warning.""") + + @cached_method + def _check_finiteness(self): + """ + Check that the constraints define a finite set. + + As mentioned in the description of this class, being finite is + almost equivalent to being inverse lexicographic iterable, + which is what we really care about. + + This set is finite if and only if: + + #. For each `i` such that there exists a list of length at + least `i+1` satisfying the constraints, there exists a + direct or indirect upper bound on the `i`-th part, that + is ``self.ceiling(i)`` is finite. + + #. There exists a global upper bound on the length. + + Failures for 1. are detected and reported later, during the + iteration, namely the first time a prefix including the `i`-th + part is explored. + + This method therefore focuses on 2., namely trying to prove + the existence of an upper bound on the length. It may fail + to do so even when the set is actually finite. + + OUTPUT: ``None`` if this method finds a proof that there + exists an upper bound on the length. Otherwise a + ``ValueError`` is raised. + + EXAMPLES:: + + sage: L = IntegerListsLex(4, max_length=4) + sage: L._check_finiteness() + + The following example is infinite:: + + sage: L = IntegerListsLex(4) + sage: L._check_finiteness() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + Indeed:: + + sage: it = iter(IntegerListsLex(4, check=False)) + sage: for _ in range(10): print next(it) + [4] + [3, 1] + [3, 0, 1] + [3, 0, 0, 1] + [3, 0, 0, 0, 1] + [3, 0, 0, 0, 0, 1] + [3, 0, 0, 0, 0, 0, 1] + [3, 0, 0, 0, 0, 0, 0, 1] + [3, 0, 0, 0, 0, 0, 0, 0, 1] + [3, 0, 0, 0, 0, 0, 0, 0, 0, 1] + + Unless ``check=False`, :meth:`_check_finiteness` is called as + soon as an iteration is attempted:: + + sage: iter(L) + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + Some other infinite examples:: + + sage: L = IntegerListsLex(ceiling=[0], min_slope=1, max_slope=2) + sage: L.list() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + sage: L = IntegerListsLex(ceiling=[0], min_slope=1, max_slope=1) + sage: L.list() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + sage: IntegerListsLex(ceiling=[0], min_slope=1, max_slope=1).list() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + The following example is actually finite, but not detected as such:: + + sage: IntegerListsLex(7, floor=[4], max_part=4, min_slope=-1).list() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + This is sad because the following equivalent example works just fine:: + + sage: IntegerListsLex(7, floor=[4,3], max_part=4, min_slope=-1).list() + [[4, 3]] + + Detecting this properly would require some deeper lookahead, + and the difficulty is to decide how far this lookahead should + search. Until this is fixed, one can disable the checks:: + + sage: IntegerListsLex(7, floor=[4], max_part=4, min_slope=-1, check=False).list() + [[4, 3]] + + If the ceiling or floor is a function, it is much more likely + that a finite set will not be detected as such:: + + sage: IntegerListsLex(ceiling=lambda i: max(3-i,0))._check_finiteness() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + sage: IntegerListsLex(7, ceiling=lambda i:0).list() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + The next example shows a case that is finite because we remove + trailing zeroes:: + + sage: list(IntegerListsLex(ceiling=[0], max_slope=0)) + [[]] + sage: L = IntegerListsLex(ceiling=[1], min_slope=1, max_slope=1) + sage: L.list() + Traceback (most recent call last): + ... + ValueError: Could not prove that the specified constraints yield a finite set + + In the next examples, there is either no solution, or the region + is bounded:: + + sage: IntegerListsLex(min_sum=10, max_sum=5).list() + [] + sage: IntegerListsLex(max_part=1, min_slope=10).list() + [[1], []] + sage: IntegerListsLex(max_part=100, min_slope=10).first() + [100] + sage: IntegerListsLex(ceiling=[1,Infinity], max_part=2, min_slope=1).list() + [[1, 2], [1], [0, 2], [0, 1, 2], [0, 1], []] + sage: IntegerListsLex(min_sum=1, floor=[1,2], max_part=1).list() + [[1]] + + sage: IntegerListsLex(min_length=2, max_length=1).list() + [] + sage: IntegerListsLex(min_length=-2, max_length=-1).list() + [] + sage: IntegerListsLex(min_length=-1, max_length=-2).list() + [] + sage: IntegerListsLex(min_length=2, max_slope=0, min_slope=1).list() + [] + sage: IntegerListsLex(min_part=2, max_part=1).list() + [[]] + + sage: IntegerListsLex(floor=[0,2], ceiling=[3,1]).list() + [[3], [2], [1], []] + sage: IntegerListsLex(7, ceiling=[2], floor=[4]).list() + [] + sage: IntegerListsLex(7, max_part=0).list() + [] + sage: IntegerListsLex(5, max_part=0, min_slope=0).list() + [] + sage: IntegerListsLex(max_part=0).list() + [[]] + sage: IntegerListsLex(max_sum=1, min_sum=4, min_slope=0).list() + [] + """ + # Trivial cases + if self.max_length < Infinity: + return + if self.max_sum < self.min_sum: + return + if self.min_slope > self.max_slope: + return + if self.max_slope < 0: + return + if self.ceiling.limit() < self.floor.limit(): + return + if self.ceiling.limit() == 0: + # This assumes no trailing zeroes + return + if self.min_slope > 0 and self.ceiling.limit() < Infinity: + return + + # Compute a lower bound on the sum of floor(i) for i=1 to infinity + if self.floor.limit() > 0 or self.min_slope > 0: + floor_sum_lower_bound = Infinity + elif self.floor.limit_start() < Infinity: + floor_sum_lower_bound = sum(self.floor(i) for i in range(self.floor.limit_start())) + else: + floor_sum_lower_bound = 0 + if floor_sum_lower_bound > 0 and self.min_slope >= 0: + floor_sum_lower_bound = Infinity + + if self.max_sum < floor_sum_lower_bound: + return + if self.max_sum == floor_sum_lower_bound and self.max_sum < Infinity: + # This assumes no trailing zeroes + return + + # Variant on ceiling.limit() ==0 where we actually discover that the ceiling limit is 0 + if self.max_slope == 0 and \ + (self.max_sum < Infinity or + (self.ceiling.limit_start() < Infinity and + any(self.ceiling(i) == 0 for i in range(self.ceiling.limit_start()+1)))): + return + + limit_start = max(self.ceiling.limit_start(), self.floor.limit_start()) + if limit_start < Infinity: + for i in range(limit_start+1): + if self.ceiling(i) < self.floor(i): + return + + raise ValueError("Could not prove that the specified constraints yield a finite set") + + def _iter(self): + """ + Return an iterator for the elements of ``self``. + + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3) + sage: list(C) # indirect doctest + [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] + """ + if self.check: + self._check_finiteness() + return IntegerListsLexIter(self) + + +# Constants for IntegerListsLexIter._next_state +LOOKAHEAD = 5 +PUSH = 4 +ME = 3 +DECREASE = 2 +POP = 1 +STOP = 0 + +class IntegerListsLexIter: + r""" + Iterator class for IntegerListsLex. + + Let ``T`` be the prefix tree of all lists of nonnegative + integers that satisfy all constraints except possibly for + ``min_length`` and ``min_sum``; let the children of a list + be sorted decreasingly according to their last part. + + The iterator is based on a depth-first search exploration of a + subtree of this tree, trying to cut branches that do not + contain a valid list. Each call of ``next`` iterates through + the nodes of this tree until it finds a valid list to return. + + Here are the attributes describing the current state of the + iterator, and their invariants: + + - ``backend`` -- the :class:`IntegerListsBackend` object this is + iterating on; + + - ``_current_list`` -- the list corresponding to the current + node of the tree; + + - ``_j`` -- the index of the last element of ``_current_list``: + ``self._j == len(self._current_list) - 1``; + + - ``_current_sum`` -- the sum of the parts of ``_current_list``; + + - ``_search_ranges`` -- a list of same length as + ``_current_list``: the range for each part. + + Furthermore, we assume that there is no obvious contradiction + in the contraints: + + - ``self.backend.min_length <= self.backend.max_length``; + - ``self.backend.min_slope <= self.backend.max_slope`` + unless ``self.backend.min_length <= 1``. + + Along this iteration, ``next`` switches between the following + states: + + - LOOKAHEAD: determine whether the current list could be a + prefix of a valid list; + - PUSH: go deeper into the prefix tree by appending the + largest possible part to the current list; + - ME: check whether the current list is valid and if yes return it + - DECREASE: decrease the last part; + - POP: pop the last part of the current list; + - STOP: the iteration is finished. + + The attribute ``_next_state`` contains the next state ``next`` + should enter in. + """ + def __init__(self, backend): + """ + TESTS:: + + sage: from sage.combinat.integer_lists.invlex import IntegerListsLexIter + sage: C = IntegerListsLex(2, length=3) + sage: I = IntegerListsLexIter(C) + sage: I._search_ranges + [] + sage: I._current_list + [] + sage: I._j + -1 + sage: I._current_sum + 0 + """ + self.backend = backend + + self._search_ranges = [] + self._current_list = [] + self._j = -1 # index of last element of _current_list + self._current_sum = 0 # sum of parts in _current_list + + # Make sure that some invariants are respected in the iterator + if (backend.min_length <= backend.max_length and + (backend.min_slope <= backend.max_slope or backend.min_length <= 1)): + self._next_state = PUSH + else: + self._next_state = STOP + + def __iter__(self): + """ + Return ``self`` as per the iterator protocol. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.invlex import IntegerListsLexIter + sage: C = IntegerListsLex(2, length=3) + sage: it = IntegerListsLexIter(C) + sage: it.__iter__() is it + True + """ + return self + + def _push_search(self): + """ + Push search forward, resetting attributes. + + The push may fail if it is discovered that + ``self._current_list`` cannot be extended in a valid way. + + OUTPUT: a boolean: whether the push succeeded + + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3) + sage: I = C._iter() + sage: I._j + -1 + sage: I._search_ranges + [] + sage: I._current_list + [] + sage: I._current_sum + 0 + sage: I._push_search() + True + sage: I._j + 0 + sage: I._search_ranges + [(0, 2)] + sage: I._current_list + [2] + sage: I._current_sum + 2 + sage: I._push_search() + True + sage: I._j + 1 + sage: I._search_ranges + [(0, 2), (0, 0)] + sage: I._current_list + [2, 0] + sage: I._current_sum + 2 + """ + max_sum = self.backend.max_sum + min_length = self.backend.min_length + max_length = self.backend.max_length + if self._j+1 >= max_length: + return False + if self._j+1 >= min_length and self._current_sum == max_sum: + # Cannot add trailing zeroes + return False + + if self._j >= 0: + prev = self._current_list[self._j] + else: + prev = None + interval = self._m_interval(self._j+1, self.backend.max_sum - self._current_sum, prev) + if interval[0] > interval[1]: + return False + + self._j += 1 + m = interval[1] + self._search_ranges.append(interval) + self._current_list.append(m) + self._current_sum += m + return True + + def _pop_search(self): + """ + Go back in search tree. Resetting attributes. + + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3) + sage: I = C._iter() + sage: I._push_search() + True + sage: I._j + 0 + sage: I._search_ranges + [(0, 2)] + sage: I._current_sum + 2 + sage: I._current_list + [2] + sage: I._pop_search() + sage: I._j + -1 + sage: I._search_ranges + [] + sage: I._current_sum + 0 + sage: I._current_list + [] + """ + if self._j >= 0: # TODO: get rid of this condition + self._j -= 1 + self._search_ranges.pop() + self._current_sum -= self._current_list[-1] + self._current_list.pop() + + def next(self): + r""" + Return the next element in the iteration. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.invlex import IntegerListsLexIter + sage: C = IntegerListsLex(2, length=3) + sage: I = IntegerListsLexIter(C) + sage: next(I) + [2, 0, 0] + sage: next(I) + [1, 1, 0] + """ + p = self.backend + min_sum = p.min_sum + max_length = p.max_length + search_ranges = self._search_ranges + + while True: + assert self._j == len(self._current_list) - 1 + assert self._j == len(self._search_ranges) - 1 + + # LOOK AHEAD + if self._next_state == LOOKAHEAD: + if self._lookahead(): + self._next_state = PUSH + else: + # We should reuse information about the + # reasons for this failure, to avoid when + # possible retrying with smaller values. + # We just do a special case for now: + if self._j + 1 == max_length and self._current_sum < min_sum: + self._next_state = POP + else: + self._next_state = DECREASE + + # PUSH + if self._next_state == PUSH: + if self._push_search(): + self._next_state = LOOKAHEAD + continue + self._next_state = ME + + # ME + if self._next_state == ME: + if self._j == -1: + self._next_state = STOP + else: + self._next_state = DECREASE + if self._internal_list_valid(): + return self._current_list + + # DECREASE + if self._next_state == DECREASE: + self._current_list[-1] -= 1 + self._current_sum -= 1 + if self._current_list[-1] >= search_ranges[self._j][0]: + self._next_state = LOOKAHEAD + continue + self._next_state = POP + + # POP + if self._next_state == POP: + self._pop_search() + self._next_state = ME + continue + + # STOP + if self._next_state == STOP: + raise StopIteration() + + assert False + + def _internal_list_valid(self): + """ + Return whether the current list in the iteration variable ``self._current_list`` is a valid list. + + This method checks whether the sum of the parts in ``self._current_list`` + is in the right range, whether its length is in the + required range, and whether there are trailing zeroes. It does not check all of the + necessary conditions to verify that an arbitrary list satisfies the + constraints from the corresponding ``IntegerListsLex`` object, and should + not be used except internally in the iterator class. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.invlex import IntegerListsLexIter + sage: C = IntegerListsLex(2, length=3) + sage: I = IntegerListsLexIter(C) + sage: I._current_list + [] + sage: I._internal_list_valid() + False + sage: next(I) + [2, 0, 0] + sage: I._current_list + [2, 0, 0] + sage: I._internal_list_valid() + True + """ + p = self.backend + mu = self._current_list + nu = self._current_sum + l = self._j + 1 + good_sum = (nu >= p.min_sum and nu <= p.max_sum) + good_length = (l >= p.min_length and l <= p.max_length) + no_trailing_zeros = (l <= max(p.min_length,0) or mu[-1] != 0) + return good_sum and good_length and no_trailing_zeros + + def _m_interval(self, i, max_sum, prev=None): + r""" + Return coarse lower and upper bounds for the part ``m`` at position ``i``. + + INPUT: + + - ``i`` -- a nonnegative integer (position) + + - ``max_sum`` -- a nonnegative integer or ``+oo`` + + - ``prev`` -- a nonnegative integer or ``None`` + + Return coarse lower and upper bounds for the value ``m`` + of the part at position ``i`` so that there could exists + some list suffix `v_i,\ldots,v_k` of sum bounded by + ``max_sum`` and satisfying the floor and upper bound + constraints. If ``prev`` is specified, then the slope + conditions between ``v[i-1]=prev`` and ``v[i]=m`` should + also be satisfied. + + Additionally, this raises an error if it can be detected + that some part is neither directly nor indirectly bounded + above, which implies that the constraints possibly do not allow for + an inverse lexicographic iterator. + + OUTPUT: + + A tuple of two integers ``(lower_bound, upper_bound)``. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.invlex import IntegerListsLexIter + sage: C = IntegerListsLex(2, length=3) + sage: I = IntegerListsLexIter(C) + sage: I._m_interval(1,2) + (0, 2) + + The second part is not bounded above, hence we can not + iterate lexicographically through all the elements:: + + sage: IntegerListsLex(ceiling=[2,infinity,3], max_length=3).first() + Traceback (most recent call last): + ... + ValueError: infinite upper bound for values of m + + Same here:: + + sage: IntegerListsLex(ceiling=[2,infinity,2], max_length=3, min_slope=-1).cardinality() + Traceback (most recent call last): + ... + ValueError: infinite upper bound for values of m + + In the following examples however, all parts are + indirectly bounded above:: + + sage: IntegerListsLex(ceiling=[2,infinity,2], length=3, min_slope=-1).cardinality() + 24 + sage: IntegerListsLex(ceiling=[2,infinity,2], max_length=3, max_slope=1).cardinality() + 24 + + sage: IntegerListsLex(max_part=2, max_length=3).cardinality() + 27 + sage: IntegerListsLex(3, max_length=3).cardinality() # parts bounded by n + 10 + sage: IntegerListsLex(max_length=0, min_length=1).list() # no part! + [] + sage: IntegerListsLex(length=0).list() # no part! + [[]] + """ + p = self.backend + + lower_bound = max(0, p.floor(i)) + upper_bound = min(max_sum, p.ceiling(i)) + if prev != None: + lower_bound = max(lower_bound, prev + p.min_slope) + upper_bound = min(upper_bound, prev + p.max_slope) + + ## check for infinite upper bound, in case max_sum is infinite + if p.check and upper_bound == Infinity: + # This assumes that there exists a valid list (which + # is not yet always guaranteed). Then we just + # discovered that part 'i' of this list can be made as + # large as desired, which implies that `self.backend` + # cannot be iterated in inverse lexicographic order + raise ValueError("infinite upper bound for values of m") + + return (lower_bound, upper_bound) + + def _lookahead(self): + r""" + Return whether the current list can possibly be a prefix of a valid list. + + OUTPUT: ``False`` if it is guaranteed that the current + list cannot be a prefix of a valid list and ``True`` + otherwise. + + EXAMPLES:: + + sage: it = IntegerListsLex(length=3, min_sum=2, max_sum=2)._iter() + sage: it._current_list = [0,1] # don't do this at home, kids + sage: it._current_sum = 1 + sage: it._j = 1 + sage: it._lookahead() + True + + sage: it = IntegerListsLex(length=3, min_sum=3, max_sum=2)._iter() + sage: it._current_list = [0,1] + sage: it._current_sum = 1 + sage: it._j = 1 + sage: it._lookahead() + False + + sage: it = IntegerListsLex(min_length=2, max_part=0)._iter() + sage: it._current_list = [0] + sage: it._current_sum = 0 + sage: it._j = 0 + sage: it._lookahead() + True + sage: it._current_list = [0, 0] + sage: it._j = 1 + sage: it._lookahead() + True + sage: it._current_list = [0, 0, 0] + sage: it._j = 2 + sage: it._lookahead() + False + + sage: n = 10**100 + sage: it = IntegerListsLex(n, length=1)._iter() + sage: it._current_list = [n-1] + sage: it._current_sum = n-1 + sage: it._j = 0 + sage: it._lookahead() + False + + sage: it = IntegerListsLex(n=3, min_part=2, min_sum=3, max_sum=3)._iter() + sage: it._current_list = [2] + sage: it._current_sum = 2 + sage: it._j = 0 + sage: it._lookahead() + False + + ALGORITHM: + + Let ``j=self._j`` be the position of the last part `m` of + ``self._current_list``. The current algorithm computes, + for `k=j,j+1,\ldots`, a lower bound `l_k` and an upper + bound `u_k` for `v_0+\dots+v_k`, and stops if none of the + invervals `[l_k, u_k]` intersect ``[min_sum, max_sum]``. + + The lower bound `l_k` is given by the area below + `v_0,\dots,v_{j-1}` prolongated by the lower envelope + between `j` and `k` and starting at `m`. The upper bound + `u_k` is given similarly using the upper envelope. + + The complexity of this algorithm is bounded above by + ``O(max_length)``. When ``max_length=oo``, the algorithm + is guaranteed to terminate, unless ``floor`` is a function + which is eventually constant with value `0`, or which + reaches the value `0` while ``max_slope=0``. + + Indeed, the lower bound `l_k` is increasing with `k`; in + fact it is strictly increasing, unless the local lower bound + at `k` is `0`. Furthermore as soon as ``l_k >= min_sum``, + we can conclude; we can also conclude if we know that the + floor is eventually constant with value `0`, or there is a + local lower bound at `k` is `0` and ``max_slope=0``. + + .. RUBRIC:: Room for improvement + + Improved prediction: the lower bound `l_k` does not take + the slope conditions into account, except for those imposed + by the value `m` at `j`. Similarly for `u_k`. + + Improved speed: given that `l_k` is increasing with `k`, + possibly some dichotomy could be used to search for `k`, + with appropriate caching / fast calculation of the partial + sums. Also, some of the information gained at depth `j` + could be reused at depth `j+1`. + + TESTS:: + + sage: it = IntegerListsLex(1, min_length=2, min_slope=0, max_slope=0, min_sum=1, max_sum=1)._iter() + sage: it._current_list = [0] + sage: it._current_sum = 0 + sage: it._j = 0 + sage: it._lookahead() + False + """ + # Check code for various termination conditions. Possible cases: + # 0. interval [lower, upper] intersects interval [min_sum, max_sum] -- terminate True + # 1. lower sum surpasses max_sum -- terminate False + # 2. iteration surpasses max_length -- terminate False + # 3. upper envelope is smaller than lower envelope -- terminate False + # 4. max_slope <= 0 -- terminate False after upper passes 0 + # 5. ceiling_limit == 0 -- terminate False after reaching larger limit point + # 6. (uncomputable) ceiling function == 0 for all but finitely many input values -- terminate False after reaching (unknown) limit point -- currently hangs + + m = self._current_list[-1] + j = self._j + min_sum = self.backend.min_sum - (self._current_sum-m) + max_sum = self.backend.max_sum - (self._current_sum-m) + + if min_sum > max_sum: + return False + + p = self.backend + + # Beware that without slope conditions, the functions below + # currently forget about the value m at k! + lower_envelope = self.backend.floor.adapt(m,j) + upper_envelope = self.backend.ceiling.adapt(m,j) + lower = 0 # The lower bound `l_k` + upper = 0 # The upper bound `u_k` + + assert j >= 0 + # get to smallest valid number of parts + for k in range(j, p.min_length-1): + # We are looking at lists `v_j,...,v_k` + lo = m if k == j else lower_envelope(k) + up = m if k == j else upper_envelope(k) + if lo > up: + return False + lower += lo + upper += up + + if j < p.min_length and min_sum <= upper and lower <= max_sum: + # There could exist a valid list `v_j,\dots,v_{min_length-1}` + return True + + k = max(p.min_length-1,j) + # Check if any of the intervals intersect the target interval + while k < p.max_length: + lo = m if k == j else lower_envelope(k) + up = m if k == j else upper_envelope(k) + if lo > up: + # There exists no valid list of length >= k + return False + lower += lo + upper += up + assert lower <= upper + + if lower > max_sum: + # There cannot exist a valid list `v_j,\dots,v_l` with l>=k + return False + + if (p.max_slope <= 0 and up <= 0) or \ + (p.ceiling.limit() == 0 and k > p.ceiling.limit_start()): + # This implies v_l=0 for l>=k: that is we would be generating + # a list with trailing zeroes + return False + + if min_sum <= upper and lower <= max_sum: + # There could exist a valid list `v_j,\dots,v_k` + return True + + k += 1 + + return False diff --git a/src/sage/combinat/integer_lists/lists.py b/src/sage/combinat/integer_lists/lists.py new file mode 100644 index 00000000000..2b2be62baa0 --- /dev/null +++ b/src/sage/combinat/integer_lists/lists.py @@ -0,0 +1,282 @@ +r""" +Enumerated set of lists of integers with constraints: front-end + +- :class:`IntegerLists`: class which models an enumerated set of lists + of integers with certain constraints. This is a Python front-end + where all user-accessible functionality should be implemented. +""" + +#***************************************************************************** +# Copyright (C) 2015 Bryan Gillespie +# Nicolas M. Thiery +# Anne Schilling +# Jeroen Demeyer +# +# 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 inspect import ismethod +from sage.categories.enumerated_sets import EnumeratedSets +from sage.structure.list_clone import ClonableArray +from sage.structure.parent import Parent +from sage.combinat.integer_lists.base import IntegerListsBackend + + +class IntegerList(ClonableArray): + """ + Element class for :class:`IntegerLists`. + """ + def check(self): + """ + Check to make sure this is a valid element in its + :class:`IntegerLists` parent. + + EXAMPLES:: + + sage: C = IntegerListsLex(4) + sage: C([4]).check() + True + sage: C([5]).check() + False + """ + return self.parent().__contains__(self) + + +class IntegerLists(Parent): + """ + Enumerated set of lists of integers with constraints. + + Currently, this is simply an abstract base class which should not + be used by itself. See :class:`IntegerListsLex` for a class which + can be used by end users. + + ``IntegerLists`` is just a Python front-end, acting as a + :class:`Parent`, supporting element classes and so on. + The attribute ``.backend`` which is an instance of + :class:`sage.combinat.integer_lists.base.IntegerListsBackend` is the + Cython back-end which implements all operations such as iteration. + + The front-end (i.e. this class) and the back-end are supposed to be + orthogonal: there is no imposed correspondence between front-ends + and back-ends. + + For example, the set of partitions of 5 and the set of weakly + decreasing sequences which sum to 5 might be implemented by the + same back-end, but they will be presented to the user by a + different front-end. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists import IntegerLists + sage: L = IntegerLists(5) + sage: L + Integer lists of sum 5 satisfying certain constraints + + sage: IntegerListsLex(2, length=3, name="A given name") + A given name + """ + backend = None + backend_class = IntegerListsBackend + + Element = IntegerList + + def __init__(self, *args, **kwds): + """ + Initialize ``self``. + + TESTS:: + + sage: from sage.combinat.integer_lists import IntegerLists + sage: C = IntegerLists(2, length=3) + sage: C == loads(dumps(C)) + True + """ + if "name" in kwds: + self.rename(kwds.pop("name")) + + if "global_options" in kwds: + self.global_options = kwds.pop("global_options") + + if "element_class" in kwds: + self.Element = kwds.pop("element_class") + + if "element_constructor" in kwds: + element_constructor = kwds.pop("element_constructor") + elif issubclass(self.Element, ClonableArray): + # Not all element classes support check=False + element_constructor = self._element_constructor_nocheck + else: + element_constructor = None # Parent's default + + category = kwds.pop("category", None) + if category is None: + category = EnumeratedSets().Finite() + + # Let self.backend be some IntegerListsBackend + self.backend = self.backend_class(*args, **kwds) + + Parent.__init__(self, element_constructor=element_constructor, + category=category) + + def __eq__(self, other): + r""" + Return whether ``self == other``. + + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3) + sage: D = IntegerListsLex(2, length=3); L = D.list(); + sage: E = IntegerListsLex(2, min_length=3) + sage: F = IntegerListsLex(2, length=3, element_constructor=list) + sage: G = IntegerListsLex(4, length=3) + sage: C == C + True + sage: C == D + True + sage: C == E + False + sage: C == F + False + sage: C == None + False + sage: C == G + False + + This is a minimal implementation enabling pickling tests. It + is safe, but one would want the two following objects to be + detected as equal:: + + sage: C = IntegerListsLex(2, ceiling=[1,1,1]) + sage: D = IntegerListsLex(2, ceiling=[1,1,1]) + sage: C == D + False + + TESTS: + + This used to fail due to poor equality testing. See + :trac:`17979`, comment 433:: + + sage: DisjointUnionEnumeratedSets(Family([2,2], + ....: lambda n: IntegerListsLex(n, length=2))).list() + [[2, 0], [1, 1], [0, 2], [2, 0], [1, 1], [0, 2]] + sage: DisjointUnionEnumeratedSets(Family([2,2], + ....: lambda n: IntegerListsLex(n, length=1))).list() + [[2], [2]] + """ + if self.__class__ != other.__class__: + return False + if self.backend != other.backend: + return False + a = self._element_constructor + b = other._element_constructor + if ismethod(a): + a = a.im_func + if ismethod(b): + b = b.im_func + return a == b + + def __ne__(self, other): + r""" + Return whether ``self != other``. + + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3) + sage: D = IntegerListsLex(2, length=3); L = D.list(); + sage: E = IntegerListsLex(2, max_length=3) + sage: C != D + False + sage: C != E + True + """ + return not self == other + + def __iter__(self): + """ + Return an iterator for the elements of ``self``. + + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3) + sage: list(C) # indirect doctest + [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] + """ + return self._element_iter(self.backend._iter(), self._element_constructor) + + @staticmethod + def _element_iter(iter, constructor): + """ + Given an iterator ``iter`` and an element constructor + ``constructor``, iterate over ``constructor(v)`` where `v` + are the values of ``iter``. + + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3) + sage: list(C._element_iter(C._iter(), tuple)) + [(2, 0, 0), (1, 1, 0), (1, 0, 1), (0, 2, 0), (0, 1, 1), (0, 0, 2)] + """ + for v in iter: + yield constructor(v) + + def __getattr__(self, name): + """ + Get an attribute of the implementation backend. + + Ideally, this would be done using multiple inheritance, but + Python doesn't support that for built-in types. + + TESTS: + + Check that uninitialized instances do not lead to infinite + recursion because there is no ``backend`` attribute:: + + sage: from sage.combinat.integer_lists import IntegerLists + sage: L = IntegerLists.__new__(IntegerLists) + sage: L.foo + Traceback (most recent call last): + ... + AttributeError: 'NoneType' object has no attribute 'foo' + """ + return getattr(self.backend, name) + + def __contains__(self, item): + """ + Return ``True`` if ``item`` meets the constraints imposed by + the arguments. + + EXAMPLES:: + + sage: C = IntegerListsLex(n=2, max_length=3, min_slope=0) + sage: all([l in C for l in C]) + True + """ + return self.backend._contains(item) + + def _element_constructor_nocheck(self, l): + r""" + A variant of the standard element constructor that passes + ``check=False`` to the element class. + + EXAMPLES:: + + sage: L = IntegerListsLex(4, max_slope=0) + sage: L._element_constructor_nocheck([1,2,3]) + [1, 2, 3] + + When relevant, this is assigned to + ``self._element_constructor`` by :meth:`__init__`, to avoid + overhead when constructing elements from trusted data in the + iterator:: + + sage: L._element_constructor + + sage: L._element_constructor([1,2,3]) + [1, 2, 3] + """ + return self.element_class(self, l, check=False) diff --git a/src/sage/combinat/integer_lists/nn.py b/src/sage/combinat/integer_lists/nn.py new file mode 100644 index 00000000000..24c7e9458fc --- /dev/null +++ b/src/sage/combinat/integer_lists/nn.py @@ -0,0 +1,43 @@ +from sage.sets.family import Family +from sage.combinat.integer_lists import IntegerListsLex +from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets + +def IntegerListsNN(**kwds): + """ + Lists of nonnegative integers with constraints. + + This function returns the union of ``IntegerListsLex(n, **kwds)`` + where `n` ranges over all nonnegative integers. + + EXAMPLES:: + + sage: from sage.combinat.integer_lists.nn import IntegerListsNN + sage: L = IntegerListsNN(max_length=3, max_slope=-1) + sage: L + Disjoint union of Lazy family ((i))_{i in Non negative integer semiring} + sage: it = iter(L) + sage: for _ in range(20): + ....: print next(it) + [] + [1] + [2] + [3] + [2, 1] + [4] + [3, 1] + [5] + [4, 1] + [3, 2] + [6] + [5, 1] + [4, 2] + [3, 2, 1] + [7] + [6, 1] + [5, 2] + [4, 3] + [4, 2, 1] + [8] + """ + return DisjointUnionEnumeratedSets(Family(NN, lambda i: IntegerListsLex(i, **kwds))) diff --git a/src/sage/combinat/integer_matrices.py b/src/sage/combinat/integer_matrices.py index 15bf04d4964..0983acbf1f4 100644 --- a/src/sage/combinat/integer_matrices.py +++ b/src/sage/combinat/integer_matrices.py @@ -18,7 +18,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.combinat.integer_list import IntegerListsLex +from sage.combinat.integer_lists import IntegerListsLex from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index b11ce3136da..d068828f1df 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -36,7 +36,7 @@ from sage.rings.infinity import PlusInfinity import cartesian_product import functools -from sage.combinat.integer_list import IntegerListsLex +from sage.combinat.integer_lists import IntegerListsLex def is_gale_ryser(r,s): @@ -923,34 +923,30 @@ def __init__(self, n, k, constraints, category=None): sage: type(v) - TESTS: - - All the attributes below are private; don't use them! - - :: + TESTS:: - sage: IV._min_length + sage: IV.min_length 3 - sage: IV._max_length + sage: IV.max_length 3 - sage: floor = IV._floor + sage: floor = IV.floor sage: [floor(i) for i in range(1,10)] [0, 0, 0, 0, 0, 0, 0, 0, 0] - sage: ceiling = IV._ceiling + sage: ceiling = IV.ceiling sage: [ceiling(i) for i in range(1,5)] [inf, inf, inf, inf] - sage: IV._min_slope + sage: IV.min_slope 0 - sage: IV._max_slope + sage: IV.max_slope inf sage: IV = IntegerVectors(3, 10, inner=[4,1,3], min_part=2) - sage: floor = IV._floor + sage: floor = IV.floor sage: floor(0), floor(1), floor(2) (4, 2, 3) sage: IV = IntegerVectors(3, 10, outer=[4,1,3], max_part=3) - sage: ceiling = IV._ceiling + sage: ceiling = IV.ceiling sage: ceiling(0), ceiling(1), ceiling(2) (3, 1, 3) """ @@ -1072,7 +1068,7 @@ def next(self, x): [0, 0, 2] """ from sage.combinat.integer_list_old import next - return next(x, self._min_length, self._max_length, self._floor, self._ceiling, self._min_slope, self._max_slope) + return next(x, self.min_length, self.max_length, self.floor, self.ceiling, self.min_slope, self.max_slope) class IntegerVectors_nconstraints(IntegerVectors_nkconstraints): def __init__(self, n, constraints): diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 144751c12df..ddbbd9dab64 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -311,7 +311,7 @@ from sage.combinat.partitions import number_of_partitions as bober_number_of_partitions from sage.combinat.partitions import ZS1_iterator, ZS1_iterator_nk from sage.combinat.integer_vector import IntegerVectors -from sage.combinat.integer_list import IntegerListsLex +from sage.combinat.integer_lists import IntegerListsLex from sage.combinat.root_system.weyl_group import WeylGroup from sage.combinat.combinatorial_map import combinatorial_map from sage.groups.perm_gps.permgroup import PermutationGroup diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index fa5aa22cf5b..6bd5e26b24a 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -1377,11 +1377,10 @@ def iter_morphisms(self, arg=None, codomain=None, min_length=1): # create an iterable of compositions (all "compositions" if arg is # None, or [arg] otherwise) if arg is None: - # TODO in #17927: use IntegerVectors(length=n, min_part=min_length) - from sage.combinat.integer_list import IntegerListsNN + from sage.combinat.integer_lists.nn import IntegerListsNN compositions = IntegerListsNN(length=n, min_part=min_length) elif isinstance(arg, tuple): - from sage.combinat.integer_list import IntegerListsLex + from sage.combinat.integer_lists import IntegerListsLex a, b = arg compositions = IntegerListsLex(min_sum=a, max_sum=b-1, length=n, min_part=min_length) From 3ebbb659f034dd17610a6afba03d307ffc7b483e Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 27 Aug 2015 13:01:09 +0200 Subject: [PATCH 0600/1872] Workaround for Trac #18192 --- src/sage/combinat/integer_lists/base.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/integer_lists/base.pyx b/src/sage/combinat/integer_lists/base.pyx index d8ea14382c1..fe146b0d175 100644 --- a/src/sage/combinat/integer_lists/base.pyx +++ b/src/sage/combinat/integer_lists/base.pyx @@ -28,6 +28,7 @@ from sage.structure.element cimport RingElement from sage.rings.integer cimport Integer Infinity = float('+inf') +MInfinity = float('-inf') cdef class IntegerListsBackend(object): @@ -51,7 +52,7 @@ cdef class IntegerListsBackend(object): min_length=0, max_length=Infinity, floor=None, ceiling=None, min_part=0, max_part=Infinity, - min_slope=-Infinity, max_slope=Infinity, + min_slope=MInfinity, max_slope=Infinity, min_sum=0, max_sum=Infinity): """ Initialize ``self``. @@ -375,7 +376,7 @@ cdef class Envelope(object): """ def __init__(self, f, *, min_part=0, max_part=Infinity, - min_slope=-Infinity, max_slope=Infinity, + min_slope=MInfinity, max_slope=Infinity, min_length=0, max_length=Infinity, sign=1): r""" Initialize this envelope. From 88a100a762bad34400aca66c52d22255737072a7 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 27 Aug 2015 14:49:21 +0200 Subject: [PATCH 0601/1872] Fix one more import of IntegerListsLex --- src/sage/algebras/schur_algebra.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 7ef9cfabbde..0f4519422fa 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -21,20 +21,23 @@ .. [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) +# Copyright (C) 2010 Eric Webster +# Copyright (C) 2011 Hugh Thomas # -# Distributed under the terms of the GNU General Public License (GPL) +# 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.categories.all import AlgebrasWithBasis from sage.categories.rings import Rings 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.integer_lists import IntegerListsLex from sage.combinat.partition import Partitions, Partition from sage.combinat.permutation import Permutations from sage.combinat.sf.sf import SymmetricFunctions From 14e30cc0ece3af07142326dd1a79d19e92c5dde6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:11:26 +0200 Subject: [PATCH 0602/1872] derive MutablePoset from object (instead of SageObject) --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 52d886757e7..62e82c96439 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -160,7 +160,7 @@ # ***************************************************************************** -class MutablePosetShell(sage.structure.sage_object.SageObject): +class MutablePosetShell(object): r""" A shell for an element of a :class:`mutable poset `. @@ -1125,7 +1125,7 @@ def is_MutablePoset(P): return isinstance(P, MutablePoset) -class MutablePoset(sage.structure.sage_object.SageObject): +class MutablePoset(object): r""" A mutable poset (partially ordered set) as data structure. From 9391c7820ec4801fcb54bf4be4db7501b4d1cd69 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:11:26 +0200 Subject: [PATCH 0603/1872] derive MutablePoset from object (instead of SageObject) --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 52d886757e7..62e82c96439 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -160,7 +160,7 @@ # ***************************************************************************** -class MutablePosetShell(sage.structure.sage_object.SageObject): +class MutablePosetShell(object): r""" A shell for an element of a :class:`mutable poset `. @@ -1125,7 +1125,7 @@ def is_MutablePoset(P): return isinstance(P, MutablePoset) -class MutablePoset(sage.structure.sage_object.SageObject): +class MutablePoset(object): r""" A mutable poset (partially ordered set) as data structure. From 4fe491905dd6871dd8414272e872d0d443f6811d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:11:48 +0200 Subject: [PATCH 0604/1872] remove forgotten line --- src/sage/rings/asymptotic/growth_group.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ef279e9fe31..cb1349ca863 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2075,7 +2075,6 @@ def __invert__(self): sage: e2 == ~e1 True """ - return self.parent()(raw_element=-self.exponent) new_element = -self.exponent try: return self.parent()(raw_element=new_element) From 307d6149dd4391d1ac694f5ed71318f5802c4933 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:13:18 +0200 Subject: [PATCH 0605/1872] extend factory to accept instances of terms as well --- src/sage/rings/asymptotic/term_monoid.py | 49 ++++++++++++++++-------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 044d60c4106..8a220250b2d 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2453,13 +2453,16 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): INPUT: - - ``term`` -- the kind of term that shall be created. Either - ``'exact'`` or ``'O'``. + - ``term`` -- the kind of term that shall be created. Either a string + ``'exact'`` or ``'O'``, or an existing instance of a term. - ``growth_group`` -- a growth group. - ``coefficient_ring`` -- a ring. + - ``asymptotic_ring`` -- if specified, then ``growth_group`` and + ``coefficient_ring`` are taken from this asymptotic ring. + OUTPUT: An asymptotic term monoid. @@ -2474,7 +2477,9 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: ET = atm.TermMonoid('exact', G, ZZ); ET Exact Term Monoid x^ZZ with coefficients in Integer Ring """ - def create_key_and_extra_args(self, term, growth_group, coefficient_ring=None, + def create_key_and_extra_args(self, term, + growth_group=None, coefficient_ring=None, + asymptotic_ring=None, **kwds): r""" Given the arguments and keyword, create a key that uniquely @@ -2486,17 +2491,36 @@ def create_key_and_extra_args(self, term, growth_group, coefficient_ring=None, sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: atm.TermMonoid.create_key_and_extra_args('O', G, QQ) - (('O', Growth Group x^ZZ, Rational Field), {}) + ((, + Growth Group x^ZZ, Rational Field), {}) sage: atm.TermMonoid.create_key_and_extra_args('exact', G, ZZ) - (('exact', Growth Group x^ZZ, Integer Ring), {}) + ((, + Growth Group x^ZZ, Integer Ring), {}) sage: atm.TermMonoid.create_key_and_extra_args('exact', G) Traceback (most recent call last): ... ValueError: A coefficient ring has to be specified to create a term monoid of type 'exact' """ - if term not in ['O', 'exact']: - raise ValueError("%s has to be either 'exact' or 'O'" % term) + if isinstance(term, GenericTermMonoid): + term_class = term.__class__ + elif term == 'O': + term_class = OTermMonoid + elif term == 'exact': + term_class = ExactTermMonoid + else: + raise ValueError("Term specification '%s' has to be either 'exact' or 'O' " + "or an instance of an existing term." % term) + + if asymptotic_ring is not None and \ + (growth_group is not None or coefficient_ring is not None): + raise ValueError("Input ambiguous: asymptotic ring %s as well as " + "growth group %s or coefficient ring %s are given." % + (asymptotic_ring, growth_group, coefficient_ring)) + + if asymptotic_ring is not None: + growth_group = asymptotic_ring.growth_group + coefficient_ring = asymptotic_ring.coefficient_ring from sage.rings.asymptotic.growth_group import GenericGrowthGroup if not isinstance(growth_group, GenericGrowthGroup): @@ -2507,7 +2531,7 @@ def create_key_and_extra_args(self, term, growth_group, coefficient_ring=None, raise ValueError("A coefficient ring has to be specified to " "create a term monoid of type '%s'" % (term,)) - return (term, growth_group, coefficient_ring), kwds + return (term_class, growth_group, coefficient_ring), kwds def create_object(self, version, key, **kwds): @@ -2524,13 +2548,8 @@ def create_object(self, version, key, **kwds): sage: atm.TermMonoid('exact', G, ZZ) # indirect doctest Exact Term Monoid x^ZZ with coefficients in Integer Ring """ - - term, growth_group, coefficient_ring = key - if term == 'O': - C = OTermMonoid - elif term == 'exact': - C = ExactTermMonoid - return C(growth_group, coefficient_ring, **kwds) + term_class, growth_group, coefficient_ring = key + return term_class(growth_group, coefficient_ring, **kwds) TermMonoid = TermMonoidFactory("TermMonoid") From 2803c4f787d407d611922aff4309ff85a39c1e36 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:13:27 +0200 Subject: [PATCH 0606/1872] small cleanup in code --- src/sage/rings/asymptotic/term_monoid.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 8a220250b2d..5f7446757c0 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -302,14 +302,12 @@ def __init__(self, parent, growth): sage: T(x^2) Generic Term with growth x^2 """ - from sage.rings.asymptotic.growth_group import GenericGrowthElement - if parent is None: raise ValueError('The parent must be provided') try: self.growth = parent.growth_group(growth) except ValueError, TypeError: - raise ValueError("%s is not in %s" % (growth, self.growth_group)) + raise ValueError("%s is not in %s" % (growth, parent.growth_group)) super(GenericTerm, self).__init__(parent=parent) From a4d22c1cc16e52996ae014f0b4089259c4494a19 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:14:02 +0200 Subject: [PATCH 0607/1872] introduce convert-flag on element constructor --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 27bbd655177..54df647a8b5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -425,7 +425,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): :mod:`sage.rings.asymptotic.term_monoid`, :mod:`sage.data_structures.mutable_poset`. """ - def __init__(self, parent, summands, simplify=True): + def __init__(self, parent, summands, simplify=True, convert=True): r""" See :class:`AsymptoticExpression` for more information. @@ -442,7 +442,21 @@ def __init__(self, parent, summands, simplify=True): """ super(AsymptoticExpression, self).__init__(parent=parent) + if convert: + from growth_group import combine_exceptions + from term_monoid import TermMonoid + summands = summands.copy() + for shell in summands.shells(): + element = shell._element_ + T = TermMonoid(term=element.parent(), asymptotic_ring=parent) + try: + shell._element_ = T(element) + except (ValueError, TypeError) as e: + raise combine_exceptions( + ValueError('Cannot include %s with parent %s in %s' % + (element, element.parent(), parent)), e) self._summands_ = summands + if simplify: self._simplify_() From 76037dd8646207c5be4f298c3eaa50f917b14e34 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:14:20 +0200 Subject: [PATCH 0608/1872] simplify _add_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 54df647a8b5..693ec0794e2 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -714,8 +714,7 @@ def _add_(self, other): sage: O(x) + x O(x) """ - smds = self.summands.copy().union(other.summands) - return self.parent()(summands=smds) + return self.parent()(self.summands.union(other.summands), convert=False) def _sub_(self, other): From 830585bc6f4569dd716886bff4624efa839813ca Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:14:40 +0200 Subject: [PATCH 0609/1872] change_parameter method --- src/sage/rings/asymptotic/asymptotic_ring.py | 40 ++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 693ec0794e2..3c988a10c46 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1276,6 +1276,46 @@ def default_prec(self): return self._default_prec_ + def change_parameter(self, **kwds): + r""" + Return an asymptotic ring with a change in one or more of the given parameters. + + INPUT: + + - ``growth_group`` -- (default: ``None``) the new growth group. + + - ``coefficient_ring`` -- (default: ``None``) the new coefficient ring. + + - ``category`` -- (default: ``None``) the new category. + + - ``default_prec`` -- (default: ``None``) the new default precision. + + OUTPUT: + + An asymptotic ring. + + EXAMPLES:: + + sage: A = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) + sage: A.change_parameter(coefficient_ring=QQ) + Asymptotic Ring over Rational Field + + TESTS:: + + sage: A.change_parameter(coefficient_ring=ZZ) is A + True + """ + parameters = ('growth_group', 'coefficient_ring', 'category', 'default_prec') + values = dict() + for parameter in parameters: + values[parameter] = kwds.get(parameter, getattr(self, parameter)) + values['category'] = values['category']() + if all(values[parameter] is getattr(self, parameter) + for parameter in parameters): + return self + return self.__class__(**values) + + @staticmethod def _create_empty_summands_(): r""" From 4115f613087a83be60abab94b92dd82a442d76ba Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:15:05 +0200 Subject: [PATCH 0610/1872] add a pushout-doctest --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 3c988a10c46..0a7951d5791 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1904,6 +1904,12 @@ class AsymptoticRingFunctor(ConstructionFunctor): sage: cm.common_parent(X, Y) Asymptotic Ring over Rational Field sage: sage.structure.element.coercion_traceback() # not tested + + :: + + sage: from sage.categories.pushout import pushout + sage: pushout(AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ), QQ) + Asymptotic Ring over Rational Field """ rank = 13 @@ -2052,4 +2058,3 @@ def __ne__(self, other): True """ return not self.__eq__(other) - From ad1ca3fa3bed24485c93eb008b01c1dcfcf413b4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:16:03 +0200 Subject: [PATCH 0611/1872] extend and simplify element_constructor and use convert-flag everywhere --- src/sage/rings/asymptotic/asymptotic_ring.py | 47 +++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0a7951d5791..3dc982cc13f 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1343,7 +1343,7 @@ def _create_empty_summands_(): merge=absorption) - def _element_constructor_(self, data, summands=None, simplify=True): + def _element_constructor_(self, data, simplify=True, convert=True): r""" Convert a given object to this asymptotic ring. @@ -1352,13 +1352,13 @@ def _element_constructor_(self, data, summands=None, simplify=True): - ``data`` -- an object representing the element to be initialized. - - ``summands`` -- (default: ``None``) if given, then this is - directly passed to the element constructor (i.e., no - conversion is performed). - - ``simplify`` -- (default: ``True``) if set, then the constructed element is simplified (terms are absorbed) automatically. + - ``convert`` -- (default: ``True``) passed on to the element + constructor. If set, then it is assured that the terms belong + to this asymptotic ring (by converting them if needed). + OUTPUT: An element of this asymptotic ring. @@ -1411,19 +1411,29 @@ def _element_constructor_(self, data, summands=None, simplify=True): sage: A. = AsymptoticRing('a^ZZ * b^ZZ', QQ) sage: 1/a a^(-1) + + :: + + sage: M = AsymptoticRing('m^ZZ', ZZ) + sage: N = AsymptoticRing('n^ZZ', QQ) + sage: N(M.an_element()) + Traceback (most recent call last): + ... + ValueError: Cannot include -m^3 with parent + Exact Term Monoid m^ZZ with coefficients in Integer Ring + in Asymptotic Ring over Rational Field + > *previous* ValueError: m^3 is not in Growth Group n^ZZ """ - if summands is not None: - if type(data) != int or data != 0: - raise ValueError('Input is ambigous: ' - '%s as well as summands=%s ' - 'are specified.' % (data, summands)) - return self.element_class(self, summands, simplify=simplify) + from sage.data_structures.mutable_poset import MutablePoset + if isinstance(data, MutablePoset): + return self.element_class(self, data, simplify=simplify, convert=convert) if type(data) == self.element_class and data.parent() == self: return data if isinstance(data, AsymptoticExpression): - return self.element_class(self, data.summands, simplify=simplify) + return self.element_class(self, data.summands, + simplify=simplify, convert=convert) from sage.rings.asymptotic.term_monoid import GenericTerm if isinstance(data, GenericTerm): @@ -1436,11 +1446,13 @@ def _element_constructor_(self, data, summands=None, simplify=True): 'asymptotic expression in %s.' % (data, self)) summands = AsymptoticRing._create_empty_summands_() summands.union_update(data) - return self.element_class(self, summands, simplify=simplify) + return self.element_class(self, summands, + simplify=simplify, convert=convert) if not data or data == 0: summands = AsymptoticRing._create_empty_summands_() - return self.element_class(self, summands, simplify=simplify) + return self.element_class(self, summands, + simplify=simplify, convert=convert) try: P = data.parent() @@ -1646,7 +1658,8 @@ def _an_element_(self): from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) - return -self(E.an_element())**3 + self(O.an_element()) + return -self(E.an_element(), convert=False)**3 + \ + self(O.an_element(), convert=False) def some_elements(self): @@ -1683,7 +1696,7 @@ def some_elements(self): from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) - return iter(-self(e)**3 + self(o) + return iter(-self(e, convert=False)**3 + self(o, convert=False) for e, o in product_diagonal( E.some_elements(), O.some_elements())) @@ -1822,7 +1835,7 @@ def create_summand(self, type, data=None, **kwds): if type == 'exact' and kwds.get('coefficient') == 0: return self(kwds['coefficient']) - return self(TM(data, **kwds)) + return self(TM(data, **kwds), convert=False) def variable_names(self): From e05a7fba92e90ad3eca48157733373cbdb47b98f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:16:32 +0200 Subject: [PATCH 0612/1872] categories and __classcall__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 3dc982cc13f..5cfd89daa4d 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1170,6 +1170,10 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, from sage.misc.defaults import series_precision default_prec = series_precision() + from sage.categories.rings import Rings + if category is None: + category = Rings() & sage.categories.posets.Posets() + return super(AsymptoticRing, cls).__classcall__(cls, growth_group, coefficient_ring, category=category, @@ -1207,14 +1211,11 @@ def __init__(self, growth_group, coefficient_ring, category=None, elif coefficient_ring not in Rings(): raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) - if category is None: - category = Rings() & sage.categories.posets.Posets() - else: - if not isinstance(category, tuple): - category = (category,) - if not any(cat.is_subcategory(Rings()) for cat in category): - raise ValueError('%s is not a subcategory of %s' % (category, - Rings())) + if not isinstance(category, tuple): + category = (category,) + if not any(cat.is_subcategory(Rings()) for cat in category): + raise ValueError('%s is not a subcategory of %s' % (category, + Rings())) self._coefficient_ring_ = coefficient_ring self._growth_group_ = growth_group From 38075d0c487872a915e6b17f3d5e5fa38446a57c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:17:15 +0200 Subject: [PATCH 0613/1872] __invert__: take care of changing parent --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 5cfd89daa4d..3e85d4fb658 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -852,7 +852,7 @@ def __invert__(self): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ', QQ, default_prec=4) + sage: R. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ, default_prec=4) sage: ~x x^(-1) sage: ~(x^42) @@ -863,12 +863,24 @@ def __invert__(self): 1 + O(x^(-4)) sage: ~(1 + O(1/x)) 1 + O(x^(-1)) + + TESTS:: + + sage: A. = AsymptoticRing(growth_group='a^ZZ', coefficient_ring=ZZ) + sage: (1 / a).parent() """ if len(self.summands) == 0: raise ZeroDivisionError('Division by zero in %s.' % (self,)) elif len(self.summands) == 1: - return self.parent()(~next(self.summands.elements())) + new_element = ~next(self.summands.elements()) + try: + return self.parent()(new_element) + except (ValueError, TypeError): + new_parent = self.parent().change_parameter( + growth_group=new_element.parent().growth_group, + coefficient_ring=new_element.parent().coefficient_ring) + return new_parent(new_element) max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: From 6d1f0c3cd5b7126f67547559d866502cab293587 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:17:38 +0200 Subject: [PATCH 0614/1872] small changes in multiplication code --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 3e85d4fb658..e60624080f3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -770,7 +770,8 @@ def _mul_term_(self, term): sage: expr._mul_term_(t) O(x^3) """ - return self.parent()([term * elem for elem in self.summands.elements()]) + return self.parent()([term * elem for elem in self.summands.elements()], + convert=False) def _mul_(self, other): @@ -801,8 +802,9 @@ def _mul_(self, other): of the underlying poset shall be implemented at a later point. """ - return self.parent()(sum(self._mul_term_(term_other) for - term_other in other.summands.elements())) + return sum(self._mul_term_(term_other) for + term_other in other.summands.elements()) + def _div_(self, other): From 66948e23c73232f947c82f180c1ffee0c5c4cb5e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:17:49 +0200 Subject: [PATCH 0615/1872] rmul, lmul --- src/sage/rings/asymptotic/asymptotic_ring.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index e60624080f3..406c840cbb6 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -806,6 +806,15 @@ def _mul_(self, other): term_other in other.summands.elements()) + def _rmul_(self, other): + from sage.rings.asymptotic.term_monoid import TermMonoid + E = TermMonoid('exact', asymptotic_ring=self.parent()) + e = E(self.parent().growth_group.one(), coefficient=other) + return self._mul_term_(e) + + + _lmul_ = _rmul_ + def _div_(self, other): r""" From f48f64ab2b7a4e513c25e30cd2ecc35b0e6b33a2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:18:01 +0200 Subject: [PATCH 0616/1872] doc --- src/sage/rings/asymptotic/asymptotic_ring.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 406c840cbb6..2cd83bef9bd 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -231,14 +231,24 @@ sage: C.an_element() -e^3*c^3 + O(c) sage: C.an_element() / 7 - -e^3/7*c^3 + O(c) + -1/7*e^3*c^3 + O(c) Here the result's coefficient ring is the newly found :: sage: (C.an_element() / 7).parent() Asymptotic Ring over - Univariate Polynomial Ring in e over Integer Ring + Univariate Polynomial Ring in e over Rational Field + +Not only the coefficient ring can be extended, but the growth group as +well. For example, we can add/multiply elements of the asymptotic +rings ``A`` and ``C`` to get an expression of new asymptotic ring:: + + sage: r = c*z + c/2 + O(z); r + c*z + 1/2*c + O(z) + sage: r.parent() + Asymptotic Ring over + Univariate Polynomial Ring in e over Rational Field Data Structures From aad4bf7aa4b5ac99cdd7f68f60e9f12a3a8a2654 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 17:18:34 +0200 Subject: [PATCH 0617/1872] convert NN in growth group factory doctest --- src/sage/rings/asymptotic/growth_group.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cb1349ca863..68d2cf8d679 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -222,6 +222,8 @@ def repr_short_to_parent(s): Rational Field sage: agg.repr_short_to_parent('SR') Symbolic Ring + sage: agg.repr_short_to_parent('NN') + Non negative integer semiring TESTS:: From c51c4a6cd70c1b0de3d51924afb711a84d41c1fc Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 27 Aug 2015 18:26:16 +0200 Subject: [PATCH 0618/1872] term monoid: warning in module description adapted --- src/sage/rings/asymptotic/term_monoid.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 5f8fc7ac6bd..3a105e76a55 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -52,14 +52,13 @@ TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, TermMonoid) + sage: G = GrowthGroup('x^ZZ * log(x)^ZZ') 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/17601 for details. - sage: T = atm.GenericTermMonoid(G, ZZ) """ # ***************************************************************************** From ad98c39d026a6767b158d879c04e9075092af4d2 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 27 Aug 2015 18:26:44 +0200 Subject: [PATCH 0619/1872] logarithm for terms (log_term) implemented --- src/sage/rings/asymptotic/term_monoid.py | 156 +++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 3a105e76a55..4c2a2df94c2 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -692,6 +692,58 @@ def _absorb_(self, other): raise NotImplementedError('Not implemented in abstract base classes') + def log_term(self, base=None): + r""" + Return the logarithm of this term. + + This method returns a list with the summands that come from + applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the logarithm is the natural + logarithm. + + OUTPUT: + + A list. + + .. NOTE:: + + This method is only implemented for :class:`ExactTerm` and + :class:`OTerm`. + + .. SEEALSO:: + + :meth:`ExactTerm.log_term`, + :meth:`OTerm.log_term`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: T = GenericTermMonoid(GrowthGroup('x^ZZ'), QQ) + sage: T.an_element().log_term() + Traceback (most recent call last): + ... + NotImplementedError: This method is only implemented for terms used + in AsymptoticExpression. + + :: + + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), QQ) + sage: T.an_element().log_term() + Traceback (most recent call last): + ... + NotImplementedError: This method is only implemented for terms used + in AsymptoticExpression. + """ + raise NotImplementedError('This method is only implemented for terms' + ' used in AsymptoticExpression.') + + def __le__(self, other): r""" Return whether the growth of this term is less than @@ -1589,6 +1641,54 @@ def _is_same_(self, other): return self.growth == other.growth + def log_term(self, base=None): + r""" + Return the logarithm of this term. + + This method returns a list with the summands that come from + applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the logarithm is the natural + logarithm. + + OUTPUT: + + A list. + + .. NOTE:: + + This method is only implemented for :class:`ExactTerm` and + :class:`OTerm`. + + .. SEEALSO:: + + :meth:`ExactTerm.log_term`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('O', GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) + sage: T(x^2).log_term() + [O(log(x))] + sage: T(x^1234).log_term() + [O(log(x))] + + :: + + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: T = TermMonoid('O', GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ'), QQ) + sage: T('x * y').log_term() + [O(log(x)), O(log(y))] + """ + growth_log = self.growth.log_factor(base=base) + P = self.parent() + return [P(factor[0]) for factor in growth_log] + + class OTermMonoid(GenericTermMonoid): r""" Parent for asymptotic big `O`-terms. @@ -2262,6 +2362,62 @@ def _absorb_(self, other): return self.parent()(self.growth, coeff_new) + def log_term(self, base=None): + r""" + Return the logarithm of this term. + + This method returns a list with the summands that come from + applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the logarithm is the natural + logarithm. + + OUTPUT: + + A list. + + .. NOTE:: + + This method is only implemented for :class:`ExactTerm` and + :class:`OTerm`. + + .. SEEALSO:: + + :meth:`OTerm.log_term`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('exact', GrowthGroup('x^ZZ * log(x)^ZZ'), SR) + sage: T(3*x^2).log_term() + [log(3), 2*log(x)] + sage: T(x^1234).log_term() + [1234*log(x)] + sage: T(49*x^7).log_term(base=7) + [log(49)/log(7), 7/log(7)*log(x)] + + :: + + sage: T = TermMonoid('exact', GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ'), SR) + sage: T('x * y').log_term() + [log(x), log(y)] + sage: T('4 * x * y').log_term(base=2) + [log(4)/log(2), 1/log(2)*log(x), 1/log(2)*log(y)] + """ + from sage.functions.log import log + growth_log = self.growth.log_factor(base=base) + P = self.parent() + lst = [P(factor[0], factor[1]) for factor in growth_log] + if self.coefficient != P.coefficient_ring.one(): + lst = [P(self.growth.parent().one(), + log(self.coefficient, base=base))] + lst + return lst + + class ExactTermMonoid(TermWithCoefficientMonoid): r""" Parent for asymptotic exact terms, implemented in From b2753ed5ee56987f222167dca4cea2ff814c0730 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 19:53:43 +0200 Subject: [PATCH 0620/1872] change _an_element_: remove - to avoid infinite loop in get_action --- src/sage/rings/asymptotic/asymptotic_ring.py | 31 ++++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 2cd83bef9bd..1b613b734d2 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -91,7 +91,7 @@ :: sage: A.an_element() - -z^(3/2) + O(z^(1/2)) + z^(3/2) + O(z^(1/2)) This element consists of two summands: the exact term with coefficient `-1` and growth `z^{3/2}` and the `O`-term `O(z^{1/2})`. Note that the @@ -110,7 +110,7 @@ Again, we can look at a typical (nontrivial) element:: sage: B.an_element() - -1/8*x^(3/2)*log(x)^3*(1/8)^y*y^(3/2) + O(x^(1/2)*log(x)*(1/2)^y*y^(1/2)) + 1/8*x^(3/2)*log(x)^3*(1/8)^y*y^(3/2) + O(x^(1/2)*log(x)*(1/2)^y*y^(1/2)) Arithemtical Operations @@ -229,9 +229,9 @@ sage: C. = AsymptoticRing(growth_group='c^ZZ', coefficient_ring=ZZ['e']) sage: C.an_element() - -e^3*c^3 + O(c) + e^3*c^3 + O(c) sage: C.an_element() / 7 - -1/7*e^3*c^3 + O(c) + 1/7*e^3*c^3 + O(c) Here the result's coefficient ring is the newly found :: @@ -1683,16 +1683,16 @@ def _an_element_(self): EXAMPLES:: sage: AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ).an_element() - -z^(3/2) + O(z^(1/2)) + z^(3/2) + O(z^(1/2)) sage: AsymptoticRing(growth_group='z^ZZ', coefficient_ring=QQ).an_element() - -1/8*z^3 + O(z) + 1/8*z^3 + O(z) sage: AsymptoticRing(growth_group='z^QQ', coefficient_ring=QQ).an_element() - -1/8*z^(3/2) + O(z^(1/2)) + 1/8*z^(3/2) + O(z^(1/2)) """ from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) - return -self(E.an_element(), convert=False)**3 + \ + return self(E.an_element(), convert=False)**3 + \ self(O.an_element(), convert=False) @@ -1715,22 +1715,22 @@ def some_elements(self): sage: from itertools import islice sage: A = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ) sage: tuple(islice(A.some_elements(), 10)) - (-z^(3/2) + O(z^(1/2)), - -z^(3/2) + O(z^(-1/2)), - z^(3/2) + O(z^(1/2)), - O(z^2), + (z^(3/2) + O(z^(1/2)), z^(3/2) + O(z^(-1/2)), + -z^(3/2) + O(z^(1/2)), + O(z^2), + -z^(3/2) + O(z^(-1/2)), O(z^(1/2)), - -z^(3/2) + O(z^(-2)), + z^(3/2) + O(z^(-2)), O(z^2), O(z^(-1/2)), - -8*z^(3/2) + O(z^(1/2))) + 8*z^(3/2) + O(z^(1/2))) """ from sage.rings.asymptotic.term_monoid import product_diagonal from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) - return iter(-self(e, convert=False)**3 + self(o, convert=False) + return iter(self(e, convert=False)**3 + self(o, convert=False) for e, o in product_diagonal( E.some_elements(), O.some_elements())) @@ -1911,7 +1911,6 @@ def construction(self): :class:`AsymptoticRing`, :class:`AsymptoticRingFunctor`. """ - return AsymptoticRingFunctor(self.growth_group), self.coefficient_ring From d59304b3d15b0824c8846fc199c7819e1621f2be Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 27 Aug 2015 19:54:06 +0200 Subject: [PATCH 0621/1872] make AsymptoticRing derived from Algebra --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 1b613b734d2..e6149dbce39 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -319,7 +319,7 @@ import sage -class AsymptoticExpression(sage.rings.ring_element.RingElement): +class AsymptoticExpression(sage.structure.element.CommutativeAlgebraElement): r""" Class for asymptotic expressions, i.e., the elements of an :class:`AsymptoticRing`. @@ -1071,7 +1071,7 @@ def O(self): -class AsymptoticRing(sage.rings.ring.Ring, +class AsymptoticRing(sage.algebras.algebra.Algebra, sage.structure.unique_representation.UniqueRepresentation): r""" A ring consisting of :class:`asymptotic expressions `. @@ -1253,7 +1253,7 @@ def __init__(self, growth_group, coefficient_ring, category=None, self._coefficient_ring_ = coefficient_ring self._growth_group_ = growth_group self._default_prec_ = default_prec - super(AsymptoticRing, self).__init__(base=coefficient_ring, + super(AsymptoticRing, self).__init__(base_ring=coefficient_ring, category=category) From 57cd39f082c3b3af7b4b2a1859735d4b28cab743 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 08:50:50 +0200 Subject: [PATCH 0622/1872] doc of rmul --- src/sage/rings/asymptotic/asymptotic_ring.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index e6149dbce39..be87158265c 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -786,7 +786,7 @@ def _mul_term_(self, term): def _mul_(self, other): r""" - Multiply ``other`` to this asymptotic expression. + Multiply this asymptotic expression by another asymptotic expression ``other``. INPUT: @@ -817,6 +817,24 @@ def _mul_(self, other): def _rmul_(self, other): + r""" + Multiply this asymptotic expression by an element ``other`` of its + coefficient ring. + + INPUT: + + - ``other`` -- an element of the coefficient ring. + + OUTPUT: + + An :class:`AsymptoticExpression`. + + TESTS:: + + sage: A. = AsymptoticRing(growth_group='QQ^a * a^QQ * log(a)^QQ', coefficient_ring=ZZ) + sage: 2*a + 2*a + """ from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', asymptotic_ring=self.parent()) e = E(self.parent().growth_group.one(), coefficient=other) From 1e625e3878234b967b580bafa54ac2090d62b60a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 08:51:15 +0200 Subject: [PATCH 0623/1872] add a doctest for scalar multiplication --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index be87158265c..361142544bb 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -907,6 +907,9 @@ def __invert__(self): sage: A. = AsymptoticRing(growth_group='a^ZZ', coefficient_ring=ZZ) sage: (1 / a).parent() + Asymptotic Ring over Integer Ring + sage: (a / 2).parent() + Asymptotic Ring over Rational Field """ if len(self.summands) == 0: raise ZeroDivisionError('Division by zero in %s.' % (self,)) From be23e638cacfc1cab51ee9127d2c3b3d73cf95fc Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 09:10:59 +0200 Subject: [PATCH 0624/1872] fix bug with "is" and change_parameter --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 361142544bb..be322fbe1b0 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1360,17 +1360,16 @@ def change_parameter(self, **kwds): sage: A.change_parameter(coefficient_ring=ZZ) is A True """ - parameters = ('growth_group', 'coefficient_ring', 'category', 'default_prec') + parameters = ('growth_group', 'coefficient_ring', 'default_prec') values = dict() for parameter in parameters: values[parameter] = kwds.get(parameter, getattr(self, parameter)) - values['category'] = values['category']() + values['category'] = self.category() if all(values[parameter] is getattr(self, parameter) - for parameter in parameters): + for parameter in parameters) and values['category'] is self.category(): return self return self.__class__(**values) - @staticmethod def _create_empty_summands_(): r""" From 0c2b6e451fc65a7d3c3a704d0bc78c79ced75dd3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 09:41:44 +0200 Subject: [PATCH 0625/1872] improves working with categories and use CommutativeAlgebras() --- src/sage/rings/asymptotic/asymptotic_ring.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index be322fbe1b0..17f492b6e68 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1224,9 +1224,12 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, from sage.misc.defaults import series_precision default_prec = series_precision() - from sage.categories.rings import Rings if category is None: - category = Rings() & sage.categories.posets.Posets() + from sage.categories.commutative_algebras import CommutativeAlgebras + from sage.categories.rings import Rings + from sage.categories.posets import Posets + + category = CommutativeAlgebras(Rings()) & Posets() return super(AsymptoticRing, cls).__classcall__(cls, growth_group, coefficient_ring, @@ -1256,21 +1259,13 @@ def __init__(self, growth_group, coefficient_ring, category=None, ... TypeError: __classcall__() takes at least 3 arguments (2 given) """ - from sage.categories.rings import Rings - if growth_group is None: raise ValueError('Growth group not specified. Cannot continue.') elif coefficient_ring is None: raise ValueError('Coefficient ring not specified. Cannot continue.') - elif coefficient_ring not in Rings(): + elif coefficient_ring not in sage.categories.rings.Rings(): raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) - if not isinstance(category, tuple): - category = (category,) - if not any(cat.is_subcategory(Rings()) for cat in category): - raise ValueError('%s is not a subcategory of %s' % (category, - Rings())) - self._coefficient_ring_ = coefficient_ring self._growth_group_ = growth_group self._default_prec_ = default_prec From ee071a786d3d4f6a781572fe514900820a28dc6c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 09:42:09 +0200 Subject: [PATCH 0626/1872] fix scalar multiplication by zero --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 17f492b6e68..ce6c7e235cb 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -835,6 +835,9 @@ def _rmul_(self, other): sage: 2*a 2*a """ + if other == 0: + return self.parent().zero() + from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', asymptotic_ring=self.parent()) e = E(self.parent().growth_group.one(), coefficient=other) @@ -1178,6 +1181,7 @@ class AsymptoticRing(sage.algebras.algebra.Algebra, sage: R1_x is R2_x is R3_x True """ + # enable the category framework for elements Element = AsymptoticExpression @@ -1501,7 +1505,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): if not data or data == 0: summands = AsymptoticRing._create_empty_summands_() return self.element_class(self, summands, - simplify=simplify, convert=convert) + simplify=simplify, convert=False) try: P = data.parent() @@ -1882,7 +1886,7 @@ def create_summand(self, type, data=None, **kwds): raise TypeError("Neither 'data' nor 'growth' are specified.") if type == 'exact' and kwds.get('coefficient') == 0: - return self(kwds['coefficient']) + return self.zero() return self(TM(data, **kwds), convert=False) From f54e5880d319aecf21809d380dc617aefc2c703b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 10:27:19 +0200 Subject: [PATCH 0627/1872] some checks on the given names of the generators (when using R.<....>) --- src/sage/rings/asymptotic/asymptotic_ring.py | 39 ++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index ce6c7e235cb..690ac889eb4 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1215,14 +1215,47 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, sage: AR. = AsymptoticRing(growth_group='log(x)^ZZ', coefficient_ring=ZZ) Traceback (most recent call last): ... - ValueError: Growth Group log(x)^ZZ does not have a generator. + ValueError: Growth Group log(x)^ZZ does not privide any generators + but name 'lx' given. + + :: + + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + Traceback (most recent call last): + ... + ValueError: Names 'a', 'b' do not coincide with + generators 'x', 'y' of Growth Group x^ZZ * y^ZZ. + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + Traceback (most recent call last): + ... + ValueError: Names 'x', 'b' do not coincide with + generators 'x', 'y' of Growth Group x^ZZ * y^ZZ. + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + Traceback (most recent call last): + ... + ValueError: Name 'x' do not coincide with + generators 'x', 'y' of Growth Group x^ZZ * y^ZZ. + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + Traceback (most recent call last): + ... + ValueError: Names 'x', 'y', 'z' do not coincide with + generators 'x', 'y' of Growth Group x^ZZ * y^ZZ. """ if isinstance(growth_group, str): from sage.rings.asymptotic.growth_group import GrowthGroup growth_group = GrowthGroup(growth_group) - if names is not None and not growth_group.gens_monomial(): - raise ValueError("%s does not have a generator." % (growth_group,)) + strgens = list(str(g) for g in growth_group.gens_monomial()) + def format_names(N): + return ('s ' if len(N) != 1 else ' ') + ', '.join("'%s'" % n for n in N) + if names and not strgens: + raise ValueError('%s does not privide any generators but name%s given.' % + (growth_group, format_names(names))) + elif names is not None and len(names) == 1 and len(strgens) == 1: + pass + elif names is not None and sorted(names) != strgens: + raise ValueError('Name%s do not coincide with generator%s of %s.' % + (format_names(names), format_names(strgens), growth_group)) if default_prec is None: from sage.misc.defaults import series_precision From 92861ed09c0bb4b6376e5876c49f46868ee24353 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 10:31:20 +0200 Subject: [PATCH 0628/1872] more on names/gens --- src/sage/rings/asymptotic/asymptotic_ring.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 690ac889eb4..a46622ba77a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1220,12 +1220,19 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, :: - sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ); A + Asymptotic Ring over Integer Ring + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + Traceback (most recent call last): + ... + ValueError: Names 'y', 'x' do not coincide with + generators 'x', 'y' of Growth Group x^ZZ * y^ZZ. + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) Traceback (most recent call last): ... ValueError: Names 'a', 'b' do not coincide with generators 'x', 'y' of Growth Group x^ZZ * y^ZZ. - sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) Traceback (most recent call last): ... ValueError: Names 'x', 'b' do not coincide with @@ -1235,7 +1242,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, ... ValueError: Name 'x' do not coincide with generators 'x', 'y' of Growth Group x^ZZ * y^ZZ. - sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) Traceback (most recent call last): ... ValueError: Names 'x', 'y', 'z' do not coincide with @@ -1245,7 +1252,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, from sage.rings.asymptotic.growth_group import GrowthGroup growth_group = GrowthGroup(growth_group) - strgens = list(str(g) for g in growth_group.gens_monomial()) + strgens = tuple(str(g) for g in growth_group.gens_monomial()) def format_names(N): return ('s ' if len(N) != 1 else ' ') + ', '.join("'%s'" % n for n in N) if names and not strgens: @@ -1253,7 +1260,7 @@ def format_names(N): (growth_group, format_names(names))) elif names is not None and len(names) == 1 and len(strgens) == 1: pass - elif names is not None and sorted(names) != strgens: + elif names is not None and names != strgens: raise ValueError('Name%s do not coincide with generator%s of %s.' % (format_names(names), format_names(strgens), growth_group)) From 18bc9e825ba19eb6a959f0bf31b242ebeda32ca2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 10:57:44 +0200 Subject: [PATCH 0629/1872] correct handling of parent in __invert__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 27 ++++++++++++++----- src/sage/rings/asymptotic/growth_group.py | 13 ++++++--- .../asymptotic/growth_group_cartesian.py | 5 ++-- src/sage/rings/asymptotic/term_monoid.py | 4 +-- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index a46622ba77a..285d3a24bbf 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -910,7 +910,7 @@ def __invert__(self): sage: A. = AsymptoticRing(growth_group='a^ZZ', coefficient_ring=ZZ) sage: (1 / a).parent() - Asymptotic Ring over Integer Ring + Asymptotic Ring over Rational Field sage: (a / 2).parent() Asymptotic Ring over Rational Field """ @@ -918,10 +918,13 @@ def __invert__(self): raise ZeroDivisionError('Division by zero in %s.' % (self,)) elif len(self.summands) == 1: - new_element = ~next(self.summands.elements()) - try: + element = next(self.summands.elements()) + new_element = ~element + if new_element.parent() is element.parent(): return self.parent()(new_element) - except (ValueError, TypeError): + else: + # Insert an 'if' here once terms can have different + # coefficient rings, as this will be for L-terms. new_parent = self.parent().change_parameter( growth_group=new_element.parent().growth_group, coefficient_ring=new_element.parent().coefficient_ring) @@ -931,11 +934,21 @@ def __invert__(self): if len(max_elem) != 1: raise ValueError('Expression %s cannot be inverted, since there ' 'are several maximal elements: %s.' % (self, max_elem)) - max_elem = max_elem[0] + imax_elem = ~max_elem - one = self.parent().one() - geom = one - self._mul_term_(imax_elem) + if imax_elem.parent() is max_elem.parent(): + new_self = self + else: + # Insert an 'if' here once terms can have different + # coefficient rings, as this will be for L-terms. + new_parent = self.parent().change_parameter( + growth_group=imax_elem.parent().growth_group, + coefficient_ring=imax_elem.parent().coefficient_ring) + new_self = new_parent(self) + + one = new_self.parent().one() + geom = one - new_self._mul_term_(imax_elem) expanding = True result = one diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 68d2cf8d679..34d80768f20 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2078,9 +2078,9 @@ def __invert__(self): True """ new_element = -self.exponent - try: + if new_element.parent() is self.exponent.parent(): return self.parent()(raw_element=new_element) - except (ValueError, TypeError): + else: new_parent = self.parent().__class__(new_element.parent(), self.parent()._var_) return new_parent(raw_element=new_element) @@ -2627,11 +2627,16 @@ def __invert__(self): True sage: e2.parent() Growth Group QQ^x + + :: + + sage: (~P(raw_element=1)).parent() + Growth Group QQ^x """ new_element = 1 / self.base - try: + if new_element.parent() is self.base.parent(): return self.parent()(raw_element=new_element) - except (ValueError, TypeError): + else: new_parent = self.parent().__class__(new_element.parent(), self.parent()._var_) return new_parent(raw_element=new_element) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index c3e955664e5..113541b7c04 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -878,9 +878,10 @@ def __invert__(self): Growth Group QQ^x * x^ZZ """ new_element = tuple(~x for x in self.cartesian_factors()) - try: + if all(n.parent() is x.parent() + for n, x in zip(new_element, self.cartesian_factors())): return self.parent()(new_element) - except (ValueError, TypeError): + else: from sage.categories.cartesian_product import cartesian_product new_parent = cartesian_product( tuple(x.parent() for x in new_element)) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 5f7446757c0..14e45acaac9 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2285,9 +2285,9 @@ def __invert__(self): raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' 'cannot be inverted.' % (self, self.coefficient)) g = ~self.growth - try: + if c.parent() is self.coefficient.parent() and g.parent() is self.growth.parent(): return self.parent()(g, c) - except (ValueError, TypeError): + else: new_parent = self.parent().__class__(g.parent(), c.parent()) return new_parent(g, c) From d83354486620b870e5470d19f296df63a55f6bd5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 11:06:55 +0200 Subject: [PATCH 0630/1872] minor rewrite of __pow__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 285d3a24bbf..97f4bd26a82 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1049,6 +1049,7 @@ def __pow__(self, power): raise NotImplementedError('Taking the sum %s to the ' 'non-integer power %s not ' 'implemented.' % (self, power)) + expr = next(self.summands.elements()) P = self.parent() if power not in P.growth_group.base(): @@ -1057,7 +1058,6 @@ def __pow__(self, power): (P.growth_group, self, power)) from sage.rings.asymptotic.term_monoid import TermWithCoefficient - expr = self.summands.elements().next() if isinstance(expr, TermWithCoefficient): new_growth = expr.growth**power new_coeff = expr.coefficient**power From 2f63d299edaaa4d477f6339e3f750a57e44ea5f3 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 11:08:54 +0200 Subject: [PATCH 0631/1872] log for asymptotic expressions implemented --- src/sage/rings/asymptotic/asymptotic_ring.py | 75 ++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 4a366a6eddd..d11726b3294 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -987,6 +987,81 @@ def O(self): for element in self.summands.maximal_elements()) + def log(self, base=None, prec=None): + r""" + The logarithm of this asymptotic expression. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the logarithm is the natural + logarithm. + + - ``prec`` -- the precision used for truncating the + expansion. If ``None`` (default value) is used, the + default precision from the parent is used. + + OUTPUT: + + An asymptotic expression. + + .. NOTE:: + + Computing the logarithm of an asymptotic expression + is possible if and only if there is exactly one maximal + term in the expression. + + In case the expression has more than one term, + the well-known expansion for `\log(1+t)` is used. + + EXAMPLES:: + + sage: R. = AsymptoticRing('x^ZZ * log(x)^ZZ', QQ) + sage: log(x) + log(x) + sage: log(x^2) + 2*log(x) + sage: log(x-1) + log(x) - x^(-1) - 1/2*x^(-2) - 1/3*x^(-3) - ... + O(x^(-21)) + + :: + + sage: log(R(1)) + 0 + """ + P = self.parent() + + if len(self.summands) == 0: + from sage.rings.infinity import minus_infinity + return minus_infinity + + elif len(self.summands) == 1: + if self == 1: + return P(0) + return P(next(self.summands.elements()).log_term()) + + max_elem = tuple(self.summands.maximal_elements()) + if len(max_elem) != 1: + raise ValueError('log(%s) cannot be constructed since there ' + 'are several maximal elements: %s.' % (self, max_elem)) + + from sage.functions.log import log + max_elem = max_elem[0] + imax_elem = ~max_elem + one = P.one() + geom = one - self._mul_term_(imax_elem) + + expanding = True + result = -geom + k = 1 + while expanding: + k += 1 + new_result = (result - geom**k / k).truncate(prec=prec) + if new_result.has_same_summands(result): + expanding = False + result = new_result + return log(P(max_elem)) + result + class AsymptoticRing(sage.rings.ring.Ring, sage.structure.unique_representation.UniqueRepresentation): From caef9eae1dc7c85e5857cef6bcf7ea0096c76754 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 11:37:54 +0200 Subject: [PATCH 0632/1872] term: is_same --> __eq__ --- src/sage/rings/asymptotic/term_monoid.py | 93 +++++++++--------------- 1 file changed, 34 insertions(+), 59 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 2fc959d43a5..b60cab537ec 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -699,9 +699,9 @@ def _le_(self, other): return self.growth <= other.growth - def is_same(self, other): + def __eq__(self, other): r""" - Return if this asymptotic term is the same as ``other``. + Return if this asymptotic term is equal to ``other``. INPUT: @@ -727,30 +727,28 @@ def is_same(self, other): sage: g = GT.an_element(); e = ET.an_element(); o = OT.an_element() sage: g, e, o (Generic Term with growth x, x, O(x)) - sage: g.is_same(g^2) - Traceback (most recent call last): - ... - NotImplementedError: Only implemented in concrete realizations. - sage: e.is_same(e^2) + sage: g == g^2 # indirect doctest + False + sage: e == e^2 # indirect doctest False - sage: e.is_same(ET(x,1)) + sage: e == ET(x,1) # indirect doctest True - sage: o.is_same(OT(x^2)) + sage: o == OT(x^2) # indirect doctest False """ from sage.structure.element import have_same_parent - if have_same_parent(self, other): - return self._is_same_(other) + return self._eq_(other) from sage.structure.element import get_coercion_model - - return get_coercion_model().bin_op(self, other, - lambda self, other: - self._is_same_(other)) + import operator + try: + return get_coercion_model().bin_op(self, other, operator.eq) + except TypeError: + return False - def _is_same_(self, other): + def _eq_(self, other): r""" Return if this asymptotic term is the same as ``other``. @@ -776,12 +774,21 @@ def _is_same_(self, other): sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid sage: T = GenericTermMonoid(GrowthGroup('x^ZZ')) sage: t = T.an_element() - sage: t.is_same(t) - Traceback (most recent call last): - ... - NotImplementedError: Only implemented in concrete realizations. + sage: t == t + True + + :: + + sage: from sage.rings.asymptotic.term_monoid import OTermMonoid + sage: OT = OTermMonoid(GrowthGroup('x^ZZ')) + sage: t = OT.an_element(); t + O(x) + sage: t == OT(x) # indirect doctest + True + sage: t == OT(x^2) # indirect doctest + False """ - raise NotImplementedError('Only implemented in concrete realizations.') + return self.growth == other.growth def _repr_(self): @@ -1264,39 +1271,6 @@ def _absorb_(self, other): return self - def _is_same_(self, other): - r""" - Return if this :class:`OTerm` is the same as ``other``. - - INPUT: - - - ``other`` -- an :class:`OTerm`. - - OUTPUT: - - A boolean. - - .. NOTE:: - - This method gets called by the coercion model, so it can - be assumed that this :class:`OTerm` and ``other`` come - from the same parent. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: from sage.rings.asymptotic.term_monoid import OTermMonoid - sage: OT = OTermMonoid(GrowthGroup('x^ZZ')) - sage: t = OT.an_element(); t - O(x) - sage: t.is_same(OT(x)) # indirect doctest - True - sage: t.is_same(OT(x^2)) # indirect doctest - False - """ - return self.growth == other.growth - - class OTermMonoid(GenericTermMonoid): r""" Parent for asymptotic big `O`-terms. @@ -1605,7 +1579,7 @@ def _le_(self, other): return super(TermWithCoefficient, self)._le_(other) - def _is_same_(self, other): + def _eq_(self, other): r""" Return if this :class:`TermWithCoefficient` is the same as ``other``. @@ -1631,14 +1605,15 @@ def _is_same_(self, other): sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), ZZ) sage: t = T.an_element(); t Asymptotic Term with coefficient 1 and growth x - sage: t.is_same(T(x, 1)) + sage: t == T(x, 1) True - sage: t.is_same(T(x, 2)) + sage: t == T(x, 2) False - sage: t.is_same(T(x^2, 1)) + sage: t == T(x^2, 1) False """ - return self.growth == other.growth and self.coefficient == other.coefficient + return super(TermWithCoefficient, self)._eq_(other) and \ + self.coefficient == other.coefficient From 561838546e14f4c9c4ed855089cc1ff76ef279dc Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 11:38:50 +0200 Subject: [PATCH 0633/1872] rewrite has_same_summands to use iterators efficiently --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 64254222535..7248947409d 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -476,9 +476,10 @@ def _has_same_summands_(self, other): """ if len(self.summands) != len(other.summands): return False - pairs = zip(self.summands.elements_topological(), - other.summands.elements_topological()) - return all(p[0].is_same(p[1]) for p in pairs) + from itertools import izip + return all(s == o for s, o in + izip(self.summands.elements_topological(), + other.summands.elements_topological())) def _simplify_(self): From 51cfce64eb1d1c128985f99b2727c5a79ac49b4b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 11:38:55 +0200 Subject: [PATCH 0634/1872] adapt doc --- src/sage/rings/asymptotic/asymptotic_ring.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 7248947409d..56fa3903994 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -420,12 +420,12 @@ def has_same_summands(self, other): .. NOTE:: While for example ``O(x) == O(x)`` yields ``False``, - these expressions *do* have the same summands. + these expressions *do* have the same summands and this method + returns ``True``. - Also, this method uses the coercion model in order to + Moreover, this method uses the coercion model in order to find a common parent for this asymptotic expression and - ``other``. The method :meth:`_has_same_summands_` is - then used for the actual comparison. + ``other``. EXAMPLES:: @@ -437,12 +437,10 @@ def has_same_summands(self, other): False """ from sage.structure.element import have_same_parent - if have_same_parent(self, other): return self._has_same_summands_(other) from sage.structure.element import get_coercion_model - return get_coercion_model().bin_op(self, other, lambda self, other: self._has_same_summands_(other)) From 2d4c680a76b6d36f543509121faa41e9acb27010 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 11:47:44 +0200 Subject: [PATCH 0635/1872] doctest fixed --- src/sage/rings/asymptotic/growth_group_cartesian.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index be0f186cebd..37301c1cdae 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1057,10 +1057,10 @@ def rpow(self, base): :: - sage: G = GrowthGroup('QQ^(x * log(x)) * x^ZZ * log(x)^ZZ') + sage: G = GrowthGroup('QQ^(x*log(x)) * x^ZZ * log(x)^ZZ') sage: x, = G.gens_monomial() sage: (x * log(x)).rpow(2) - 2^(x * log(x)) + 2^(x*log(x)) """ P = self.parent() factors = self.factor() From e4bf13875ec50e09d3acf9f5d995c26d07d6e65a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 11:47:47 +0200 Subject: [PATCH 0636/1872] fix failing doctest after merge --- src/sage/rings/asymptotic/term_monoid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index cf4cb29619f..3321d18f101 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -882,7 +882,7 @@ def _eq_(self, other): :: sage: from sage.rings.asymptotic.term_monoid import OTermMonoid - sage: OT = OTermMonoid(GrowthGroup('x^ZZ')) + sage: OT = OTermMonoid(GrowthGroup('x^ZZ'), QQ) sage: t = OT.an_element(); t O(x) sage: t == OT(x) # indirect doctest From a13f6cb4f4f378104543c4fcbdcbf3c1a20c2e42 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 12:25:22 +0200 Subject: [PATCH 0637/1872] write map and mapped --- src/sage/data_structures/mutable_poset.py | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 62e82c96439..1ebaeb1a2b9 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2876,6 +2876,70 @@ def minimal_elements(self): if not shell.is_special()) + def map(self, function): + r""" + Applies the given ``function`` on each element. + + INPUT: + + - ``function`` -- a function mapping an existing element to a new element. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: P.map(lambda e: str(e)) + sage: P + poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') + """ + for shell in self.shells(): + shell._element_ = function(shell._element_) + + + def mapped(self, function): + r""" + Return a poset where on each element the given ``function`` was applied. + + INPUT: + + - ``function`` -- a function mapping an existing element to a new element. + + OUTPUT: + + A :class:`MutablePoset` + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: P.mapped(lambda e: str(e)) + poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') + """ + new = self.copy() + new.map(function) + return new + + # ***************************************************************************** From 70859d74ebdba2797a4a25e23d192349b1874bec Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 16:07:36 +0200 Subject: [PATCH 0638/1872] cleanup: delete toset since not yet implemented --- src/sage/data_structures/mutable_poset.py | 34 ++--------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 62e82c96439..3b64f3d23a1 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -48,9 +48,8 @@ poset(3, 7, 13, 42) We see that they elements are sorted using `\leq` which exists on the -integers `\ZZ`. Since this is even a total order, we could have used -the more efficient :class:`MutableToset`. (Note that also other data -structures are suitable for totally ordered sets.) +integers `\ZZ`. Since this is even a total order, we could have used a +more efficient data structure. A less boring Example @@ -137,6 +136,7 @@ AUTHORS: - Daniel Krenn (2015-01-21): initial version +- Daniel Krenn (2015-08-28): mapping methods, bug fixes, cleanup ACKNOWLEDGEMENT: @@ -2877,31 +2877,3 @@ def minimal_elements(self): # ***************************************************************************** - - -class MutableTosetShell(MutablePosetShell): - r""" - A shell containing an element of a mutable toset (totally ordered set). - - .. TODO:: - - Implement this class. - """ - pass - - -# ***************************************************************************** - - -class MutableToset(MutablePoset): - r""" - A mutable toset (totally ordered set) as data structure. - - .. TODO:: - - Implement this class. - """ - pass - - -# ***************************************************************************** From d647d951c9c02c3daf4c1bcb86e54fada03582b3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 12:25:22 +0200 Subject: [PATCH 0639/1872] write map and mapped --- src/sage/data_structures/mutable_poset.py | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3b64f3d23a1..ce21eceb891 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2876,4 +2876,68 @@ def minimal_elements(self): if not shell.is_special()) + def map(self, function): + r""" + Applies the given ``function`` on each element. + + INPUT: + + - ``function`` -- a function mapping an existing element to a new element. + + OUTPUT: + + Nothing. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: P.map(lambda e: str(e)) + sage: P + poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') + """ + for shell in self.shells(): + shell._element_ = function(shell._element_) + + + def mapped(self, function): + r""" + Return a poset where on each element the given ``function`` was applied. + + INPUT: + + - ``function`` -- a function mapping an existing element to a new element. + + OUTPUT: + + A :class:`MutablePoset` + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP() + sage: P.add(T((1, 3))) + sage: P.add(T((2, 1))) + sage: P.add(T((4, 4))) + sage: P.add(T((1, 2))) + sage: P.add(T((2, 2))) + sage: P.mapped(lambda e: str(e)) + poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') + """ + new = self.copy() + new.map(function) + return new + + # ***************************************************************************** From b9c1a6a9ac0a9633a66e675313efba5c14f25eb3 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 13:26:24 +0200 Subject: [PATCH 0640/1872] modified log_factor algorithm to work with QQ['e'] --- src/sage/rings/asymptotic/growth_group_cartesian.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 37301c1cdae..193d5d22874 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1004,7 +1004,13 @@ def log_factor(self, base=None): log_factors.append([growth, coef]) elif isinstance(FP, ExponentialGrowthGroup): - coef = log(factor._raw_element_, base=base) + b = factor._raw_element_ + if hasattr(b, 'is_monomial') and b.is_monomial(): + if b.variable_name() == 'e' and not base: + coef = b.valuation() + else: + coef = log(b, base=base) + growth = P(repr(FP._var_)) log_factors.append([growth, coef]) From c99f55087253280593cf38383659d885b41a57d5 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 13:27:23 +0200 Subject: [PATCH 0641/1872] doctest added --- src/sage/rings/asymptotic/growth_group_cartesian.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 193d5d22874..cc89a1463cb 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -984,6 +984,13 @@ def log_factor(self, base=None): ... ValueError: Logarithm of log(x) cannot be constructed in Growth Group QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ. + + TESTS:: + + sage: G = GrowthGroup("QQ['e']^x * x^ZZ * log(x)^ZZ") + sage: x, = G.gens_monomial() + sage: (exp(x) * x).log_factor() + [[x, 1], [log(x), 1]] """ P = self.parent() factors = self.factor() From 2658c9431769d71403bf1394223843f396dae02c Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 13:28:06 +0200 Subject: [PATCH 0642/1872] raise exception if log does not work for growth elements --- src/sage/rings/asymptotic/growth_group_cartesian.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index cc89a1463cb..c9d18bb2f61 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -874,6 +874,12 @@ def log(self, base=None): lf = self.log_factor(base=base) if len(lf) == 1 and lf[0][1] == 1: return lf[0][0] + if base: + raise ValueError('The logarithm of %s with base %s cannot be ' + 'constructed in %s.' % (self, base, self.parent())) + + raise ValueError('The logarithm of %s cannot be constructed in ' + '%s.' % (self, self.parent())) def factor(self): r""" From 53e7d93d4a956c28ed09a14edd7a8027ee29f142 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 13:28:26 +0200 Subject: [PATCH 0643/1872] added examples and tests (log for growth elements) --- .../asymptotic/growth_group_cartesian.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index c9d18bb2f61..c3625ea7898 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -870,6 +870,37 @@ def log(self, base=None): A growth element. + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * log(x)^ZZ') + sage: x, = G.gens_monomial() + sage: log(x) # indirect doctest + log(x) + sage: log(x^5) + Traceback (most recent call last): + ... + ValueError: The logarithm of x^5 cannot be constructed in Growth Group x^ZZ * log(x)^ZZ. + + :: + + sage: G = GrowthGroup('QQ^x * x^ZZ') + sage: x, = G.gens_monomial() + sage: el = x.rpow(2); el + 2^x + sage: log(el) + Traceback (most recent call last): + ... + ValueError: The logarithm of 2^x cannot be constructed in Growth Group QQ^x * x^ZZ. + sage: log(el, base=2) + x + + TESTS:: + + sage: G = GrowthGroup("QQ['e']^x * x^ZZ") + sage: x, = G.gens_monomial() + sage: log(exp(x)) + x """ lf = self.log_factor(base=base) if len(lf) == 1 and lf[0][1] == 1: From a2999cf37eab13c8939cd3f15665d472d2a2a640 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 15:19:22 +0200 Subject: [PATCH 0644/1872] typo fixed --- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index c3625ea7898..e941274d10b 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1059,7 +1059,7 @@ def log_factor(self, base=None): log_factors.append([growth, coef]) else: - raise NotImplementedError('Taking the Logarithm of %s ' + raise NotImplementedError('Taking the logarithm of %s ' 'is not implemented.' % (factor,)) From 9780c4bb6820fae929954f21a9bde73b1500d1bf Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 15:19:40 +0200 Subject: [PATCH 0645/1872] indentation fixed --- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index e941274d10b..e0c71cf212b 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1065,7 +1065,7 @@ def log_factor(self, base=None): except (ValueError, TypeError): raise ValueError('Logarithm of %s cannot be ' - 'constructed in %s.' % (factor, P)) + 'constructed in %s.' % (factor, P)) return log_factors From 6b747e62712570c837ea60257bd79c434fa76f3d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 15:57:40 +0200 Subject: [PATCH 0646/1872] mapping argument for .copy() --- src/sage/data_structures/mutable_poset.py | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 1ebaeb1a2b9..3978e73ca5d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -608,7 +608,7 @@ def eq(left, right): __eq__ = eq - def _copy_all_linked_(self, memo, poset): + def _copy_all_linked_(self, memo, poset, mapping): r""" Helper function for :meth:`MutablePoset.copy`. @@ -619,6 +619,8 @@ def _copy_all_linked_(self, memo, poset): - ``poset`` -- the poset to which the newly created shells belongs. + - ``mapping`` -- a function which is applied on each of the elements. + OUTPUT: A new shell. @@ -629,7 +631,7 @@ def _copy_all_linked_(self, memo, poset): sage: P = MP() sage: Q = MP() sage: memo = {} - sage: z = P.null._copy_all_linked_(memo, Q) + sage: z = P.null._copy_all_linked_(memo, Q, lambda e: e) sage: z.poset is Q True sage: oo = z.successors().pop() @@ -641,12 +643,13 @@ def _copy_all_linked_(self, memo, poset): except KeyError: pass - new = self.__class__(poset, self.element) + new = self.__class__(poset, mapping(self.element) + if self.element is not None else None) memo[id(self)] = new for reverse in (False, True): for e in self.successors(reverse): - new.successors(reverse).add(e._copy_all_linked_(memo, poset)) + new.successors(reverse).add(e._copy_all_linked_(memo, poset, mapping)) return new @@ -1231,7 +1234,7 @@ def __init__(self, data=None, key=None, merge=None, can_merge=None): if is_MutablePoset(data): if key is not None: raise TypeError('Cannot use key when data is a poset.') - self._copy_shells_(data) + self._copy_shells_(data, lambda e: e) else: self.clear() @@ -1435,7 +1438,7 @@ def get_key(self, element): return self._key_(element) - def _copy_shells_(self, other): + def _copy_shells_(self, other, mapping): r""" Helper function for copying shells. @@ -1444,6 +1447,8 @@ def _copy_shells_(self, other): - ``other`` -- the mutable poset from which the shells should be copied this poset. + - ``mapping`` -- a function which is applied on each of the elements. + OUTPUT: Nothing. @@ -1461,7 +1466,7 @@ def _copy_shells_(self, other): sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: Q = MP() - sage: Q._copy_shells_(P) + sage: Q._copy_shells_(P, lambda e: e) sage: P.repr_full() == Q.repr_full() True """ @@ -1470,20 +1475,20 @@ def _copy_shells_(self, other): self._merge_ = copy(other._merge_) self._can_merge_ = copy(other._can_merge_) memo = {} - self._null_ = other._null_._copy_all_linked_(memo, self) + self._null_ = other._null_._copy_all_linked_(memo, self, mapping) self._oo_ = memo[id(other._oo_)] self._shells_ = dict((f.key, f) for f in iter(memo[id(e)] for e in other._shells_.itervalues())) - def copy(self): + def copy(self, mapping=None): r""" Creates a shallow copy. INPUT: - Nothing. + - ``mapping`` -- a function which is applied on each of the elements. OUTPUT: @@ -1505,8 +1510,10 @@ def copy(self): sage: P.repr_full() == Q.repr_full() True """ + if mapping is None: + mapping = lambda element: element new = self.__class__() - new._copy_shells_(self) + new._copy_shells_(self, mapping) return new From e64cbd80ca50a19544af525b6da681ec7dfe607d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 15:57:40 +0200 Subject: [PATCH 0647/1872] mapping argument for .copy() --- src/sage/data_structures/mutable_poset.py | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ce21eceb891..a5f4a5f52c2 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -608,7 +608,7 @@ def eq(left, right): __eq__ = eq - def _copy_all_linked_(self, memo, poset): + def _copy_all_linked_(self, memo, poset, mapping): r""" Helper function for :meth:`MutablePoset.copy`. @@ -619,6 +619,8 @@ def _copy_all_linked_(self, memo, poset): - ``poset`` -- the poset to which the newly created shells belongs. + - ``mapping`` -- a function which is applied on each of the elements. + OUTPUT: A new shell. @@ -629,7 +631,7 @@ def _copy_all_linked_(self, memo, poset): sage: P = MP() sage: Q = MP() sage: memo = {} - sage: z = P.null._copy_all_linked_(memo, Q) + sage: z = P.null._copy_all_linked_(memo, Q, lambda e: e) sage: z.poset is Q True sage: oo = z.successors().pop() @@ -641,12 +643,13 @@ def _copy_all_linked_(self, memo, poset): except KeyError: pass - new = self.__class__(poset, self.element) + new = self.__class__(poset, mapping(self.element) + if self.element is not None else None) memo[id(self)] = new for reverse in (False, True): for e in self.successors(reverse): - new.successors(reverse).add(e._copy_all_linked_(memo, poset)) + new.successors(reverse).add(e._copy_all_linked_(memo, poset, mapping)) return new @@ -1231,7 +1234,7 @@ def __init__(self, data=None, key=None, merge=None, can_merge=None): if is_MutablePoset(data): if key is not None: raise TypeError('Cannot use key when data is a poset.') - self._copy_shells_(data) + self._copy_shells_(data, lambda e: e) else: self.clear() @@ -1435,7 +1438,7 @@ def get_key(self, element): return self._key_(element) - def _copy_shells_(self, other): + def _copy_shells_(self, other, mapping): r""" Helper function for copying shells. @@ -1444,6 +1447,8 @@ def _copy_shells_(self, other): - ``other`` -- the mutable poset from which the shells should be copied this poset. + - ``mapping`` -- a function which is applied on each of the elements. + OUTPUT: Nothing. @@ -1461,7 +1466,7 @@ def _copy_shells_(self, other): sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: Q = MP() - sage: Q._copy_shells_(P) + sage: Q._copy_shells_(P, lambda e: e) sage: P.repr_full() == Q.repr_full() True """ @@ -1470,20 +1475,20 @@ def _copy_shells_(self, other): self._merge_ = copy(other._merge_) self._can_merge_ = copy(other._can_merge_) memo = {} - self._null_ = other._null_._copy_all_linked_(memo, self) + self._null_ = other._null_._copy_all_linked_(memo, self, mapping) self._oo_ = memo[id(other._oo_)] self._shells_ = dict((f.key, f) for f in iter(memo[id(e)] for e in other._shells_.itervalues())) - def copy(self): + def copy(self, mapping=None): r""" Creates a shallow copy. INPUT: - Nothing. + - ``mapping`` -- a function which is applied on each of the elements. OUTPUT: @@ -1505,8 +1510,10 @@ def copy(self): sage: P.repr_full() == Q.repr_full() True """ + if mapping is None: + mapping = lambda element: element new = self.__class__() - new._copy_shells_(self) + new._copy_shells_(self, mapping) return new From edfd1b827e698aaf1db53aaae90bfc1ee65aeaea Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 15:58:28 +0200 Subject: [PATCH 0648/1872] bring map and mapped back to work and use new copy-construction --- src/sage/data_structures/mutable_poset.py | 27 ++++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3978e73ca5d..53c65992e4b 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2883,7 +2883,7 @@ def minimal_elements(self): if not shell.is_special()) - def map(self, function): + def map(self, function, topological=False, reverse=False): r""" Applies the given ``function`` on each element. @@ -2891,10 +2891,20 @@ def map(self, function): - ``function`` -- a function mapping an existing element to a new element. + - ``topological`` -- (default: ``False``) if set, then the mapping is done + in topological order, otherwise unordered. + + - ``reverse`` -- is passed on to topological ordering. + OUTPUT: Nothing. + .. NOTE:: + + Since this method works inplace, it is not allowed that + ``function`` alters the key of an element. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2911,7 +2921,9 @@ def map(self, function): sage: P poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') """ - for shell in self.shells(): + shells = self.shells_topological(reverse=reverse) \ + if topological else self.shells() + for shell in shells: shell._element_ = function(shell._element_) @@ -2923,9 +2935,14 @@ def mapped(self, function): - ``function`` -- a function mapping an existing element to a new element. + - ``topological`` -- (default: ``False``) if set, then the mapping is done + in topological order, otherwise unordered. + + - ``reverse`` -- is passed on to topological ordering. + OUTPUT: - A :class:`MutablePoset` + A :class:`MutablePoset`. EXAMPLES:: @@ -2942,9 +2959,7 @@ def mapped(self, function): sage: P.mapped(lambda e: str(e)) poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') """ - new = self.copy() - new.map(function) - return new + return self.copy(mapping=function) # ***************************************************************************** From c28749c93a74337e1de987419d5d6e8760c55317 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 15:58:28 +0200 Subject: [PATCH 0649/1872] bring map and mapped back to work and use new copy-construction --- src/sage/data_structures/mutable_poset.py | 27 ++++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index a5f4a5f52c2..a78284a9b35 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2883,7 +2883,7 @@ def minimal_elements(self): if not shell.is_special()) - def map(self, function): + def map(self, function, topological=False, reverse=False): r""" Applies the given ``function`` on each element. @@ -2891,10 +2891,20 @@ def map(self, function): - ``function`` -- a function mapping an existing element to a new element. + - ``topological`` -- (default: ``False``) if set, then the mapping is done + in topological order, otherwise unordered. + + - ``reverse`` -- is passed on to topological ordering. + OUTPUT: Nothing. + .. NOTE:: + + Since this method works inplace, it is not allowed that + ``function`` alters the key of an element. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2911,7 +2921,9 @@ def map(self, function): sage: P poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') """ - for shell in self.shells(): + shells = self.shells_topological(reverse=reverse) \ + if topological else self.shells() + for shell in shells: shell._element_ = function(shell._element_) @@ -2923,9 +2935,14 @@ def mapped(self, function): - ``function`` -- a function mapping an existing element to a new element. + - ``topological`` -- (default: ``False``) if set, then the mapping is done + in topological order, otherwise unordered. + + - ``reverse`` -- is passed on to topological ordering. + OUTPUT: - A :class:`MutablePoset` + A :class:`MutablePoset`. EXAMPLES:: @@ -2942,9 +2959,7 @@ def mapped(self, function): sage: P.mapped(lambda e: str(e)) poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') """ - new = self.copy() - new.map(function) - return new + return self.copy(mapping=function) # ***************************************************************************** From 4a33e4f624fcf21585777d3ffde1307ce02077de Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 15:58:40 +0200 Subject: [PATCH 0650/1872] fix bug in merge --- src/sage/data_structures/mutable_poset.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 53c65992e4b..c145f042700 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2799,6 +2799,18 @@ def merge(self, key=None, reverse=False): sage: copy(P).merge(reverse=False) == copy(P).merge(reverse=True) True + + :: + + sage: P = MP(srange(4), + ....: merge=lambda l, r: l, can_merge=lambda l, r: l >= r); P + poset(0, 1, 2, 3) + sage: Q = P.copy() + sage: Q.merge(reverse=True); Q + poset(3) + sage: R = P.mapped(lambda x: x+1) + sage: R.merge(reverse=True); R + poset(4) """ if key is None: for shell in tuple(self.shells_topological(reverse=reverse)): @@ -2812,7 +2824,11 @@ def can_merge(other): for rev in (reverse, not reverse): to_merge = shell.iter_depth_first( reverse=rev, condition=can_merge) - next(to_merge) + try: + next(to_merge) + except StopIteration: + raise RuntimeError('Stopping merge before started; the ' + 'can_merge-function is not reflexive.') for m in tuple(to_merge): if m.is_special(): continue From ceb0b37bc7640f4300962a89eabefe5abc7263d1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 15:58:40 +0200 Subject: [PATCH 0651/1872] fix bug in merge --- src/sage/data_structures/mutable_poset.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index a78284a9b35..9de14a1166d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2799,6 +2799,18 @@ def merge(self, key=None, reverse=False): sage: copy(P).merge(reverse=False) == copy(P).merge(reverse=True) True + + :: + + sage: P = MP(srange(4), + ....: merge=lambda l, r: l, can_merge=lambda l, r: l >= r); P + poset(0, 1, 2, 3) + sage: Q = P.copy() + sage: Q.merge(reverse=True); Q + poset(3) + sage: R = P.mapped(lambda x: x+1) + sage: R.merge(reverse=True); R + poset(4) """ if key is None: for shell in tuple(self.shells_topological(reverse=reverse)): @@ -2812,7 +2824,11 @@ def can_merge(other): for rev in (reverse, not reverse): to_merge = shell.iter_depth_first( reverse=rev, condition=can_merge) - next(to_merge) + try: + next(to_merge) + except StopIteration: + raise RuntimeError('Stopping merge before started; the ' + 'can_merge-function is not reflexive.') for m in tuple(to_merge): if m.is_special(): continue From 768053193c735369e84cead0731982fbeaf33f48 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 15:59:43 +0200 Subject: [PATCH 0652/1872] make truncate faster --- src/sage/rings/asymptotic/asymptotic_ring.py | 37 ++++++++++++-------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 3296f9cd1f2..55c21355fe3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -960,13 +960,13 @@ def __invert__(self): return result._mul_term_(imax_elem) - def truncate(self, prec=None): + def truncate(self, precision=None): r""" Truncate this asymptotic expression. INPUT: - - ``prec`` -- a positive integer or ``None``. Number of + - ``precision`` -- a positive integer or ``None``. Number of summands that are kept. If ``None`` (default value) is given, then ``default_prec`` from the parent is used. @@ -977,32 +977,40 @@ def truncate(self, prec=None): .. NOTE:: For example, truncating an asymptotic expression with - ``prec=20`` does not yield an expression with exactly 20 + ``precision=20`` does not yield an expression with exactly 20 summands! Rather than that, it keeps the 20 summands - with the largest growth, and adds an appropriate - `O`-Term. + with the largest growth, and adds appropriate + `O`-Terms. EXAMPLES:: sage: R. = AsymptoticRing('x^ZZ', QQ) sage: ex = sum(x^k for k in range(5)); ex x^4 + x^3 + x^2 + x + 1 - sage: ex.truncate(prec=2) + sage: ex.truncate(precision=2) x^4 + x^3 + O(x^2) - sage: ex.truncate(prec=0) + sage: ex.truncate(precision=0) O(x^4) sage: ex.truncate() x^4 + x^3 + x^2 + x + 1 """ - if prec is None: - prec = self.parent().default_prec + if precision is None: + precision = self.parent().default_prec - if len(self.summands) <= prec: + if len(self.summands) <= precision: return self - else: - g = self.summands.elements_topological(reverse=True) - main_part = self.parent()([g.next() for _ in range(prec)]) - return main_part + (self - main_part).O() + + summands = self.summands.copy() + from term_monoid import TermMonoid + def convert_terms(element): + if convert_terms.count < precision: + convert_terms.count += 1 + return element + T = TermMonoid(term='O', asymptotic_ring=self.parent()) + return T(element) + convert_terms.count = 0 + summands.map(convert_terms, topological=True, reverse=True) + return self.parent()(summands, simplify=True, convert=False) def __pow__(self, power): @@ -1422,6 +1430,7 @@ def change_parameter(self, **kwds): return self return self.__class__(**values) + @staticmethod def _create_empty_summands_(): r""" From c7c02b0b17d7f80aa20032f3d84b008b9e1a9555 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 16:00:16 +0200 Subject: [PATCH 0653/1872] element.__init__: check if summands are of correct type --- src/sage/rings/asymptotic/asymptotic_ring.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 55c21355fe3..23a3d2e813b 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -452,6 +452,11 @@ def __init__(self, parent, summands, simplify=True, convert=True): """ super(AsymptoticExpression, self).__init__(parent=parent) + from sage.data_structures.mutable_poset import MutablePoset + if not isinstance(summands, MutablePoset): + raise TypeError('Summands %s are not in a mutable poset as expected ' + 'when creating an element of %s.' % (summands, parent)) + if convert: from growth_group import combine_exceptions from term_monoid import TermMonoid From 46599725b3f2574fe2e271a41f8b56eaa1069b7f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 16:00:50 +0200 Subject: [PATCH 0654/1872] rewrite __init__ of element to use new feature of MutablePoset --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 23a3d2e813b..d27d9c35e68 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -460,17 +460,19 @@ def __init__(self, parent, summands, simplify=True, convert=True): if convert: from growth_group import combine_exceptions from term_monoid import TermMonoid - summands = summands.copy() - for shell in summands.shells(): - element = shell._element_ + def convert_terms(element): T = TermMonoid(term=element.parent(), asymptotic_ring=parent) try: - shell._element_ = T(element) + return T(element) except (ValueError, TypeError) as e: raise combine_exceptions( ValueError('Cannot include %s with parent %s in %s' % (element, element.parent(), parent)), e) - self._summands_ = summands + new_summands = summands.copy() + new_summands.map(convert_terms, topological=True, reverse=True) + self._summands_ = new_summands + else: + self._summands_ = summands if simplify: self._simplify_() @@ -664,7 +666,7 @@ def _simplify_(self): sage: R(lst) # indirect doctest 4*x^4 + O(x^3) """ - self.summands.merge(reverse=True) + self._summands_.merge(reverse=True) def _repr_(self): @@ -1539,7 +1541,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): sage: N(M.an_element()) Traceback (most recent call last): ... - ValueError: Cannot include -m^3 with parent + ValueError: Cannot include m^3 with parent Exact Term Monoid m^ZZ with coefficients in Integer Ring in Asymptotic Ring over Rational Field > *previous* ValueError: m^3 is not in Growth Group n^ZZ From 7287ca1ef24fd556ff4f04f4aaf5408991573649 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 16:01:24 +0200 Subject: [PATCH 0655/1872] make _mul_term_ faster --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d27d9c35e68..dc6332018f3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -787,7 +787,7 @@ def _mul_term_(self, term): sage: expr._mul_term_(t) O(x^3) """ - return self.parent()([term * elem for elem in self.summands.elements()], + return self.parent()(self.summands.mapped(lambda element: term * element), convert=False) From 02666527529b1c81e2d8e4ccb66dcfa69e8e912b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 16:08:51 +0200 Subject: [PATCH 0656/1872] log for expressions now also uses its keyword 'base' --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d5a9a57ee4d..9bc5ea5a52a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1158,7 +1158,7 @@ def log(self, base=None, prec=None): elif len(self.summands) == 1: if self == 1: return P(0) - return P(next(self.summands.elements()).log_term()) + return P(next(self.summands.elements()).log_term(base=base)) max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: @@ -1180,7 +1180,11 @@ def log(self, base=None, prec=None): if new_result.has_same_summands(result): expanding = False result = new_result - return log(P(max_elem)) + result + + result = log(P(max_elem)) + result + if base: + result = result / log(base) + return result class AsymptoticRing(sage.algebras.algebra.Algebra, From dc1dc116b1c7f01e09e1aa79a7a1c3285b626122 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 28 Aug 2015 16:13:54 +0200 Subject: [PATCH 0657/1872] prec --> precision --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index be9712357fd..3ad4c5f9c57 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1122,7 +1122,7 @@ def O(self): for element in self.summands.maximal_elements()) - def log(self, base=None, prec=None): + def log(self, base=None, precision=None): r""" The logarithm of this asymptotic expression. @@ -1132,7 +1132,7 @@ def log(self, base=None, prec=None): (default value) is used, the logarithm is the natural logarithm. - - ``prec`` -- the precision used for truncating the + - ``precision`` -- the precision used for truncating the expansion. If ``None`` (default value) is used, the default precision from the parent is used. @@ -1191,7 +1191,7 @@ def log(self, base=None, prec=None): k = 1 while expanding: k += 1 - new_result = (result - geom**k / k).truncate(prec=prec) + new_result = (result - geom**k / k).truncate(precision=precision) if new_result.has_same_summands(result): expanding = False result = new_result From 6c04529928efe00371a71cb4846b8c6f527ad108 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 16:33:41 +0200 Subject: [PATCH 0658/1872] fix lazy import problem when using short representations --- src/sage/rings/asymptotic/growth_group.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 34d80768f20..32c28439990 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -239,6 +239,11 @@ def repr_short_to_parent(s): except Exception as e: raise combine_exceptions( ValueError("Cannot create a parent out of '%s'." % (s,)), e) + + from sage.misc.lazy_import import LazyImport + if type(P) is LazyImport: + P = P._get_object() + from sage.structure.parent import is_Parent if not is_Parent(P): raise ValueError("'%s' does not describe a parent." % (s,)) From 1d023c6bafe1587bc7d1be94cd5318e20bcdbe17 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 16:57:29 +0200 Subject: [PATCH 0659/1872] import AsymptoticRing lazy --- src/sage/rings/asymptotic/all.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/all.py b/src/sage/rings/asymptotic/all.py index 554d02cc4d7..daf2b157307 100644 --- a/src/sage/rings/asymptotic/all.py +++ b/src/sage/rings/asymptotic/all.py @@ -1 +1,2 @@ -from asymptotic_ring import AsymptoticRing +from sage.misc.lazy_import import lazy_import +lazy_import('sage.rings.asymptotic.asymptotic_ring', 'AsymptoticRing') From e02895f024b31973ece986b90b2c06af5ab131bb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 17:14:35 +0200 Subject: [PATCH 0660/1872] remove some empty lines --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 -- src/sage/rings/asymptotic/term_monoid.py | 1 - 2 files changed, 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index dc6332018f3..fc946c753a0 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1086,7 +1086,6 @@ def __pow__(self, power): ' for the term %s.' % (self, )) - def O(self): r""" Convert all terms in this asymptotic expression to `O`-terms. @@ -1122,7 +1121,6 @@ def O(self): for element in self.summands.maximal_elements()) - class AsymptoticRing(sage.algebras.algebra.Algebra, sage.structure.unique_representation.UniqueRepresentation): r""" diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 3321d18f101..e4dae2b0cc1 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2001,7 +2001,6 @@ def _eq_(self, other): self.coefficient == other.coefficient - class TermWithCoefficientMonoid(GenericTermMonoid): r""" This class implements the base structure for parents of From 738f4ed1d2f3d1baceadd1e0ee243acbd44777c2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 17:15:22 +0200 Subject: [PATCH 0661/1872] explicitly use coefficient_ring(-1) in subtraction --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index fc946c753a0..601d1ab3c4e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -760,7 +760,7 @@ def _sub_(self, other): sage: O(x) - O(x) O(x) """ - return self + (-1)*other + return self + self.parent().coefficient_ring(-1)*other def _mul_term_(self, term): From ecf5ba8dbd91ae2a686a0f81705de253d1dbbf6c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 17:15:51 +0200 Subject: [PATCH 0662/1872] use simplify/convert everywhere explicit --- src/sage/rings/asymptotic/asymptotic_ring.py | 22 +++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 601d1ab3c4e..01e7f96a7ae 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -731,7 +731,8 @@ def _add_(self, other): sage: O(x) + x O(x) """ - return self.parent()(self.summands.union(other.summands), convert=False) + return self.parent()(self.summands.union(other.summands), + simplify=True, convert=False) def _sub_(self, other): @@ -787,8 +788,10 @@ def _mul_term_(self, term): sage: expr._mul_term_(t) O(x^3) """ + from term_monoid import OTerm + simplify = isinstance(term, OTerm) return self.parent()(self.summands.mapped(lambda element: term * element), - convert=False) + simplify=simplify, convert=False) def _mul_(self, other): @@ -928,14 +931,16 @@ def __invert__(self): element = next(self.summands.elements()) new_element = ~element if new_element.parent() is element.parent(): - return self.parent()(new_element) + return self.parent()(new_element, + simplify=False, convert=False) else: # Insert an 'if' here once terms can have different # coefficient rings, as this will be for L-terms. new_parent = self.parent().change_parameter( growth_group=new_element.parent().growth_group, coefficient_ring=new_element.parent().coefficient_ring) - return new_parent(new_element) + return new_parent(new_element, + simplify=False, convert=False) max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: @@ -1778,8 +1783,8 @@ def _an_element_(self): from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) - return self(E.an_element(), convert=False)**3 + \ - self(O.an_element(), convert=False) + return self(E.an_element(), simplify=False, convert=False)**3 + \ + self(O.an_element(), simplify=False, convert=False) def some_elements(self): @@ -1816,7 +1821,8 @@ def some_elements(self): from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) - return iter(self(e, convert=False)**3 + self(o, convert=False) + return iter(self(e, simplify=False, convert=False)**3 + + self(o, simplify=False, convert=False) for e, o in product_diagonal( E.some_elements(), O.some_elements())) @@ -1955,7 +1961,7 @@ def create_summand(self, type, data=None, **kwds): if type == 'exact' and kwds.get('coefficient') == 0: return self.zero() - return self(TM(data, **kwds), convert=False) + return self(TM(data, **kwds), simplify=False, convert=False) def variable_names(self): From 55d6ad3c66c8194781932756800a96bb35872648 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 21:03:11 +0200 Subject: [PATCH 0663/1872] restructure and rewrite classcall and init of growth group --- src/sage/rings/asymptotic/growth_group.py | 45 ++++++++++------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 32c28439990..9207af4a277 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1120,16 +1120,30 @@ def __classcall__(cls, base, var=None, category=None): sage: L1 is L2 True """ + from sage.categories.sets_cat import Sets + Sets_parent_class = Sets().parent_class + while issubclass(cls, Sets_parent_class): + cls = cls.__base__ + + if not isinstance(base, sage.structure.parent.Parent): + raise TypeError('%s is not a valid base.' % (base,)) + if var is None: var = Variable('') elif not isinstance(var, Variable): var = Variable(var) + + if category is None: + from sage.categories.monoids import Monoids + from sage.categories.posets import Posets + category = Monoids() & Posets() + return super(GenericGrowthGroup, cls).__classcall__( cls, base, var, category) @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, base, var, category=None): + def __init__(self, base, var, category): r""" See :class:`GenericGrowthElement` for more information. @@ -1168,56 +1182,37 @@ def __init__(self, base, var, category=None): sage: G2 = agg.GenericGrowthGroup(ZZ, category=FiniteGroups() & Posets()) sage: G2.category() Join of Category of finite groups and Category of finite posets - sage: G3 = agg.GenericGrowthGroup(ZZ, category=Rings()) - Traceback (most recent call last): - ... - ValueError: (Category of rings,) is not a subcategory of Join of Category of monoids and Category of posets :: sage: G = agg.GenericGrowthGroup('42') Traceback (most recent call last): ... - TypeError: 42 is not a valid base + TypeError: 42 is not a valid base. :: sage: agg.MonomialGrowthGroup('x', ZZ) Traceback (most recent call last): ... - ValueError: 'Integer Ring' is not a valid name for a variable. + TypeError: x is not a valid base. sage: agg.MonomialGrowthGroup('x', 'y') Traceback (most recent call last): ... - TypeError: x is not a valid base + TypeError: x is not a valid base. :: sage: agg.ExponentialGrowthGroup('x', ZZ) Traceback (most recent call last): ... - ValueError: 'Integer Ring' is not a valid name for a variable. + TypeError: x is not a valid base. sage: agg.ExponentialGrowthGroup('x', 'y') Traceback (most recent call last): ... - TypeError: x is not a valid base + TypeError: x is not a valid base. """ - if not isinstance(base, sage.structure.parent.Parent): - raise TypeError('%s is not a valid base' % (base,)) - from sage.categories.monoids import Monoids - from sage.categories.posets import Posets - - if category is None: - category = Monoids() & Posets() - else: - if not isinstance(category, tuple): - category = (category,) - if not any(cat.is_subcategory(Monoids() & Posets()) for cat in - category): - raise ValueError('%s is not a subcategory of %s' - % (category, Monoids() & Posets())) - self._var_ = var super(GenericGrowthGroup, self).__init__(category=category, base=base) From 3e449df91ab790796d1c20c2e5f09426014d8f95 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 21:04:27 +0200 Subject: [PATCH 0664/1872] solve non-uniquenessbug by rewriting classcall and init of term --- src/sage/rings/asymptotic/term_monoid.py | 98 ++++++++++++++---------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index e4dae2b0cc1..77b7b31230d 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -919,8 +919,8 @@ def _repr_(self): return 'Generic Term with growth ' + repr(self.growth) -class GenericTermMonoid(sage.structure.parent.Parent, - sage.structure.unique_representation.UniqueRepresentation): +class GenericTermMonoid(sage.structure.unique_representation.UniqueRepresentation, + sage.structure.parent.Parent): r""" Parent for generic asymptotic terms. @@ -964,71 +964,86 @@ class GenericTermMonoid(sage.structure.parent.Parent, # enable the category framework for elements Element = GenericTerm + + @staticmethod + def __classcall__(cls, growth_group, coefficient_ring, category=None): + r""" + Normalizes the input in order to ensure a unique + representation of the parent. + + TESTS:: + + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ') + sage: T = GenericTermMonoid(G, QQ) + sage: T.__class__(G, QQ) is T + True + """ + from sage.categories.sets_cat import Sets + Sets_parent_class = Sets().parent_class + while issubclass(cls, Sets_parent_class): + cls = cls.__base__ + + from sage.rings.asymptotic.growth_group import GenericGrowthGroup + if growth_group is None: + raise ValueError('No growth group specified.') + if not isinstance(growth_group, sage.structure.parent.Parent): + raise TypeError('%s is not a valid growth group.' % (growth_group,)) + + if coefficient_ring is None: + raise ValueError('No coefficient ring specified.') + if not isinstance(coefficient_ring, sage.structure.parent.Parent): + raise TypeError('%s is not a valid coefficient ring.' % (coefficient_ring,)) + + if category is None: + from sage.categories.monoids import Monoids + from sage.categories.posets import Posets + category = Monoids() & Posets() + + return super(GenericTermMonoid, cls).__classcall__( + cls, growth_group, coefficient_ring, category) + + @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, growth_group, coefficient_ring, category=None): + def __init__(self, growth_group, coefficient_ring, category): r""" See :class:`GenericTermMonoid` for more information. EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_x = agg.GrowthGroup('x^ZZ') - sage: T_x = atm.GenericTermMonoid(G_x, QQ); T_x + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid, TermWithCoefficientMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_x = GrowthGroup('x^ZZ') + sage: T_x = GenericTermMonoid(G_x, QQ); T_x Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: T_x.growth_group Growth Group x^ZZ - sage: G_y = agg.GrowthGroup('y^QQ') - sage: T_y = atm.GenericTermMonoid(G_y, QQ); T_y + sage: G_y = GrowthGroup('y^QQ') + sage: T_y = GenericTermMonoid(G_y, QQ); T_y Generic Term Monoid y^QQ with (implicit) coefficients in Rational Field sage: T_x is T_y False :: - sage: atm.GenericTermMonoid(None, None) + sage: GenericTermMonoid(None, None) Traceback (most recent call last): ... - ValueError: Growth Group has to be specified + ValueError: No growth group specified. :: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T_ZZ = atm.TermWithCoefficientMonoid(G, ZZ); T_ZZ + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T_ZZ = TermWithCoefficientMonoid(G, ZZ); T_ZZ Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring - sage: T_QQ = atm.TermWithCoefficientMonoid(G, QQ); T_QQ + sage: T_QQ = TermWithCoefficientMonoid(G, QQ); T_QQ Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: T_QQ.category() Join of Category of monoids and Category of posets """ - from sage.categories.monoids import Monoids - from sage.categories.posets import Posets - from sage.rings.asymptotic.growth_group import GenericGrowthGroup - - if category is None: - category = Monoids() & Posets() - else: - if not isinstance(category, tuple): - category = (category,) - if not any(cat.is_subcategory(Monoids() & Posets()) for cat in - category): - raise ValueError('%s is not a subcategory of %s' - % (category, Monoids() & Posets())) - - if growth_group is None: - raise ValueError('Growth Group has to be specified') - else: - if not isinstance(growth_group, GenericGrowthGroup): - raise ValueError('%s does not inherit from %s' - % (growth_group, GenericGrowthGroup())) self._growth_group_ = growth_group - - if coefficient_ring is None: - raise ValueError('Coefficient ring is not specified.') self._coefficient_ring_ = coefficient_ring - super(GenericTermMonoid, self).__init__(category=category) @@ -1655,6 +1670,7 @@ class OTermMonoid(GenericTermMonoid): sage: atm.TermMonoid('O', agg.GrowthGroup('x^QQ'), QQ) O-Term Monoid x^QQ with implicit coefficients in Rational Field """ + # enable the category framework for elements Element = OTerm @@ -2387,9 +2403,11 @@ class ExactTermMonoid(TermWithCoefficientMonoid): sage: atm.TermMonoid('exact', agg.GrowthGroup('x^ZZ'), QQ) Exact Term Monoid x^ZZ with coefficients in Rational Field """ + # enable the category framework for elements Element = ExactTerm + def _repr_(self): r""" A representation string for this exact term monoid. From 5068df9eca37c7c1ca557fcd89376d9657814ef1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 28 Aug 2015 21:05:04 +0200 Subject: [PATCH 0665/1872] rewrite classcall and init of asymptotic ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 32 +++++++++++--------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 01e7f96a7ae..b16a45676a7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1279,10 +1279,23 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, ValueError: Names 'x', 'y', 'z' do not coincide with generators 'x', 'y' of Growth Group x^ZZ * y^ZZ. """ + from sage.categories.sets_cat import Sets + Sets_parent_class = Sets().parent_class + while issubclass(cls, Sets_parent_class): + cls = cls.__base__ + if isinstance(growth_group, str): from sage.rings.asymptotic.growth_group import GrowthGroup growth_group = GrowthGroup(growth_group) + if growth_group is None: + raise ValueError('Growth group not specified. Cannot continue.') + + if coefficient_ring is None: + raise ValueError('Coefficient ring not specified. Cannot continue.') + if coefficient_ring not in sage.categories.rings.Rings(): + raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) + strgens = tuple(str(g) for g in growth_group.gens_monomial()) def format_names(N): return ('s ' if len(N) != 1 else ' ') + ', '.join("'%s'" % n for n in N) @@ -1295,17 +1308,16 @@ def format_names(N): raise ValueError('Name%s do not coincide with generator%s of %s.' % (format_names(names), format_names(strgens), growth_group)) - if default_prec is None: - from sage.misc.defaults import series_precision - default_prec = series_precision() - if category is None: from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.rings import Rings from sage.categories.posets import Posets - category = CommutativeAlgebras(Rings()) & Posets() + if default_prec is None: + from sage.misc.defaults import series_precision + default_prec = series_precision() + return super(AsymptoticRing, cls).__classcall__(cls, growth_group, coefficient_ring, category=category, @@ -1313,8 +1325,7 @@ def format_names(N): @sage.misc.superseded.experimental(trac_number=17601) - def __init__(self, growth_group, coefficient_ring, category=None, - default_prec=None): + def __init__(self, growth_group, coefficient_ring, category, default_prec): r""" See :class:`AsymptoticRing` for more information. @@ -1334,13 +1345,6 @@ def __init__(self, growth_group, coefficient_ring, category=None, ... TypeError: __classcall__() takes at least 3 arguments (2 given) """ - if growth_group is None: - raise ValueError('Growth group not specified. Cannot continue.') - elif coefficient_ring is None: - raise ValueError('Coefficient ring not specified. Cannot continue.') - elif coefficient_ring not in sage.categories.rings.Rings(): - raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) - self._coefficient_ring_ = coefficient_ring self._growth_group_ = growth_group self._default_prec_ = default_prec From c89b7c6ef04215e33ad810ab0a7936317233723a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 29 Aug 2015 08:50:59 +0200 Subject: [PATCH 0666/1872] trac #18175 fixing a typo in the doc --- src/sage/categories/metric_spaces.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index b1ca4144ea1..ed041469f6f 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -94,7 +94,7 @@ def _test_metric(self, **options): r""" Test that this metric space has a properly implemented metric. - INPUT:: + INPUT: - ``options`` -- any keyword arguments accepted by :meth:`_tester` From 328ec3d96b9ef2ed922586c046de4e7e993cdca2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 29 Aug 2015 16:38:48 +0200 Subject: [PATCH 0667/1872] new tool underlying_class --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +- src/sage/rings/asymptotic/growth_group.py | 44 ++++++++++++++++---- src/sage/rings/asymptotic/term_monoid.py | 14 +++---- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b16a45676a7..051e53be657 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1442,7 +1442,8 @@ def change_parameter(self, **kwds): if all(values[parameter] is getattr(self, parameter) for parameter in parameters) and values['category'] is self.category(): return self - return self.__class__(**values) + from sage.rings.asymptotic.growth_group import underlying_class + return underlying_class(self)(**values) @staticmethod diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 9207af4a277..0edf5eaa4d7 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -387,6 +387,37 @@ def combine_exceptions(e, *f): return e +def underlying_class(P): + r""" + Return the underlying class (class without the attached + categories) of the given instance. + + OUTPUT: + + A class. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import underlying_class + sage: type(QQ) + + sage: underlying_class(QQ) + + """ + cls = type(P) + if not P._is_category_initialized(): + return cls + from sage.structure.misc import is_extension_type + if is_extension_type(cls): + return cls + + from sage.categories.sets_cat import Sets + Sets_parent_class = Sets().parent_class + while issubclass(cls, Sets_parent_class): + cls = cls.__base__ + return cls + + class Variable(sage.structure.unique_representation.CachedRepresentation, sage.structure.sage_object.SageObject): r""" @@ -1120,11 +1151,6 @@ def __classcall__(cls, base, var=None, category=None): sage: L1 is L2 True """ - from sage.categories.sets_cat import Sets - Sets_parent_class = Sets().parent_class - while issubclass(cls, Sets_parent_class): - cls = cls.__base__ - if not isinstance(base, sage.structure.parent.Parent): raise TypeError('%s is not a valid base.' % (base,)) @@ -2081,8 +2107,8 @@ def __invert__(self): if new_element.parent() is self.exponent.parent(): return self.parent()(raw_element=new_element) else: - new_parent = self.parent().__class__(new_element.parent(), - self.parent()._var_) + new_parent = underlying_class(self.parent())(new_element.parent(), + self.parent()._var_) return new_parent(raw_element=new_element) @@ -2637,8 +2663,8 @@ def __invert__(self): if new_element.parent() is self.base.parent(): return self.parent()(raw_element=new_element) else: - new_parent = self.parent().__class__(new_element.parent(), - self.parent()._var_) + new_parent = underlying_class(self.parent())(new_element.parent(), + self.parent()._var_) return new_parent(raw_element=new_element) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 77b7b31230d..1b7bb7fd19a 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -977,14 +977,10 @@ def __classcall__(cls, growth_group, coefficient_ring, category=None): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ') sage: T = GenericTermMonoid(G, QQ) - sage: T.__class__(G, QQ) is T + sage: from sage.rings.asymptotic.growth_group import underlying_class + sage: underlying_class(T)(G, QQ) is T True """ - from sage.categories.sets_cat import Sets - Sets_parent_class = Sets().parent_class - while issubclass(cls, Sets_parent_class): - cls = cls.__base__ - from sage.rings.asymptotic.growth_group import GenericGrowthGroup if growth_group is None: raise ValueError('No growth group specified.') @@ -2278,7 +2274,8 @@ def __invert__(self): if c.parent() is self.coefficient.parent() and g.parent() is self.growth.parent(): return self.parent()(g, c) else: - new_parent = self.parent().__class__(g.parent(), c.parent()) + from sage.rings.asymptotic.growth_group import underlying_class + new_parent = underlying_class(self.parent())(g.parent(), c.parent()) return new_parent(g, c) @@ -2493,7 +2490,8 @@ def create_key_and_extra_args(self, term, to create a term monoid of type 'exact' """ if isinstance(term, GenericTermMonoid): - term_class = term.__class__ + from sage.rings.asymptotic.growth_group import underlying_class + term_class = underlying_class(term) elif term == 'O': term_class = OTermMonoid elif term == 'exact': From 6b492746920474de256bbfd6fed228f22953237c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 09:55:13 +0200 Subject: [PATCH 0668/1872] growth group: create element via parent method --- src/sage/rings/asymptotic/growth_group.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 0edf5eaa4d7..36c0dfe689a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1393,6 +1393,38 @@ def some_elements(self): for e in self.base().some_elements()) + def _create_element_via_parent_(self, raw_element, old_parent=None): + r""" + Create an element with a possibly other parent. + + INPUT: + + - ``raw_element`` -- the element data. + + - ``old_parent`` -- the parent of ``raw_element`` is compared to ``old_parent``. + + OUTPUT: + + An element. + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: G._create_element_via_parent_(3).parent() + Growth Group z^ZZ + sage: G._create_element_via_parent_(1/2).parent() + Traceback (most recent call last): + ... + TypeError: no conversion of this rational to integer + sage: G._create_element_via_parent_(1/2, ZZ).parent() + Growth Group z^QQ + """ + if old_parent is None or raw_element.parent() is old_parent: + parent = self + else: + parent = underlying_class(self)(raw_element.parent(), self._var_) + return parent(raw_element=raw_element) + + def le(self, left, right): r""" Return if the growth of ``left`` is at most (less than or From 865fa46eccbb13f8ef6a2c9faa6ee0545d0caf1b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 09:55:49 +0200 Subject: [PATCH 0669/1872] adapt __pow__ --- src/sage/rings/asymptotic/growth_group.py | 56 +++++++---------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 36c0dfe689a..f14e19efa49 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2136,21 +2136,16 @@ def __invert__(self): True """ new_element = -self.exponent - if new_element.parent() is self.exponent.parent(): - return self.parent()(raw_element=new_element) - else: - new_parent = underlying_class(self.parent())(new_element.parent(), - self.parent()._var_) - return new_parent(raw_element=new_element) + return self.parent()._create_element_via_parent_(-self.exponent, self.exponent.parent()) - def __pow__(self, power): + def __pow__(self, exponent): r""" - Raises this growth element to the given ``power``. + Calculate the power of this growth element to the given ``exponent``. INPUT: - - ``power`` -- a number. This can be anything that is a + - ``exponent`` -- a number. This can be anything that is a valid right hand side of ``*`` with elements of the parent's base. @@ -2160,28 +2155,22 @@ def __pow__(self, power): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: x = P.gen() sage: a = x^7; a x^7 sage: a^(1/2) - Traceback (most recent call last): - ... - ValueError: Growth Group x^ZZ disallows taking x^7 to the power of 1/2. - sage: P = agg.MonomialGrowthGroup(QQ, 'x') + x^(7/2) + sage: (a^(1/2)).parent() + Growth Group x^QQ + sage: P = GrowthGroup('x^QQ') sage: b = P.gen()^(7/2); b x^(7/2) sage: b^12 x^42 """ - new_exponent = self.exponent * power - P = self.parent() - if new_exponent in P.base(): - return P(raw_element=new_exponent) - else: - raise ValueError('%s disallows taking %s to the power ' - 'of %s.' % (P, self, power)) + return self.parent()._create_element_via_parent_(self.exponent * exponent, self.exponent.parent()) def _le_(self, other): @@ -2692,21 +2681,16 @@ def __invert__(self): Growth Group QQ^x """ new_element = 1 / self.base - if new_element.parent() is self.base.parent(): - return self.parent()(raw_element=new_element) - else: - new_parent = underlying_class(self.parent())(new_element.parent(), - self.parent()._var_) - return new_parent(raw_element=new_element) + return self.parent()._create_element_via_parent_(1 / self.base, self.base.parent()) - def __pow__(self, power): + def __pow__(self, exponent): r""" - Takes this growth element to the given ``power``. + Calculate the power of this growth element to the given ``exponent``. INPUT: - - ``power`` -- a number. This can anything that is valid to be + - ``exponent`` -- a number. This can anything that is valid to be on the right hand side of ``*`` with an elements of the parent's base. @@ -2727,15 +2711,7 @@ def __pow__(self, power): sage: b^12 117649^x """ - new_base = self.base ** power - try: - return self.parent()(raw_element=new_base) - except (ValueError, TypeError): - pass - - new_parent = ExponentialGrowthGroup(new_base.parent(), - self.parent()._var_) - return new_parent(raw_element=new_base) + return self.parent()._create_element_via_parent_(self.base ** exponent, self.base.parent()) def _le_(self, other): From 9cc304cabc062e9f0b3ed026caa6de50522ee604 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 09:56:34 +0200 Subject: [PATCH 0670/1872] create element via parent in term --- src/sage/rings/asymptotic/term_monoid.py | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 1b7bb7fd19a..a22213287e8 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1302,6 +1302,43 @@ def _create_element_(self, growth, coefficient): return self.element_class(self, growth) + def _create_element_via_parent_(self, growth, coefficient, + old_parent_growth=None, old_parent_coefficient=None): + r""" + Create an element with a possibly other parent. + + INPUT: + + - ``raw_element`` -- the element data. + + - ``old_parent`` -- the parent of ``raw_element`` is compared to ``old_parent``. + + OUTPUT: + + An element. + + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: T = TermMonoid('exact', G, ZZ) + sage: T._create_element_via_parent_(G.an_element(), 3, G, ZZ) + 3*z + sage: T._create_element_via_parent_(G.an_element(), 3/2, G, ZZ).parent() + Exact Term Monoid z^ZZ with coefficients in Rational Field + """ + if (old_parent_growth is None or growth.parent() is old_parent_growth) and \ + (old_parent_coefficient is None or + coefficient is not None and coefficient.parent() is old_parent_coefficient): + parent = self + else: + from sage.rings.asymptotic.growth_group import underlying_class + parent = underlying_class(self)(growth.parent(), + coefficient.parent() + if coefficient is not None + else old_parent_coefficient) + return parent(growth, coefficient) + + def _split_growth_and_coefficient_(self, data): r""" Split given ``data`` into a growth element and a coefficient. From ecdeebed79aff72d2e8ccfb0dd1a6efa0c8f0607 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 09:56:58 +0200 Subject: [PATCH 0671/1872] __pow__ & co for terms --- src/sage/rings/asymptotic/term_monoid.py | 216 ++++++++++++++++++++++- 1 file changed, 208 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index a22213287e8..f21ffc209a7 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -445,6 +445,122 @@ def __invert__(self): '(in this abstract method).' % (self,)) + def __pow__(self, exponent): + r""" + Calculate the power of this element to the given ``exponent``. + + INPUT: + + - ``exponent`` -- an element. + + OUTPUT: + + Raise a :class:`NotImplementedError` since it is an abstract base class. + + TESTS:: + + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: t = GenericTermMonoid(G, ZZ).an_element(); t + Generic Term with growth z + sage: t^3 # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: Taking powers of Generic Term with growth z + not implemented (in this abstract method). + """ + raise NotImplementedError('Taking powers of %s not implemented ' + '(in this abstract method).' % (self,)) + + + def _calculate_pow_test_zero_(self, exponent): + r""" + Helper function for :meth:`__pow__` which calculates the power of this + element to the given ``exponent`` only if zero to this exponent is possible. + + INPUT: + + - ``exponent`` -- an element. + + OUTPUT: + + A term. + + TESTS:: + + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: t = GenericTermMonoid(G, ZZ).an_element(); t + Generic Term with growth z + sage: t._calculate_pow_test_zero_(3) + Generic Term with growth z^3 + sage: t._calculate_pow_test_zero_(-2) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot take Generic Term with growth z to exponent -2. + > *previous* ZeroDivisionError: Rational division by zero + """ + zero = self.parent().coefficient_ring.zero() + try: + _ = zero ** exponent + except (TypeError, ValueError, ZeroDivisionError) as e: + from sage.rings.asymptotic.growth_group import combine_exceptions + raise combine_exceptions( + ZeroDivisionError('Cannot take %s to exponent %s.' % (self, exponent)), e) + return self._calculate_pow_(exponent) + + + def _calculate_pow_(self, exponent, coefficient=None): + r""" + Helper function for :meth:`__pow__` which calculates the power of this + element to the given ``exponent``. + + INPUT: + + - ``exponent`` -- an element. + + - ``coefficient`` -- if not ``None`` this is passed on to the + construction of the element (in particular, not taken to any power). + + OUTPUT: + + A term. + + TESTS:: + + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: t = GenericTermMonoid(G, ZZ).an_element(); t + Generic Term with growth z + sage: t._calculate_pow_(3) + Generic Term with growth z^3 + sage: t._calculate_pow_(3, coefficient=2) + Traceback (most recent call last): + ... + ValueError: Coefficient 2 is not 1, but Generic Term Monoid z^ZZ with + (implicit) coefficients in Integer Ring does not support coefficients. + sage: t._calculate_pow_(-2) + Generic Term with growth z^(-2) + sage: t._calculate_pow_(-2, coefficient=2) + Traceback (most recent call last): + ... + ValueError: Coefficient 2 is not 1, but Generic Term Monoid z^ZZ with + (implicit) coefficients in Integer Ring does not support coefficients. + """ + try: + g = self.growth ** exponent + except (ValueError, TypeError, ZeroDivisionError) as e: + from sage.rings.asymptotic.growth_group import combine_exceptions + raise combine_exceptions( + ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) + + return self.parent()._create_element_via_parent_( + g, coefficient, self.parent().growth_group, self.parent().coefficient_ring) + + def can_absorb(self, other): r""" Check, whether this asymptotic term is able to absorb @@ -829,8 +945,6 @@ def __eq__(self, other): sage: g = GT.an_element(); e = ET.an_element(); o = OT.an_element() sage: g, e, o (Generic Term with growth x, x, O(x)) - sage: g == g^2 # indirect doctest - False sage: e == e^2 # indirect doctest False sage: e == ET(x,1) # indirect doctest @@ -1599,6 +1713,33 @@ def __invert__(self): raise ZeroDivisionError('Cannot invert %s.' % (self,)) + def __pow__(self, exponent): + r""" + Calculate the power of this :class:`OTerm` to the given ``exponent``. + + INPUT: + + - ``exponent`` -- an element. + + OUTPUT: + + An :class:`OTerm`. + + TESTS:: + + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: t = TermMonoid('O', G, ZZ).an_element(); t + O(z) + sage: t^3 # indirect doctest + O(z^3) + sage: t^(1/2) # indirect doctest + O(z^(1/2)) + """ + return self._calculate_pow_test_zero_(exponent) + + def _can_absorb_(self, other): r""" Check, whether this `O`-term can absorb ``other``. @@ -1964,6 +2105,42 @@ def _mul_(self, other): self.coefficient * other.coefficient) + def _calculate_pow_(self, exponent): + r""" + Helper function for :meth:`__pow__` which calculates the power of this + element to the given ``exponent``. + + INPUT: + + - ``exponent`` -- an element. + + OUTPUT: + + A term. + + TESTS:: + + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: t = TermWithCoefficientMonoid(G, ZZ).an_element(); t + Asymptotic Term with coefficient 1 and growth z + sage: t._calculate_pow_(3) + Asymptotic Term with coefficient 1 and growth z^3 + sage: t._calculate_pow_(-2) + Asymptotic Term with coefficient 1 and growth z^(-2) + """ + try: + c = self.coefficient ** exponent + except (TypeError, ValueError, ZeroDivisionError) as e: + from sage.rings.asymptotic.growth_group import combine_exceptions + raise combine_exceptions( + ZeroDivisionError('Cannot take %s to the exponent %s since its ' + 'coefficient %s cannot be taken to this exponent.' % + (self, exponent, self.coefficient)), e) + return super(TermWithCoefficient, self)._calculate_pow_(exponent, coefficient=c) + + def _le_(self, other): r""" Return whether this asymptotic term with coefficient grows @@ -2308,12 +2485,35 @@ def __invert__(self): raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' 'cannot be inverted.' % (self, self.coefficient)) g = ~self.growth - if c.parent() is self.coefficient.parent() and g.parent() is self.growth.parent(): - return self.parent()(g, c) - else: - from sage.rings.asymptotic.growth_group import underlying_class - new_parent = underlying_class(self.parent())(g.parent(), c.parent()) - return new_parent(g, c) + return self.parent()._create_element_via_parent_( + g, c, self.parent().growth_group, self.parent().coefficient_ring) + + + def __pow__(self, exponent): + r""" + Calculate the power of this :class:`ExactTerm` to the given ``exponent``. + + INPUT: + + - ``exponent`` -- an element. + + OUTPUT: + + An :class:`ExactTerm`. + + TESTS:: + + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: t = TermMonoid('exact', G, ZZ).an_element(); t + z + sage: t^3 # indirect doctest + z^3 + sage: t^(1/2) # indirect doctest + z^(1/2) + """ + return self._calculate_pow_(exponent) def _can_absorb_(self, other): From 25231e1e401700b1d6ea0e251234158df9562d5f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 10:01:32 +0200 Subject: [PATCH 0672/1872] rewrite __pow__ of asymptotic ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 75 +++++++++++--------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 051e53be657..50982e62d57 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1025,13 +1025,13 @@ def convert_terms(element): return self.parent()(summands, simplify=True, convert=False) - def __pow__(self, power): + def __pow__(self, exponent): r""" - Takes this element to the given ``power``. + Calculate the power of this element to the given ``exponent``. INPUT: - - ``power`` -- an element. + - ``exponent`` -- an element. OUTPUT: @@ -1044,9 +1044,9 @@ def __pow__(self, power): x^(1/7) sage: R_ZZ. = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=ZZ) sage: y^(1/7) - Traceback (most recent call last): - ... - ValueError: Growth Group y^ZZ disallows taking y to the power of 1/7. + y^(1/7) + sage: (y^(1/7)).parent() + Asymptotic Ring over Rational Field sage: (x^(1/2) + O(x^0))^15 x^(15/2) + O(x^7) @@ -1057,38 +1057,47 @@ def __pow__(self, power): ... ZeroDivisionError: Cannot invert O(x). """ + if not self.summands: + if exponent == 0: + return self.parent().one() + elif exponent > 0: + return self.parent().zero() + elif exponent < 0: + raise ZeroDivisionError('Cannot take %s to the negative exponent %s.' % + (self, exponent)) + else: + raise NotImplementedError('Taking %s to the exponent %s not implemented.' % + (self, exponent)) + + elif len(self.summands) == 1: + element = next(self.summands.elements()) + new_element = element ** exponent + if new_element.parent() is element.parent(): + return self.parent()(new_element, + simplify=False, convert=False) + else: + # Insert an 'if' here once terms can have different + # coefficient rings, as this will be for L-terms. + new_parent = self.parent().change_parameter( + growth_group=new_element.parent().growth_group, + coefficient_ring=new_element.parent().coefficient_ring) + return new_parent(new_element, + simplify=False, convert=False) + from sage.rings.integer_ring import ZZ try: - power = ZZ(power) + exponent = ZZ(exponent) except (TypeError, ValueError): pass else: - return super(AsymptoticExpression, self).__pow__(power) - - if len(self.summands) > 1: - raise NotImplementedError('Taking the sum %s to the ' - 'non-integer power %s not ' - 'implemented.' % (self, power)) - expr = next(self.summands.elements()) - - P = self.parent() - if power not in P.growth_group.base(): - raise ValueError('%s disallows taking %s ' - 'to the power of %s.' % - (P.growth_group, self, power)) - - from sage.rings.asymptotic.term_monoid import TermWithCoefficient - if isinstance(expr, TermWithCoefficient): - new_growth = expr.growth**power - new_coeff = expr.coefficient**power - return P(expr.parent()(new_growth, new_coeff)) - else: - if power >= 0: - new_growth = expr.growth**power - return P(expr.parent()(new_growth)) - else: - raise NotImplementedError('Negative powers are not implemented' - ' for the term %s.' % (self, )) + return super(AsymptoticExpression, self).__pow__(exponent) + + try: + return (exponent * self.log()).exp() + except (TypeError, ValueError, ZeroDivisionError) as e: + from sage.rings.asymptotic.growth_group import combine_exceptions + raise combine_exceptions( + ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) def O(self): From 5408f6da96e9f9aa1a7685affe9c110d5264b26d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 10:07:29 +0200 Subject: [PATCH 0673/1872] Asymptotic Term with ... --> Term with ... --- src/sage/rings/asymptotic/term_monoid.py | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index f21ffc209a7..4ecea3cf392 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1329,7 +1329,7 @@ def _element_constructor_(self, data, coefficient=None): sage: G = agg.GrowthGroup('x^ZZ') sage: T = atm.TermWithCoefficientMonoid(G, ZZ) sage: t1 = T(x^2, 5); t1 # indirect doctest - Asymptotic Term with coefficient 5 and growth x^2 + Term with coefficient 5 and growth x^2 TESTS:: @@ -1340,23 +1340,23 @@ def _element_constructor_(self, data, coefficient=None): :: sage: T(G.gen()^10) - Asymptotic Term with coefficient 1 and growth x^10 + Term with coefficient 1 and growth x^10 sage: T(G.gen()^10, coefficient=10) - Asymptotic Term with coefficient 10 and growth x^10 + Term with coefficient 10 and growth x^10 sage: T(x^123) - Asymptotic Term with coefficient 1 and growth x^123 + Term with coefficient 1 and growth x^123 :: sage: T(x) - Asymptotic Term with coefficient 1 and growth x + Term with coefficient 1 and growth x :: sage: G_log = agg.GrowthGroup('log(x)^ZZ') sage: T_log = atm.TermWithCoefficientMonoid(G_log, ZZ) sage: T_log(log(x)) - Asymptotic Term with coefficient 1 and growth log(x) + Term with coefficient 1 and growth log(x) """ if type(data) == self.element_class and data.parent() == self: @@ -1976,9 +1976,9 @@ class TermWithCoefficient(GenericTerm): sage: CT_ZZ = atm.TermWithCoefficientMonoid(G, ZZ) sage: CT_QQ = atm.TermWithCoefficientMonoid(G, QQ) sage: CT_ZZ(x^2, 5) - Asymptotic Term with coefficient 5 and growth x^2 + Term with coefficient 5 and growth x^2 sage: CT_QQ(x^3, 3/8) - Asymptotic Term with coefficient 3/8 and growth x^3 + Term with coefficient 3/8 and growth x^3 """ def __init__(self, parent, growth, coefficient): @@ -2003,7 +2003,7 @@ def __init__(self, parent, growth, coefficient): ValueError: 1/2 is not a coefficient in Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring. sage: t = CT_QQ(x, 1/2); t - Asymptotic Term with coefficient 1/2 and growth x + Term with coefficient 1/2 and growth x For technical reasons, the coefficient 0 is not allowed:: @@ -2019,7 +2019,7 @@ def __init__(self, parent, growth, coefficient): sage: x = SR('x'); x.parent() Symbolic Ring sage: CT_ZZ(x^42, 42) - Asymptotic Term with coefficient 42 and growth x^42 + Term with coefficient 42 and growth x^42 """ try: coefficient = parent.coefficient_ring(coefficient) @@ -2053,9 +2053,9 @@ def _repr_(self): sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() sage: T = atm.TermWithCoefficientMonoid(G, ZZ) sage: T(x^2, 5)._repr_() - 'Asymptotic Term with coefficient 5 and growth x^2' + 'Term with coefficient 5 and growth x^2' """ - return 'Asymptotic Term with coefficient %s and growth %s' % \ + return 'Term with coefficient %s and growth %s' % \ (self.coefficient, self.growth) @@ -2093,7 +2093,7 @@ def _mul_(self, other): sage: t1 = CT(x^2, 2); t2 = CT(x^3, 3) sage: t1 * t2 - Asymptotic Term with coefficient 6 and growth x^5 + Term with coefficient 6 and growth x^5 And now, an example for exact terms:: @@ -2124,11 +2124,11 @@ def _calculate_pow_(self, exponent): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') sage: t = TermWithCoefficientMonoid(G, ZZ).an_element(); t - Asymptotic Term with coefficient 1 and growth z + Term with coefficient 1 and growth z sage: t._calculate_pow_(3) - Asymptotic Term with coefficient 1 and growth z^3 + Term with coefficient 1 and growth z^3 sage: t._calculate_pow_(-2) - Asymptotic Term with coefficient 1 and growth z^(-2) + Term with coefficient 1 and growth z^(-2) """ try: c = self.coefficient ** exponent @@ -2215,7 +2215,7 @@ def _eq_(self, other): sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), ZZ) sage: t = T.an_element(); t - Asymptotic Term with coefficient 1 and growth x + Term with coefficient 1 and growth x sage: t == T(x, 1) True sage: t == T(x, 2) @@ -2312,7 +2312,7 @@ def _an_element_(self): sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GrowthGroup('x^ZZ') sage: atm.TermWithCoefficientMonoid(G, ZZ).an_element() # indirect doctest - Asymptotic Term with coefficient 1 and growth x + Term with coefficient 1 and growth x sage: atm.ExactTermMonoid(G, ZZ).an_element() # indirect doctest x sage: atm.ExactTermMonoid(G, QQ).an_element() # indirect doctest From 8730ab82860cffa5e7aa11f8a57d0b58ea849329 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 11:18:39 +0200 Subject: [PATCH 0674/1872] creation of element via parent method for ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 34 ++++++++++++++++++++ src/sage/rings/asymptotic/growth_group.py | 3 +- src/sage/rings/asymptotic/term_monoid.py | 6 ++-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 50982e62d57..fc6c343a31a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1482,6 +1482,40 @@ def _create_empty_summands_(): merge=absorption) + def _create_element_via_parent_(self, term, old_parent=None): + r""" + Create an element with a possibly other parent. + + INPUT: + + - ``term`` -- the element data. + + - ``old_parent`` -- the parent of ``term`` is compared to this parent. + + OUTPUT: + + An element. + + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ') + sage: T = TermMonoid('exact', G, ZZ) + sage: T._create_element_via_parent_(G.an_element(), 3, G, ZZ) + 3*z + sage: T._create_element_via_parent_(G.an_element(), 3/2, G, ZZ).parent() + Exact Term Monoid z^ZZ with coefficients in Rational Field + """ + if old_parent is None or term.parent() is old_parent: + parent = self + else: + # Insert an 'if' here once terms can have different + # coefficient rings, as this will be for L-terms. + parent = self.change_parameter( + growth_group=term.parent().growth_group, + coefficient_ring=term.parent().coefficient_ring) + return parent(term, simplify=False, convert=False) + + def _element_constructor_(self, data, simplify=True, convert=True): r""" Convert a given object to this asymptotic ring. diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index f14e19efa49..6abba26f5ed 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1401,7 +1401,8 @@ def _create_element_via_parent_(self, raw_element, old_parent=None): - ``raw_element`` -- the element data. - - ``old_parent`` -- the parent of ``raw_element`` is compared to ``old_parent``. + - ``old_parent`` -- the parent of ``raw_element`` is compared + to this parent. OUTPUT: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 4ecea3cf392..93e4c891dcc 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1423,9 +1423,11 @@ def _create_element_via_parent_(self, growth, coefficient, INPUT: - - ``raw_element`` -- the element data. + - ``growth`` and ``coefficient`` -- the element data. - - ``old_parent`` -- the parent of ``raw_element`` is compared to ``old_parent``. + - ``old_parent_growth`` and ``old_parent_coefficient`` -- the + parents of ``growth`` and ``coefficient`` are compared to + these parents. OUTPUT: From ac3d1ecc01dc2a11f429e67217f0ccd8e8f15d55 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 11:19:02 +0200 Subject: [PATCH 0675/1872] adapt __pow__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 39 ++++---------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index fc6c343a31a..287c0f7d2c2 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -929,35 +929,22 @@ def __invert__(self): elif len(self.summands) == 1: element = next(self.summands.elements()) - new_element = ~element - if new_element.parent() is element.parent(): - return self.parent()(new_element, - simplify=False, convert=False) - else: - # Insert an 'if' here once terms can have different - # coefficient rings, as this will be for L-terms. - new_parent = self.parent().change_parameter( - growth_group=new_element.parent().growth_group, - coefficient_ring=new_element.parent().coefficient_ring) - return new_parent(new_element, - simplify=False, convert=False) + return self.parent()._create_element_via_parent_( + ~element, element.parent()) max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: raise ValueError('Expression %s cannot be inverted, since there ' - 'are several maximal elements: %s.' % (self, max_elem)) + 'are several maximal elements: %s.' % + (self, max_elem)) max_elem = max_elem[0] imax_elem = ~max_elem if imax_elem.parent() is max_elem.parent(): new_self = self else: - # Insert an 'if' here once terms can have different - # coefficient rings, as this will be for L-terms. - new_parent = self.parent().change_parameter( - growth_group=imax_elem.parent().growth_group, - coefficient_ring=imax_elem.parent().coefficient_ring) - new_self = new_parent(self) + new_self = self.parent()._create_element_via_parent_( + imax_elem, max_elem.parent()).parent()(self) one = new_self.parent().one() geom = one - new_self._mul_term_(imax_elem) @@ -1071,18 +1058,8 @@ def __pow__(self, exponent): elif len(self.summands) == 1: element = next(self.summands.elements()) - new_element = element ** exponent - if new_element.parent() is element.parent(): - return self.parent()(new_element, - simplify=False, convert=False) - else: - # Insert an 'if' here once terms can have different - # coefficient rings, as this will be for L-terms. - new_parent = self.parent().change_parameter( - growth_group=new_element.parent().growth_group, - coefficient_ring=new_element.parent().coefficient_ring) - return new_parent(new_element, - simplify=False, convert=False) + return self.parent()._create_element_via_parent_( + element ** exponent, element.parent()) from sage.rings.integer_ring import ZZ try: From fff27dac077532ac55902a28fe52e3eecc49e581 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 11:21:59 +0200 Subject: [PATCH 0676/1872] fix FloatingPointException (vs. ZeroDivisonError) still one blank line appearing --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 ++- src/sage/rings/asymptotic/term_monoid.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 287c0f7d2c2..e35d03830c7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1042,7 +1042,8 @@ def __pow__(self, exponent): sage: O(x)^(-1) Traceback (most recent call last): ... - ZeroDivisionError: Cannot invert O(x). + ZeroDivisionError: Cannot take O(x) to exponent -1. + > *previous* FloatingPointError: Floating point exception. """ if not self.summands: if exponent == 0: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 93e4c891dcc..34dc57e3065 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -505,10 +505,12 @@ def _calculate_pow_test_zero_(self, exponent): zero = self.parent().coefficient_ring.zero() try: _ = zero ** exponent - except (TypeError, ValueError, ZeroDivisionError) as e: + except (TypeError, ValueError, + ZeroDivisionError, FloatingPointError) as e: from sage.rings.asymptotic.growth_group import combine_exceptions raise combine_exceptions( - ZeroDivisionError('Cannot take %s to exponent %s.' % (self, exponent)), e) + ZeroDivisionError('Cannot take %s to exponent %s.' % + (self, exponent)), e) return self._calculate_pow_(exponent) From 1097dee3e9ae5596a2af6a97e40aeda968d80227 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 11:31:39 +0200 Subject: [PATCH 0677/1872] create misc.py and move functions from other files to this file --- src/sage/rings/asymptotic/growth_group.py | 218 --------- .../asymptotic/growth_group_cartesian.py | 100 ---- src/sage/rings/asymptotic/misc.py | 444 ++++++++++++++++++ src/sage/rings/asymptotic/term_monoid.py | 116 ----- 4 files changed, 444 insertions(+), 434 deletions(-) create mode 100644 src/sage/rings/asymptotic/misc.py diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6abba26f5ed..ebd6b674739 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -200,224 +200,6 @@ lazy_import('sage.rings.asymptotic.growth_group_cartesian', 'CartesianProductGrowthGroups') -def repr_short_to_parent(s): - r""" - Helper method for the growth group factory, which converts a short - representation string to a parent. - - INPUT: - - A string. - - OUTPUT: - - A parent. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.repr_short_to_parent('ZZ') - Integer Ring - sage: agg.repr_short_to_parent('QQ') - Rational Field - sage: agg.repr_short_to_parent('SR') - Symbolic Ring - sage: agg.repr_short_to_parent('NN') - Non negative integer semiring - - TESTS:: - - sage: agg.repr_short_to_parent('abcdef') - Traceback (most recent call last): - ... - ValueError: Cannot create a parent out of 'abcdef'. - > *previous* NameError: name 'abcdef' is not defined - """ - from sage.misc.sage_eval import sage_eval - try: - P = sage_eval(s) - except Exception as e: - raise combine_exceptions( - ValueError("Cannot create a parent out of '%s'." % (s,)), e) - - from sage.misc.lazy_import import LazyImport - if type(P) is LazyImport: - P = P._get_object() - - from sage.structure.parent import is_Parent - if not is_Parent(P): - raise ValueError("'%s' does not describe a parent." % (s,)) - return P - - -def parent_to_repr_short(P): - r""" - Helper method which generates a short(er) representation string - out of a parent. - - INPUT: - - A parent. - - OUTPUT: - - A string. - - EXAMPLES:: - - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.parent_to_repr_short(ZZ) - 'ZZ' - sage: agg.parent_to_repr_short(QQ) - 'QQ' - sage: agg.parent_to_repr_short(SR) - 'SR' - sage: agg.parent_to_repr_short(ZZ[x]) - '(Univariate Polynomial Ring in x over Integer Ring)' - """ - if P is sage.rings.integer_ring.ZZ: - return 'ZZ' - elif P is sage.rings.rational_field.QQ: - return 'QQ' - elif P is sage.symbolic.ring.SR: - return 'SR' - else: - rep = repr(P) - if ' ' in rep: - rep = '(' + rep + ')' - return rep - - -def split_str_by_mul(string): - r""" - Split the given string into a tuple of substrings arising by - splitting by '*' and taking care of parentheses. - - INPUT: - - - ``string`` - a string. - - OUTPUT: - - A tuple of strings. - - TESTS:: - - sage: from sage.rings.asymptotic.growth_group import split_str_by_mul - sage: split_str_by_mul('x^ZZ') - ('x^ZZ',) - sage: split_str_by_mul('log(x)^ZZ * y^QQ') - ('log(x)^ZZ', 'y^QQ') - sage: split_str_by_mul('log(x)**ZZ * y**QQ') - ('log(x)**ZZ', 'y**QQ') - sage: split_str_by_mul('a^b * * c^d') - Traceback (most recent call last): - ... - ValueError: 'a^b * * c^d' is invalid since a '*' follows a '*' - sage: split_str_by_mul('a^b * (c*d^e)') - ('a^b', 'c*d^e') - """ - factors = list() - balanced = True - if string and string[0] == '*': - raise ValueError("'%s' is invalid since it starts with a '*'." % - (string,)) - for s in string.split('*'): - if not s: - factors[-1] += '*' - balanced = False - continue - if not s.strip(): - raise ValueError("'%s' is invalid since a '*' follows a '*'" % - (string,)) - if not balanced: - s = factors.pop() + '*' + s - balanced = s.count('(') == s.count(')') - factors.append(s) - - if not balanced: - raise ValueError("Parentheses in '%s' are not balanced" % (string,)) - - def strip(s): - s = s.strip() - if not s: - return s - if s[0] == '(' and s[-1] == ')': - s = s[1:-1] - return s.strip() - - return tuple(strip(f) for f in factors) - - -def combine_exceptions(e, *f): - r""" - Helper function which combines the messages of the given exceptions. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import combine_exceptions - sage: raise combine_exceptions(ValueError('Outer.'), TypeError('Inner.')) - Traceback (most recent call last): - ... - ValueError: Outer. - > *previous* TypeError: Inner. - sage: raise combine_exceptions(ValueError('Outer.'), - ....: TypeError('Inner1.'), TypeError('Inner2.')) - Traceback (most recent call last): - ... - ValueError: Outer. - > *previous* TypeError: Inner1. - > *and* TypeError: Inner2. - sage: raise combine_exceptions(ValueError('Outer.'), - ....: combine_exceptions(TypeError('Middle.'), - ....: TypeError('Inner.'))) - Traceback (most recent call last): - ... - ValueError: Outer. - > *previous* TypeError: Middle. - >> *previous* TypeError: Inner. - """ - import re - msg = ('\n *previous* ' + - '\n *and* '.join("%s: %s" % (ff.__class__.__name__, str(ff)) for ff in f)) - msg = re.sub(r'^([>]* \*previous\*)', r'>\1', msg, flags=re.MULTILINE) - msg = re.sub(r'^([>]* \*and\*)', r'>\1', msg, flags=re.MULTILINE) - msg = str(e.args if len(e.args) > 1 else e.args[0]) + msg - e.args = (msg,) - return e - - -def underlying_class(P): - r""" - Return the underlying class (class without the attached - categories) of the given instance. - - OUTPUT: - - A class. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import underlying_class - sage: type(QQ) - - sage: underlying_class(QQ) - - """ - cls = type(P) - if not P._is_category_initialized(): - return cls - from sage.structure.misc import is_extension_type - if is_extension_type(cls): - return cls - - from sage.categories.sets_cat import Sets - Sets_parent_class = Sets().parent_class - while issubclass(cls, Sets_parent_class): - cls = cls.__base__ - return cls - - class Variable(sage.structure.unique_representation.CachedRepresentation, sage.structure.sage_object.SageObject): r""" diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 113541b7c04..701ad3755d8 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -88,106 +88,6 @@ #***************************************************************************** import sage -from growth_group import combine_exceptions - -def merge_overlapping(A, B, key=None): - r""" - Merge the two overlapping tuples/lists. - - TESTS:: - - sage: from sage.rings.asymptotic.growth_group_cartesian import merge_overlapping - sage: def f(L, s): - ....: return list((ell, s) for ell in L) - sage: key = lambda k: k[0] - sage: merge_overlapping(f([0..3], 'a'), f([5..7], 'b'), key) - Traceback (most recent call last): - ... - ValueError: Input does not have an overlap. - sage: merge_overlapping(f([0..2], 'a'), f([4..7], 'b'), key) - Traceback (most recent call last): - ... - ValueError: Input does not have an overlap. - sage: merge_overlapping(f([4..7], 'a'), f([0..2], 'b'), key) - Traceback (most recent call last): - ... - ValueError: Input does not have an overlap. - sage: merge_overlapping(f([0..3], 'a'), f([3..4], 'b'), key) - ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a'), (4, 'b')], - [(0, 'a'), (1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]) - sage: merge_overlapping(f([3..4], 'a'), f([0..3], 'b'), key) - ([(0, 'b'), (1, 'b'), (2, 'b'), (3, 'a'), (4, 'a')], - [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b'), (4, 'a')]) - sage: merge_overlapping(f([0..1], 'a'), f([0..4], 'b'), key) - ([(0, 'a'), (1, 'a'), (2, 'b'), (3, 'b'), (4, 'b')], - [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b'), (4, 'b')]) - sage: merge_overlapping(f([0..3], 'a'), f([0..1], 'b'), key) - ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], - [(0, 'b'), (1, 'b'), (2, 'a'), (3, 'a')]) - sage: merge_overlapping(f([0..3], 'a'), f([1..3], 'b'), key) - ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], - [(0, 'a'), (1, 'b'), (2, 'b'), (3, 'b')]) - sage: merge_overlapping(f([1..3], 'a'), f([0..3], 'b'), key) - ([(0, 'b'), (1, 'a'), (2, 'a'), (3, 'a')], - [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b')]) - sage: merge_overlapping(f([0..6], 'a'), f([3..4], 'b'), key) - ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a'), (4, 'a'), (5, 'a'), (6, 'a')], - [(0, 'a'), (1, 'a'), (2, 'a'), (3, 'b'), (4, 'b'), (5, 'a'), (6, 'a')]) - sage: merge_overlapping(f([0..3], 'a'), f([1..2], 'b'), key) - ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], - [(0, 'a'), (1, 'b'), (2, 'b'), (3, 'a')]) - sage: merge_overlapping(f([1..2], 'a'), f([0..3], 'b'), key) - ([(0, 'b'), (1, 'a'), (2, 'a'), (3, 'b')], - [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b')]) - sage: merge_overlapping(f([1..3], 'a'), f([1..3], 'b'), key) - ([(1, 'a'), (2, 'a'), (3, 'a')], - [(1, 'b'), (2, 'b'), (3, 'b')]) - """ - if key is None: - key = lambda k: k - - def find_overlapping_index(A, B): - if len(B) > len(A) - 2: - raise StopIteration - matches = iter(i for i in xrange(1, len(A) - len(B)) - if all(key(a) == key(b) for a, b in zip(A[i:i+len(B)], B))) - return next(matches) - - def find_mergedoverlapping_index(A, B): - """ - Return in index i where to merge two overlapping tuples/lists ``A`` and ``B``. - - Then ``A + B[i:]`` or ``A[:-i] + B`` are the merged tuples/lists. - - Adapted from http://stackoverflow.com/a/30056066/1052778. - """ - matches = iter(i for i in xrange(min(len(A), len(B)), 0, -1) - if all(key(a) == key(b) for a, b in zip(A[-i:], B[:i]))) - return next(matches, 0) - - i = find_mergedoverlapping_index(A, B) - if i > 0: - return A + B[i:], A[:-i] + B - - i = find_mergedoverlapping_index(B, A) - if i > 0: - return B[:-i] + A, B + A[i:] - - try: - i = find_overlapping_index(A, B) - except StopIteration: - pass - else: - return A, A[:i] + B + A[i+len(B):] - - try: - i = find_overlapping_index(B, A) - except StopIteration: - pass - else: - return B[:i] + A + B[i+len(A):], B - - raise ValueError('Input does not have an overlap.') class CartesianProductFactory(sage.structure.factory.UniqueFactory): diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py new file mode 100644 index 00000000000..fd0102e0058 --- /dev/null +++ b/src/sage/rings/asymptotic/misc.py @@ -0,0 +1,444 @@ +r""" +Asymptotic Ring -- Misc + +AUTHORS: + +- Daniel Krenn (2015-08): move functions from other files to this file + + +Methods +======= +""" + +def repr_short_to_parent(s): + r""" + Helper method for the growth group factory, which converts a short + representation string to a parent. + + INPUT: + + A string. + + OUTPUT: + + A parent. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: agg.repr_short_to_parent('ZZ') + Integer Ring + sage: agg.repr_short_to_parent('QQ') + Rational Field + sage: agg.repr_short_to_parent('SR') + Symbolic Ring + sage: agg.repr_short_to_parent('NN') + Non negative integer semiring + + TESTS:: + + sage: agg.repr_short_to_parent('abcdef') + Traceback (most recent call last): + ... + ValueError: Cannot create a parent out of 'abcdef'. + > *previous* NameError: name 'abcdef' is not defined + """ + from sage.misc.sage_eval import sage_eval + try: + P = sage_eval(s) + except Exception as e: + raise combine_exceptions( + ValueError("Cannot create a parent out of '%s'." % (s,)), e) + + from sage.misc.lazy_import import LazyImport + if type(P) is LazyImport: + P = P._get_object() + + from sage.structure.parent import is_Parent + if not is_Parent(P): + raise ValueError("'%s' does not describe a parent." % (s,)) + return P + + +def parent_to_repr_short(P): + r""" + Helper method which generates a short(er) representation string + out of a parent. + + INPUT: + + A parent. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: import sage.rings.asymptotic.growth_group as agg + sage: agg.parent_to_repr_short(ZZ) + 'ZZ' + sage: agg.parent_to_repr_short(QQ) + 'QQ' + sage: agg.parent_to_repr_short(SR) + 'SR' + sage: agg.parent_to_repr_short(ZZ[x]) + '(Univariate Polynomial Ring in x over Integer Ring)' + """ + if P is sage.rings.integer_ring.ZZ: + return 'ZZ' + elif P is sage.rings.rational_field.QQ: + return 'QQ' + elif P is sage.symbolic.ring.SR: + return 'SR' + else: + rep = repr(P) + if ' ' in rep: + rep = '(' + rep + ')' + return rep + + +def split_str_by_mul(string): + r""" + Split the given string into a tuple of substrings arising by + splitting by '*' and taking care of parentheses. + + INPUT: + + - ``string`` - a string. + + OUTPUT: + + A tuple of strings. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import split_str_by_mul + sage: split_str_by_mul('x^ZZ') + ('x^ZZ',) + sage: split_str_by_mul('log(x)^ZZ * y^QQ') + ('log(x)^ZZ', 'y^QQ') + sage: split_str_by_mul('log(x)**ZZ * y**QQ') + ('log(x)**ZZ', 'y**QQ') + sage: split_str_by_mul('a^b * * c^d') + Traceback (most recent call last): + ... + ValueError: 'a^b * * c^d' is invalid since a '*' follows a '*' + sage: split_str_by_mul('a^b * (c*d^e)') + ('a^b', 'c*d^e') + """ + factors = list() + balanced = True + if string and string[0] == '*': + raise ValueError("'%s' is invalid since it starts with a '*'." % + (string,)) + for s in string.split('*'): + if not s: + factors[-1] += '*' + balanced = False + continue + if not s.strip(): + raise ValueError("'%s' is invalid since a '*' follows a '*'" % + (string,)) + if not balanced: + s = factors.pop() + '*' + s + balanced = s.count('(') == s.count(')') + factors.append(s) + + if not balanced: + raise ValueError("Parentheses in '%s' are not balanced" % (string,)) + + def strip(s): + s = s.strip() + if not s: + return s + if s[0] == '(' and s[-1] == ')': + s = s[1:-1] + return s.strip() + + return tuple(strip(f) for f in factors) + + +def combine_exceptions(e, *f): + r""" + Helper function which combines the messages of the given exceptions. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import combine_exceptions + sage: raise combine_exceptions(ValueError('Outer.'), TypeError('Inner.')) + Traceback (most recent call last): + ... + ValueError: Outer. + > *previous* TypeError: Inner. + sage: raise combine_exceptions(ValueError('Outer.'), + ....: TypeError('Inner1.'), TypeError('Inner2.')) + Traceback (most recent call last): + ... + ValueError: Outer. + > *previous* TypeError: Inner1. + > *and* TypeError: Inner2. + sage: raise combine_exceptions(ValueError('Outer.'), + ....: combine_exceptions(TypeError('Middle.'), + ....: TypeError('Inner.'))) + Traceback (most recent call last): + ... + ValueError: Outer. + > *previous* TypeError: Middle. + >> *previous* TypeError: Inner. + """ + import re + msg = ('\n *previous* ' + + '\n *and* '.join("%s: %s" % (ff.__class__.__name__, str(ff)) for ff in f)) + msg = re.sub(r'^([>]* \*previous\*)', r'>\1', msg, flags=re.MULTILINE) + msg = re.sub(r'^([>]* \*and\*)', r'>\1', msg, flags=re.MULTILINE) + msg = str(e.args if len(e.args) > 1 else e.args[0]) + msg + e.args = (msg,) + return e + + +def underlying_class(P): + r""" + Return the underlying class (class without the attached + categories) of the given instance. + + OUTPUT: + + A class. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import underlying_class + sage: type(QQ) + + sage: underlying_class(QQ) + + """ + cls = type(P) + if not P._is_category_initialized(): + return cls + from sage.structure.misc import is_extension_type + if is_extension_type(cls): + return cls + + from sage.categories.sets_cat import Sets + Sets_parent_class = Sets().parent_class + while issubclass(cls, Sets_parent_class): + cls = cls.__base__ + return cls + + +def merge_overlapping(A, B, key=None): + r""" + Merge the two overlapping tuples/lists. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group_cartesian import merge_overlapping + sage: def f(L, s): + ....: return list((ell, s) for ell in L) + sage: key = lambda k: k[0] + sage: merge_overlapping(f([0..3], 'a'), f([5..7], 'b'), key) + Traceback (most recent call last): + ... + ValueError: Input does not have an overlap. + sage: merge_overlapping(f([0..2], 'a'), f([4..7], 'b'), key) + Traceback (most recent call last): + ... + ValueError: Input does not have an overlap. + sage: merge_overlapping(f([4..7], 'a'), f([0..2], 'b'), key) + Traceback (most recent call last): + ... + ValueError: Input does not have an overlap. + sage: merge_overlapping(f([0..3], 'a'), f([3..4], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a'), (4, 'b')], + [(0, 'a'), (1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]) + sage: merge_overlapping(f([3..4], 'a'), f([0..3], 'b'), key) + ([(0, 'b'), (1, 'b'), (2, 'b'), (3, 'a'), (4, 'a')], + [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b'), (4, 'a')]) + sage: merge_overlapping(f([0..1], 'a'), f([0..4], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'b'), (3, 'b'), (4, 'b')], + [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b'), (4, 'b')]) + sage: merge_overlapping(f([0..3], 'a'), f([0..1], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], + [(0, 'b'), (1, 'b'), (2, 'a'), (3, 'a')]) + sage: merge_overlapping(f([0..3], 'a'), f([1..3], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], + [(0, 'a'), (1, 'b'), (2, 'b'), (3, 'b')]) + sage: merge_overlapping(f([1..3], 'a'), f([0..3], 'b'), key) + ([(0, 'b'), (1, 'a'), (2, 'a'), (3, 'a')], + [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b')]) + sage: merge_overlapping(f([0..6], 'a'), f([3..4], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a'), (4, 'a'), (5, 'a'), (6, 'a')], + [(0, 'a'), (1, 'a'), (2, 'a'), (3, 'b'), (4, 'b'), (5, 'a'), (6, 'a')]) + sage: merge_overlapping(f([0..3], 'a'), f([1..2], 'b'), key) + ([(0, 'a'), (1, 'a'), (2, 'a'), (3, 'a')], + [(0, 'a'), (1, 'b'), (2, 'b'), (3, 'a')]) + sage: merge_overlapping(f([1..2], 'a'), f([0..3], 'b'), key) + ([(0, 'b'), (1, 'a'), (2, 'a'), (3, 'b')], + [(0, 'b'), (1, 'b'), (2, 'b'), (3, 'b')]) + sage: merge_overlapping(f([1..3], 'a'), f([1..3], 'b'), key) + ([(1, 'a'), (2, 'a'), (3, 'a')], + [(1, 'b'), (2, 'b'), (3, 'b')]) + """ + if key is None: + key = lambda k: k + + def find_overlapping_index(A, B): + if len(B) > len(A) - 2: + raise StopIteration + matches = iter(i for i in xrange(1, len(A) - len(B)) + if all(key(a) == key(b) for a, b in zip(A[i:i+len(B)], B))) + return next(matches) + + def find_mergedoverlapping_index(A, B): + """ + Return in index i where to merge two overlapping tuples/lists ``A`` and ``B``. + + Then ``A + B[i:]`` or ``A[:-i] + B`` are the merged tuples/lists. + + Adapted from http://stackoverflow.com/a/30056066/1052778. + """ + matches = iter(i for i in xrange(min(len(A), len(B)), 0, -1) + if all(key(a) == key(b) for a, b in zip(A[-i:], B[:i]))) + return next(matches, 0) + + i = find_mergedoverlapping_index(A, B) + if i > 0: + return A + B[i:], A[:-i] + B + + i = find_mergedoverlapping_index(B, A) + if i > 0: + return B[:-i] + A, B + A[i:] + + try: + i = find_overlapping_index(A, B) + except StopIteration: + pass + else: + return A, A[:i] + B + A[i+len(B):] + + try: + i = find_overlapping_index(B, A) + except StopIteration: + pass + else: + return B[:i] + A + B[i+len(A):], B + + raise ValueError('Input does not have an overlap.') + + +def product_diagonal(A, B): + r""" + Return an iterator over the product of `A` and `B` which iterates + along the diagonal. + + INPUT: + + - ``A`` and ``B`` -- iterables (over a finite number of elements) + + OUTPUT: + + An iterator over `(a,b)` for `a \in A` and `b \in B`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.term_monoid import product_diagonal + sage: tuple(product_diagonal(srange(2), srange(2))) + ((0, 0), (0, 1), (1, 0), (1, 1)) + sage: tuple(product_diagonal(srange(4), srange(2))) + ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) + sage: tuple(product_diagonal(srange(2), srange(3))) + ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) + sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) + ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') + + TESTS: + + Check that all pairs are returned:: + + sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n + ....: for m in srange(5) for n in srange(5)) + True + + Check that everthing is loaded in the correct order:: + + sage: def it(s, n): + ....: for i in srange(n): + ....: print '%s loads item number %s' % (s, i) + ....: yield i + sage: for p in product_diagonal(it('A', 2), it('B', 2)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + (1, 1) + sage: for p in product_diagonal(it('A', 3), it('B', 2)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + (1, 1) + A loads item number 2 + (2, 0) + (2, 1) + sage: for p in product_diagonal(it('A', 2), it('B', 4)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + B loads item number 2 + (0, 2) + (1, 1) + B loads item number 3 + (0, 3) + (1, 2) + (1, 3) + """ + # when writing this code I thought the solution would be shorter... + + class iter_as_list(list): + def __init__(self, iterable): + self.it = iter(iterable) + self.newdata = True + def __getitem__(self, i): + self.newdata = False + try: + while len(self) <= i: + self.append(next(self.it)) + self.newdata = True + except StopIteration: + raise + return list.__getitem__(self, i) + + from itertools import count + A = iter_as_list(A) + B = iter_as_list(B) + for s in count(): + for i in range(s+1): + stopped = False + try: + a = A[i] + except StopIteration: + stopped = True + try: + b = B[s-i] + except StopIteration: + stopped = True + if stopped: + continue + yield a, b + if not A.newdata and not B.newdata and s >= len(A) + len(B): + return diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 34dc57e3065..c22c35c2dde 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -76,122 +76,6 @@ import sage -def product_diagonal(A, B): - r""" - Return an iterator over the product of `A` and `B` which iterates - along the diagonal. - - INPUT: - - - ``A`` and ``B`` -- iterables (over a finite number of elements) - - OUTPUT: - - An iterator over `(a,b)` for `a \in A` and `b \in B`. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.term_monoid import product_diagonal - sage: tuple(product_diagonal(srange(2), srange(2))) - ((0, 0), (0, 1), (1, 0), (1, 1)) - sage: tuple(product_diagonal(srange(4), srange(2))) - ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) - sage: tuple(product_diagonal(srange(2), srange(3))) - ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) - sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) - ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') - - TESTS: - - Check that all pairs are returned:: - - sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n - ....: for m in srange(5) for n in srange(5)) - True - - Check that everthing is loaded in the correct order:: - - sage: def it(s, n): - ....: for i in srange(n): - ....: print '%s loads item number %s' % (s, i) - ....: yield i - sage: for p in product_diagonal(it('A', 2), it('B', 2)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - (1, 1) - sage: for p in product_diagonal(it('A', 3), it('B', 2)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - (1, 1) - A loads item number 2 - (2, 0) - (2, 1) - sage: for p in product_diagonal(it('A', 2), it('B', 4)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - B loads item number 2 - (0, 2) - (1, 1) - B loads item number 3 - (0, 3) - (1, 2) - (1, 3) - """ - # when writing this code I thought the solution would be shorter... - - class iter_as_list(list): - def __init__(self, iterable): - self.it = iter(iterable) - self.newdata = True - def __getitem__(self, i): - self.newdata = False - try: - while len(self) <= i: - self.append(next(self.it)) - self.newdata = True - except StopIteration: - raise - return list.__getitem__(self, i) - - from itertools import count - A = iter_as_list(A) - B = iter_as_list(B) - for s in count(): - for i in range(s+1): - stopped = False - try: - a = A[i] - except StopIteration: - stopped = True - try: - b = B[s-i] - except StopIteration: - stopped = True - if stopped: - continue - yield a, b - if not A.newdata and not B.newdata and s >= len(A) + len(B): - return - - def absorption(left, right): r""" Helper method used by From 8bae4a92336c0c09e7810ebe1d8732c3facf513f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 11:46:40 +0200 Subject: [PATCH 0678/1872] change imports to make everything running again --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++++------ src/sage/rings/asymptotic/growth_group.py | 7 +++++++ .../rings/asymptotic/growth_group_cartesian.py | 4 +++- src/sage/rings/asymptotic/misc.py | 17 ++++++++++------- src/sage/rings/asymptotic/term_monoid.py | 17 +++++++++-------- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index e35d03830c7..00c2b0f0a79 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -458,7 +458,7 @@ def __init__(self, parent, summands, simplify=True, convert=True): 'when creating an element of %s.' % (summands, parent)) if convert: - from growth_group import combine_exceptions + from misc import combine_exceptions from term_monoid import TermMonoid def convert_terms(element): T = TermMonoid(term=element.parent(), asymptotic_ring=parent) @@ -1073,7 +1073,7 @@ def __pow__(self, exponent): try: return (exponent * self.log()).exp() except (TypeError, ValueError, ZeroDivisionError) as e: - from sage.rings.asymptotic.growth_group import combine_exceptions + from misc import combine_exceptions raise combine_exceptions( ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) @@ -1429,7 +1429,7 @@ def change_parameter(self, **kwds): if all(values[parameter] is getattr(self, parameter) for parameter in parameters) and values['category'] is self.category(): return self - from sage.rings.asymptotic.growth_group import underlying_class + from misc import underlying_class return underlying_class(self)(**values) @@ -1610,7 +1610,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): except AttributeError: return self._create_exact_summand_(data) - from growth_group import combine_exceptions + from misc import combine_exceptions if P is sage.symbolic.ring.SR: from sage.symbolic.operators import add_vararg if data.operator() == add_vararg: @@ -1843,8 +1843,8 @@ def some_elements(self): O(z^(-1/2)), 8*z^(3/2) + O(z^(1/2))) """ - from sage.rings.asymptotic.term_monoid import product_diagonal - from sage.rings.asymptotic.term_monoid import TermMonoid + from misc import product_diagonal + from term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) return iter(self(e, simplify=False, convert=False)**3 + diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ebd6b674739..c9579c9e66d 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1048,6 +1048,7 @@ def _repr_short_(self): sage: GenericGrowthGroup(QQ, ('a', 'b')) Growth Group Generic(QQ, a, b) """ + from misc import parent_to_repr_short vars = ', '.join(self._var_.variable_names()) if vars: vars = ', ' + vars @@ -1201,6 +1202,7 @@ def _create_element_via_parent_(self, raw_element, old_parent=None): sage: G._create_element_via_parent_(1/2, ZZ).parent() Growth Group z^QQ """ + from misc import underlying_class if old_parent is None or raw_element.parent() is old_parent: parent = self else: @@ -2056,6 +2058,7 @@ def _repr_short_(self): sage: agg.MonomialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() 'a^(Univariate Polynomial Ring in x over Rational Field)' """ + from misc import parent_to_repr_short return '%s^%s' % (self._var_, parent_to_repr_short(self.base())) @@ -2594,6 +2597,7 @@ def _repr_short_(self): sage: agg.ExponentialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() '(Univariate Polynomial Ring in x over Rational Field)^a' """ + from misc import parent_to_repr_short return '%s^%s' % (parent_to_repr_short(self.base()), self._var_) @@ -2837,6 +2841,7 @@ def create_key_and_extra_args(self, specification, **kwds): ... ValueError: 'asdf' is not a valid string describing a growth group. """ + from misc import split_str_by_mul factors = split_str_by_mul(specification) factors = tuple(f.replace('**', '^') for f in factors) @@ -2872,6 +2877,7 @@ def create_object(self, version, factors, **kwds): > *and* ValueError: Cannot create a parent out of 'y^z'. >> *previous* NameError: name 'y' is not defined """ + from misc import repr_short_to_parent groups = [] for factor in factors: b, _, e = factor.partition('^') @@ -2886,6 +2892,7 @@ def create_object(self, version, factors, **kwds): E = None if B is None and E is None: + from misc import combine_exceptions raise combine_exceptions( ValueError("'%s' is not a valid string describing " "a growth group." % (factor,)), exc_b, exc_e) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 701ad3755d8..61cb3a6fb10 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -342,6 +342,7 @@ def convert_factors(data, raw_data): try: return self._convert_factors_(data) except ValueError as e: + from misc import combine_exceptions raise combine_exceptions( ValueError('%s is not in %s.' % (raw_data, self)), e) @@ -358,7 +359,7 @@ def convert_factors(data, raw_data): return self.element_class(self, data) elif isinstance(data, str): - from growth_group import split_str_by_mul + from misc import split_str_by_mul return convert_factors(split_str_by_mul(data), data) elif hasattr(data, 'parent'): @@ -567,6 +568,7 @@ def _pushout_(self, other): Growth Group QQ^x * x^QQ * y^ZZ * z^QQ """ from growth_group import GenericGrowthGroup, AbstractGrowthGroupFunctor + from misc import merge_overlapping if isinstance(other, GenericProduct): Ofactors = other.cartesian_factors() diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index fd0102e0058..5d73bdec8fd 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -10,6 +10,9 @@ ======= """ +import sage + + def repr_short_to_parent(s): r""" Helper method for the growth group factory, which converts a short @@ -25,7 +28,7 @@ def repr_short_to_parent(s): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg + sage: import sage.rings.asymptotic.misc as agg sage: agg.repr_short_to_parent('ZZ') Integer Ring sage: agg.repr_short_to_parent('QQ') @@ -75,7 +78,7 @@ def parent_to_repr_short(P): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg + sage: import sage.rings.asymptotic.misc as agg sage: agg.parent_to_repr_short(ZZ) 'ZZ' sage: agg.parent_to_repr_short(QQ) @@ -113,7 +116,7 @@ def split_str_by_mul(string): TESTS:: - sage: from sage.rings.asymptotic.growth_group import split_str_by_mul + sage: from sage.rings.asymptotic.misc import split_str_by_mul sage: split_str_by_mul('x^ZZ') ('x^ZZ',) sage: split_str_by_mul('log(x)^ZZ * y^QQ') @@ -165,7 +168,7 @@ def combine_exceptions(e, *f): EXAMPLES:: - sage: from sage.rings.asymptotic.growth_group import combine_exceptions + sage: from sage.rings.asymptotic.misc import combine_exceptions sage: raise combine_exceptions(ValueError('Outer.'), TypeError('Inner.')) Traceback (most recent call last): ... @@ -208,7 +211,7 @@ def underlying_class(P): EXAMPLES:: - sage: from sage.rings.asymptotic.growth_group import underlying_class + sage: from sage.rings.asymptotic.misc import underlying_class sage: type(QQ) sage: underlying_class(QQ) @@ -234,7 +237,7 @@ def merge_overlapping(A, B, key=None): TESTS:: - sage: from sage.rings.asymptotic.growth_group_cartesian import merge_overlapping + sage: from sage.rings.asymptotic.misc import merge_overlapping sage: def f(L, s): ....: return list((ell, s) for ell in L) sage: key = lambda k: k[0] @@ -343,7 +346,7 @@ def product_diagonal(A, B): EXAMPLES:: - sage: from sage.rings.asymptotic.term_monoid import product_diagonal + sage: from sage.rings.asymptotic.misc import product_diagonal sage: tuple(product_diagonal(srange(2), srange(2))) ((0, 0), (0, 1), (1, 0), (1, 1)) sage: tuple(product_diagonal(srange(4), srange(2))) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index c22c35c2dde..7f826ff1ec9 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -391,7 +391,7 @@ def _calculate_pow_test_zero_(self, exponent): _ = zero ** exponent except (TypeError, ValueError, ZeroDivisionError, FloatingPointError) as e: - from sage.rings.asymptotic.growth_group import combine_exceptions + from misc import combine_exceptions raise combine_exceptions( ZeroDivisionError('Cannot take %s to exponent %s.' % (self, exponent)), e) @@ -439,7 +439,7 @@ def _calculate_pow_(self, exponent, coefficient=None): try: g = self.growth ** exponent except (ValueError, TypeError, ZeroDivisionError) as e: - from sage.rings.asymptotic.growth_group import combine_exceptions + from misc import combine_exceptions raise combine_exceptions( ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) @@ -977,7 +977,7 @@ def __classcall__(cls, growth_group, coefficient_ring, category=None): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ') sage: T = GenericTermMonoid(G, QQ) - sage: from sage.rings.asymptotic.growth_group import underlying_class + sage: from sage.rings.asymptotic.misc import underlying_class sage: underlying_class(T)(G, QQ) is T True """ @@ -1255,7 +1255,7 @@ def _element_constructor_(self, data, coefficient=None): raise ValueError('No input specified. Cannot continue ' 'creating an element of %s.' % (self,)) - from growth_group import combine_exceptions + from misc import combine_exceptions if coefficient is not None: try: data = self.growth_group(data) @@ -1333,7 +1333,7 @@ def _create_element_via_parent_(self, growth, coefficient, coefficient is not None and coefficient.parent() is old_parent_coefficient): parent = self else: - from sage.rings.asymptotic.growth_group import underlying_class + from misc import underlying_class parent = underlying_class(self)(growth.parent(), coefficient.parent() if coefficient is not None @@ -1414,7 +1414,7 @@ def _get_factors_(self, data): (x^2, log(x)) """ if isinstance(data, str): - from growth_group import split_str_by_mul + from misc import split_str_by_mul return split_str_by_mul(data) try: @@ -2021,7 +2021,7 @@ def _calculate_pow_(self, exponent): try: c = self.coefficient ** exponent except (TypeError, ValueError, ZeroDivisionError) as e: - from sage.rings.asymptotic.growth_group import combine_exceptions + from misc import combine_exceptions raise combine_exceptions( ZeroDivisionError('Cannot take %s to the exponent %s since its ' 'coefficient %s cannot be taken to this exponent.' % @@ -2236,6 +2236,7 @@ def some_elements(self): z^2, -2*z^(1/2), 2*z^(-1/2), -z^2, z^(-2)) """ + from misc import product_diagonal return iter(self(g, c) for g, c in product_diagonal( self.growth_group.some_elements(), iter(c for c in self.coefficient_ring.some_elements() if c != 0))) @@ -2615,7 +2616,7 @@ def create_key_and_extra_args(self, term, to create a term monoid of type 'exact' """ if isinstance(term, GenericTermMonoid): - from sage.rings.asymptotic.growth_group import underlying_class + from misc import underlying_class term_class = underlying_class(term) elif term == 'O': term_class = OTermMonoid From 184ead82b453aeefb3dabfe0abe177f23a692171 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 11:51:52 +0200 Subject: [PATCH 0679/1872] use relative imports where possible --- src/sage/rings/asymptotic/asymptotic_ring.py | 13 ++++++------- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 00c2b0f0a79..677fa083c6f 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -848,7 +848,7 @@ def _rmul_(self, other): if other == 0: return self.parent().zero() - from sage.rings.asymptotic.term_monoid import TermMonoid + from term_monoid import TermMonoid E = TermMonoid('exact', asymptotic_ring=self.parent()) e = E(self.parent().growth_group.one(), coefficient=other) return self._mul_term_(e) @@ -1272,7 +1272,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, cls = cls.__base__ if isinstance(growth_group, str): - from sage.rings.asymptotic.growth_group import GrowthGroup + from growth_group import GrowthGroup growth_group = GrowthGroup(growth_group) if growth_group is None: @@ -1453,8 +1453,7 @@ def _create_empty_summands_(): poset() """ from sage.data_structures.mutable_poset import MutablePoset - from sage.rings.asymptotic.term_monoid import \ - can_absorb, absorption + from term_monoid import can_absorb, absorption return MutablePoset(key=lambda element: element.growth, can_merge=can_absorb, merge=absorption) @@ -1586,7 +1585,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): return self.element_class(self, data.summands, simplify=simplify, convert=convert) - from sage.rings.asymptotic.term_monoid import GenericTerm + from term_monoid import GenericTerm if isinstance(data, GenericTerm): data = (data,) @@ -1806,7 +1805,7 @@ def _an_element_(self): sage: AsymptoticRing(growth_group='z^QQ', coefficient_ring=QQ).an_element() 1/8*z^(3/2) + O(z^(1/2)) """ - from sage.rings.asymptotic.term_monoid import TermMonoid + from term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) return self(E.an_element(), simplify=False, convert=False)**3 + \ @@ -1975,7 +1974,7 @@ def create_summand(self, type, data=None, **kwds): ValueError: Growth 42*x^2 is not in O-Term Monoid x^ZZ with implicit coefficients in Integer Ring. > *previous* ValueError: 42*x^2 is not in Growth Group x^ZZ. """ - from sage.rings.asymptotic.term_monoid import TermMonoid + from term_monoid import TermMonoid TM = TermMonoid(type, self.growth_group, self.coefficient_ring) if data is None: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 7f826ff1ec9..9c8f350c655 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -981,7 +981,7 @@ def __classcall__(cls, growth_group, coefficient_ring, category=None): sage: underlying_class(T)(G, QQ) is T True """ - from sage.rings.asymptotic.growth_group import GenericGrowthGroup + from growth_group import GenericGrowthGroup if growth_group is None: raise ValueError('No growth group specified.') if not isinstance(growth_group, sage.structure.parent.Parent): @@ -2636,7 +2636,7 @@ def create_key_and_extra_args(self, term, growth_group = asymptotic_ring.growth_group coefficient_ring = asymptotic_ring.coefficient_ring - from sage.rings.asymptotic.growth_group import GenericGrowthGroup + from growth_group import GenericGrowthGroup if not isinstance(growth_group, GenericGrowthGroup): raise ValueError("%s has to be an asymptotic growth group" % growth_group) From ed536a1c83318b26a8d0023a9fa543c694f946fb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 11:54:43 +0200 Subject: [PATCH 0680/1872] use asymptotic_ring option when calling factory TermMonoid --- src/sage/rings/asymptotic/asymptotic_ring.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 677fa083c6f..e6729a18489 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1806,8 +1806,8 @@ def _an_element_(self): 1/8*z^(3/2) + O(z^(1/2)) """ from term_monoid import TermMonoid - E = TermMonoid('exact', self.growth_group, self.coefficient_ring) - O = TermMonoid('O', self.growth_group, self.coefficient_ring) + E = TermMonoid('exact', asymptotic_ring=self) + O = TermMonoid('O', asymptotic_ring=self) return self(E.an_element(), simplify=False, convert=False)**3 + \ self(O.an_element(), simplify=False, convert=False) @@ -1844,8 +1844,8 @@ def some_elements(self): """ from misc import product_diagonal from term_monoid import TermMonoid - E = TermMonoid('exact', self.growth_group, self.coefficient_ring) - O = TermMonoid('O', self.growth_group, self.coefficient_ring) + E = TermMonoid('exact', asymptotic_ring=self) + O = TermMonoid('O', asymptotic_ring=self) return iter(self(e, simplify=False, convert=False)**3 + self(o, simplify=False, convert=False) for e, o in product_diagonal( @@ -1975,7 +1975,7 @@ def create_summand(self, type, data=None, **kwds): > *previous* ValueError: 42*x^2 is not in Growth Group x^ZZ. """ from term_monoid import TermMonoid - TM = TermMonoid(type, self.growth_group, self.coefficient_ring) + TM = TermMonoid(type, asymptotic_ring=self) if data is None: try: From 93b8e0bd27461b3912149f7bf65232a722973294 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 12:03:01 +0200 Subject: [PATCH 0681/1872] correct thing reported by pyflakes --- src/sage/rings/asymptotic/asymptotic_ring.py | 1 - src/sage/rings/asymptotic/growth_group.py | 3 --- src/sage/rings/asymptotic/term_monoid.py | 5 ++--- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index e6729a18489..4499398d8cc 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2032,7 +2032,6 @@ def construction(self): from sage.categories.pushout import ConstructionFunctor -from growth_group import Variable class AsymptoticRingFunctor(ConstructionFunctor): r""" A :class:`construction functor ` diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c9579c9e66d..0f48eacd4e1 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1920,7 +1920,6 @@ def __invert__(self): sage: e2 == ~e1 True """ - new_element = -self.exponent return self.parent()._create_element_via_parent_(-self.exponent, self.exponent.parent()) @@ -2466,7 +2465,6 @@ def __invert__(self): sage: (~P(raw_element=1)).parent() Growth Group QQ^x """ - new_element = 1 / self.base return self.parent()._create_element_via_parent_(1 / self.base, self.base.parent()) @@ -2658,7 +2656,6 @@ def _convert_(self, data): try: P = data.parent() except AttributeError: - import re if var not in str(data): return # this has to end here diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 9c8f350c655..8da330bdbc3 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -190,7 +190,7 @@ def __init__(self, parent, growth): raise ValueError('The parent must be provided') try: self.growth = parent.growth_group(growth) - except ValueError, TypeError: + except (ValueError, TypeError): raise ValueError("%s is not in %s" % (growth, parent.growth_group)) super(GenericTerm, self).__init__(parent=parent) @@ -388,7 +388,7 @@ def _calculate_pow_test_zero_(self, exponent): """ zero = self.parent().coefficient_ring.zero() try: - _ = zero ** exponent + zero ** exponent except (TypeError, ValueError, ZeroDivisionError, FloatingPointError) as e: from misc import combine_exceptions @@ -981,7 +981,6 @@ def __classcall__(cls, growth_group, coefficient_ring, category=None): sage: underlying_class(T)(G, QQ) is T True """ - from growth_group import GenericGrowthGroup if growth_group is None: raise ValueError('No growth group specified.') if not isinstance(growth_group, sage.structure.parent.Parent): From 8aa97d33ebf996d3943db2cb470d67dbb2bdbbfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 30 Aug 2015 17:42:04 +0200 Subject: [PATCH 0682/1872] trac #18937 patchbot version without pytz --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index 62ffca027aa..8fe090e4573 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=25e1f2a8bbe84a01e2b5157cfeffc02218a6e7ab -md5=d2b2fde69496db246d2fe3b086ad20d5 -cksum=532828853 +sha1=f8e41048da15add40d24c0d01a846bef2ff22f95 +md5=b063258d4dfbb6b888f38b53e257432b +cksum=3707204329 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 197c4d5c2d7..005119baaa0 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.0 +2.4.1 From 6fd5a5c0f5605c369c696df39637464b1f865d09 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 20:06:52 +0200 Subject: [PATCH 0683/1872] fix __eq__ in AsymptoticExpression --- src/sage/rings/asymptotic/asymptotic_ring.py | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 4499398d8cc..b11d2390b61 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -548,10 +548,50 @@ def __eq__(self, other): True sage: O(x) == O(x) False + + TESTS:: + + sage: x == None + False """ + if other is None: + return False return not bool(self - other) + def __ne__(self, other): + r""" + Return if this asymptotic expression is not equal to ``other``. + + INPUT: + + - ``other`` -- an object. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This function uses the coercion model to find a common + parent for the two operands. + + EXAMPLES:: + + sage: R. = AsymptoticRing('x^ZZ', QQ) + sage: (1 + 2*x + 3*x^2) != (3*x^2 + 2*x + 1) # indirect doctest + False + sage: O(x) != O(x) + True + + TESTS:: + + sage: x != None + True + """ + return not self == other + + def has_same_summands(self, other): r""" Return if this asymptotic expression and ``other`` have the @@ -583,7 +623,14 @@ def has_same_summands(self, other): True sage: O(x_ZZ) == O(x_QQ) False + + TESTS:: + + sage: x_ZZ.has_same_summands(None) + False """ + if other is None: + return False from sage.structure.element import have_same_parent if have_same_parent(self, other): return self._has_same_summands_(other) From dd42bb254faf62b166d804ac65918bf61215545e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 20:07:40 +0200 Subject: [PATCH 0684/1872] QQ(0)^(-1) bug; #19110 --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/term_monoid.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b11d2390b61..68f647fbb18 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1086,7 +1086,7 @@ def __pow__(self, exponent): :: - sage: O(x)^(-1) + sage: O(x)^(-1) # not tested # see #19110 Traceback (most recent call last): ... ZeroDivisionError: Cannot take O(x) to exponent -1. diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 8da330bdbc3..e5d74893b2f 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -389,8 +389,7 @@ def _calculate_pow_test_zero_(self, exponent): zero = self.parent().coefficient_ring.zero() try: zero ** exponent - except (TypeError, ValueError, - ZeroDivisionError, FloatingPointError) as e: + except (TypeError, ValueError, ZeroDivisionError) as e: from misc import combine_exceptions raise combine_exceptions( ZeroDivisionError('Cannot take %s to exponent %s.' % From 38cc8179e153a0c8168c50ea142b2c83eff6be37 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 20:07:52 +0200 Subject: [PATCH 0685/1872] TestSuite for Ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 68f647fbb18..90eb9df930c 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1245,6 +1245,20 @@ class AsymptoticRing(sage.algebras.algebra.Algebra, Asymptotic Ring over Rational Field sage: R1_x is R2_x is R3_x True + + :: + + sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing as AR_class + sage: class AR(AR_class): + ....: class Element(AR_class.Element): + ....: __eq__ = AR_class.Element.has_same_summands + sage: A = AR(growth_group='z^QQ', coefficient_ring=QQ) + sage: from itertools import islice + sage: TestSuite(A).run( # not tested # long + ....: verbose=True, + ....: elements=tuple(islice(A.some_elements(), 10)), + ....: skip=('_test_some_elements', # to many elements + ....: '_test_distributivity')) # due to cancellations: O(z) != O(z^2) """ # enable the category framework for elements From df29853f396dbdc4dd7bf8caaf7e55b02046e01b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 20:08:58 +0200 Subject: [PATCH 0686/1872] some_elements for growth_group_cartesian some_elements from the category framework is not taken since we have an implementation in GenericGrowthGroup --- .../asymptotic/growth_group_cartesian.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 61cb3a6fb10..c79ea457ad9 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -275,6 +275,43 @@ def __init__(self, sets, category, **kwds): __hash__ = CartesianProductPosets.__hash__ + def some_elements(self): + r""" + Return some elements of this cartesian product of growth groups. + + See :class:`TestSuite` for a typical use case. + + INPUT: + + Nothing. + + OUTPUT: + + An iterator. + + EXAMPLES:: + + sage: from itertools import islice + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^y * x^QQ * log(x)^ZZ') + sage: tuple(islice(G.some_elements(), 10)) + (x^(1/2)*(1/2)^y, + x^(-1/2)*log(x)*(-1/2)^y, + x^2*log(x)^(-1)*2^y, + x^(-2)*log(x)^2*(-2)^y, + log(x)^(-2)*(0)^y, + x*log(x)^3, + x^(-1)*log(x)^(-3)*(-1)^y, + x^42*log(x)^4*42^y, + x^(2/3)*log(x)^(-4)*(2/3)^y, + x^(-2/3)*log(x)^5*(-2/3)^y) + """ + from itertools import izip + return iter( + self(c) for c in + izip(*tuple(F.some_elements() for F in self.cartesian_factors()))) + + def _element_constructor_(self, data): r""" Converts the given object to an element of this cartesian From 2105de2bcd6f63d7b1a094e5b081a06265a99ced Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Aug 2015 20:09:15 +0200 Subject: [PATCH 0687/1872] TestSuite for growth groups --- src/sage/rings/asymptotic/growth_group.py | 86 +++++++++++++++++++++-- 1 file changed, 79 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 0f48eacd4e1..0218c665089 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2807,23 +2807,95 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GrowthGroup('x^ZZ') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ') Growth Group x^ZZ - sage: agg.GrowthGroup('log(x)^QQ') + sage: GrowthGroup('log(x)^QQ') Growth Group log(x)^QQ This factory can also be used to construct Cartesian products of growth groups:: - sage: agg.GrowthGroup('x^ZZ * y^ZZ') + sage: GrowthGroup('x^ZZ * y^ZZ') Growth Group x^ZZ * y^ZZ - sage: agg.GrowthGroup('x^ZZ * log(x)^ZZ') + sage: GrowthGroup('x^ZZ * log(x)^ZZ') Growth Group x^ZZ * log(x)^ZZ - sage: agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ') + sage: GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ') Growth Group x^ZZ * log(x)^ZZ * y^QQ - sage: agg.GrowthGroup('QQ^x * x^ZZ * y^QQ * QQ^z') + sage: GrowthGroup('QQ^x * x^ZZ * y^QQ * QQ^z') Growth Group QQ^x * x^ZZ * y^QQ * QQ^z + + TESTS:: + + sage: TestSuite(GrowthGroup('x^ZZ')).run(verbose=True) + running ._test_an_element() . . . pass + running ._test_associativity() . . . pass + running ._test_category() . . . pass + running ._test_elements() . . . + Running the test suite of self.an_element() + running ._test_category() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + pass + running ._test_elements_eq_reflexive() . . . pass + running ._test_elements_eq_symmetric() . . . pass + running ._test_elements_eq_transitive() . . . pass + running ._test_elements_neq() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_one() . . . pass + running ._test_pickling() . . . pass + running ._test_prod() . . . pass + running ._test_some_elements() . . . pass + + :: + + sage: TestSuite(GrowthGroup('QQ^y')).run(verbose=True) + running ._test_an_element() . . . pass + running ._test_associativity() . . . pass + running ._test_category() . . . pass + running ._test_elements() . . . + Running the test suite of self.an_element() + running ._test_category() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + pass + running ._test_elements_eq_reflexive() . . . pass + running ._test_elements_eq_symmetric() . . . pass + running ._test_elements_eq_transitive() . . . pass + running ._test_elements_neq() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_one() . . . pass + running ._test_pickling() . . . pass + running ._test_prod() . . . pass + running ._test_some_elements() . . . pass + + :: + + sage: TestSuite(GrowthGroup('x^QQ * log(x)^ZZ')).run(verbose=True) + running ._test_an_element() . . . pass + running ._test_associativity() . . . pass + running ._test_category() . . . pass + running ._test_elements() . . . + Running the test suite of self.an_element() + running ._test_category() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + pass + running ._test_elements_eq_reflexive() . . . pass + running ._test_elements_eq_symmetric() . . . pass + running ._test_elements_eq_transitive() . . . pass + running ._test_elements_neq() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_one() . . . pass + running ._test_pickling() . . . pass + running ._test_prod() . . . pass + running ._test_some_elements() . . . pass """ def create_key_and_extra_args(self, specification, **kwds): r""" From dc3cbd8b711ff1e3c57e6a6aebabd44853ff9355 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 09:37:16 +0200 Subject: [PATCH 0688/1872] fix one doctest (changed repr-string) --- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 47d0c288beb..2e9c3479fe7 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -299,7 +299,7 @@ def some_elements(self): x^(-1/2)*log(x)*(-1/2)^y, x^2*log(x)^(-1)*2^y, x^(-2)*log(x)^2*(-2)^y, - log(x)^(-2)*(0)^y, + log(x)^(-2)*0^y, x*log(x)^3, x^(-1)*log(x)^(-3)*(-1)^y, x^42*log(x)^4*42^y, From 3a71b33f273be9645fe597b937e1f2c7467a4786 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 09:38:16 +0200 Subject: [PATCH 0689/1872] __invert__: precision-option as in log --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d520a644796..7d6a652b59e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -931,13 +931,15 @@ def _div_(self, other): return self * ~other - def __invert__(self): + def __invert__(self, precision=None): r""" Return the multiplicative inverse of this element. INPUT: - Nothing. + - ``precision`` -- the precision used for truncating the + expansion. If ``None`` (default value) is used, the + default precision of the parent is used. OUTPUT: @@ -971,7 +973,7 @@ def __invert__(self): sage: (a / 2).parent() Asymptotic Ring over Rational Field """ - if len(self.summands) == 0: + if not self.summands: raise ZeroDivisionError('Division by zero in %s.' % (self,)) elif len(self.summands) == 1: @@ -981,9 +983,9 @@ def __invert__(self): max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: - raise ValueError('Expression %s cannot be inverted, since there ' - 'are several maximal elements: %s.' % - (self, max_elem)) + raise ValueError('Expression %s cannot be inverted since there ' + 'are several maximal elements %s.' % + (self, ', '.join(str(e) for e in max_elem))) max_elem = max_elem[0] imax_elem = ~max_elem @@ -999,7 +1001,7 @@ def __invert__(self): expanding = True result = one while expanding: - new_result = (geom*result + one).truncate() + new_result = (geom*result + one).truncate(precision=precision) if new_result.has_same_summands(result): expanding = False result = new_result From 2696a5972ad1bf4fa0bdcd1c0d440e79944c0245 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 09:38:48 +0200 Subject: [PATCH 0690/1872] minor changes in doctstring of log --- src/sage/rings/asymptotic/asymptotic_ring.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 7d6a652b59e..fbb19a114c2 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1174,7 +1174,7 @@ def log(self, base=None, precision=None): - ``precision`` -- the precision used for truncating the expansion. If ``None`` (default value) is used, the - default precision from the parent is used. + default precision of the parent is used. OUTPUT: @@ -1184,10 +1184,13 @@ def log(self, base=None, precision=None): Computing the logarithm of an asymptotic expression is possible if and only if there is exactly one maximal - term in the expression. + summand in the expression. + + .. ALGORITHM:: - In case the expression has more than one term, - the well-known expansion for `\log(1+t)` is used. + If the expression has more than one summands, + the asymptotic expansion for `\log(1+t)` as `t` tends to `0` + is used. EXAMPLES:: @@ -1199,7 +1202,7 @@ def log(self, base=None, precision=None): sage: log(x-1) log(x) - x^(-1) - 1/2*x^(-2) - 1/3*x^(-3) - ... + O(x^(-21)) - :: + TESTS:: sage: log(R(1)) 0 From b1330e7cdc6c5f875ae641e2e9ccf225b5693780 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 09:39:02 +0200 Subject: [PATCH 0691/1872] rewrite AR.log --- src/sage/rings/asymptotic/asymptotic_ring.py | 35 +++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index fbb19a114c2..67f2eb61be9 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1209,38 +1209,49 @@ def log(self, base=None, precision=None): """ P = self.parent() - if len(self.summands) == 0: + if not self.summands: from sage.rings.infinity import minus_infinity return minus_infinity elif len(self.summands) == 1: if self == 1: - return P(0) - return P(next(self.summands.elements()).log_term(base=base)) + return self.parent().zero() + element = next(self.summands.elements()) + return sum(self.parent()._create_element_via_parent_(l, element.parent()) + for l in element.log_term(base=base)) max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: raise ValueError('log(%s) cannot be constructed since there ' - 'are several maximal elements: %s.' % (self, max_elem)) - - from sage.functions.log import log + 'are several maximal elements %s.' % + (self, ', '.join(str(e) for e in max_elem))) max_elem = max_elem[0] + imax_elem = ~max_elem - one = P.one() - geom = one - self._mul_term_(imax_elem) + if imax_elem.parent() is max_elem.parent(): + new_self = self + else: + new_self = self.parent()._create_element_via_parent_( + imax_elem, max_elem.parent()).parent()(self) + + one = new_self.parent().one() + geom = one - new_self._mul_term_(imax_elem) expanding = True result = -geom - k = 1 + geom_k = geom + k = one while expanding: - k += 1 - new_result = (result - geom**k / k).truncate(precision=precision) + k += one + geom_k *= geom + new_result = (result - geom_k / k).truncate(precision=precision) if new_result.has_same_summands(result): expanding = False result = new_result - result = log(P(max_elem)) + result + result += new_self.parent()(max_elem).log() if base: + from sage.functions.log import log result = result / log(base) return result From ab37f7261ea35042d098c2aa1ba127cb0b5fd40c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 11:14:20 +0200 Subject: [PATCH 0692/1872] modify _create_term_via_parent_: delete old_parent options since not needed --- src/sage/rings/asymptotic/growth_group.py | 16 ++++++--------- src/sage/rings/asymptotic/term_monoid.py | 24 ++++++++--------------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 41084394314..72213b028b4 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1250,7 +1250,7 @@ def some_elements(self): for e in self.base().some_elements()) - def _create_element_via_parent_(self, raw_element, old_parent=None): + def _create_element_via_parent_(self, raw_element): r""" Create an element with a possibly other parent. @@ -1270,14 +1270,10 @@ def _create_element_via_parent_(self, raw_element, old_parent=None): sage: G._create_element_via_parent_(3).parent() Growth Group z^ZZ sage: G._create_element_via_parent_(1/2).parent() - Traceback (most recent call last): - ... - TypeError: no conversion of this rational to integer - sage: G._create_element_via_parent_(1/2, ZZ).parent() Growth Group z^QQ """ from misc import underlying_class - if old_parent is None or raw_element.parent() is old_parent: + if raw_element.parent() is self.base(): parent = self else: parent = underlying_class(self)(raw_element.parent(), self._var_) @@ -1994,7 +1990,7 @@ def __invert__(self): sage: e2 == ~e1 True """ - return self.parent()._create_element_via_parent_(-self.exponent, self.exponent.parent()) + return self.parent()._create_element_via_parent_(-self.exponent) def __pow__(self, exponent): @@ -2028,7 +2024,7 @@ def __pow__(self, exponent): sage: b^12 x^42 """ - return self.parent()._create_element_via_parent_(self.exponent * exponent, self.exponent.parent()) + return self.parent()._create_element_via_parent_(self.exponent * exponent) def _le_(self, other): @@ -2539,7 +2535,7 @@ def __invert__(self): sage: (~P(raw_element=1)).parent() Growth Group QQ^x """ - return self.parent()._create_element_via_parent_(1 / self.base, self.base.parent()) + return self.parent()._create_element_via_parent_(1 / self.base) def __pow__(self, exponent): @@ -2569,7 +2565,7 @@ def __pow__(self, exponent): sage: b^12 117649^x """ - return self.parent()._create_element_via_parent_(self.base ** exponent, self.base.parent()) + return self.parent()._create_element_via_parent_(self.base ** exponent) def _le_(self, other): diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index c2a62abd2de..54fe8f8c0c3 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -441,8 +441,7 @@ def _calculate_pow_(self, exponent, coefficient=None): raise combine_exceptions( ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) - return self.parent()._create_element_via_parent_( - g, coefficient, self.parent().growth_group, self.parent().coefficient_ring) + return self.parent()._create_element_via_parent_(g, coefficient) def can_absorb(self, other): @@ -1351,8 +1350,7 @@ def _create_element_(self, growth, coefficient): return self.element_class(self, growth) - def _create_element_via_parent_(self, growth, coefficient, - old_parent_growth=None, old_parent_coefficient=None): + def _create_element_via_parent_(self, growth, coefficient): r""" Create an element with a possibly other parent. @@ -1360,10 +1358,6 @@ def _create_element_via_parent_(self, growth, coefficient, - ``growth`` and ``coefficient`` -- the element data. - - ``old_parent_growth`` and ``old_parent_coefficient`` -- the - parents of ``growth`` and ``coefficient`` are compared to - these parents. - OUTPUT: An element. @@ -1372,21 +1366,20 @@ def _create_element_via_parent_(self, growth, coefficient, sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') sage: T = TermMonoid('exact', G, ZZ) - sage: T._create_element_via_parent_(G.an_element(), 3, G, ZZ) + sage: T._create_element_via_parent_(G.an_element(), 3) 3*z - sage: T._create_element_via_parent_(G.an_element(), 3/2, G, ZZ).parent() + sage: T._create_element_via_parent_(G.an_element(), 3/2).parent() Exact Term Monoid z^ZZ with coefficients in Rational Field """ - if (old_parent_growth is None or growth.parent() is old_parent_growth) and \ - (old_parent_coefficient is None or - coefficient is not None and coefficient.parent() is old_parent_coefficient): + if (growth.parent() is self.growth_group) and \ + (coefficient is None or coefficient.parent() is self.coefficient_ring): parent = self else: from misc import underlying_class parent = underlying_class(self)(growth.parent(), coefficient.parent() if coefficient is not None - else old_parent_coefficient) + else self.coefficient_ring) return parent(growth, coefficient) @@ -2471,8 +2464,7 @@ def __invert__(self): raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' 'cannot be inverted.' % (self, self.coefficient)) g = ~self.growth - return self.parent()._create_element_via_parent_( - g, c, self.parent().growth_group, self.parent().coefficient_ring) + return self.parent()._create_element_via_parent_(g, c) def __pow__(self, exponent): From a160205a24671dcb942d671376f86cea40b57228 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 11:35:35 +0200 Subject: [PATCH 0693/1872] change doctests with FutureWarning at top --- src/sage/rings/asymptotic/term_monoid.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 54fe8f8c0c3..48082622b90 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -53,12 +53,13 @@ TESTS:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, TermMonoid) + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid sage: G = GrowthGroup('x^ZZ * log(x)^ZZ') 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/17601 for details. + sage: T = GenericTermMonoid(G, ZZ) """ # ***************************************************************************** From 7f7874334f620a6dbd2f60fed6f02541bae7cd34 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 11:36:14 +0200 Subject: [PATCH 0694/1872] fix a doctest in AsymptopicRing._construct_element_via_parent_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 67f2eb61be9..63942961410 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1630,14 +1630,10 @@ def _create_element_via_parent_(self, term, old_parent=None): An element. - sage: from sage.rings.asymptotic.term_monoid import TermMonoid - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('z^ZZ') - sage: T = TermMonoid('exact', G, ZZ) - sage: T._create_element_via_parent_(G.an_element(), 3, G, ZZ) - 3*z - sage: T._create_element_via_parent_(G.an_element(), 3/2, G, ZZ).parent() - Exact Term Monoid z^ZZ with coefficients in Rational Field + sage: A = AsymptoticRing('z^ZZ', ZZ) + sage: term = next(A.an_element().summands.elements_topological()) + sage: A._create_element_via_parent_(term, A) + O(z) """ if old_parent is None or term.parent() is old_parent: parent = self From 3d38d70e19e9881ae485477eccf70a0cc091c928 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 12:53:22 +0200 Subject: [PATCH 0695/1872] check implicit constant of O-Term (if given) --- src/sage/rings/asymptotic/term_monoid.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 48082622b90..45eb766af6a 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1852,6 +1852,15 @@ def _create_element_(self, growth, coefficient): sage: T_ZZ(G_ZZ.gen()) # indirect doctest O(x) """ + if coefficient is not None: + try: + self.coefficient_ring(coefficient) + except (TypeError, ValueError) as e: + from misc import combine_exceptions + raise combine_exceptions( + ValueError('Cannot create O(%s) since given coefficient %s ' + 'is not a valid in %s.' % + (growth, coefficient, self)), e) return self.element_class(self, growth) From 174f00fd26b2d71ba6741604f07d916141531c92 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 13:22:47 +0200 Subject: [PATCH 0696/1872] minor rewrites of docstrings of log_factor --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +- src/sage/rings/asymptotic/term_monoid.py | 70 ++++++++------------ 2 files changed, 29 insertions(+), 44 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 63942961410..1ea372c51d5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1169,8 +1169,7 @@ def log(self, base=None, precision=None): INPUT: - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the logarithm is the natural - logarithm. + (default value) is used, the natural logarithm is taken. - ``precision`` -- the precision used for truncating the expansion. If ``None`` (default value) is used, the diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 45eb766af6a..0036d900493 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -693,30 +693,27 @@ def _absorb_(self, other): def log_term(self, base=None): r""" - Return the logarithm of this term. - - This method returns a list with the summands that come from - applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. + Determine the logarithm of this term. INPUT: - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the logarithm is the natural - logarithm. + (default value) is used, the natural logarithm is taken. OUTPUT: - A list. + A tuple of terms. .. NOTE:: - This method is only implemented for :class:`ExactTerm` and - :class:`OTerm`. + This method returns a tuple with the summands that come from + applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. - .. SEEALSO:: + .. NOTE:: - :meth:`ExactTerm.log_term`, - :meth:`OTerm.log_term`. + This abstract method raises a + :class:`NotImplementedError`. See :class:`ExactTerm` and + :class:`OTerm` for a concrete implementation. EXAMPLES:: @@ -726,8 +723,8 @@ def log_term(self, base=None): sage: T.an_element().log_term() Traceback (most recent call last): ... - NotImplementedError: This method is only implemented for terms used - in AsymptoticExpression. + NotImplementedError: This method is not implemented in + this abstract base class. :: @@ -736,8 +733,13 @@ def log_term(self, base=None): sage: T.an_element().log_term() Traceback (most recent call last): ... - NotImplementedError: This method is only implemented for terms used - in AsymptoticExpression. + NotImplementedError: This method is not implemented in + this abstract base class. + + .. SEEALSO:: + + :meth:`ExactTerm.log_term`, + :meth:`OTerm.log_term`. """ raise NotImplementedError('This method is only implemented for terms' ' used in AsymptoticExpression.') @@ -1745,29 +1747,21 @@ def _absorb_(self, other): def log_term(self, base=None): r""" - Return the logarithm of this term. - - This method returns a list with the summands that come from - applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. + Determine the logarithm of this O-term. INPUT: - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the logarithm is the natural - logarithm. + (default value) is used, the natural logarithm is taken. OUTPUT: - A list. + A tuple of terms. .. NOTE:: - This method is only implemented for :class:`ExactTerm` and - :class:`OTerm`. - - .. SEEALSO:: - - :meth:`ExactTerm.log_term`. + This method returns a tuple with the summands that come from + applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. EXAMPLES:: @@ -2588,29 +2582,21 @@ def _absorb_(self, other): def log_term(self, base=None): r""" - Return the logarithm of this term. - - This method returns a list with the summands that come from - applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. + Determine the logarithm of this exact term. INPUT: - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the logarithm is the natural - logarithm. + (default value) is used, the natural logarithm is taken. OUTPUT: - A list. + A tuple of terms. .. NOTE:: - This method is only implemented for :class:`ExactTerm` and - :class:`OTerm`. - - .. SEEALSO:: - - :meth:`OTerm.log_term`. + This method returns a tuple with the summands that come from + applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. EXAMPLES:: From ab20a697c35569fdf4e230e440ad7c3072b812a6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 13:23:01 +0200 Subject: [PATCH 0697/1872] rewrite log_term --- src/sage/rings/asymptotic/term_monoid.py | 108 ++++++++++++++++++----- 1 file changed, 87 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 0036d900493..5a064862621 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -741,8 +741,40 @@ def log_term(self, base=None): :meth:`ExactTerm.log_term`, :meth:`OTerm.log_term`. """ - raise NotImplementedError('This method is only implemented for terms' - ' used in AsymptoticExpression.') + raise NotImplementedError('This method is not implemented in this ' + 'abstract base class.') + + + def _log_growth_(self, base=None): + r""" + Helper function to calculate the logarithm of the growth of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the natural logarithm is taken. + + OUTPUT: + + A tuple of terms. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('O', GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) + sage: T(x^2)._log_growth_() + (O(log(x)),) + sage: T(x^1234).log_term() # indirect doctest + (O(log(x)),) + + .. SEEALSO:: + + :meth:`ExactTerm.log_term`, + :meth:`OTerm.log_term`. + """ + return tuple(self.parent()._create_element_via_parent_(g, c) + for g, c in self.growth.log_factor(base=base)) def __le__(self, other): @@ -1769,20 +1801,22 @@ def log_term(self, base=None): sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: T = TermMonoid('O', GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) sage: T(x^2).log_term() - [O(log(x))] + (O(log(x)),) sage: T(x^1234).log_term() - [O(log(x))] + (O(log(x)),) :: sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid sage: T = TermMonoid('O', GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ'), QQ) sage: T('x * y').log_term() - [O(log(x)), O(log(y))] + (O(log(x)), O(log(y))) + + .. SEEALSO:: + + :meth:`ExactTerm.log_term`. """ - growth_log = self.growth.log_factor(base=base) - P = self.parent() - return [P(factor[0]) for factor in growth_log] + return self._log_growth_(base=base) class OTermMonoid(GenericTermMonoid): @@ -2123,6 +2157,41 @@ def _calculate_pow_(self, exponent): return super(TermWithCoefficient, self)._calculate_pow_(exponent, coefficient=c) + def _log_coefficient_(self, base=None): + r""" + Helper function to calculate the logarithm of the coefficient of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the natural logarithm is taken. + + OUTPUT: + + A tuple of terms. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('exact', GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) + sage: T(3*x^2)._log_coefficient_() + (log(3),) + sage: T(x^1234).log_term() # indirect doctest + (1234*log(x),) + + .. SEEALSO:: + + :meth:`ExactTerm.log_term`, + :meth:`OTerm.log_term`. + """ + if self.coefficient == self.parent().coefficient_ring.one(): + return tuple() + from sage.functions.log import log + return (self.parent()._create_element_via_parent_( + self.parent().growth_group.one(), log(self.coefficient, base=base)),) + + def _le_(self, other): r""" Return whether this asymptotic term with coefficient grows @@ -2604,28 +2673,25 @@ def log_term(self, base=None): sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: T = TermMonoid('exact', GrowthGroup('x^ZZ * log(x)^ZZ'), SR) sage: T(3*x^2).log_term() - [log(3), 2*log(x)] + (log(3), 2*log(x)) sage: T(x^1234).log_term() - [1234*log(x)] + (1234*log(x),) sage: T(49*x^7).log_term(base=7) - [log(49)/log(7), 7/log(7)*log(x)] + (log(49)/log(7), 7/log(7)*log(x)) :: sage: T = TermMonoid('exact', GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ'), SR) sage: T('x * y').log_term() - [log(x), log(y)] + (log(x), log(y)) sage: T('4 * x * y').log_term(base=2) - [log(4)/log(2), 1/log(2)*log(x), 1/log(2)*log(y)] + (log(4)/log(2), 1/log(2)*log(x), 1/log(2)*log(y)) + + .. SEEALSO:: + + :meth:`OTerm.log_term`. """ - from sage.functions.log import log - growth_log = self.growth.log_factor(base=base) - P = self.parent() - lst = [P(factor[0], factor[1]) for factor in growth_log] - if self.coefficient != P.coefficient_ring.one(): - lst = [P(self.growth.parent().one(), - log(self.coefficient, base=base))] + lst - return lst + return self._log_coefficient_(base=base) + self._log_growth_(base=base) class ExactTermMonoid(TermWithCoefficientMonoid): From c1200d7a0b3002480790672e2c90d8337ece2aeb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 13:25:02 +0200 Subject: [PATCH 0698/1872] minor rewrite of __ne__ --- src/sage/rings/asymptotic/growth_group.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 72213b028b4..25aa2c8bad0 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -351,7 +351,7 @@ def __ne__(self, other): sage: Variable('x') != Variable('y') True """ - return not self.__eq__(other) + return not self == other def _repr_(self): @@ -823,7 +823,7 @@ def __ne__(self, other): sage: G(1) != G(1) False """ - return not self.__eq__(other) + return not self == other def __le__(self, other): @@ -1841,7 +1841,7 @@ def __ne__(self, other): sage: F != G True """ - return not self.__eq__(other) + return not self == other class MonomialGrowthElement(GenericGrowthElement): From b3f555aa50e2f8f21bb681ac61afc62c1d3426d9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 13:57:24 +0200 Subject: [PATCH 0699/1872] minor changes in docstring of log_factor --- src/sage/rings/asymptotic/growth_group.py | 5 ++--- src/sage/rings/asymptotic/growth_group_cartesian.py | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 25aa2c8bad0..cc4981afce3 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -902,13 +902,12 @@ def _le_(self, other): def log(self, base=None): r""" - The logarithm of this element. + Return the logarithm of this element. INPUT: - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the logarithm is the natural - logarithm. + (default value) is used, the natural logarithm is taken. OUTPUT: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 2e9c3479fe7..7200e781004 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -797,13 +797,12 @@ def _repr_(self): def log(self, base=None): r""" - The logarithm of this element. + Return the logarithm of this element. INPUT: - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the logarithm is the natural - logarithm. + (default value) is used, the natural logarithm is taken. OUTPUT: From 94a700e2278be6616458e7f84ab09c75a2282a0c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 13:58:53 +0200 Subject: [PATCH 0700/1872] rewrite .factors --- src/sage/rings/asymptotic/growth_group.py | 23 +++++++ .../asymptotic/growth_group_cartesian.py | 65 ++++++++----------- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cc4981afce3..70e6020edc1 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -939,6 +939,29 @@ def log(self, base=None): raise ArithmeticError('building log(%s) is not possible.' % (self,)) + def factors(self): + r""" + Return the atomic factors of this growth element. An atomic factor + cannot be split further. + + INPUT: + + Nothing. + + OUTPUT: + + A tuple of growth elements. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ') + sage: G.an_element().factors() + (x,) + """ + return (self,) + + class GenericGrowthGroup( sage.structure.unique_representation.UniqueRepresentation, sage.structure.parent.Parent): diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 7200e781004..c071673581a 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -850,10 +850,10 @@ def log(self, base=None): raise ValueError('The logarithm of %s cannot be constructed in ' '%s.' % (self, self.parent())) - def factor(self): + def factors(self): r""" - Return a factorization of this element into growth - elements from atomic growth groups. + Return the atomic factors of this growth element. An atomic factor + cannot be split further. INPUT: @@ -861,52 +861,41 @@ def factor(self): OUTPUT: - A list of growth elements. + A tuple of growth elements. EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ * log(x)^ZZ * y^ZZ') sage: x, y = G.gens_monomial() - sage: x.factor() - [x] - sage: f = (x * y).factor(); f - [x, y] - sage: [factor.parent() for factor in f] - [Growth Group x^ZZ, Growth Group y^ZZ] - sage: f = (x * log(x)).factor(); f - [x, log(x)] - sage: [factor.parent() for factor in f] - [Growth Group x^ZZ, Growth Group log(x)^ZZ] + sage: x.factors() + (x,) + sage: f = (x * y).factors(); f + (x, y) + sage: tuple(factor.parent() for factor in f) + (Growth Group x^ZZ, Growth Group y^ZZ) + sage: f = (x * log(x)).factors(); f + (x, log(x)) + sage: tuple(factor.parent() for factor in f) + (Growth Group x^ZZ, Growth Group log(x)^ZZ) :: sage: G = GrowthGroup('x^ZZ * log(x)^ZZ * log(log(x))^ZZ * y^QQ') sage: x, y = G.gens_monomial() - sage: f = (x * log(x) * y).factor(); f - [x, log(x), y] - sage: [factor.parent() for factor in f] - [Growth Group x^ZZ, Growth Group log(x)^ZZ, Growth Group y^QQ] + sage: f = (x * log(x) * y).factors(); f + (x, log(x), y) + sage: tuple(factor.parent() for factor in f) + (Growth Group x^ZZ, Growth Group log(x)^ZZ, Growth Group y^QQ) :: - sage: G.one().factor() - Traceback (most recent call last): - ... - ValueError: 1 does not have a factorization. + sage: G.one().factors() + () """ - components = [] - for (component, factor) in zip(self.value, - self.parent().cartesian_factors()): - if component != factor.one(): - if hasattr(component, 'factor'): - components = components + component.factor() - else: - components.append(component) + return sum(iter(f.factors() for f in self.value if f != f.parent().one()), + tuple()) - if components: - return components - raise ValueError('%s does not have a factorization.' % (self,)) def log_factor(self, base=None): r""" @@ -948,9 +937,7 @@ def log_factor(self, base=None): :: sage: G(1).log_factor() - Traceback (most recent call last): - ... - ValueError: 1 does not have a factorization. + () :: @@ -968,7 +955,7 @@ def log_factor(self, base=None): [[x, 1], [log(x), 1]] """ P = self.parent() - factors = self.factor() + factors = self.factors() log_factors = [] from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup, \ MonomialGrowthGroup @@ -1051,7 +1038,7 @@ def rpow(self, base): 2^(x*log(x)) """ P = self.parent() - factors = self.factor() + factors = self.factors() if base == 0: raise ValueError('%s is not an allowed base.' % (base,)) @@ -1064,7 +1051,7 @@ def rpow(self, base): new_elem = P(repr(fp._var_)[4:-1]) if base == 'e': return new_elem - base_ring = new_elem.factor()[0].base_ring() + base_ring = new_elem.factors()[0].base_ring() return new_elem ** log(base_ring(base)) from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup From a7f5ce04693be1cb1a16f46a71aceda88079955b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 15:01:43 +0200 Subject: [PATCH 0701/1872] growth group: 1.factor() --> [] (instead of error) --- src/sage/rings/asymptotic/growth_group_cartesian.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 2e9c3479fe7..d81153ff0c3 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -949,9 +949,7 @@ def log_factor(self, base=None): :: sage: G(1).log_factor() - Traceback (most recent call last): - ... - ValueError: 1 does not have a factorization. + [] :: @@ -969,6 +967,10 @@ def log_factor(self, base=None): [[x, 1], [log(x), 1]] """ P = self.parent() + + if self == P.one(): + return [] + factors = self.factor() log_factors = [] from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup, \ From 2613712ba65e4b0fba14abb2679ade637131eac1 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 15:02:09 +0200 Subject: [PATCH 0702/1872] tests for log-factorization of exact terms added --- src/sage/rings/asymptotic/term_monoid.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index c2a62abd2de..41dc5eb44dd 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2629,6 +2629,19 @@ def log_term(self, base=None): [log(x), log(y)] sage: T('4 * x * y').log_term(base=2) [log(4)/log(2), 1/log(2)*log(x), 1/log(2)*log(y)] + + TESTS:: + + sage: T = TermMonoid('exact', GrowthGroup('x^ZZ * log(x)^ZZ'), SR) + sage: T('2 * x').log_term() + [log(2), log(x)] + sage: T(7).log_term() + [log(7)] + sage: T(1).log_term() + [] + sage: T(49).log_term(base=7) + [log(49)/log(7)] + """ from sage.functions.log import log growth_log = self.growth.log_factor(base=base) From ba62bfb95d9d81ef448166774d04be7d12fcf375 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 17:58:10 +0200 Subject: [PATCH 0703/1872] rewrite log_factor --- src/sage/rings/asymptotic/growth_group.py | 30 +++++ .../asymptotic/growth_group_cartesian.py | 106 +++++++++--------- 2 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 70e6020edc1..731857e13c3 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -939,6 +939,11 @@ def log(self, base=None): raise ArithmeticError('building log(%s) is not possible.' % (self,)) + def _log_factor_(self, base=None): + raise ValueError('Cannot determine logarithmized factorization of %s ' + 'in abstract base class.' % (self,)) + + def factors(self): r""" Return the atomic factors of this growth element. An atomic factor @@ -2049,6 +2054,16 @@ def __pow__(self, exponent): return self.parent()._create_element_via_parent_(self.exponent * exponent) + def _log_factor_(self, base=None): + if self == self.parent().one(): + return tuple() + coefficient = self.exponent + if base is not None: + from sage.functions.log import log + coefficient = coefficient / log(base) + return (('log(%s)' % (self.parent()._var_,), coefficient),) + + def _le_(self, other): r""" Return if this :class:`MonomialGrowthElement` is at most @@ -2590,6 +2605,21 @@ def __pow__(self, exponent): return self.parent()._create_element_via_parent_(self.base ** exponent) + def _log_factor_(self, base=None): + if self == self.parent().one(): + return tuple() + b = self.base + if base is None and \ + hasattr(b, 'is_monomial') and b.is_monomial() and \ + b.variable_name() == 'e': + coefficient = b.valuation() + else: + from sage.functions.log import log + coefficient = log(b, base=base) + + return ((str(self.parent()._var_), coefficient),) + + def _le_(self, other): r""" Return if this :class:`ExponentialGrowthElement` is at most diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index c071673581a..e92f1c242b7 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -795,6 +795,7 @@ def _repr_(self): return '1' return s + def log(self, base=None): r""" Return the logarithm of this element. @@ -850,6 +851,7 @@ def log(self, base=None): raise ValueError('The logarithm of %s cannot be constructed in ' '%s.' % (self, self.parent())) + def factors(self): r""" Return the atomic factors of this growth element. An atomic factor @@ -893,7 +895,9 @@ def factors(self): sage: G.one().factors() () """ - return sum(iter(f.factors() for f in self.value if f != f.parent().one()), + return sum(iter(f.factors() + for f in self.cartesian_factors() + if f != f.parent().one()), tuple()) @@ -902,25 +906,20 @@ def log_factor(self, base=None): Return the logarithm of the factorization of this element. - In particular, this function yields a list of pairs - consisting of the growth and the corresponding - coefficient resulting from taking the logarithm of every - atomic factor of this element. - INPUT: - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the logarithm is the natural - logarithm. + (default value) is used, the natural logarithm is taken. OUTPUT: - A list. + A tuple of pairs, where the first entry is a growth + element and the second a multiplicative coefficient. - .. SEEALSO:: + .. ALGORITHM:: - :meth:`factor`, - :meth:`log`. + This function factors the given element and calculates + the logarithm of each of these factors. EXAMPLES:: @@ -928,11 +927,11 @@ def log_factor(self, base=None): sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ') sage: x, y = G.gens_monomial() sage: (x * y).log_factor() - [[log(x), 1], [log(y), 1]] + ((log(x), 1), (log(y), 1)) sage: (x^123).log_factor() - [[log(x), 123]] + ((log(x), 123),) sage: (G('2^x') * x^2).log_factor(base=2) - [[x, 1], [log(x), 2/log(2)]] + ((x, 1), (log(x), 2/log(2))) :: @@ -944,55 +943,56 @@ def log_factor(self, base=None): sage: log(x).log_factor() Traceback (most recent call last): ... - ValueError: Logarithm of log(x) cannot be constructed in Growth - Group QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ. + ArithmeticError: Cannot build log(log(x)) since log(log(x)) is + not in Growth Group QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ. + + .. SEEALSO:: + + :meth:`factor`, + :meth:`log`. TESTS:: sage: G = GrowthGroup("QQ['e']^x * x^ZZ * log(x)^ZZ") sage: x, = G.gens_monomial() sage: (exp(x) * x).log_factor() - [[x, 1], [log(x), 1]] + ((x, 1), (log(x), 1)) """ - P = self.parent() - factors = self.factors() - log_factors = [] - from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup, \ - MonomialGrowthGroup - from sage.functions.log import log + log_factor = self._log_factor_(base=base) - for factor in factors: - try: - FP = factor.parent() - if isinstance(FP, MonomialGrowthGroup): - if base is None: - coef = factor._raw_element_ - else: - coef = factor._raw_element_ / log(base) - growth = P('log(' + repr(FP._var_) + ')') - log_factors.append([growth, coef]) - - elif isinstance(FP, ExponentialGrowthGroup): - b = factor._raw_element_ - if hasattr(b, 'is_monomial') and b.is_monomial(): - if b.variable_name() == 'e' and not base: - coef = b.valuation() - else: - coef = log(b, base=base) - - growth = P(repr(FP._var_)) - log_factors.append([growth, coef]) + from growth_group import GenericGrowthGroup + for g, c in log_factor: + if hasattr(g, 'parent') and \ + isinstance(g.parent(), GenericGrowthGroup): + continue + raise ArithmeticError('Cannot build log(%s) since %s ' + 'is not in %s.' % (self, g, self.parent())) - else: - raise NotImplementedError('Taking the logarithm of %s ' - 'is not implemented.' % - (factor,)) + return log_factor - except (ValueError, TypeError): - raise ValueError('Logarithm of %s cannot be ' - 'constructed in %s.' % (factor, P)) - return log_factors + def _log_factor_(self, base=None): + if self == self.parent().one(): + return tuple() + + def try_create_growth(g): + try: + return self.parent()(g) + except (TypeError, ValueError): + return g + + try: + return sum(iter(tuple((try_create_growth(g), c) + for g, c in factor._log_factor_(base=base)) + for factor in self.cartesian_factors() + if factor != factor.parent().one()), + tuple()) + except (ArithmeticError, TypeError, ValueError) as e: + from misc import combine_exceptions + raise combine_exceptions( + ArithmeticError('Cannot build log(%s) in %s.' % + (self, self.parent())), e) + def rpow(self, base): r""" From b8208a4c5ff01601a468c27d79a2b817566ae505 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 18:12:13 +0200 Subject: [PATCH 0704/1872] doc of _log_factor_ helper method --- src/sage/rings/asymptotic/growth_group.py | 67 ++++++++++++++++++- .../asymptotic/growth_group_cartesian.py | 22 ++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 731857e13c3..6222c4539d4 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -940,8 +940,29 @@ def log(self, base=None): def _log_factor_(self, base=None): - raise ValueError('Cannot determine logarithmized factorization of %s ' - 'in abstract base class.' % (self,)) + r""" + Helper method for calculating the logarithm of the factorization + of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the natural logarithm is taken. + + OUTPUT: + + A tuple of pairs, where the first entry is either a growth + element or something out of which we can construct a growth element + and the second a multiplicative coefficient. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x') + sage: G('x').log_factor() # indirect doctest + """ + raise NotImplementedError('Cannot determine logarithmized factorization ' + 'of %s in abstract base class.' % (self,)) def factors(self): @@ -2055,6 +2076,27 @@ def __pow__(self, exponent): def _log_factor_(self, base=None): + r""" + Helper method for calculating the logarithm of the factorization + of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the natural logarithm is taken. + + OUTPUT: + + A tuple of pairs, where the first entry is either a growth + element or something out of which we can construct a growth element + and the second a multiplicative coefficient. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x') + sage: G('x').log_factor() # indirect doctest + """ if self == self.parent().one(): return tuple() coefficient = self.exponent @@ -2606,6 +2648,27 @@ def __pow__(self, exponent): def _log_factor_(self, base=None): + r""" + Helper method for calculating the logarithm of the factorization + of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the natural logarithm is taken. + + OUTPUT: + + A tuple of pairs, where the first entry is either a growth + element or something out of which we can construct a growth element + and the second a multiplicative coefficient. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x') + sage: G('x').log_factor() # indirect doctest + """ if self == self.parent().one(): return tuple() b = self.base diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index e92f1c242b7..a1982876866 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -972,6 +972,28 @@ def log_factor(self, base=None): def _log_factor_(self, base=None): + r""" + Helper method for calculating the logarithm of the factorization + of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the natural logarithm is taken. + + OUTPUT: + + A tuple of pairs, where the first entry is either a growth + element or something out of which we can construct a growth element + and the second a multiplicative coefficient. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ') + sage: x, y = G.gens_monomial() + sage: (x * y).log_factor() # indirect doctest + """ if self == self.parent().one(): return tuple() From d379d1caf492c9d3869bb91f98e73d3b5cfea331 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 18:15:37 +0200 Subject: [PATCH 0705/1872] fixed algorithm-block --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 67f2eb61be9..70a40815a25 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1186,11 +1186,11 @@ def log(self, base=None, precision=None): is possible if and only if there is exactly one maximal summand in the expression. - .. ALGORITHM:: + ALGORITHM: - If the expression has more than one summands, - the asymptotic expansion for `\log(1+t)` as `t` tends to `0` - is used. + If the expression has more than one summand, + the asymptotic expansion for `\log(1+t)` as `t` tends to `0` + is used. EXAMPLES:: From 15fb90037889584f8036ec5ccecdae91673ac9c7 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 18:16:00 +0200 Subject: [PATCH 0706/1872] self.parent() --> P in some cases --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 70a40815a25..70065743337 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1215,9 +1215,9 @@ def log(self, base=None, precision=None): elif len(self.summands) == 1: if self == 1: - return self.parent().zero() + return P.zero() element = next(self.summands.elements()) - return sum(self.parent()._create_element_via_parent_(l, element.parent()) + return sum(P._create_element_via_parent_(l, element.parent()) for l in element.log_term(base=base)) max_elem = tuple(self.summands.maximal_elements()) @@ -1231,7 +1231,7 @@ def log(self, base=None, precision=None): if imax_elem.parent() is max_elem.parent(): new_self = self else: - new_self = self.parent()._create_element_via_parent_( + new_self = P._create_element_via_parent_( imax_elem, max_elem.parent()).parent()(self) one = new_self.parent().one() From ec26132de7e9989f5891a9b46a2723c686fd4c8a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 18:20:37 +0200 Subject: [PATCH 0707/1872] documentation in reference/asymptotic_ring --- src/doc/en/reference/asymptotic_ring/conf.py | 1 + src/doc/en/reference/asymptotic_ring/index.rst | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 120000 src/doc/en/reference/asymptotic_ring/conf.py create mode 100644 src/doc/en/reference/asymptotic_ring/index.rst diff --git a/src/doc/en/reference/asymptotic_ring/conf.py b/src/doc/en/reference/asymptotic_ring/conf.py new file mode 120000 index 00000000000..2bdf7e68470 --- /dev/null +++ b/src/doc/en/reference/asymptotic_ring/conf.py @@ -0,0 +1 @@ +../conf_sub.py \ No newline at end of file diff --git a/src/doc/en/reference/asymptotic_ring/index.rst b/src/doc/en/reference/asymptotic_ring/index.rst new file mode 100644 index 00000000000..9c85b83e0e2 --- /dev/null +++ b/src/doc/en/reference/asymptotic_ring/index.rst @@ -0,0 +1,12 @@ +Asymptotic Computations +======================= + + +.. toctree:: + :maxdepth: 2 + + sage/rings/asymptotic/asymptotic_ring + sage/rings/asymptotic/growth_group + sage/rings/asymptotic/growth_group_cartesian + sage/rings/asymptotic/term_monoid + sage/rings/asymptotic/misc From 63435e391eb75d06a6f2d0416309f85e57717fea Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 18:30:10 +0200 Subject: [PATCH 0708/1872] removed other references to rings/asymptotic --- src/doc/en/reference/groups/index.rst | 3 --- src/doc/en/reference/monoids/index.rst | 2 -- src/doc/en/reference/rings/index.rst | 1 - 3 files changed, 6 deletions(-) diff --git a/src/doc/en/reference/groups/index.rst b/src/doc/en/reference/groups/index.rst index 4132441b85a..3ef8d105455 100644 --- a/src/doc/en/reference/groups/index.rst +++ b/src/doc/en/reference/groups/index.rst @@ -56,9 +56,6 @@ Groups sage/groups/perm_gps/partn_ref sage/groups/perm_gps/partn_ref2 - sage/rings/asymptotic/growth_group - sage/rings/asymptotic/growth_group_cartesian - Internals --------- diff --git a/src/doc/en/reference/monoids/index.rst b/src/doc/en/reference/monoids/index.rst index 2584fd9bc77..de4db62002d 100644 --- a/src/doc/en/reference/monoids/index.rst +++ b/src/doc/en/reference/monoids/index.rst @@ -20,6 +20,4 @@ finite number of indeterminates. sage/monoids/string_ops - sage/rings/asymptotic/term_monoid - .. include:: ../footer.txt diff --git a/src/doc/en/reference/rings/index.rst b/src/doc/en/reference/rings/index.rst index 9d0771d5468..607830c10a6 100644 --- a/src/doc/en/reference/rings/index.rst +++ b/src/doc/en/reference/rings/index.rst @@ -18,7 +18,6 @@ General Rings, Ideals, and Morphisms sage/rings/quotient_ring_element sage/rings/invariant_theory - sage/rings/asymptotic/asymptotic_ring sage/rings/bernmm sage/rings/bernoulli_mod_p sage/rings/big_oh From 53c1698edacd16822e8f69d7e7f0b9d184acfe95 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 18:30:29 +0200 Subject: [PATCH 0709/1872] added footer to asymptotic_ring/index.rst --- src/doc/en/reference/asymptotic_ring/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/en/reference/asymptotic_ring/index.rst b/src/doc/en/reference/asymptotic_ring/index.rst index 9c85b83e0e2..326375a5766 100644 --- a/src/doc/en/reference/asymptotic_ring/index.rst +++ b/src/doc/en/reference/asymptotic_ring/index.rst @@ -10,3 +10,5 @@ Asymptotic Computations sage/rings/asymptotic/growth_group_cartesian sage/rings/asymptotic/term_monoid sage/rings/asymptotic/misc + +.. include:: ../footer.txt From 03d4b95bcb617f69b016db768ac931af64f31e2d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 18:31:59 +0200 Subject: [PATCH 0710/1872] move log_factor to growth_group --- src/sage/rings/asymptotic/growth_group.py | 70 +++++++++++++++++++ .../asymptotic/growth_group_cartesian.py | 68 ------------------ 2 files changed, 70 insertions(+), 68 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6222c4539d4..ae26e6b1d3a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -528,6 +528,76 @@ def strip(s): return tuple(vars) +def log_factor(self, base=None): + r""" + Return the logarithm of the factorization of this + element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the natural logarithm is taken. + + OUTPUT: + + A tuple of pairs, where the first entry is a growth + element and the second a multiplicative coefficient. + + .. ALGORITHM:: + + This function factors the given element and calculates + the logarithm of each of these factors. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ') + sage: x, y = G.gens_monomial() + sage: (x * y).log_factor() + ((log(x), 1), (log(y), 1)) + sage: (x^123).log_factor() + ((log(x), 123),) + sage: (G('2^x') * x^2).log_factor(base=2) + ((x, 1), (log(x), 2/log(2))) + + :: + + sage: G(1).log_factor() + () + + :: + + sage: log(x).log_factor() + Traceback (most recent call last): + ... + ArithmeticError: Cannot build log(log(x)) since log(log(x)) is + not in Growth Group QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ. + + .. SEEALSO:: + + :meth:`factor`, + :meth:`log`. + + TESTS:: + + sage: G = GrowthGroup("QQ['e']^x * x^ZZ * log(x)^ZZ") + sage: x, = G.gens_monomial() + sage: (exp(x) * x).log_factor() + ((x, 1), (log(x), 1)) + """ + log_factor = self._log_factor_(base=base) + + from growth_group import GenericGrowthGroup + for g, c in log_factor: + if hasattr(g, 'parent') and \ + isinstance(g.parent(), GenericGrowthGroup): + continue + raise ArithmeticError('Cannot build log(%s) since %s ' + 'is not in %s.' % (self, g, self.parent())) + + return log_factor + + class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): r""" An abstract implementation of a generic growth element. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index a1982876866..f47d9eb4510 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -901,74 +901,6 @@ def factors(self): tuple()) - def log_factor(self, base=None): - r""" - Return the logarithm of the factorization of this - element. - - INPUT: - - - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the natural logarithm is taken. - - OUTPUT: - - A tuple of pairs, where the first entry is a growth - element and the second a multiplicative coefficient. - - .. ALGORITHM:: - - This function factors the given element and calculates - the logarithm of each of these factors. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ') - sage: x, y = G.gens_monomial() - sage: (x * y).log_factor() - ((log(x), 1), (log(y), 1)) - sage: (x^123).log_factor() - ((log(x), 123),) - sage: (G('2^x') * x^2).log_factor(base=2) - ((x, 1), (log(x), 2/log(2))) - - :: - - sage: G(1).log_factor() - () - - :: - - sage: log(x).log_factor() - Traceback (most recent call last): - ... - ArithmeticError: Cannot build log(log(x)) since log(log(x)) is - not in Growth Group QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ. - - .. SEEALSO:: - - :meth:`factor`, - :meth:`log`. - - TESTS:: - - sage: G = GrowthGroup("QQ['e']^x * x^ZZ * log(x)^ZZ") - sage: x, = G.gens_monomial() - sage: (exp(x) * x).log_factor() - ((x, 1), (log(x), 1)) - """ - log_factor = self._log_factor_(base=base) - - from growth_group import GenericGrowthGroup - for g, c in log_factor: - if hasattr(g, 'parent') and \ - isinstance(g.parent(), GenericGrowthGroup): - continue - raise ArithmeticError('Cannot build log(%s) since %s ' - 'is not in %s.' % (self, g, self.parent())) - - return log_factor def _log_factor_(self, base=None): From d825419dadef9f5da6bd36f2bcf56a2478bdcb02 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 18:32:32 +0200 Subject: [PATCH 0711/1872] make log_factor working again --- src/sage/rings/asymptotic/growth_group.py | 3 +++ src/sage/rings/asymptotic/growth_group_cartesian.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ae26e6b1d3a..6f8be456f36 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1009,6 +1009,9 @@ def log(self, base=None): raise ArithmeticError('building log(%s) is not possible.' % (self,)) + log_factor = log_factor + + def _log_factor_(self, base=None): r""" Helper method for calculating the logarithm of the factorization diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index f47d9eb4510..0818f820f19 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -901,6 +901,8 @@ def factors(self): tuple()) + from growth_group import log_factor + log_factor = log_factor def _log_factor_(self, base=None): From 3ac612b93d2c46db286894018bcc08ed0c898769 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 18:32:57 +0200 Subject: [PATCH 0712/1872] fix doc and doctests --- src/sage/rings/asymptotic/growth_group.py | 22 ++++++++++++++----- .../asymptotic/growth_group_cartesian.py | 3 ++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6f8be456f36..0f149dbf175 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1030,9 +1030,13 @@ def _log_factor_(self, base=None): TESTS:: - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('QQ^x') - sage: G('x').log_factor() # indirect doctest + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(QQ) + sage: G.an_element().log_factor() # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: Cannot determine logarithmized factorization of + GenericGrowthElement(1/2) in abstract base class. """ raise NotImplementedError('Cannot determine logarithmized factorization ' 'of %s in abstract base class.' % (self,)) @@ -2167,8 +2171,12 @@ def _log_factor_(self, base=None): TESTS:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('QQ^x') + sage: G = GrowthGroup('x^QQ') sage: G('x').log_factor() # indirect doctest + Traceback (most recent call last): + ... + ArithmeticError: Cannot build log(x) since log(x) is not in + Growth Group x^QQ. """ if self == self.parent().one(): return tuple() @@ -2740,7 +2748,11 @@ def _log_factor_(self, base=None): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('QQ^x') - sage: G('x').log_factor() # indirect doctest + sage: G('4^x').log_factor(base=2) # indirect doctest + Traceback (most recent call last): + ... + ArithmeticError: Cannot build log(4^x) since x is not in + Growth Group QQ^x. """ if self == self.parent().one(): return tuple() diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 0818f820f19..6e36752a249 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -855,7 +855,7 @@ def log(self, base=None): def factors(self): r""" Return the atomic factors of this growth element. An atomic factor - cannot be split further. + cannot be split further and is not the identity (`1`). INPUT: @@ -927,6 +927,7 @@ def _log_factor_(self, base=None): sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ') sage: x, y = G.gens_monomial() sage: (x * y).log_factor() # indirect doctest + ((log(x), 1), (log(y), 1)) """ if self == self.parent().one(): return tuple() From 4629e82695697bd4c5c2cb0495800dde2f12b1fe Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 18:50:49 +0200 Subject: [PATCH 0713/1872] improve doc of log --- .../asymptotic/growth_group_cartesian.py | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 6e36752a249..f7e6eab7369 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -819,7 +819,8 @@ def log(self, base=None): sage: log(x^5) Traceback (most recent call last): ... - ValueError: The logarithm of x^5 cannot be constructed in Growth Group x^ZZ * log(x)^ZZ. + ArithmeticError: When calculating log(x^5) a factor 5 != 1 appeared, + which is not contained in Growth Group x^ZZ * log(x)^ZZ. :: @@ -830,7 +831,8 @@ def log(self, base=None): sage: log(el) Traceback (most recent call last): ... - ValueError: The logarithm of 2^x cannot be constructed in Growth Group QQ^x * x^ZZ. + ArithmeticError: When calculating log(2^x) a factor log(2) != 1 + appeared, which is not contained in Growth Group QQ^x * x^ZZ. sage: log(el, base=2) x @@ -840,16 +842,33 @@ def log(self, base=None): sage: x, = G.gens_monomial() sage: log(exp(x)) x + + :: + + sage: G.one().log() + Traceback (most recent call last): + ... + ArithmeticError: log(1) is zero, which is not contained in + Growth Group (Univariate Polynomial Ring in e over + Rational Field)^x * x^ZZ. """ - lf = self.log_factor(base=base) - if len(lf) == 1 and lf[0][1] == 1: - return lf[0][0] - if base: - raise ValueError('The logarithm of %s with base %s cannot be ' - 'constructed in %s.' % (self, base, self.parent())) - - raise ValueError('The logarithm of %s cannot be constructed in ' - '%s.' % (self, self.parent())) + log_factor = self.log_factor(base=base) + if not log_factor: + raise ArithmeticError('log(%s) is zero, ' + 'which is not contained in %s.' % + (self, self.parent())) + + if len(log_factor) != 1: + raise ArithmeticError('Calculating log(%s) results in a sum, ' + 'which is not contained in %s.' % + (self, self.parent())) + g, c = log_factor[0] + if c != 1: + raise ArithmeticError('When calculating log(%s) a factor %s != 1 ' + 'appeared, which is not contained in %s.' % + (self, c, self.parent())) + return g + def factors(self): From 15cc256e6778149263b243a0df7bc4c0c201e9bd Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 18:52:22 +0200 Subject: [PATCH 0714/1872] move log to growth_group --- src/sage/rings/asymptotic/growth_group.py | 75 ++++++++++++++++++ .../asymptotic/growth_group_cartesian.py | 78 +------------------ 2 files changed, 77 insertions(+), 76 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 0f149dbf175..f3881566bf6 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -528,6 +528,80 @@ def strip(s): return tuple(vars) +def log(self, base=None): + r""" + Return the logarithm of this element. + + INPUT: + + - ``base`` -- the base of the logarithm. If ``None`` + (default value) is used, the natural logarithm is taken. + + OUTPUT: + + A growth element. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * log(x)^ZZ') + sage: x, = G.gens_monomial() + sage: log(x) # indirect doctest + log(x) + sage: log(x^5) + Traceback (most recent call last): + ... + ArithmeticError: When calculating log(x^5) a factor 5 != 1 appeared, + which is not contained in Growth Group x^ZZ * log(x)^ZZ. + + :: + + sage: G = GrowthGroup('QQ^x * x^ZZ') + sage: x, = G.gens_monomial() + sage: el = x.rpow(2); el + 2^x + sage: log(el) + Traceback (most recent call last): + ... + ArithmeticError: When calculating log(2^x) a factor log(2) != 1 + appeared, which is not contained in Growth Group QQ^x * x^ZZ. + sage: log(el, base=2) + x + + TESTS:: + + sage: G = GrowthGroup("QQ['e']^x * x^ZZ") + sage: x, = G.gens_monomial() + sage: log(exp(x)) + x + + :: + + sage: G.one().log() + Traceback (most recent call last): + ... + ArithmeticError: log(1) is zero, which is not contained in + Growth Group (Univariate Polynomial Ring in e over + Rational Field)^x * x^ZZ. + """ + log_factor = self.log_factor(base=base) + if not log_factor: + raise ArithmeticError('log(%s) is zero, ' + 'which is not contained in %s.' % + (self, self.parent())) + + if len(log_factor) != 1: + raise ArithmeticError('Calculating log(%s) results in a sum, ' + 'which is not contained in %s.' % + (self, self.parent())) + g, c = log_factor[0] + if c != 1: + raise ArithmeticError('When calculating log(%s) a factor %s != 1 ' + 'appeared, which is not contained in %s.' % + (self, c, self.parent())) + return g + + def log_factor(self, base=None): r""" Return the logarithm of the factorization of this @@ -1009,6 +1083,7 @@ def log(self, base=None): raise ArithmeticError('building log(%s) is not possible.' % (self,)) + log = log log_factor = log_factor diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index f7e6eab7369..2790c5aa59d 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -796,81 +796,6 @@ def _repr_(self): return s - def log(self, base=None): - r""" - Return the logarithm of this element. - - INPUT: - - - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the natural logarithm is taken. - - OUTPUT: - - A growth element. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('x^ZZ * log(x)^ZZ') - sage: x, = G.gens_monomial() - sage: log(x) # indirect doctest - log(x) - sage: log(x^5) - Traceback (most recent call last): - ... - ArithmeticError: When calculating log(x^5) a factor 5 != 1 appeared, - which is not contained in Growth Group x^ZZ * log(x)^ZZ. - - :: - - sage: G = GrowthGroup('QQ^x * x^ZZ') - sage: x, = G.gens_monomial() - sage: el = x.rpow(2); el - 2^x - sage: log(el) - Traceback (most recent call last): - ... - ArithmeticError: When calculating log(2^x) a factor log(2) != 1 - appeared, which is not contained in Growth Group QQ^x * x^ZZ. - sage: log(el, base=2) - x - - TESTS:: - - sage: G = GrowthGroup("QQ['e']^x * x^ZZ") - sage: x, = G.gens_monomial() - sage: log(exp(x)) - x - - :: - - sage: G.one().log() - Traceback (most recent call last): - ... - ArithmeticError: log(1) is zero, which is not contained in - Growth Group (Univariate Polynomial Ring in e over - Rational Field)^x * x^ZZ. - """ - log_factor = self.log_factor(base=base) - if not log_factor: - raise ArithmeticError('log(%s) is zero, ' - 'which is not contained in %s.' % - (self, self.parent())) - - if len(log_factor) != 1: - raise ArithmeticError('Calculating log(%s) results in a sum, ' - 'which is not contained in %s.' % - (self, self.parent())) - g, c = log_factor[0] - if c != 1: - raise ArithmeticError('When calculating log(%s) a factor %s != 1 ' - 'appeared, which is not contained in %s.' % - (self, c, self.parent())) - return g - - - def factors(self): r""" Return the atomic factors of this growth element. An atomic factor @@ -920,7 +845,8 @@ def factors(self): tuple()) - from growth_group import log_factor + from growth_group import log_factor, log + log = log log_factor = log_factor From 742c0b9aa8e70fa753775dc282e6c2d4bb2e8db5 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 18:53:37 +0200 Subject: [PATCH 0715/1872] documentation: asymptotic_ring index title adapted --- src/doc/en/reference/asymptotic_ring/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/reference/asymptotic_ring/index.rst b/src/doc/en/reference/asymptotic_ring/index.rst index 326375a5766..ab6745100f3 100644 --- a/src/doc/en/reference/asymptotic_ring/index.rst +++ b/src/doc/en/reference/asymptotic_ring/index.rst @@ -1,5 +1,5 @@ -Asymptotic Computations -======================= +Asymptotic Ring +=============== .. toctree:: From 1dca8c0c24ea8ae58069029c014a7592f3f7d6d8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 18:56:34 +0200 Subject: [PATCH 0716/1872] get rid of old log method --- src/sage/rings/asymptotic/growth_group.py | 58 ++++++++--------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index f3881566bf6..d38964cc129 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -568,6 +568,25 @@ def log(self, base=None): sage: log(el, base=2) x + :: + + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: x = GenericGrowthGroup(ZZ).an_element() + sage: log(x) # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: Cannot determine logarithmized factorization of + GenericGrowthElement(1) in abstract base class. + + :: + + sage: x = GrowthGroup('x^ZZ').an_element() + sage: log(x) + Traceback (most recent call last): + ... + ArithmeticError: Cannot build log(x) since log(x) is not in + Growth Group x^ZZ. + TESTS:: sage: G = GrowthGroup("QQ['e']^x * x^ZZ") @@ -1044,45 +1063,6 @@ def _le_(self, other): raise NotImplementedError('Only implemented in concrete realizations.') - def log(self, base=None): - r""" - Return the logarithm of this element. - - INPUT: - - - ``base`` -- the base of the logarithm. If ``None`` - (default value) is used, the natural logarithm is taken. - - OUTPUT: - - A growth element. - - .. NOTE:: - - The logarithm is only implemented for elements from a - Cartesian product of growth groups, see - :meth:`~sage.rings.asymptotic.growth_group_cartesian.GenericProduct.Element.log`. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import (GrowthGroup, GenericGrowthGroup) - sage: x = GenericGrowthGroup(ZZ).an_element() - sage: log(x) # indirect doctest - Traceback (most recent call last): - ... - ArithmeticError: building log(GenericGrowthElement(1)) is not possible. - - :: - - sage: x = GrowthGroup('x^ZZ').an_element() - sage: log(x) - Traceback (most recent call last): - ... - ArithmeticError: building log(x) is not possible. - """ - raise ArithmeticError('building log(%s) is not possible.' % (self,)) - - log = log log_factor = log_factor From d67d4aaf3b7ded35a67e374535eb635f0af28409 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 19:08:25 +0200 Subject: [PATCH 0717/1872] minor doc change in exp + one additional doctest --- src/sage/rings/asymptotic/growth_group.py | 1 - src/sage/rings/asymptotic/growth_group_cartesian.py | 13 +++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index d38964cc129..32c4d4bfd36 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2994,7 +2994,6 @@ def _convert_(self, data): else: return # end of parsing - from sage.symbolic.ring import SR import operator from sage.symbolic.operators import mul_vararg diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 2790c5aa59d..e040c97cbaf 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -979,7 +979,7 @@ def check_factor(factor): def exp(self): r""" - The exponential function of this element. + The exponential of this element. INPUT: @@ -993,7 +993,7 @@ def exp(self): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ * log(x)^ZZ * log(log(x))^ZZ') - sage: x, = G.gens_monomial() + sage: x = G('x') sage: exp(log(x)) x sage: exp(log(log(x))) @@ -1005,6 +1005,15 @@ def exp(self): Traceback (most recent call last): ... ValueError: Cannot construct e^x in Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ. + + TESTS:: + + sage: E = GrowthGroup("QQ['e']^y * y^QQ * log(y)^QQ") + sage: y = E('y') + sage: log(exp(y)) + y + sage: exp(log(y)) + y """ return self.rpow('e') From 9ba466d8ce794d2703bf2ac0b82ce215c90372f9 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 19:09:23 +0200 Subject: [PATCH 0718/1872] implementation and some doctests for exp --- src/sage/rings/asymptotic/asymptotic_ring.py | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 70065743337..5d3b2025e43 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1256,6 +1256,53 @@ def log(self, base=None, precision=None): return result + def exp(self, precision=None): + r""" + Return the exponential function `\exp(\,\cdot\,)` of this + asymptotic expression. + + INPUT: + + - ``precision`` -- the precision used for truncating the + expansion. If ``None`` (default value) is used, the + default precision of the parent is used. + + OUTPUT: + + An asymptotic expression. + + .. NOTE:: + + The exponential function of this expression can only be + computed exactly, if the respective growth element can be + constructed in the underlying growth group. + + ALGORITHM: + + If the corresponding growth can be constructed, return + the exact exponential function. Otherwise, if this term + is within `O(1)`, try to expand the series and truncate + according to the given precision. + + EXAMPLES:: + + sage: A. = AsymptoticRing('SR^x * x^ZZ * log(x)^ZZ', SR) + sage: exp(x) # not tested + e^x + sage: exp(2*x) # not tested + (e^2)^x + sage: exp(x + log(x)) # not tested + e^x*x + + :: + + sage: exp(x^(-1)) # not tested + 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + ... + O(x^(-21)) + """ + return self._rpow_('e') + + + class AsymptoticRing(sage.algebras.algebra.Algebra, sage.structure.unique_representation.UniqueRepresentation): r""" From 75b5911d1bfd12c0fa899e70d7343d820448d12f Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 19:10:34 +0200 Subject: [PATCH 0719/1872] is_lt_one implemented for growth groups --- src/sage/rings/asymptotic/growth_group.py | 26 +++++++++++++++++++ .../asymptotic/growth_group_cartesian.py | 3 +++ 2 files changed, 29 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 41084394314..2d9e3be6748 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -200,6 +200,30 @@ lazy_import('sage.rings.asymptotic.growth_group_cartesian', 'CartesianProductGrowthGroups') +def is_lt_one(self): + r""" + Return if this element is less than `1`. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ'); x = G(x) + sage: (x^42).is_lt_one() + False + sage: (x^(-42)).is_lt_one() + True + """ + one = self.parent().one() + return self <= one and self != one + class Variable(sage.structure.unique_representation.CachedRepresentation, sage.structure.sage_object.SageObject): r""" @@ -939,6 +963,8 @@ def log(self, base=None): """ raise ArithmeticError('building log(%s) is not possible.' % (self,)) + is_lt_one = is_lt_one + class GenericGrowthGroup( sage.structure.unique_representation.UniqueRepresentation, diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index d81153ff0c3..bbbb99a447f 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -770,6 +770,9 @@ def variable_names(self): class Element(CartesianProductPosets.Element): + from growth_group import is_lt_one + is_lt_one = is_lt_one + def _repr_(self): r""" A representation string for this cartesian product element. From 1a513efad0fb04b92caf28a2b97598761bc55130 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 19:11:54 +0200 Subject: [PATCH 0720/1872] documentation: log --> \log (within math mode) --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- src/sage/rings/asymptotic/growth_group.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 90eb9df930c..cbfe0ba8986 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -34,13 +34,13 @@ - elements of the form `z^q` for some integer or rational `q` (growth groups ``z^ZZ`` or ``z^QQ``), -- elements of the form `log(z)^q` for some integer or rational `q` (growth +- elements of the form `\log(z)^q` for some integer or rational `q` (growth groups ``log(z)^ZZ`` or ``log(z)^QQ``), - elements of the form `a^z` for some rational `a` (growth group ``QQ^z``), or -- more sophisticated constructions like products `x^r log(x)^s \cdot +- more sophisticated constructions like products `x^r \log(x)^s \cdot a^y \cdot y^q` (this corresponds to an element of the growth group ``x^QQ * log(x)^ZZ * QQ^y * y^QQ``). diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 0218c665089..62d4eac605a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -21,13 +21,13 @@ - elements of the form `z^q` for some integer or rational `q` (growth groups ``z^ZZ`` or ``z^QQ``), -- elements of the form `log(z)^q` for some integer or rational `q` (growth +- elements of the form `\log(z)^q` for some integer or rational `q` (growth groups ``log(z)^ZZ`` or ``log(z)^QQ``), - elements of the form `a^z` for some rational `a` (growth group ``QQ^z``), or -- more sophisticated constructions like products `x^r log(x)^s \cdot +- more sophisticated constructions like products `x^r \log(x)^s \cdot a^y \cdot y^q` (this corresponds to an element of the growth group ``x^QQ * log(x)^ZZ * QQ^y * y^QQ``). From a5f7f9adfed06637aa2925235b808dfba4c3bdb7 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 19:12:14 +0200 Subject: [PATCH 0721/1872] fixed broken reference --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index cbfe0ba8986..04dce5e3301 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2102,7 +2102,7 @@ class AsymptoticRingFunctor(ConstructionFunctor): - ``growth_group`` -- a partially ordered group (see :class:`AsymptoticRing` or - mod:`~sage.rings.asymptotic.growth_group` for details). + :mod:`~sage.rings.asymptotic.growth_group` for details). EXAMPLES:: From d209e2032e914acfb45de645d7355ee27976f8ca Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 19:12:34 +0200 Subject: [PATCH 0722/1872] * --> \cdot (within math mode) --- src/sage/rings/asymptotic/term_monoid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index e5d74893b2f..6cdc4b055af 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -27,7 +27,7 @@ able to "absorb" other terms (see :meth:`~sage.rings.asymptotic.term_monoid.GenericTerm.absorb`). For instance, `O(x^2)` is able to absorb `O(x)` (with result -`O(x^2)`), and `3*x^5` is able to absorb `-2*x^5` (with result +`O(x^2)`), and `3\cdot x^5` is able to absorb `-2\cdot x^5` (with result `x^5`). Essentially, absorption can be interpreted as the addition of "compatible" terms (partial addition). From db2e98ad0f856a1bf473a528a9aaa7687aa2f679 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 31 Aug 2015 19:12:47 +0200 Subject: [PATCH 0723/1872] : --> :: (marking doctests correctly) --- src/sage/rings/asymptotic/growth_group.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 62d4eac605a..af97dfd9e13 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -97,12 +97,12 @@ sage: E.an_element() (1/2)^z -More complex groups are created in a similar fashion. For example +More complex groups are created in a similar fashion. For example:: sage: C = GrowthGroup('QQ^z * z^QQ * log(z)^QQ'); C Growth Group QQ^z * z^QQ * log(z)^QQ -This contains elements of the form +This contains elements of the form:: sage: C.an_element() (1/2)^z*z^(1/2)*log(z)^(1/2) @@ -2354,7 +2354,7 @@ def base(self): r""" The base of this exponential growth element. - EXAMPLES: + EXAMPLES:: sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('ZZ^x') From 32b422db6fc47d7bd05073c39ce694341de97980 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Aug 2015 20:38:51 +0200 Subject: [PATCH 0724/1872] major rpow rewriting in growth group --- src/sage/rings/asymptotic/growth_group.py | 102 ++++++++++++++++++ .../asymptotic/growth_group_cartesian.py | 94 ++++------------ 2 files changed, 120 insertions(+), 76 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 32c4d4bfd36..48385cf0219 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -691,6 +691,74 @@ def log_factor(self, base=None): return log_factor +def rpow(self, base): + r""" + Calculate the power of ``base`` to this element. + + INPUT: + + - ``base`` -- an element. + + OUTPUT: + + A growth element. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x * x^ZZ') + sage: x = G('x') + sage: x.rpow(2) + 2^x + sage: x.rpow(1/2) + (1/2)^x + + :: + + sage: x.rpow(0) + Traceback (most recent call last): + ... + ValueError: 0 is not an allowed base for calculating the power to x. + sage: (x^2).rpow(2) + Traceback (most recent call last): + ... + ArithmeticError: Cannot construct 2^(x^2) in Growth Group QQ^x * x^ZZ + > *previous* TypeError: unsupported operand parent(s) for '*': + 'Growth Group QQ^x * x^ZZ' and 'Growth Group ZZ^(x^2)' + + :: + + sage: G = GrowthGroup('QQ^(x*log(x)) * x^ZZ * log(x)^ZZ') + sage: x = G('x') + sage: (x * log(x)).rpow(2) + 2^(x*log(x)) + """ + if base == 0: + raise ValueError('%s is not an allowed base for calculating the ' + 'power to %s.' % (base, self)) + try: + return self.parent().one() * self._rpow_element_(base) + except (TypeError, ValueError) as e: + from misc import combine_exceptions + var = str(self) + if '*' in var or '^' in var: + var = '(' + var + ')' + raise combine_exceptions( + ArithmeticError('Cannot construct %s^%s in %s' % + (base, var, self.parent())), e) + + +def _rpow_element_(self, base): + new_var = str(self) + if '*' in new_var or '^' in new_var: + new_var = '(' + new_var + ')' + if base == 'e': + from sage.rings.integer_ring import ZZ + base = ZZ[base](base) + E = ExponentialGrowthGroup(base.parent(), new_var) + return E(raw_element=base) + + class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): r""" An abstract implementation of a generic growth element. @@ -1097,6 +1165,14 @@ def _log_factor_(self, base=None): 'of %s in abstract base class.' % (self,)) + + rpow = rpow + + + def _rpow_element_(self, base): + raise NotImplementedError() + + def factors(self): r""" Return the atomic factors of this growth element. An atomic factor @@ -2242,6 +2318,29 @@ def _log_factor_(self, base=None): return (('log(%s)' % (self.parent()._var_,), coefficient),) + def _rpow_element_(self, base): + try: + return self._rpow_element_from_log_(base) + except ValueError: + return _rpow_element_from_log(self, base) + + + def _rpow_element_from_log_(self, base): + var = str(self.parent()._var_) + if not(var.startswith('log(') and self.exponent == 1): + raise ValueError('Variable %s is not a log of something.') + new_var = var[4:-1] + if base == 'e': + from sage.rings.integer_ring import ZZ + M = MonomialGrowthGroup(ZZ, new_var) + return M(raw_element=ZZ(1)) + else: + from sage.functions.log import log + new_exponent = log(base) + M = MonomialGrowthGroup(new_exponent.parent(), new_var) + return M(raw_element=new_exponent) + + def _le_(self, other): r""" Return if this :class:`MonomialGrowthElement` is at most @@ -2823,6 +2922,9 @@ def _log_factor_(self, base=None): return ((str(self.parent()._var_), coefficient),) + _rpow_element_ = _rpow_element_ + + def _le_(self, other): r""" Return if this :class:`ExponentialGrowthElement` is at most diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index e040c97cbaf..654a92c61e9 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -896,85 +896,23 @@ def try_create_growth(g): (self, self.parent())), e) - def rpow(self, base): - r""" - Take ``base`` to the power of this element. - - In other words, this is the exponential function with - ``base`` as its base. - - INPUT: - - - ``base`` -- the base of the exponential function. - - OUTPUT: - - A growth element. + from growth_group import rpow + rpow = rpow - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('QQ^x * x^ZZ') - sage: x, = G.gens_monomial() - sage: x.rpow(2) - 2^x - sage: x.rpow(1/2) - (1/2)^x - :: - - sage: x.rpow(0) - Traceback (most recent call last): - ... - ValueError: 0 is not an allowed base. - sage: (x^2).rpow(2) - Traceback (most recent call last): - ... - ValueError: Cannot construct 2^(x^2) in Growth Group QQ^x * x^ZZ. - - :: - - sage: G = GrowthGroup('QQ^(x*log(x)) * x^ZZ * log(x)^ZZ') - sage: x, = G.gens_monomial() - sage: (x * log(x)).rpow(2) - 2^(x*log(x)) - """ - P = self.parent() + def _rpow_element_(self, base): factors = self.factors() - if base == 0: - raise ValueError('%s is not an allowed base.' % (base,)) - - from sage.rings.asymptotic.growth_group import MonomialGrowthGroup if len(factors) == 1: - fp = factors[0].parent() - if isinstance(fp, MonomialGrowthGroup) and repr(fp._var_).startswith('log('): - if factors[0]._raw_element_ == 1: - from sage.functions.log import log - new_elem = P(repr(fp._var_)[4:-1]) - if base == 'e': - return new_elem - base_ring = new_elem.factors()[0].base_ring() - return new_elem ** log(base_ring(base)) - - from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup - new_var = repr(self) - if '*' in new_var or '^' in new_var: - new_var = '(' + new_var + ')' - - def check_factor(factor): - return new_var == repr(factor._var_) and \ - isinstance(factor, ExponentialGrowthGroup) - - for cf in P.cartesian_factors(): - if hasattr(cf, 'cartesian_factors'): - for ccf in cf.cartesian_factors(): - if check_factor(ccf): - return P(ccf(raw_element=ccf.base_ring()(base))) - else: - if check_factor(cf): - return P(cf(raw_element=cf.base_ring()(base))) - - raise ValueError('Cannot construct %s^%s in %s.' % (base, new_var, P)) + for factor in factors: + from growth_group import MonomialGrowthGroup + if not isinstance(factor.parent(), MonomialGrowthGroup): + continue + try: + return factor._rpow_element_from_log_(base) + except ValueError: + pass + from growth_group import _rpow_element_ + return _rpow_element_(self, base) def exp(self): @@ -1004,7 +942,11 @@ def exp(self): sage: exp(x) Traceback (most recent call last): ... - ValueError: Cannot construct e^x in Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ. + ArithmeticError: Cannot construct e^x in + Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ + > *previous* TypeError: unsupported operand parent(s) for '*': + 'Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ' and + 'Growth Group (Univariate Polynomial Ring in e over Integer Ring)^x' TESTS:: From 9b8e8a6a13ce6abd338d89ab918f90f750db4c49 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 08:22:50 +0200 Subject: [PATCH 0725/1872] simplify rpow code --- src/sage/rings/asymptotic/growth_group.py | 46 ++++++++----------- .../asymptotic/growth_group_cartesian.py | 4 +- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 48385cf0219..c7da7502169 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -736,29 +736,33 @@ def rpow(self, base): if base == 0: raise ValueError('%s is not an allowed base for calculating the ' 'power to %s.' % (base, self)) + + element = None try: - return self.parent().one() * self._rpow_element_(base) + element = self._rpow_element_(base) + except ValueError: + pass + + var = str(self) + if '*' in var or '^' in var: + var = '(' + var + ')' + + if element is None: + if base == 'e': + from sage.rings.integer_ring import ZZ + base = ZZ[base](base) + E = ExponentialGrowthGroup(base.parent(), var) + element = E(raw_element=base) + + try: + return self.parent().one() * element except (TypeError, ValueError) as e: from misc import combine_exceptions - var = str(self) - if '*' in var or '^' in var: - var = '(' + var + ')' raise combine_exceptions( ArithmeticError('Cannot construct %s^%s in %s' % (base, var, self.parent())), e) -def _rpow_element_(self, base): - new_var = str(self) - if '*' in new_var or '^' in new_var: - new_var = '(' + new_var + ')' - if base == 'e': - from sage.rings.integer_ring import ZZ - base = ZZ[base](base) - E = ExponentialGrowthGroup(base.parent(), new_var) - return E(raw_element=base) - - class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): r""" An abstract implementation of a generic growth element. @@ -1170,7 +1174,7 @@ def _log_factor_(self, base=None): def _rpow_element_(self, base): - raise NotImplementedError() + pass def factors(self): @@ -2319,13 +2323,6 @@ def _log_factor_(self, base=None): def _rpow_element_(self, base): - try: - return self._rpow_element_from_log_(base) - except ValueError: - return _rpow_element_from_log(self, base) - - - def _rpow_element_from_log_(self, base): var = str(self.parent()._var_) if not(var.startswith('log(') and self.exponent == 1): raise ValueError('Variable %s is not a log of something.') @@ -2922,9 +2919,6 @@ def _log_factor_(self, base=None): return ((str(self.parent()._var_), coefficient),) - _rpow_element_ = _rpow_element_ - - def _le_(self, other): r""" Return if this :class:`ExponentialGrowthElement` is at most diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 654a92c61e9..7fa9962c698 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -908,11 +908,9 @@ def _rpow_element_(self, base): if not isinstance(factor.parent(), MonomialGrowthGroup): continue try: - return factor._rpow_element_from_log_(base) + return factor._rpow_element_(base) except ValueError: pass - from growth_group import _rpow_element_ - return _rpow_element_(self, base) def exp(self): From fc3a77f94dc36356207b8a43ecd860a5dd2b9d7f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 08:54:19 +0200 Subject: [PATCH 0726/1872] minor rewrite of _rpow_element_ --- .../asymptotic/growth_group_cartesian.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 7fa9962c698..6f47230a30a 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -902,15 +902,16 @@ def try_create_growth(g): def _rpow_element_(self, base): factors = self.factors() - if len(factors) == 1: - for factor in factors: - from growth_group import MonomialGrowthGroup - if not isinstance(factor.parent(), MonomialGrowthGroup): - continue - try: - return factor._rpow_element_(base) - except ValueError: - pass + if len(factors) != 1: + return + from growth_group import MonomialGrowthGroup + for factor in factors: + if not isinstance(factor.parent(), MonomialGrowthGroup): + continue + try: + return factor._rpow_element_(base) + except ValueError: + pass def exp(self): From 797eb74cdd8c80c3f34658ef4b761421e35d72d1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 08:54:36 +0200 Subject: [PATCH 0727/1872] docstrings for rpow and rpow_element --- src/sage/rings/asymptotic/growth_group.py | 49 +++++++++++++++++++ .../asymptotic/growth_group_cartesian.py | 22 +++++++++ 2 files changed, 71 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c7da7502169..cfbe9edc03f 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1174,6 +1174,26 @@ def _log_factor_(self, base=None): def _rpow_element_(self, base): + r""" + Return an element which is the power of ``base`` to this + element; it lives (in contrast to :meth:`rpow`) in its own group. + + INPUT: + + - ``base`` -- an element. + + OUTPUT: + + A growth element or ``None``. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x') + sage: x = G(raw_element=3) + sage: x._rpow_element_(2) is None + True + """ pass @@ -2323,6 +2343,35 @@ def _log_factor_(self, base=None): def _rpow_element_(self, base): + r""" + Return an element which is the power of ``base`` to this + element; it lives (in contrast to :meth:`rpow`) in its own group. + + INPUT: + + - ``base`` -- an element. + + OUTPUT: + + A growth element or ``None``. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ') + sage: x = G('x') + sage: x._rpow_element_(2) + Traceback (most recent call last): + ... + ValueError: Variable %s is not a log of something. + sage: G = GrowthGroup('log(x)^ZZ') + sage: lx = G(raw_element=1); lx + log(x) + sage: rp = lx._rpow_element_('e'); rp + x + sage: rp.parent() + Growth Group x^ZZ + """ var = str(self.parent()._var_) if not(var.startswith('log(') and self.exponent == 1): raise ValueError('Variable %s is not a log of something.') diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 6f47230a30a..780db85f912 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -901,6 +901,28 @@ def try_create_growth(g): def _rpow_element_(self, base): + r""" + Return an element which is the power of ``base`` to this + element; it lives (in contrast to :meth:`rpow`) in its own group. + + INPUT: + + - ``base`` -- an element. + + OUTPUT: + + A growth element or ``None``. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ') + sage: lx = log(G('x')) + sage: rp = lx._rpow_element_('e'); rp + x + sage: rp.parent() + Growth Group x^ZZ + """ factors = self.factors() if len(factors) != 1: return From d729a81e4f895cd9b0256406bd9729c7acdbdad7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 09:01:52 +0200 Subject: [PATCH 0728/1872] minor: change position of :: in docstring --- src/sage/rings/asymptotic/growth_group.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index af97dfd9e13..f93b3fa882d 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -97,12 +97,14 @@ sage: E.an_element() (1/2)^z -More complex groups are created in a similar fashion. For example:: +More complex groups are created in a similar fashion. For example +:: sage: C = GrowthGroup('QQ^z * z^QQ * log(z)^QQ'); C Growth Group QQ^z * z^QQ * log(z)^QQ -This contains elements of the form:: +This contains elements of the form +:: sage: C.an_element() (1/2)^z*z^(1/2)*log(z)^(1/2) From 780d26b914ec0bf8efa32dc7cf36b9bb4b371aa1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 09:08:57 +0200 Subject: [PATCH 0729/1872] fix ALGORITHM block --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/growth_group.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 1ea372c51d5..91398c34cd7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1185,7 +1185,7 @@ def log(self, base=None, precision=None): is possible if and only if there is exactly one maximal summand in the expression. - .. ALGORITHM:: + ALGORITHM: If the expression has more than one summands, the asymptotic expansion for `\log(1+t)` as `t` tends to `0` diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cfbe9edc03f..6592b4b5ddc 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -636,7 +636,7 @@ def log_factor(self, base=None): A tuple of pairs, where the first entry is a growth element and the second a multiplicative coefficient. - .. ALGORITHM:: + ALGORITHM: This function factors the given element and calculates the logarithm of each of these factors. From 5cffb72d896fe5e3db3375d34dd0b46714da688b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 09:19:41 +0200 Subject: [PATCH 0730/1872] TestSuite for term monoids --- src/sage/rings/asymptotic/term_monoid.py | 58 ++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index c7ae2c5a7d3..c1ce3ccb814 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2789,13 +2789,61 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: OT = atm.TermMonoid('O', G, QQ); OT + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ') + sage: OT = TermMonoid('O', G, QQ); OT O-Term Monoid x^ZZ with implicit coefficients in Rational Field - sage: ET = atm.TermMonoid('exact', G, ZZ); ET + sage: ET = TermMonoid('exact', G, ZZ); ET Exact Term Monoid x^ZZ with coefficients in Integer Ring + + TESTS:: + + sage: TestSuite(TermMonoid('exact', GrowthGroup('x^ZZ'), QQ)).run(verbose=True) + running ._test_an_element() . . . pass + running ._test_associativity() . . . pass + running ._test_category() . . . pass + running ._test_elements() . . . + Running the test suite of self.an_element() + running ._test_category() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + pass + running ._test_elements_eq_reflexive() . . . pass + running ._test_elements_eq_symmetric() . . . pass + running ._test_elements_eq_transitive() . . . pass + running ._test_elements_neq() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_one() . . . pass + running ._test_pickling() . . . pass + running ._test_prod() . . . pass + running ._test_some_elements() . . . pass + + :: + + sage: TestSuite(TermMonoid('O', GrowthGroup('x^QQ'), ZZ)).run(verbose=True) + running ._test_an_element() . . . pass + running ._test_associativity() . . . pass + running ._test_category() . . . pass + running ._test_elements() . . . + Running the test suite of self.an_element() + running ._test_category() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + pass + running ._test_elements_eq_reflexive() . . . pass + running ._test_elements_eq_symmetric() . . . pass + running ._test_elements_eq_transitive() . . . pass + running ._test_elements_neq() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_one() . . . pass + running ._test_pickling() . . . pass + running ._test_prod() . . . pass + running ._test_some_elements() . . . pass """ def create_key_and_extra_args(self, term, growth_group=None, coefficient_ring=None, From e491aea87b3ef32e8280c3124da67ada1325b4ea Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 09:26:09 +0200 Subject: [PATCH 0731/1872] mark some tests as "long time" --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/growth_group.py | 6 +++--- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index bef825b1eeb..67232013f08 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1349,7 +1349,7 @@ class AsymptoticRing(sage.algebras.algebra.Algebra, ....: __eq__ = AR_class.Element.has_same_summands sage: A = AR(growth_group='z^QQ', coefficient_ring=QQ) sage: from itertools import islice - sage: TestSuite(A).run( # not tested # long + sage: TestSuite(A).run( # not tested # long time ....: verbose=True, ....: elements=tuple(islice(A.some_elements(), 10)), ....: skip=('_test_some_elements', # to many elements diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 69ab9a5335d..4aa21f2993b 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3311,7 +3311,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): TESTS:: - sage: TestSuite(GrowthGroup('x^ZZ')).run(verbose=True) + sage: TestSuite(GrowthGroup('x^ZZ')).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass running ._test_category() . . . pass @@ -3335,7 +3335,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): :: - sage: TestSuite(GrowthGroup('QQ^y')).run(verbose=True) + sage: TestSuite(GrowthGroup('QQ^y')).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass running ._test_category() . . . pass @@ -3359,7 +3359,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): :: - sage: TestSuite(GrowthGroup('x^QQ * log(x)^ZZ')).run(verbose=True) + sage: TestSuite(GrowthGroup('x^QQ * log(x)^ZZ')).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass running ._test_category() . . . pass diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index c1ce3ccb814..75a27a68da9 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2799,7 +2799,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): TESTS:: - sage: TestSuite(TermMonoid('exact', GrowthGroup('x^ZZ'), QQ)).run(verbose=True) + sage: TestSuite(TermMonoid('exact', GrowthGroup('x^ZZ'), QQ)).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass running ._test_category() . . . pass @@ -2823,7 +2823,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): :: - sage: TestSuite(TermMonoid('O', GrowthGroup('x^QQ'), ZZ)).run(verbose=True) + sage: TestSuite(TermMonoid('O', GrowthGroup('x^QQ'), ZZ)).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass running ._test_category() . . . pass From ab01ce8085b99561544cf2b7a7274cac06b74362 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 09:31:14 +0200 Subject: [PATCH 0732/1872] replace -oo result on log(0) by exception --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 67232013f08..84be5ea7ed3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1205,12 +1205,16 @@ def log(self, base=None, precision=None): sage: log(R(1)) 0 + sage: log(R(0)) + Traceback (most recent call last): + ... + ArithmeticError: Cannot build log(0) in + Asymptotic Ring over Rational Field. """ P = self.parent() if not self.summands: - from sage.rings.infinity import minus_infinity - return minus_infinity + raise ArithmeticError('Cannot build log(0) in %s.' % (self.parent(),)) elif len(self.summands) == 1: if self == 1: From e53dcdb66d7e2ea3de940b1c025d12b26e809b93 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 09:58:36 +0200 Subject: [PATCH 0733/1872] extend short representation --- src/sage/rings/asymptotic/growth_group.py | 11 ++-- .../asymptotic/growth_group_cartesian.py | 2 +- src/sage/rings/asymptotic/misc.py | 64 ++++++++++++++----- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 4aa21f2993b..191599b5000 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -602,8 +602,7 @@ def log(self, base=None): Traceback (most recent call last): ... ArithmeticError: log(1) is zero, which is not contained in - Growth Group (Univariate Polynomial Ring in e over - Rational Field)^x * x^ZZ. + Growth Group QQ[e]^x * x^ZZ. """ log_factor = self.log_factor(base=base) if not log_factor: @@ -2487,7 +2486,7 @@ def _repr_short_(self): sage: agg.MonomialGrowthGroup(QQ, 'a')._repr_short_() 'a^QQ' sage: agg.MonomialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() - 'a^(Univariate Polynomial Ring in x over Rational Field)' + 'a^QQ[x]' """ from misc import parent_to_repr_short return '%s^%s' % (self._var_, parent_to_repr_short(self.base())) @@ -2706,7 +2705,7 @@ class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): sage: A = GrowthGroup('x^QQ') sage: B = MonomialGrowthGroupFunctor('x')(ZZ['t']) sage: cm.common_parent(A, B) - Growth Group x^(Univariate Polynomial Ring in t over Rational Field) + Growth Group x^QQ[t] """ _functor_name = 'MonomialGrowthGroup' @@ -3065,7 +3064,7 @@ def _repr_short_(self): sage: agg.ExponentialGrowthGroup(QQ, 'a')._repr_short_() 'QQ^a' sage: agg.ExponentialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() - '(Univariate Polynomial Ring in x over Rational Field)^a' + 'QQ[x]^a' """ from misc import parent_to_repr_short return '%s^%s' % (parent_to_repr_short(self.base()), self._var_) @@ -3235,7 +3234,7 @@ class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): sage: A = GrowthGroup('QQ^x') sage: B = ExponentialGrowthGroupFunctor('x')(ZZ['t']) sage: cm.common_parent(A, B) - Growth Group (Univariate Polynomial Ring in t over Rational Field)^x + Growth Group QQ[t]^x """ _functor_name = 'ExponentialGrowthGroup' diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 780db85f912..896e68e5b67 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -967,7 +967,7 @@ def exp(self): Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ > *previous* TypeError: unsupported operand parent(s) for '*': 'Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ' and - 'Growth Group (Univariate Polynomial Ring in e over Integer Ring)^x' + 'Growth Group ZZ[e]^x' TESTS:: diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 5d73bdec8fd..5340e75ef9e 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -78,27 +78,59 @@ def parent_to_repr_short(P): EXAMPLES:: - sage: import sage.rings.asymptotic.misc as agg - sage: agg.parent_to_repr_short(ZZ) + sage: from sage.rings.asymptotic.misc import parent_to_repr_short + sage: parent_to_repr_short(ZZ) 'ZZ' - sage: agg.parent_to_repr_short(QQ) + sage: parent_to_repr_short(QQ) 'QQ' - sage: agg.parent_to_repr_short(SR) + sage: parent_to_repr_short(SR) 'SR' - sage: agg.parent_to_repr_short(ZZ[x]) - '(Univariate Polynomial Ring in x over Integer Ring)' + sage: parent_to_repr_short(ZZ['x']) + 'ZZ[x]' + sage: parent_to_repr_short(QQ['d, k']) + '(QQ[d, k])' + sage: parent_to_repr_short(QQ['e']) + 'QQ[e]' + sage: parent_to_repr_short(SR[['a, r']]) + '(SR[[a, r]])' + sage: parent_to_repr_short(Zmod(3)) + '(Ring of integers modulo 3)' + sage: parent_to_repr_short(Zmod(3)['g']) + '(Univariate Polynomial Ring in g over Ring of integers modulo 3)' """ - if P is sage.rings.integer_ring.ZZ: - return 'ZZ' - elif P is sage.rings.rational_field.QQ: - return 'QQ' - elif P is sage.symbolic.ring.SR: - return 'SR' + def abbreviate(P): + if P is sage.rings.integer_ring.ZZ: + return 'ZZ' + elif P is sage.rings.rational_field.QQ: + return 'QQ' + elif P is sage.symbolic.ring.SR: + return 'SR' + raise ValueError('Cannot abbreviate %s.' % (P,)) + + poly = sage.rings.polynomial.polynomial_ring.is_PolynomialRing(P) or \ + sage.rings.polynomial.multi_polynomial_ring_generic.is_MPolynomialRing(P) + from sage.rings import multi_power_series_ring + power = sage.rings.power_series_ring.is_PowerSeriesRing(P) or \ + multi_power_series_ring.is_MPowerSeriesRing(P) + + if poly or power: + if poly: + op, cl = ('[', ']') + else: + op, cl = ('[[', ']]') + try: + s = abbreviate(P.base_ring()) + op + ', '.join(P.variable_names()) + cl + except ValueError: + s = str(P) else: - rep = repr(P) - if ' ' in rep: - rep = '(' + rep + ')' - return rep + try: + s = abbreviate(P) + except ValueError: + s = str(P) + + if ' ' in s: + s = '(' + s + ')' + return s def split_str_by_mul(string): From 9a7101a98700013892d3a97dd653370307faba4a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 10:03:19 +0200 Subject: [PATCH 0734/1872] extend error message on missing growth group or coefficient ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 84be5ea7ed3..59c5d35e931 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1365,7 +1365,7 @@ class AsymptoticRing(sage.algebras.algebra.Algebra, @staticmethod - def __classcall__(cls, growth_group, coefficient_ring, names=None, + def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, category=None, default_prec=None): r""" Normalizes the input in order to ensure a unique @@ -1490,7 +1490,7 @@ def __init__(self, growth_group, coefficient_ring, category, default_prec): sage: R3 = AsymptoticRing('x^ZZ') Traceback (most recent call last): ... - TypeError: __classcall__() takes at least 3 arguments (2 given) + ValueError: Coefficient ring not specified. Cannot continue. """ self._coefficient_ring_ = coefficient_ring self._growth_group_ = growth_group From daffd54864920642672a15a9e5566dd6efa4840b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 11:00:48 +0200 Subject: [PATCH 0735/1872] move doctree asymptotic_ring back to rings --- src/doc/en/reference/asymptotic_ring/conf.py | 1 - .../en/reference/asymptotic_ring/index.rst | 14 -------- .../reference/rings/asymptotic_ring_index.rst | 34 +++++++++++++++++++ src/doc/en/reference/rings/index.rst | 1 + 4 files changed, 35 insertions(+), 15 deletions(-) delete mode 120000 src/doc/en/reference/asymptotic_ring/conf.py delete mode 100644 src/doc/en/reference/asymptotic_ring/index.rst create mode 100644 src/doc/en/reference/rings/asymptotic_ring_index.rst diff --git a/src/doc/en/reference/asymptotic_ring/conf.py b/src/doc/en/reference/asymptotic_ring/conf.py deleted file mode 120000 index 2bdf7e68470..00000000000 --- a/src/doc/en/reference/asymptotic_ring/conf.py +++ /dev/null @@ -1 +0,0 @@ -../conf_sub.py \ No newline at end of file diff --git a/src/doc/en/reference/asymptotic_ring/index.rst b/src/doc/en/reference/asymptotic_ring/index.rst deleted file mode 100644 index ab6745100f3..00000000000 --- a/src/doc/en/reference/asymptotic_ring/index.rst +++ /dev/null @@ -1,14 +0,0 @@ -Asymptotic Ring -=============== - - -.. toctree:: - :maxdepth: 2 - - sage/rings/asymptotic/asymptotic_ring - sage/rings/asymptotic/growth_group - sage/rings/asymptotic/growth_group_cartesian - sage/rings/asymptotic/term_monoid - sage/rings/asymptotic/misc - -.. include:: ../footer.txt diff --git a/src/doc/en/reference/rings/asymptotic_ring_index.rst b/src/doc/en/reference/rings/asymptotic_ring_index.rst new file mode 100644 index 00000000000..56f9804674c --- /dev/null +++ b/src/doc/en/reference/rings/asymptotic_ring_index.rst @@ -0,0 +1,34 @@ +Asymptotic Ring +=============== + +The Asymptotic Ring +------------------- + +- :doc:`sage/rings/asymptotic/asymptotic_ring` + +Supplements +----------- + +Growth Groups and Term Monoids +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- :doc:`sage/rings/asymptotic/growth_group` +- :doc:`sage/rings/asymptotic/growth_group_cartesian` +- :doc:`sage/rings/asymptotic/term_monoid` + +Miscellaneous +^^^^^^^^^^^^^ + +- :doc:`sage/rings/asymptotic/misc` + +.. toctree:: + :maxdepth: 2 + :hidden: + + sage/rings/asymptotic/asymptotic_ring + sage/rings/asymptotic/growth_group + sage/rings/asymptotic/growth_group_cartesian + sage/rings/asymptotic/term_monoid + sage/rings/asymptotic/misc + +.. include:: ../footer.txt diff --git a/src/doc/en/reference/rings/index.rst b/src/doc/en/reference/rings/index.rst index 607830c10a6..23a8ea84f9b 100644 --- a/src/doc/en/reference/rings/index.rst +++ b/src/doc/en/reference/rings/index.rst @@ -18,6 +18,7 @@ General Rings, Ideals, and Morphisms sage/rings/quotient_ring_element sage/rings/invariant_theory + asymptotic_ring_index sage/rings/bernmm sage/rings/bernoulli_mod_p sage/rings/big_oh From cea984709ece8ae6d02fd11dd1080eda26476c3e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 13:10:41 +0200 Subject: [PATCH 0736/1872] improve doc-index of asymptotic ring --- .../reference/rings/asymptotic_ring_index.rst | 38 ++++++++++++++----- src/sage/rings/asymptotic/asymptotic_ring.py | 4 +- src/sage/rings/asymptotic/growth_group.py | 3 ++ .../asymptotic/growth_group_cartesian.py | 3 ++ src/sage/rings/asymptotic/misc.py | 6 +-- src/sage/rings/asymptotic/term_monoid.py | 5 ++- 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/doc/en/reference/rings/asymptotic_ring_index.rst b/src/doc/en/reference/rings/asymptotic_ring_index.rst index 56f9804674c..a89a694f3ec 100644 --- a/src/doc/en/reference/rings/asymptotic_ring_index.rst +++ b/src/doc/en/reference/rings/asymptotic_ring_index.rst @@ -4,26 +4,46 @@ Asymptotic Ring The Asymptotic Ring ------------------- -- :doc:`sage/rings/asymptotic/asymptotic_ring` +The asymptotic ring, as well as its main documentation is contained in +the module + +- :doc:`sage/rings/asymptotic/asymptotic_ring`. Supplements ----------- -Growth Groups and Term Monoids -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Behind the scenes of working with asymptotic expressions a couple of +additional classes and tools turn up. For instance the growth in each +summand is managed in growth groups, see below. + + +Growth Groups +^^^^^^^^^^^^^ + +The growth of a summand of an asymptotic expression is managed in + +- :doc:`sage/rings/asymptotic/growth_group` and -- :doc:`sage/rings/asymptotic/growth_group` -- :doc:`sage/rings/asymptotic/growth_group_cartesian` -- :doc:`sage/rings/asymptotic/term_monoid` +- :doc:`sage/rings/asymptotic/growth_group_cartesian`. + +Term Monoids +^^^^^^^^^^^^ + +A summand of an asymptotic expression is basically a term out of the following monoid: + +- :doc:`sage/rings/asymptotic/term_monoid`. Miscellaneous ^^^^^^^^^^^^^ -- :doc:`sage/rings/asymptotic/misc` +Various useful functions and tools are collected in + +- :doc:`sage/rings/asymptotic/misc`. + +Asymptotic Ring --- Table of Contents +------------------------------------- .. toctree:: - :maxdepth: 2 - :hidden: sage/rings/asymptotic/asymptotic_ring sage/rings/asymptotic/growth_group diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 59c5d35e931..15f15595510 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -303,8 +303,8 @@ - Daniel Krenn (2015-08): various improvents, review; documentation -Methods -======= +Classes and Methods +=================== """ # ***************************************************************************** diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 191599b5000..ea7f99b3ed6 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -184,6 +184,9 @@ - Daniel Krenn (2015-06-02): cartesian products - Benjamin Hackl (2015-07): growth group factory - Benjamin Hackl (2015-08): exponential growth group, initial version + +Classes and Methods +=================== """ #***************************************************************************** diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 896e68e5b67..8e36b354eba 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -74,6 +74,9 @@ (1/2)^x*x sage: tuple(E.an_element()) (1, x^(1/2)) + +Classes and Methods +=================== """ #***************************************************************************** diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 5340e75ef9e..46ffb17c08a 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -1,13 +1,13 @@ r""" -Asymptotic Ring -- Misc +Asymptotic Ring --- Miscellaneous AUTHORS: - Daniel Krenn (2015-08): move functions from other files to this file -Methods -======= +Functions, Classes and Methods +============================== """ import sage diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 75a27a68da9..20c73bd06d0 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1,5 +1,5 @@ r""" -Asymptotic Term Monoid +(Asymptotic) Term Monoids This module implements asymptotic term monoids. The elements of these monoids are used behind the scenes when performing calculations in an @@ -60,6 +60,9 @@ without a formal deprecation. See http://trac.sagemath.org/17601 for details. sage: T = GenericTermMonoid(G, ZZ) + +Classes and Methods +=================== """ # ***************************************************************************** From c0feeede46a8589db4681e75a612e99eb3f58170 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 13:11:22 +0200 Subject: [PATCH 0737/1872] minor mod in module description of ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 26 ++++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 15f15595510..c17c03d5e99 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -8,17 +8,28 @@ Definition ========== -An asymptotic expression is a sum; its summands are the following: +An asymptotic expression is a sum such as + +.. MATH:: + + 5z^3 + 4z^2 + O(z) + +or + +.. MATH:: + + 3x^{42}y^2 + 7x^3y^3 + O(x^2) + O(y) + +Its summands are the following: - Exact terms `c\cdot g` with a coefficient `c` and an element `g` of - an :ref:`growth group `. + an growth group (:ref:`see below `). - `O`-terms `O(g)` (see :wikipedia:`Big O notation `; - also called *Bachmann--Landau notation*) for some :mod:`growth group - element ` `g` (:ref:`see below - `). + also called *Bachmann--Landau notation*) for growth group + element `g` (:ref:`again see below `). -Examples of such elements can found :ref:`below `. +Further examples of such elements can be found :ref:`here `. .. _asymptotic_ring_growth: @@ -26,8 +37,7 @@ Growth Elements --------------- -The elements of a :mod:`growth group -` are equipped with a partial +The elements of a :doc:`growth group ` are equipped with a partial ordering and usually contain a variable. Examples are (among many other possibilities) From bc1aba62f866588d7cb5a6d83d6b1c3f2ebe386b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 13:25:40 +0200 Subject: [PATCH 0738/1872] update links (:mod: --> :doc:) --- src/sage/rings/asymptotic/asymptotic_ring.py | 22 +++++++++---------- src/sage/rings/asymptotic/growth_group.py | 15 ++++++------- .../asymptotic/growth_group_cartesian.py | 2 +- src/sage/rings/asymptotic/term_monoid.py | 8 +++---- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index c17c03d5e99..fc8b187259f 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -266,9 +266,9 @@ The summands of an :class:`asymptotic expression ` are wrapped -:mod:`growth group elements `. +:doc:`growth group elements `. This wrapping is done by the -:mod:`term monoid module `. +:doc:`term monoid module `. However, inside an :class:`asymptotic expression ` these summands (terms) are stored together with their growth-relationship, i.e., each @@ -441,8 +441,8 @@ class AsymptoticExpression(sage.structure.element.CommutativeAlgebraElement): .. SEEALSO:: - :mod:`sage.rings.asymptotic.growth_group`, - :mod:`sage.rings.asymptotic.term_monoid`, + :doc:`growth_group`, + :doc:`term_monoid`, :mod:`sage.data_structures.mutable_poset`. """ def __init__(self, parent, summands, simplify=True, convert=True): @@ -829,7 +829,7 @@ def _mul_term_(self, term): INPUT: - ``term`` -- an asymptotic term (see - :mod:`~sage.rings.asymptotic.term_monoid`). + :doc:`term_monoid`). OUTPUT: @@ -1277,7 +1277,7 @@ class AsymptoticRing(sage.algebras.algebra.Algebra, INPUT: - ``growth_group`` -- either a partially ordered group (see - :mod:`~sage.rings.asymptotic.growth_group`) or a string + :doc:`growth_group`) or a string describing such a growth group (see :class:`~sage.rings.asymptotic.growth_group.GrowthGroupFactory`). @@ -1323,7 +1323,7 @@ class AsymptoticRing(sage.algebras.algebra.Algebra, sage: R_log = AsymptoticRing(growth_group='log(x)^ZZ', coefficient_ring=QQ); R_log Asymptotic Ring over Rational Field - Other growth groups are available. See :mod:`~sage.rings.asymptotic.asymptotic_ring` for + Other growth groups are available. See :doc:`asymptotic_ring` for a lot more examples. Below there are some technical details. @@ -1522,7 +1522,7 @@ def growth_group(self): .. SEEALSO:: - :mod:`sage.rings.asymptotic.growth_group` + :doc:`growth_group` """ return self._growth_group_ @@ -2190,7 +2190,7 @@ def construction(self): .. SEEALSO:: - :mod:`sage.rings.asymptotic.asymptotic_ring`, + :doc:`asymptotic_ring`, :class:`AsymptoticRing`, :class:`AsymptoticRingFunctor`. """ @@ -2207,7 +2207,7 @@ class AsymptoticRingFunctor(ConstructionFunctor): - ``growth_group`` -- a partially ordered group (see :class:`AsymptoticRing` or - :mod:`~sage.rings.asymptotic.growth_group` for details). + :doc:`growth_group` for details). EXAMPLES:: @@ -2216,7 +2216,7 @@ class AsymptoticRingFunctor(ConstructionFunctor): .. SEEALSO:: - :mod:`sage.rings.asymptotic.asymptotic_ring`, + :doc:`asymptotic_ring`, :class:`AsymptoticRing`, :class:`sage.rings.asymptotic.growth_group.AbstractGrowthGroupFunctor`, :class:`sage.rings.asymptotic.growth_group.ExponentialGrowthGroupFunctor`, diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ea7f99b3ed6..4d434a8cc1b 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -8,13 +8,12 @@ gets large (tend to `\infty`) is compared. Growth groups are used for the calculations done in the -:mod:`asymptotic ring `. +:doc:`asymptotic ring `. A Formal Definition =================== -The elements of a :mod:`growth group -` are equipped with a partial +The elements of a :doc:`growth group ` are equipped with a partial ordering and usually contain a variable. Examples are (among many other possibilities) @@ -672,8 +671,8 @@ def log_factor(self, base=None): .. SEEALSO:: - :meth:`factor`, - :meth:`log`. + :meth:`~GenericGrowthElement.factors`, + :meth:`~GenericGrowthElement.log`. TESTS:: @@ -2005,7 +2004,7 @@ class AbstractGrowthGroupFunctor(ConstructionFunctor): .. SEEALSO:: - :mod:`sage.rings.asymptotic.asymptotic_ring`, + :doc:`asymptotic_ring`, :class:`ExponentialGrowthGroupFunctor`, :class:`MonomialGrowthGroupFunctor`, :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, @@ -2695,7 +2694,7 @@ class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): .. SEEALSO:: - :mod:`sage.rings.asymptotic.asymptotic_ring`, + :doc:`asymptotic_ring`, :class:`AbstractGrowthGroupFunctor`, :class:`ExponentialGrowthGroupFunctor`, :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, @@ -3224,7 +3223,7 @@ class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): .. SEEALSO:: - :mod:`sage.rings.asymptotic.asymptotic_ring`, + :doc:`asymptotic_ring`, :class:`AbstractGrowthGroupFunctor`, :class:`MonomialGrowthGroupFunctor`, :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 8e36b354eba..ed194bd642a 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1,7 +1,7 @@ r""" Growth Groups as Cartesian Products -See :mod:`sage.rings.asymptotic.growth_group` for a description. +See :doc:`growth_group` for a description. AUTHORS: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 20c73bd06d0..e505e3fb187 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3,12 +3,12 @@ This module implements asymptotic term monoids. The elements of these monoids are used behind the scenes when performing calculations in an -:mod:`asymptotic ring `. +:doc:`asymptotic ring `. The monoids build upon the (asymptotic) growth groups. While growth elements only model the growth of a function as it tends towards infinity (or tends towards another fixed point; see -:mod:`~sage.rings.asymptotic.growth_group` for more details), an +:doc:`growth_group` for more details), an asymptotic term additionally specifies its "type" and performs the actual arithmetic operations (multiplication and partial addition/absorption of terms). @@ -558,8 +558,8 @@ def absorb(self, other, check=True): .. NOTE:: For a more detailed explanation of the *absorption* of - asymptotic terms see the introduction of :mod:`this module - `, or the examples + asymptotic terms see the introduction of + :doc:`this module `, or the examples below. EXAMPLES: From b5cc3bd8fb9bf6d6e0ec126fa841d016fe83637e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 13:51:21 +0200 Subject: [PATCH 0739/1872] begin examples log, exp --- src/sage/rings/asymptotic/asymptotic_ring.py | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index fc8b187259f..c91eae1ffa7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -199,6 +199,24 @@ is not invertible, since it includes `0`. +Powers, Expontials and Logarithms +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It works as simple as it can be; just use the usual operators ``^``, +``exp`` and ``log``. For example, we obtain the usual series expansion +of the logarithm +:: + + sage: -log(1-1/z) + z^(-1) + 1/2*z^(-2) + 1/3*z^(-3) + ... + O(z^(-21)) + +as `z \to \infty`. + +.. TODO:: + + write more here + + Multivariate Arithemtic ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,6 +227,10 @@ sage: B Asymptotic Ring over Rational Field +.. TODO:: + + write this part + More Examples ============= From be96415fff98eb033a4c27261850d975a4137348 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 1 Sep 2015 14:01:30 +0200 Subject: [PATCH 0740/1872] is_little_o_of_one for terms implemented --- src/sage/rings/asymptotic/term_monoid.py | 130 +++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 5a064862621..7014c445deb 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -977,6 +977,38 @@ def _eq_(self, other): return self.growth == other.growth + def is_little_o_of_one(self): + r""" + Return if this term is of order `o(1)`. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, + ....: TermWithCoefficientMonoid) + sage: T = GenericTermMonoid(GrowthGroup('x^ZZ'), QQ) + sage: T.an_element().is_little_o_of_one() + Traceback (most recent call last): + ... + NotImplementedError: Growth comparison not implemented (for this abstract method). + sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), QQ) + sage: T.an_element().is_little_o_of_one() + Traceback (most recent call last): + ... + NotImplementedError: Growth comparison not implemented (for this abstract method). + """ + raise NotImplementedError('Growth comparison not implemented ' + '(for this abstract method).') + + def _repr_(self): r""" A representation string for this generic term. @@ -1819,6 +1851,55 @@ def log_term(self, base=None): return self._log_growth_(base=base) + def is_little_o_of_one(self): + r""" + Return if this term is of order `o(1)`. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('O', GrowthGroup('x^ZZ'), QQ) + sage: T(x).is_little_o_of_one() + False + sage: T(1).is_little_o_of_one() + False + sage: T(x^(-1)).is_little_o_of_one() + True + + :: + + sage: T = TermMonoid('O', GrowthGroup('x^ZZ * y^ZZ'), QQ) + sage: T('x * y^(-1)').is_little_o_of_one() + False + sage: T('x^(-1) * y').is_little_o_of_one() + False + sage: T('x^(-2) * y^(-3)').is_little_o_of_one() + True + + :: + + sage: T = TermMonoid('O', GrowthGroup('x^QQ * log(x)^QQ'), QQ) + sage: T('x * log(x)^2').is_little_o_of_one() + False + sage: T('x^2 * log(x)^(-1234)').is_little_o_of_one() + False + sage: T('x^(-1) * log(x)^4242').is_little_o_of_one() + True + sage: T('x^(-1/100) * log(x)^(1000/7)').is_little_o_of_one() + True + """ + return self.growth.is_lt_one() + + class OTermMonoid(GenericTermMonoid): r""" Parent for asymptotic big `O`-terms. @@ -2694,6 +2775,55 @@ def log_term(self, base=None): return self._log_coefficient_(base=base) + self._log_growth_(base=base) + def is_little_o_of_one(self): + r""" + Return if this term is of order `o(1)`. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('exact', GrowthGroup('x^ZZ'), QQ) + sage: T(x).is_little_o_of_one() + False + sage: T(1).is_little_o_of_one() + False + sage: T(x^(-1)).is_little_o_of_one() + True + + :: + + sage: T = TermMonoid('exact', GrowthGroup('x^ZZ * y^ZZ'), QQ) + sage: T('x * y^(-1)').is_little_o_of_one() + False + sage: T('x^(-1) * y').is_little_o_of_one() + False + sage: T('x^(-2) * y^(-3)').is_little_o_of_one() + True + + :: + + sage: T = TermMonoid('exact', GrowthGroup('x^QQ * log(x)^QQ'), QQ) + sage: T('x * log(x)^2').is_little_o_of_one() + False + sage: T('x^2 * log(x)^(-1234)').is_little_o_of_one() + False + sage: T('x^(-1) * log(x)^4242').is_little_o_of_one() + True + sage: T('x^(-1/100) * log(x)^(1000/7)').is_little_o_of_one() + True + """ + return self.growth.is_lt_one() + + class ExactTermMonoid(TermWithCoefficientMonoid): r""" Parent for asymptotic exact terms, implemented in From 00cd9b4f2992b174b5092be407d40ef32c7e9ae8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 14:04:37 +0200 Subject: [PATCH 0741/1872] update authors and acknowledgement --- src/sage/rings/asymptotic/asymptotic_ring.py | 11 ++++++++--- src/sage/rings/asymptotic/growth_group.py | 12 +++++++++--- .../rings/asymptotic/growth_group_cartesian.py | 8 +++++++- src/sage/rings/asymptotic/misc.py | 8 +++++++- src/sage/rings/asymptotic/term_monoid.py | 16 +++++++++++----- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index c91eae1ffa7..01334b887c5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -330,9 +330,14 @@ AUTHORS: -- Benjamin Hackl (2015-06): initial version -- Benjamin Hackl (2015-07): improvement user interface (short notation) -- Daniel Krenn (2015-08): various improvents, review; documentation +- Benjamin Hackl (2015-06-00): initial version +- Benjamin Hackl (2015-07-00): improvement user interface (short notation) +- Daniel Krenn (2015-08-31): various improvements, review; documentation + +ACKNOWLEDGEMENT: + +- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the + Austrian Science Fund (FWF): P 24644-N26. Classes and Methods diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 4d434a8cc1b..4209f148024 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -178,11 +178,17 @@ AUTHORS: -- Benjamin Hackl (2015-01): initial version +- Benjamin Hackl (2015-01-01): initial version - Daniel Krenn (2015-05-29): initial version and review - Daniel Krenn (2015-06-02): cartesian products -- Benjamin Hackl (2015-07): growth group factory -- Benjamin Hackl (2015-08): exponential growth group, initial version +- Benjamin Hackl (2015-07-00): growth group factory +- Benjamin Hackl (2015-08-00): exponential growth group, initial version +- Daniel Krenn (2015-08-31): various improvements, review; documentation + +ACKNOWLEDGEMENT: + +- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the + Austrian Science Fund (FWF): P 24644-N26. Classes and Methods =================== diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index ed194bd642a..1fc6768d60c 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -6,7 +6,13 @@ AUTHORS: - Daniel Krenn (2015-06-02): cartesian products -- Benjamin Hackl (2015-07) +- Benjamin Hackl (2015-07-00) +- Daniel Krenn (2015-08-31): various improvements, review; documentation + +ACKNOWLEDGEMENT: + +- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the + Austrian Science Fund (FWF): P 24644-N26. .. WARNING:: diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 46ffb17c08a..fa30f1537cc 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -3,7 +3,13 @@ AUTHORS: -- Daniel Krenn (2015-08): move functions from other files to this file +- Daniel Krenn (2015-08-25): move functions from other files to this file +- Daniel Krenn (2015-08-31): various improvements, review; documentation + +ACKNOWLEDGEMENT: + +- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the + Austrian Science Fund (FWF): P 24644-N26. Functions, Classes and Methods diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index e505e3fb187..a00646089bf 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -38,11 +38,17 @@ AUTHORS: -- Benjamin Hackl (2015-01): initial version -- Benjamin Hackl, Daniel Krenn (2015-05): conception of the asymptotic ring -- Benjamin Hackl (2015-06): refactoring caused by refactoring growth groups -- Daniel Krenn (2015-07): extensive review and patches -- Benjamin Hackl (2015-07): cross-review; short notation +- Benjamin Hackl (2015-01-01): initial version +- Benjamin Hackl, Daniel Krenn (2015-05-15): conception of the asymptotic ring +- Benjamin Hackl (2015-06-00): refactoring caused by refactoring growth groups +- Daniel Krenn (2015-07-00): extensive review and patches +- Benjamin Hackl (2015-07-00): cross-review; short notation +- Daniel Krenn (2015-08-31): various improvements, review; documentation + +ACKNOWLEDGEMENT: + +- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the + Austrian Science Fund (FWF): P 24644-N26. .. WARNING:: From cadffab65ea4b0717ee912f070b435e16ac869f6 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 1 Sep 2015 15:03:22 +0200 Subject: [PATCH 0742/1872] fixed __pow__ for cartesian product elements --- .../asymptotic/growth_group_cartesian.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 677fbc7f073..6569da11b97 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -799,6 +799,40 @@ def _repr_(self): return s + def __pow__(self, exponent): + r""" + Calculate the power of this growth element to the given + ``exponent``. + + INPUT: + + - ``exponent`` -- a number. This can be anything that is a + valid right hand side of ``*`` with elements of the + parent's base. + + OUTPUT: + + A growth element. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * y^QQ * z^ZZ') + sage: x, y, z = G.gens_monomial() + sage: (x^5 * y * z^5)^(1/5) # indirect doctest + x*y^(1/5)*z + + :: + + sage: G = GrowthGroup('x^QQ * log(x)^QQ'); x = G('x') + sage: (x^(21/5) * log(x)^7)^(1/42) # indirect doctest + x^(1/10)*log(x)^(1/6) + """ + P = self.parent() + return P.prod(P.cartesian_injection(elt.parent(), elt ** exponent) + for elt in self.value) + + def factors(self): r""" Return the atomic factors of this growth element. An atomic factor From c19af13af41f9850858e2759e7f78780e8cb01cc Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 1 Sep 2015 15:20:38 +0200 Subject: [PATCH 0743/1872] is_little_o_of_one for expressions implemented --- src/sage/rings/asymptotic/asymptotic_ring.py | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 958a7913ddf..9f8a9c24447 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1255,6 +1255,43 @@ def log(self, base=None, precision=None): return result + def is_little_o_of_one(self): + r""" + Return if this expression is of order `o(1)`. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: A. = AsymptoticRing('x^ZZ * log(x)^ZZ', QQ) + sage: (x^4 * log(x)^(-2) + x^(-4) * log(x)^2).is_little_o_of_one() + False + sage: (x^(-1) * log(x)^1234 + x^(-2) + O(x^(-3))).is_little_o_of_one() + True + sage: (log(x) - log(x-1)).is_little_o_of_one() + True + + :: + + sage: A. = AsymptoticRing('x^QQ * y^QQ * log(y)^ZZ', QQ) + sage: (x^(-1/16) * y^32 + x^32 * y^(-1/16)).is_little_o_of_one() + False + sage: (x^(-1) * y^(-3) + x^(-3) * y^(-1)).is_little_o_of_one() + True + sage: (x^(-1) * y / log(y)).is_little_o_of_one() + False + sage: (log(y-1)/log(y) - 1).is_little_o_of_one() + True + """ + return all(term.is_little_o_of_one() for term in self.summands.maximal_elements()) + + def exp(self, precision=None): r""" Return the exponential function `\exp(\,\cdot\,)` of this From 5ef48b17f3e76760d567e75f6420382709f1d482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 1 Sep 2015 15:56:05 +0200 Subject: [PATCH 0744/1872] trac #18937 adding the dependencies file --- build/pkgs/patchbot/dependencies | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/pkgs/patchbot/dependencies diff --git a/build/pkgs/patchbot/dependencies b/build/pkgs/patchbot/dependencies new file mode 100644 index 00000000000..b50cc22b772 --- /dev/null +++ b/build/pkgs/patchbot/dependencies @@ -0,0 +1 @@ +# No dependencies \ No newline at end of file From 6d2c1f465c683641910916afcaf2323da42880f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 1 Sep 2015 15:59:32 +0200 Subject: [PATCH 0745/1872] adding a missing newline --- build/pkgs/patchbot/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/patchbot/dependencies b/build/pkgs/patchbot/dependencies index b50cc22b772..4e1e0144211 100644 --- a/build/pkgs/patchbot/dependencies +++ b/build/pkgs/patchbot/dependencies @@ -1 +1 @@ -# No dependencies \ No newline at end of file +# No dependencies From d2ff0627171251668b807e811bbcc3797ea56dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 1 Sep 2015 16:03:58 +0200 Subject: [PATCH 0746/1872] trac #18937 turning to 2.4.2 --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index 8fe090e4573..e801e6e5156 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=f8e41048da15add40d24c0d01a846bef2ff22f95 -md5=b063258d4dfbb6b888f38b53e257432b -cksum=3707204329 +sha1=9f7d1d3df8dbb8821d8d077f3ffb6ba94d464372 +md5=54155d5531d615928011387185f48b34 +cksum=3140942259 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 005119baaa0..8e8299dcc06 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.1 +2.4.2 From 54f17e294b497fb20e606502f9f107f7bcf7cb24 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Sep 2015 18:27:08 +0200 Subject: [PATCH 0747/1872] == 0, == 1 --> .is_zero(), .is_one() --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- src/sage/rings/asymptotic/growth_group.py | 12 ++++++------ src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 01334b887c5..71f90c6cf14 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -929,7 +929,7 @@ def _rmul_(self, other): sage: 2*a 2*a """ - if other == 0: + if other.is_zero(): return self.parent().zero() from term_monoid import TermMonoid @@ -1254,7 +1254,7 @@ def log(self, base=None, precision=None): raise ArithmeticError('Cannot build log(0) in %s.' % (self.parent(),)) elif len(self.summands) == 1: - if self == 1: + if self.is_one(): return self.parent().zero() element = next(self.summands.elements()) return sum(self.parent()._create_element_via_parent_(l, element.parent()) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 4209f148024..d1d76d6bd64 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2214,9 +2214,9 @@ def _repr_(self): from sage.rings.integer_ring import ZZ var = repr(self.parent()._var_) - if self.exponent == 0: + if self.exponent.is_zero(): return '1' - elif self.exponent == 1: + elif self.exponent.is_one(): return var elif self.exponent in ZZ and self.exponent > 0: return var + '^' + str(self.exponent) @@ -2342,7 +2342,7 @@ def _log_factor_(self, base=None): ArithmeticError: Cannot build log(x) since log(x) is not in Growth Group x^QQ. """ - if self == self.parent().one(): + if self.is_one(): return tuple() coefficient = self.exponent if base is not None: @@ -2382,7 +2382,7 @@ def _rpow_element_(self, base): Growth Group x^ZZ """ var = str(self.parent()._var_) - if not(var.startswith('log(') and self.exponent == 1): + if not(var.startswith('log(') and self.exponent.is_one()): raise ValueError('Variable %s is not a log of something.') new_var = var[4:-1] if base == 'e': @@ -2834,7 +2834,7 @@ def _repr_(self): from sage.rings.integer_ring import ZZ var = repr(self.parent()._var_) - if self.base == 1: + if self.base.is_one(): return '1' elif not any(s in str(self.base) for s in '-/^'): return str(self.base) + '^' + var @@ -2963,7 +2963,7 @@ def _log_factor_(self, base=None): ArithmeticError: Cannot build log(4^x) since x is not in Growth Group QQ^x. """ - if self == self.parent().one(): + if self.is_one(): return tuple() b = self.base if base is None and \ diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 1fc6768d60c..1db6af0ec77 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -883,7 +883,7 @@ def _log_factor_(self, base=None): sage: (x * y).log_factor() # indirect doctest ((log(x), 1), (log(y), 1)) """ - if self == self.parent().one(): + if self.is_one(): return tuple() def try_create_growth(g): diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index a00646089bf..6d81ec2d35a 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2194,7 +2194,7 @@ def _log_coefficient_(self, base=None): :meth:`ExactTerm.log_term`, :meth:`OTerm.log_term`. """ - if self.coefficient == self.parent().coefficient_ring.one(): + if self.coefficient.is_one(): return tuple() from sage.functions.log import log return (self.parent()._create_element_via_parent_( @@ -2652,7 +2652,7 @@ def _absorb_(self, other): ArithmeticError: x^5 cannot absorb 2*x^2 """ coeff_new = self.coefficient + other.coefficient - if coeff_new == 0: + if coeff_new.is_zero(): return None else: return self.parent()(self.growth, coeff_new) From 9d0b39cf106cf03530b3e0e7effd42d0454c81b4 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 1 Sep 2015 20:18:53 +0200 Subject: [PATCH 0748/1872] is_constant for terms implemented --- src/sage/rings/asymptotic/term_monoid.py | 70 ++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 00a98c86292..57785bd2c9f 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -986,6 +986,42 @@ def _eq_(self, other): return self.growth == other.growth + def is_constant(self): + r""" + Return if this term is an (exact) constant. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + .. NOTE:: + + Only :class:`ExactTerm` with constant growth (`1`) are + constant. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, TermMonoid) + sage: T = GenericTermMonoid(GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) + sage: T.an_element().is_constant() + False + + :: + + sage: T = TermMonoid('O', GrowthGroup('x^ZZ'), QQ) + sage: T('x').is_constant() + False + sage: T(1).is_constant() + False + """ + return False + + def is_little_o_of_one(self): r""" Return if this term is of order `o(1)`. @@ -2784,6 +2820,40 @@ def log_term(self, base=None): return self._log_coefficient_(base=base) + self._log_growth_(base=base) + def is_constant(self): + r""" + Return if this term is an (exact) constant. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + .. NOTE:: + + Only :class:`ExactTerm` with constant growth (`1`) are + constant. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('exact', GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) + sage: T('x * log(x)').is_constant() + False + sage: T('3*x').is_constant() + False + sage: T(1/2).is_constant() + True + sage: T(42).is_constant() + True + """ + return self.growth.is_one() + + def is_little_o_of_one(self): r""" Return if this term is of order `o(1)`. From bdf8ae73f08d634d2f2f49a9247c81bfbf6353c4 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 1 Sep 2015 20:19:30 +0200 Subject: [PATCH 0749/1872] helper functions _construct_exp_ for terms implemented --- src/sage/rings/asymptotic/term_monoid.py | 155 +++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 57785bd2c9f..0c106398879 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1054,6 +1054,35 @@ def is_little_o_of_one(self): '(for this abstract method).') + def _construct_exp_(self, base=None): + r""" + Helper function to compute the exponential function with + the given ``base`` of this element. + + INPUT: + + - ``base`` -- the base of the exponential function. If + ``None`` (default value) is used, the Euler constant + `e` is taken as the base. + + OUTPUT: + + An asymptotic term. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: T = GenericTermMonoid(GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) + sage: T.an_element()._construct_exp_() + Traceback (most recent call last): + ... + NotImplementedError: Exponential function not implemented for this (abstract) term. + """ + raise NotImplementedError('Exponential function not implemented for ' + 'this (abstract) term.') + + def _repr_(self): r""" A representation string for this generic term. @@ -1945,6 +1974,63 @@ def is_little_o_of_one(self): return self.growth.is_lt_one() + def _construct_exp_(self, base=None): + r""" + Helper function to compute the exponential function with + the given ``base`` of this element. + + INPUT: + + - ``base`` -- the base of the exponential function. If + ``None`` (default value) is used, the Euler constant + `e` is taken as the base. + + OUTPUT: + + An asymptotic term. + + .. NOTE:: + + For :class:`OTerm`, the exponential function can only be + constructed for `O(1)`, or if ``base`` is `1`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('O', GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) + sage: T(1)._construct_exp_() + O(1) + sage: T(1)._construct_exp_(base=2) + O(1) + + :: + + sage: T.an_element()._construct_exp_(base=1) + 1 + sage: T('x^2')._construct_exp_(base=1) + 1 + + :: + + sage: T.an_element()._construct_exp_() + Traceback (most recent call last): + ... + ValueError: Exponential function of O(x*log(x)) cannot be constructed. + sage: T('log(x)')._construct_exp_() + Traceback (most recent call last): + ... + ValueError: Exponential function of O(log(x)) cannot be constructed. + """ + if self.is_one() and base != 0: + return self + if base == 1: + P = self.parent() + return ExactTermMonoid(P.growth_group, P.coefficient_ring).one() + raise ValueError('Exponential function of %s cannot be ' + 'constructed.' % (self,)) + + class OTermMonoid(GenericTermMonoid): r""" Parent for asymptotic big `O`-terms. @@ -2283,6 +2369,25 @@ def _calculate_pow_(self, exponent): return super(TermWithCoefficient, self)._calculate_pow_(exponent, coefficient=c) + def _construct_exp_(self, base=None): + r""" + Helper function to compute the exponential function with + the given ``base`` of this element. + + INPUT: + + - ``base`` -- the base of the exponential function. If + ``None`` (default value) is used, the Euler constant + `e` is taken as the base. + + OUTPUT: + + An asymptotic term. + + + """ + + def _log_coefficient_(self, base=None): r""" Helper function to calculate the logarithm of the coefficient of this element. @@ -2903,6 +3008,56 @@ def is_little_o_of_one(self): return self.growth.is_lt_one() + def _construct_exp_(self, base=None): + r""" + Helper function to compute the exponential function with + the given ``base`` of this element. + + INPUT: + + - ``base`` -- the base of the exponential function. If + ``None`` (default value) is used, the Euler constant + `e` is taken as the base. + + OUTPUT: + + An asymptotic term. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('exact', GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ'), QQ) + sage: T('x')._construct_exp_(base=2) + 2^x + sage: T('log(x)')._construct_exp_() + x + sage: T('42*log(x)')._construct_exp_() + x^42 + sage: T('3*x')._construct_exp_(base=2) + 8^x + + :: + + sage: T('3*x^2')._construct_exp_(base=2) + Traceback (most recent call last): + ... + ArithmeticError: Cannot construct 2^(x^2) in Growth Group QQ^x * x^ZZ * log(x)^ZZ + > *previous* TypeError: unsupported operand parent(s) for '*': 'Growth Group QQ^x * x^ZZ * log(x)^ZZ' and 'Growth Group ZZ^(x^2)' + """ + P = self.parent() + if not base: + base = 'e' + + if self.is_constant(): + return P(P.growth_group.one(), coefficient=base**self.coefficient) + + elem = P(self.growth.rpow(base=base), + coefficient=P.coefficient_ring.one()) + return elem**self.coefficient + + + class ExactTermMonoid(TermWithCoefficientMonoid): r""" Parent for asymptotic exact terms, implemented in From 8ff9e7bc86c9ce15bbd869eb0be72002a6377e19 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 00:53:19 +0200 Subject: [PATCH 0750/1872] implemented helper function _rpow_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 91 ++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 45dc770fd10..6d1f7d33a48 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1333,6 +1333,97 @@ def is_little_o_of_one(self): return all(term.is_little_o_of_one() for term in self.summands.maximal_elements()) + def _rpow_(self, base=None, precision=None): + r""" + Helper function. Handles exponentiation of this asymptotic + expression where the base is an element of the coefficient + ring. + + INPUT: + + - ``base`` -- the base of the exponential function. If + ``None`` (default value) is used, the Eulerian constant + `e` is taken as the base. + + - ``precision`` -- a positive integer or ``None``. + Determines the precision used for expansion of the + exponential function. + + ALGORITHM: + + The strategy for computing the exponential function is + as follows: + + - This asymptotic expression is split into a part that + is in `o(1)` and the rest. + + - The part that is in `o(1)` is expanded according to + the series expansion of `\exp(t)` for `t \to 0`. + + - The remaining part of the expression is taken exactly. + In particular, this means that the respective growth + elements have to be constructed. + + EXAMPLES:: + + sage: A. = AsymptoticRing('x^ZZ * y^ZZ', QQ) + sage: (1/x)._rpow_(precision=5) + 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + 1/24*x^(-4) + O(x^(-5)) + """ + P = self.parent() + + # first: remove terms from a copy of this term such that a + # term in o(1) remains + + expr_o = self.summands.copy() + large_terms = [] + for term in self.summands.elements(): + if not term.is_little_o_of_one(): + large_terms.append(term) + expr_o.remove(term.growth) + + expr_o = P(expr_o) + + # next: try to take the exponential function of the large elements + + try: + for k in range(len(large_terms)): + term = large_terms[k] + large_terms[k] = term._construct_exp_(base=base) + except (ValueError, TypeError): + raise ValueError('Cannot construct the exponential function of ' + 'the term %s.' % (term,)) + else: + large_result = P.prod(P(term) for term in large_terms) + + # then: expand expr_o + + if not expr_o: + return large_result + + from sage.functions.other import factorial + from sage.functions.log import log + + if not base or base == 'e': + geom = expr_o + else: + geom = expr_o * log(base) + + expanding = True + result = P.one() + geom_k = geom + k = 1 + while expanding: + new_result = (result + geom_k / factorial(k)).truncate(precision=precision) + if new_result.has_same_summands(result): + expanding = False + result = new_result + k += 1 + geom_k *= geom + + return result * large_result + + def exp(self, precision=None): r""" Return the exponential function `\exp(\,\cdot\,)` of this From 2e3dec47fa788ad101008a74513a30427157db48 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 00:53:29 +0200 Subject: [PATCH 0751/1872] doctests for exp are now actually tested --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 6d1f7d33a48..e3a6af176be 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1455,19 +1455,19 @@ def exp(self, precision=None): EXAMPLES:: sage: A. = AsymptoticRing('SR^x * x^ZZ * log(x)^ZZ', SR) - sage: exp(x) # not tested + sage: exp(x) e^x - sage: exp(2*x) # not tested + sage: exp(2*x) (e^2)^x - sage: exp(x + log(x)) # not tested + sage: exp(x + log(x)) e^x*x :: - sage: exp(x^(-1)) # not tested - 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + ... + O(x^(-21)) + sage: (x^(-1)).exp(precision=7) + 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + ... + O(x^(-7)) """ - return self._rpow_('e') + return self._rpow_(precision=precision) From 7adba3ce5344298e4b75df898fc025ceed1d8744 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 00:53:41 +0200 Subject: [PATCH 0752/1872] adaption of __pow__: call to _rpow_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index e3a6af176be..ae9129a4969 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1145,6 +1145,8 @@ def __pow__(self, exponent): elif len(self.summands) == 1: element = next(self.summands.elements()) + if isinstance(exponent, AsymptoticExpression) and element.is_constant(): + return exponent._rpow_(base=element.coefficient) return self.parent()._create_element_via_parent_( element ** exponent, element.parent()) From 0ea030c2f33ea5653cffa424517ca1b8ac367857 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 01:52:33 +0200 Subject: [PATCH 0753/1872] _log_factor_ (exponential growth group): improved handling of base=None --- src/sage/rings/asymptotic/growth_group.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 1cecce20c9a..3ee723f95ae 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2992,10 +2992,12 @@ def _log_factor_(self, base=None): if self.is_one(): return tuple() b = self.base - if base is None and \ - hasattr(b, 'is_monomial') and b.is_monomial() and \ - b.variable_name() == 'e': - coefficient = b.valuation() + if base is None and hasattr(b, 'is_monomial') and b.is_monomial() and \ + b.variable_name() == 'e': + coefficient = b.valuation() + elif base is None and hasattr(b, 'is_symbol') and b.is_symbol() and \ + repr(b) == 'e': + coefficient = self.parent().base().one() else: from sage.functions.log import log coefficient = log(b, base=base) From bb3f7077a17477ea3a4d820b40530c1a00c15e45 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 01:53:48 +0200 Subject: [PATCH 0754/1872] exponentiation of constant terms with base=None --- src/sage/rings/asymptotic/term_monoid.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 0c106398879..9332d30728e 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3050,7 +3050,8 @@ def _construct_exp_(self, base=None): base = 'e' if self.is_constant(): - return P(P.growth_group.one(), coefficient=base**self.coefficient) + return P(P.growth_group.one(), + coefficient=P.coefficient_ring(base)**self.coefficient) elem = P(self.growth.rpow(base=base), coefficient=P.coefficient_ring.one()) From d4ae5d3fb500efb7dbe1626180c59f48ddf3f667 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 01:54:02 +0200 Subject: [PATCH 0755/1872] doctests added --- src/sage/rings/asymptotic/asymptotic_ring.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index ae9129a4969..11acaea19fc 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1468,6 +1468,19 @@ def exp(self, precision=None): sage: (x^(-1)).exp(precision=7) 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + ... + O(x^(-7)) + + TESTS:: + + sage: A. = AsymptoticRing('SR^x * x^QQ * log(x)^QQ', SR) + sage: exp(log(x)) + x + sage: log(exp(x)) + x + + :: + + sage: exp(x+1) + e*e^x """ return self._rpow_(precision=precision) From ff3e5361a80e41ac469288300738ca4a902d7a13 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 02:01:44 +0200 Subject: [PATCH 0756/1872] some small doctests for __pow__ added --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 11acaea19fc..54eada966fb 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1123,6 +1123,18 @@ def __pow__(self, exponent): sage: (x^(1/2) + O(x^0))^15 x^(15/2) + O(x^7) + :: + + sage: A. = AsymptoticRing('QQ^x * x^SR * log(x)^ZZ', QQ) + sage: x * 2^x + 2^x*x + sage: 5^x * 2^x + 10^x + sage: 2^log(x) + x^(log(2)) + sage: 2^(x + 1/x) + 2^x + log(2)*2^x*x^(-1) + 1/2*log(2)^2*2^x*x^(-2) + ... + O(2^x*x^(-20)) + :: sage: O(x)^(-1) # not tested # see #19110 From 009f065afebf9beb44de0600f3b165709cfd9762 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 10:16:09 +0200 Subject: [PATCH 0757/1872] rewrite _rpow_ of AsymptoticExpression --- src/sage/rings/asymptotic/asymptotic_ring.py | 51 +++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 54eada966fb..732d2140e92 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1134,6 +1134,8 @@ def __pow__(self, exponent): x^(log(2)) sage: 2^(x + 1/x) 2^x + log(2)*2^x*x^(-1) + 1/2*log(2)^2*2^x*x^(-2) + ... + O(2^x*x^(-20)) + sage: _.parent() + Asymptotic Ring over Symbolic Ring :: @@ -1347,7 +1349,7 @@ def is_little_o_of_one(self): return all(term.is_little_o_of_one() for term in self.summands.maximal_elements()) - def _rpow_(self, base=None, precision=None): + def _rpow_(self, base, precision=None): r""" Helper function. Handles exponentiation of this asymptotic expression where the base is an element of the coefficient @@ -1355,13 +1357,11 @@ def _rpow_(self, base=None, precision=None): INPUT: - - ``base`` -- the base of the exponential function. If - ``None`` (default value) is used, the Eulerian constant - `e` is taken as the base. + - ``base`` -- an element or the ``'e'``. - - ``precision`` -- a positive integer or ``None``. - Determines the precision used for expansion of the - exponential function. + - ``precision`` -- the precision used for truncating the + expansion. If ``None`` (default value) is used, the + default precision of the parent is used. ALGORITHM: @@ -1381,9 +1381,12 @@ def _rpow_(self, base=None, precision=None): EXAMPLES:: sage: A. = AsymptoticRing('x^ZZ * y^ZZ', QQ) - sage: (1/x)._rpow_(precision=5) + sage: (1/x)._rpow_('e', precision=5) 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + 1/24*x^(-4) + O(x^(-5)) """ + if base is None: + base = 'e' + P = self.parent() # first: remove terms from a copy of this term such that a @@ -1391,7 +1394,7 @@ def _rpow_(self, base=None, precision=None): expr_o = self.summands.copy() large_terms = [] - for term in self.summands.elements(): + for term in self.summands.elements_topological(): if not term.is_little_o_of_one(): large_terms.append(term) expr_o.remove(term.growth) @@ -1401,14 +1404,15 @@ def _rpow_(self, base=None, precision=None): # next: try to take the exponential function of the large elements try: - for k in range(len(large_terms)): - term = large_terms[k] - large_terms[k] = term._construct_exp_(base=base) - except (ValueError, TypeError): - raise ValueError('Cannot construct the exponential function of ' - 'the term %s.' % (term,)) - else: - large_result = P.prod(P(term) for term in large_terms) + large_result = P.prod( + P._create_element_via_parent_(term.rpow(base), + term.parent()) + for term in large_terms) + except (TypeError, ValueError) as e: + from misc import combine_exceptions + raise combine_exceptions( + ValueError('Cannot construct the power of %s to the exponent %s in %s.' % + (base, self, self.parent())), e) # then: expand expr_o @@ -1418,22 +1422,23 @@ def _rpow_(self, base=None, precision=None): from sage.functions.other import factorial from sage.functions.log import log - if not base or base == 'e': + if base == 'e': geom = expr_o else: geom = expr_o * log(base) + P = geom.parent() expanding = True result = P.one() - geom_k = geom - k = 1 + geom_k = P.one() + k = 0 while expanding: + k += 1 + geom_k *= geom new_result = (result + geom_k / factorial(k)).truncate(precision=precision) if new_result.has_same_summands(result): expanding = False result = new_result - k += 1 - geom_k *= geom return result * large_result @@ -1494,7 +1499,7 @@ def exp(self, precision=None): sage: exp(x+1) e*e^x """ - return self._rpow_(precision=precision) + return self._rpow_('e', precision=precision) From afb2e5577f1db8407b0383a521d081024b1f5a89 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 10:17:19 +0200 Subject: [PATCH 0758/1872] rename _construct_exp_ to rpow; rewrite docstrings; remove default argument for base --- src/sage/rings/asymptotic/term_monoid.py | 98 +++++++++--------------- 1 file changed, 35 insertions(+), 63 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 9332d30728e..01b59d0ecc6 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1050,37 +1050,34 @@ def is_little_o_of_one(self): ... NotImplementedError: Growth comparison not implemented (for this abstract method). """ - raise NotImplementedError('Growth comparison not implemented ' - '(for this abstract method).') + raise NotImplementedError('Cannot check if %s is o(1) in the ' + 'abstract base class.' % (self, self.parent())) - def _construct_exp_(self, base=None): + def rpow(self, base): r""" - Helper function to compute the exponential function with - the given ``base`` of this element. + Return the power of ``base`` to this generic term. - INPUT: + INPUT: - - ``base`` -- the base of the exponential function. If - ``None`` (default value) is used, the Euler constant - `e` is taken as the base. + - ``base`` -- an element or the ``'e'``. OUTPUT: - An asymptotic term. + A term. EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid sage: T = GenericTermMonoid(GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) - sage: T.an_element()._construct_exp_() + sage: T.an_element().rpow('e') Traceback (most recent call last): ... NotImplementedError: Exponential function not implemented for this (abstract) term. """ - raise NotImplementedError('Exponential function not implemented for ' - 'this (abstract) term.') + raise NotImplementedError('Cannot take %s to the exponent %s in the ' + 'abstract base class %s.' % (base, self, self.parent()) def _repr_(self): @@ -1974,50 +1971,47 @@ def is_little_o_of_one(self): return self.growth.is_lt_one() - def _construct_exp_(self, base=None): + def rpow(self, base): r""" - Helper function to compute the exponential function with - the given ``base`` of this element. + Return the power of ``base`` to this O-term. - INPUT: + INPUT: - - ``base`` -- the base of the exponential function. If - ``None`` (default value) is used, the Euler constant - `e` is taken as the base. + - ``base`` -- an element or the ``'e'``. OUTPUT: - An asymptotic term. + A term. .. NOTE:: - For :class:`OTerm`, the exponential function can only be - constructed for `O(1)`, or if ``base`` is `1`. + For :class:`OTerm`, the powers can only be + constructed for exponents `O(1)` or if ``base`` is `1`. EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: T = TermMonoid('O', GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) - sage: T(1)._construct_exp_() + sage: T(1).rpow('e') O(1) - sage: T(1)._construct_exp_(base=2) + sage: T(1).rpow(2) O(1) :: - sage: T.an_element()._construct_exp_(base=1) + sage: T.an_element().rpow(1) 1 - sage: T('x^2')._construct_exp_(base=1) + sage: T('x^2').rpow(1) 1 :: - sage: T.an_element()._construct_exp_() + sage: T.an_element().rpow('e') Traceback (most recent call last): ... ValueError: Exponential function of O(x*log(x)) cannot be constructed. - sage: T('log(x)')._construct_exp_() + sage: T('log(x)').rpow('e') Traceback (most recent call last): ... ValueError: Exponential function of O(log(x)) cannot be constructed. @@ -2027,8 +2021,8 @@ def _construct_exp_(self, base=None): if base == 1: P = self.parent() return ExactTermMonoid(P.growth_group, P.coefficient_ring).one() - raise ValueError('Exponential function of %s cannot be ' - 'constructed.' % (self,)) + raise ValueError('Cannot take %s to the exponent %s in %s' % + (base, self, self.parent())) class OTermMonoid(GenericTermMonoid): @@ -2369,25 +2363,6 @@ def _calculate_pow_(self, exponent): return super(TermWithCoefficient, self)._calculate_pow_(exponent, coefficient=c) - def _construct_exp_(self, base=None): - r""" - Helper function to compute the exponential function with - the given ``base`` of this element. - - INPUT: - - - ``base`` -- the base of the exponential function. If - ``None`` (default value) is used, the Euler constant - `e` is taken as the base. - - OUTPUT: - - An asymptotic term. - - - """ - - def _log_coefficient_(self, base=None): r""" Helper function to calculate the logarithm of the coefficient of this element. @@ -3008,38 +2983,35 @@ def is_little_o_of_one(self): return self.growth.is_lt_one() - def _construct_exp_(self, base=None): + def rpow(self, base): r""" - Helper function to compute the exponential function with - the given ``base`` of this element. + Return the power of ``base`` to this term. - INPUT: + INPUT: - - ``base`` -- the base of the exponential function. If - ``None`` (default value) is used, the Euler constant - `e` is taken as the base. + - ``base`` -- an element or the ``'e'``. OUTPUT: - An asymptotic term. + A term. EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: T = TermMonoid('exact', GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ'), QQ) - sage: T('x')._construct_exp_(base=2) + sage: T('x').rpow(base=2) 2^x - sage: T('log(x)')._construct_exp_() + sage: T('log(x)').rpow() x - sage: T('42*log(x)')._construct_exp_() + sage: T('42*log(x)').rpow() x^42 - sage: T('3*x')._construct_exp_(base=2) + sage: T('3*x').rpow(base=2) 8^x :: - sage: T('3*x^2')._construct_exp_(base=2) + sage: T('3*x^2').rpow(base=2) Traceback (most recent call last): ... ArithmeticError: Cannot construct 2^(x^2) in Growth Group QQ^x * x^ZZ * log(x)^ZZ From 0637ba070f45f213e6c35299fafce7bb8cb22de8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 10:41:08 +0200 Subject: [PATCH 0759/1872] fix doctests --- src/sage/rings/asymptotic/term_monoid.py | 40 +++++++++++++++--------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 01b59d0ecc6..de7095828ec 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1043,15 +1043,19 @@ def is_little_o_of_one(self): sage: T.an_element().is_little_o_of_one() Traceback (most recent call last): ... - NotImplementedError: Growth comparison not implemented (for this abstract method). + NotImplementedError: Cannot check if Generic Term with growth x is o(1) + in the abstract base class + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field. sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), QQ) sage: T.an_element().is_little_o_of_one() Traceback (most recent call last): ... - NotImplementedError: Growth comparison not implemented (for this abstract method). + NotImplementedError: Cannot check if Term with coefficient 1/2 and growth x + is o(1) in the abstract base class + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field. """ raise NotImplementedError('Cannot check if %s is o(1) in the ' - 'abstract base class.' % (self, self.parent())) + 'abstract base class %s.' % (self, self.parent())) def rpow(self, base): @@ -1074,10 +1078,12 @@ def rpow(self, base): sage: T.an_element().rpow('e') Traceback (most recent call last): ... - NotImplementedError: Exponential function not implemented for this (abstract) term. + NotImplementedError: Cannot take e to the exponent + Generic Term with growth x*log(x) in the abstract base class + Generic Term Monoid x^ZZ * log(x)^ZZ with (implicit) coefficients in Rational Field. """ raise NotImplementedError('Cannot take %s to the exponent %s in the ' - 'abstract base class %s.' % (base, self, self.parent()) + 'abstract base class %s.' % (base, self, self.parent())) def _repr_(self): @@ -2010,11 +2016,13 @@ def rpow(self, base): sage: T.an_element().rpow('e') Traceback (most recent call last): ... - ValueError: Exponential function of O(x*log(x)) cannot be constructed. + ValueError: Cannot take e to the exponent O(x*log(x)) in + O-Term Monoid x^ZZ * log(x)^ZZ with implicit coefficients in Rational Field sage: T('log(x)').rpow('e') Traceback (most recent call last): ... - ValueError: Exponential function of O(log(x)) cannot be constructed. + ValueError: Cannot take e to the exponent O(log(x)) in + O-Term Monoid x^ZZ * log(x)^ZZ with implicit coefficients in Rational Field """ if self.is_one() and base != 0: return self @@ -2985,7 +2993,7 @@ def is_little_o_of_one(self): def rpow(self, base): r""" - Return the power of ``base`` to this term. + Return the power of ``base`` to this exact term. INPUT: @@ -3000,22 +3008,24 @@ def rpow(self, base): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: T = TermMonoid('exact', GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ'), QQ) - sage: T('x').rpow(base=2) + sage: T('x').rpow(2) 2^x - sage: T('log(x)').rpow() + sage: T('log(x)').rpow('e') x - sage: T('42*log(x)').rpow() + sage: T('42*log(x)').rpow('e') x^42 - sage: T('3*x').rpow(base=2) + sage: T('3*x').rpow(2) 8^x :: - sage: T('3*x^2').rpow(base=2) + sage: T('3*x^2').rpow(2) Traceback (most recent call last): ... - ArithmeticError: Cannot construct 2^(x^2) in Growth Group QQ^x * x^ZZ * log(x)^ZZ - > *previous* TypeError: unsupported operand parent(s) for '*': 'Growth Group QQ^x * x^ZZ * log(x)^ZZ' and 'Growth Group ZZ^(x^2)' + ArithmeticError: Cannot construct 2^(x^2) in + Growth Group QQ^x * x^ZZ * log(x)^ZZ + > *previous* TypeError: unsupported operand parent(s) for '*': + 'Growth Group QQ^x * x^ZZ * log(x)^ZZ' and 'Growth Group ZZ^(x^2)' """ P = self.parent() if not base: From 1d8fe499abf5f9c51209720682a7d36b6f51c54e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 10:41:33 +0200 Subject: [PATCH 0760/1872] rewrite rpow of exact term to take care of parent changes --- src/sage/rings/asymptotic/term_monoid.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index de7095828ec..707baa6e66d 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3028,17 +3028,16 @@ def rpow(self, base): 'Growth Group QQ^x * x^ZZ * log(x)^ZZ' and 'Growth Group ZZ^(x^2)' """ P = self.parent() - if not base: - base = 'e' if self.is_constant(): - return P(P.growth_group.one(), - coefficient=P.coefficient_ring(base)**self.coefficient) - - elem = P(self.growth.rpow(base=base), - coefficient=P.coefficient_ring.one()) - return elem**self.coefficient - + if not hasattr(base, 'parent'): + base = P.coefficient_ring(base) + return P._create_element_via_parent_( + P.growth_group.one(), base ** self.coefficient) + + elem = P._create_element_via_parent_( + self.growth.rpow(base), P.coefficient_ring.one()) + return elem ** self.coefficient class ExactTermMonoid(TermWithCoefficientMonoid): From f7742239b2df96f19effe33bd8da75a956bbd26d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 10:41:42 +0200 Subject: [PATCH 0761/1872] generalize log_factor --- src/sage/rings/asymptotic/growth_group.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 3ee723f95ae..6ea92fe4b39 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2995,8 +2995,7 @@ def _log_factor_(self, base=None): if base is None and hasattr(b, 'is_monomial') and b.is_monomial() and \ b.variable_name() == 'e': coefficient = b.valuation() - elif base is None and hasattr(b, 'is_symbol') and b.is_symbol() and \ - repr(b) == 'e': + elif base is None and str(b) == 'e': coefficient = self.parent().base().one() else: from sage.functions.log import log From 3e07d1e366bbdec34871f60124a7022011d5118d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 10:43:34 +0200 Subject: [PATCH 0762/1872] minor change on docstring of is_little_o_of_one --- src/sage/rings/asymptotic/term_monoid.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 707baa6e66d..64072ff6ecb 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1024,7 +1024,7 @@ def is_constant(self): def is_little_o_of_one(self): r""" - Return if this term is of order `o(1)`. + Return if this generic term is of order `o(1)`. INPUT: @@ -1930,7 +1930,7 @@ def log_term(self, base=None): def is_little_o_of_one(self): r""" - Return if this term is of order `o(1)`. + Return if this O-term is of order `o(1)`. INPUT: @@ -2944,7 +2944,7 @@ def is_constant(self): def is_little_o_of_one(self): r""" - Return if this term is of order `o(1)`. + Return if this exact term is of order `o(1)`. INPUT: From f7140be2dea94d4d58ab8ea544c5d68e87dcbc1d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 11:11:18 +0200 Subject: [PATCH 0763/1872] cartesian_product of growth groups: create_element_via_parent --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/growth_group.py | 3 -- .../asymptotic/growth_group_cartesian.py | 52 ++++++++++++++----- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 732d2140e92..0044535d5e8 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1135,7 +1135,7 @@ def __pow__(self, exponent): sage: 2^(x + 1/x) 2^x + log(2)*2^x*x^(-1) + 1/2*log(2)^2*2^x*x^(-2) + ... + O(2^x*x^(-20)) sage: _.parent() - Asymptotic Ring over Symbolic Ring + Asymptotic Ring over Symbolic Ring :: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6ea92fe4b39..5b21ae753bf 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1573,9 +1573,6 @@ def _create_element_via_parent_(self, raw_element): - ``raw_element`` -- the element data. - - ``old_parent`` -- the parent of ``raw_element`` is compared - to this parent. - OUTPUT: An element. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 75dcb576924..cbb797c7ce0 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -321,6 +321,42 @@ def some_elements(self): izip(*tuple(F.some_elements() for F in self.cartesian_factors()))) + def _create_element_via_parent_(self, element): + r""" + Create an element with a possibly other parent. + + INPUT: + + - ``element`` -- a tuple. + + OUTPUT: + + An element. + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^ZZ * log(z)^ZZ') + sage: z = G('z')[0] + sage: lz = G('log(z)')[1] + sage: G._create_element_via_parent_((z^3, lz)).parent() + Growth Group z^ZZ * log(z)^ZZ + sage: G._create_element_via_parent_((z^(1/2), lz)).parent() + Growth Group z^QQ * log(z)^ZZ + """ + from misc import underlying_class + + factors = self.cartesian_factors() + if len(element) != len(factors): + raise ValueError('Cannot create %s as a cartesian product like %s.' % + (element, self)) + + if all(n.parent() is f for n, f in zip(element, factors)): + parent = self + else: + parent = underlying_class(self)(tuple(n.parent() for n in element), + category=self.category()) + return parent(element) + + def _element_constructor_(self, data): r""" Converts the given object to an element of this cartesian @@ -837,9 +873,8 @@ def __pow__(self, exponent): sage: (x^(21/5) * log(x)^7)^(1/42) # indirect doctest x^(1/10)*log(x)^(1/6) """ - P = self.parent() - return P.prod(P.cartesian_injection(elt.parent(), elt ** exponent) - for elt in self.value) + return self.parent()._create_element_via_parent_( + tuple(x ** exponent for x in self.cartesian_factors())) def factors(self): @@ -1047,15 +1082,8 @@ def __invert__(self): sage: (~g).parent() Growth Group QQ^x * x^ZZ """ - new_element = tuple(~x for x in self.cartesian_factors()) - if all(n.parent() is x.parent() - for n, x in zip(new_element, self.cartesian_factors())): - return self.parent()(new_element) - else: - from sage.categories.cartesian_product import cartesian_product - new_parent = cartesian_product( - tuple(x.parent() for x in new_element)) - return new_parent(new_element) + return self.parent()._create_element_via_parent_( + tuple(~x for x in self.cartesian_factors())) CartesianProduct = CartesianProductGrowthGroups From 16bd20044cef5b14eaf74873cd30ebf41d6ea05e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 11:14:15 +0200 Subject: [PATCH 0764/1872] create_element_via_parent: use categories as well --- src/sage/rings/asymptotic/growth_group.py | 5 +++-- src/sage/rings/asymptotic/growth_group_cartesian.py | 3 +-- src/sage/rings/asymptotic/term_monoid.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 5b21ae753bf..84c7c9b4135 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1584,11 +1584,12 @@ def _create_element_via_parent_(self, raw_element): sage: G._create_element_via_parent_(1/2).parent() Growth Group z^QQ """ - from misc import underlying_class if raw_element.parent() is self.base(): parent = self else: - parent = underlying_class(self)(raw_element.parent(), self._var_) + from misc import underlying_class + parent = underlying_class(self)(raw_element.parent(), self._var_, + category=self.category()) return parent(raw_element=raw_element) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index cbb797c7ce0..17214efb2e1 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -342,8 +342,6 @@ def _create_element_via_parent_(self, element): sage: G._create_element_via_parent_((z^(1/2), lz)).parent() Growth Group z^QQ * log(z)^ZZ """ - from misc import underlying_class - factors = self.cartesian_factors() if len(element) != len(factors): raise ValueError('Cannot create %s as a cartesian product like %s.' % @@ -352,6 +350,7 @@ def _create_element_via_parent_(self, element): if all(n.parent() is f for n, f in zip(element, factors)): parent = self else: + from misc import underlying_class parent = underlying_class(self)(tuple(n.parent() for n in element), category=self.category()) return parent(element) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 64072ff6ecb..55b89557ddf 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1523,7 +1523,8 @@ def _create_element_via_parent_(self, growth, coefficient): parent = underlying_class(self)(growth.parent(), coefficient.parent() if coefficient is not None - else self.coefficient_ring) + else self.coefficient_ring, + category=self.category()) return parent(growth, coefficient) From e29d13ec504f7a113e30f533f4642f489364c2ca Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 11:33:36 +0200 Subject: [PATCH 0765/1872] rpow, precision, docs --- src/sage/rings/asymptotic/asymptotic_ring.py | 38 ++++++++++++-------- src/sage/rings/asymptotic/term_monoid.py | 6 ++-- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0044535d5e8..896bad66961 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1098,14 +1098,18 @@ def convert_terms(element): return self.parent()(summands, simplify=True, convert=False) - def __pow__(self, exponent): + def __pow__(self, exponent, precision=None): r""" - Calculate the power of this element to the given ``exponent``. + Calculate the power of this asymptotic expression to the given ``exponent``. INPUT: - ``exponent`` -- an element. + - ``precision`` -- the precision used for truncating the + expansion. If ``None`` (default value) is used, the + default precision of the parent is used. + OUTPUT: An asymptotic expression. @@ -1160,7 +1164,7 @@ def __pow__(self, exponent): elif len(self.summands) == 1: element = next(self.summands.elements()) if isinstance(exponent, AsymptoticExpression) and element.is_constant(): - return exponent._rpow_(base=element.coefficient) + return exponent.rpow(base=element.coefficient, precision=precision) return self.parent()._create_element_via_parent_( element ** exponent, element.parent()) @@ -1173,13 +1177,16 @@ def __pow__(self, exponent): return super(AsymptoticExpression, self).__pow__(exponent) try: - return (exponent * self.log()).exp() + return (exponent * self.log(precision=precision)).exp(precision=precision) except (TypeError, ValueError, ZeroDivisionError) as e: from misc import combine_exceptions raise combine_exceptions( ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) + pow = __pow__ + + def O(self): r""" Convert all terms in this asymptotic expression to `O`-terms. @@ -1349,20 +1356,22 @@ def is_little_o_of_one(self): return all(term.is_little_o_of_one() for term in self.summands.maximal_elements()) - def _rpow_(self, base, precision=None): + def rpow(self, base, precision=None): r""" - Helper function. Handles exponentiation of this asymptotic - expression where the base is an element of the coefficient - ring. + Return the power of ``base`` to this asymptotic expression. INPUT: - - ``base`` -- an element or the ``'e'``. + - ``base`` -- an element or ``'e'``. - ``precision`` -- the precision used for truncating the expansion. If ``None`` (default value) is used, the default precision of the parent is used. + OUTPUT: + + An asymptotic expression. + ALGORITHM: The strategy for computing the exponential function is @@ -1381,11 +1390,11 @@ def _rpow_(self, base, precision=None): EXAMPLES:: sage: A. = AsymptoticRing('x^ZZ * y^ZZ', QQ) - sage: (1/x)._rpow_('e', precision=5) + sage: (1/x).rpow('e', precision=5) 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + 1/24*x^(-4) + O(x^(-5)) """ - if base is None: - base = 'e' + if isinstance(base, AsymptoticExpression): + return base.__pow__(self, precision=precision) P = self.parent() @@ -1445,8 +1454,7 @@ def _rpow_(self, base, precision=None): def exp(self, precision=None): r""" - Return the exponential function `\exp(\,\cdot\,)` of this - asymptotic expression. + Return the exponential of (i.e., the power of `e` to) this asymptotic expression. INPUT: @@ -1499,7 +1507,7 @@ def exp(self, precision=None): sage: exp(x+1) e*e^x """ - return self._rpow_('e', precision=precision) + return self.rpow('e', precision=precision) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 55b89557ddf..948c30da089 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1064,7 +1064,7 @@ def rpow(self, base): INPUT: - - ``base`` -- an element or the ``'e'``. + - ``base`` -- an element or ``'e'``. OUTPUT: @@ -1984,7 +1984,7 @@ def rpow(self, base): INPUT: - - ``base`` -- an element or the ``'e'``. + - ``base`` -- an element or ``'e'``. OUTPUT: @@ -2998,7 +2998,7 @@ def rpow(self, base): INPUT: - - ``base`` -- an element or the ``'e'``. + - ``base`` -- an element or ``'e'``. OUTPUT: From 58026e4754a1cb6416f7f53ac6b737f878c28d4e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 12:31:05 +0200 Subject: [PATCH 0766/1872] create invert = __invert__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 896bad66961..be0ff83ed71 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -986,7 +986,7 @@ def __invert__(self, precision=None): Due to truncation of infinite expansions, the element returned by this method might not fulfill - ``el * el._invert_() == 1``. + ``el * ~el == 1``. EXAMPLES:: @@ -1045,6 +1045,9 @@ def __invert__(self, precision=None): return result._mul_term_(imax_elem) + invert = __invert__ + + def truncate(self, precision=None): r""" Truncate this asymptotic expression. From 6377bb77b8708a93d82991cc58765c6ee43c0ec1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 12:48:43 +0200 Subject: [PATCH 0767/1872] minor rewrite of AR.rpow --- src/sage/rings/asymptotic/asymptotic_ring.py | 10 +++++----- src/sage/rings/asymptotic/term_monoid.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index be0ff83ed71..51b121c6612 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1431,23 +1431,23 @@ def rpow(self, base, precision=None): if not expr_o: return large_result - from sage.functions.other import factorial - from sage.functions.log import log if base == 'e': geom = expr_o else: + from sage.functions.log import log geom = expr_o * log(base) P = geom.parent() expanding = True result = P.one() geom_k = P.one() - k = 0 + from sage.rings.integer_ring import ZZ + k = ZZ(0) while expanding: - k += 1 + k += ZZ(1) geom_k *= geom - new_result = (result + geom_k / factorial(k)).truncate(precision=precision) + new_result = (result + geom_k / k.factorial()).truncate(precision=precision) if new_result.has_same_summands(result): expanding = False result = new_result diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 948c30da089..db7e3195dab 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1043,7 +1043,7 @@ def is_little_o_of_one(self): sage: T.an_element().is_little_o_of_one() Traceback (most recent call last): ... - NotImplementedError: Cannot check if Generic Term with growth x is o(1) + NotImplementedError: Cannot check if Generic Term with growth x is o(1) in the abstract base class Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field. sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), QQ) From 1a695773b57b7645fd87e0b8404ccba303ed2308 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 13:49:03 +0200 Subject: [PATCH 0768/1872] example constant e --- src/sage/rings/asymptotic/asymptotic_ring.py | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 51b121c6612..67464c63d0e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -235,6 +235,28 @@ More Examples ============= + +The mathematical constant e as a limit +-------------------------------------- + +The base of the natural logarithm `e` satisfies the equation + +.. MATH:: + + e = \lim_{n\to\infty} \left(1+\frac{1}{n}\right)^n + +By using asymptotic expressions, we obtain the more precise result +:: + + sage: E. = AsymptoticRing(growth_group='n^ZZ', coefficient_ring=SR, default_prec=5); E + Asymptotic Ring over Symbolic Ring + sage: (1 + 1/n)^n + e - 1/2*e*n^(-1) + 11/24*e*n^(-2) - 7/16*e*n^(-3) + 2447/5760*e*n^(-4) + O(n^(-5)) + + +Example n+1 +----------- + .. TODO:: write more examples From 312f5bfd8ce38908eaa3f04b990cba35a9fe1cc5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 13:49:14 +0200 Subject: [PATCH 0769/1872] fix a broken link --- src/sage/rings/asymptotic/growth_group.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 84c7c9b4135..3d8e719d942 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -701,8 +701,8 @@ def log_factor(self, base=None): .. SEEALSO:: - :meth:`~GenericGrowthElement.factors`, - :meth:`~GenericGrowthElement.log`. + :meth:`~sage.rings.asymptotic.growth_group.GenericGrowthElement.factors`, + :meth:`~sage.rings.asymptotic.growth_group.GenericGrowthElement.log`. TESTS:: @@ -1252,6 +1252,7 @@ def factors(self): """ return (self,) + is_lt_one = is_lt_one From aa3330be8897e25acad09dbe15230a687a50f0a8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 13:52:50 +0200 Subject: [PATCH 0770/1872] adapt doctests (SR vs. QQ['e']) --- src/sage/rings/asymptotic/growth_group.py | 15 ++++++++++++++- .../rings/asymptotic/growth_group_cartesian.py | 7 +++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 3d8e719d942..5df31251349 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -627,14 +627,23 @@ def log(self, base=None): sage: x, = G.gens_monomial() sage: log(exp(x)) x + sage: G.one().log() + Traceback (most recent call last): + ... + ArithmeticError: log(1) is zero, which is not contained in + Growth Group QQ[e]^x * x^ZZ. :: + sage: G = GrowthGroup("SR^x * x^ZZ") + sage: x, = G.gens_monomial() + sage: log(exp(x)) + x sage: G.one().log() Traceback (most recent call last): ... ArithmeticError: log(1) is zero, which is not contained in - Growth Group QQ[e]^x * x^ZZ. + Growth Group SR^x * x^ZZ. """ log_factor = self.log_factor(base=base) if not log_factor: @@ -710,6 +719,10 @@ def log_factor(self, base=None): sage: x, = G.gens_monomial() sage: (exp(x) * x).log_factor() ((x, 1), (log(x), 1)) + sage: G = GrowthGroup("SR^x * x^ZZ * log(x)^ZZ") + sage: x, = G.gens_monomial() + sage: (exp(x) * x).log_factor() + ((x, 1), (log(x), 1)) """ log_factor = self._log_factor_(base=base) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 17214efb2e1..53c5b26c8f2 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1057,6 +1057,13 @@ def exp(self): y sage: exp(log(y)) y + sage: E = GrowthGroup("SR^y * y^QQ * log(y)^QQ") + sage: y = E('y') + sage: log(exp(y)) + y + sage: exp(log(y)) + y + """ return self.rpow('e') From 2addcc0f183be4d282a0fd54a90d53547aa209db Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 15:37:41 +0200 Subject: [PATCH 0771/1872] ack. GSoC15 --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 ++ src/sage/rings/asymptotic/growth_group.py | 2 ++ src/sage/rings/asymptotic/growth_group_cartesian.py | 2 ++ src/sage/rings/asymptotic/misc.py | 2 ++ src/sage/rings/asymptotic/term_monoid.py | 2 ++ 5 files changed, 10 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 51b121c6612..cda07714df6 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -339,6 +339,8 @@ - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the Austrian Science Fund (FWF): P 24644-N26. +- Benjamin Hackl is supported by the Google Summer of Code 2015. + Classes and Methods =================== diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 84c7c9b4135..496d36a6274 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -190,6 +190,8 @@ - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the Austrian Science Fund (FWF): P 24644-N26. +- Benjamin Hackl is supported by the Google Summer of Code 2015. + Classes and Methods =================== """ diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 17214efb2e1..716b1819a7a 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -14,6 +14,8 @@ - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the Austrian Science Fund (FWF): P 24644-N26. +- Benjamin Hackl is supported by the Google Summer of Code 2015. + .. WARNING:: As this code is experimental, warnings are thrown when a growth diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index fa30f1537cc..bade7ec4868 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -11,6 +11,8 @@ - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the Austrian Science Fund (FWF): P 24644-N26. +- Benjamin Hackl is supported by the Google Summer of Code 2015. + Functions, Classes and Methods ============================== diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index db7e3195dab..b10f4d4592c 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -50,6 +50,8 @@ - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the Austrian Science Fund (FWF): P 24644-N26. +- Benjamin Hackl is supported by the Google Summer of Code 2015. + .. WARNING:: As this code is experimental, a warning is thrown when a term From 517cec28489ca2b35a6b08bab7eedc6c454e526c Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 15:44:41 +0200 Subject: [PATCH 0772/1872] minor rewording --- src/sage/rings/asymptotic/term_monoid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index b10f4d4592c..42604817e27 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -820,7 +820,7 @@ def __le__(self, other): (5*x^2, 2/7*x^3) In order for the comparison to work, the terms have come from - or coerce into the same parent. Concretely, comparing + or coerce into the same parent. In particular, comparing :class:`GenericTerm` to, for example, an :class:`OTerm` always yields ``False``:: From a04ae59f0652fb4683c2f9e93956788058ba689d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 15:45:06 +0200 Subject: [PATCH 0773/1872] remove strange comment in doctest --- src/sage/rings/asymptotic/term_monoid.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 42604817e27..5d3b556c087 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1376,9 +1376,11 @@ def _element_constructor_(self, data, coefficient=None): sage: T_QQ = atm.GenericTermMonoid(G_QQ, QQ) sage: term1 = T_ZZ(G_ZZ.gen()) sage: term2 = T_QQ(G_QQ.gen()^2) - sage: term1 <= term2 # in order for two terms to be compared, - ....: # a coercion into one of the parents - ....: # has to be found. + + In order for two terms to be compared, a coercion into one + of the parents has to be found:: + + sage: term1 <= term2 True sage: T_QQ.coerce(term1) # coercion does not fail Generic Term with growth x From a804b7b01f0678ed001f0d681bb9afb8ac43774a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 15:45:41 +0200 Subject: [PATCH 0774/1872] refactoring doctests: agg, atm: gone. instead: from ... import ... --- src/sage/rings/asymptotic/growth_group.py | 344 ++++++------ .../asymptotic/growth_group_cartesian.py | 28 +- src/sage/rings/asymptotic/misc.py | 12 +- src/sage/rings/asymptotic/term_monoid.py | 502 +++++++++--------- 4 files changed, 441 insertions(+), 445 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 496d36a6274..8dbad220807 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -133,10 +133,10 @@ EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_x = agg.GrowthGroup('x^ZZ'); repr(G_x) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_x = GrowthGroup('x^ZZ'); repr(G_x) 'Growth Group x^ZZ' - sage: G_xy = agg.GrowthGroup('x^ZZ * y^ZZ'); G_xy + sage: G_xy = GrowthGroup('x^ZZ * y^ZZ'); G_xy Growth Group x^ZZ * y^ZZ sage: G_xy.an_element() x*y @@ -156,12 +156,12 @@ In terms of uniqueness, we have the following behaviour:: - sage: agg.GrowthGroup('x^ZZ * y^ZZ') is agg.GrowthGroup('y^ZZ * x^ZZ') + sage: GrowthGroup('x^ZZ * y^ZZ') is GrowthGroup('y^ZZ * x^ZZ') True The above is ``True`` since the order of the factors does not play a role here; they use different variables. But when using the same variable, it plays a role:: - sage: agg.GrowthGroup('x^ZZ * log(x)^ZZ') is agg.GrowthGroup('log(x)^ZZ * x^ZZ') + sage: GrowthGroup('x^ZZ * log(x)^ZZ') is GrowthGroup('log(x)^ZZ * x^ZZ') False (Note that it is mathematically nonsense to make ``log(x)`` larger than ``x``.) @@ -169,7 +169,7 @@ With the help of the short notation, even complicated growth groups can be constructed easily:: - sage: G = agg.GrowthGroup('QQ^x * x^ZZ * log(x)^QQ * y^QQ') + sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^QQ * y^QQ') sage: G.an_element() (1/2)^x*x*log(x)^(1/2)*y^(1/2) sage: (x, y) = var('x y') @@ -814,9 +814,10 @@ class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) - sage: g = agg.GenericGrowthElement(G, 42); g + sage: from sage.rings.asymptotic.growth_group import (GenericGrowthGroup, + ....: GenericGrowthElement) + sage: G = GenericGrowthGroup(ZZ) + sage: g = GenericGrowthElement(G, 42); g GenericGrowthElement(42) sage: g.parent() Growth Group Generic(ZZ) @@ -830,8 +831,8 @@ def __init__(self, parent, raw_element): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ) sage: G(raw_element=42) GenericGrowthElement(42) @@ -842,13 +843,14 @@ def __init__(self, parent, raw_element): :: - sage: G = agg.GenericGrowthGroup(ZZ) + sage: G = GenericGrowthGroup(ZZ) sage: G(raw_element=42).category() Category of elements of Growth Group Generic(ZZ) :: - sage: agg.GenericGrowthElement(None, 0) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthElement + sage: GenericGrowthElement(None, 0) Traceback (most recent call last): ... ValueError: The parent must be provided @@ -902,8 +904,8 @@ def __hash__(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ); + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ); sage: hash(G(raw_element=42)) # random 5656565656565656 """ @@ -929,8 +931,8 @@ def _mul_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ) sage: g = G.an_element() sage: g*g Traceback (most recent call last): @@ -992,8 +994,8 @@ def __eq__(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ) sage: G.an_element() == G.an_element() True sage: G(raw_element=42) == G(raw_element=7) @@ -1001,15 +1003,16 @@ def __eq__(self, other): :: - sage: G_ZZ = agg.GenericGrowthGroup(ZZ) - sage: G_QQ = agg.GenericGrowthGroup(QQ) + sage: G_ZZ = GenericGrowthGroup(ZZ) + sage: G_QQ = GenericGrowthGroup(QQ) sage: G_ZZ(raw_element=1) == G_QQ(raw_element=1) True :: - sage: P_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P_QQ = agg.MonomialGrowthGroup(QQ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P_ZZ = GrowthGroup('x^ZZ') + sage: P_QQ = GrowthGroup('x^QQ') sage: P_ZZ.gen() == P_QQ.gen() True sage: ~P_ZZ.gen() == P_ZZ.gen() @@ -1048,8 +1051,8 @@ def _eq_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: e1 = P(raw_element=1) sage: e1._eq_(P.gen()) True @@ -1119,9 +1122,9 @@ def __le__(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P_QQ = agg.MonomialGrowthGroup(QQ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P_ZZ = GrowthGroup('x^ZZ') + sage: P_QQ = GrowthGroup('x^QQ') sage: P_ZZ.gen() <= P_QQ.gen()^2 True sage: ~P_ZZ.gen() <= P_ZZ.gen() @@ -1159,8 +1162,8 @@ def _le_(self, other): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ) sage: e1 = G(raw_element=1); e2 = G(raw_element=2) sage: e1 <= e2 # indirect doctest Traceback (most recent call last): @@ -1279,8 +1282,8 @@ class GenericGrowthGroup( EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ); G + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ); G Growth Group Generic(ZZ) .. SEEALSO:: @@ -1304,23 +1307,23 @@ def __classcall__(cls, base, var=None, category=None): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P1 = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P2 = agg.MonomialGrowthGroup(ZZ, ZZ['x'].gen()) - sage: P3 = agg.MonomialGrowthGroup(ZZ, SR.var('x')) + sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup + sage: P1 = MonomialGrowthGroup(ZZ, 'x') + sage: P2 = MonomialGrowthGroup(ZZ, ZZ['x'].gen()) + sage: P3 = MonomialGrowthGroup(ZZ, SR.var('x')) sage: P1 is P2 and P2 is P3 True - sage: P4 = agg.MonomialGrowthGroup(ZZ, buffer('xylophone', 0, 1)) + sage: P4 = MonomialGrowthGroup(ZZ, buffer('xylophone', 0, 1)) sage: P1 is P4 True - sage: P5 = agg.MonomialGrowthGroup(ZZ, 'x ') + sage: P5 = MonomialGrowthGroup(ZZ, 'x ') sage: P1 is P5 True :: - sage: L1 = agg.MonomialGrowthGroup(QQ, log(x)) - sage: L2 = agg.MonomialGrowthGroup(QQ, 'log(x)') + sage: L1 = MonomialGrowthGroup(QQ, log(x)) + sage: L2 = MonomialGrowthGroup(QQ, 'log(x)') sage: L1 is L2 True """ @@ -1348,65 +1351,64 @@ def __init__(self, base, var, category): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GenericGrowthGroup(ZZ).category() + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: GenericGrowthGroup(ZZ).category() Join of Category of monoids and Category of posets :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup + sage: MonomialGrowthGroup(ZZ, 'x') Growth Group x^ZZ - sage: agg.MonomialGrowthGroup(QQ, SR.var('n')) + sage: MonomialGrowthGroup(QQ, SR.var('n')) Growth Group n^QQ - sage: agg.MonomialGrowthGroup(ZZ, ZZ['y'].gen()) + sage: MonomialGrowthGroup(ZZ, ZZ['y'].gen()) Growth Group y^ZZ - sage: agg.MonomialGrowthGroup(QQ, 'log(x)') + sage: MonomialGrowthGroup(QQ, 'log(x)') Growth Group log(x)^QQ :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.ExponentialGrowthGroup(QQ, 'x') + sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup + sage: ExponentialGrowthGroup(QQ, 'x') Growth Group QQ^x - sage: agg.ExponentialGrowthGroup(SR, ZZ['y'].gen()) + sage: ExponentialGrowthGroup(SR, ZZ['y'].gen()) Growth Group SR^y TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) + sage: G = GenericGrowthGroup(ZZ) sage: G.is_parent_of(G(raw_element=42)) True - sage: G2 = agg.GenericGrowthGroup(ZZ, category=FiniteGroups() & Posets()) + sage: G2 = GenericGrowthGroup(ZZ, category=FiniteGroups() & Posets()) sage: G2.category() Join of Category of finite groups and Category of finite posets :: - sage: G = agg.GenericGrowthGroup('42') + sage: G = GenericGrowthGroup('42') Traceback (most recent call last): ... TypeError: 42 is not a valid base. :: - sage: agg.MonomialGrowthGroup('x', ZZ) + sage: MonomialGrowthGroup('x', ZZ) Traceback (most recent call last): ... TypeError: x is not a valid base. - sage: agg.MonomialGrowthGroup('x', 'y') + sage: MonomialGrowthGroup('x', 'y') Traceback (most recent call last): ... TypeError: x is not a valid base. :: - sage: agg.ExponentialGrowthGroup('x', ZZ) + sage: ExponentialGrowthGroup('x', ZZ) Traceback (most recent call last): ... TypeError: x is not a valid base. - sage: agg.ExponentialGrowthGroup('x', 'y') + sage: ExponentialGrowthGroup('x', 'y') Traceback (most recent call last): ... TypeError: x is not a valid base. @@ -1462,15 +1464,15 @@ def _repr_(self, condense=False): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.MonomialGrowthGroup(ZZ, 'x') # indirect doctest + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ') # indirect doctest Growth Group x^ZZ - sage: agg.MonomialGrowthGroup(QQ, 'log(x)') # indirect doctest + sage: GrowthGroup('log(x)^QQ') # indirect doctest Growth Group log(x)^QQ TESTS:: - sage: agg.MonomialGrowthGroup(QQ, 'log(x)')._repr_(condense=True) + sage: GrowthGroup('log(x)^QQ')._repr_(condense=True) 'log(x)^QQ' """ pre = 'Growth Group ' if not condense else '' @@ -1491,21 +1493,20 @@ def __hash__(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: hash(agg.GenericGrowthGroup(ZZ)) # random + sage: from sage.rings.asymptotic.growth_group import (GenericGrowthGroup, + ....: GrowthGroup) + sage: hash(GenericGrowthGroup(ZZ)) # random 4242424242424242 :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: P = GrowthGroup('x^ZZ') sage: hash(P) # random -1234567890123456789 :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') + sage: P = GrowthGroup('QQ^x') sage: hash(P) # random -1234567890123456789 """ @@ -1526,13 +1527,16 @@ def _an_element_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GenericGrowthGroup(ZZ).an_element() # indirect doctest + sage: from sage.rings.asymptotic.growth_group import (GenericGrowthGroup, + ....: GrowthGroup) + sage: GenericGrowthGroup(ZZ).an_element() # indirect doctest GenericGrowthElement(1) - sage: agg.MonomialGrowthGroup(ZZ, 'z').an_element() # indirect doctest + sage: GrowthGroup('z^ZZ').an_element() # indirect doctest z - sage: agg.MonomialGrowthGroup(QQ, 'log(z)').an_element() # indirect doctest + sage: GrowthGroup('log(z)^QQ').an_element() # indirect doctest log(z)^(1/2) + sage: GrowthGroup('QQ^(x*log(x))').an_element() # indirect doctest + (1/2)^(x*log(x)) """ return self.element_class(self, self.base().an_element()) @@ -1553,11 +1557,11 @@ def some_elements(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: tuple(agg.MonomialGrowthGroup(ZZ, 'z').some_elements()) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: tuple(GrowthGroup('z^ZZ').some_elements()) (1, z, z^(-1), z^2, z^(-2), z^3, z^(-3), z^4, z^(-4), z^5, z^(-5), ...) - sage: tuple(agg.MonomialGrowthGroup(QQ, 'z').some_elements()) + sage: tuple(GrowthGroup('z^QQ').some_elements()) (z^(1/2), z^(-1/2), z^2, z^(-2), 1, z, z^(-1), z^42, z^(2/3), z^(-2/3), z^(3/2), z^(-3/2), @@ -1617,8 +1621,8 @@ def le(self, left, right): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ') sage: x = G.gen() sage: G.le(x, x^2) True @@ -1654,8 +1658,8 @@ def _element_constructor_(self, data, raw_element=None): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.GenericGrowthGroup(ZZ) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G_ZZ = GenericGrowthGroup(ZZ) sage: z = G_ZZ(raw_element=42); z GenericGrowthElement(42) sage: z is G_ZZ(z) @@ -1663,7 +1667,7 @@ def _element_constructor_(self, data, raw_element=None): :: - sage: G_QQ = agg.GenericGrowthGroup(QQ) + sage: G_QQ = GenericGrowthGroup(QQ) sage: q = G_QQ(raw_element=42) sage: q is z False @@ -1691,8 +1695,9 @@ def _element_constructor_(self, data, raw_element=None): :: - sage: x = agg.MonomialGrowthGroup(ZZ, 'x')(raw_element=1) - sage: G_y = agg.MonomialGrowthGroup(ZZ, 'y') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: x = GrowthGroup('x^ZZ')(raw_element=1) + sage: G_y = GrowthGroup('y^ZZ') sage: G_y(x) Traceback (most recent call last): ... @@ -1743,8 +1748,8 @@ def _convert_(self, data): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ) sage: G._convert_('icecream') is None True """ @@ -1765,9 +1770,9 @@ def _coerce_map_from_(self, S): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') - sage: G_QQ = agg.MonomialGrowthGroup(QQ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G_ZZ = GrowthGroup('x^ZZ') + sage: G_QQ = GrowthGroup('x^QQ') sage: G_ZZ.has_coerce_map_from(G_QQ) # indirect doctest False sage: G_QQ.has_coerce_map_from(G_ZZ) # indirect doctest @@ -1775,14 +1780,14 @@ def _coerce_map_from_(self, S): :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P_x_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P_x_QQ = agg.MonomialGrowthGroup(QQ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P_x_ZZ = GrowthGroup('x^ZZ') + sage: P_x_QQ = GrowthGroup('x^QQ') sage: P_x_ZZ.has_coerce_map_from(P_x_QQ) # indirect doctest False sage: P_x_QQ.has_coerce_map_from(P_x_ZZ) # indirect doctest True - sage: P_y_ZZ = agg.MonomialGrowthGroup(ZZ, 'y') + sage: P_y_ZZ = GrowthGroup('y^ZZ') sage: P_y_ZZ.has_coerce_map_from(P_x_ZZ) # indirect doctest False sage: P_x_ZZ.has_coerce_map_from(P_y_ZZ) # indirect doctest @@ -1794,14 +1799,14 @@ def _coerce_map_from_(self, S): :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P_x_ZZ = agg.GrowthGroup('ZZ^x') - sage: P_x_QQ = agg.GrowthGroup('QQ^x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P_x_ZZ = GrowthGroup('ZZ^x') + sage: P_x_QQ = GrowthGroup('QQ^x') sage: P_x_ZZ.has_coerce_map_from(P_x_QQ) # indirect doctest False sage: P_x_QQ.has_coerce_map_from(P_x_ZZ) # indirect doctest True - sage: P_y_ZZ = agg.GrowthGroup('ZZ^y') + sage: P_y_ZZ = GrowthGroup('ZZ^y') sage: P_y_ZZ.has_coerce_map_from(P_x_ZZ) # indirect doctest False sage: P_x_ZZ.has_coerce_map_from(P_y_ZZ) # indirect doctest @@ -1813,7 +1818,7 @@ def _coerce_map_from_(self, S): :: - sage: agg.GrowthGroup('x^QQ').has_coerce_map_from(agg.GrowthGroup('QQ^x')) + sage: GrowthGroup('x^QQ').has_coerce_map_from(GrowthGroup('QQ^x')) False """ if isinstance(S, type(self)) and self._var_ == S._var_: @@ -1880,14 +1885,16 @@ def gens_monomial(self): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GenericGrowthGroup(ZZ).gens_monomial() + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: GenericGrowthGroup(ZZ).gens_monomial() () - TESTS:: + :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GrowthGroup('ZZ^x').gens_monomial() + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^QQ').gens_monomial() + (x,) + sage: GrowthGroup('QQ^x').gens_monomial() () """ return tuple() @@ -1908,11 +1915,11 @@ def gens(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: P.gens() (x,) - sage: agg.MonomialGrowthGroup(ZZ, 'log(x)').gens() + sage: GrowthGroup('log(x)^ZZ').gens() (log(x),) """ return (self(raw_element=self.base().one()),) @@ -1932,15 +1939,14 @@ def gen(self, n=0): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: P.gen() x :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('QQ^x') + sage: P = GrowthGroup('QQ^x') sage: P.gen() Traceback (most recent call last): ... @@ -1963,17 +1969,16 @@ def ngens(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: P.ngens() 1 - sage: agg.MonomialGrowthGroup(ZZ, 'log(x)').ngens() + sage: GrowthGroup('log(x)^ZZ').ngens() 1 :: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('QQ^x') + sage: P = GrowthGroup('QQ^x') sage: P.ngens() 0 """ @@ -1990,8 +1995,8 @@ def variable_names(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GenericGrowthGroup(ZZ).variable_names() + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: GenericGrowthGroup(ZZ).variable_names() () :: @@ -2004,7 +2009,6 @@ def variable_names(self): :: - sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: GrowthGroup('QQ^x').variable_names() ('x',) sage: GrowthGroup('QQ^(x*log(x))').variable_names() @@ -2178,8 +2182,8 @@ class MonomialGrowthElement(GenericGrowthElement): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup + sage: P = MonomialGrowthGroup(ZZ, 'x') sage: e1 = P(1); e1 1 sage: e2 = P(raw_element=2); e2 @@ -2199,8 +2203,8 @@ def exponent(self): EXAMPLES: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: P(x^42).exponent 42 """ @@ -2221,8 +2225,8 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^QQ') sage: P(1)._repr_() '1' sage: P(x^5) # indirect doctest @@ -2269,8 +2273,8 @@ def _mul_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: a = P(x^2) sage: b = P(x^3) sage: c = a._mul_(b); c @@ -2297,8 +2301,8 @@ def __invert__(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: e1 = P(raw_element=2) sage: e2 = e1.__invert__(); e2 x^(-2) @@ -2442,9 +2446,9 @@ def _le_(self, other): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P_ZZ = agg.MonomialGrowthGroup(ZZ, 'x') - sage: P_QQ = agg.MonomialGrowthGroup(QQ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P_ZZ = GrowthGroup('x^ZZ') + sage: P_QQ = GrowthGroup('x^QQ') sage: P_ZZ.gen() <= P_QQ.gen()^2 # indirect doctest True """ @@ -2479,10 +2483,10 @@ class MonomialGrowthGroup(GenericGrowthGroup): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x'); P + sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup + sage: P = MonomialGrowthGroup(ZZ, 'x'); P Growth Group x^ZZ - sage: agg.MonomialGrowthGroup(ZZ, log(SR.var('y'))) + sage: MonomialGrowthGroup(ZZ, log(SR.var('y'))) Growth Group log(y)^ZZ .. SEEALSO:: @@ -2508,18 +2512,18 @@ def _repr_short_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.MonomialGrowthGroup(ZZ, 'a') # indirect doctest + sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup + sage: MonomialGrowthGroup(ZZ, 'a') # indirect doctest Growth Group a^ZZ TESTS:: - sage: agg.MonomialGrowthGroup(ZZ, 'a')._repr_short_() + sage: MonomialGrowthGroup(ZZ, 'a')._repr_short_() 'a^ZZ' - sage: agg.MonomialGrowthGroup(QQ, 'a')._repr_short_() + sage: MonomialGrowthGroup(QQ, 'a')._repr_short_() 'a^QQ' - sage: agg.MonomialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() + sage: MonomialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() 'a^QQ[x]' """ from misc import parent_to_repr_short @@ -2542,8 +2546,8 @@ def _convert_(self, data): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^ZZ') sage: P._convert_('icecream') is None True sage: P(1) # indirect doctest @@ -2678,10 +2682,10 @@ def gens_monomial(self): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.MonomialGrowthGroup(ZZ, 'x').gens_monomial() + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('x^ZZ').gens_monomial() (x,) - sage: agg.MonomialGrowthGroup(QQ, 'log(x)').gens_monomial() + sage: GrowthGroup('log(x)^QQ').gens_monomial() () """ if not self._var_.is_monomial(): @@ -2800,8 +2804,8 @@ class ExponentialGrowthElement(GenericGrowthElement): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('ZZ^x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('ZZ^x') sage: e1 = P(1); e1 1 sage: e2 = P(raw_element=2); e2 @@ -2821,8 +2825,8 @@ def base(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('ZZ^x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('ZZ^x') sage: P(42^x).base 42 """ @@ -2843,8 +2847,8 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('QQ^x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('QQ^x') sage: P(1)._repr_() '1' sage: P(5^x) # indirect doctest @@ -2887,8 +2891,8 @@ def _mul_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('ZZ^x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('ZZ^x') sage: a = P(2^x) sage: b = P(3^x) sage: c = a._mul_(b); c @@ -2949,8 +2953,8 @@ def __pow__(self, exponent): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.GrowthGroup('ZZ^x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('ZZ^x') sage: a = P(7^x); a 7^x sage: b = a^(1/2); b @@ -3024,9 +3028,9 @@ def _le_(self, other): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P_ZZ = agg.GrowthGroup('ZZ^x') - sage: P_SR = agg.GrowthGroup('SR^x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P_ZZ = GrowthGroup('ZZ^x') + sage: P_SR = GrowthGroup('SR^x') sage: P_ZZ(2^x) <= P_SR(sqrt(3)^x)^2 # indirect doctest True """ @@ -3062,8 +3066,8 @@ class ExponentialGrowthGroup(GenericGrowthGroup): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.ExponentialGrowthGroup(QQ, 'x'); P + sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup + sage: P = ExponentialGrowthGroup(QQ, 'x'); P Growth Group QQ^x .. SEEALSO:: @@ -3089,16 +3093,16 @@ def _repr_short_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.ExponentialGrowthGroup(QQ, 'a') # indirect doctest + sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup + sage: ExponentialGrowthGroup(QQ, 'a') # indirect doctest Growth Group QQ^a TESTS:: - sage: agg.ExponentialGrowthGroup(QQ, 'a')._repr_short_() + sage: ExponentialGrowthGroup(QQ, 'a')._repr_short_() 'QQ^a' - sage: agg.ExponentialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() + sage: ExponentialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() 'QQ[x]^a' """ from misc import parent_to_repr_short @@ -3121,8 +3125,8 @@ def _convert_(self, data): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.ExponentialGrowthGroup(ZZ, 'x') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('QQ^x') sage: P._convert_('icecream') is None True sage: P(1) # indirect doctest @@ -3139,7 +3143,7 @@ def _convert_(self, data): sage: P(0) # indirect doctest Traceback (most recent call last): ... - ValueError: 0 is not in Growth Group ZZ^x. + ValueError: 0 is not in Growth Group QQ^x. :: @@ -3150,7 +3154,7 @@ def _convert_(self, data): :: - sage: P = agg.GrowthGroup('SR^x') + sage: P = GrowthGroup('SR^x') sage: P(sqrt(3)^x) sqrt(3)^x sage: P((3^(1/3))^x) @@ -3422,8 +3426,8 @@ def create_key_and_extra_args(self, specification, **kwds): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GrowthGroup.create_key_and_extra_args('asdf') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup.create_key_and_extra_args('asdf') Traceback (most recent call last): ... ValueError: 'asdf' is not a valid string describing a growth group. @@ -3446,8 +3450,8 @@ def create_object(self, version, factors, **kwds): TESTS:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: agg.GrowthGroup('as^df') # indirect doctest + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: GrowthGroup('as^df') # indirect doctest Traceback (most recent call last): ... ValueError: 'as^df' is not a valid string describing a growth group. @@ -3455,7 +3459,7 @@ def create_object(self, version, factors, **kwds): >> *previous* SyntaxError: unexpected EOF while parsing (, line 1) > *and* ValueError: Cannot create a parent out of 'df'. >> *previous* NameError: name 'df' is not defined - sage: agg.GrowthGroup('x^y^z') + sage: GrowthGroup('x^y^z') Traceback (most recent call last): ... ValueError: 'x^y^z' is not a valid string describing a growth group. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 716b1819a7a..7117be4cc86 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -232,9 +232,9 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') - sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^QQ') + sage: L = GrowthGroup('log(x)^ZZ') sage: C = cartesian_product([P, L], order='lex'); C Growth Group x^QQ * log(x)^ZZ sage: C.an_element() @@ -242,10 +242,10 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): :: - sage: Px = agg.MonomialGrowthGroup(QQ, 'x') - sage: Lx = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: Px = GrowthGroup('x^QQ') + sage: Lx = GrowthGroup('log(x)^ZZ') sage: Cx = cartesian_product([Px, Lx], order='lex') - sage: Py = agg.MonomialGrowthGroup(QQ, 'y') + sage: Py = GrowthGroup('y^QQ') sage: C = cartesian_product([Cx, Py], order='components'); C Growth Group x^QQ * log(x)^ZZ * y^QQ sage: C.an_element() @@ -488,9 +488,9 @@ def _repr_short_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') - sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^QQ') + sage: L = GrowthGroup('log(x)^ZZ') sage: cartesian_product([P, L], order='lex')._repr_short_() 'x^QQ * log(x)^ZZ' """ @@ -777,8 +777,8 @@ def gens_monomial(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ') sage: G.gens_monomial() (x, y) @@ -833,9 +833,9 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: P = agg.MonomialGrowthGroup(QQ, 'x') - sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: P = GrowthGroup('x^QQ') + sage: L = GrowthGroup('log(x)^ZZ') sage: cartesian_product([P, L], order='lex').an_element()._repr_() 'x^(1/2)*log(x)' """ diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index bade7ec4868..3a4b0eda932 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -36,19 +36,19 @@ def repr_short_to_parent(s): EXAMPLES:: - sage: import sage.rings.asymptotic.misc as agg - sage: agg.repr_short_to_parent('ZZ') + sage: from sage.rings.asymptotic.misc import repr_short_to_parent + sage: repr_short_to_parent('ZZ') Integer Ring - sage: agg.repr_short_to_parent('QQ') + sage: repr_short_to_parent('QQ') Rational Field - sage: agg.repr_short_to_parent('SR') + sage: repr_short_to_parent('SR') Symbolic Ring - sage: agg.repr_short_to_parent('NN') + sage: repr_short_to_parent('NN') Non negative integer semiring TESTS:: - sage: agg.repr_short_to_parent('abcdef') + sage: repr_short_to_parent('abcdef') Traceback (most recent call last): ... ValueError: Cannot create a parent out of 'abcdef'. diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 5d3b556c087..e34bc90d005 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -104,13 +104,12 @@ def absorption(left, right): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: T = atm.TermMonoid('O', G, ZZ) - sage: atm.absorption(T(x^2), T(x^3)) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (TermMonoid, absorption) + sage: T = TermMonoid('O', GrowthGroup('x^ZZ'), ZZ) + sage: absorption(T(x^2), T(x^3)) O(x^3) - sage: atm.absorption(T(x^3), T(x^2)) + sage: absorption(T(x^3), T(x^2)) O(x^3) """ try: @@ -141,13 +140,12 @@ def can_absorb(left, right): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: T = atm.TermMonoid('O', G, ZZ) - sage: atm.can_absorb(T(x^2), T(x^3)) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (TermMonoid, can_absorb) + sage: T = TermMonoid('O', GrowthGroup('x^ZZ'), ZZ) + sage: can_absorb(T(x^2), T(x^3)) True - sage: atm.can_absorb(T(x^3), T(x^2)) + sage: can_absorb(T(x^3), T(x^2)) True """ return left.can_absorb(right) or right.can_absorb(left) @@ -166,10 +164,10 @@ class GenericTerm(sage.structure.element.MonoidElement): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2); (t1, t2) (Generic Term with growth x, Generic Term with growth x^2) sage: t1 * t2 @@ -190,10 +188,10 @@ def __init__(self, parent, growth): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, ZZ) sage: T(x^2) Generic Term with growth x^2 """ @@ -227,10 +225,10 @@ def _mul_(self, other): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, ZZ) sage: t1 = T(x); t2 = T(x^2) sage: t1, t2 (Generic Term with growth x, Generic Term with growth x^2) @@ -262,10 +260,10 @@ def __div__(self, other): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2) sage: t1 / t2 # indirect doctest Traceback (most recent call last): @@ -302,10 +300,10 @@ def _div_(self, other): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2) sage: t1 / t2 # indirect doctest Traceback (most recent call last): @@ -326,10 +324,10 @@ def __invert__(self): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, QQ) sage: ~T(x) # indirect doctest Traceback (most recent call last): ... @@ -475,11 +473,11 @@ def can_absorb(self, other): by which other terms. We start by defining the necessary term monoids and some terms:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(G, ZZ) - sage: ET = atm.ExactTermMonoid(G, coefficient_ring=QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: OT = TermMonoid('O', G, coefficient_ring=ZZ) + sage: ET = TermMonoid('exact', G, coefficient_ring=QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: et1 = ET(x^2, 2) @@ -531,10 +529,10 @@ def _can_absorb_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GenericGrowthGroup(ZZ) - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GenericGrowthGroup(ZZ) + sage: T = GenericTermMonoid(G, QQ) sage: g1 = G(raw_element=21); g2 = G(raw_element=42) sage: t1 = T(g1); t2 = T(g2) sage: t1.can_absorb(t2) # indirect doctest @@ -577,11 +575,11 @@ def absorb(self, other, check=True): of this operation. We start by defining some parents and elements:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_QQ = agg.GrowthGroup('x^QQ'); x = G_QQ.gen() - sage: OT = atm.OTermMonoid(G_QQ, ZZ) - sage: ET = atm.ExactTermMonoid(G_QQ, coefficient_ring=QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G_QQ = GrowthGroup('x^QQ'); x = G_QQ.gen() + sage: OT = TermMonoid('O', G_QQ, coefficient_ring=ZZ) + sage: ET = TermMonoid('exact', G_QQ, coefficient_ring=QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: et1 = ET(x, 100); et2 = ET(x^2, 2) sage: et3 = ET(x^2, 1); et4 = ET(x^2, -2) @@ -682,10 +680,10 @@ def _absorb_(self, other): First, we define some asymptotic terms:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2) When it comes to absorption, note that the method @@ -805,13 +803,13 @@ def __le__(self, other): First, we define some asymptotic terms (and their parents):: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: GT = atm.GenericTermMonoid(G, QQ) - sage: OT = atm.OTermMonoid(G, QQ) - sage: ET_ZZ = atm.ExactTermMonoid(G, ZZ) - sage: ET_QQ = atm.ExactTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, TermMonoid) + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: GT = GenericTermMonoid(G, QQ) + sage: OT = TermMonoid('O', G, QQ) + sage: ET_ZZ = TermMonoid('exact', G, ZZ) + sage: ET_QQ = TermMonoid('exact', G, QQ) sage: g1 = GT(x); g2 = GT(x^2); g1, g2 (Generic Term with growth x, Generic Term with growth x^2) sage: o1 = OT(x^-1); o2 = OT(x^3); o1, o2 @@ -884,10 +882,10 @@ def _le_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, QQ) sage: t1 = T(x^-2); t2 = T(x^5); t1, t2 (Generic Term with growth x^(-2), Generic Term with growth x^5) sage: t1._le_(t2) @@ -1102,10 +1100,10 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, QQ) sage: T(x)._repr_() 'Generic Term with growth x' sage: T(x^7)._repr_() @@ -1144,12 +1142,12 @@ class GenericTermMonoid(sage.structure.unique_representation.UniqueRepresentatio EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_x = agg.GrowthGroup('x^ZZ'); x = G_x.gen() - sage: G_y = agg.GrowthGroup('y^QQ'); y = G_y.gen() - sage: T_x_ZZ = atm.GenericTermMonoid(G_x, QQ) - sage: T_y_QQ = atm.GenericTermMonoid(G_y, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G_x = GrowthGroup('x^ZZ'); x = G_x.gen() + sage: G_y = GrowthGroup('y^QQ'); y = G_y.gen() + sage: T_x_ZZ = GenericTermMonoid(G_x, QQ) + sage: T_y_QQ = GenericTermMonoid(G_y, QQ) sage: T_x_ZZ Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: T_y_QQ @@ -1244,10 +1242,9 @@ def growth_group(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.ExactTermMonoid(G, ZZ).growth_group + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: TermMonoid('exact', GrowthGroup('x^ZZ'), ZZ).growth_group Growth Group x^ZZ """ return self._growth_group_ @@ -1261,10 +1258,9 @@ def coefficient_ring(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.GenericTermMonoid(G, ZZ).coefficient_ring + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: GenericTermMonoid(GrowthGroup('x^ZZ'), ZZ).coefficient_ring Integer Ring """ return self._coefficient_ring_ @@ -1284,13 +1280,11 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GenericGrowthGroup(ZZ) - sage: atm.GenericTermMonoid(G, QQ)._repr_() + sage: from sage.rings.asymptotic.growth_group import (GenericGrowthGroup, GrowthGroup) + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: GenericTermMonoid(GenericGrowthGroup(ZZ), QQ)._repr_() 'Generic Term Monoid Generic(ZZ) with (implicit) coefficients in Rational Field' - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.GenericTermMonoid(G, QQ)._repr_() + sage: GenericTermMonoid(GrowthGroup('x^ZZ'), QQ)._repr_() 'Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field' """ return 'Generic Term Monoid %s with (implicit) coefficients in %s' % \ @@ -1317,27 +1311,23 @@ def _coerce_map_from_(self, S): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.GrowthGroup('x^ZZ') - sage: G_ZZ = agg.GrowthGroup('x^ZZ') - sage: T_ZZ = atm.GenericTermMonoid(G_ZZ, QQ); T_ZZ + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G_ZZ = GrowthGroup('x^ZZ') + sage: T_ZZ = GenericTermMonoid(G_ZZ, QQ); T_ZZ Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field - sage: G_QQ = agg.GrowthGroup('x^QQ') - sage: T_QQ = atm.GenericTermMonoid(G_QQ, QQ); T_QQ + sage: G_QQ = GrowthGroup('x^QQ') + sage: T_QQ = GenericTermMonoid(G_QQ, QQ); T_QQ Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field sage: T_QQ.has_coerce_map_from(T_ZZ) # indirect doctest True :: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.GrowthGroup('x^ZZ') - sage: G_QQ = agg.GrowthGroup('x^QQ') - sage: TC_ZZ = atm.TermWithCoefficientMonoid(G_ZZ, ZZ); TC_ZZ + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: TC_ZZ = TermWithCoefficientMonoid(G_ZZ, ZZ); TC_ZZ Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring - sage: TC_QQ = atm.TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ + sage: TC_QQ = TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field sage: TC_QQ.has_coerce_map_from(TC_ZZ) # indirect doctest True @@ -1368,12 +1358,12 @@ def _element_constructor_(self, data, coefficient=None): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G_ZZ = GrowthGroup('x^ZZ') sage: G_QQ = GrowthGroup('x^QQ') - sage: T_ZZ = atm.GenericTermMonoid(G_ZZ, QQ) - sage: T_QQ = atm.GenericTermMonoid(G_QQ, QQ) + sage: T_ZZ = GenericTermMonoid(G_ZZ, QQ) + sage: T_QQ = GenericTermMonoid(G_QQ, QQ) sage: term1 = T_ZZ(G_ZZ.gen()) sage: term2 = T_QQ(G_QQ.gen()^2) @@ -1406,16 +1396,16 @@ def _element_constructor_(self, data, coefficient=None): :: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ') - sage: T = atm.TermWithCoefficientMonoid(G, ZZ) + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: G = GrowthGroup('x^ZZ') + sage: T = TermWithCoefficientMonoid(G, ZZ) sage: t1 = T(x^2, 5); t1 # indirect doctest Term with coefficient 5 and growth x^2 TESTS:: - sage: O_ZZ = atm.OTermMonoid(G_ZZ, QQ) + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: O_ZZ = TermMonoid('O', G_ZZ, QQ) sage: O_ZZ(x^11) O(x^11) @@ -1435,8 +1425,8 @@ def _element_constructor_(self, data, coefficient=None): :: - sage: G_log = agg.GrowthGroup('log(x)^ZZ') - sage: T_log = atm.TermWithCoefficientMonoid(G_log, ZZ) + sage: G_log = GrowthGroup('log(x)^ZZ') + sage: T_log = TermWithCoefficientMonoid(G_log, ZZ) sage: T_log(log(x)) Term with coefficient 1 and growth log(x) @@ -1485,10 +1475,10 @@ def _create_element_(self, growth, coefficient): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G_ZZ = GrowthGroup('x^ZZ') - sage: T_ZZ = atm.GenericTermMonoid(G_ZZ, QQ) + sage: T_ZZ = GenericTermMonoid(G_ZZ, QQ) sage: T_ZZ(G_ZZ.gen()) # indirect doctest Generic Term with growth x """ @@ -1546,10 +1536,10 @@ def _split_growth_and_coefficient_(self, data): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G_ZZ = GrowthGroup('x^ZZ') - sage: T_ZZ = atm.ExactTermMonoid(G_ZZ, QQ) + sage: T_ZZ = TermMonoid('exact', G_ZZ, QQ) sage: T_ZZ._split_growth_and_coefficient_('2*x^3') (x^3, 2) """ @@ -1597,10 +1587,10 @@ def _get_factors_(self, data): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G_ZZ = GrowthGroup('x^ZZ') - sage: T_ZZ = atm.ExactTermMonoid(G_ZZ, QQ) + sage: T_ZZ = TermMonoid('exact', G_ZZ, QQ) sage: T_ZZ._get_factors_(x^2 * log(x)) (x^2, log(x)) """ @@ -1636,12 +1626,12 @@ def _an_element_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.OTermMonoid(G, QQ).an_element() # indirect doctest + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, TermMonoid) + sage: G = GrowthGroup('x^ZZ') + sage: TermMonoid('O', G, QQ).an_element() # indirect doctest O(x) - sage: atm.GenericTermMonoid(G, QQ).an_element() # indirect doctest + sage: GenericTermMonoid(G, QQ).an_element() # indirect doctest Generic Term with growth x """ return self(self.growth_group.an_element()) @@ -1663,10 +1653,10 @@ def some_elements(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: tuple(atm.OTermMonoid(G, QQ).some_elements()) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ') + sage: tuple(TermMonoid('O', G, QQ).some_elements()) (O(1), O(x), O(x^(-1)), O(x^2), O(x^(-2)), O(x^3), ...) """ return iter(self(g) for g in self.growth_group.some_elements()) @@ -1689,10 +1679,10 @@ def le(self, left, right): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.GenericTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = GenericTermMonoid(G, QQ) sage: t1 = T(x); t2 = T(x^2) sage: T.le(t1, t2) True @@ -1716,10 +1706,10 @@ class OTerm(GenericTerm): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import OTermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: OT = OTermMonoid(G, QQ) sage: t1 = OT(x^-7); t2 = OT(x^5); t3 = OT(x^42) sage: t1, t2, t3 (O(x^(-7)), O(x^5), O(x^42)) @@ -1757,10 +1747,10 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: OT = TermMonoid('O', G, QQ) sage: t1 = OT(x); t2 = OT(x^2); t3 = OT(x^3) sage: t1._repr_(), t2._repr_() ('O(x)', 'O(x^2)') @@ -1780,10 +1770,10 @@ def __invert__(self): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.OTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = TermMonoid('O', G, QQ) sage: ~T(x) # indirect doctest Traceback (most recent call last): ... @@ -1838,9 +1828,9 @@ def _can_absorb_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: OT = atm.TermMonoid('O', agg.GrowthGroup('x^ZZ'), QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: OT = TermMonoid('O', GrowthGroup('x^ZZ'), QQ) sage: t1 = OT(x^21); t2 = OT(x^42) sage: t1.can_absorb(t2) # indirect doctest False @@ -1874,10 +1864,10 @@ def _absorb_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: OT = TermMonoid('O', G, QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: ot1.absorb(ot1) O(x) @@ -2053,21 +2043,22 @@ class OTermMonoid(GenericTermMonoid): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_x_ZZ = agg.GrowthGroup('x^ZZ') - sage: G_y_QQ = agg.GrowthGroup('y^QQ') - sage: OT_x_ZZ = atm.OTermMonoid(G_x_ZZ, QQ); OT_x_ZZ + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import OTermMonoid + sage: G_x_ZZ = GrowthGroup('x^ZZ') + sage: G_y_QQ = GrowthGroup('y^QQ') + sage: OT_x_ZZ = OTermMonoid(G_x_ZZ, QQ); OT_x_ZZ O-Term Monoid x^ZZ with implicit coefficients in Rational Field - sage: OT_y_QQ = atm.OTermMonoid(G_y_QQ, QQ); OT_y_QQ + sage: OT_y_QQ = OTermMonoid(G_y_QQ, QQ); OT_y_QQ O-Term Monoid y^QQ with implicit coefficients in Rational Field `O`-term monoids can also be created by using the :class:`term factory `:: - sage: atm.TermMonoid('O', G_x_ZZ, QQ) is OT_x_ZZ + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: TermMonoid('O', G_x_ZZ, QQ) is OT_x_ZZ True - sage: atm.TermMonoid('O', agg.GrowthGroup('x^QQ'), QQ) + sage: TermMonoid('O', GrowthGroup('x^QQ'), QQ) O-Term Monoid x^QQ with implicit coefficients in Rational Field """ @@ -2092,10 +2083,10 @@ def _create_element_(self, growth, coefficient): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G_ZZ = GrowthGroup('x^ZZ') - sage: T_ZZ = atm.OTermMonoid(G_ZZ, QQ) + sage: T_ZZ = TermMonoid('O', G_ZZ, QQ) sage: T_ZZ(G_ZZ.gen()) # indirect doctest O(x) """ @@ -2137,13 +2128,13 @@ def _coerce_map_from_(self, S): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() - sage: G_QQ = agg.GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() - sage: OT_ZZ = atm.OTermMonoid(G_ZZ, QQ) - sage: OT_QQ = atm.OTermMonoid(G_QQ, QQ) - sage: ET = atm.ExactTermMonoid(G_ZZ, ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G_ZZ = GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() + sage: G_QQ = GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() + sage: OT_ZZ = TermMonoid('O', G_ZZ, QQ) + sage: OT_QQ = TermMonoid('O', G_QQ, QQ) + sage: ET = TermMonoid('exact', G_ZZ, ZZ) Now, the :class:`OTermMonoid` whose growth group is over the interger ring has to coerce into the :class:`OTermMonoid` with @@ -2179,10 +2170,10 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: atm.OTermMonoid(G, QQ)._repr_() + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: TermMonoid('O', G, QQ)._repr_() 'O-Term Monoid x^ZZ with implicit coefficients in Rational Field' """ return 'O-Term Monoid %s with implicit coefficients in %s' % \ @@ -2205,11 +2196,11 @@ class TermWithCoefficient(GenericTerm): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: CT_ZZ = atm.TermWithCoefficientMonoid(G, ZZ) - sage: CT_QQ = atm.TermWithCoefficientMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: CT_ZZ = TermWithCoefficientMonoid(G, ZZ) + sage: CT_QQ = TermWithCoefficientMonoid(G, QQ) sage: CT_ZZ(x^2, 5) Term with coefficient 5 and growth x^2 sage: CT_QQ(x^3, 3/8) @@ -2224,11 +2215,11 @@ def __init__(self, parent, growth, coefficient): First, we define some monoids:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: CT_ZZ = atm.TermWithCoefficientMonoid(G, ZZ) - sage: CT_QQ = atm.TermWithCoefficientMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: CT_ZZ = TermWithCoefficientMonoid(G, ZZ) + sage: CT_QQ = TermWithCoefficientMonoid(G, QQ) The coefficients have to be from the given coefficient ring:: @@ -2283,10 +2274,10 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.TermWithCoefficientMonoid(G, ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = TermWithCoefficientMonoid(G, ZZ) sage: T(x^2, 5)._repr_() 'Term with coefficient 5 and growth x^2' """ @@ -2315,11 +2306,11 @@ def _mul_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: CT = atm.TermWithCoefficientMonoid(G, ZZ) - sage: ET = atm.ExactTermMonoid(G, ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (TermWithCoefficientMonoid, TermMonoid) + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: CT = TermWithCoefficientMonoid(G, ZZ) + sage: ET = TermMonoid('exact', G, ZZ) This method handles the multiplication of abstract terms with coefficient (i.e. :class:`TermWithCoefficient`) and @@ -2432,10 +2423,10 @@ def _le_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: ET = atm.ExactTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: ET = TermMonoid('exact', G, QQ) sage: t1 = ET(x, 5); t2 = ET(x^2, 3); t3 = ET(x^2, 42) sage: t1 <= t2 True @@ -2518,13 +2509,13 @@ class TermWithCoefficientMonoid(GenericTermMonoid): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() - sage: G_QQ = agg.GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() - sage: TC_ZZ = atm.TermWithCoefficientMonoid(G_ZZ, QQ); TC_ZZ + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid + sage: G_ZZ = GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() + sage: G_QQ = GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() + sage: TC_ZZ = TermWithCoefficientMonoid(G_ZZ, QQ); TC_ZZ Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field - sage: TC_QQ = atm.TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ + sage: TC_QQ = TermWithCoefficientMonoid(G_QQ, QQ); TC_QQ Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field sage: TC_ZZ == TC_QQ or TC_ZZ is TC_QQ False @@ -2554,10 +2545,10 @@ def _create_element_(self, growth, coefficient): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm + sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G_ZZ = GrowthGroup('x^ZZ') - sage: T_ZZ = atm.ExactTermMonoid(G_ZZ, QQ) + sage: T_ZZ = TermMonoid('exact', G_ZZ, QQ) sage: T_ZZ(G_ZZ.gen(), 4/3) # indirect doctest 4/3*x """ @@ -2578,14 +2569,14 @@ def _an_element_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.TermWithCoefficientMonoid(G, ZZ).an_element() # indirect doctest + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (TermWithCoefficientMonoid, TermMonoid) + sage: G = GrowthGroup('x^ZZ') + sage: TermWithCoefficientMonoid(G, ZZ).an_element() # indirect doctest Term with coefficient 1 and growth x - sage: atm.ExactTermMonoid(G, ZZ).an_element() # indirect doctest + sage: TermMonoid('exact', G, ZZ).an_element() # indirect doctest x - sage: atm.ExactTermMonoid(G, QQ).an_element() # indirect doctest + sage: TermMonoid('exact', G, QQ).an_element() # indirect doctest 1/2*x """ return self(self.growth_group.an_element(), @@ -2609,10 +2600,10 @@ def some_elements(self): EXAMPLES:: sage: from itertools import islice - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('z^QQ') - sage: T = atm.ExactTermMonoid(G, ZZ) + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('z^QQ') + sage: T = TermMonoid('exact', G, ZZ) sage: tuple(islice(T.some_elements(), 10)) (z^(1/2), -z^(1/2), z^(-1/2), 2*z^(1/2), -z^(-1/2), z^2, -2*z^(1/2), 2*z^(-1/2), -z^2, z^(-2)) @@ -2641,10 +2632,10 @@ class ExactTerm(TermWithCoefficient): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: ET = atm.ExactTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import (ExactTermMonoid, TermMonoid) + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: ET = ExactTermMonoid(G, QQ) Asymptotic exact terms may be multiplied (with the usual rules applying):: @@ -2656,7 +2647,7 @@ class ExactTerm(TermWithCoefficient): They may also be multiplied with `O`-terms:: - sage: OT = atm.OTermMonoid(G, QQ) + sage: OT = TermMonoid('O', G, QQ) sage: ET(x^2, 42) * OT(x) O(x^3) @@ -2703,10 +2694,10 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: ET = atm.ExactTermMonoid(G, ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: ET = TermMonoid('exact', G, ZZ) sage: et1 = ET(x^2, 2); et1 2*x^2 @@ -2741,10 +2732,10 @@ def __invert__(self): TESTS:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: T = atm.ExactTermMonoid(G, ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: T = TermMonoid('exact', G, ZZ) sage: ~T(x, 2) # indirect doctest 1/2*x^(-1) sage: (~T(x, 2)).parent() @@ -2806,9 +2797,9 @@ def _can_absorb_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: ET = atm.TermMonoid('exact', agg.GrowthGroup('x^ZZ'), ZZ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: ET = TermMonoid('exact', GrowthGroup('x^ZZ'), ZZ) sage: t1 = ET(x^21, 1); t2 = ET(x^21, 2); t3 = ET(x^42, 1) sage: t1.can_absorb(t2) # indirect doctest True @@ -2840,10 +2831,10 @@ def _absorb_(self, other): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: ET = atm.ExactTermMonoid(G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: ET = TermMonoid('exact', G, QQ) Asymptotic exact terms can absorb other asymptotic exact terms with the same growth:: @@ -3064,13 +3055,13 @@ class ExactTermMonoid(TermWithCoefficientMonoid): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G_ZZ = agg.GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() - sage: G_QQ = agg.GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() - sage: ET_ZZ = atm.ExactTermMonoid(G_ZZ, ZZ); ET_ZZ + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import ExactTermMonoid + sage: G_ZZ = GrowthGroup('x^ZZ'); x_ZZ = G_ZZ.gen() + sage: G_QQ = GrowthGroup('x^QQ'); x_QQ = G_QQ.gen() + sage: ET_ZZ = ExactTermMonoid(G_ZZ, ZZ); ET_ZZ Exact Term Monoid x^ZZ with coefficients in Integer Ring - sage: ET_QQ = atm.ExactTermMonoid(G_QQ, QQ); ET_QQ + sage: ET_QQ = ExactTermMonoid(G_QQ, QQ); ET_QQ Exact Term Monoid x^QQ with coefficients in Rational Field sage: ET_QQ.coerce_map_from(ET_ZZ) Conversion map: @@ -3079,9 +3070,10 @@ class ExactTermMonoid(TermWithCoefficientMonoid): Exact term monoids can also be created using the term factory:: - sage: atm.TermMonoid('exact', G_ZZ, ZZ) is ET_ZZ + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: TermMonoid('exact', G_ZZ, ZZ) is ET_ZZ True - sage: atm.TermMonoid('exact', agg.GrowthGroup('x^ZZ'), QQ) + sage: TermMonoid('exact', GrowthGroup('x^ZZ'), QQ) Exact Term Monoid x^ZZ with coefficients in Rational Field """ @@ -3103,10 +3095,10 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: atm.ExactTermMonoid(G, QQ)._repr_() + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: TermMonoid('exact', G, QQ)._repr_() 'Exact Term Monoid x^ZZ with coefficients in Rational Field' """ return 'Exact Term Monoid %s with coefficients in %s' % \ @@ -3206,16 +3198,16 @@ def create_key_and_extra_args(self, term, EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.TermMonoid.create_key_and_extra_args('O', G, QQ) + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ') + sage: TermMonoid.create_key_and_extra_args('O', G, QQ) ((, Growth Group x^ZZ, Rational Field), {}) - sage: atm.TermMonoid.create_key_and_extra_args('exact', G, ZZ) + sage: TermMonoid.create_key_and_extra_args('exact', G, ZZ) ((, Growth Group x^ZZ, Integer Ring), {}) - sage: atm.TermMonoid.create_key_and_extra_args('exact', G) + sage: TermMonoid.create_key_and_extra_args('exact', G) Traceback (most recent call last): ... ValueError: A coefficient ring has to be specified @@ -3260,12 +3252,12 @@ def create_object(self, version, key, **kwds): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: import sage.rings.asymptotic.term_monoid as atm - sage: G = agg.GrowthGroup('x^ZZ') - sage: atm.TermMonoid('O', G, QQ) # indirect doctest + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ') + sage: TermMonoid('O', G, QQ) # indirect doctest O-Term Monoid x^ZZ with implicit coefficients in Rational Field - sage: atm.TermMonoid('exact', G, ZZ) # indirect doctest + sage: TermMonoid('exact', G, ZZ) # indirect doctest Exact Term Monoid x^ZZ with coefficients in Integer Ring """ term_class, growth_group, coefficient_ring = key From cc8bf18a4feea1cfab4f42f30fc31415b1485836 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 16:00:36 +0200 Subject: [PATCH 0775/1872] fix broken links in documentation --- src/sage/rings/asymptotic/term_monoid.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index e34bc90d005..d9acbe8e85b 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -348,7 +348,8 @@ def __pow__(self, exponent): OUTPUT: - Raise a :class:`NotImplementedError` since it is an abstract base class. + Raise a :python:`NotImplementedError` + since it is an abstract base class. TESTS:: @@ -721,8 +722,9 @@ def log_term(self, base=None): .. NOTE:: This abstract method raises a - :class:`NotImplementedError`. See :class:`ExactTerm` and - :class:`OTerm` for a concrete implementation. + :python:`NotImplementedError`. + See :class:`ExactTerm` and :class:`OTerm` for a concrete + implementation. EXAMPLES:: From efb9d67c75f42ed6b07fe1d86ed84c3300e72a63 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 16:59:28 +0200 Subject: [PATCH 0776/1872] fix z^(...) bug --- src/sage/rings/asymptotic/asymptotic_ring.py | 15 +++++++++++++-- src/sage/rings/asymptotic/term_monoid.py | 6 +++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 33d565e79d4..8e51528821b 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1175,6 +1175,13 @@ def __pow__(self, exponent, precision=None): ... ZeroDivisionError: Cannot take O(x) to exponent -1. > *previous* FloatingPointError: Floating point exception. + + :: + + sage: B. = AsymptoticRing(growth_group='z^QQ * log(z)^QQ', coefficient_ring=QQ, default_prec=5) + sage: z^(1+1/z) + z + log(z) + 1/2*z^(-1)*log(z)^2 + 1/6*z^(-2)*log(z)^3 + + 1/24*z^(-3)*log(z)^4 + O(z^(-4)*log(z)^5) """ if not self.summands: if exponent == 0: @@ -1192,8 +1199,12 @@ def __pow__(self, exponent, precision=None): element = next(self.summands.elements()) if isinstance(exponent, AsymptoticExpression) and element.is_constant(): return exponent.rpow(base=element.coefficient, precision=precision) - return self.parent()._create_element_via_parent_( - element ** exponent, element.parent()) + try: + return self.parent()._create_element_via_parent_( + element ** exponent, element.parent()) + except (ArithmeticError, TypeError, ValueError): + if not isinstance(exponent, AsymptoticExpression): + raise from sage.rings.integer_ring import ZZ try: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index d9acbe8e85b..1e31bec9771 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2363,9 +2363,9 @@ def _calculate_pow_(self, exponent): except (TypeError, ValueError, ZeroDivisionError) as e: from misc import combine_exceptions raise combine_exceptions( - ZeroDivisionError('Cannot take %s to the exponent %s since its ' - 'coefficient %s cannot be taken to this exponent.' % - (self, exponent, self.coefficient)), e) + ArithmeticError('Cannot take %s to the exponent %s in %s since its ' + 'coefficient %s cannot be taken to this exponent.' % + (self, exponent, self.parent(), self.coefficient)), e) return super(TermWithCoefficient, self)._calculate_pow_(exponent, coefficient=c) From 4110613fee65f49f2adddc4fdcb3d3ebad0ca69d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 2 Sep 2015 16:59:43 +0200 Subject: [PATCH 0777/1872] examples on exp, pow --- src/sage/rings/asymptotic/asymptotic_ring.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 8e51528821b..ab9b0a0cec8 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -212,9 +212,16 @@ as `z \to \infty`. -.. TODO:: +Similarly, we can apply the exponential function of an asymptotic expression:: + + sage: exp(1/z) + 1 + z^(-1) + 1/2*z^(-2) + 1/6*z^(-3) + 1/24*z^(-4) + ... + O(z^(-20)) + +Arbitrary powers work as well; for example, we have +:: - write more here + sage: (1 + 1/z + O(1/z^5))^(1 + 1/z) + 1 + z^(-1) + z^(-2) + 1/2*z^(-3) + 1/3*z^(-4) + O(z^(-5)) Multivariate Arithemtic From ecb16e648cdff2cb22bc88c7fd01f114af8006a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Thu, 3 Sep 2015 09:51:28 +0300 Subject: [PATCH 0778/1872] Added tests to is_chain_of_poset(). --- src/sage/combinat/posets/posets.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 9b7cef63f84..3d30d681191 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -113,7 +113,7 @@ :widths: 30, 70 :delim: | - :meth:`~FinitePoset.is_chain_of_poset` | Return ``True`` if given iterable is a chain of the poset. + :meth:`~FinitePoset.is_chain_of_poset` | Return ``True`` if given list is a chain of the poset. :meth:`~FinitePoset.chains` | Return the chains of the poset. :meth:`~FinitePoset.antichains` | Return the antichains of the poset. :meth:`~FinitePoset.maximal_chains` | Return the maximal chains of the poset. @@ -2398,8 +2398,8 @@ def is_chain_of_poset(self, elms, ordered=False): INPUT: - - ``elms`` -- an iterable (e. g., list, set, or tuple) - containing some elements of the poset + - ``elms`` -- a list or other iterable containing some elements + of the poset - ``ordered`` -- a Boolean. If ``True``, then return ``True`` only if elements in `elms` are strictly increasing in the poset. If @@ -2423,6 +2423,24 @@ def is_chain_of_poset(self, elms, ordered=False): False sage: P.is_chain_of_poset((1, 3), ordered=True) True + + TESTS:: + + sage: P = Posets.BooleanLattice(4) + sage: P.is_chain_of_poset([]) + True + sage: P.is_chain_of_poset((1,3,7,15,14)) + False + sage: P.is_chain_of_poset({10}) + True + sage: P.is_chain_of_poset({10}, ordered=True) + Traceback (most recent call last): + ... + TypeError: ordered=True not compatible with type for elms + sage: P.is_chain_of_poset([32]) + Traceback (most recent call last): + ... + ValueError: element (=32) not in poset """ if ordered: if not hasattr(elms, '__getitem__'): @@ -3344,8 +3362,9 @@ def width(self): r""" Return the width of the poset (the size of its longest antichain). - It is computed through a matching in a bipartite graph. See - :wikipedia:`Dilworth's_theorem` for more information. + It is computed through a matching in a bipartite graph; see + :wikipedia:`Dilworth's_theorem` for more information. The width is + also called Dilworth number. .. SEEALSO:: From 43d30cee4936432f4f6bbd50ecbf9380fb002eff Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 09:05:54 +0200 Subject: [PATCH 0779/1872] extend split_str_by_op --- src/sage/rings/asymptotic/misc.py | 49 +++++++++++++++++++------------ 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 3a4b0eda932..8a914025399 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -141,14 +141,18 @@ def abbreviate(P): return s -def split_str_by_mul(string): +def split_str_by_op(string, op, strip_parentheses=True): r""" Split the given string into a tuple of substrings arising by splitting by '*' and taking care of parentheses. INPUT: - - ``string`` - a string. + - ``string`` -- a string. + + - ``op`` -- a string. + + - ``strip_parentheses`` -- (default: ``True``) a boolean. OUTPUT: @@ -156,46 +160,53 @@ def split_str_by_mul(string): TESTS:: - sage: from sage.rings.asymptotic.misc import split_str_by_mul - sage: split_str_by_mul('x^ZZ') + sage: from sage.rings.asymptotic.misc import split_str_by_op + sage: split_str_by_op('x^ZZ', '*') ('x^ZZ',) - sage: split_str_by_mul('log(x)^ZZ * y^QQ') + sage: split_str_by_op('log(x)^ZZ * y^QQ', '*') ('log(x)^ZZ', 'y^QQ') - sage: split_str_by_mul('log(x)**ZZ * y**QQ') + sage: split_str_by_op('log(x)**ZZ * y**QQ', '*') ('log(x)**ZZ', 'y**QQ') - sage: split_str_by_mul('a^b * * c^d') + sage: split_str_by_op('a^b * * c^d', '*') Traceback (most recent call last): ... - ValueError: 'a^b * * c^d' is invalid since a '*' follows a '*' - sage: split_str_by_mul('a^b * (c*d^e)') + ValueError: 'a^b * * c^d' is invalid since a '*' follows a '*'. + sage: split_str_by_op('a^b * (c*d^e)', '*') ('a^b', 'c*d^e') + + :: + + sage: split_str_by_op('(a^b)^c', '^') + ('a^b', 'c') + sage: split_str_by_op('a^(b^c)', '^') + ('a', 'b^c') """ factors = list() balanced = True - if string and string[0] == '*': - raise ValueError("'%s' is invalid since it starts with a '*'." % - (string,)) - for s in string.split('*'): + if string and string.startswith(op): + raise ValueError("'%s' is invalid since it starts with a '%s'." % + (string, op)) + for s in string.split(op): if not s: - factors[-1] += '*' + factors[-1] += op balanced = False continue if not s.strip(): - raise ValueError("'%s' is invalid since a '*' follows a '*'" % - (string,)) + raise ValueError("'%s' is invalid since a '%s' follows a '%s'." % + (string, op, op)) if not balanced: - s = factors.pop() + '*' + s + s = factors.pop() + op + s balanced = s.count('(') == s.count(')') factors.append(s) if not balanced: - raise ValueError("Parentheses in '%s' are not balanced" % (string,)) + raise ValueError("Parentheses in '%s' are not balanced." % (string,)) def strip(s): s = s.strip() if not s: return s - if s[0] == '(' and s[-1] == ')': + if strip_parentheses and s[0] == '(' and s[-1] == ')': s = s[1:-1] return s.strip() From dcd342b4e4ff9323a338c884799b3257f2e702da Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 09:07:13 +0200 Subject: [PATCH 0780/1872] adapt code; improve error messages --- src/sage/rings/asymptotic/growth_group.py | 53 +++++++++++++------ .../asymptotic/growth_group_cartesian.py | 4 +- src/sage/rings/asymptotic/term_monoid.py | 4 +- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cf32d8d1cc8..07fd47d5181 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3444,16 +3444,16 @@ def create_key_and_extra_args(self, specification, **kwds): sage: GrowthGroup.create_key_and_extra_args('asdf') Traceback (most recent call last): ... - ValueError: 'asdf' is not a valid string describing a growth group. + ValueError: 'asdf' is not a valid substring of 'asdf' describing a growth group. """ - from misc import split_str_by_mul - factors = split_str_by_mul(specification) + from misc import split_str_by_op + factors = split_str_by_op(specification, '*') factors = tuple(f.replace('**', '^') for f in factors) for f in factors: - if '^' not in f and '**' not in f: - raise ValueError("'%s' is not a valid string describing " - "a growth group." % (f,)) + if '^' not in f: + raise ValueError("'%s' is not a valid substring of '%s' describing " + "a growth group." % (f, specification)) return factors, kwds @@ -3468,7 +3468,8 @@ def create_object(self, version, factors, **kwds): sage: GrowthGroup('as^df') # indirect doctest Traceback (most recent call last): ... - ValueError: 'as^df' is not a valid string describing a growth group. + ValueError: 'as^df' is not a valid substring of as^df + describing a growth group. > *previous* ValueError: Cannot create a parent out of 'as'. >> *previous* SyntaxError: unexpected EOF while parsing (, line 1) > *and* ValueError: Cannot create a parent out of 'df'. @@ -3476,17 +3477,38 @@ def create_object(self, version, factors, **kwds): sage: GrowthGroup('x^y^z') Traceback (most recent call last): ... - ValueError: 'x^y^z' is not a valid string describing a growth group. + ValueError: 'x^y^z' is an ambigous substring of + a growth group description of 'x^y^z'. + Use parentheses to make it unique. + sage: GrowthGroup('(x^y)^z') + Traceback (most recent call last): + ... + ValueError: '(x^y)^z' is not a valid substring of (x^y)^z + describing a growth group. + > *previous* ValueError: Cannot create a parent out of '(x^y)'. + >> *previous* NameError: name 'x' is not defined + > *and* ValueError: Cannot create a parent out of 'z'. + >> *previous* NameError: name 'z' is not defined + sage: GrowthGroup('x^(y^z)') + Traceback (most recent call last): + ... + ValueError: 'x^(y^z)' is not a valid substring of x^(y^z) + describing a growth group. > *previous* ValueError: Cannot create a parent out of 'x'. >> *previous* NameError: name 'x' is not defined - > *and* ValueError: Cannot create a parent out of 'y^z'. + > *and* ValueError: Cannot create a parent out of '(y^z)'. >> *previous* NameError: name 'y' is not defined """ - from misc import repr_short_to_parent + from misc import repr_short_to_parent, split_str_by_op groups = [] for factor in factors: - b, _, e = factor.partition('^') + split = split_str_by_op(factor, '^', strip_parentheses=False) + if len(split) != 2: + raise ValueError("'%s' is an ambigous substring of a growth group " + "description of '%s'. Use parentheses to make it " + "unique." % (factor, ' * '.join(factors))) + b, e = split try: B = repr_short_to_parent(b) except ValueError as exc_b: @@ -3499,15 +3521,16 @@ def create_object(self, version, factors, **kwds): if B is None and E is None: from misc import combine_exceptions raise combine_exceptions( - ValueError("'%s' is not a valid string describing " - "a growth group." % (factor,)), exc_b, exc_e) + ValueError("'%s' is not a valid substring of %s describing " + "a growth group." % (factor, ' * '.join(factors))), + exc_b, exc_e) elif B is None and E is not None: groups.append(MonomialGrowthGroup(E, b, **kwds)) elif B is not None and E is None: groups.append(ExponentialGrowthGroup(B, e, **kwds)) else: - raise ValueError("'%s' is an ambigous string of a growth group " - "description." % (factor,)) + raise ValueError("'%s' is an ambigous substring of a growth group " + "description of '%s'." % (factor, ' * '.join(factors))) if len(groups) == 1: return groups[0] diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index e9366f7fbe9..380420be251 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -442,8 +442,8 @@ def convert_factors(data, raw_data): return self.element_class(self, data) elif isinstance(data, str): - from misc import split_str_by_mul - return convert_factors(split_str_by_mul(data), data) + from misc import split_str_by_op + return convert_factors(split_str_by_op(data, '*'), data) elif hasattr(data, 'parent'): P = data.parent() diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 1e31bec9771..a8e71ff665d 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1597,8 +1597,8 @@ def _get_factors_(self, data): (x^2, log(x)) """ if isinstance(data, str): - from misc import split_str_by_mul - return split_str_by_mul(data) + from misc import split_str_by_op + return split_str_by_op(data, '*') try: P = data.parent() From 5a6c60977c52d5c055fec9586ec0601949b18d5a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 09:07:33 +0200 Subject: [PATCH 0781/1872] ignore variables in Variable class --- src/sage/rings/asymptotic/growth_group.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 07fd47d5181..8d6d26da9a9 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -251,6 +251,8 @@ class Variable(sage.structure.unique_representation.CachedRepresentation, will be displayed instead of ``var``. Use this to get e.g. ``log(x)^ZZ``: ``var`` is then used to specify the variable `x`. + - ``ignore`` -- (default: ``None``) a tuple (or other iterable) + of strings which are not variables. TESTS:: @@ -292,8 +294,13 @@ class Variable(sage.structure.unique_representation.CachedRepresentation, sage: v = Variable('x', repr='log(x)'); repr(v), v.variable_names() ('log(x)', ('x',)) + + :: + + sage: v = Variable('e^x', ignore=('e',)); repr(v), v.variable_names() + ('e^x', ('x',)) """ - def __init__(self, var, repr=None): + def __init__(self, var, repr=None, ignore=None): r""" See :class:`Variable` for details. @@ -311,11 +318,14 @@ def __init__(self, var, repr=None): var = (var,) var = tuple(str(v).strip() for v in var) + if ignore is None: + ignore = tuple() + if repr is None: - var_bases = sum(iter( + var_bases = tuple(i for i in sum(iter( self.extract_variable_names(v) if not isidentifier(v) else (v,) - for v in var), tuple()) + for v in var), tuple()) if i not in ignore) var_repr = ', '.join(var) else: for v in var: From 6d27513c3d1731795392aacc4faeba46791208fd Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 09:08:07 +0200 Subject: [PATCH 0782/1872] move code is_lt_one --- src/sage/rings/asymptotic/growth_group.py | 49 ++++++++++++----------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 8d6d26da9a9..0e3461994eb 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -212,30 +212,6 @@ lazy_import('sage.rings.asymptotic.growth_group_cartesian', 'CartesianProductGrowthGroups') -def is_lt_one(self): - r""" - Return if this element is less than `1`. - - INPUT: - - Nothing. - - OUTPUT: - - A boolean. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G = GrowthGroup('x^ZZ'); x = G(x) - sage: (x^42).is_lt_one() - False - sage: (x^(-42)).is_lt_one() - True - """ - one = self.parent().one() - return self <= one and self != one - class Variable(sage.structure.unique_representation.CachedRepresentation, sage.structure.sage_object.SageObject): r""" @@ -574,6 +550,31 @@ def strip(s): return tuple(vars) +def is_lt_one(self): + r""" + Return if this element is less than `1`. + + INPUT: + + Nothing. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ'); x = G(x) + sage: (x^42).is_lt_one() + False + sage: (x^(-42)).is_lt_one() + True + """ + one = self.parent().one() + return self <= one and self != one + + def log(self, base=None): r""" Return the logarithm of this element. From e4f26bc1b07586e37bc903f2288b92927575c7ed Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 09:32:38 +0200 Subject: [PATCH 0783/1872] ignore_variables in growth groups --- src/sage/rings/asymptotic/growth_group.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 0e3461994eb..50c1b4b2322 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1301,6 +1301,10 @@ class GenericGrowthGroup( Category of groups and Category of posets``. This is also the default category if ``None`` is specified. + - ``ignore_variables`` -- (default: ``None``) a tuple (or other + iterable) of strings. The specified names are not considered as + a variable. + .. NOTE:: This class should be derived to get concrete implementations. @@ -1323,7 +1327,7 @@ class GenericGrowthGroup( @staticmethod - def __classcall__(cls, base, var=None, category=None): + def __classcall__(cls, base, var=None, category=None, ignore_variables=None): r""" Normalizes the input in order to ensure a unique representation. @@ -1358,7 +1362,7 @@ def __classcall__(cls, base, var=None, category=None): if var is None: var = Variable('') elif not isinstance(var, Variable): - var = Variable(var) + var = Variable(var, ignore=ignore_variables) if category is None: from sage.categories.monoids import Monoids From ff1c29fc8f552788f1212f3cf12f5ed21b8e222a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 09:33:28 +0200 Subject: [PATCH 0784/1872] adapt growth group factory (ignore_variables) --- src/sage/rings/asymptotic/growth_group.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 50c1b4b2322..d2dd8d79316 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3352,6 +3352,11 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): - ``specification`` -- a string. + - keyword arguments are passed on to the growth group + constructor. If not specified, then the argument + ``ignore_variables=('e',)`` (to ignore ``e`` as a variable name) + is added. + OUTPUT: An asymptotic growth group. @@ -3375,6 +3380,10 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): Growth Group x^ZZ * log(x)^ZZ * y^QQ sage: GrowthGroup('QQ^x * x^ZZ * y^QQ * QQ^z') Growth Group QQ^x * x^ZZ * y^QQ * QQ^z + sage: GrowthGroup('exp(x)^ZZ * x^ZZ') + Growth Group exp(x)^ZZ * x^ZZ + sage: GrowthGroup('(e^x)^ZZ * x^ZZ') + Growth Group (e^x)^ZZ * x^ZZ TESTS:: @@ -3470,6 +3479,8 @@ def create_key_and_extra_args(self, specification, **kwds): raise ValueError("'%s' is not a valid substring of '%s' describing " "a growth group." % (f, specification)) + kwds.setdefault('ignore_variables', ('e',)) + return factors, kwds From 4cc405ce3838dd235c72cda052b88bff05235aa6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 10:42:36 +0200 Subject: [PATCH 0785/1872] write repr_op function --- src/sage/rings/asymptotic/misc.py | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 8a914025399..5a1330790b0 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -213,6 +213,46 @@ def strip(s): return tuple(strip(f) for f in factors) +def repr_op(left, op, right=None): + r""" + Create a string ``left op right`` with + taking care of parentheses in its operands. + + INPUT: + + - ``left`` -- an element. + + - ``op`` -- a string. + + - ``right`` -- an alement. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.misc import repr_op + sage: repr_op('a^b', '^', 'c') + '(a^b)^c' + """ + left = str(left) + right = str(right) if right is not None else '' + + def add_parentheses(s, op): + if op == '^': + signals = ('^', '*', '+', ' ') + else: + return s + if any(sig in s for sig in signals): + return '(%s)' % (s,) + else: + return s + + return add_parentheses(left, op) + op +\ + add_parentheses(right, op) + + def combine_exceptions(e, *f): r""" Helper function which combines the messages of the given exceptions. From 97cb437b052185c0fd9bde9b334757e76cb89d60 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 10:43:50 +0200 Subject: [PATCH 0786/1872] extend log/exp to recognise variables e^x and exp(x) --- src/sage/rings/asymptotic/growth_group.py | 31 +++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index d2dd8d79316..ee0eb5c02e8 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -803,23 +803,23 @@ def rpow(self, base): pass var = str(self) - if '*' in var or '^' in var: - var = '(' + var + ')' if element is None: if base == 'e': from sage.rings.integer_ring import ZZ - base = ZZ[base](base) - E = ExponentialGrowthGroup(base.parent(), var) - element = E(raw_element=base) + M = MonomialGrowthGroup(ZZ, 'e^' + var, ignore_variables=('e',)) + element = M(raw_element=ZZ(1)) + else: + E = ExponentialGrowthGroup(base.parent(), var) + element = E(raw_element=base) try: return self.parent().one() * element except (TypeError, ValueError) as e: - from misc import combine_exceptions + from misc import combine_exceptions, repr_op raise combine_exceptions( - ArithmeticError('Cannot construct %s^%s in %s' % - (base, var, self.parent())), e) + ArithmeticError('Cannot construct %s in %s' % + (repr_op(base, '^', var), self.parent())), e) class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): @@ -2404,6 +2404,21 @@ def _log_factor_(self, base=None): if self.is_one(): return tuple() coefficient = self.exponent + + var = str(self.parent()._var_) + + from misc import split_str_by_op + split = split_str_by_op(var, '^') + if len(split) == 2: + b, e = split + if base is None and b == 'e' or \ + base is not None and b == str(base): + return ((e, coefficient),) + + if var.startswith('exp('): + assert(var[-1] == ')') + return ((var[4:-1], coefficient),) + if base is not None: from sage.functions.log import log coefficient = coefficient / log(base) From 9f881b08e7135ce9379a1a99463dd016dd401ee6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 3 Sep 2015 10:45:46 +0200 Subject: [PATCH 0787/1872] adapt repr of %s^%s and fix doctests --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 +-- src/sage/rings/asymptotic/growth_group.py | 38 +++++++++---------- .../asymptotic/growth_group_cartesian.py | 11 +----- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index ab9b0a0cec8..12071ad40ec 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1526,11 +1526,11 @@ def exp(self, precision=None): EXAMPLES:: - sage: A. = AsymptoticRing('SR^x * x^ZZ * log(x)^ZZ', SR) + sage: A. = AsymptoticRing('(e^x)^ZZ * x^ZZ * log(x)^ZZ', SR) sage: exp(x) e^x sage: exp(2*x) - (e^2)^x + (e^x)^2 sage: exp(x + log(x)) e^x*x @@ -1541,7 +1541,7 @@ def exp(self, precision=None): TESTS:: - sage: A. = AsymptoticRing('SR^x * x^QQ * log(x)^QQ', SR) + sage: A. = AsymptoticRing('(e^x)^ZZ * x^QQ * log(x)^QQ', SR) sage: exp(log(x)) x sage: log(exp(x)) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ee0eb5c02e8..c67943c5119 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -636,7 +636,7 @@ def log(self, base=None): TESTS:: - sage: G = GrowthGroup("QQ['e']^x * x^ZZ") + sage: G = GrowthGroup("(e^x)^QQ * x^ZZ") sage: x, = G.gens_monomial() sage: log(exp(x)) x @@ -644,11 +644,11 @@ def log(self, base=None): Traceback (most recent call last): ... ArithmeticError: log(1) is zero, which is not contained in - Growth Group QQ[e]^x * x^ZZ. + Growth Group (e^x)^QQ * x^ZZ. :: - sage: G = GrowthGroup("SR^x * x^ZZ") + sage: G = GrowthGroup("(e^x)^ZZ * x^ZZ") sage: x, = G.gens_monomial() sage: log(exp(x)) x @@ -656,7 +656,7 @@ def log(self, base=None): Traceback (most recent call last): ... ArithmeticError: log(1) is zero, which is not contained in - Growth Group SR^x * x^ZZ. + Growth Group (e^x)^ZZ * x^ZZ. """ log_factor = self.log_factor(base=base) if not log_factor: @@ -728,11 +728,7 @@ def log_factor(self, base=None): TESTS:: - sage: G = GrowthGroup("QQ['e']^x * x^ZZ * log(x)^ZZ") - sage: x, = G.gens_monomial() - sage: (exp(x) * x).log_factor() - ((x, 1), (log(x), 1)) - sage: G = GrowthGroup("SR^x * x^ZZ * log(x)^ZZ") + sage: G = GrowthGroup("(e^x)^ZZ * x^ZZ * log(x)^ZZ") sage: x, = G.gens_monomial() sage: (exp(x) * x).log_factor() ((x, 1), (log(x), 1)) @@ -2271,6 +2267,7 @@ def _repr_(self): x^(-42) """ from sage.rings.integer_ring import ZZ + from misc import repr_op var = repr(self.parent()._var_) if self.exponent.is_zero(): @@ -2278,9 +2275,9 @@ def _repr_(self): elif self.exponent.is_one(): return var elif self.exponent in ZZ and self.exponent > 0: - return var + '^' + str(self.exponent) + return repr_op(var, '^') + str(self.exponent) else: - return var + '^(' + str(self.exponent) + ')' + return repr_op(var, '^') + '(' + str(self.exponent) + ')' def _mul_(self, other): @@ -2570,8 +2567,8 @@ def _repr_short_(self): sage: MonomialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() 'a^QQ[x]' """ - from misc import parent_to_repr_short - return '%s^%s' % (self._var_, parent_to_repr_short(self.base())) + from misc import parent_to_repr_short, repr_op + return repr_op(self._var_, '^', parent_to_repr_short(self.base())) def _convert_(self, data): @@ -2906,14 +2903,15 @@ def _repr_(self): (-1)^x """ from sage.rings.integer_ring import ZZ + from misc import repr_op var = repr(self.parent()._var_) if self.base.is_one(): return '1' elif not any(s in str(self.base) for s in '-/^'): - return str(self.base) + '^' + var + return str(self.base) + repr_op('', '^', var) else: - return '(' + str(self.base) + ')^' + var + return '(' + str(self.base) + ')' + repr_op('', '^', var) def _mul_(self, other): @@ -3149,8 +3147,8 @@ def _repr_short_(self): sage: ExponentialGrowthGroup(PolynomialRing(QQ, 'x'), 'a')._repr_short_() 'QQ[x]^a' """ - from misc import parent_to_repr_short - return '%s^%s' % (parent_to_repr_short(self.base()), self._var_) + from misc import parent_to_repr_short, repr_op + return repr_op(parent_to_repr_short(self.base()), '^', self._var_) def _convert_(self, data): @@ -3526,7 +3524,7 @@ def create_object(self, version, factors, **kwds): ... ValueError: '(x^y)^z' is not a valid substring of (x^y)^z describing a growth group. - > *previous* ValueError: Cannot create a parent out of '(x^y)'. + > *previous* ValueError: Cannot create a parent out of 'x^y'. >> *previous* NameError: name 'x' is not defined > *and* ValueError: Cannot create a parent out of 'z'. >> *previous* NameError: name 'z' is not defined @@ -3537,13 +3535,13 @@ def create_object(self, version, factors, **kwds): describing a growth group. > *previous* ValueError: Cannot create a parent out of 'x'. >> *previous* NameError: name 'x' is not defined - > *and* ValueError: Cannot create a parent out of '(y^z)'. + > *and* ValueError: Cannot create a parent out of 'y^z'. >> *previous* NameError: name 'y' is not defined """ from misc import repr_short_to_parent, split_str_by_op groups = [] for factor in factors: - split = split_str_by_op(factor, '^', strip_parentheses=False) + split = split_str_by_op(factor, '^') if len(split) != 2: raise ValueError("'%s' is an ambigous substring of a growth group " "description of '%s'. Use parentheses to make it " diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 380420be251..bb99b404b43 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1049,23 +1049,16 @@ def exp(self): Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ > *previous* TypeError: unsupported operand parent(s) for '*': 'Growth Group x^ZZ * log(x)^ZZ * log(log(x))^ZZ' and - 'Growth Group ZZ[e]^x' + 'Growth Group (e^x)^ZZ' TESTS:: - sage: E = GrowthGroup("QQ['e']^y * y^QQ * log(y)^QQ") + sage: E = GrowthGroup("(e^y)^QQ * y^QQ * log(y)^QQ") sage: y = E('y') sage: log(exp(y)) y sage: exp(log(y)) y - sage: E = GrowthGroup("SR^y * y^QQ * log(y)^QQ") - sage: y = E('y') - sage: log(exp(y)) - y - sage: exp(log(y)) - y - """ return self.rpow('e') From 93f35e5dd1f134f072a84f8d08971207d64d8023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Thu, 3 Sep 2015 14:05:33 +0300 Subject: [PATCH 0788/1872] Removed a (failing) test of 'elms' being ordered. --- src/sage/combinat/posets/posets.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 3d30d681191..bb31700320e 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -113,7 +113,7 @@ :widths: 30, 70 :delim: | - :meth:`~FinitePoset.is_chain_of_poset` | Return ``True`` if given list is a chain of the poset. + :meth:`~FinitePoset.is_chain_of_poset` | Return ``True`` if the given list is a chain of the poset. :meth:`~FinitePoset.chains` | Return the chains of the poset. :meth:`~FinitePoset.antichains` | Return the antichains of the poset. :meth:`~FinitePoset.maximal_chains` | Return the maximal chains of the poset. @@ -2402,8 +2402,9 @@ def is_chain_of_poset(self, elms, ordered=False): of the poset - ``ordered`` -- a Boolean. If ``True``, then return ``True`` - only if elements in `elms` are strictly increasing in the poset. If - ``False`` (the default), then elements can be repeated and be in any + only if elements in `elms` are strictly increasing in the + poset; this makes no sense if `elms` is a set. If ``False`` + (the default), then elements can be repeated and be in any order. EXAMPLES:: @@ -2433,18 +2434,12 @@ def is_chain_of_poset(self, elms, ordered=False): False sage: P.is_chain_of_poset({10}) True - sage: P.is_chain_of_poset({10}, ordered=True) - Traceback (most recent call last): - ... - TypeError: ordered=True not compatible with type for elms sage: P.is_chain_of_poset([32]) Traceback (most recent call last): ... ValueError: element (=32) not in poset """ if ordered: - if not hasattr(elms, '__getitem__'): - raise TypeError("ordered=True not compatible with type %s for elms" % type(elms)) sorted_o = elms return all(self.lt(a, b) for a, b in zip(sorted_o, sorted_o[1:])) else: From 10a8690efc7144000009f2ce053346346ab7e5a2 Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Sat, 31 Jan 2015 22:26:12 +0100 Subject: [PATCH 0789/1872] Add KeyConvertingDict and use it for the result of variety(). --- .../polynomial/multi_polynomial_ideal.py | 27 +- src/sage/structure/converting_dict.py | 286 ++++++++++++++++++ 2 files changed, 308 insertions(+), 5 deletions(-) create mode 100644 src/sage/structure/converting_dict.py diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 273a7cfe490..5d394abaf8c 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2204,7 +2204,6 @@ def variety(self, ring=None): This is due to precision error, which causes the computation of an intermediate Groebner basis to fail. - If the ground field's characteristic is too large for Singular, we resort to a toy implementation:: @@ -2216,6 +2215,22 @@ def variety(self, ring=None): verbose 0 (...: multi_polynomial_ideal.py, variety) Warning: falling back to very slow toy implementation. [{y: 0, x: 0}] + The dictionary expressing the variety will be indexed by generators + of the polynomial ring after changing to the target field. + But the mapping will also accept generators of the original ring, + or even generator names as strings, when provided as keys:: + + sage: K. = QQ[] + sage: I = ideal([x^2+2*y-5,x+y+3]) + sage: v = I.variety(AA)[0]; v + {x: 4.464101615137755?, y: -7.464101615137755?} + sage: v.keys()[0].parent() + Multivariate Polynomial Ring in x, y over Algebraic Real Field + sage: v[x] + 4.464101615137755? + sage: v["y"] + -7.464101615137755? + TESTS:: sage: K. = GF(27) @@ -2352,15 +2367,16 @@ def _variety(T, V, v=None): else: raise TypeError("Local/unknown orderings not supported by 'toy_buchberger' implementation.") + from sage.structure.converting_dict import KeyConvertingDict V = [] for t in T: Vbar = _variety([P(f) for f in t], []) #Vbar = _variety(list(t.gens()),[]) for v in Vbar: - V.append(dict([(P(var),val) for var,val in v.iteritems()])) + V.append(KeyConvertingDict(P, v)) V.sort() - return Sequence(V) + return V @require_field def hilbert_polynomial(self): @@ -4398,8 +4414,9 @@ def weil_restriction(self): Ring in x0, x1, x2, x3, x4, y0, y1, y2, y3, y4, z0, z1, z2, z3, z4 over Finite Field of size 3 sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal - sage: J.variety() - [{y1: 0, y4: 0, x4: 0, y2: 0, y3: 0, y0: 0, x2: 0, z4: 0, z3: 0, z2: 0, x1: 0, z1: 0, z0: 0, x0: 1, x3: 0}] + sage: from sage.doctest.fixtures import reproducible_repr + sage: print(reproducible_repr(J.variety())) + [{x0: 1, x1: 0, x2: 0, x3: 0, x4: 0, y0: 0, y1: 0, y2: 0, y3: 0, y4: 0, z0: 0, z1: 0, z2: 0, z3: 0, z4: 0}] Weil restrictions are often used to study elliptic curves over diff --git a/src/sage/structure/converting_dict.py b/src/sage/structure/converting_dict.py new file mode 100644 index 00000000000..7c5cb447604 --- /dev/null +++ b/src/sage/structure/converting_dict.py @@ -0,0 +1,286 @@ +r""" +Converting Dictionary + +At the moment, the only class contained in this model is a key +converting dictionary, which applies some function (e.g. type +conversion function) to all arguments used as keys. + +.. It is conceivable that a other dicts might be added later on. + +AUTHORS: + +- Martin von Gagern (2015-01-31): initial version + +EXAMPLES: + +A `KeyConvertingDict` will apply a conversion function to all method +arguments which are keys:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d["3"] = 42 + sage: d.items() + [(3, 42)] + +This is used e.g. in the result of a variety, to allow access to the +result no matter how a generator is identified:: + + sage: K. = QQ[] + sage: I = ideal([x^2+2*y-5,x+y+3]) + sage: v = I.variety(AA)[0]; v + {x: 4.464101615137755?, y: -7.464101615137755?} + sage: v.keys()[0].parent() + Multivariate Polynomial Ring in x, y over Algebraic Real Field + sage: v[x] + 4.464101615137755? + sage: v["y"] + -7.464101615137755? +""" + +#***************************************************************************** +# Copyright (C) 2015 Martin von Gagern +# +# 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/ +#***************************************************************************** + +import collections + +class KeyConvertingDict(dict): + r""" + A dictionary which automatically applys a conversions to its keys. + + The most common application is the case where the conversion + function is the object representing some category, so that key + conversion means a type conversion to adapt keys to that + category. This allows different representations for keys which in + turn makes accessing the correct element easier. + + INPUT: + + - ``key_conversion_function`` -- a function which will be + applied to all method arguments which represent keys. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d["3"] = 42 + sage: d.items() + [(3, 42)] + sage: d[5.0] = 64 + sage: d["05"] + 64 + + """ + + def __init__(self, key_conversion_function, *args, **kwargs): + r""" + Construct a dictionary with a given conversion function. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d["3"] = 42 + sage: d.items() + [(3, 42)] + """ + self.key_conversion_function = key_conversion_function + if args or kwargs: + self.update(*args, **kwargs) + + def __getitem__(self, key): + r""" + Retrieve an element from the dictionary. + + INPUT: + + - ``key`` -- A value identifying the element, will be converted. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d[3] = 42 + sage: d["3"] + 42 + """ + key = self.key_conversion_function(key) + return super(KeyConvertingDict, self).__getitem__(key) + + def __setitem__(self, key, value): + r""" + Assign an element in the dictionary. + + INPUT: + + - ``key`` -- A value identifying the element, will be converted. + - ``value`` -- The associated value, will be left unmodified. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d["3"] = 42 + sage: d.items() + [(3, 42)] + """ + key = self.key_conversion_function(key) + return super(KeyConvertingDict, self).__setitem__(key, value) + + def __delitem__(self, key): + r""" + Remove a mapping from the dictionary. + + INPUT: + + - ``key`` -- A value identifying the element, will be converted. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d[3] = 42 + sage: del d["3"] + sage: len(d) + 0 + """ + key = self.key_conversion_function(key) + return super(KeyConvertingDict, self).__delitem__(key) + + def __contains__(self, key): + r""" + Test whether a given key is contained in the mapping. + + INPUT: + + - ``key`` -- A value identifying the element, will be converted. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d[3] = 42 + sage: "3" in d + True + sage: 4 in d + False + """ + key = self.key_conversion_function(key) + return super(KeyConvertingDict, self).__contains__(key) + + def has_key(self, key): + r""" + Deprecated; present just for the sake of compatibility. + Use ``key in self`` instead. + + INPUT: + + - ``key`` -- A value identifying the element, will be converted. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d[3] = 42 + sage: d.has_key("3") + True + sage: d.has_key(4) + False + """ + return key in self + + _no_default_provided = object() + + def pop(self, key, default=_no_default_provided): + r""" + Remove and retreive a given element from the dictionary + + INPUT: + + - ``key`` -- A value identifying the element, will be converted. + - ``default`` -- The value to return if the element is not mapped. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d[3] = 42 + sage: d.pop("3") + 42 + sage: d.pop("3", 33) + 33 + sage: d.pop("3") + Traceback (most recent call last): + ... + KeyError: ... + """ + key = self.key_conversion_function(key) + if default is self._no_default_provided: + return super(KeyConvertingDict, self).pop(key) + else: + return super(KeyConvertingDict, self).pop(key, default) + + def setdefault(self, key, default=None): + r""" + Create a given mapping unless there already exists a mapping + for that key. + + INPUT: + + - ``key`` -- A value identifying the element, will be converted. + - ``default`` -- The value to associate with the key. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d.setdefault("3") + sage: d.items() + [(3, None)] + """ + key = self.key_conversion_function(key) + return super(KeyConvertingDict, self).setdefault(key, default) + + def update(self, *args, **kwds): + r""" + Update the dictionary with key-value pairs from another dictionary, + sequence of key-value pairs, or keyword arguments. + + INPUT: + + - ``key`` -- A value identifying the element, will be converted. + - ``args`` -- A single dict or sequence of pairs. + - ``kwds`` -- Named elements require that the conversion + function accept strings. + + EXAMPLES:: + + sage: from sage.structure.converting_dict import KeyConvertingDict + sage: d = KeyConvertingDict(int) + sage: d.update([("3",1),(4,2)]) + sage: d[3] + 1 + sage: d = KeyConvertingDict(QQ['x']) + sage: d.update(x=42) + sage: d + {x: 42} + """ + f = self.key_conversion_function + u = super(KeyConvertingDict, self).update + if args: + if len(args) != 1: + raise TypeError("update expected at most 1 argument") + arg = args[0] + if isinstance(arg, collections.Mapping): + seq = ((f(k), arg[k]) for k in arg) + else: + seq = ((f(k), v) for k, v in arg) + u(seq) + if kwds: + seq = ((f(k), v) for k, v in kwds.iteritems()) + u(seq) From 7b9a8042bd8a7ad5feb26684bec81af2085bb5d0 Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Sun, 1 Feb 2015 16:45:04 +0100 Subject: [PATCH 0790/1872] Document KeyConvertingDict constructor data argument. The constructor accepts a second argument to provide data. This needs to be documented. Allowing for keywords arguments to the constructor appears unneccessary, so support for these has been dropped. In the update method, the mapping codepath is now doctested as well. --- src/sage/structure/converting_dict.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/structure/converting_dict.py b/src/sage/structure/converting_dict.py index 7c5cb447604..798568b89c5 100644 --- a/src/sage/structure/converting_dict.py +++ b/src/sage/structure/converting_dict.py @@ -63,6 +63,8 @@ class KeyConvertingDict(dict): - ``key_conversion_function`` -- a function which will be applied to all method arguments which represent keys. + - ``data`` -- optional dictionary or sequence of key-value pairs + to initialize this mapping. EXAMPLES:: @@ -77,7 +79,7 @@ class KeyConvertingDict(dict): """ - def __init__(self, key_conversion_function, *args, **kwargs): + def __init__(self, key_conversion_function, data=None): r""" Construct a dictionary with a given conversion function. @@ -89,9 +91,10 @@ def __init__(self, key_conversion_function, *args, **kwargs): sage: d.items() [(3, 42)] """ + super(KeyConvertingDict, self).__init__() self.key_conversion_function = key_conversion_function - if args or kwargs: - self.update(*args, **kwargs) + if data: + self.update(data) def __getitem__(self, key): r""" @@ -265,6 +268,9 @@ def update(self, *args, **kwds): sage: d.update([("3",1),(4,2)]) sage: d[3] 1 + sage: d.update({"5": 7, "9": 12}) + sage: d[9] + 12 sage: d = KeyConvertingDict(QQ['x']) sage: d.update(x=42) sage: d From a7bc6d010193b86d37e967ad670a369563670161 Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Sun, 8 Feb 2015 16:24:23 +0100 Subject: [PATCH 0791/1872] Move KeyConvertingDict from sage.structure to sage.misc. --- src/doc/en/reference/misc/index.rst | 1 + .../{structure => misc}/converting_dict.py | 22 +++++++++---------- .../polynomial/multi_polynomial_ideal.py | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) rename src/sage/{structure => misc}/converting_dict.py (90%) diff --git a/src/doc/en/reference/misc/index.rst b/src/doc/en/reference/misc/index.rst index 6efcf30199e..638bafba73b 100644 --- a/src/doc/en/reference/misc/index.rst +++ b/src/doc/en/reference/misc/index.rst @@ -49,6 +49,7 @@ Lists and Iteration, etc. :maxdepth: 1 sage/misc/callable_dict + sage/misc/converting_dict sage/misc/flatten sage/misc/search sage/misc/sage_itertools diff --git a/src/sage/structure/converting_dict.py b/src/sage/misc/converting_dict.py similarity index 90% rename from src/sage/structure/converting_dict.py rename to src/sage/misc/converting_dict.py index 798568b89c5..411e67186bb 100644 --- a/src/sage/structure/converting_dict.py +++ b/src/sage/misc/converting_dict.py @@ -16,7 +16,7 @@ A `KeyConvertingDict` will apply a conversion function to all method arguments which are keys:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d["3"] = 42 sage: d.items() @@ -68,7 +68,7 @@ class KeyConvertingDict(dict): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d["3"] = 42 sage: d.items() @@ -85,7 +85,7 @@ def __init__(self, key_conversion_function, data=None): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d["3"] = 42 sage: d.items() @@ -106,7 +106,7 @@ def __getitem__(self, key): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d[3] = 42 sage: d["3"] @@ -126,7 +126,7 @@ def __setitem__(self, key, value): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d["3"] = 42 sage: d.items() @@ -145,7 +145,7 @@ def __delitem__(self, key): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d[3] = 42 sage: del d["3"] @@ -165,7 +165,7 @@ def __contains__(self, key): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d[3] = 42 sage: "3" in d @@ -187,7 +187,7 @@ def has_key(self, key): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d[3] = 42 sage: d.has_key("3") @@ -210,7 +210,7 @@ def pop(self, key, default=_no_default_provided): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d[3] = 42 sage: d.pop("3") @@ -240,7 +240,7 @@ def setdefault(self, key, default=None): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d.setdefault("3") sage: d.items() @@ -263,7 +263,7 @@ def update(self, *args, **kwds): EXAMPLES:: - sage: from sage.structure.converting_dict import KeyConvertingDict + sage: from sage.misc.converting_dict import KeyConvertingDict sage: d = KeyConvertingDict(int) sage: d.update([("3",1),(4,2)]) sage: d[3] diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 5d394abaf8c..f0d73dd9adf 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2367,7 +2367,7 @@ def _variety(T, V, v=None): else: raise TypeError("Local/unknown orderings not supported by 'toy_buchberger' implementation.") - from sage.structure.converting_dict import KeyConvertingDict + from sage.misc.converting_dict import KeyConvertingDict V = [] for t in T: Vbar = _variety([P(f) for f in t], []) From 497d9c0cef4dd817a8806770885894291a8c4811 Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Sun, 8 Feb 2015 18:51:09 +0100 Subject: [PATCH 0792/1872] Fix docstring formatting and add doctest for KeyConvertingDict. --- src/sage/misc/converting_dict.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/converting_dict.py b/src/sage/misc/converting_dict.py index 411e67186bb..1b18f915e0c 100644 --- a/src/sage/misc/converting_dict.py +++ b/src/sage/misc/converting_dict.py @@ -13,7 +13,7 @@ EXAMPLES: -A `KeyConvertingDict` will apply a conversion function to all method +A ``KeyConvertingDict`` will apply a conversion function to all method arguments which are keys:: sage: from sage.misc.converting_dict import KeyConvertingDict @@ -90,6 +90,10 @@ def __init__(self, key_conversion_function, data=None): sage: d["3"] = 42 sage: d.items() [(3, 42)] + sage: KeyConvertingDict(int, {"5": 7}).items() + [(5, 7)] + sage: KeyConvertingDict(int, [("9", 99)]).items() + [(9, 99)] """ super(KeyConvertingDict, self).__init__() self.key_conversion_function = key_conversion_function From f45d0359ad87ec1df1c165554b1274c5050b9b3b Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Sun, 8 Feb 2015 18:52:07 +0100 Subject: [PATCH 0793/1872] Use KeyConvertingDict for BooleanPolynomialIdeal.variety as well. --- src/sage/rings/polynomial/pbori.pyx | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index 4ff7170e1c4..8c5488680a1 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -5110,10 +5110,11 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): A Simple example:: + sage: from sage.doctest.fixtures import reproducible_repr sage: R. = BooleanPolynomialRing() sage: I = ideal( [ x*y*z + x*z + y + 1, x+y+z+1 ] ) - sage: I.variety() - [{z: 0, y: 1, x: 0}, {z: 1, y: 1, x: 1}] + sage: print(reproducible_repr(I.variety())) + [{x: 0, y: 1, z: 0}, {x: 1, y: 1, z: 1}] TESTS: @@ -5130,14 +5131,14 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): x1*x2 + x1*x4 + x1*x5 + x1*x6 + x2*x3 + x2*x4 + x2*x5 + x3*x5 + x5*x6 + x5 + x6, \ x1*x2 + x1*x6 + x2*x4 + x2*x5 + x2*x6 + x3*x6 + x4*x6 + x5*x6 + x5] sage: I = R.ideal( polys ) - sage: I.variety() - [{x6: 0, x5: 0, x4: 0, x3: 0, x2: 0, x1: 0}, - {x6: 1, x5: 0, x4: 0, x3: 1, x2: 1, x1: 1}] + sage: print(reproducible_repr(I.variety())) + [{x1: 0, x2: 0, x3: 0, x4: 0, x5: 0, x6: 0}, {x1: 1, x2: 1, x3: 1, x4: 0, x5: 0, x6: 1}] sage: R = PolynomialRing(GF(2), 6, ['x%d'%(i+1) for i in range(6)], order='lex') sage: I = R.ideal( polys ) - sage: (I + sage.rings.ideal.FieldIdeal(R)).variety() - [{x2: 0, x5: 0, x4: 0, x1: 0, x6: 0, x3: 0}, {x2: 1, x5: 0, x4: 0, x1: 1, x6: 1, x3: 1}] + sage: v = (I + sage.rings.ideal.FieldIdeal(R)).variety() + sage: print(reproducible_repr(v)) + [{x1: 0, x2: 0, x3: 0, x4: 0, x5: 0, x6: 0}, {x1: 1, x2: 1, x3: 1, x4: 0, x5: 0, x6: 1}] Check that :trac:`13976` is fixed:: @@ -5148,13 +5149,21 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): sage: sols[0][y] 1 + Make sure the result is a key converting dict, as discussed in + :trac:`9788` and consistent with + :meth:`sage.rings.polynomial.multi_polynomial_ideal.MPolynomialIdeal_singular_repr.variety`:: + + sage: sols[0]["y"] + 1 + """ + from sage.misc.converting_dict import KeyConvertingDict R_bool = self.ring() R = R_bool.cover_ring() I = R.ideal( [ R( f ) for f in self.groebner_basis() ] ) J = FieldIdeal(R) solutions = (I+J).variety(**kwds) - return [ { R_bool(var):val for var,val in s.iteritems() } for s in solutions ] + return [ KeyConvertingDict(R_bool, s) for s in solutions ] def reduce(self, f): From e68d6eb879f9e5f437cfd9bf82bedf4638d19d4a Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Mon, 20 Apr 2015 09:12:40 +0200 Subject: [PATCH 0794/1872] Unify key domain for PolynomialSequence_gf2.solve Now the key domain is the set of monomials from the appropriate ring. The key conversion function, which is given as a lambda, first converts to the polynomial ring, then takes the leading monomial of the result. This might cause strange results if the provided key is not a bare monomial. Some doctests were made less random by using reproducible_repr. --- .../polynomial/multi_polynomial_sequence.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_sequence.py b/src/sage/rings/polynomial/multi_polynomial_sequence.py index b586b4ea108..ad3d490b71f 100644 --- a/src/sage/rings/polynomial/multi_polynomial_sequence.py +++ b/src/sage/rings/polynomial/multi_polynomial_sequence.py @@ -157,6 +157,7 @@ from sage.misc.cachefunc import cached_method from types import GeneratorType +from sage.misc.converting_dict import KeyConvertingDict from sage.misc.package import is_package_installed from sage.structure.sequence import Sequence, Sequence_generic @@ -1346,10 +1347,12 @@ def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, ver Without argument, a single arbitrary solution is returned:: + sage: from sage.doctest.fixtures import reproducible_repr sage: R. = BooleanPolynomialRing() sage: S = Sequence([x*y+z, y*z+x, x+y+z+1]) - sage: sol = S.solve(); sol # random - [{y: 1, z: 0, x: 0}] + sage: sol = S.solve() + sage: print(reproducible_repr(sol)) + [{x: 0, y: 1, z: 0}] We check that it is actually a solution:: @@ -1358,7 +1361,8 @@ def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, ver We obtain all solutions:: - sage: sols = S.solve(n=Infinity); sols # random + sage: sols = S.solve(n=Infinity) + sage: print(reproducible_repr(sols)) [{x: 0, y: 1, z: 0}, {x: 1, y: 1, z: 1}] sage: map( lambda x: S.subs(x), sols) [[0, 0, 0], [0, 0, 0]] @@ -1366,15 +1370,17 @@ def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, ver We can force the use of exhaustive search if the optional package ``FES`` is present:: - sage: sol = S.solve(algorithm='exhaustive_search'); sol # random, optional - FES + sage: sol = S.solve(algorithm='exhaustive_search') # optional - FES + sage: print(reproducible_repr(sol)) # optional - FES [{x: 1, y: 1, z: 1}] sage: S.subs( sol[0] ) [0, 0, 0] And we may use SAT-solvers if they are available:: - sage: sol = S.solve(algorithm='sat'); sol # random, optional - cryptominisat - [{y: 1, z: 0, x: 0}] + sage: sol = S.solve(algorithm='sat'); sol # optional - cryptominisat + sage: print(reproducible_repr(sol)) # optional - cryptominisat + [{x: 0, y: 1, z: 0}] sage: S.subs( sol[0] ) [0, 0, 0] @@ -1450,15 +1456,19 @@ def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, ver eliminated_variables = { f.lex_lead() for f in reductors } leftover_variables = { x.lm() for x in R_origin.gens() } - solved_variables - eliminated_variables + key_convert = lambda x: R_origin(x).lm() if leftover_variables != set(): partial_solutions = solutions solutions = [] for sol in partial_solutions: for v in VectorSpace( GF(2), len(leftover_variables) ): - new_solution = sol.copy() + new_solution = KeyConvertingDict(key_convert, sol) for var,val in zip(leftover_variables, v): new_solution[ var ] = val solutions.append( new_solution ) + else: + solutions = [ KeyConvertingDict(key_convert, sol) + for sol in solutions ] for r in reductors: for sol in solutions: From 75532137c4acea92ed58014e2239bad563e3a1cb Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Mon, 20 Apr 2015 12:21:19 +0200 Subject: [PATCH 0795/1872] Use reproducible representations in one more doctest --- .../polynomial/multi_polynomial_ideal.py | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index f0d73dd9adf..0ceb0f01523 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2260,27 +2260,28 @@ def variety(self, ring=None): x26^2 + x26, x27^2 + x27, x28^2 + x28, x29^2 + x29, x30^2 + x30]) sage: I.basis_is_groebner() True - sage: for V in I.variety(): print V # long time (6s on sage.math, 2011) - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 0, x4: 0, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 0, x4: 1, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 0, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 1, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 0, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 1, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 1, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 1, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 0, x19: 0, x18: 0, x7: 1, x6: 0, x10: 1, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 1, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 1, x19: 0, x18: 0, x7: 1, x6: 0, x10: 1, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 1, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 0, x4: 0, x19: 0, x18: 1, x7: 1, x6: 0, x10: 1, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 0, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 0, x4: 1, x19: 0, x18: 1, x7: 1, x6: 0, x10: 1, x30: 0, x28: 1, x29: 1, x13: 0, x27: 0, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 0, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 0, x4: 0, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 0, x4: 1, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 0, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 1, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 0, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 1, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 1, x19: 0, x18: 0, x7: 1, x6: 0, x10: 0, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 1, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 0, x19: 0, x18: 0, x7: 1, x6: 0, x10: 1, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 1, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 1, x4: 1, x19: 0, x18: 0, x7: 1, x6: 0, x10: 1, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 1, x25: 1, x9: 0, x8: 0, x20: 0, x17: 1, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 0, x4: 0, x19: 0, x18: 1, x7: 1, x6: 0, x10: 1, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 0, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} - {x14: 0, x24: 0, x16: 1, x1: 1, x3: 1, x2: 0, x5: 0, x4: 1, x19: 0, x18: 1, x7: 1, x6: 0, x10: 1, x30: 0, x28: 1, x29: 1, x13: 0, x27: 1, x11: 0, x25: 1, x9: 0, x8: 0, x20: 0, x17: 0, x23: 0, x26: 0, x15: 0, x21: 1, x12: 0, x22: 0} + sage: from sage.doctest.fixtures import reproducible_repr + sage: for V in I.variety(): print reproducible_repr(V) # long time (6s on sage.math, 2011) + {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 1, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 1, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 1, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 0, x18: 1, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 1, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 0, x18: 1, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 0, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 1, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 1, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 1, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 0, x18: 1, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} + {x1: 1, x10: 1, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 0, x18: 1, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} Check that the issue at :trac:`7425` is fixed:: From 5b572c301640a2b0ef55fff24fd878524ff9358a Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Mon, 20 Apr 2015 12:28:41 +0200 Subject: [PATCH 0796/1872] Present result of one doctest in a more compact way --- .../polynomial/multi_polynomial_ideal.py | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 0ceb0f01523..50667f7a7b8 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2260,28 +2260,27 @@ def variety(self, ring=None): x26^2 + x26, x27^2 + x27, x28^2 + x28, x29^2 + x29, x30^2 + x30]) sage: I.basis_is_groebner() True - sage: from sage.doctest.fixtures import reproducible_repr - sage: for V in I.variety(): print reproducible_repr(V) # long time (6s on sage.math, 2011) - {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 1, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 1, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 1, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 0, x18: 1, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 1, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 0, x18: 1, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 0, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 0, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 1, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 1, x11: 1, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 1, x18: 0, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 1, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 1, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 0, x18: 1, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 0, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} - {x1: 1, x10: 1, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 1, x17: 0, x18: 1, x19: 0, x2: 0, x20: 0, x21: 1, x22: 0, x23: 0, x24: 0, x25: 1, x26: 0, x27: 1, x28: 1, x29: 1, x3: 1, x30: 0, x4: 1, x5: 0, x6: 0, x7: 1, x8: 0, x9: 0} + sage: sorted("".join(str(V[g]) for g in R.gens()) for V in I.variety()) # long time (6s on sage.math, 2011) + ['101000100000000110001000100110', + '101000100000000110001000101110', + '101000100100000101001000100110', + '101000100100000101001000101110', + '101010100000000110001000100110', + '101010100000000110001000101110', + '101010100010000110001000100110', + '101010100010000110001000101110', + '101010100110000110001000100110', + '101010100110000110001000101110', + '101100100000000110001000100110', + '101100100000000110001000101110', + '101100100100000101001000100110', + '101100100100000101001000101110', + '101110100000000110001000100110', + '101110100000000110001000101110', + '101110100010000110001000100110', + '101110100010000110001000101110', + '101110100110000110001000100110', + '101110100110000110001000101110'] Check that the issue at :trac:`7425` is fixed:: From 1c7a0f1221b3abfbd8a742b04c0cacd5afd6c748 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 12:43:02 +0200 Subject: [PATCH 0797/1872] small correction in all.py --- src/sage/rings/all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index aa03245686a..9f77accbb09 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -184,4 +184,4 @@ from sage.rings.contfrac import (CFF, ContinuedFractionField) # asymptotic ring -from asymptotic.all import AsymptoticRing \ No newline at end of file +from asymptotic.all import * From 5aa2a71993c004985dc5e4991faa996e6bef34b0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 12:44:33 +0200 Subject: [PATCH 0798/1872] update copyright --- src/sage/rings/asymptotic/asymptotic_ring.py | 1 + src/sage/rings/asymptotic/misc.py | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 12071ad40ec..6e68615a9a5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -377,6 +377,7 @@ # ***************************************************************************** # Copyright (C) 2015 Benjamin Hackl +# 2015 Daniel Krenn # # 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 diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 5a1330790b0..170f8f5ccaa 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -18,6 +18,16 @@ ============================== """ +#***************************************************************************** +# Copyright (C) 2015 Daniel Krenn +# +# 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/ +#***************************************************************************** + import sage From 03b99cecc6d0fd4fe0d3a375e6596998b03b155d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 12:45:38 +0200 Subject: [PATCH 0799/1872] extend change_parameter to accept strings for growth groups --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 6e68615a9a5..1573ef77521 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1884,6 +1884,9 @@ def change_parameter(self, **kwds): for parameter in parameters: values[parameter] = kwds.get(parameter, getattr(self, parameter)) values['category'] = self.category() + if isinstance(values['growth_group'], str): + from growth_group import GrowthGroup + values['growth_group'] = GrowthGroup(values['growth_group']) if all(values[parameter] is getattr(self, parameter) for parameter in parameters) and values['category'] is self.category(): return self From f54618716d2e055732a2f5cd95ac23fe904a7154 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 12:45:53 +0200 Subject: [PATCH 0800/1872] extend module doc --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 1573ef77521..fe5288ec6e5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -180,7 +180,12 @@ z^(-1) + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21)) Since there is a default precision (parameter ``default_prec``) -defined, only the first `20` summands are calculated. +defined, only the first `20` summands are calculated. However, if we +only want the first `5` exact terms, we cut of the rest by using +:: + + sage: (1 / (z-1)).truncate(5) + z^(-1) + z^(-2) + z^(-3) + z^(-4) + z^(-5) + O(z^(-6)) Of course, we can work with more complicated expressions as well:: From 0e8f05e94d3da4121892505fb21df2188ea8b250 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 12:46:39 +0200 Subject: [PATCH 0801/1872] Variable: fix double variable bug --- src/sage/rings/asymptotic/growth_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c67943c5119..a7ba263c64c 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -544,7 +544,8 @@ def strip(s): # else: a variable if not isidentifier(s): raise ValueError("'%s' is not a valid name for a variable." % (s,)) - vars.append(s) + if s not in vars: + vars.append(s) strip(s) return tuple(vars) From 9bccac1c270985df7b260e0dd293744a97b2624f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 12:51:53 +0200 Subject: [PATCH 0802/1872] rename: asymptotic expression --> asymptotic expansion --- src/sage/rings/asymptotic/asymptotic_ring.py | 194 +++++++++---------- src/sage/rings/asymptotic/term_monoid.py | 4 +- 2 files changed, 99 insertions(+), 99 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index fe5288ec6e5..fa6ac18b9f2 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2,13 +2,13 @@ Asymptotic Ring This module provides a ring (called :class:`AsymptoticRing`) for -computations with asymptotic expressions. +computations with asymptotic expansions. Definition ========== -An asymptotic expression is a sum such as +An asymptotic expansion is a sum such as .. MATH:: @@ -106,7 +106,7 @@ This element consists of two summands: the exact term with coefficient `-1` and growth `z^{3/2}` and the `O`-term `O(z^{1/2})`. Note that the growth of `z^{3/2}` is larger than the growth of `z^{1/2}` as -`z\to\infty`, thus this expression cannot be simplified (which would +`z\to\infty`, thus this expansion cannot be simplified (which would be done automatically, see below). Next, we construct a more sophisticated asymptotic ring in the @@ -154,7 +154,7 @@ sage: (z^(5/2)+z^(1/7)) * z^(-1/5) z^(23/10) + z^(-2/35) -The central concepts of computations with asymptotic expressions is +The central concepts of computations with asymptotic expansions is that the `O`-notation can be used. For example, we have :: @@ -173,7 +173,7 @@ Division ^^^^^^^^ -The asymptotic expressions support division. For example, we get can +The asymptotic expansions support division. For example, we get can expand `1/(1-z)` to a geometric series:: sage: 1 / (z-1) @@ -187,7 +187,7 @@ sage: (1 / (z-1)).truncate(5) z^(-1) + z^(-2) + z^(-3) + z^(-4) + z^(-5) + O(z^(-6)) -Of course, we can work with more complicated expressions as well:: +Of course, we can work with more complicated expansions as well:: sage: (4*z+1) / (z^3+z^2+z+O(A(1))) 4*z^(-2) - 3*z^(-3) - z^(-4) + O(z^(-5)) @@ -217,7 +217,7 @@ as `z \to \infty`. -Similarly, we can apply the exponential function of an asymptotic expression:: +Similarly, we can apply the exponential function of an asymptotic expansion:: sage: exp(1/z) 1 + z^(-1) + 1/2*z^(-2) + 1/6*z^(-3) + 1/24*z^(-4) + ... + O(z^(-20)) @@ -257,7 +257,7 @@ e = \lim_{n\to\infty} \left(1+\frac{1}{n}\right)^n -By using asymptotic expressions, we obtain the more precise result +By using asymptotic expansions, we obtain the more precise result :: sage: E. = AsymptoticRing(growth_group='n^ZZ', coefficient_ring=SR, default_prec=5); E @@ -308,7 +308,7 @@ Not only the coefficient ring can be extended, but the growth group as well. For example, we can add/multiply elements of the asymptotic -rings ``A`` and ``C`` to get an expression of new asymptotic ring:: +rings ``A`` and ``C`` to get an expansion of new asymptotic ring:: sage: r = c*z + c/2 + O(z); r c*z + 1/2*c + O(z) @@ -321,12 +321,12 @@ --------------- The summands of an -:class:`asymptotic expression ` are wrapped +:class:`asymptotic expansion ` are wrapped :doc:`growth group elements `. This wrapping is done by the :doc:`term monoid module `. However, inside an -:class:`asymptotic expression ` these summands +:class:`asymptotic expansion ` these summands (terms) are stored together with their growth-relationship, i.e., each summand knows its direct predecessors and successors. As a data structure a special poset (namely a @@ -393,25 +393,25 @@ import sage -class AsymptoticExpression(sage.structure.element.CommutativeAlgebraElement): +class AsymptoticExpansion(sage.structure.element.CommutativeAlgebraElement): r""" - Class for asymptotic expressions, i.e., the elements of an + Class for asymptotic expansions, i.e., the elements of an :class:`AsymptoticRing`. INPUT: - - ``parent`` -- the parent of the asymptotic expression. + - ``parent`` -- the parent of the asymptotic expansion. - ``summands`` -- the summands as a :class:`~sage.data_structures.mutable_poset.MutablePoset`, which represents the underlying structure. - ``simplify`` -- a boolean (default: ``True``). It controls - automatic simplification (absorption) of the asymptotic expression. + automatic simplification (absorption) of the asymptotic expansion. EXAMPLES: - There are several ways to create asymptotic expressions; usually + There are several ways to create asymptotic expansions; usually this is done by using the corresponding rings/parents:: sage: R_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R_x @@ -419,7 +419,7 @@ class AsymptoticExpression(sage.structure.element.CommutativeAlgebraElement): sage: R_y. = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=ZZ); R_y Asymptotic Ring over Integer Ring - At this point, `x` and `y` are already asymptotic expressions:: + At this point, `x` and `y` are already asymptotic expansions:: sage: type(x) @@ -433,16 +433,16 @@ class AsymptoticExpression(sage.structure.element.CommutativeAlgebraElement): 27*x + 54*x^(2/3) + 36*x^(1/3) + 8 One of the central ideas behind computing with asymptotic - expressions is that the `O`-notation (see + expansions is that the `O`-notation (see :wikipedia:`Big_O_notation`) can be used. For example, we have:: sage: (x+2*x^2+3*x^3+4*x^4) * (O(x)+x^2) 4*x^6 + O(x^5) In particular, :meth:`~sage.rings.big_oh.O` can be used to - construct the asymptotic expressions. With the help of the + construct the asymptotic expansions. With the help of the :meth:`summands`, we can also have a look at the inner structure - of an asymptotic expression:: + of an asymptotic expansion:: sage: expr1 = x + 2*x^2 + 3*x^3 + 4*x^4; expr2 = O(x) + x^2 sage: print(expr1.summands.repr_full()) @@ -511,7 +511,7 @@ class AsymptoticExpression(sage.structure.element.CommutativeAlgebraElement): """ def __init__(self, parent, summands, simplify=True, convert=True): r""" - See :class:`AsymptoticExpression` for more information. + See :class:`AsymptoticExpansion` for more information. TESTS:: @@ -524,7 +524,7 @@ def __init__(self, parent, summands, simplify=True, convert=True): sage: ex1 * ex2 5*x^6 + O(x^5) """ - super(AsymptoticExpression, self).__init__(parent=parent) + super(AsymptoticExpansion, self).__init__(parent=parent) from sage.data_structures.mutable_poset import MutablePoset if not isinstance(summands, MutablePoset): @@ -555,7 +555,7 @@ def convert_terms(element): @property def summands(self): r""" - The summands of this asymptotic expression stored in the + The summands of this asymptotic expansion stored in the underlying data structure (a :class:`~sage.data_structures.mutable_poset.MutablePoset`). @@ -575,7 +575,7 @@ def summands(self): def __nonzero__(self): r""" - Return if this asymptotic expression is not identically zero. + Return if this asymptotic expansion is not identically zero. INPUT: @@ -600,7 +600,7 @@ def __nonzero__(self): def __eq__(self, other): r""" - Return if this asymptotic expression is equal to ``other``. + Return if this asymptotic expansion is equal to ``other``. INPUT: @@ -635,7 +635,7 @@ def __eq__(self, other): def __ne__(self, other): r""" - Return if this asymptotic expression is not equal to ``other``. + Return if this asymptotic expansion is not equal to ``other``. INPUT: @@ -668,12 +668,12 @@ def __ne__(self, other): def has_same_summands(self, other): r""" - Return if this asymptotic expression and ``other`` have the + Return if this asymptotic expansion and ``other`` have the same summands. INPUT: - - ``other`` -- an asymptotic expression. + - ``other`` -- an asymptotic expansion. OUTPUT: @@ -682,11 +682,11 @@ def has_same_summands(self, other): .. NOTE:: While for example ``O(x) == O(x)`` yields ``False``, - these expressions *do* have the same summands and this method + these expansions *do* have the same summands and this method returns ``True``. Moreover, this method uses the coercion model in order to - find a common parent for this asymptotic expression and + find a common parent for this asymptotic expansion and ``other``. EXAMPLES:: @@ -717,12 +717,12 @@ def has_same_summands(self, other): def _has_same_summands_(self, other): r""" - Return, if this :class:`AsymptoticExpression` has the same + Return, if this :class:`AsymptoticExpansion` has the same summands as ``other``. INPUT: - - ``other`` -- an :class:`AsymptoticExpression`. + - ``other`` -- an :class:`AsymptoticExpansion`. OUTPUT: @@ -730,7 +730,7 @@ def _has_same_summands_(self, other): .. NOTE:: - This method compares two :class:`AsymptoticExpression` + This method compares two :class:`AsymptoticExpansion` with the same parent. EXAMPLES:: @@ -751,7 +751,7 @@ def _has_same_summands_(self, other): def _simplify_(self): r""" - Simplify this asymptotic expression. + Simplify this asymptotic expansion. INPUT: @@ -759,17 +759,17 @@ def _simplify_(self): OUTPUT: - Nothing, but modifies this asymptotic expression. + Nothing, but modifies this asymptotic expansion. .. NOTE:: This method is usually called during initialization of - this asymptotic expression. + this asymptotic expansion. .. NOTE:: - This asymptotic expression is simplified by letting - `O`-terms that are included in this expression absorb all + This asymptotic expansion is simplified by letting + `O`-terms that are included in this expansion absorb all terms with smaller growth. TESTS:: @@ -792,7 +792,7 @@ def _simplify_(self): def _repr_(self): r""" - A representation string for this asymptotic expression. + A representation string for this asymptotic expansion. INPUT: @@ -820,15 +820,15 @@ def _repr_(self): def _add_(self, other): r""" - Add ``other`` to this asymptotic expression. + Add ``other`` to this asymptotic expansion. INPUT: - - ``other`` -- an :class:`AsymptoticExpression`. + - ``other`` -- an :class:`AsymptoticExpansion`. OUTPUT: - The sum as an :class:`AsymptoticExpression`. + The sum as an :class:`AsymptoticExpansion`. EXAMPLES:: @@ -839,7 +839,7 @@ def _add_(self, other): sage: expr1 + expr2 # indirect doctest x^321 + x^123 - If an `O`-term is added to an asymptotic expression, then + If an `O`-term is added to an asymptotic expansion, then the `O`-term absorbs everything it can:: sage: x^123 + x^321 + O(x^555) # indirect doctest @@ -858,19 +858,19 @@ def _add_(self, other): def _sub_(self, other): r""" - Subtract ``other`` from this asymptotic expression. + Subtract ``other`` from this asymptotic expansion. INPUT: - - ``other`` -- an :class:`AsymptoticExpression`. + - ``other`` -- an :class:`AsymptoticExpansion`. OUTPUT: - The difference as an :class:`AsymptoticExpression`. + The difference as an :class:`AsymptoticExpansion`. .. NOTE:: - Subtraction of two asymptotic expressions is implemented + Subtraction of two asymptotic expansions is implemented by means of addition: `e_1 - e_2 = e_1 + (-1)\cdot e_2`. EXAMPLES:: @@ -887,7 +887,7 @@ def _sub_(self, other): def _mul_term_(self, term): r""" - Helper method: multiply this asymptotic expression with the + Helper method: multiply this asymptotic expansion with the asymptotic term ``term``. INPUT: @@ -897,7 +897,7 @@ def _mul_term_(self, term): OUTPUT: - The product as an :class:`AsymptoticExpression`. + The product as an :class:`AsymptoticExpansion`. TESTS:: @@ -917,15 +917,15 @@ def _mul_term_(self, term): def _mul_(self, other): r""" - Multiply this asymptotic expression by another asymptotic expression ``other``. + Multiply this asymptotic expansion by another asymptotic expansion ``other``. INPUT: - - ``other`` -- an :class:`AsymptoticExpression`. + - ``other`` -- an :class:`AsymptoticExpansion`. OUTPUT: - The product as an :class:`AsymptoticExpression`. + The product as an :class:`AsymptoticExpansion`. EXAMPLES:: @@ -949,7 +949,7 @@ def _mul_(self, other): def _rmul_(self, other): r""" - Multiply this asymptotic expression by an element ``other`` of its + Multiply this asymptotic expansion by an element ``other`` of its coefficient ring. INPUT: @@ -958,7 +958,7 @@ def _rmul_(self, other): OUTPUT: - An :class:`AsymptoticExpression`. + An :class:`AsymptoticExpansion`. TESTS:: @@ -984,11 +984,11 @@ def _div_(self, other): INPUT: - - ``other`` -- an asymptotic expression. + - ``other`` -- an asymptotic expansion. OUTPUT: - An asymptotic expression. + An asymptotic expansion. EXAMPLES:: @@ -1017,7 +1017,7 @@ def __invert__(self, precision=None): OUTPUT: - An asymptotic expression. + An asymptotic expansion. .. WARNING:: @@ -1057,7 +1057,7 @@ def __invert__(self, precision=None): max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: - raise ValueError('Expression %s cannot be inverted since there ' + raise ValueError('Expansion %s cannot be inverted since there ' 'are several maximal elements %s.' % (self, ', '.join(str(e) for e in max_elem))) max_elem = max_elem[0] @@ -1087,7 +1087,7 @@ def __invert__(self, precision=None): def truncate(self, precision=None): r""" - Truncate this asymptotic expression. + Truncate this asymptotic expansion. INPUT: @@ -1097,12 +1097,12 @@ def truncate(self, precision=None): OUTPUT: - An asymptotic expression. + An asymptotic expansion. .. NOTE:: - For example, truncating an asymptotic expression with - ``precision=20`` does not yield an expression with exactly 20 + For example, truncating an asymptotic expansion with + ``precision=20`` does not yield an expansion with exactly 20 summands! Rather than that, it keeps the 20 summands with the largest growth, and adds appropriate `O`-Terms. @@ -1140,7 +1140,7 @@ def convert_terms(element): def __pow__(self, exponent, precision=None): r""" - Calculate the power of this asymptotic expression to the given ``exponent``. + Calculate the power of this asymptotic expansion to the given ``exponent``. INPUT: @@ -1152,7 +1152,7 @@ def __pow__(self, exponent, precision=None): OUTPUT: - An asymptotic expression. + An asymptotic expansion. TESTS:: @@ -1210,13 +1210,13 @@ def __pow__(self, exponent, precision=None): elif len(self.summands) == 1: element = next(self.summands.elements()) - if isinstance(exponent, AsymptoticExpression) and element.is_constant(): + if isinstance(exponent, AsymptoticExpansion) and element.is_constant(): return exponent.rpow(base=element.coefficient, precision=precision) try: return self.parent()._create_element_via_parent_( element ** exponent, element.parent()) except (ArithmeticError, TypeError, ValueError): - if not isinstance(exponent, AsymptoticExpression): + if not isinstance(exponent, AsymptoticExpansion): raise from sage.rings.integer_ring import ZZ @@ -1225,7 +1225,7 @@ def __pow__(self, exponent, precision=None): except (TypeError, ValueError): pass else: - return super(AsymptoticExpression, self).__pow__(exponent) + return super(AsymptoticExpansion, self).__pow__(exponent) try: return (exponent * self.log(precision=precision)).exp(precision=precision) @@ -1240,7 +1240,7 @@ def __pow__(self, exponent, precision=None): def O(self): r""" - Convert all terms in this asymptotic expression to `O`-terms. + Convert all terms in this asymptotic expansion to `O`-terms. INPUT: @@ -1248,7 +1248,7 @@ def O(self): OUTPUT: - An asymptotic expression. + An asymptotic expansion. EXAMPLES:: @@ -1275,7 +1275,7 @@ def O(self): def log(self, base=None, precision=None): r""" - The logarithm of this asymptotic expression. + The logarithm of this asymptotic expansion. INPUT: @@ -1288,17 +1288,17 @@ def log(self, base=None, precision=None): OUTPUT: - An asymptotic expression. + An asymptotic expansion. .. NOTE:: - Computing the logarithm of an asymptotic expression + Computing the logarithm of an asymptotic expansion is possible if and only if there is exactly one maximal - summand in the expression. + summand in the expansion. ALGORITHM: - If the expression has more than one summand, + If the expansion has more than one summand, the asymptotic expansion for `\log(1+t)` as `t` tends to `0` is used. @@ -1372,7 +1372,7 @@ def log(self, base=None, precision=None): def is_little_o_of_one(self): r""" - Return if this expression is of order `o(1)`. + Return if this expansion is of order `o(1)`. INPUT: @@ -1409,7 +1409,7 @@ def is_little_o_of_one(self): def rpow(self, base, precision=None): r""" - Return the power of ``base`` to this asymptotic expression. + Return the power of ``base`` to this asymptotic expansion. INPUT: @@ -1421,20 +1421,20 @@ def rpow(self, base, precision=None): OUTPUT: - An asymptotic expression. + An asymptotic expansion. ALGORITHM: The strategy for computing the exponential function is as follows: - - This asymptotic expression is split into a part that + - This asymptotic expansion is split into a part that is in `o(1)` and the rest. - The part that is in `o(1)` is expanded according to the series expansion of `\exp(t)` for `t \to 0`. - - The remaining part of the expression is taken exactly. + - The remaining part of the expansion is taken exactly. In particular, this means that the respective growth elements have to be constructed. @@ -1444,7 +1444,7 @@ def rpow(self, base, precision=None): sage: (1/x).rpow('e', precision=5) 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + 1/24*x^(-4) + O(x^(-5)) """ - if isinstance(base, AsymptoticExpression): + if isinstance(base, AsymptoticExpansion): return base.__pow__(self, precision=precision) P = self.parent() @@ -1505,7 +1505,7 @@ def rpow(self, base, precision=None): def exp(self, precision=None): r""" - Return the exponential of (i.e., the power of `e` to) this asymptotic expression. + Return the exponential of (i.e., the power of `e` to) this asymptotic expansion. INPUT: @@ -1515,11 +1515,11 @@ def exp(self, precision=None): OUTPUT: - An asymptotic expression. + An asymptotic expansion. .. NOTE:: - The exponential function of this expression can only be + The exponential function of this expansion can only be computed exactly, if the respective growth element can be constructed in the underlying growth group. @@ -1565,7 +1565,7 @@ def exp(self, precision=None): class AsymptoticRing(sage.algebras.algebra.Algebra, sage.structure.unique_representation.UniqueRepresentation): r""" - A ring consisting of :class:`asymptotic expressions `. + A ring consisting of :class:`asymptotic expansions `. INPUT: @@ -1575,7 +1575,7 @@ class AsymptoticRing(sage.algebras.algebra.Algebra, :class:`~sage.rings.asymptotic.growth_group.GrowthGroupFactory`). - ``coefficient_ring`` -- the ring which contains the - coefficients of the expressions. + coefficients of the expansions. - ``default_prec`` -- a positive integer. This is the number of summands that are kept before truncating an infinite series. @@ -1664,7 +1664,7 @@ class AsymptoticRing(sage.algebras.algebra.Algebra, """ # enable the category framework for elements - Element = AsymptoticExpression + Element = AsymptoticExpansion @staticmethod @@ -1841,7 +1841,7 @@ def default_prec(self): This is the parameter used to determine how many summands are kept before truncating an infinite series (which occur - when inverting asymptotic expressions). + when inverting asymptotic expansions). EXAMPLES:: @@ -2043,7 +2043,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): if type(data) == self.element_class and data.parent() == self: return data - if isinstance(data, AsymptoticExpression): + if isinstance(data, AsymptoticExpansion): return self.element_class(self, data.summands, simplify=simplify, convert=convert) @@ -2055,7 +2055,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): if not all(isinstance(elem, GenericTerm) for elem in data): raise TypeError('Not all list entries of %s ' 'are asymptotic terms, so cannot create an ' - 'asymptotic expression in %s.' % (data, self)) + 'asymptotic expansion in %s.' % (data, self)) summands = AsymptoticRing._create_empty_summands_() summands.union_update(data) return self.element_class(self, summands, @@ -2106,7 +2106,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): elif sage.rings.power_series_ring.is_PowerSeriesRing(P): raise NotImplementedError( - 'Cannot convert %s from the %s to an asymptotic expression ' + 'Cannot convert %s from the %s to an asymptotic expansion ' 'in %s, since growths at other points than +oo are not yet ' 'supported.' % (data, P, self)) # Delete lines above as soon as we can deal with growths @@ -2142,7 +2142,7 @@ def _create_exact_summand_(self, data): OUTPUT: - An asymptotic expression. + An asymptotic expansion. TESTS:: @@ -2165,7 +2165,7 @@ def _create_exact_summand_(self, data): pass raise ValueError('Cannot convert %s to an exact summand in an ' - 'asymptotic expression in %s.' % (data, self)) + 'asymptotic expansion in %s.' % (data, self)) def _coerce_map_from_(self, R): @@ -2256,7 +2256,7 @@ def _an_element_(self): OUTPUT: - An :class:`AsymptoticExpression`. + An :class:`AsymptoticExpansion`. EXAMPLES:: @@ -2324,7 +2324,7 @@ def gens(self): OUTPUT: - A tuple of asymptotic expressions. + A tuple of asymptotic expansions. .. NOTE:: @@ -2358,7 +2358,7 @@ def gen(self, n=0): OUTPUT: - An asymptotic expression. + An asymptotic expansion. EXAMPLES:: @@ -2392,7 +2392,7 @@ def ngens(self): def create_summand(self, type, data=None, **kwds): r""" - Create a simple asymptotic expression consisting of a single + Create a simple asymptotic expansion consisting of a single summand. INPUT: @@ -2412,7 +2412,7 @@ def create_summand(self, type, data=None, **kwds): OUTPUT: - An asymptotic expression. + An asymptotic expansion. .. NOTE:: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index a8e71ff665d..9fab9ee9a70 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -90,7 +90,7 @@ def absorption(left, right): r""" Helper method used by - :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpression`. + :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpansion`. INPUT: @@ -121,7 +121,7 @@ def absorption(left, right): def can_absorb(left, right): r""" Helper method used by - :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpression`. + :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpansion`. INPUT: From 54f2386f8d6c14331fa57c509ba81e5bb00dfa97 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 13:12:10 +0200 Subject: [PATCH 0803/1872] rewrite module-doc: definition --- src/sage/rings/asymptotic/asymptotic_ring.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index fa6ac18b9f2..6928dd6a881 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2,11 +2,11 @@ Asymptotic Ring This module provides a ring (called :class:`AsymptoticRing`) for -computations with asymptotic expansions. +computations with :wikipedia:`asymptotic expansions `. -Definition -========== +(Informal) Definition +===================== An asymptotic expansion is a sum such as @@ -14,13 +14,17 @@ 5z^3 + 4z^2 + O(z) -or +as `z \to \infty` or .. MATH:: 3x^{42}y^2 + 7x^3y^3 + O(x^2) + O(y) -Its summands are the following: +as `x` and `y` tend to `\infty`. It is a truncated series (after a +finite number of terms), which approximates a function. + +The summands of the asymptotic expansions are partially ordered. In +this module these summands are the following: - Exact terms `c\cdot g` with a coefficient `c` and an element `g` of an growth group (:ref:`see below `). @@ -29,10 +33,11 @@ also called *Bachmann--Landau notation*) for growth group element `g` (:ref:`again see below `). +See :wikipedia:`Asymptotic_expansion` for more details. Further examples of such elements can be found :ref:`here `. -.. _asymptotic_ring_growth: +.. _asymptotic_ring_growth: Growth Elements --------------- From 40a10db0bc6faa1567920a457e47666616221eff Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 1 Sep 2015 23:27:56 +0200 Subject: [PATCH 0804/1872] raise ZeroDivisionError when QQ(0) is taken to a negative power --- src/sage/rings/rational.pyx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index af28104d786..9cb95ee0acb 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -2391,6 +2391,9 @@ cdef class Rational(sage.structure.element.FieldElement): if nn < 0: sig_on() + if mpz_sgn(mpq_numref(x.value)) == 0: + sig_off() + raise ZeroDivisionError('rational division by zero') # mpz_pow_ui(mpq_denref(x.value), mpq_numref(_self.value), (-nn)) # mpz_pow_ui(mpq_numref(x.value), mpq_denref(_self.value), (-nn)) # The above causes segfaults, so swap after instead... From 81c998df223291780b7527193cc0cbc290d77471 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 1 Sep 2015 23:28:49 +0200 Subject: [PATCH 0805/1872] add a doctest for QQ(0)^(-1) --- src/sage/rings/rational.pyx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 9cb95ee0acb..288c86aff40 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -2317,6 +2317,13 @@ cdef class Rational(sage.structure.element.FieldElement): 1/8*8^(4/5) sage: 3^(-3/2) 1/9*sqrt(3) + + TESTS:: + + sage: QQ(0)^(-1) + Traceback (most recent call last): + ... + ZeroDivisionError: rational division by zero """ if dummy is not None: raise ValueError, "__pow__ dummy variable not used" From e2ba02878c049631a9c034ff1bd15b6198e6c201 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 1 Sep 2015 23:35:49 +0200 Subject: [PATCH 0806/1872] _self.value instead of x.value --- src/sage/rings/rational.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 288c86aff40..e7f0a8502e1 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -2398,7 +2398,7 @@ cdef class Rational(sage.structure.element.FieldElement): if nn < 0: sig_on() - if mpz_sgn(mpq_numref(x.value)) == 0: + if mpz_sgn(mpq_numref(_self.value)) == 0: sig_off() raise ZeroDivisionError('rational division by zero') # mpz_pow_ui(mpq_denref(x.value), mpq_numref(_self.value), (-nn)) From dd55f52d12eef9eb38a324f16197151836401c1a Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 2 Sep 2015 09:48:06 +0200 Subject: [PATCH 0807/1872] move comparison before sig_on() --- src/sage/rings/rational.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index e7f0a8502e1..1d1a6891d2e 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -2397,10 +2397,10 @@ cdef class Rational(sage.structure.element.FieldElement): return x if nn < 0: - sig_on() if mpz_sgn(mpq_numref(_self.value)) == 0: - sig_off() raise ZeroDivisionError('rational division by zero') + + sig_on() # mpz_pow_ui(mpq_denref(x.value), mpq_numref(_self.value), (-nn)) # mpz_pow_ui(mpq_numref(x.value), mpq_denref(_self.value), (-nn)) # The above causes segfaults, so swap after instead... From b027f11c5c7b8952d982e115d6cf3be2d8636d49 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 3 Sep 2015 12:47:23 +0200 Subject: [PATCH 0808/1872] rational division --> Rational division --- src/sage/rings/rational.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 1d1a6891d2e..692764f76dd 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -2230,7 +2230,7 @@ cdef class Rational(sage.structure.element.FieldElement): -17/4 """ if self.is_zero(): - raise ZeroDivisionError, "rational division by zero" + raise ZeroDivisionError('Rational division by zero') cdef Rational x x = Rational.__new__(Rational) mpq_inv(x.value, self.value) @@ -2323,7 +2323,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: QQ(0)^(-1) Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero """ if dummy is not None: raise ValueError, "__pow__ dummy variable not used" @@ -2398,7 +2398,7 @@ cdef class Rational(sage.structure.element.FieldElement): if nn < 0: if mpz_sgn(mpq_numref(_self.value)) == 0: - raise ZeroDivisionError('rational division by zero') + raise ZeroDivisionError('Rational division by zero') sig_on() # mpz_pow_ui(mpq_denref(x.value), mpq_numref(_self.value), (-nn)) From 1648aae8c247ff79f836d0783575b3b52bebc0fb Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 3 Sep 2015 12:52:00 +0200 Subject: [PATCH 0809/1872] more rational div.. --> Rational div.. --- src/sage/algebras/quatalg/quaternion_algebra_element.pyx | 4 ++-- src/sage/categories/magmas.py | 2 +- src/sage/libs/singular/polynomial.pyx | 2 +- src/sage/rings/number_field/number_field_element.pyx | 2 +- src/sage/rings/polynomial/multi_polynomial_libsingular.pyx | 2 +- src/sage/rings/polynomial/plural.pyx | 2 +- src/sage/rings/polynomial/polynomial_element.pyx | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index a8d94079714..848aa5a86c7 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -469,7 +469,7 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): sage: 1/Q(0) Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero Note that the quaternion algebra need not be a division algebra, in which case we can get a ZeroDivisionException:: @@ -481,7 +481,7 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): sage: 1/theta Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero The ``universal`` test: diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index 943592b3613..4ad1a436739 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -599,7 +599,7 @@ def __invert__(self): sage: ~C([0,2,2,2]) Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero sage: ~C([2,2,2,2]) Traceback (most recent call last): diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index d1efeb64ee0..c555f6d2040 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -326,7 +326,7 @@ cdef int singular_polynomial_div_coeff(poly** ret, poly *p, poly *q, ring *r) ex sage: x/0 Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero """ if q == NULL: raise ZeroDivisionError diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 6e17e8b1420..2221ff3af2f 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -1953,7 +1953,7 @@ cdef class NumberFieldElement(FieldElement): sage: I/0 # indirect doctest Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero :: diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index afc6c7eb514..823764378fa 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2367,7 +2367,7 @@ cdef class MPolynomial_libsingular(sage.rings.polynomial.multi_polynomial.MPolyn sage: x/0 Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero """ cdef poly *p cdef MPolynomial_libsingular right = right_ringelement diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 5983834ef69..54c75b2d8f2 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -1612,7 +1612,7 @@ cdef class NCPolynomial_plural(RingElement): sage: x/0 Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero """ cdef poly *p cdef bint is_field = left._parent._base.is_field() diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index e132ba1d7fa..53a63fd9ecd 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4397,7 +4397,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f.monic() Traceback (most recent call last): ... - ZeroDivisionError: rational division by zero + ZeroDivisionError: Rational division by zero Notice that the monic version of a polynomial over the integers is defined over the rationals. From c04d8fb4a52c12feadf25831e296fb902637691d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 3 Sep 2015 17:23:44 +0200 Subject: [PATCH 0810/1872] ZeroDivisionError: Rational.. --> rational.. --- .../algebras/quatalg/quaternion_algebra_element.pyx | 4 ++-- src/sage/categories/finite_posets.py | 2 +- src/sage/categories/magmas.py | 2 +- src/sage/libs/singular/polynomial.pyx | 2 +- src/sage/modular/overconvergent/weightspace.py | 2 +- src/sage/repl/interpreter.py | 6 +++--- src/sage/rings/continued_fraction.py | 2 +- src/sage/rings/integer_ring.pyx | 4 ++-- src/sage/rings/number_field/number_field_element.pyx | 2 +- .../rings/polynomial/multi_polynomial_libsingular.pyx | 2 +- src/sage/rings/polynomial/plural.pyx | 2 +- src/sage/rings/polynomial/polynomial_element.pyx | 2 +- src/sage/rings/rational.pyx | 10 +++++----- src/sage/schemes/elliptic_curves/ell_point.py | 2 +- src/sage/structure/proof/proof.py | 2 +- 15 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index 848aa5a86c7..a8d94079714 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -469,7 +469,7 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): sage: 1/Q(0) Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero Note that the quaternion algebra need not be a division algebra, in which case we can get a ZeroDivisionException:: @@ -481,7 +481,7 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): sage: 1/theta Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero The ``universal`` test: diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index c8b5b70576d..c7774d58f82 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -909,7 +909,7 @@ def birational_toggle(self, v, labelling): sage: t1 = V.birational_toggle(1, t) Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero We don't get into zero-division issues in the tropical semiring (unless the zero of the tropical semiring appears diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index 4ad1a436739..943592b3613 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -599,7 +599,7 @@ def __invert__(self): sage: ~C([0,2,2,2]) Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero sage: ~C([2,2,2,2]) Traceback (most recent call last): diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index c555f6d2040..d1efeb64ee0 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -326,7 +326,7 @@ cdef int singular_polynomial_div_coeff(poly** ret, poly *p, poly *q, ring *r) ex sage: x/0 Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero """ if q == NULL: raise ZeroDivisionError diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index 3ee2366b00b..3e6e55445f4 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -443,7 +443,7 @@ def one_over_Lvalue(self): sage: pAdicWeightSpace(11)(3).one_over_Lvalue() Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero sage: pAdicWeightSpace(11)(0).one_over_Lvalue() 0 sage: type(_) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 108f661db1d..f330273123b 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -79,11 +79,11 @@ .../sage/rings/integer_ring.pyx in sage.rings.integer_ring.IntegerRing_class._div (build/cythonized/sage/rings/integer_ring.c:...)() ... cdef rational.Rational x = rational.Rational.__new__(rational.Rational) ... if mpz_sgn(right.value) == 0: - ... raise ZeroDivisionError('Rational division by zero') + ... raise ZeroDivisionError('rational division by zero') ... mpz_set(mpq_numref(x.value), left.value) ... mpz_set(mpq_denref(x.value), right.value) - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero sage: shell.quit() """ @@ -372,7 +372,7 @@ def run_cell(self, *args, **kwds): --------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero sage: rc is None True sage: shell.quit() diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index 1785e428866..66e52c1ecf8 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -1366,7 +1366,7 @@ def __invert__(self): 1 """ if not self: - raise ZeroDivisionError("Rational division by 0") + raise ZeroDivisionError("rational division by zero") if self._x1: if self._x1[0] < 0: return -(-self).__invert__() diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 83d34d1fba3..d9cf66640c7 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -428,11 +428,11 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: A._div(12,0) Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero """ cdef rational.Rational x = rational.Rational.__new__(rational.Rational) if mpz_sgn(right.value) == 0: - raise ZeroDivisionError('Rational division by zero') + raise ZeroDivisionError('rational division by zero') mpz_set(mpq_numref(x.value), left.value) mpz_set(mpq_denref(x.value), right.value) mpq_canonicalize(x.value) diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 2221ff3af2f..6e17e8b1420 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -1953,7 +1953,7 @@ cdef class NumberFieldElement(FieldElement): sage: I/0 # indirect doctest Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero :: diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 823764378fa..afc6c7eb514 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2367,7 +2367,7 @@ cdef class MPolynomial_libsingular(sage.rings.polynomial.multi_polynomial.MPolyn sage: x/0 Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero """ cdef poly *p cdef MPolynomial_libsingular right = right_ringelement diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 54c75b2d8f2..5983834ef69 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -1612,7 +1612,7 @@ cdef class NCPolynomial_plural(RingElement): sage: x/0 Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero """ cdef poly *p cdef bint is_field = left._parent._base.is_field() diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 53a63fd9ecd..e132ba1d7fa 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4397,7 +4397,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f.monic() Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero Notice that the monic version of a polynomial over the integers is defined over the rationals. diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 692764f76dd..88c2449a0a4 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -2187,10 +2187,10 @@ cdef class Rational(sage.structure.element.FieldElement): sage: 3/0 # indirect doctest Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero """ if mpq_cmp_si(( right).value, 0, 1) == 0: - raise ZeroDivisionError, "Rational division by zero" + raise ZeroDivisionError('rational division by zero') cdef Rational x x = Rational.__new__(Rational) mpq_div(x.value, self.value, (right).value) @@ -2230,7 +2230,7 @@ cdef class Rational(sage.structure.element.FieldElement): -17/4 """ if self.is_zero(): - raise ZeroDivisionError('Rational division by zero') + raise ZeroDivisionError('rational division by zero') cdef Rational x x = Rational.__new__(Rational) mpq_inv(x.value, self.value) @@ -2323,7 +2323,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: QQ(0)^(-1) Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero """ if dummy is not None: raise ValueError, "__pow__ dummy variable not used" @@ -2398,7 +2398,7 @@ cdef class Rational(sage.structure.element.FieldElement): if nn < 0: if mpz_sgn(mpq_numref(_self.value)) == 0: - raise ZeroDivisionError('Rational division by zero') + raise ZeroDivisionError('rational division by zero') sig_on() # mpz_pow_ui(mpq_denref(x.value), mpq_numref(_self.value), (-nn)) diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 3d51ebe7645..6cdf83e5d33 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -776,7 +776,7 @@ def xy(self): sage: Q.xy() Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero """ if self[2] == 1: return self[0], self[1] diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index 156b0da0815..46e3951de25 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -204,7 +204,7 @@ class WithProof: ... Traceback (most recent call last): ... - ZeroDivisionError: Rational division by zero + ZeroDivisionError: rational division by zero sage: proof.arithmetic() True """ From 2eeb13ef8eee96666dedf37606124f92a986cb86 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 13:34:24 +0200 Subject: [PATCH 0811/1872] doctests after merge of #19110 --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- src/sage/rings/asymptotic/term_monoid.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 6928dd6a881..d829fd23cdd 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1188,11 +1188,11 @@ def __pow__(self, exponent, precision=None): :: - sage: O(x)^(-1) # not tested # see #19110 + sage: O(x)^(-1) # see :trac:`19110` Traceback (most recent call last): ... ZeroDivisionError: Cannot take O(x) to exponent -1. - > *previous* FloatingPointError: Floating point exception. + > *previous* ZeroDivisionError: rational division by zero :: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 9fab9ee9a70..55dff4ceed0 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -394,7 +394,16 @@ def _calculate_pow_test_zero_(self, exponent): Traceback (most recent call last): ... ZeroDivisionError: Cannot take Generic Term with growth z to exponent -2. - > *previous* ZeroDivisionError: Rational division by zero + > *previous* ZeroDivisionError: rational division by zero + + :: + + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: TermMonoid('O', G, QQ)('z')._calculate_pow_test_zero_(-1) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot take O(z) to exponent -1. + > *previous* ZeroDivisionError: rational division by zero """ zero = self.parent().coefficient_ring.zero() try: From d47f79f6f7d799afeaa7cd7d8081e9e5be5bfd8f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 18:14:52 +0200 Subject: [PATCH 0812/1872] allow op=None in split_str_by_op --- src/sage/rings/asymptotic/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 170f8f5ccaa..adb86fd31dc 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -193,7 +193,7 @@ def split_str_by_op(string, op, strip_parentheses=True): """ factors = list() balanced = True - if string and string.startswith(op): + if string and op is not None and string.startswith(op): raise ValueError("'%s' is invalid since it starts with a '%s'." % (string, op)) for s in string.split(op): From 5e41a11ad15750f188341dc9884efee7702f7343 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 18:15:53 +0200 Subject: [PATCH 0813/1872] fix element constructor of cartesian product --- .../asymptotic/growth_group_cartesian.py | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index bb99b404b43..042ed071b23 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -420,6 +420,13 @@ def _element_constructor_(self, data): ValueError: ['2^log(x)', 'x^55'] is not in Growth Group QQ^x * x^QQ. > *previous* ValueError: 2^log(x) is not in any of the factors of Growth Group QQ^x * x^QQ + + TESTS:: + + sage: n = GrowthGroup('n^ZZ * log(n)^ZZ')('n') + sage: G = GrowthGroup('QQ^n * n^ZZ * log(n)^ZZ') + sage: G(n).value + (1, n, 1) """ def convert_factors(data, raw_data): try: @@ -438,9 +445,6 @@ def convert_factors(data, raw_data): elif type(data) == self.element_class and data.parent() == self: return data - elif isinstance(data, self.element_class): - return self.element_class(self, data) - elif isinstance(data, str): from misc import split_str_by_op return convert_factors(split_str_by_op(data, '*'), data) @@ -458,14 +462,13 @@ def convert_factors(data, raw_data): # room for other parents (e.g. polynomial ring et al.) - else: - try: - return super(GenericProduct, self)._element_constructor_(data) - except ValueError: - pass - if isinstance(data, (tuple, list, - sage.sets.cartesian_product.CartesianProduct.Element)): - return convert_factors(tuple(data), data) + try: + return super(GenericProduct, self)._element_constructor_(data) + except (TypeError, ValueError): + pass + if isinstance(data, (tuple, list, + sage.sets.cartesian_product.CartesianProduct.Element)): + return convert_factors(tuple(data), data) return convert_factors((data,), data) @@ -819,6 +822,7 @@ class Element(CartesianProductPosets.Element): from growth_group import is_lt_one is_lt_one = is_lt_one + def _repr_(self): r""" A representation string for this cartesian product element. From c5972f288f4af6aa7b6c2edf4f1453dcbde93a9a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 18:16:52 +0200 Subject: [PATCH 0814/1872] fix a bug in creation of exponential factors during rpow --- src/sage/rings/asymptotic/growth_group.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index a7ba263c64c..95b99e588dc 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -804,7 +804,9 @@ def rpow(self, base): if element is None: if base == 'e': from sage.rings.integer_ring import ZZ - M = MonomialGrowthGroup(ZZ, 'e^' + var, ignore_variables=('e',)) + from misc import repr_op + M = MonomialGrowthGroup(ZZ, repr_op('e', '^', var), + ignore_variables=('e',)) element = M(raw_element=ZZ(1)) else: E = ExponentialGrowthGroup(base.parent(), var) From 2aaba817581e263da662aa9f1e7ff2181dff8c9b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 18:17:22 +0200 Subject: [PATCH 0815/1872] more doctests on creating GrowthGroups --- src/sage/rings/asymptotic/growth_group.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 95b99e588dc..dc794466341 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3401,6 +3401,19 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): sage: GrowthGroup('(e^x)^ZZ * x^ZZ') Growth Group (e^x)^ZZ * x^ZZ + TESTS:: + + sage: G = GrowthGroup('(e^(n*log(n)))^ZZ') + sage: G, G._var_ + (Growth Group (e^(n*log(n)))^ZZ, e^(n*log(n))) + sage: G = GrowthGroup('(e^n)^ZZ') + sage: G, G._var_ + (Growth Group (e^n)^ZZ, e^n) + sage: G = GrowthGroup('(e^(n*log(n)))^ZZ * (e^n)^ZZ * n^ZZ * log(n)^ZZ') + sage: G, tuple(F._var_ for F in G.cartesian_factors()) + (Growth Group (e^(n*log(n)))^ZZ * (e^n)^ZZ * n^ZZ * log(n)^ZZ, + (e^(n*log(n)), e^n, n, log(n))) + TESTS:: sage: TestSuite(GrowthGroup('x^ZZ')).run(verbose=True) # long time From dd4aac160d3dc689f92c0dec174b3aea1ea745ee Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 18:18:06 +0200 Subject: [PATCH 0816/1872] extend init of Variable to strip of parentheses --- src/sage/rings/asymptotic/growth_group.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index dc794466341..ab442adcc70 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -275,6 +275,13 @@ class Variable(sage.structure.unique_representation.CachedRepresentation, sage: v = Variable('e^x', ignore=('e',)); repr(v), v.variable_names() ('e^x', ('x',)) + + :: + + sage: v = Variable('(e^n)', ignore=('e',)); repr(v), v.variable_names() + ('e^n', ('n',)) + sage: v = Variable('(e^(n*log(n)))', ignore=('e',)); repr(v), v.variable_names() + ('e^(n*log(n))', ('n',)) """ def __init__(self, var, repr=None, ignore=None): r""" @@ -291,7 +298,8 @@ def __init__(self, var, repr=None, ignore=None): from sage.symbolic.ring import isidentifier if not isinstance(var, (list, tuple)): - var = (var,) + from misc import split_str_by_op + var = split_str_by_op(str(var), None) # we strip off parentheses var = tuple(str(v).strip() for v in var) if ignore is None: From 10e0eb51bdbf9c2f4325b4da2480beef68b78e60 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 4 Sep 2015 18:27:13 +0200 Subject: [PATCH 0817/1872] substitute-method --- src/sage/rings/asymptotic/asymptotic_ring.py | 98 +++++++++++++++++++ src/sage/rings/asymptotic/growth_group.py | 39 ++++++++ .../asymptotic/growth_group_cartesian.py | 14 +++ src/sage/rings/asymptotic/misc.py | 6 ++ src/sage/rings/asymptotic/term_monoid.py | 56 +++++++++++ 5 files changed, 213 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d829fd23cdd..fcadbf2db2e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1566,6 +1566,104 @@ def exp(self, precision=None): return self.rpow('e', precision=precision) + def substitute(self, rules=None, domain=None, **kwds): + r""" + EXAMPLES:: + + sage: A. = AsymptoticRing(growth_group='(e^x)^QQ * x^ZZ * log(x)^ZZ', coefficient_ring=QQ, default_prec=5) + + :: + + sage: (e^x * x^2 + log(x)).subs(x=SR('s')) + s^2*e^s + log(s) + sage: _.parent() + Symbolic Ring + + :: + + sage: (x^3 + x + log(x)).subs(x=x+5).truncate(5) + x^3 + 15*x^2 + 76*x + log(x) + 130 + O(x^(-1)) + sage: _.parent() + Asymptotic Ring <(e^x)^QQ * x^ZZ * log(x)^ZZ> over Rational Field + + :: + + sage: (e^x * x^2 + log(x)).subs(x=2*x) + 4*(e^x)^2*x^2 + log(x) + log(2) + sage: _.parent() + Asymptotic Ring <(e^x)^QQ * x^QQ * log(x)^QQ> over Symbolic Ring + + :: + + sage: (x^2 + log(x)).subs(x=4*x+2).truncate(5) + 16*x^2 + 16*x + log(x) + log(4) + 4 + 1/2*x^(-1) + O(x^(-2)) + sage: _.parent() + Asymptotic Ring <(e^x)^QQ * x^ZZ * log(x)^ZZ> over Symbolic Ring + + :: + + sage: (e^x * x^2 + log(x)).subs(x=RIF(pi)) + 229.534211738584? + sage: _.parent() + Real Interval Field with 53 bits of precision + """ + if not rules and not kwds: + return self + + gens = self.parent().gens() + locals = dict((str(g), g) for g in gens) + + if isinstance(rules, dict): + locals.update(rules) + elif rules is not None: + raise TypeError('Substitution rules %s have to be a dictionary.' % + (rules,)) + + if kwds: + gens_str = tuple(str(g) for g in gens) + for k, v in kwds.iteritems(): + k = str(k) + if k not in gens_str: + raise ValueError('Cannot substitute %s by %s in %s ' + 'since it is not a generator of %s.' % + (k, v, self, self.parent())) + locals[k] = v + + if domain is None: + P = self.parent() + for g in gens: + G = locals[str(g)].parent() + if G is not P: + domain = G + break + else: + domain = P + + try: + return self._substitute_(locals, domain) + except TypeError as e: + from misc import combine_exceptions + raise combine_exceptions( + TypeError('Cannot apply the substitution rules %s at %s ' + 'in %s.' % (locals, self, self.parent())), e) + + + subs = substitute + + + def _substitute_(self, rules, domain): + if not self.summands: + return domain.zero() + from sage.symbolic.operators import add_vararg + try: + return add_vararg( + *tuple(s._substitute_(rules, domain) + for s in self.summands.elements_topological())) + except (ArithmeticError, NotImplementedError, + TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + class AsymptoticRing(sage.algebras.algebra.Algebra, sage.structure.unique_representation.UniqueRepresentation): diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ab442adcc70..0b00a131867 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -559,6 +559,16 @@ def strip(s): return tuple(vars) + def _substitute_(self, rules, domain): + from sage.misc.sage_eval import sage_eval + try: + return sage_eval(self.var_repr, locals=rules) + except (ArithmeticError, NotImplementedError, + TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + def is_lt_one(self): r""" Return if this element is less than `1`. @@ -1292,6 +1302,13 @@ def factors(self): is_lt_one = is_lt_one + def _substitute_(self, rules, domain): + if self.is_one(): + return domain.one() + raise NotImplementedError('Cannot substitute in %s in the abstract ' + 'base class %s.' % (self, self.parent())) + + class GenericGrowthGroup( sage.structure.unique_representation.UniqueRepresentation, sage.structure.parent.Parent): @@ -2507,6 +2524,17 @@ def _le_(self, other): return self.exponent <= other.exponent + def _substitute_(self, rules, domain): + if self.is_one(): + return domain.one() + try: + return self.parent()._var_._substitute_(rules, domain) ** self.exponent + except (ArithmeticError, NotImplementedError, + TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + class MonomialGrowthGroup(GenericGrowthGroup): r""" A growth group dealing with powers of a fixed object/symbol. @@ -3090,6 +3118,17 @@ def _le_(self, other): return bool(abs(self.base) <= abs(other.base)) + def _substitute_(self, rules, domain): + if self.is_one(): + return domain.one() + try: + return self.base ** self.parent()._var_._substitute_(rules, domain) + except (ArithmeticError, NotImplementedError, + TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + class ExponentialGrowthGroup(GenericGrowthGroup): r""" A growth group dealing with expressions involving a fixed diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 042ed071b23..77770295ca8 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1091,6 +1091,20 @@ def __invert__(self): tuple(~x for x in self.cartesian_factors())) + def _substitute_(self, rules, domain): + if self.is_one(): + return domain.one() + from sage.symbolic.operators import mul_vararg + try: + return mul_vararg( + *tuple(x._substitute_(rules, domain) + for x in self.cartesian_factors())) + except (ArithmeticError, NotImplementedError, + TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + CartesianProduct = CartesianProductGrowthGroups diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index adb86fd31dc..969b069898a 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -301,6 +301,12 @@ def combine_exceptions(e, *f): return e +def substitute_raise_exception(self, e, rules, domain): + raise combine_exceptions( + TypeError('Cannot substitute in %s in %s.' % + (self, self.parent())), e) + + def underlying_class(P): r""" Return the underlying class (class without the attached diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 55dff4ceed0..f196d167e9a 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1123,6 +1123,11 @@ def _repr_(self): return 'Generic Term with growth ' + repr(self.growth) + def _substitute_(self, rules, domain): + raise NotImplementedError('Cannot substitute in %s in the abstract ' + 'base class %s.' % (self, self.parent())) + + class GenericTermMonoid(sage.structure.unique_representation.UniqueRepresentation, sage.structure.parent.Parent): r""" @@ -2039,6 +2044,40 @@ def rpow(self, base): (base, self, self.parent())) + def _substitute_(self, rules, domain): + try: + g = self.growth._substitute_(rules, domain) + except (ArithmeticError, NotImplementedError, + TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + try: + return rules['O'](g) + except KeyError: + pass + + from asymptotic_ring import AsymptoticRing + if isinstance(g.parent(), AsymptoticRing): + return g.O() + + elif isinstance(g.parent(), sage.symbolic.ring.SR): + return g.Order() + + elif domain is sage.symbolic.ring.SR: + try: + return domain(g).Order() + except (TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + try: + return sage.rings.big_oh.O(g) + except (TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + class OTermMonoid(GenericTermMonoid): r""" Parent for asymptotic big `O`-terms. @@ -3047,6 +3086,23 @@ def rpow(self, base): return elem ** self.coefficient + def _substitute_(self, rules, domain): + try: + g = self.growth._substitute_(rules, domain) + except (ArithmeticError, NotImplementedError, + TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + c = self.coefficient + + try: + return c * g + except (TypeError, ValueError) as e: + from misc import substitute_raise_exception + substitute_raise_exception(self, e, rules, domain) + + class ExactTermMonoid(TermWithCoefficientMonoid): r""" Parent for asymptotic exact terms, implemented in From a5504ba8ecfb96fd9106e723d3dca32ea8f98892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 8 Sep 2015 17:46:38 +0300 Subject: [PATCH 0818/1872] Hopefully working function is_subposet(). --- src/sage/combinat/posets/posets.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 67747db9b0c..8a33b0b29c2 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5603,7 +5603,11 @@ def incidence_algebra(self, R, prefix='I'): def is_subposet(self, other): r""" - Return ``True`` if the poset is a subposet of ``other``, and ``False`` otherwise. + Return ``True`` if the poset is a subposet of ``other``, and + ``False`` otherwise. + + A poset $P$ is an (induced) subposet of `Q` if every element + of `P` is an element of `Q`, and `x \le_P y` iff `x \le_Q y`. .. NOTE:: @@ -5622,7 +5626,10 @@ def is_subposet(self, other): sage: P.is_subposet(R) True """ - return self.hasse_diagram().is_subgraph(other.hasse_diagram().transitive_closure()) + if hasattr(other, 'hasse_diagram'): + return other.subposet(self) == self + else: + raise ValueError('the input is not a finite poset') FinitePoset._dual_class = FinitePoset From 00daf69f415aa6f10410dc65841ebe48f592c88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 8 Sep 2015 18:59:07 +0300 Subject: [PATCH 0819/1872] Fix for facade posets. --- src/sage/combinat/posets/posets.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 8a33b0b29c2..01471ec69b1 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5606,15 +5606,16 @@ def is_subposet(self, other): Return ``True`` if the poset is a subposet of ``other``, and ``False`` otherwise. - A poset $P$ is an (induced) subposet of `Q` if every element + A poset `P` is an (induced) subposet of `Q` if every element of `P` is an element of `Q`, and `x \le_P y` iff `x \le_Q y`. .. NOTE:: This method does not check whether the poset is a - subposet *isomorphic* to ``other``, but only if ``other`` - directly contains the poset as an (induced) subposet. - For isomorphic subposets see :meth:`has_isomorphic_subposet`. + subposet *isomorphic* (i.e., up to relabeling) to ``other``, + but only if ``other`` directly contains the poset as an + (induced) subposet. For isomorphic subposets see + :meth:`has_isomorphic_subposet`. EXAMPLES:: @@ -5627,7 +5628,8 @@ def is_subposet(self, other): True """ if hasattr(other, 'hasse_diagram'): - return other.subposet(self) == self + return (Poset(other.subposet(self), facade=True) == + Poset(self, facade=True)) else: raise ValueError('the input is not a finite poset') From 9db71143f587b7c69efecc539f5c7cbf9eba5291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 8 Sep 2015 23:43:28 +0300 Subject: [PATCH 0820/1872] More on facade, added tests etc. --- src/sage/combinat/posets/posets.py | 33 ++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 01471ec69b1..dc8309d74b5 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5603,10 +5603,10 @@ def incidence_algebra(self, R, prefix='I'): def is_subposet(self, other): r""" - Return ``True`` if the poset is a subposet of ``other``, and + Return ``True`` if the poset is an induced subposet of ``other``, and ``False`` otherwise. - A poset `P` is an (induced) subposet of `Q` if every element + A poset `P` is an induced subposet of `Q` if every element of `P` is an element of `Q`, and `x \le_P y` iff `x \le_Q y`. .. NOTE:: @@ -5614,9 +5614,12 @@ def is_subposet(self, other): This method does not check whether the poset is a subposet *isomorphic* (i.e., up to relabeling) to ``other``, but only if ``other`` directly contains the poset as an - (induced) subposet. For isomorphic subposets see + induced subposet. For isomorphic subposets see :meth:`has_isomorphic_subposet`. + Also note that "induced" here has somewhat different + meaning compared to that of graphs. + EXAMPLES:: sage: P = Poset({1:[2, 3]}) @@ -5626,13 +5629,27 @@ def is_subposet(self, other): sage: R = Poset({0:[1], 1:[3, 4], 3:[5], 4:[2]}) sage: P.is_subposet(R) True + + TESTS:: + + sage: P = Poset({2:[1]}, facade=True) + sage: Q = Poset({2:[1]}, facade=False) + sage: P.is_subposet(Q), Q.is_subposet(P) + (True, True) + sage: Poset().is_subposet(P) + True + sage: Poset().is_subposet(Poset()) + True + sage: P.is_subposet(Poset()) + False """ - if hasattr(other, 'hasse_diagram'): - return (Poset(other.subposet(self), facade=True) == - Poset(self, facade=True)) - else: + if not hasattr(other, 'hasse_diagram'): raise ValueError('the input is not a finite poset') - + self_ = Poset(self, facade=True) + other_ = Poset(other, facade=True) + return (set(self_).issubset(set(other_)) and + other_.subposet(self_) == self_) + FinitePoset._dual_class = FinitePoset ##### Posets ##### From c3b48f366eb7a82519338fb390d9363ce6c68180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Wed, 9 Sep 2015 08:06:04 +0300 Subject: [PATCH 0821/1872] Moved a note in docstring. --- src/sage/combinat/posets/posets.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index dc8309d74b5..39c93f3cce6 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5608,6 +5608,8 @@ def is_subposet(self, other): A poset `P` is an induced subposet of `Q` if every element of `P` is an element of `Q`, and `x \le_P y` iff `x \le_Q y`. + Note that "induced" here has somewhat different meaning compared + to that of graphs. .. NOTE:: @@ -5617,9 +5619,6 @@ def is_subposet(self, other): induced subposet. For isomorphic subposets see :meth:`has_isomorphic_subposet`. - Also note that "induced" here has somewhat different - meaning compared to that of graphs. - EXAMPLES:: sage: P = Poset({1:[2, 3]}) From ac80aeb7f0ca7efb3cbf0365c11ee16f4f53e548 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 9 Sep 2015 17:12:39 +0200 Subject: [PATCH 0822/1872] add growth_group_cartesian to index --- src/doc/en/reference/rings/asymptotic_expansions_index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/rings/asymptotic_expansions_index.rst b/src/doc/en/reference/rings/asymptotic_expansions_index.rst index 3940261ee77..0277d81a91d 100644 --- a/src/doc/en/reference/rings/asymptotic_expansions_index.rst +++ b/src/doc/en/reference/rings/asymptotic_expansions_index.rst @@ -4,5 +4,6 @@ Asymptotic Expansions .. toctree:: sage/rings/asymptotic/growth_group + sage/rings/asymptotic/growth_group_cartesian .. include:: ../footer.txt From dece275cac5a229f9365fad4c8b5404c6a7ebe6b Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 9 Sep 2015 19:10:38 -0700 Subject: [PATCH 0823/1872] trac 19179: chain homotopies, chain contractions, and duals of chain maps --- src/doc/en/reference/homology/index.rst | 1 + src/sage/homology/chain_complex_morphism.py | 33 ++ src/sage/homology/chain_homotopy.py | 563 ++++++++++++++++++++ 3 files changed, 597 insertions(+) create mode 100644 src/sage/homology/chain_homotopy.py diff --git a/src/doc/en/reference/homology/index.rst b/src/doc/en/reference/homology/index.rst index 7834bd7d79d..81c7e86b9b7 100644 --- a/src/doc/en/reference/homology/index.rst +++ b/src/doc/en/reference/homology/index.rst @@ -13,6 +13,7 @@ cell complexes. sage/homology/chain_complex sage/homology/chain_complex_morphism + sage/homology/chain_homotopy sage/homology/chain_complex_homspace sage/homology/simplicial_complex sage/homology/simplicial_complex_morphism diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index 4f3e6ffc9a2..72c6c006f14 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -217,6 +217,39 @@ def in_degree(self, n): cols = self._domain.free_module_rank(n) return zero_matrix(self._domain.base_ring(), rows, cols) + def dual(self): + """ + The dual chain map to this one. + + That is, the map from the dual of the codomain of this one to + the dual of its domain, represented in each degree by the + transpose of the corresponding matrix. + + EXAMPLES:: + + sage: X = simplicial_complexes.Simplex(1) + sage: Y = simplicial_complexes.Simplex(0) + sage: g = Hom(X,Y)({0:0, 1:0}) + sage: f = g.associated_chain_complex_morphism() + sage: f.in_degree(0) + [1 1] + sage: f.dual() + Chain complex morphism from Chain complex with at most 1 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + sage: f.dual().in_degree(0) + [1] + [1] + sage: ascii_art(f._domain) + [-1] + [ 1] + 0 <-- C_0 <----- C_1 <-- 0 + sage: ascii_art(f.dual()._codomain) + [-1 1] + 0 <-- C_1 <-------- C_0 <-- 0 + """ + matrix_dict = self._matrix_dictionary + matrices = {i: matrix_dict[i].transpose() for i in matrix_dict} + return ChainComplexMorphism(matrices, self._codomain.dual(), self._domain.dual()) + def __neg__(self): """ Returns ``-x``. diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py new file mode 100644 index 00000000000..868a51b43a2 --- /dev/null +++ b/src/sage/homology/chain_homotopy.py @@ -0,0 +1,563 @@ +# -*- coding: utf-8 -*- +r""" +Chain homotopies and chain contractions. + +Chain homotopies are standard constructions in homological algebra: +given chain complexes `C` and `D` and chain maps `f, g: C \to D`, say +with differential of degree `-1`, a *chain homotopy* `H` between `f` and +`g` is a collection of maps `H_n: C_n \to D_{n+1}` satisfying + +.. math:: + + \partial_D H + H \partial_C = f - g + +The presence of a chain homotopy defines an equivalence relation +(*chain homotopic*) on chain maps. If `f` and `g` are chain homotopic, +then one can show that `f` and `g` induce the same map on homology. + +Chain contractions are not as well known. The papers [M-AR]_, [RM-A]_, +and [PR]_ provide some references. Given two chain complexes `C` and +`D`, a *chain contraction* is a chain homotopy `H: C \to C` for which +there are chain maps `\pi: C \to D` ("projection") and `\iota: D \to +C` ("inclusion") such that + +- `H` is a chain homotopy between `1_C` and `\iota \pi`, +- `\pi \iota = 1_D`, +- `\pi H = 0`, +- `H \iota = 0`, +- `H \circ H = 0`. + +Such a chain homotopy provides a strong relation between the chain +complexes `C` and `D`; for example, their homology groups are +isomorphic. + +REFERENCES: + +.. [M-AR] H. Molina-Abril and P. Réal, "Homology computation using spanning + trees" in Progress in Pattern Recognition, Image Analysis, + Computer Vision, and Applications, Lecture Notes in Computer + Science, volume 5856, pp 272-278, Springer, Berlin (2009). + +.. [PR] P. Pilarczyk and P. Réal, "Computation of cubical homology, + cohomology, and (co)homological operations via chain contraction", + Adv. Comput. Math. 41 (2015), pp 253--275. + +.. [RM-A] P. Réal and H. Molina-Abril, "Cell AT-models for digital + volumes" in Torsello, Escolano, Brun (eds.), Graph-Based + Representations in Pattern Recognition, Lecture Notes in + Computer Science, volume 5534, pp. 314-3232, Springer, + Berlin (2009). +""" + +######################################################################## +# Copyright (C) 2015 John H. Palmieri +# +# 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.sage_object import SageObject +from sage.homology.chain_complex_morphism import ChainComplexMorphism + +class ChainHomotopy(SageObject): + r"""A chain homotopy. + + A chain homotopy `H` between chain maps `f, g: C \to D` is a sequence + of maps `H_n: C_n \to D_{n+1}` (if the chain complexes are graded + homologically) satisfying + + .. math:: + + \partial_D H + H \partial_C = f - g + + INPUT: + + - ``matrices`` -- dictionary of matrices, keyed by dimension + - ``f`` -- chain map `C \to D`. + - ``g`` (optional) -- chain map `C \to D`. + + The dictionary ``matrices`` defines ``H`` by specifying the matrix + defining it in each degree: the entry `m` corresponding to key `i` + gives the linear transformation `C_i \to D_{i+1}`. + + If `f` is specified but not `g`, then `g` can be recovered from + the defining formula. + + Note that the degree of the differential on the chain complex `C` + must agree with that for `D`, and those degrees determine the + "degree" of the chain homotopy map: if the degree of the + differential is `d`, then the chain homotopy consists of a + sequence of maps `C_n \to C_{n-d}`. The keys in the dictionary + ``matrices`` specify the starting degrees. + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: g = Hom(C,D)({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1)}, f, g) + + Note that the maps `f` and `g` are stored in the attributes ``H._f`` and ``H._g``:: + + sage: H._f + Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + sage: H._f.in_degree(0) + [1] + sage: H._g.in_degree(0) + [0] + + A non-example:: + + sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1)}, f, g) + Traceback (most recent call last): + ... + ValueError: the data do not define a valid chain homotopy + """ + def __init__(self, matrices, f, g=None): + r""" + Create a chain homotopy between the given chain maps + from a dictionary of matrices. + + INPUT: + + - ``matrices`` -- dictionary of matrices, keyed by dimension + - ``f`` -- chain map `C \to D`. + - ``g`` (optional) -- chain map `C \to D`. + + EXAMPLES: + + If ``g`` is not specified, it is set equal to `f - (H \partial + \partial H)`. :: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({1: matrix(ZZ, 1, 2, (1,0)), 2: matrix(ZZ, 2, 1, (0, 2))}, degree_of_differential=-1) + sage: D = ChainComplex({2: matrix(ZZ, 1, 1, (6,))}, degree_of_differential=-1) + sage: f_d = {1: matrix(ZZ, 1, 2, (0,3)), 2: identity_matrix(ZZ, 1)} + sage: f = Hom(C,D)(f_d) + sage: H_d = {0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 2, (2,2))} + sage: H = ChainHomotopy(H_d, f) + sage: H._g.in_degree(0) + [] + sage: H._g.in_degree(1) + [-13 -9] + sage: H._g.in_degree(2) + [-3] + + TESTS: + + Try to construct a chain homotopy in which the maps do not + have matching domains and codomains:: + + sage: g = Hom(C,C)({}) # the zero chain map + sage: H = ChainHomotopy(H_d, f, g) + Traceback (most recent call last): + ... + AssertionError: the chain maps are not compatible + """ + domain = f._domain + codomain = f._codomain + deg = domain.degree_of_differential() + # Check that the chain complexes are compatible. This should + # never arise, because first there should be errors in + # constructing the chain maps. But just in case... + assert (domain.degree_of_differential() == + codomain.degree_of_differential()), 'the chain complexes are not compatible' + if g: + # Check that the chain maps are compatible. + assert (domain == g._domain and codomain == + g._codomain), 'the chain maps are not compatible' + # Check that the data define a chain homotopy. + for i in domain.differential(): + if i in matrices and i+deg in matrices: + if not (codomain.differential(i-deg) * matrices[i] + matrices[i+deg] * domain.differential(i) == f.in_degree(i) - g.in_degree(i)): + raise ValueError('the data do not define a valid chain homotopy') + elif i in matrices: + if not (codomain.differential(i-deg) * matrices[i] == f.in_degree(i) - g.in_degree(i)): + raise ValueError('the data do not define a valid chain homotopy') + elif i+deg in matrices: + if not (matrices[i+deg] * domain.differential(i) == f.in_degree(i) - g.in_degree(i)): + raise ValueError('the data do not define a valid chain homotopy') + else: + # Define g. + g_data = {} + for i in domain.differential(): + if i in matrices and i+deg in matrices: + g_data[i] = f.in_degree(i) - matrices[i+deg] * domain.differential(i) - codomain.differential(i-deg) * matrices[i] + elif i in matrices: + g_data[i] = f.in_degree(i) - codomain.differential(i-deg) * matrices[i] + elif i+deg in matrices: + g_data[i] = f.in_degree(i) - matrices[i+deg] * domain.differential(i) + g = ChainComplexMorphism(g_data, domain, codomain) + self._domain = domain + self._codomain = codomain + self._matrix_dictionary = matrices + self._f = f + self._g = g + + def is_algebraic_gradient_vector_field(self): + r""" + An algebraic gradient vector field is a linear map + `H: C \to C` such that `H \circ H = 0`. + + (Some authors also require that `H \partial H = H`, whereas + some make this part of the definition of "homology gradient + vector field. We have made the second choice.) See + Molina-Abril and Réal [M-AR]_ and Réal and Molina-Abril + [RM-A]_ for this and related terminology. + + See also :meth:`is_homology_gradient_vector_field`. + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({0: zero_matrix(ZZ, 1), 1: identity_matrix(ZZ, 1)}) + + The chain complex `C` is chain homotopy equivalent to a copy of + `\ZZ` in degree 0. Two chain maps `C \to C` will be chain + homotopic as long as they agree in degree 0. :: + + sage: f = Hom(C,C)({0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 1, [3]), 2: matrix(ZZ, 1, 1, [3])}) + sage: g = Hom(C,C)({0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 1, [2]), 2: matrix(ZZ, 1, 1, [2])}) + sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, f, g) + sage: H.is_algebraic_gradient_vector_field() + True + + A chain homotopy which is not an algebraic gradient vector field:: + + sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, f, g) + sage: H.is_algebraic_gradient_vector_field() + False + """ + try: + assert self._domain == self._codomain + except AssertionError: + return False + deg = self._domain.degree_of_differential() + matrices = self._matrix_dictionary + for i in matrices: + if i-deg in matrices: + if matrices[i-deg] * matrices[i] != 0: + return False + return True + + def is_homology_gradient_vector_field(self): + r""" + A homology gradient vector field is an algebraic gradient vector + field `H: C \to C` (i.e., a chain homotopy satisfying `H \circ + H = 0`) such that `\partial H \partial = \partial` and `H + \partial H = H`. See Molina-Abril and Réal [M-AR]_ and Réal + and Molina-Abril [RM-A]_ for this and related terminology. + + See also :meth:`is_algebraic_gradient_vector_field`. + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({0: zero_matrix(ZZ, 1), 1: identity_matrix(ZZ, 1)}) + + sage: f = Hom(C,C)({0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 1, [3]), 2: matrix(ZZ, 1, 1, [3])}) + sage: g = Hom(C,C)({0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 1, [2]), 2: matrix(ZZ, 1, 1, [2])}) + sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, f, g) + sage: H.is_homology_gradient_vector_field() + True + """ + if not self.is_algebraic_gradient_vector_field(): + return False + deg = self._domain.degree_of_differential() + matrices = self._matrix_dictionary + for i in matrices: + if i+deg in matrices: + diff_i = self._domain.differential(i) + if diff_i * matrices[i+deg] * diff_i != diff_i: + return False + if matrices[i] * self._domain.differential(i-deg) * matrices[i] != matrices[i]: + return False + return True + + def in_degree(self, n): + """ + The matrix representing this chain homotopy in degree ``n`` + + INPUT: + + - ``n`` -- degree + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: f = Hom(C, D)({}) + sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) + sage: H.in_degree(1) + [3 1] + + This returns an appropriately sized zero matrix if the chain homotopy is not defined in degree n:: + + sage: H.in_degree(-3) + [] + """ + try: + return self._matrix_dictionary[n] + except KeyError: + from sage.matrix.constructor import zero_matrix + deg = self._domain.degree_of_differential() + rows = self._codomain.free_module_rank(n-deg) + cols = self._domain.free_module_rank(n) + return zero_matrix(self._domain.base_ring(), rows, cols) + + def dual(self): + """ + Dual chain homotopy to this one. + + That is, if this one is a chain homotopy between chain maps + `f, g: C \to D`, then its dual is a chain homotopy between the + dual of `f` and the dual of `g`, from `D^*` to `C^*`. It is + represented in each degree by the transpose of the + corresponding matrix. + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: f = Hom(C, D)({}) + sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) + sage: H.in_degree(1) + [3 1] + sage: H.dual().in_degree(0) + [3] + [1] + """ + matrix_dict = self._matrix_dictionary + deg = self._domain.degree_of_differential() + matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} + return ChainHomotopy(matrices, self._f.dual(), self._g.dual()) + + def _repr_(self): + """ + String representation + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: g = Hom(C,D)({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1)}, f, g) + Chain homotopy between Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring and Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + """ + return 'Chain homotopy between {} and {}'.format(self._f, self._g) + +class ChainContraction(ChainHomotopy): + r""" + An algebraic gradient vector field `H: C \to C` (that is a chain + homotopy satisfying `H \circ H = 0`) for which there are chain + maps `\pi: C \to D` ("projection") and `\iota: D \to C` + ("inclusion") such that + + - `H` is a chain homotopy between `1_C` and `\iota \pi`, + - `\pi \iota = 1_D`, + - `\pi H = 0`, + - `H \iota = 0`. + + ``H`` is defined by a dictionary ``matrices`` of matrices. + + INPUTS: + + - ``matrices`` -- dictionary of matrices, keyed by dimension + - ``pi`` -- a chain map `C \to D` + - ``iota`` -- a chain map `D \to C` + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainContraction + sage: C = ChainComplex({0: zero_matrix(ZZ, 1), 1: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) + + The chain complex `C` is chain homotopy equivalent to `D`, which is just a + copy of `\ZZ` in degree 0, and we construct a chain contraction:: + + sage: pi = Hom(C,D)({0: identity_matrix(ZZ, 1)}) + sage: iota = Hom(D,C)({0: identity_matrix(ZZ, 1)}) + sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota) + """ + def __init__(self, matrices, pi, iota): + r""" + Create a chain contraction from the given data. + + INPUTS: + + - ``matrices`` -- dictionary of matrices, keyed by dimension + - ``pi`` -- a chain map `C \to D` + - ``iota`` -- a chain map `D \to C` + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainContraction + sage: C = ChainComplex({0: zero_matrix(ZZ, 1), 1: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) + + The chain complex `C` is chain homotopy equivalent to `D`, + which is just a copy of `\ZZ` in degree 0, and we try + construct a chain contraction, but get the map `\iota` wrong:: + + sage: pi = Hom(C,D)({0: identity_matrix(ZZ, 1)}) + sage: iota = Hom(D,C)({0: zero_matrix(ZZ, 1)}) + sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota) + Traceback (most recent call last): + ... + ValueError: the composite 'pi iota' is not the identity + + Another bad `\iota`:: + + sage: iota = pi # wrong domain, codomain + sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota) + Traceback (most recent call last): + ... + AssertionError: the chain maps are not composable + + `\iota` is okay, but wrong data defining `H`:: + + sage: iota = Hom(D,C)({0: identity_matrix(ZZ, 1)}) + sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota) + Traceback (most recent call last): + ... + AssertionError: not an algebraic gradient vector field + """ + from sage.matrix.constructor import identity_matrix + from chain_complex_morphism import ChainComplexMorphism + + assert (pi._domain == iota._codomain + and pi._codomain == iota._domain), 'the chain maps are not composable' + C = pi._domain + D = pi._codomain + base_ring = C.base_ring() + + # Check that the composite 'pi iota' is 1. + for i in D.nonzero_degrees(): + if pi.in_degree(i) * iota.in_degree(i) != identity_matrix(base_ring, D.free_module_rank(i)): + raise ValueError("the composite 'pi iota' is not the identity") + + # Construct the chain map 'id_C'. + id_C_dict = {} + for i in C.nonzero_degrees(): + id_C_dict[i] = identity_matrix(base_ring, C.free_module_rank(i)) + id_C = ChainComplexMorphism(id_C_dict, C, C) + + # Now check that + # - `H` is a chain homotopy between `id_C` and `\iota \pi` + # - `HH = 0` + ChainHomotopy.__init__(self, matrices, id_C, iota * pi) + assert self.is_algebraic_gradient_vector_field(), 'not an algebraic gradient vector field' + # Check that `\pi H = 0`: + deg = C.degree_of_differential() + for i in matrices: + if pi.in_degree(i-deg) * matrices[i] != 0: + raise ValueError('the data do not define a valid chain contraction: pi H != 0') + # Check that `H \iota = 0`: + for i in iota._matrix_dictionary: + if i in matrices: + if matrices[i] * iota.in_degree(i) != 0: + raise ValueError('the data do not define a valid chain contraction: H iota != 0') + self._pi = pi + self._iota = iota + + def pi(self): + r""" + The chain map `\pi` associated to this chain contraction. + + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: phi, M = S2.algebraic_topological_model(QQ) + sage: phi.pi() + Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + sage: phi.pi().in_degree(0) # Every vertex represents a homology class. + [1 1 1 1] + sage: phi.pi().in_degree(1) # No homology in degree 1. + [] + + The degree 2 homology generator is detected on a single simplex:: + + sage: phi.pi().in_degree(2) + [0 0 0 1] + """ + return self._pi + + def iota(self): + r""" + The chain map `\iota` associated to this chain contraction. + + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: phi, M = S2.algebraic_topological_model(QQ) + sage: phi.iota() + Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + + Lifting the degree zero homology class gives a single vertex:: + + sage: phi.iota().in_degree(0) + [0] + [0] + [0] + [1] + + Lifting the degree two homology class gives the signed sum of + all of the 2-simplices:: + + sage: phi.iota().in_degree(2) + [-1] + [-1] + [ 1] + [ 1] + """ + return self._iota + + def dual(self): + """ + The chain contraction dual to this one. + Useful when switching from homology to cohomology. + + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: phi, M = S2.algebraic_topological_model(QQ) + sage: phi.iota() + Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + + Lifting the degree zero homology class gives a single vertex, + but the degree zero cohomology class needs to be detected on + every vertex, and vice versa for degree 2:: + + sage: phi.iota().in_degree(0) + [0] + [0] + [0] + [1] + sage: phi.dual().iota().in_degree(0) + [1] + [1] + [1] + [1] + sage: phi.iota().in_degree(2) + [-1] + [-1] + [ 1] + [ 1] + sage: phi.dual().iota().in_degree(2) + [0] + [0] + [0] + [1] + """ + matrix_dict = self._matrix_dictionary + deg = self._domain.degree_of_differential() + matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} + return ChainContraction(matrices, self.iota().dual(), self.pi().dual()) From 763a8a8a03921e5198a8d51dbd61cc12ff0edcbc Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 9 Sep 2015 19:28:52 -0700 Subject: [PATCH 0824/1872] trac 6102: cup products, cohomology rings, mod 2 cohomology operations --- src/doc/en/reference/homology/index.rst | 2 + .../homology/algebraic_topological_model.py | 317 ++++++++++ src/sage/homology/cell_complex.py | 398 +++++++++++++ src/sage/homology/cubical_complex.py | 68 ++- .../homology_vector_space_with_basis.py | 544 ++++++++++++++++++ src/sage/homology/simplicial_complex.py | 44 ++ 6 files changed, 1370 insertions(+), 3 deletions(-) create mode 100644 src/sage/homology/algebraic_topological_model.py create mode 100644 src/sage/homology/homology_vector_space_with_basis.py diff --git a/src/doc/en/reference/homology/index.rst b/src/doc/en/reference/homology/index.rst index 81c7e86b9b7..c948e30c555 100644 --- a/src/doc/en/reference/homology/index.rst +++ b/src/doc/en/reference/homology/index.rst @@ -24,6 +24,8 @@ cell complexes. sage/homology/cell_complex sage/homology/koszul_complex sage/homology/homology_group + sage/homology/homology_vector_space_with_basis + sage/homology/algebraic_topological_model sage/homology/matrix_utils sage/interfaces/chomp diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py new file mode 100644 index 00000000000..fd6e5c385ed --- /dev/null +++ b/src/sage/homology/algebraic_topological_model.py @@ -0,0 +1,317 @@ +# -*- coding: utf-8 -*- +""" +Algebraic topological model for a cell complex + +AUTHORS: + +- John H. Palmieri (2015-09) +""" + +######################################################################## +# Copyright (C) 2015 John H. Palmieri +# +# 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/ +######################################################################## + +# TODO: cythonize this. + +from sage.modules.free_module_element import vector +from sage.matrix.constructor import matrix, zero_matrix +from chain_complex import ChainComplex +from chain_complex_morphism import ChainComplexMorphism +from chain_homotopy import ChainContraction +from sage.rings.rational_field import QQ + +def algebraic_topological_model(K, base_ring=None): + r""" + Algebraic topological model for cell complex ``K`` + with coefficients in ``base_ring``. ``base_ring`` must be a field. + + INPUT: + + - ``K`` -- either a simplicial complex or a cubical complex. + - ``base_ring`` -- coefficient ring (optional, default ``QQ``). + Must be a field. + + OUTPUT: a pair ``(phi, M)`` consisting of + + - the chain contraction ``phi`` associated to `C`, `M`, `\pi: C + \to M`, and `\iota: M \to C` satisfying `\iota \pi = 1_M` and + `\pi \iota`. + - the chain complex `M` + + This construction appears in a paper by Pilarczyk and Réal [PR]_. + Given a cell complex `K` and a field `F`, there is a chain complex + `C` associated to `K` with coefficients in `F`. The *algebraic + topological model* for `K` is a chain complex `M` with trivial + differential, along with chain maps `\pi: C \to M` and `\iota: M + \to C` such that + + - `\pi \circ \iota = 1_M`. + - There is a chain homotopy `\phi` between `1_C` and `\iota \circ \pi`. + + In particular, `\pi` and `\iota` induce isomorphisms on homology, + and since `M` has trivial differential, it is its own + homology. Thus `\iota` lifts homology classes to their cycle + representatives. + + The chain homotopy `\phi` satisfies some additional properties, + making it a *chain contraction*: + + - `\phi \circ \phi = 0`, + - `\pi \phi = 0`, + - `\phi \iota = 0`. + + Given an algebraic topological model for `K`, it is then easy to + compute cup products and cohomology operations on the cohomology + of `K`, as described in [G-DR]_ and [PR]_. + + Implementation details: the cell complex `K` must have a + :meth:`cell_complex.GenericCellComplex.n_cells` method from which + we can extract a list of cells in each dimension. Combining the + lists in increasing order of dimension then defines a filtration + of the complex: a list of cells in which the boundary of each cell + consists of cells earlier in the list. This is required by + Pilarczyk and Réal's algorithm. There must also be a + :meth:`cell_complex.GenericCellComplex.chain_complex` method, to + construct the chain complex `C` associated to this chain complex. + + In particular, this should work on simplicial complexes and + cubical complexes. It doesn't work for delta complexes, though: + the list of their n-cells has the wrong format. + + Note that from the chain contraction ``\phi``, one can recover the + chain maps `\pi` and `\iota` via ``phi.pi()`` and + ``phi.iota()``. Then one can recover `C` and `M` from, for + example, ``phi.pi()._domain`` and ``phi.pi()._codomain``, + respectively. + + EXAMPLES:: + + sage: from sage.homology.algebraic_topological_model import algebraic_topological_model + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: phi, M = algebraic_topological_model(RP2, GF(2)) + sage: M.homology() + {0: Vector space of dimension 1 over Finite Field of size 2, + 1: Vector space of dimension 1 over Finite Field of size 2, + 2: Vector space of dimension 1 over Finite Field of size 2} + sage: T = cubical_complexes.Torus() + sage: phi, M = algebraic_topological_model(T, QQ) + sage: M.homology() + {0: Vector space of dimension 1 over Rational Field, + 1: Vector space of dimension 2 over Rational Field, + 2: Vector space of dimension 1 over Rational Field} + + If you want to work with cohomology rather than homology, just + dualize the outputs of this function:: + + sage: M.dual().homology() + {0: Vector space of dimension 1 over Rational Field, + 1: Vector space of dimension 2 over Rational Field, + 2: Vector space of dimension 1 over Rational Field} + sage: M.dual().degree_of_differential() + 1 + sage: phi.dual() + Chain homotopy between Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field and Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + + In degree 0, the inclusion of the homology `M` into the chain + complex `C` sends the homology generator to a single vertex:: + + sage: K = simplicial_complexes.Simplex(2) + sage: phi, M = algebraic_topological_model(K, QQ) + sage: phi.iota().in_degree(0) + [0] + [0] + [1] + + In cohomology, though, one needs the dual of every degree 0 chain + to detect the degree 0 cohomology generator:: + + sage: phi.dual().iota().in_degree(0) + [1] + [1] + [1] + + TESTS:: + + sage: T = cubical_complexes.Torus() + sage: C = T.chain_complex() + sage: H, M = T.algebraic_topological_model() + sage: C.differential(1) * H.iota().in_degree(1).column(0) == 0 + True + sage: C.differential(1) * H.iota().in_degree(1).column(1) == 0 + True + sage: coC = T.chain_complex(cochain=True) + sage: coC.differential(1) * H.dual().iota().in_degree(1).column(0) == 0 + True + sage: coC.differential(1) * H.dual().iota().in_degree(1).column(1) == 0 + True + """ + if base_ring is None: + base_ring = QQ + if not base_ring.is_field(): + raise ValueError('the coefficient ring must be a field.') + + # The following are all dictionaries indexed by dimension. + # For each n, gens[n] is an ordered list of the n-cells generating the complex M. + gens = {} + # For each n, phi_dict[n] is a dictionary of the form {idx: + # vector}, where idx is the index of an n-cell in the list of + # n-cells in K, and vector is the image of that n-cell, as an + # element in the free module of (n+1)-chains for K. + phi_dict = {} + # For each n, pi_dict[n] is a dictionary of the same form, except + # that the target vectors should be elements of the chain complex M. + pi_dict = {} + # For each n, iota_dict[n] is a dictionary of the form {cell: + # vector}, where cell is one of the generators for M and vector is + # its image in C, as an element in the free module of n-chains. + iota_dict = {} + + for n in range(K.dimension()+1): + gens[n] = [] + phi_dict[n] = {} + pi_dict[n] = {} + iota_dict[n] = {} + + C = K.chain_complex(base_ring=base_ring) + # old_cells: cells one dimension lower. + old_cells = [] + + for dim in range(K.dimension()+1): + n_cells = K.n_cells(dim) + # No need to set zero values for any of the maps: we will + # assume any unset values are zero. + # From the paper: phi_dict[c] = 0. + diff = C.differential(dim) + rank = len(n_cells) + old_rank = len(old_cells) + + for c_idx, c in enumerate(n_cells): + c_vec = vector(base_ring, rank, {c_idx: 1}) + + # c_bar = c - phi(bdry(c)) + c_bar = c_vec + bdry_c = diff * c_vec + for (idx, coord) in bdry_c.iteritems(): + try: + c_bar -= coord * phi_dict[dim-1][idx] + except KeyError: + pass + + bdry_c_bar = diff * c_bar + + # Evaluate pi(bdry(c_bar)). + pi_bdry_c_bar = vector(base_ring, old_rank) + + for (idx, coeff) in bdry_c_bar.iteritems(): + try: + pi_bdry_c_bar += coeff * pi_dict[dim-1][idx] + except KeyError: + pass + + # One small typo in the published algorithm: it says + # "if bdry(c_bar) == 0", but should say + # "if pi(bdry(c_bar)) == 0". + if not pi_bdry_c_bar: + # Append c to list of gens. + gens[dim].append(c) + # iota(c) = c_bar + iota_dict[dim][c] = c_bar + # pi(c) = c + pi_dict[dim][c_idx] = c_vec + else: + # Take any u in gens so that lambda_i = != 0. + # u_idx will be the index of the corresponding cell. + for (u_idx, lambda_i) in pi_bdry_c_bar.iteritems(): + # Now find the actual cell. + u = old_cells[u_idx] + if u in gens[dim-1]: + break + + # pi(c) = 0: no need to do anything about this. + for c_j_idx, c_j in enumerate(old_cells): + # c_j_vec: representative of c_j in the free + # module of chains in dimension dim-1. + c_j_vec = vector(base_ring, old_rank, {c_j_idx: 1}) + # eta_ij = . + try: + eta_ij = pi_dict[dim-1][c_j_idx][u_idx] + except (KeyError, IndexError): + eta_ij = 0 + if eta_ij: + # Adjust phi(c_j). + try: + phi_dict[dim-1][c_j_idx] += eta_ij * lambda_i**(-1) * c_bar + except KeyError: + phi_dict[dim-1][c_j_idx] = eta_ij * lambda_i**(-1) * c_bar + # Adjust pi(c_j). + try: + pi_dict[dim-1][c_j_idx] += -eta_ij * lambda_i**(-1) * pi_bdry_c_bar + except KeyError: + pi_dict[dim-1][c_j_idx] = -eta_ij * lambda_i**(-1) * pi_bdry_c_bar + + gens[dim-1].remove(u) + del iota_dict[dim-1][u] + old_cells = n_cells + + # Now we have constructed the raw data for M, pi, iota, phi, so we + # have to convert that to data which can be used to construct chain + # complexes, chain maps, and chain contractions. + + # M_data will contain (trivial) matrices defining the differential + # on M. Keep track of the sizes using "M_rows" and "M_cols", which are + # just the ranks of consecutive graded pieces of M. + M_data = {} + M_rows = 0 + # pi_data: the matrices defining pi. Similar for iota_data and phi_data. + pi_data = {} + iota_data = {} + phi_data = {} + for n in range(K.dimension()+1): + n_cells = K.n_cells(n) + # Remove zero entries from pi_dict and phi_dict. + pi_dict[n] = {i: pi_dict[n][i] for i in pi_dict[n] if pi_dict[n][i]} + phi_dict[n] = {i: phi_dict[n][i] for i in phi_dict[n] if phi_dict[n][i]} + # Convert gens to data defining the chain complex M with + # trivial differential. + M_cols = len(gens[n]) + M_data[n] = zero_matrix(base_ring, M_rows, M_cols) + M_rows = M_cols + # Convert the dictionaries for pi, iota, phi to matrices which + # will define chain maps and chain homotopies. + pi_cols = [] + phi_cols = [] + for (idx, c) in enumerate(n_cells): + # First pi: + if idx in pi_dict[n]: + column = vector(base_ring, M_rows) + for (entry, coeff) in pi_dict[n][idx].iteritems(): + # Translate from cells in n_cells to cells in gens[n]. + column[gens[n].index(n_cells[entry])] = coeff + else: + column = vector(base_ring, M_rows) + pi_cols.append(column) + + # Now phi: + try: + column = phi_dict[n][idx] + except KeyError: + column = vector(base_ring, len(K.n_cells(n+1))) + phi_cols.append(column) + # Now iota: + iota_cols = [iota_dict[n][c] for c in gens[n]] + + pi_data[n] = matrix(base_ring, pi_cols).transpose() + iota_data[n] = matrix(base_ring, len(gens[n]), len(n_cells), iota_cols).transpose() + phi_data[n] = matrix(base_ring, phi_cols).transpose() + + M = ChainComplex(M_data, base_ring=base_ring, degree=-1) + pi = ChainComplexMorphism(pi_data, C, M) + iota = ChainComplexMorphism(iota_data, M, C) + phi = ChainContraction(phi_data, pi, iota) + return phi, M diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 8bbd56b3ad6..8c81c2aae41 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Generic cell complexes @@ -37,6 +38,8 @@ from sage.structure.sage_object import SageObject from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ +from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement +from sage.misc.cachefunc import cached_method class GenericCellComplex(SageObject): r""" @@ -650,6 +653,280 @@ def betti(self, dim=None, subcomplex=None): except AttributeError: return H.dimension() + def n_chains(self, n, base_ring=None, cochains=False): + r""" + Return the free module of chains in degree ``n`` over ``base_ring``. + + INPUTS: + + - ``n`` -- integer + - ``base_ring`` -- ring (optional, default `\ZZ`) + - ``cochains`` -- boolean (optional, default ``False``). If + ``True``, return cochains instead. + + The only difference between chains and cochains is + notation. In a simplicial complex, for example, a simplex + ``(0,1,2)`` is written as "(0,1,2)" in the group of chains but + as "\\chi_(0,1,2)" in the group of cochains. + + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: S2.n_chains(1, QQ) + Free module generated by {(2, 3), (0, 2), (1, 3), (1, 2), (0, 3), (0, 1)} over Rational Field + sage: list(simplicial_complexes.Sphere(2).n_chains(1, QQ, cochains=False).basis()) + [(2, 3), (0, 2), (1, 3), (1, 2), (0, 3), (0, 1)] + sage: list(simplicial_complexes.Sphere(2).n_chains(1, QQ, cochains=True).basis()) + [\chi_(2, 3), \chi_(0, 2), \chi_(1, 3), \chi_(1, 2), \chi_(0, 3), \chi_(0, 1)] + """ + return Chains(tuple(self.n_cells(n)), base_ring, cochains) + + # This is cached for speed reasons: it can be very slow to run + # this function. + @cached_method + def algebraic_topological_model(self, base_ring=None): + r""" + Algebraic topological model, as defined by Pilarczyk and Réal + [PR]_, for this cell complex with coefficients in ``base_ring``. + + This is only implemented for simplicial and cubical complexes. + + INPUT: + + - ``base_ring`` - coefficient ring (optional, default + ``QQ``). Must be a field. + + Denote by `C` the chain complex associated to this cell + complex. The algebraic topological model is a chain complex + `M` with zero differential, with the same homology as `C`, + along with chain maps `\pi: C \to M` and `\iota: M \to C` + satisfying `\iota \pi = 1_M` and `\pi \iota` chain homotopic + to `1_C`. The chain homotopy `H` must satisfy + + - `H \circ H = 0`, + - `\pi H = 0`, + - `H \iota = 0`. + + Such a chain homotopy is called a *chain contraction*. + + OUTPUT: a pair consisting of + + - chain contraction ``H`` associated to `C`, `M`, `\pi`, and + `\iota` + - the chain complex `M` + + Note that from the chain contraction ``H``, one can recover the + chain maps `\pi` and `\iota` via ``H.pi()`` and + ``H.iota()``. Then one can recover `C` and `M` from, for + example, ``H.pi()._domain`` and ``H.pi()._codomain``, + respectively. + + EXAMPLES:: + + sage: from sage.homology.algebraic_topological_model import algebraic_topological_model + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: H, M = RP2.algebraic_topological_model(GF(2)) + sage: M.homology() + {0: Vector space of dimension 1 over Finite Field of size 2, + 1: Vector space of dimension 1 over Finite Field of size 2, + 2: Vector space of dimension 1 over Finite Field of size 2} + sage: T = simplicial_complexes.Torus() + sage: H, M = T.algebraic_topological_model(QQ) + sage: M.homology() + {0: Vector space of dimension 1 over Rational Field, + 1: Vector space of dimension 2 over Rational Field, + 2: Vector space of dimension 1 over Rational Field} + """ + from algebraic_topological_model import algebraic_topological_model + from cubical_complex import CubicalComplex + from simplicial_complex import SimplicialComplex + if not isinstance(self, (CubicalComplex, SimplicialComplex)): + raise NotImplementedError('only implemented for simplicial and cubical complexes') + try: + assert self.is_immutable(), 'the complex must be immutable' + except AttributeError: + # Cubical complexes don't have an is_immutable method, and + # they are always immutable. + pass + return algebraic_topological_model(self, base_ring) + + # This is cached for uniqueness reasons: calling + # K.homology_with_basis(...) twice should yield identical spaces, + # so that one can compare, say, x.cup_product(one) with x (if + # "one" is the identity element in H^0(K)). + @cached_method + def homology_with_basis(self, dim, base_ring=None, cohomology=False): + r""" + Return the unreduced homology in dimension ``dim`` with + coefficients in ``base_ring`` with a chosen basis. Should be + suitable for computing cup products and (in positive + characteristic) cohomology operations. + + This is only implemented for simplicial and cubical complexes. + + INPUTS: + + - ``dim`` -- dimension + - ``base_ring`` -- coefficient ring (optional, default + ``QQ``). Must be a field. + - ``cohomology`` -- boolean (optional, default ``False``). If + ``True``, return cohomology instead of homology. + + Homology basis elements are named 'h_{dim,i}' where i ranges + between 0 and `r-1`, if `r` is the rank of the homology + group. Cohomology basis elements are denoted `h^{dim,i}` + instead. + + EXAMPLES:: + + sage: K = simplicial_complexes.KleinBottle() + sage: K.homology_with_basis(1, QQ) + Free module generated by (h_{1,0},) over Rational Field + sage: K.homology_with_basis(1, GF(2)) + Free module generated by (h_{1,0}, h_{1,1}) over Finite Field of size 2 + """ + from homology_vector_space_with_basis import HomologyVectorSpaceWithBasis + H, M = self.algebraic_topological_model(base_ring) + if cohomology: + H = H.dual() + return HomologyVectorSpaceWithBasis(dim, H, self) + + def cohomology_with_basis(self, dim, base_ring=None): + r""" + Return the unreduced cohomology in dimension ``dim`` with + coefficients in ``base_ring`` with a chosen basis. Should be + suitable for computing cup products and (in positive + characteristic) cohomology operations. + + This is only implemented for simplicial and cubical complexes. + + INPUTS: + + - ``dim`` -- dimension + - ``base_ring`` -- coefficient ring (optional, default + ``QQ``). Must be a field. + + The basis elements are named 'h^{dim,i}' where i ranges + between 0 and `r-1`, if `r` is the rank of the homology group. + + EXAMPLES:: + + sage: K = simplicial_complexes.KleinBottle() + sage: K.cohomology_with_basis(1, QQ) + Free module generated by (h^{1,0},) over Rational Field + sage: K.cohomology_with_basis(1, GF(2)) + Free module generated by (h^{1,0}, h^{1,1}) over Finite Field of size 2 + + sage: H1 = simplicial_complexes.Torus().cohomology_with_basis(1, QQ) + sage: x = H1.basis()[0]; x + h^{1,0} + sage: y = H1.basis()[1]; y + h^{1,1} + + sage: simplicial_complexes.Torus().cohomology_with_basis(2, QQ) + Free module generated by (h^{2,0},) over Rational Field + + You can compute cup products of cohomology classes:: + + sage: x.cup_product(y) + h^{2,0} + sage: y.cup_product(x) + -h^{2,0} + sage: x.cup_product(x) + 0 + """ + return self.homology_with_basis(dim, base_ring, cohomology=True) + + # This is cached for speed reasons: it can be very slow to run + # this function. + @cached_method + def cohomology_ring(self, base_ring=None): + """ + The cohomology ring of this cell complex, with field coefficients. + + This is only implemented for simplicial and cubical complexes. + + INPUT: + + - ``base_ring`` -- coefficient ring (optional, default + ``QQ``). Must be a field. + + This returns a finite-dimensional algebra: more precisely, an + instance of + :class:`sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra.FiniteDimensionalAlgebra`. Thus + the defining data are the matrices which define right + multiplication by each basis element. + + EXAMPLES:: + + sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) + sage: H = RP3.cohomology_ring(GF(2)) + sage: H + Finite-dimensional algebra of degree 4 over Finite Field of size 2 + sage: H.basis() + [h00, h10, h20, h30] + + The matrices specifying right multiplication by each basis element:: + + sage: H.table() + [ + [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] + [0 1 0 0] [0 0 1 0] [0 0 0 1] [0 0 0 0] + [0 0 1 0] [0 0 0 1] [0 0 0 0] [0 0 0 0] + [0 0 0 1], [0 0 0 0], [0 0 0 0], [0 0 0 0] + ] + sage: H.is_associative() + True + sage: H.is_commutative() # True because it's characteristic 2. + True + sage: T = cubical_complexes.Torus() + sage: T.cohomology_ring(QQ).is_commutative() + False + """ + from sage.matrix.constructor import matrix + from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra + if base_ring is None: + base_ring = QQ + # First construct the basis. This is a dictionary with keys + # (d, i): d is the degree of the cohomology class, i ranges + # from 0 to r-1, if r is the rank of H^d. List these elements + # in order of increasing d and i; then the value for each key + # is just its index. + basis = {} + idx = 0 + for d in range(self.dimension()+1): + for i in range(self.cohomology_with_basis(d, base_ring=base_ring).dimension()): + basis[(d,i)] = idx + idx += 1 + + # Now iterate over each basis element, in order, to construct + # the list of matrices representing right multiplication by + # each basis element. + matrices = [] + rank = len(basis) + for y in sorted(basis): + y_matrix_dict = {} + y_elt = self.cohomology_with_basis(y[0], base_ring).basis()[y[1]] + for x in basis: + x_elt = self.cohomology_with_basis(x[0], base_ring).basis()[x[1]] + z = x_elt.cup_product(y_elt) + d = z.parent().degree() + idx = basis[x] + try: + start = basis[(d,0)] + except KeyError: + # No cohomology in this degree. + pass + z_vec = z.to_vector() + for j in range(z_vec.degree()): + y_matrix_dict[(idx, start+j)] = z_vec[j] + # Use dense matrices because of a bug: try using sparse + # matrices and mod 2 coefficients, and run the method + # "is_unitary()" on the ring. See trac 19165. + matrices.append(matrix(base_ring, rank, rank, y_matrix_dict, sparse=False)) + names = ['h{}{}'.format(y[0], y[1]) for y in sorted(basis)] + return FiniteDimensionalAlgebra(base_ring, table=matrices, names=names) + ############################################################ # end of chain complexes, homology ############################################################ @@ -784,3 +1061,124 @@ def _repr_(self): else: cells_string = " and 1 %s" % cell_name return Name + " complex " + vertex_string + cells_string + + +class Chains(CombinatorialFreeModule): + r""" + Class for the free module of chains and/or cochains in a given + degree. + + INPUT: + + - ``n_cells`` -- tuple of `n`-cells, which thus forms a basis for + this module + - ``base_ring`` -- optional (default `\ZZ`) + - ``cochains`` -- boolean (optional, default ``False``). If + ``True``, return cochains instead. + + One difference between chains and cochains is notation. In a + simplicial complex, for example, a simplex ``(0,1,2)`` is written + as "(0,1,2)" in the group of chains but as "\\chi_(0,1,2)" in the + group of cochains. + + Also, since the free modules of chains and cochains are dual, + there is a pairing `\langle c, z \rangle`, sending a cochain `c` + and a chain `z` to a scalar. + + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: C_2 = S2.n_chains(1) + sage: C_2_co = S2.n_chains(1, cochains=True) + sage: x = C_2.basis()[Simplex((0,2))] + sage: y = C_2.basis()[Simplex((1,3))] + sage: z = x+2*y + sage: a = C_2_co.basis()[Simplex((1,3))] + sage: b = C_2_co.basis()[Simplex((0,3))] + sage: c = 3*a-2*b + sage: z + (0, 2) + 2*(1, 3) + sage: c + -2*\chi_(0, 3) + 3*\chi_(1, 3) + sage: c.eval(z) + 6 + """ + def __init__(self, n_cells, base_ring=None, cochains=False): + """ + EXAMPLES:: + + sage: T = cubical_complexes.Torus() + sage: T.n_chains(2, QQ) + Free module generated by {[1,1] x [0,1] x [1,1] x [0,1], [0,0] x [0,1] x [0,1] x [1,1], [0,0] x [0,1] x [1,1] x [0,1], [0,0] x [0,1] x [0,0] x [0,1], [0,1] x [1,1] x [0,1] x [0,0], [0,1] x [0,0] x [0,0] x [0,1], [1,1] x [0,1] x [0,1] x [0,0], [0,1] x [1,1] x [0,0] x [0,1], [0,0] x [0,1] x [0,1] x [0,0], [0,1] x [0,0] x [0,1] x [0,0], [0,1] x [0,0] x [1,1] x [0,1], [0,1] x [1,1] x [1,1] x [0,1], [0,1] x [0,0] x [0,1] x [1,1], [1,1] x [0,1] x [0,0] x [0,1], [1,1] x [0,1] x [0,1] x [1,1], [0,1] x [1,1] x [0,1] x [1,1]} over Rational Field + sage: T.n_chains(2).dimension() + 16 + + TESTS:: + + sage: T.n_chains(2).base_ring() + Integer Ring + sage: T.n_chains(8).dimension() + 0 + sage: T.n_chains(-3).dimension() + 0 + """ + if base_ring is None: + base_ring=ZZ + self._cochains = cochains + if cochains: + CombinatorialFreeModule.__init__(self, base_ring, n_cells, + prefix='\\chi', bracket=['_', '']) + else: + CombinatorialFreeModule.__init__(self, base_ring, n_cells, + prefix='', bracket=False) + + class Element(CombinatorialFreeModuleElement): + + def eval(self, other): + """ + Evaluate this cochain on the chain ``other``. + + INPUT: + + - ``other`` -- a chain for the same cell complex in the + same dimension with the same base ring + + OUTPUT: scalar + + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: C_2 = S2.n_chains(1) + sage: C_2_co = S2.n_chains(1, cochains=True) + sage: x = C_2.basis()[Simplex((0,2))] + sage: y = C_2.basis()[Simplex((1,3))] + sage: z = x+2*y + sage: a = C_2_co.basis()[Simplex((1,3))] + sage: b = C_2_co.basis()[Simplex((0,3))] + sage: c = 3*a-2*b + sage: z + (0, 2) + 2*(1, 3) + sage: c + -2*\chi_(0, 3) + 3*\chi_(1, 3) + sage: c.eval(z) + 6 + + TESTS:: + + sage: z.eval(c) # z is not a cochain + Traceback (most recent call last): + ... + ValueError: this element is not a cochain + sage: c.eval(c) # can't evaluate a cochain on a cochain + Traceback (most recent call last): + ... + AssertionError: the elements are not compatible + """ + if self.parent()._cochains: + assert (other.parent().indices() == self.parent().indices() + and other.base_ring() == self.base_ring() + and not other.parent()._cochains), 'the elements are not compatible' + result = sum(coeff * other.coefficient(cell) for cell, coeff in self) + return result + else: + raise ValueError('this element is not a cochain') diff --git a/src/sage/homology/cubical_complex.py b/src/sage/homology/cubical_complex.py index c0dc67555ea..07464e200c2 100644 --- a/src/sage/homology/cubical_complex.py +++ b/src/sage/homology/cubical_complex.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Finite cubical complexes @@ -547,6 +548,67 @@ def _triangulation_(self): simplices.append(S.join(Simplex((v,)), rename_vertices=False)) return simplices + def alexander_whitney(self, dim): + r""" + Subdivide this cube into pairs of cubes. + + This provides a cubical approximation for the diagonal map `K + \to K \times K`. + + INPUTS: + + - ``dim`` -- integer between 0 and one more than the + dimension of this cube + + OUTPUT: + + - a list containing triples ``(coeff, left, right)`` + + This uses the algorithm described by Pilarczyk and Réal [PR]_ + on p. 267; the formula is originally due to Serre. Calling + this method ``alexander_whitney`` is an abuse of notation, + since the actual Alexander-Whitney map goes from `C(K \times + L) \to C(K) \otimes C(L)`, where `C(-)` denotes the associated + chain complex, but this subdivision of cubes is at the heart + of it. + + EXAMPLES:: + + sage: from sage.homology.cubical_complex import Cube + sage: C1 = Cube([[0,1], [3,4]]) + sage: C1.alexander_whitney(0) + [(1, [0,0] x [3,3], [0,1] x [3,4])] + sage: C1.alexander_whitney(1) + [(1, [0,1] x [3,3], [1,1] x [3,4]), (-1, [0,0] x [3,4], [0,1] x [4,4])] + sage: C1.alexander_whitney(2) + [(1, [0,1] x [3,4], [1,1] x [4,4])] + """ + from sage.sets.set import Set + N = Set(self.nondegenerate_intervals()) + result = [] + for J in N.subsets(dim): + Jprime = N.difference(J) + nu = 0 + for i in J: + for j in Jprime: + if j +# +# 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.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement + +class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): + """Homology (or cohomology) vector space. + + This is intended to provide enough structure to allow the + computation of cup products and cohomology operations. The former + has been implemented, but not the latter (yet). + + It also requires field coefficients (hence the "VectorSpace" in + the name of the class). + + .. note:: + + This is not intended to be used directly by the user, but instead + via the methods + :meth:`cell_complex.CellComplex.homology_with_basis` and + :meth:`cell_complex.CellComplex.cohomology_with_basis`. + + EXAMPLES: + + Homology classes are denoted by ``h_{d,i}`` where ``d`` is the + degree of the homology class and ``i`` is their index in the list + of basis elements. Cohomology classes are denoted ``h^{1,0}``:: + + sage: RP2 = cubical_complexes.RealProjectivePlane() + sage: RP2.homology_with_basis(1, GF(2)) + Free module generated by (h_{1,0},) over Finite Field of size 2 + sage: RP2.cohomology_with_basis(1, GF(2)) + Free module generated by (h^{1,0},) over Finite Field of size 2 + sage: simplicial_complexes.Torus().homology_with_basis(1, QQ) + Free module generated by (h_{1,0}, h_{1,1}) over Rational Field + + To access a basis element, use its index (0 or 1 in the 1st + cohomology group of a torus):: + + sage: H1 = simplicial_complexes.Torus().cohomology_with_basis(1, QQ) + sage: H1.indices() + {0, 1} + sage: H1.basis()[0] + h^{1,0} + sage: H1.basis()[1] + h^{1,1} + + You can then form linear combinations of these easily enough:: + + sage: x = H1.basis()[0] + sage: y = H1.basis()[1] + sage: 2*x-3*y + 2*h^{1,0} - 3*h^{1,1} + + Or you can use the :meth:`from_vector` method to do this in one step:: + + sage: H1.from_vector(vector((2, -3))) + 2*h^{1,0} - 3*h^{1,1} + + You can compute cup products of cohomology classes:: + + sage: x.cup_product(y) + h^{2,0} + sage: y.cup_product(x) + -h^{2,0} + sage: x.cup_product(x) + 0 + + This works with both simplicial complexes and cubical complexes:: + + sage: Klein_c = cubical_complexes.KleinBottle() + sage: H1 = Klein_c.cohomology_with_basis(1, GF(2)) + sage: x,y = H1.basis() + sage: x.cup_product(x) + h^{2,0} + sage: x.cup_product(y) + 0 + sage: y.cup_product(y) + h^{2,0} + + sage: Klein_s = simplicial_complexes.KleinBottle() + sage: H1 = Klein_s.cohomology_with_basis(1, GF(2)) + sage: a,b = H1.basis() + + The basis elements have been chosen differently; apply the change + of basis `x \mapsto a+b`, `y \mapsto b` to see the same product + structure. :: + + sage: a.cup_product(a) + 0 + sage: a.cup_product(b) + h^{2,0} + sage: (a+b).cup_product(a+b) + h^{2,0} + sage: b.cup_product(b) + h^{2,0} + + """ + def __init__(self, deg, contraction, cell_complex): + """ + INPUTS: + + - ``deg`` -- the degree of this homology group + - ``contraction`` -- the chain contraction associated to this + homology computation + - ``cell_complex`` -- the cell complex whose homology we are + computing + + EXAMPLES:: + + sage: RP2 = simplicial_complexes.ProjectivePlane() + sage: RP2.homology_with_basis(1, QQ) # indirect doctest + Free module generated by () over Rational Field + sage: RP2.homology_with_basis(1, GF(2)) + Free module generated by (h_{1,0},) over Finite Field of size 2 + sage: RP2.cohomology_with_basis(1, GF(2)) + Free module generated by (h^{1,0},) over Finite Field of size 2 + sage: RP2.cohomology_with_basis(1, GF(5)) + Free module generated by () over Finite Field of size 5 + """ + self._contraction = contraction + # M is the homology chain complex. + M = self._contraction.pi()._codomain + self._degree = deg + self._complex = cell_complex + rank = M.free_module_rank(deg) + # Homology vs. cohomology is detected by the degree of the + # differential in the relevant chain complexes: + self._cohomology = (M.degree_of_differential() == 1) + CombinatorialFreeModule.__init__(self, M.base_ring(), range(rank)) + + def degree(self): + """ + The degree of this homology group: if this is `H_n(K)` for some + complex `K`, return `n`. + + EXAMPLES:: + + sage: H2 = simplicial_complexes.Torus().homology_with_basis(2, GF(7)) + sage: H2.degree() + 2 + """ + return self._degree + + def contraction(self): + r""" + The chain contraction associated to this homology computation. + + That is, to work with chain representatives of homology + classes, we need the chain complex `C` associated to the cell + complex, the chain complex `H` of its homology (with trivial + differential), chain maps `\pi: C \to H` and `\iota: H \to C`, + and a chain contraction `\phi` giving a chain homotopy between + `1_C` and `\iota \circ \pi`. + + OUTPUT: `\phi` + + See :class:`chain_homotopy.ChainContraction` for information + about chain contractions, and see + :func:`algebraic_topological_model.algebraic_topological_model` + for the construction of this particular chain contraction + `\phi`. + + EXAMPLES:: + + sage: H1 = simplicial_complexes.Simplex(2).homology_with_basis(1, QQ) + sage: H1.contraction() + Chain homotopy between Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field and Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + + From the chain contraction, one can also recover the maps `\pi` and `\iota`:: + + sage: phi = H1.contraction() + sage: phi.pi() + Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 1 nonzero terms over Rational Field + sage: phi.iota() + Chain complex morphism from Chain complex with at most 1 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + """ + return self._contraction + + def complex(self): + """ + The cell complex whose homology is being computed. + + EXAMPLES:: + + sage: H1 = simplicial_complexes.Simplex(2).homology_with_basis(1, QQ) + sage: H1.complex() + Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)} + """ + return self._complex + + def _repr_(self): + """ + EXAMPLES:: + + sage: simplicial_complexes.Torus().homology_with_basis(1, QQ) + Free module generated by (h_{1,0}, h_{1,1}) over Rational Field + """ + return "Free module generated by {} over {}".format(tuple(self.basis()), self.base_ring()) + + def _repr_term(self, i): + """ + Return 'h_{d,i}' for the ith generator in degree d for homology, + 'h^{d,i}' for cohomology. + + EXAMPLES:: + + sage: H1 = simplicial_complexes.Torus().homology_with_basis(1, QQ) + sage: H1.basis()[0] # indirect doctest + h_{1,0} + sage: latex(H1.basis()[1]) # indirect doctest + h_{1,1} + sage: co = simplicial_complexes.KleinBottle().homology_with_basis(1, GF(2), cohomology=True) + sage: co.basis()[0] # indirect doctest + h^{1,0} + """ + sym = '^' if self._cohomology else '_' + return 'h{}{{{},{}}}'.format(sym, self.degree(), i) + + _latex_term = _repr_term + + # We need an element class so we can apply iota to the elements, + # compute cup products, Steenrod operations, etc. + + class Element(CombinatorialFreeModuleElement): + + def to_cycle(self): + r""" + (Co)cycle representative of this (co)homology class. + + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: H2 = S2.homology_with_basis(2, QQ) + sage: H2.basis()[0] + h_{2,0} + sage: H2.basis()[0].to_cycle() + -(0, 1, 2) + (0, 1, 3) - (0, 2, 3) + (1, 2, 3) + + Chains are written as linear combinations of simplices + `\sigma`. Cochains are written as linear combinations of + characteristic functions `\chi_{\sigma}` for those + simplices:: + + sage: S2.cohomology_with_basis(2, QQ).basis()[0].to_cycle() + \chi_(0, 1, 3) + sage: S2.cohomology_with_basis(0, QQ).basis()[0].to_cycle() + \chi_(0,) + \chi_(1,) + \chi_(2,) + \chi_(3,) + """ + deg = self.parent().degree() + vec = self.parent().contraction().iota().in_degree(deg) * self.to_vector() + chains = self.parent().complex().n_chains(deg, self.base_ring(), + cochains=self.parent()._cohomology) + return chains.from_vector(vec) + + def cup_product(self, other): + r""" + The cup product of this element with ``other``. + + INPUTS: + + - ``other`` -- a cohomology class from the same cell complex. + + Algorithm: see González-Díaz and Réal [G-DR03]_, p. 88. + Given two cohomology classes, lift them to cocycle + representatives using :meth:`to_cycle`. In the sum of + their dimensions, look at all of the homology classes + `\gamma`: lift each of those to a cycle representative, + apply the Alexander-Whitney diagonal map to each cell in + the cycle, evaluate the two cocycles on these factors, and + multiply. The result is the value of the cup product + cocycle on this homology class. After this has been done + for all homology classes, since homology and cohomology + are dual, one can tell which cohomology class corresponds + to the cup product. + + EXAMPLES:: + + sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) + sage: H1 = RP3.cohomology_with_basis(1, GF(2)) + sage: c = H1.basis()[0] + sage: c.cup_product(c).cup_product(c) + h^{3,0} + + sage: T = simplicial_complexes.Torus() + sage: x,y = list(T.cohomology_with_basis(1, QQ).basis()) + sage: x.cup_product(y) + h^{2,0} + sage: x.cup_product(x) + 0 + + sage: one = T.cohomology_with_basis(0, QQ).basis()[0] + sage: x.cup_product(one) + h^{1,0} + sage: one.cup_product(y) == y + True + sage: one.cup_product(one) + h^{0,0} + sage: x.cup_product(y) + y.cup_product(x) + 0 + + This also works with cubical complexes:: + + sage: T = cubical_complexes.Torus() + sage: x,y = list(T.cohomology_with_basis(1, QQ).basis()) + sage: x.cup_product(y) + -h^{2,0} + sage: x.cup_product(x) + 0 + """ + complex = self.parent().complex() + base_ring = self.base_ring() + assert (complex == other.parent().complex() + and self.parent()._cohomology + and other.parent()._cohomology), 'these are not cohomology classes from the same complex' + deg_left = self.parent().degree() + deg_right = other.parent().degree() + deg_tot = deg_left + deg_right + result = [] + for gamma in complex.homology_with_basis(deg_tot, base_ring).basis(): + gamma_coeff = base_ring.zero() + for cell, coeff in gamma.to_cycle(): + for (c, left_cell, right_cell) in cell.alexander_whitney(deg_left): + left = complex.n_chains(deg_left, base_ring)(left_cell) + right = complex.n_chains(deg_right, base_ring)(right_cell) + gamma_coeff += c * coeff * self.to_cycle().eval(left) * other.to_cycle().eval(right) + result.append((gamma.leading_support(), gamma_coeff)) + return complex.cohomology_with_basis(deg_tot, base_ring).sum_of_terms(result) + + def Sq(self, i): + r""" + Return the result of applying Sq^i to this element. + + INPUT: + + - ``i`` -- nonnegative integer + + .. warning:: + + This is only implemented for simplicial complexes, not + cubical complexes. + + This cohomology operation is only defined in + characteristic 2. + + Algorithm: see González-Díaz and Réal [G-DR99]_, Corollary + 3.2. + + EXAMPLES:: + + sage: RP2 = simplicial_complexes.RealProjectiveSpace(2) + sage: x = RP2.cohomology_with_basis(1, GF(2)).basis()[0] + sage: x.Sq(1) + h^{2,0} + + sage: K = RP2.suspension() + sage: K.set_immutable() + sage: y = K.cohomology_with_basis(2, GF(2)).basis()[0] + sage: y.Sq(1) + h^{3,0} + + sage: RP4 = simplicial_complexes.RealProjectiveSpace(4) + sage: x = RP4.cohomology_with_basis(1, GF(2)).basis()[0] # long time + sage: y = RP4.cohomology_with_basis(2, GF(2)).basis()[0] # long time + sage: z = RP4.cohomology_with_basis(3, GF(2)).basis()[0] # long time + sage: x.Sq(1) # long time + h^{2,0} + sage: y.Sq(1) # long time + 0 + sage: y.Sq(2) # long time + h^{4,0} + sage: z.Sq(1) # long time + h^{4,0} + + TESTS:: + + sage: T = cubical_complexes.Torus() + sage: x = T.cohomology_with_basis(1, GF(2)).basis()[0] + sage: x.Sq(1) + Traceback (most recent call last): + ... + NotImplementedError: Steenrod squares are only implemented for simplicial complexes + sage: S2 = simplicial_complexes.Sphere(2) + sage: x = S2.cohomology_with_basis(2, GF(7)).basis()[0] + sage: x.Sq(1) + Traceback (most recent call last): + ... + ValueError: Steenrod squares are only defined in characteristic 2 + """ + from simplicial_complex import SimplicialComplex + complex = self.parent().complex() + if not isinstance(complex, SimplicialComplex): + raise NotImplementedError('Steenrod squares are only implemented for simplicial complexes') + base_ring = self.base_ring() + if base_ring.characteristic() != 2: + raise ValueError('Steenrod squares are only defined in characteristic 2') + # We keep the same notation as in [G-DR99]. + j = self.parent().degree() + m = j+i + # The trivial cases: + if i == 0: + # Sq^0 is the identity. + return self + target = complex.cohomology_with_basis(m, base_ring) + if target.dimension() == 0: + return target.zero() + if i > j: + return target.zero() + if i == j: + return self.cup_product(self) + n = j-i + # Now assemble the indices over which the sums take place. + # S(n) is defined to be floor((m+1)/2) + floor(n/2). + S_n = (m+1)//2 + n//2 + if n == 0: + sums = [[S_n]] + else: + sums = [] + for i_n in range(S_n, m+1): + sums.extend([[i_n] + _ for _ in sum_indices(n-1, i_n, S_n)]) + # At this point, 'sums' is a list of lists of the form + # [i_n, i_{n-1}, ..., i_0]. (It is reversed from the + # obvious order because this is closer to the order in + # which the face maps will be applied.) Now we sum over + # these, according to the formula in [G-DR99], Corollary + # 3.2. + result = [] + cycle = self.to_cycle() + for gamma in complex.homology_with_basis(m, base_ring).basis(): + gamma_coeff = base_ring.zero() + for cell, coeff in gamma.to_cycle(): + for indices in sums: + indices = list(indices) + left = cell + right = cell + # Since we are working with a simplicial complex, 'cell' is a simplex. + if not m % 2: + left_endpoint = m + while indices: + right_endpoint = indices[0]-1 + for k in range(left_endpoint, indices.pop(0), -1): + left = left.face(k) + try: + left_endpoint = indices[0]-1 + for k in range(right_endpoint, indices.pop(0), -1): + right = right.face(k) + except IndexError: + pass + for k in range(right_endpoint, -1, -1): + right = right.face(k) + else: + right_endpoint = m + while indices: + left_endpoint = indices[0]-1 + try: + for k in range(right_endpoint, indices.pop(0), -1): + right = right.face(k) + right_endpoint = indices[0]-1 + except IndexError: + pass + for k in range(left_endpoint, indices.pop(0), -1): + left = left.face(k) + for k in range(right_endpoint, -1, -1): + right = right.face(k) + + left = complex.n_chains(j, base_ring)(left) + right = complex.n_chains(j, base_ring)(right) + gamma_coeff += coeff * cycle.eval(left) * cycle.eval(right) + result.append((gamma.leading_support(), gamma_coeff)) + return complex.cohomology_with_basis(m, base_ring).sum_of_terms(result) + + +def sum_indices(k, i_k_plus_one, S_k_plus_one): + """This is a recursive function for computing the indices for the + nested sums in González-Díaz and Réal [G-DR99]_, Corollary 3.2. + + In the paper, given indices `i_n`, `i_{n-1}`, ..., `i_{k+1}`, + given `k`, and given `S(k+1)`, the number `S(k)` is defined to be + + .. math:: + + S(k) = -S(k+1) + floor(k/2) + floor((k+1)/2) + i_{k+1}, + + and `i_k` ranges from `S(k)` to `i_{k+1}-1`. There are two special + cases: if `k=0`, then `i_0 = S(0)`. Also, the initial case of + `S(k)` is `S(n)`, which is set in the method :meth:`Sq` before + calling this function. For this function, given `k`, `i_{k+1}`, + and `S(k+1)`, return a list consisting of the allowable possible + indices `[i_k, i_{k-1}, ..., i_1, i_0]` given by the above + formula. + + INPUTS: + + - ``k`` -- non-negative integer + - ``i_k_plus_one`` -- the positive integer `i_{k+1}` + - ``S_k_plus_one`` -- the integer `S(k+1)` + + EXAMPLES:: + + sage: from sage.homology.homology_vector_space_with_basis import sum_indices + sage: sum_indices(1, 3, 3) + [[1, 0], [2, 1]] + sage: sum_indices(0, 4, 2) + [[2]] + + """ + S_k = -S_k_plus_one + k//2 + (k+1)//2 + i_k_plus_one + if k == 0: + return [[S_k]] + ans = [] + for i_k in range(S_k, i_k_plus_one): + ans.extend([[i_k] + _ for _ in sum_indices(k-1, i_k, S_k)]) + return ans + diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index c8c188552f6..8b8bc58b6d3 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -625,6 +625,50 @@ def product(self, other, rename_vertices=True): answer.append(Simplex(new)) return answer + def alexander_whitney(self, dim): + r""" + Subdivide this simplex into a pair of simplices. + + If this simplex has vertices `v_0`, `v_1`, ..., `v_n`, then + subdivide it into simplices `(v_0, v_1, ..., v_{dim})` and + `(v_{dim}, v_{dim + 1}, ..., v_n)`. + + INPUTS: + + - ``dim`` -- integer between 0 and one more than the + dimension of this simplex + + OUTPUT: + + - a list containing just the triple ``(1, left, right)``, + where ``left`` and ``right`` are the two simplices described + above. + + This method allows one to construct a coproduct from the + `p+q`-chains to the tensor product of the `p`-chains and the + `q`-chains. The number 1 (a Sage integer) is the coefficient + of ``left tensor right`` in this coproduct. (The corresponding + formula is more complicated for the cubes that make up a + cubical complex, and the output format is intended to be + consistent for both cubes and simplices.) + + Calling this method ``alexander_whitney`` is an abuse of + notation, since the actual Alexander-Whitney map goes from + `C(X \times Y) \to C(X) \otimes C(Y)`, where `C(-)` denotes + the chain complex of singular chains, but this subdivision of + simplices is at the heart of it. + + EXAMPLES:: + + sage: s = Simplex((0,1,3,4)) + sage: s.alexander_whitney(0) + [(1, (0,), (0, 1, 3, 4))] + sage: s.alexander_whitney(2) + [(1, (0, 1, 3), (3, 4))] + """ + return [(ZZ.one(), Simplex(self.tuple()[:dim+1]), + Simplex(self.tuple()[dim:]))] + def __cmp__(self, other): """ Return ``True`` iff this simplex is the same as ``other``: that From 752721d9bd5757fb911f9c92faed16248ea92d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Thu, 10 Sep 2015 15:37:48 +0300 Subject: [PATCH 0825/1872] Change strategy: Don't even try with non-facade posets. --- src/sage/combinat/posets/posets.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 39c93f3cce6..d42f76381a2 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -139,6 +139,7 @@ :delim: | :meth:`~FinitePoset.is_isomorphic` | Return ``True`` if both posets are isomorphic. + :meth:`~FinitePoset.is_subposet` | Return ``True`` if give poset is an induced subposet of this poset. **Polynomials** @@ -5631,10 +5632,7 @@ def is_subposet(self, other): TESTS:: - sage: P = Poset({2:[1]}, facade=True) - sage: Q = Poset({2:[1]}, facade=False) - sage: P.is_subposet(Q), Q.is_subposet(P) - (True, True) + sage: P = Poset({2:[1]}) sage: Poset().is_subposet(P) True sage: Poset().is_subposet(Poset()) @@ -5643,11 +5641,11 @@ def is_subposet(self, other): False """ if not hasattr(other, 'hasse_diagram'): - raise ValueError('the input is not a finite poset') - self_ = Poset(self, facade=True) - other_ = Poset(other, facade=True) - return (set(self_).issubset(set(other_)) and - other_.subposet(self_) == self_) + raise TypeError('the input is not a finite poset') + if not self._is_facade or not other._is_facade: + raise TypeError('the function is not defined on non-facade posets') + return (set(self).issubset(set(other)) and + other.subposet(self) == self) FinitePoset._dual_class = FinitePoset From 08f4ad4c68c66484199c66a0fc20d02fd5bd0469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Thu, 10 Sep 2015 15:39:24 +0300 Subject: [PATCH 0826/1872] A typo. --- src/sage/combinat/posets/posets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index d42f76381a2..0dc6aa1bf97 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -139,7 +139,7 @@ :delim: | :meth:`~FinitePoset.is_isomorphic` | Return ``True`` if both posets are isomorphic. - :meth:`~FinitePoset.is_subposet` | Return ``True`` if give poset is an induced subposet of this poset. + :meth:`~FinitePoset.is_subposet` | Return ``True`` if given poset is an induced subposet of this poset. **Polynomials** From d7b9ed4072c3d96edf1ab67c7e61f19bff91b0b7 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 10 Sep 2015 08:17:51 -0700 Subject: [PATCH 0827/1872] change AssertionError to other errors --- src/sage/homology/chain_homotopy.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index 868a51b43a2..f3e83c286a2 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -156,7 +156,7 @@ def __init__(self, matrices, f, g=None): sage: H = ChainHomotopy(H_d, f, g) Traceback (most recent call last): ... - AssertionError: the chain maps are not compatible + ValueError: the chain maps are not compatible """ domain = f._domain codomain = f._codomain @@ -168,8 +168,9 @@ def __init__(self, matrices, f, g=None): codomain.degree_of_differential()), 'the chain complexes are not compatible' if g: # Check that the chain maps are compatible. - assert (domain == g._domain and codomain == - g._codomain), 'the chain maps are not compatible' + if not (domain == g._domain and codomain == + g._codomain): + raise ValueError('the chain maps are not compatible') # Check that the data define a chain homotopy. for i in domain.differential(): if i in matrices and i+deg in matrices: @@ -232,9 +233,7 @@ def is_algebraic_gradient_vector_field(self): sage: H.is_algebraic_gradient_vector_field() False """ - try: - assert self._domain == self._codomain - except AssertionError: + if self._domain != self._codomain: return False deg = self._domain.degree_of_differential() matrices = self._matrix_dictionary @@ -420,7 +419,7 @@ def __init__(self, matrices, pi, iota): sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota) Traceback (most recent call last): ... - AssertionError: the chain maps are not composable + ValueError: the chain maps are not composable `\iota` is okay, but wrong data defining `H`:: @@ -428,13 +427,14 @@ def __init__(self, matrices, pi, iota): sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota) Traceback (most recent call last): ... - AssertionError: not an algebraic gradient vector field + ValueError: not an algebraic gradient vector field """ from sage.matrix.constructor import identity_matrix from chain_complex_morphism import ChainComplexMorphism - assert (pi._domain == iota._codomain - and pi._codomain == iota._domain), 'the chain maps are not composable' + if not (pi._domain == iota._codomain + and pi._codomain == iota._domain): + raise ValueError('the chain maps are not composable') C = pi._domain D = pi._codomain base_ring = C.base_ring() @@ -454,7 +454,8 @@ def __init__(self, matrices, pi, iota): # - `H` is a chain homotopy between `id_C` and `\iota \pi` # - `HH = 0` ChainHomotopy.__init__(self, matrices, id_C, iota * pi) - assert self.is_algebraic_gradient_vector_field(), 'not an algebraic gradient vector field' + if not self.is_algebraic_gradient_vector_field(): + raise ValueError('not an algebraic gradient vector field') # Check that `\pi H = 0`: deg = C.degree_of_differential() for i in matrices: From c0918b809f2f7ec04b87b75f218e132061bcf782 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 10 Sep 2015 08:23:55 -0700 Subject: [PATCH 0828/1872] change AttributeErrors to other errors --- src/sage/homology/cell_complex.py | 10 ++++++---- src/sage/homology/homology_vector_space_with_basis.py | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 8c81c2aae41..6645dcff009 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -743,7 +743,8 @@ def algebraic_topological_model(self, base_ring=None): if not isinstance(self, (CubicalComplex, SimplicialComplex)): raise NotImplementedError('only implemented for simplicial and cubical complexes') try: - assert self.is_immutable(), 'the complex must be immutable' + if not self.is_immutable(): + raise ValueError('the complex must be immutable') except AttributeError: # Cubical complexes don't have an is_immutable method, and # they are always immutable. @@ -1172,12 +1173,13 @@ def eval(self, other): sage: c.eval(c) # can't evaluate a cochain on a cochain Traceback (most recent call last): ... - AssertionError: the elements are not compatible + ValueError: the elements are not compatible """ if self.parent()._cochains: - assert (other.parent().indices() == self.parent().indices() + if not (other.parent().indices() == self.parent().indices() and other.base_ring() == self.base_ring() - and not other.parent()._cochains), 'the elements are not compatible' + and not other.parent()._cochains): + raise ValueError('the elements are not compatible') result = sum(coeff * other.coefficient(cell) for cell, coeff in self) return result else: diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 772a8b87603..f6e7ba78e90 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -340,9 +340,10 @@ def cup_product(self, other): """ complex = self.parent().complex() base_ring = self.base_ring() - assert (complex == other.parent().complex() + if not (complex == other.parent().complex() and self.parent()._cohomology - and other.parent()._cohomology), 'these are not cohomology classes from the same complex' + and other.parent()._cohomology): + raise ValueError('these are not cohomology classes from the same complex') deg_left = self.parent().degree() deg_right = other.parent().degree() deg_tot = deg_left + deg_right From 698ba79f9837c3c2e83bd358441b4cd4a4073392 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 10 Sep 2015 15:06:51 -0700 Subject: [PATCH 0829/1872] trac 6101: maps in (co)homology induced by simplicial maps --- src/sage/homology/homology_morphism.py | 261 ++++++++++++++++++ .../homology/simplicial_complex_homset.py | 4 +- .../homology/simplicial_complex_morphism.py | 61 ++++ 3 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 src/sage/homology/homology_morphism.py diff --git a/src/sage/homology/homology_morphism.py b/src/sage/homology/homology_morphism.py new file mode 100644 index 00000000000..2dd73fce323 --- /dev/null +++ b/src/sage/homology/homology_morphism.py @@ -0,0 +1,261 @@ +r""" +Induced morphisms on homology + +This module implements morphisms on homology induced by morphisms of +simplicial complexes. It requires working with field coefficients. + +See :class:`InducedHomologyMorphism` for documentation. + +AUTHORS: + +- John H. Palmieri (2015.09) +""" + +######################################################################## +# Copyright (C) 2015 John H. Palmieri +# +# 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/ +######################################################################## + +# To do: implement morphisms of cubical complexes, with methods +# - domain +# - codomain +# - associated_chain_complex_morphism +# Once this is done, the code here ought to work without modification. + +from sage.structure.sage_object import SageObject +from sage.rings.rational_field import QQ + +class InducedHomologyMorphism(SageObject): + """ + An element of this class is a morphism of (co)homology groups + induced by a map of simplicial complexes. It requires working + with field coefficients. + + INPUTS: + + - ``map`` -- the map of simplicial complexes + - ``base_ring`` -- a field (optional, default ``QQ``) + - ``cohomology`` -- boolean (optional, default ``False``). If + ``True``, return the induced map in cohomology rather than + homology. + + .. note:: + + This is not intended to be used directly by the user, but instead + via the method + :meth:`simplicial_complex_morphism.SimplicialComplexMorphism.induced_homology_morphism`. + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: H = Hom(S1, S1) + sage: f = H({0:0, 1:2, 2:1}) # f switches two vertices + sage: f_star = f.induced_homology_morphism(QQ, cohomology=True) + sage: f_star.to_matrix(1) + [-1] + + sage: T = simplicial_complexes.Torus() + sage: y = T.homology_with_basis(1, QQ).basis()[1] + sage: y.to_cycle() + (0, 3) - (0, 6) + (3, 6) + + Since `(0,3) - (0,6) + (3,6)` is a cycle representing a homology + class in the torus, we can define a map `S^1 \to T` inducing an + inclusion on `H_1`:: + + sage: Hom(S1, T)({0:0, 1:3, 2: 6}) + Simplicial complex morphism {0: 0, 1: 3, 2: 6} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6) and 14 facets + sage: g = Hom(S1, T)({0:0, 1:3, 2: 6}) + sage: g_star = g.induced_homology_morphism(QQ) + sage: g_star.to_matrix(0) + [1] + sage: g_star.to_matrix(1) + [0] + [1] + """ + def __init__(self, map, base_ring=None, cohomology=False): + """ + INPUTS: + + - ``map`` -- the map of simplicial complexes + - ``base_ring`` -- a field (optional, default ``QQ``) + - ``cohomology`` -- boolean (optional, default ``False``). If + ``True``, return the induced map in cohomology rather than + homology. + + EXAMPLES:: + + sage: from sage.homology.homology_morphism import InducedHomologyMorphism + sage: K = simplicial_complexes.RandomComplex(8, 3) + sage: H = Hom(K,K) + sage: id = H.identity() + sage: f = InducedHomologyMorphism(id, QQ) + sage: f.to_matrix(0) == 1 and f.to_matrix(1) == 1 and f.to_matrix(2) == 1 + True + sage: f = InducedHomologyMorphism(id, ZZ) + Traceback (most recent call last): + ... + ValueError: the coefficient ring must be a field + sage: S1 = simplicial_complexes.Sphere(1).barycentric_subdivision() + sage: S1.is_mutable() + True + sage: g = Hom(S1, S1).identity() + sage: h = g.induced_homology_morphism(QQ) + Traceback (most recent call last): + ... + ValueError: the domain and codomain complexes must be immutable + sage: S1.set_immutable() + sage: g = Hom(S1, S1).identity() + sage: h = g.induced_homology_morphism(QQ) + """ + if map.domain().is_mutable() or map.codomain().is_mutable(): + raise ValueError('the domain and codomain complexes must be immutable') + if base_ring is None: + base_ring = QQ + if not base_ring.is_field(): + raise ValueError('the coefficient ring must be a field') + + self._cohomology = cohomology + self._map = map + self._base_ring = base_ring + + def base_ring(self): + """ + The base ring for this map + + EXAMPLES:: + + sage: K = simplicial_complexes.Simplex(2) + sage: H = Hom(K,K) + sage: id = H.identity() + sage: id.induced_homology_morphism(QQ).base_ring() + Rational Field + sage: id.induced_homology_morphism(GF(13)).base_ring() + Finite Field of size 13 + """ + return self._base_ring + + def to_matrix(self, deg): + """ + The matrix for this map in degree ``deg`` + + INPUTS: + + - ``deg`` -- integer + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: S1_b = S1.barycentric_subdivision() + sage: S1_b.set_immutable() + sage: d = {(0,): 0, (0,1): 1, (1,): 2, (1,2): 0, (2,): 1, (0,2): 2} + sage: f = Hom(S1_b, S1)(d) + sage: h = f.induced_homology_morphism(QQ) + sage: h.to_matrix(1) + [2] + """ + base_ring = self.base_ring() + if self._cohomology: + domain = self._map.codomain() + codomain = self._map.domain() + else: + domain = self._map.domain() + codomain = self._map.codomain() + phi_codomain, _ = codomain.algebraic_topological_model(base_ring) + phi_domain, _ = domain.algebraic_topological_model(base_ring) + return phi_codomain.pi().in_degree(deg) * self._map.associated_chain_complex_morphism(self.base_ring(), cochain=self._cohomology).in_degree(deg) * phi_domain.iota().in_degree(deg) + + def __call__(self, elt): + """ + Evaluate this map on ``elt``, an element of (co)homology. + + INPUT: + + - ``elt`` -- informally, an element of the domain of this + map. More formally, an element of + :class:`homology_vector_space_with_basis.HomologyVectorSpaceWithBasis`. + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: f = {0:0, 1:2, 2:1} + sage: H = Hom(S1,S1) + sage: g = H(f) + sage: h = g.induced_homology_morphism(QQ) + sage: x = S1.homology_with_basis(1).basis()[0] + sage: x + h_{1,0} + sage: h(x) # indirect doctest + -h_{1,0} + """ + deg = elt.parent().degree() + base_ring = self.base_ring() + if self._cohomology: + codomain = self._map.domain().cohomology_with_basis(deg, base_ring) + if elt.parent().complex() != self._map.codomain(): + raise ValueError('element is not a cohomology class for the correct complex') + else: + codomain = self._map.codomain().homology_with_basis(deg, base_ring) + if elt.parent().complex() != self._map.domain(): + raise ValueError('element is not a homology class for the correct complex') + + return codomain.from_vector(self.to_matrix(deg) * elt.to_vector()) + + def __eq__(self, other): + """ + Return ``True`` if and only if this map agrees with ``other``. + + INPUTS: + + - ``other`` -- another induced homology morphism + + This automatically returns ``False`` if the morphisms have + different domains, codomains, base rings, or values for their + cohomology flags + + Otherwise, determine this by computing the matrices for this + map and ``other`` using the (same) basis for the homology + vector spaces. + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: K = simplicial_complexes.Simplex(2) + sage: f = Hom(S1, K)({0: 0, 1:1, 2:2}) + sage: g = Hom(S1, K)({0: 0, 1:0, 2:0}) + sage: f.induced_homology_morphism(QQ) == g.induced_homology_morphism(QQ) + True + sage: f.induced_homology_morphism(QQ) == g.induced_homology_morphism(GF(2)) + False + sage: id = Hom(K, K).identity() # different domain + sage: f.induced_homology_morphism(QQ) == id.induced_homology_morphism(QQ) + False + """ + if (self._map.domain() != other._map.domain() + or self._map.codomain() != other._map.codomain() + or self.base_ring() != other.base_ring() + or self._cohomology != other._cohomology): + return False + dim = min(self._map.domain().dimension(), self._map.codomain().dimension()) + return all(self.to_matrix(d) == other.to_matrix(d) for d in range(dim+1)) + + def _repr_(self): + """ + Return the string representation of ``self``. + + EXAMPLES:: + + sage: K = simplicial_complexes.Simplex(1) + sage: f = Hom(K,K).identity() + sage: f.induced_homology_morphism(QQ) + Homology morphism induced by Simplicial complex morphism {0: 0, 1: 1} from Simplicial complex with vertex set (0, 1) and facets {(0, 1)} to Simplicial complex with vertex set (0, 1) and facets {(0, 1)} + sage: f.induced_homology_morphism(QQ, cohomology=True) + Cohomology morphism induced by Simplicial complex morphism {0: 0, 1: 1} from Simplicial complex with vertex set (0, 1) and facets {(0, 1)} to Simplicial complex with vertex set (0, 1) and facets {(0, 1)} + """ + name = "Homology" if not self._cohomology else "Cohomology" + return "{} morphism induced by {}".format(name, self._map) diff --git a/src/sage/homology/simplicial_complex_homset.py b/src/sage/homology/simplicial_complex_homset.py index 46d3aed15d4..23c8596e53b 100644 --- a/src/sage/homology/simplicial_complex_homset.py +++ b/src/sage/homology/simplicial_complex_homset.py @@ -119,7 +119,9 @@ def diagonal_morphism(self,rename_vertices=True): """ if self._codomain == self._domain.product(self._domain,rename_vertices=rename_vertices): - X = self._domain.product(self._domain,rename_vertices=rename_vertices) + # Preserve whether the codomain is mutable when renaming the vertices. + mutable = self._codomain.is_mutable() + X = self._domain.product(self._domain,rename_vertices=rename_vertices, is_mutable=mutable) f = dict() if rename_vertices: for i in self._domain.vertices().set(): diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py index 75b4d0172a2..0ff13d5f7f8 100644 --- a/src/sage/homology/simplicial_complex_morphism.py +++ b/src/sage/homology/simplicial_complex_morphism.py @@ -624,3 +624,64 @@ def mapping_torus(self): for i in range(facet.dimension()+1): facets.append(tuple(left[:i+1]+right[i:])) return simplicial_complex.SimplicialComplex(facets) + + def induced_homology_morphism(self, base_ring=None, cohomology=False): + """The map in (co)homology induced by this map + + INPUTS: + + - ``base_ring`` -- must be a field (optional, default ``QQ``) + + - ``cohomology`` -- boolean (optional, default ``False``). If + ``True``, the map induced in cohomology rather than homology. + + EXAMPLES:: + + sage: S = simplicial_complexes.Sphere(1) + sage: T = S.product(S, is_mutable=False) + sage: H = Hom(S,T) + sage: diag = H.diagonal_morphism() + sage: h = diag.induced_homology_morphism(QQ) + sage: h + Homology morphism induced by Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2'} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with 9 vertices and 18 facets + + We can view the matrix form for the homomorphism:: + + sage: h.to_matrix(0) + [1] + sage: h.to_matrix(1) + [ 2] + [-1] + + We can evaluate it on (co)homology classes:: + + sage: coh = diag.induced_homology_morphism(QQ, cohomology=True) + sage: coh.to_matrix(1) + [1 1] + sage: x,y = T.cohomology_with_basis(1, QQ).basis() + sage: coh(x) + h^{1,0} + sage: coh(2*x+3*y) + 5*h^{1,0} + + Note that the complexes must be immutable for this to + work. Many, but not all, complexes are immutable when + constructed:: + + sage: S.is_immutable() + True + sage: S.barycentric_subdivision().is_immutable() + False + sage: S2 = S.suspension() + sage: S2.is_immutable() + False + sage: h = Hom(S,S2)({0: 0, 1:1, 2:2}).induced_homology_morphism() + Traceback (most recent call last): + ... + ValueError: the domain and codomain complexes must be immutable + sage: S2.set_immutable(); S2.is_immutable() + True + sage: h = Hom(S,S2)({0: 0, 1:1, 2:2}).induced_homology_morphism() + """ + from homology_morphism import InducedHomologyMorphism + return InducedHomologyMorphism(self, base_ring, cohomology) From 91199806bd11f9cb287eecef6166f26e7d817da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Fri, 11 Sep 2015 09:03:39 +0300 Subject: [PATCH 0830/1872] is_subposet -> is_induced_subposet. --- src/sage/combinat/posets/posets.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 0dc6aa1bf97..b37aa5bd448 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -139,7 +139,7 @@ :delim: | :meth:`~FinitePoset.is_isomorphic` | Return ``True`` if both posets are isomorphic. - :meth:`~FinitePoset.is_subposet` | Return ``True`` if given poset is an induced subposet of this poset. + :meth:`~FinitePoset.is_induced_subposet` | Return ``True`` if given poset is an induced subposet of this poset. **Polynomials** @@ -5602,7 +5602,7 @@ def incidence_algebra(self, R, prefix='I'): from sage.combinat.posets.incidence_algebras import IncidenceAlgebra return IncidenceAlgebra(R, self, prefix) - def is_subposet(self, other): + def is_induced_subposet(self, other): r""" Return ``True`` if the poset is an induced subposet of ``other``, and ``False`` otherwise. @@ -5615,7 +5615,7 @@ def is_subposet(self, other): .. NOTE:: This method does not check whether the poset is a - subposet *isomorphic* (i.e., up to relabeling) to ``other``, + *isomorphic* (i.e., up to relabeling) subposet of ``other``, but only if ``other`` directly contains the poset as an induced subposet. For isomorphic subposets see :meth:`has_isomorphic_subposet`. @@ -5624,20 +5624,20 @@ def is_subposet(self, other): sage: P = Poset({1:[2, 3]}) sage: Q = Poset({1:[2, 4], 2:[3]}) - sage: P.is_subposet(Q) + sage: P.is_induced_subposet(Q) False sage: R = Poset({0:[1], 1:[3, 4], 3:[5], 4:[2]}) - sage: P.is_subposet(R) + sage: P.is_induced_subposet(R) True TESTS:: sage: P = Poset({2:[1]}) - sage: Poset().is_subposet(P) + sage: Poset().is_induced_subposet(P) True - sage: Poset().is_subposet(Poset()) + sage: Poset().is_induced_subposet(Poset()) True - sage: P.is_subposet(Poset()) + sage: P.is_induced_subposet(Poset()) False """ if not hasattr(other, 'hasse_diagram'): From 0901df9d8c1e2b92427280d0d2d29d36194fe0c4 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Fri, 11 Sep 2015 18:29:17 +0900 Subject: [PATCH 0831/1872] Commit a_tour_of_sage on branch a_tour_of_sage --- src/doc/ja/a_tour_of_sage/conf.py | 47 ++++++++ src/doc/ja/a_tour_of_sage/eigen_plot.png | Bin 0 -> 18520 bytes src/doc/ja/a_tour_of_sage/index.rst | 134 +++++++++++++++++++++++ src/doc/ja/a_tour_of_sage/sin_plot.png | Bin 0 -> 18520 bytes 4 files changed, 181 insertions(+) create mode 100755 src/doc/ja/a_tour_of_sage/conf.py create mode 100644 src/doc/ja/a_tour_of_sage/eigen_plot.png create mode 100755 src/doc/ja/a_tour_of_sage/index.rst create mode 100644 src/doc/ja/a_tour_of_sage/sin_plot.png diff --git a/src/doc/ja/a_tour_of_sage/conf.py b/src/doc/ja/a_tour_of_sage/conf.py new file mode 100755 index 00000000000..a357e185c79 --- /dev/null +++ b/src/doc/ja/a_tour_of_sage/conf.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# +# Sage documentation build configuration file, based on that created by +# sphinx-quickstart on Thu Aug 21 20:15:55 2008. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# The contents of this file are pickled, so don't put values in the namespace +# that aren't pickleable (module imports are okay, they're removed automatically). +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +sys.path.append(os.environ['SAGE_DOC']) +from common.conf import * + +# General information about the project. +project = u"Sage ガイドツアー" +name = u'a_tour_of_sage' +language = "ja" + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = project + " v"+release + +# Output file base name for HTML help builder. +htmlhelp_basename = name + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, document class [howto/manual]). +latex_documents = [ + ('index', name+'.tex', project, + u'The Sage Group', 'manual'), +] + +# LaTeX の docclass 設定 +latex_docclass = {'manual': 'jsbook'} + +# Additional LaTeX stuff for the French version +#latex_elements['preamble'] += '\\DeclareUnicodeCharacter{00A0}{\\nobreakspace}\n' + +# the definition of \\at in the standard preamble of the sphinx doc +# conflicts with that in babel/french[b] +latex_elements['preamble'] += '\\let\\at\\undefined' + +html_use_smartypants = False diff --git a/src/doc/ja/a_tour_of_sage/eigen_plot.png b/src/doc/ja/a_tour_of_sage/eigen_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..925264764f198f9f7f4e9d753d684eb180e1d048 GIT binary patch literal 18520 zcmch2!$Y42=@5FbI;_JaSz|;=DTg1>m0A6U%WlH zXz;j-_zJCjOH*!M0WA^lumJ*b*<&!yV0n~cSk4u`ZTamjlaqX-!^;OZ)4mvAdHswd zCh&^J@4YssPfvfpJ$LW(p;x`37w2B3hePUT^UV#Z`P7*|2fi{y;4|$szDR@r10O#M zB!wUvi*w*CA(JQnzx^`Tu)NbT=bV#~!7-`{PQ)n`q5!A$gS-fwN7Kju@fXH@Um4i0 za5{c@-02boJ!3hiO?5nXy~=$x7menNi;sWe^#mLvRruZRIn$`NnJ5n0YuCQdY<^#L zSNP{IG{)jDEA^xKdjF8=fzR3bMt2i}~0YSm@Dq7o4IW zxQyG}+)*5EtD|ro9UUHi{;)qE!5^g3M@mTog6D&Rh`pqkE63Mv_mD$S%T;iO0tw2| zq`IfZ;3lWl{g;z+p4u7RE1!t=@9`jmplq>(2!?YH{EyWc?zQAiPxHYHF%GMJU*t9L z1%0X4At;m{Z9KR!Y^LGlH03$-#Ciz5&;{Pt!a|H@kZ>huQdUct@YCw(jL}{vfgm@N z4@GZF?k)awsrB9+;j7d)gr%mX*&KT=Znk|Dkp!_vO(QDlbo!QU|V6FhtZx;P&v&>pfD64Aqp3neZ4Ync+IDBX#p@B1rD( z%?9UZwIikY`J+0 zNWeze<3)g#1@CD%3 zZoXqg8{F|M8mRNz7)G96OQ{6WG%O#8p|~f660DCcsCX!`$g$YYg<3B7a4gl)iTWT= zLMOwot7z7$SbxfJ;01!+^0~9eRN?H}j<*L#CH}d(iMaL{7Dhs*bp84%UddyU-)}!X zHku7%&zs`>-gVU4osmjShCA#Ay_EZW3NB9T?ffZ-9g{1!$nvtY6<0?wAHJ{i@W;KS zjHx?l4KFQSZEx~Fu`^!|rVc6$_(f{HsIi!t)UQy!;se0EXMGZgAoP+C^9^LqqZJH4z-*!;x{tHbR@hWjs#du=HwCaP?nOJu-e7bDfXcwDL;|Cu;M_t^Lq?T$I<@ zPL5p`Di5|$%~W}lejuP`LXQ~H+?ttI-O1v)*SSw<^H{hS} z`E$($k?tI(=;)-IC5hpg^!!a5eArP7EFU{ zwGwB(5fcHE;Yp%#{zqN@?v;GK*M*+wmT+ui3hN!zSPfmHq`ig^Vw}EW=5kalESdvAy2&THt=gvNcI}Ha_AOl=gL!bHN zD7#|^TcgpgEpKd`|+Swd;;d|6oFy}RZ8Kfp}yC zM)lsb4EbG|Dno@udSW@b9oQvi@9)u_W0=y0C7g1;Mf~LUB2MZ;z81o2o@L0!b~=n*m60OO1*+nZ=K z%SvXe-NqG6+V>Kf=?cb(NC8~G#O-mV#V{|AO%9zp|pHtVYNXb z79TM^o3^9E&&qi?7j7Iv4PG;X#jpB<=8Rd_fm%k3rT zW-qp}EPG7S8^x~GjWMXPxJC*)XK?m9{=A*yhZT0v-%!%-Nu_(~w*z0@lbX4-_=+q; zO%`LEuOpO)cU#KYNxBL_?f-JAaD;^#UENVZoO8t=C7-63W1@L~WUMvPP%3!{oOuGQ zvT~?rqc8vi&v@Bw-p#leCdL=AoP}I+!1rVF3_xZ|zHBTWI;;8Gzy6qQZuZ<2T#_ip zW_i+=z4q97s_N#W48c09nwspLWz^RQsT^m3bma5s@L-7CKTI92~zowrbtv zF>#^Jp^r^((0NqpQV7-_^;rlN&rf0&e4doJYTGq02R^>Ls$r5|=H)W;;{p`u`6!T< zeH2T{WQ*^v)DOb*p3Dh`i6xxum2(`&@uH9cSged*xh^!fqr{a=Q?WY}ffBVxS6G9~ zdVL{GOb~*mN%dY+z5nnbE+r-Z_}CX99Pnr}eEsXW4!42Ro9*xH2&G@WkMifb>5Yaf zOGMf2~zoepTgvtRBTVkPxR+`L0KnTBiO5%&HpfrsxYq@xkC&Zh1p_x1uYx z{Vh|iIj<}^A1>}x3+VeF!Wiz~>3yGN!A;(Ncw={+rBa*-qOl!jbDg5jym;~A?2h-G zdo{aE$nkM+@p1tL6EC;*apgY9x_dvb{+#cfrx^I=T)Fa2F^CtED`9VNo|>fkIIx=* z(-jx>}S1Y3=h6FnS}qxQQ`L%%4B*C(Nqi zx-Rp&4djsA7t;?k7>TW?%k~x4F{D~uNy-l8`HwLUOx}J80_kR|zm7`Ge<67xsQ5KR zfjQhAo0_p717$eBXhEpw+B!*X(VMeIK1 zf5h0*Pwas#l>y?PwPDolgZSg9pcJK+##f7h^@<}Syph;{Omddgx-v2$16us2ZW1K~vJHc6z~;l5dCBZD{&fppLO(!>B4G_-TWPI#Kl<9kwgS1}2+A}VUs zlY|et1d^C(`iRTDg9A(DFOx-$;U~1qDTs?b3b&0i#@7coi7M6OLz2ZZ=1e?1D|yzM9dZEa zMVytfTIl;>T$geX3cQkfRhv(IMqf6c2jG9%|K#-r9Cz0JJz2Cv>m|Jdo4$t~9VJWK zpvYZ?tx?_Xr}26JA%C#DM;7n5T0W^%>n)Dt<&N4NX7_}neLSoObBmsW%m_mp-&B2J zuH&}vvmUqmQ|OLi>5E6YiE}Rw_zi5vLe35owwtLDDs>j}2diT@94DZ_*_Mm(B#0tY zBXg9WQKg2&%q8oQd!6_{o*7{`_(PWl+I4sKNpk7<(Z7c}1(orJwr1AWVDI1-`rMNf z84mV{Aw?O8~J+>2;Q&#E2?12*VmI*3|wYw;2j#XCH2;ki@ryoiP=Z%AmuB3c7 zRRqG=w>`R-v9SJF9&|$AyQv`>+3$_c|DH|@*4b@B_1?TeocKjZqg8tDwkevMyLabw z94!rAPGJVe2F>q=Bbm1pGnOo-#lS{abcN=amq z{@xpvqV@o$=l^&VLWSV=U#~@hrev}ILKVdNdE;6-$&xW=xk^$7dqi0lS>E!5L87!? zM|-guQq6l+gixm|s&TA?|EhjB~@WSdP=Lq7LB@%YFA0liWE$vq^pSt_v zSB#pH?U3SFx$;cg*sj@R9gfL^#*Rpi4R9GtIo|x}C6H)tJ&okyMGZV(Ob@ZMEe;4c z0@-3}S*s8mXm@sk!q}p&szzo$Ej|MIpM;3+nVKci{@Y`u|0p7-%A{e6RX^Nzjlriw_T(_cC?3s2lb7U&@&ZLK#$P$L;&=QPxJBoniRU#Bz3~n#7?rg<|(BqWK#BkSPmUoI~>7 zjyz8lD^M?W2kVd`{36tzOVpYzCBT2`!V^et1;i^`hCD_4Dit%x`9&8&=yVq*iFUn@ z*B)1-Y?){5&v55k;vz#A3^zr)8Iq&{k)-B}9 z-bNL7igM@5P32ej?5*AbsIboor$VT!M~#A8KJPYbeDjK^UF3OcEJ9+?ZRy3B|MHM{ zeF5yMkBxdXmDICD*-1njfDP>2Sn@W&1JwB)7<}mO*ie1F2mo>$uTReB; zOp78kklyGLWdX;H>Lng-_T~dO%`Bx4bUJ2>$&7h<1Rel~3X?Q~0hp@C5J+5GRTY0U-~O8mI2Pl%fqvcQx>!y$X1We zQ2+X5v2s53L+f^AM!2luVVf*RL|f`b*GjbE5NCoSXn(>Ox&4mv=d|bMl}`>~mMNSV z>#L)3qw5nsDCylunZxhl<&Ft;XA>8b4oM2F`!n2E(Z`P*99~TDLL5mM?TxyX&ZzU0 z3>p0OmgnfNUCUO8VCE4NOyJ1ZE`Hejma;!nCFy(P!ylie#}GwJwhhp-oT?Y5i=HYM0=Z+!dCF+|<7_-N00DB|dlr+GsZ2vaFhmSJ(=LPiYVW^I*9lAVa{uZPw@D@NB{4(8&= zc6P_ylRsbASLWsX=FLX+7tQG&=%v`WiP6c)jB#;s+=7B?!DQ5kwRIR5A^3)i%`i?g zPgX&+c&`+<4P?NsIv3HDgJ3>gKeLnEs9s0Q4E^q+OJ04?m6|QBc(iZEd$+Hy7Jyuh zF)U@OD8!KrqQ#w-h;F(sQ{`0+Uwf*O?;LGj%$#GPCW}DAoXxmj`9OWZMr9Tf%XR%^ zv^*hRFrlObK#zPAH}xoCo7lkx;=mViW#Za$U%d9ls#Zh9cCnt1w zw-+vZj{mI0-3(Fm80R$b&avk@^re%7mpi1uqbF-du-6JJ9#);W`vf`du58pR0Lu29 zwp>uQp?_ncqmlLSoncag z>sm%kzFnZ$uh+~R9|E?eZgp?^17IDMWKXXBWjL;iy{2r3ylXbU$0DL6F`qnj7a38d3q@az`}vAv z5Sw3S`eu6vPe;C58bN!tM1t!oE%v?2CN8kZ`T%+Nt=aH}PDe?&yKC#kC$5 z=*t^MJ_zG|vO`$;2Db(xKr$%5d9$05)-T)Vj`(s@NVDVnOBs)~O5Alz#r`Zk&Vzn6 z$KhilR$Tz$_vv?P3=6?Sd-hR@GtaZ7Em)5IN z1K=F6DZiK&j5ZIS#Nc&F_rsa^$$frbw?1;uNt2UUyFWh}m$=0EN&2j2&Ynn4>Lyv| z11G2AlG0N6vuCUkZR~({qmPij`3@vTGG?oMCl0+Z9zp85Og%9`mgJ+GyPqSJkiMpQ z8e}Ydpmn>yHxq%Nar@OYgjMZG>ZeDUL@!l?)cnfHX`n8qP<}DeBRRdJ~27rRb zTO&MFEm&mqb&DDfMAqwgnfzQghU<=WpMjLguV=ASDdAS)BWUE{M-w3_P~kqbG^pWF zke@g=`%H^MZY90x?xm?c1l4qWA%EGiN?_`Zp<-cF^ou#q)2`t zkpCg8l&{QUml(gG?Lc<#?*0BuSb`DrefLT<_x4m{{I>rhYRGPMzBDe!$p3=>iCF~c zycrCkI$gVGx5LNYoTx21xJew?+Cq0T@X3rbtc}I!=-}N|{$jr&zV_Al(@koM0uH@& z?}eM4i_v_W7%c(!Lpd9)|Si84sx6?g<#x4E0&#ru>Vwc2{@9HcJ(gMdP!FwT04(qk>6U z*$OI}{uEJ(w>YERhiIxYEs+?mi+dw&b%Of0{SHtAWjS&0_E*KmG>(6f<%Plf=Mt0y zj=#>ijlX;}JaGjYcn`Y6)4xgk=PqPTY1!X{a+j)Hi|M4?yk;mD)dDU8mZ`YqaMHhY z^;=eIw5pUk=bnkM!Jb*<{wBcpc&v!}7_Min0NqH1Jv+E@s7#Vf=ioOl!whkGI)C_YHDazy$okgI6Gr{B-b$wLI5S z9?uULzSSI=gw7@7u21UqcxE5FmvOtX*8omg)HBNza}^}LKy3K^hoJvy5COr( z1v|KNzG@XK=fez3tkOR+~ za?#8>zXxNy*Ro_m$#AU(=Qd`KgKNoK)Irf?Up*@|Yy!Qnf8Up0 z{ByWYd#FkhpCDS3ivkTmcZKsY=)`n%5Dvu9Qqw=hV!y<%8kAVv&&pTDzq?Su)bVwv zqtPn?`{`>(!T_6l=WaJqr1Kg?V}8NZ$`6FOvw?X1w-?~bRV^d?E)-D%;QXNJiDdD{ z#<&-1v{cM|_QS>x5Y_ID^GRaVwQBNjwvV^EL4WFZS}7b*w>=w!74bUW1iL?EUK z1ET)4p}iXM8YaO{O|9Hp7xZwsL-l9;wAU2P+J@Fo+n6ldHwWQx9rooY_VzAfn)iPb z2E>~v^pD)~o)lY5p)R(}c&S^`!|=K5k-M^Cz{Z2TwKY7z&3;wzG?u#$mqz*vsuyp~ zAE9;3)b0@nvix26SWowT(~9j0AB{r8_=KIwv(d_U{#EYQlf8%u zDWaD1AO`l$R15LE;9>fVRor(wYM{P;hnMl*W8D%$=E`l)%Fw3WFYS)*mc}ocjXNu| zRz!0YYE}JuyU@iVw~_`pv8Aq5&f;iNj#r?vXT;bgsYllxc0^ApL}243qw`I>QtiET z#3mMek(ny&LPk(=7}%Xa?T_v$tUn*bTR)hG%GY~Tc(N*{*X8`@a2ZGhBcjvmX9$wW z*Pt4Muve5}j*#}!9tYfff*}vak>#%&cjT%z9xk39p~{4B*!Ho#to!otaPkbzuU7A$ z{@_O7tXy<8N%YTGv$I<;7XRD)hI~w}k**Cyh~0Gb)5BdoABkd*^@b%lD8kYkfdB+; zNwfGpmpD8AUP}fQzk)i6i0A?hiv4RjztPjZP4$^)0`w!hEEm*AusaAp8^hu}CUs5+ zFDq!zc?MWC7Psjd@B^;sZ&r%PDiqZDi2zwoy94JOHRQq%GP&8}AX3N#Yp=I3-0%vQ z0o&$37flMx60b*8#7JdzZtF}o=V-28cnrOZ0KSc;l~8uRO=)TA?VmAfx*t-Qr8AZb z%d=>RIGBM8!s^`T&p_mS6Rrh^O$G?&>zdoUNw}At@6Sr*@jG#woxhOg6gj&V$l(F~ zD)FxcbU3d5%wP}m`7@m-#$kMai@3J}Ai%&U1K51m-I1MY_f9(7JCv-afY#j*T=J?l z1drnHWNA0O_u|)TwVbQ-FZv?lx7_k|bs9CG%?J?SKo4CS${!0i!(JqMJ;qz8C}cTG zXA1Hr-cZ9GE9`?6dAByG?0smx>_^UeN-$dp2q4_uu>{5+;0^a`>-|eOV>w2Yv&4>md+w;y*v-;B*6UoIg`4*LVV|KWGH|2BESYH<8 zDtZ6Dz8Eg~MN}H9eg*EdsiM6#(qqz|SHCMs?*kJEPQsJliO3WK&Zk|gS=P9E(P+3{FK=qFH zd`}~{4LEQ3ej^#~YlIR7{dpu(OpQVO9*-u;GisGD(yv-0lai`u=06Kr+8q3u3&)#V zSe!SYfQp;uqIZXzol9g6IQD=33Q-PWqKmU8%FcRyspweLaRPm`UT=gPI3BwIO*fEG zD;Cx>OS#X4;X*It(jH)&2J7p$k!Om2M^7xnp=3^1sv%h*r5U)7m^)XG-<;Rb)QpRY zN^cA%vz=~v_s6?d{nJfoz@b00w>V!9Wfl<^&tDoZ0Z2P@MyMtJ^^eAAz^NWQ$x3lg zjOW+O97r7bG8h{dXZ>fkori}9w=z=7Intq(hsZB;UDT)?cOWQA2ysjpiQN6;jbPWQ zSFhyq;Jk|oMh^?OJULFo$iYD=i%$33WS3rFRqaKd9nVV?8dSOFJo)%nx(djwSa6)x z(jFPNx^NCpD9nBt0U8F>EtQPEuYd?kDID{098+Bx9}CaRUGY(RxULBm^WJnRiWf90 zIM|wBKA1-q?j-(K`S_<(0g(BlGiqw2fT>3}Nm|lgnpp0>`HOQ`M#r%E(hY~FK8rv~ zxvEyylyO5;J12x&Gdqd&@uPH)#4o=GHUr(32dapGz{$OD9=$_HgJC}sZZ%yP3FF9HXjftq4! z0FQIU!P3>POMrItkcrvt`AiQ*pos@FH2qBJy|86Cs6=i?)eb3hj(v9+LK(rn57iV% z0Q(haE80xxA5XdYyXx@1o}bdut_~Kkbe*Dnsk)GTB+W1##A=b^mRUP6;a;!s~gliFP{*w20 zAnKDq@=_;QK%LWQNX6;2#Vv) zhjLskBdW8~P56A5UC>yR5K$&hL zuyx>6A`R`;jXWGNAL`>cIt^+2Z$i7H*y#=J}n>%Qm`Uz|~oQr&$D6BVaP2 zlGWF(t?HX3rqNP#_J~9x3mwL*R`1^$VFI@lqr@O}Khh^I>L$Ra(hu%?6u7R}60n*5 zsP-nVnVP!BeO$sCsEgm|^NU^Qy8(hH>qfdpZ+Gxs_LG!*YI|k%LJM2KoqucXnC7k% z$u+N5X4%u$9c0>*G5eqg3Q}B84{!j#7aTRS1O@XVdkT_d40J1cTk8&P?N2P@#ZHf3 zc{YKru0t47qyvO=S0ZTypz^WySe#qa1;m#J&i+l$N__Kyj;<@pReI z4Blho7;yrO#?dOy5~*X1DGhi(KTD%eBm%5`a#vg`Gw_Bn1fF5_Q3%khhCRD3ZbaMj z4s9RIYj{@y&c%gII`SjXbsIp1)V_-|X-3{#lR_CG{Cl;)5msxuN26x5&{ za|`#`Qi)oYF;R+|<0=C99IMSEr0s4LA1Wb$^lKXr53FCxUFf0=6;M0Y*!D&Xf> zsOaGucM6%a0er{yxJNuB>s_{U4{dmzS@E&mWeMXCG|UJ8e+VxV6z)w}#InExRp7red13EFLHDPz50w}YwRh8}t&KBj;g;PpZf2L=3L zR|lnz;Avb*{CH_mFrc_)uU~cS0HeTSKgr9RKc7B%w61)WOE>zMw~)r}W?eDp-+;-n z=!l0WgWfQbIpC*~B;Y$pjs1?4==E8{SOihWr#(kNo1W`TS$Fx{ME1mPR8AZ0)qg6g z`?FHZgihL3Ya%&)pM8_XR3E#!r67uo`m^yrMkc4m`NVYU0-NDK*A z71mE2Xdmsy2fGcMXsl0QtK8a{E+;Y5xPzOR_LKyAjsG(@)CueqlBz0kpiicfsaV4o z=$hl*SFA)ZiA8%s_ZwI=A-S*1V_LdZ1E~yrf(hLc$_#hX*6_94(b91XMi=iduu@>j zOK6q}d;$oQmbWI&8EP^YnDvU}7-Xa*wuqKK0B%R_$I<||>&i!=46iLVS$bnFQ0<{F z(_@YV3k8s}+~Z?_lKJE#IWsR`nSC=5Ed#3Gj{1I8IL%MCNSc^V?!@@GRyn!-n4om6*7SQ(uhF0z%I&*SAgJkANcZXm1MZUAm z;n8Gpgka6Hj&6q!2g>QFA(Aw(S567|`7 zCx3UW2a%(pk-;7wDNwI(GcK`xNXAmuvNsB%3?$5f+&Io}lK}x{U5weXpm~30bq)H` zyo}iu_wq`g2h?IvDJ%x<*WE~_+@Gl<=hn&Jh!@bm&E%~3IP=ndQ&I|uMhJ8_tIaX0 z7o`)Dcu#&&(@D|NDGAoFx~Jz6-##yxAZo54c1}EHU+K*$_-O(b~V%%~C;%-_k?D=B~Iu8H&okQ?Io*eO5(gc$1sXWsEU_KENhWDEqF^XyCNKUL|2FGRzV zOV5>Wy^L7)7|u^BGnL<{1l~xQ<7c|{bx!jkvkwC2{<}0s3=Omm}Y| zW;Ak*8pum<1zR75t0q=C_U!6iUIBY)mwese&~XF$vlNX6TVU zq<=KC7snkSWf=tceO0>(14fZo%X=agfO3pzE1mfZqB+9hG7$Mdc_(9uRZ_~J5G;$! zx9G})Pv85Sg8vul%D+xW8@ChRym8HIBVl?pU`X8w*;pBmS zI~s6i)pKPtTxkso%y2$C*)2;qDm28RhS56PzhAdB6ILfj>fpu3rpF}A$p3muC94y` zY#!YaNYvP-lB6W<^Tbj>QQz(|F?g=b8X;&qA?1^}5iXgryZTj{mm@L5ppl1pH$*4rm-gDw;}SoR-~=@9z@ zM@j}Po{@S$OQX;jAaouvF|pBp2zuO*;&Gn-a_yRgEwUf|nX~HbpeLPnf)nt!yvE)? zop9fyqLKus^)$#p2APdQvPk?c41u#GiG?@{DEh*xY<<- z?s~lWD~0-s9*&-YpO?3PwmpV`Hb+V=m7@tQ03u)4dJ%^Lh#rG*$?A}VS`vUrT7@4kawOXhV3?RXhw7Vqc3%?x=R*32Vxd9t)&{i-6fVj156-k57KAg@ZFYQ zO>bTmD=+=1`jeox z^Os&y;R3;m+TaUP>W$8ZHUf$VA~N9v)(|F|5v4V4aFxiqZ+>SpD4DG#p&TmWK3+%s8h2cHMo}hn@?2tfc+^PDH9Ox* zee|Xmq1l(?&s3q1Ib9L51_*_A`BzB(H`NH{cqDwQO8x_zm|6>=m4|Hl^7R(9K`$^D zhdY>82F572vbR)}b(yfMoqd4oe)r^N`#aE*2I@*37YX}%E_muDKChLUCZX15w<;eC zDv4r8o$Mu?rz*4AD6C_s6lWKW44w-llt{N88Qv6+)HrjizK7n^7p%9f=52wu+rD|} zaHn)>Ly;M#M+Odj2-*~i?2b-gE$L9*4FE*vVE$4k{o-PntU?PNmYnH7$RQ+9MyBpY zSt$VPulIb`itQi6Z1Ad8>vgS27E=mfOZ&66HJGn!!LIiP3S1I(hz0G#;Vz{;az+cz znXh9u_HG$JcJY&@4E+^AkOogro0?l%=7F-s9Fa8yie2DrsYx(rVWEL-o0=>?@F#D% zf%KasO4?dbZ+JLIpQCca=VGyi7a0c?fw>Cij%aJ{poLh!>p7AJ@wVsI(9EUQA7F54yQHNF@Pl- zYTL*{W)P8p0S5-l?og@dpG4pd06U!>M7RR3b;5^CmcPP1KdjuI*TA&brk<;VL*Fme5Mnwmu$$;|)RM}{c$08drs=9Xa?^GM%3$TfA_S*np zfT|bQ0}@)pVoFNv26KOJJtHN>sVfW`j5Zd+^EP@e_dNi^L=6r~YUTGXC5b7^%i~Dt z&mmc)bs6qH1UvQg*zzcMr2JV4gWhKD7U~~%C@S+jV33h&K&2vhKLXCil*FIIM=DG1Sx-OCyI7Amyv7oy#Zf8w zy{AX3++p0EF=mAdBG1a#%l9yGlb1&*FN3!MyQj=vI~VQ&nY@F))qQ|J_JeZ>gEzH? z|1x+JsfgHZraZk+!h929*`s#Bi&hNBfjkN(GJu01Mcibs7~CqkOB-C3S{@BV=d?E8 z6E@mkcN~&qW3Jv`>u$-BbKI9UuW_O;)}}WPlC$ ziUg&=T-@Rwl(*kXSXK2{q#%>i>*t0JZIixc-<~+uiC1ksY^GrWsY?C>JsBW9dt^Rz z>(j^(M#diZ0Zqr&@aH+PS)98Kn}1q%R8!OGl4Ctq@=_F zGpKflBM|XG82Bp14t(Q0JkemQTKtIg-nmFszyb8LFG7L?VSwlxOp^AIVosDMf!NmO z5>S0#^R-Ou-(Gt6)3?Z$;PRQIdf`I@(eR5+>ifKmi)I5ZV$eZGrCePi5Sf90m9;Tr zkT+!XK?k4X=VN{BX+4GwRiW4cY7;<&R-?k!K&}JL7hw0nzzxTqQ2=I;w;pKqb$+P4 zg7*{pm;YInfkGsZ4kY}6x7Y08AWW8Jh2ifT#SVOQ82cOd9VYavHk!Z`RW|`=v4*=Y z7>~Vmthbk@h>#g|E~e4DExZKg<#>2`mB9>{LOU2X`*KrIt?D;}@{9UYZ=l0|k!Bwt zs2osBQH&avmKS#TN7=fIAxEA<@^n*S5qQdeJhe?JE#;!VtOL*|MDrCiZE?ILZD42K z5FPFTGM5^yYAPQ{3~Cw zV$GG?mnoT(#MG*`H5SV!83GE(S=-0|MIDYqBGsxH!AKSlZw$cvfa(EQvVA^Aiup*l z7U2K(7*zGz`+eaUI$rJnDH@<45!+iTNP&MMcKA==ij0!WN04-UX~<0wTZUP-nb~l&9&d6X51Vy#BnPydnBD8k`fg z?avA)-5O7)?{1$zf9~k&3fl(0+R*H|PShi6jQ^WxfUR+o>)J(cTB9QMUY|}WMLRn? zmxUvyp+FAzqt#d737LI4@0qY{6)tXYaQOH@j;7o1&z5gLW@TpbfO7=4nW2_q#>fBmG|Mj`dSD1T=} zzkh!*j9FUufU}YNt2F4yK z&7*@q&dcVCfwcY?t{ba>u`h0J?kX^#W>cG)o2vw-Bf(>9zDKJkRoWwY8F!ezqgiCiP}Y3g=kw}7`83==$htGKw>m#Xfp_#N;#kTGyv=E4OZzUJ`#3^GBW z;{QHY3L+j%4m`Ea8EhV{GXP^&Kq$59xxGnX93o$+O2ZSydi?!&b-2Z}luXok(fjwA z_H7G+3m8-}^$)aA;-5Imyn7Ek>M+O+$#5`Zat;n}91G&rQVL-rbhHDRu`dY)Q1KqPBXhVfqyyi6qnQE=Q%WVr6`o2GD6$2R$1+Dxfpv3?jZsXML0V$8^nHK;i+RVR zzXw&#+n0CNvfqJ$)MrM7*6qK|4*zGW79vnQ|J%gw(_oUbnBf1MlR~)wUir^==D8kL zkqc=juOR6b-7Tr6i{%5SWJE}^a=-#avamV^Mrh)h1N0ey`dN8zROo}+-+wf8T+r6} z4B%lDQkf07Kq07V-;^Mi-%U`KmNFldHHb8yg_1P&IUZ|u^dMl4Q)?4-P z$@G2bB_cF2a*u!+<$oO%|JP~feLMM!m0DCM=9xWcg(LC?@7Db;99xl&WMHtF0E{qykyRCT_?o*z9Y+$$meB13aD}P_VRo=1#LvBpSx?lQ_q=O&>N3+WTUD%=g8Bi7fmQeF zbK0Sy z#b#}}j+1pufTro)2jkEp&a;YyvFrI{mvHdPB{!;WRq?rN1YU!LjB22fj0Ft_xL5AC zSuz=V04PLte+r^xy#EZif)kj%W-r5hyTj}|V!1nh{J6w0BSeh^LbHf9?y( zHmE(*y88F$UcL3Sm)^)X9h}GlI3Q5>^x5C_RNn1Mk<=2b-PZViAL-@!5AUT_Sy`!D zWc-RlW@dc)Q7Gu&ksL_;a@g+kD;;~20qdRLzYja<8yc?J_I-Kd2&%OVvSYD4 z47B6RQXz-!U0pjEFupjywW%YPSyFOu5@_h_)yIE250Y=Fo0z17(OUmHFrdD%r^pWG z2R1NvBloO6_IU0U1-;4Esdmrr=`qcXz5CA-ARHDPF%ngD}1E z2pr|@rR!h7+T|P8>Vn(Kg>+%h$PzzJKqXY77=} zntlvc8eG@oz&D?MZ5`O~UnwtjAxG%w&uxGMJsQ0?1AO4{dGUdQFJB%Kg!bKGGivFrA3~r(i)pbO|Mb(LoM6Tm zoAiz8sf_xOEUpPSJ9L%DdO0$!lH z$*aY+hK||{>Pdq3SZTapSH{SR0!sPzEd>f$R(Gv5{@Vhcw z8{EKhT}Ev%P7A(!nZz*;HbKOp`exBo5497IhL> zJ&3&Y%yB(jh2wS8?T>~Oe-#rSt=sZEqj(u?9#3h=>iOV&cl(dijb?iNSESIhTc8wn zoTG!}J_As2`zpu@=EM|G+EY;RVlVJPf%jgC7=r>{@yM8Rzd2oNP=Rb3dVEM`HEyMAiX z=;cIn9cRY2W_luMvSoOy!E);01dQd*11sV`pWVRlDU-Y1(aO)10-ECazxY(!hG8M- zWk>_Vo!v{&Pm>QX|I_ck-qHN0tN-6m-A;o4Itldr0FW#HFYe<1^@~QRDPA>BewC;q Rd}#*+lUIFQ@X$Eu{{Y)ke@y@Y literal 0 HcmV?d00001 diff --git a/src/doc/ja/a_tour_of_sage/index.rst b/src/doc/ja/a_tour_of_sage/index.rst new file mode 100755 index 00000000000..2ffd822be17 --- /dev/null +++ b/src/doc/ja/a_tour_of_sage/index.rst @@ -0,0 +1,134 @@ +================== +Sageガイドツアー +================== + +以下では,『Mathematicaブック』冒頭のMathematica紹介をなぞって,Sageの紹介を試みる. + + +電卓としてのSage +==================== + +Sageのコマンドラインに表示されている ``sage:`` プロンプトを入力する必要はない. +Sageノートブックを使っている場合, ``sage:`` に続く全てを入力セルに入れて ``shift-enter`` と押すと計算出力が得られる. + +:: + + sage: 3 + 5 + 8 + +キャレット記号 ``^`` は「べき乗」を表わす. + +:: + + sage: 57.1 ^ 100 + 4.60904368661396e175 + + +Sageで :math:`2 \times 2` 行列の逆行列を計算してみよう. + +:: + + sage: matrix([[1,2], [3,4]])^(-1) + [ -2 1] + [ 3/2 -1/2] + +初等的な関数を積分してみる. + +:: + + sage: x = var('x') # 記号変数を定義 + sage: integrate(sqrt(x)*sqrt(1+x), x) + 1/4*((x + 1)^(3/2)/x^(3/2) + sqrt(x + 1)/sqrt(x))/((x + 1)^2/x^2 - 2*(x + 1)/x + 1) - 1/8*log(sqrt(x + 1)/sqrt(x) + 1) + 1/8*log(sqrt(x + 1)/sqrt(x) - 1) + + +以下ではSageに2次方程式を解かせる. +Sageでは等号として記号 ``==`` を使う. + +:: + + sage: a = var('a') + sage: S = solve(x^2 + x == a, x); S + [x == -1/2*sqrt(4*a + 1) - 1/2, x == 1/2*sqrt(4*a + 1) - 1/2] + +結果は等式のリストになっている. + +.. link + +:: + + sage: S[0].rhs() + -1/2*sqrt(4*a + 1) - 1/2 + sage: show(plot(sin(x) + sin(1.6*x), 0, 40)) + +.. image:: sin_plot.* + + +Sageで力まかせに計算 +========================= + +まず要素値が乱数で与えられる :math:`500 \times 500` 行列を作っておく. + +:: + + sage: m = random_matrix(RDF,500) + +Sageでこの行列の固有値を計算してプロットするのも二,三秒程度の仕事だ. + +.. link + +:: + + sage: e = m.eigenvalues() # 約2秒 + sage: w = [(i, abs(e[i])) for i in range(len(e))] + sage: show(points(w)) + +.. image:: eigen_plot.* + + +GNU多倍長ライブラリ(GMP)のおかげで,Sageは数百万から数十億桁までの非常に大きな数を扱うことができる. + +:: + + sage: factorial(100) + 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 + sage: n = factorial(1000000) # 2.5秒ほどかかる + +以下では :math:`\pi` を,少なくとも100桁まで計算する. + +:: + + sage: N(pi, digits=100) + 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 + +Sageに2変数多項式を因数分解させる. + +:: + + sage: R. = QQ[] + sage: F = factor(x^99 + y^99) + sage: F + (x + y) * (x^2 - x*y + y^2) * (x^6 - x^3*y^3 + y^6) * + (x^10 - x^9*y + x^8*y^2 - x^7*y^3 + x^6*y^4 - x^5*y^5 + + x^4*y^6 - x^3*y^7 + x^2*y^8 - x*y^9 + y^10) * + (x^20 + x^19*y - x^17*y^3 - x^16*y^4 + x^14*y^6 + x^13*y^7 - + x^11*y^9 - x^10*y^10 - x^9*y^11 + x^7*y^13 + x^6*y^14 - + x^4*y^16 - x^3*y^17 + x*y^19 + y^20) * (x^60 + x^57*y^3 - + x^51*y^9 - x^48*y^12 + x^42*y^18 + x^39*y^21 - x^33*y^27 - + x^30*y^30 - x^27*y^33 + x^21*y^39 + x^18*y^42 - x^12*y^48 - + x^9*y^51 + x^3*y^57 + y^60) + sage: F.expand() + x^99 + y^99 + +Sageでは,1億を正整数の和として表す仕方を計算するにも5秒以下しかかからない. + +:: + + sage: z = Partitions(10^8).cardinality() # 約4.5秒 + sage: str(z)[:40] + '1760517045946249141360373894679135204009' + + +Sageにおけるアルゴリズム群の利用 +================================== + +Sageの利用とは,オープンソース計算アルゴリズムの世界最大級の集大成を利用することを意味している. diff --git a/src/doc/ja/a_tour_of_sage/sin_plot.png b/src/doc/ja/a_tour_of_sage/sin_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..925264764f198f9f7f4e9d753d684eb180e1d048 GIT binary patch literal 18520 zcmch2!$Y42=@5FbI;_JaSz|;=DTg1>m0A6U%WlH zXz;j-_zJCjOH*!M0WA^lumJ*b*<&!yV0n~cSk4u`ZTamjlaqX-!^;OZ)4mvAdHswd zCh&^J@4YssPfvfpJ$LW(p;x`37w2B3hePUT^UV#Z`P7*|2fi{y;4|$szDR@r10O#M zB!wUvi*w*CA(JQnzx^`Tu)NbT=bV#~!7-`{PQ)n`q5!A$gS-fwN7Kju@fXH@Um4i0 za5{c@-02boJ!3hiO?5nXy~=$x7menNi;sWe^#mLvRruZRIn$`NnJ5n0YuCQdY<^#L zSNP{IG{)jDEA^xKdjF8=fzR3bMt2i}~0YSm@Dq7o4IW zxQyG}+)*5EtD|ro9UUHi{;)qE!5^g3M@mTog6D&Rh`pqkE63Mv_mD$S%T;iO0tw2| zq`IfZ;3lWl{g;z+p4u7RE1!t=@9`jmplq>(2!?YH{EyWc?zQAiPxHYHF%GMJU*t9L z1%0X4At;m{Z9KR!Y^LGlH03$-#Ciz5&;{Pt!a|H@kZ>huQdUct@YCw(jL}{vfgm@N z4@GZF?k)awsrB9+;j7d)gr%mX*&KT=Znk|Dkp!_vO(QDlbo!QU|V6FhtZx;P&v&>pfD64Aqp3neZ4Ync+IDBX#p@B1rD( z%?9UZwIikY`J+0 zNWeze<3)g#1@CD%3 zZoXqg8{F|M8mRNz7)G96OQ{6WG%O#8p|~f660DCcsCX!`$g$YYg<3B7a4gl)iTWT= zLMOwot7z7$SbxfJ;01!+^0~9eRN?H}j<*L#CH}d(iMaL{7Dhs*bp84%UddyU-)}!X zHku7%&zs`>-gVU4osmjShCA#Ay_EZW3NB9T?ffZ-9g{1!$nvtY6<0?wAHJ{i@W;KS zjHx?l4KFQSZEx~Fu`^!|rVc6$_(f{HsIi!t)UQy!;se0EXMGZgAoP+C^9^LqqZJH4z-*!;x{tHbR@hWjs#du=HwCaP?nOJu-e7bDfXcwDL;|Cu;M_t^Lq?T$I<@ zPL5p`Di5|$%~W}lejuP`LXQ~H+?ttI-O1v)*SSw<^H{hS} z`E$($k?tI(=;)-IC5hpg^!!a5eArP7EFU{ zwGwB(5fcHE;Yp%#{zqN@?v;GK*M*+wmT+ui3hN!zSPfmHq`ig^Vw}EW=5kalESdvAy2&THt=gvNcI}Ha_AOl=gL!bHN zD7#|^TcgpgEpKd`|+Swd;;d|6oFy}RZ8Kfp}yC zM)lsb4EbG|Dno@udSW@b9oQvi@9)u_W0=y0C7g1;Mf~LUB2MZ;z81o2o@L0!b~=n*m60OO1*+nZ=K z%SvXe-NqG6+V>Kf=?cb(NC8~G#O-mV#V{|AO%9zp|pHtVYNXb z79TM^o3^9E&&qi?7j7Iv4PG;X#jpB<=8Rd_fm%k3rT zW-qp}EPG7S8^x~GjWMXPxJC*)XK?m9{=A*yhZT0v-%!%-Nu_(~w*z0@lbX4-_=+q; zO%`LEuOpO)cU#KYNxBL_?f-JAaD;^#UENVZoO8t=C7-63W1@L~WUMvPP%3!{oOuGQ zvT~?rqc8vi&v@Bw-p#leCdL=AoP}I+!1rVF3_xZ|zHBTWI;;8Gzy6qQZuZ<2T#_ip zW_i+=z4q97s_N#W48c09nwspLWz^RQsT^m3bma5s@L-7CKTI92~zowrbtv zF>#^Jp^r^((0NqpQV7-_^;rlN&rf0&e4doJYTGq02R^>Ls$r5|=H)W;;{p`u`6!T< zeH2T{WQ*^v)DOb*p3Dh`i6xxum2(`&@uH9cSged*xh^!fqr{a=Q?WY}ffBVxS6G9~ zdVL{GOb~*mN%dY+z5nnbE+r-Z_}CX99Pnr}eEsXW4!42Ro9*xH2&G@WkMifb>5Yaf zOGMf2~zoepTgvtRBTVkPxR+`L0KnTBiO5%&HpfrsxYq@xkC&Zh1p_x1uYx z{Vh|iIj<}^A1>}x3+VeF!Wiz~>3yGN!A;(Ncw={+rBa*-qOl!jbDg5jym;~A?2h-G zdo{aE$nkM+@p1tL6EC;*apgY9x_dvb{+#cfrx^I=T)Fa2F^CtED`9VNo|>fkIIx=* z(-jx>}S1Y3=h6FnS}qxQQ`L%%4B*C(Nqi zx-Rp&4djsA7t;?k7>TW?%k~x4F{D~uNy-l8`HwLUOx}J80_kR|zm7`Ge<67xsQ5KR zfjQhAo0_p717$eBXhEpw+B!*X(VMeIK1 zf5h0*Pwas#l>y?PwPDolgZSg9pcJK+##f7h^@<}Syph;{Omddgx-v2$16us2ZW1K~vJHc6z~;l5dCBZD{&fppLO(!>B4G_-TWPI#Kl<9kwgS1}2+A}VUs zlY|et1d^C(`iRTDg9A(DFOx-$;U~1qDTs?b3b&0i#@7coi7M6OLz2ZZ=1e?1D|yzM9dZEa zMVytfTIl;>T$geX3cQkfRhv(IMqf6c2jG9%|K#-r9Cz0JJz2Cv>m|Jdo4$t~9VJWK zpvYZ?tx?_Xr}26JA%C#DM;7n5T0W^%>n)Dt<&N4NX7_}neLSoObBmsW%m_mp-&B2J zuH&}vvmUqmQ|OLi>5E6YiE}Rw_zi5vLe35owwtLDDs>j}2diT@94DZ_*_Mm(B#0tY zBXg9WQKg2&%q8oQd!6_{o*7{`_(PWl+I4sKNpk7<(Z7c}1(orJwr1AWVDI1-`rMNf z84mV{Aw?O8~J+>2;Q&#E2?12*VmI*3|wYw;2j#XCH2;ki@ryoiP=Z%AmuB3c7 zRRqG=w>`R-v9SJF9&|$AyQv`>+3$_c|DH|@*4b@B_1?TeocKjZqg8tDwkevMyLabw z94!rAPGJVe2F>q=Bbm1pGnOo-#lS{abcN=amq z{@xpvqV@o$=l^&VLWSV=U#~@hrev}ILKVdNdE;6-$&xW=xk^$7dqi0lS>E!5L87!? zM|-guQq6l+gixm|s&TA?|EhjB~@WSdP=Lq7LB@%YFA0liWE$vq^pSt_v zSB#pH?U3SFx$;cg*sj@R9gfL^#*Rpi4R9GtIo|x}C6H)tJ&okyMGZV(Ob@ZMEe;4c z0@-3}S*s8mXm@sk!q}p&szzo$Ej|MIpM;3+nVKci{@Y`u|0p7-%A{e6RX^Nzjlriw_T(_cC?3s2lb7U&@&ZLK#$P$L;&=QPxJBoniRU#Bz3~n#7?rg<|(BqWK#BkSPmUoI~>7 zjyz8lD^M?W2kVd`{36tzOVpYzCBT2`!V^et1;i^`hCD_4Dit%x`9&8&=yVq*iFUn@ z*B)1-Y?){5&v55k;vz#A3^zr)8Iq&{k)-B}9 z-bNL7igM@5P32ej?5*AbsIboor$VT!M~#A8KJPYbeDjK^UF3OcEJ9+?ZRy3B|MHM{ zeF5yMkBxdXmDICD*-1njfDP>2Sn@W&1JwB)7<}mO*ie1F2mo>$uTReB; zOp78kklyGLWdX;H>Lng-_T~dO%`Bx4bUJ2>$&7h<1Rel~3X?Q~0hp@C5J+5GRTY0U-~O8mI2Pl%fqvcQx>!y$X1We zQ2+X5v2s53L+f^AM!2luVVf*RL|f`b*GjbE5NCoSXn(>Ox&4mv=d|bMl}`>~mMNSV z>#L)3qw5nsDCylunZxhl<&Ft;XA>8b4oM2F`!n2E(Z`P*99~TDLL5mM?TxyX&ZzU0 z3>p0OmgnfNUCUO8VCE4NOyJ1ZE`Hejma;!nCFy(P!ylie#}GwJwhhp-oT?Y5i=HYM0=Z+!dCF+|<7_-N00DB|dlr+GsZ2vaFhmSJ(=LPiYVW^I*9lAVa{uZPw@D@NB{4(8&= zc6P_ylRsbASLWsX=FLX+7tQG&=%v`WiP6c)jB#;s+=7B?!DQ5kwRIR5A^3)i%`i?g zPgX&+c&`+<4P?NsIv3HDgJ3>gKeLnEs9s0Q4E^q+OJ04?m6|QBc(iZEd$+Hy7Jyuh zF)U@OD8!KrqQ#w-h;F(sQ{`0+Uwf*O?;LGj%$#GPCW}DAoXxmj`9OWZMr9Tf%XR%^ zv^*hRFrlObK#zPAH}xoCo7lkx;=mViW#Za$U%d9ls#Zh9cCnt1w zw-+vZj{mI0-3(Fm80R$b&avk@^re%7mpi1uqbF-du-6JJ9#);W`vf`du58pR0Lu29 zwp>uQp?_ncqmlLSoncag z>sm%kzFnZ$uh+~R9|E?eZgp?^17IDMWKXXBWjL;iy{2r3ylXbU$0DL6F`qnj7a38d3q@az`}vAv z5Sw3S`eu6vPe;C58bN!tM1t!oE%v?2CN8kZ`T%+Nt=aH}PDe?&yKC#kC$5 z=*t^MJ_zG|vO`$;2Db(xKr$%5d9$05)-T)Vj`(s@NVDVnOBs)~O5Alz#r`Zk&Vzn6 z$KhilR$Tz$_vv?P3=6?Sd-hR@GtaZ7Em)5IN z1K=F6DZiK&j5ZIS#Nc&F_rsa^$$frbw?1;uNt2UUyFWh}m$=0EN&2j2&Ynn4>Lyv| z11G2AlG0N6vuCUkZR~({qmPij`3@vTGG?oMCl0+Z9zp85Og%9`mgJ+GyPqSJkiMpQ z8e}Ydpmn>yHxq%Nar@OYgjMZG>ZeDUL@!l?)cnfHX`n8qP<}DeBRRdJ~27rRb zTO&MFEm&mqb&DDfMAqwgnfzQghU<=WpMjLguV=ASDdAS)BWUE{M-w3_P~kqbG^pWF zke@g=`%H^MZY90x?xm?c1l4qWA%EGiN?_`Zp<-cF^ou#q)2`t zkpCg8l&{QUml(gG?Lc<#?*0BuSb`DrefLT<_x4m{{I>rhYRGPMzBDe!$p3=>iCF~c zycrCkI$gVGx5LNYoTx21xJew?+Cq0T@X3rbtc}I!=-}N|{$jr&zV_Al(@koM0uH@& z?}eM4i_v_W7%c(!Lpd9)|Si84sx6?g<#x4E0&#ru>Vwc2{@9HcJ(gMdP!FwT04(qk>6U z*$OI}{uEJ(w>YERhiIxYEs+?mi+dw&b%Of0{SHtAWjS&0_E*KmG>(6f<%Plf=Mt0y zj=#>ijlX;}JaGjYcn`Y6)4xgk=PqPTY1!X{a+j)Hi|M4?yk;mD)dDU8mZ`YqaMHhY z^;=eIw5pUk=bnkM!Jb*<{wBcpc&v!}7_Min0NqH1Jv+E@s7#Vf=ioOl!whkGI)C_YHDazy$okgI6Gr{B-b$wLI5S z9?uULzSSI=gw7@7u21UqcxE5FmvOtX*8omg)HBNza}^}LKy3K^hoJvy5COr( z1v|KNzG@XK=fez3tkOR+~ za?#8>zXxNy*Ro_m$#AU(=Qd`KgKNoK)Irf?Up*@|Yy!Qnf8Up0 z{ByWYd#FkhpCDS3ivkTmcZKsY=)`n%5Dvu9Qqw=hV!y<%8kAVv&&pTDzq?Su)bVwv zqtPn?`{`>(!T_6l=WaJqr1Kg?V}8NZ$`6FOvw?X1w-?~bRV^d?E)-D%;QXNJiDdD{ z#<&-1v{cM|_QS>x5Y_ID^GRaVwQBNjwvV^EL4WFZS}7b*w>=w!74bUW1iL?EUK z1ET)4p}iXM8YaO{O|9Hp7xZwsL-l9;wAU2P+J@Fo+n6ldHwWQx9rooY_VzAfn)iPb z2E>~v^pD)~o)lY5p)R(}c&S^`!|=K5k-M^Cz{Z2TwKY7z&3;wzG?u#$mqz*vsuyp~ zAE9;3)b0@nvix26SWowT(~9j0AB{r8_=KIwv(d_U{#EYQlf8%u zDWaD1AO`l$R15LE;9>fVRor(wYM{P;hnMl*W8D%$=E`l)%Fw3WFYS)*mc}ocjXNu| zRz!0YYE}JuyU@iVw~_`pv8Aq5&f;iNj#r?vXT;bgsYllxc0^ApL}243qw`I>QtiET z#3mMek(ny&LPk(=7}%Xa?T_v$tUn*bTR)hG%GY~Tc(N*{*X8`@a2ZGhBcjvmX9$wW z*Pt4Muve5}j*#}!9tYfff*}vak>#%&cjT%z9xk39p~{4B*!Ho#to!otaPkbzuU7A$ z{@_O7tXy<8N%YTGv$I<;7XRD)hI~w}k**Cyh~0Gb)5BdoABkd*^@b%lD8kYkfdB+; zNwfGpmpD8AUP}fQzk)i6i0A?hiv4RjztPjZP4$^)0`w!hEEm*AusaAp8^hu}CUs5+ zFDq!zc?MWC7Psjd@B^;sZ&r%PDiqZDi2zwoy94JOHRQq%GP&8}AX3N#Yp=I3-0%vQ z0o&$37flMx60b*8#7JdzZtF}o=V-28cnrOZ0KSc;l~8uRO=)TA?VmAfx*t-Qr8AZb z%d=>RIGBM8!s^`T&p_mS6Rrh^O$G?&>zdoUNw}At@6Sr*@jG#woxhOg6gj&V$l(F~ zD)FxcbU3d5%wP}m`7@m-#$kMai@3J}Ai%&U1K51m-I1MY_f9(7JCv-afY#j*T=J?l z1drnHWNA0O_u|)TwVbQ-FZv?lx7_k|bs9CG%?J?SKo4CS${!0i!(JqMJ;qz8C}cTG zXA1Hr-cZ9GE9`?6dAByG?0smx>_^UeN-$dp2q4_uu>{5+;0^a`>-|eOV>w2Yv&4>md+w;y*v-;B*6UoIg`4*LVV|KWGH|2BESYH<8 zDtZ6Dz8Eg~MN}H9eg*EdsiM6#(qqz|SHCMs?*kJEPQsJliO3WK&Zk|gS=P9E(P+3{FK=qFH zd`}~{4LEQ3ej^#~YlIR7{dpu(OpQVO9*-u;GisGD(yv-0lai`u=06Kr+8q3u3&)#V zSe!SYfQp;uqIZXzol9g6IQD=33Q-PWqKmU8%FcRyspweLaRPm`UT=gPI3BwIO*fEG zD;Cx>OS#X4;X*It(jH)&2J7p$k!Om2M^7xnp=3^1sv%h*r5U)7m^)XG-<;Rb)QpRY zN^cA%vz=~v_s6?d{nJfoz@b00w>V!9Wfl<^&tDoZ0Z2P@MyMtJ^^eAAz^NWQ$x3lg zjOW+O97r7bG8h{dXZ>fkori}9w=z=7Intq(hsZB;UDT)?cOWQA2ysjpiQN6;jbPWQ zSFhyq;Jk|oMh^?OJULFo$iYD=i%$33WS3rFRqaKd9nVV?8dSOFJo)%nx(djwSa6)x z(jFPNx^NCpD9nBt0U8F>EtQPEuYd?kDID{098+Bx9}CaRUGY(RxULBm^WJnRiWf90 zIM|wBKA1-q?j-(K`S_<(0g(BlGiqw2fT>3}Nm|lgnpp0>`HOQ`M#r%E(hY~FK8rv~ zxvEyylyO5;J12x&Gdqd&@uPH)#4o=GHUr(32dapGz{$OD9=$_HgJC}sZZ%yP3FF9HXjftq4! z0FQIU!P3>POMrItkcrvt`AiQ*pos@FH2qBJy|86Cs6=i?)eb3hj(v9+LK(rn57iV% z0Q(haE80xxA5XdYyXx@1o}bdut_~Kkbe*Dnsk)GTB+W1##A=b^mRUP6;a;!s~gliFP{*w20 zAnKDq@=_;QK%LWQNX6;2#Vv) zhjLskBdW8~P56A5UC>yR5K$&hL zuyx>6A`R`;jXWGNAL`>cIt^+2Z$i7H*y#=J}n>%Qm`Uz|~oQr&$D6BVaP2 zlGWF(t?HX3rqNP#_J~9x3mwL*R`1^$VFI@lqr@O}Khh^I>L$Ra(hu%?6u7R}60n*5 zsP-nVnVP!BeO$sCsEgm|^NU^Qy8(hH>qfdpZ+Gxs_LG!*YI|k%LJM2KoqucXnC7k% z$u+N5X4%u$9c0>*G5eqg3Q}B84{!j#7aTRS1O@XVdkT_d40J1cTk8&P?N2P@#ZHf3 zc{YKru0t47qyvO=S0ZTypz^WySe#qa1;m#J&i+l$N__Kyj;<@pReI z4Blho7;yrO#?dOy5~*X1DGhi(KTD%eBm%5`a#vg`Gw_Bn1fF5_Q3%khhCRD3ZbaMj z4s9RIYj{@y&c%gII`SjXbsIp1)V_-|X-3{#lR_CG{Cl;)5msxuN26x5&{ za|`#`Qi)oYF;R+|<0=C99IMSEr0s4LA1Wb$^lKXr53FCxUFf0=6;M0Y*!D&Xf> zsOaGucM6%a0er{yxJNuB>s_{U4{dmzS@E&mWeMXCG|UJ8e+VxV6z)w}#InExRp7red13EFLHDPz50w}YwRh8}t&KBj;g;PpZf2L=3L zR|lnz;Avb*{CH_mFrc_)uU~cS0HeTSKgr9RKc7B%w61)WOE>zMw~)r}W?eDp-+;-n z=!l0WgWfQbIpC*~B;Y$pjs1?4==E8{SOihWr#(kNo1W`TS$Fx{ME1mPR8AZ0)qg6g z`?FHZgihL3Ya%&)pM8_XR3E#!r67uo`m^yrMkc4m`NVYU0-NDK*A z71mE2Xdmsy2fGcMXsl0QtK8a{E+;Y5xPzOR_LKyAjsG(@)CueqlBz0kpiicfsaV4o z=$hl*SFA)ZiA8%s_ZwI=A-S*1V_LdZ1E~yrf(hLc$_#hX*6_94(b91XMi=iduu@>j zOK6q}d;$oQmbWI&8EP^YnDvU}7-Xa*wuqKK0B%R_$I<||>&i!=46iLVS$bnFQ0<{F z(_@YV3k8s}+~Z?_lKJE#IWsR`nSC=5Ed#3Gj{1I8IL%MCNSc^V?!@@GRyn!-n4om6*7SQ(uhF0z%I&*SAgJkANcZXm1MZUAm z;n8Gpgka6Hj&6q!2g>QFA(Aw(S567|`7 zCx3UW2a%(pk-;7wDNwI(GcK`xNXAmuvNsB%3?$5f+&Io}lK}x{U5weXpm~30bq)H` zyo}iu_wq`g2h?IvDJ%x<*WE~_+@Gl<=hn&Jh!@bm&E%~3IP=ndQ&I|uMhJ8_tIaX0 z7o`)Dcu#&&(@D|NDGAoFx~Jz6-##yxAZo54c1}EHU+K*$_-O(b~V%%~C;%-_k?D=B~Iu8H&okQ?Io*eO5(gc$1sXWsEU_KENhWDEqF^XyCNKUL|2FGRzV zOV5>Wy^L7)7|u^BGnL<{1l~xQ<7c|{bx!jkvkwC2{<}0s3=Omm}Y| zW;Ak*8pum<1zR75t0q=C_U!6iUIBY)mwese&~XF$vlNX6TVU zq<=KC7snkSWf=tceO0>(14fZo%X=agfO3pzE1mfZqB+9hG7$Mdc_(9uRZ_~J5G;$! zx9G})Pv85Sg8vul%D+xW8@ChRym8HIBVl?pU`X8w*;pBmS zI~s6i)pKPtTxkso%y2$C*)2;qDm28RhS56PzhAdB6ILfj>fpu3rpF}A$p3muC94y` zY#!YaNYvP-lB6W<^Tbj>QQz(|F?g=b8X;&qA?1^}5iXgryZTj{mm@L5ppl1pH$*4rm-gDw;}SoR-~=@9z@ zM@j}Po{@S$OQX;jAaouvF|pBp2zuO*;&Gn-a_yRgEwUf|nX~HbpeLPnf)nt!yvE)? zop9fyqLKus^)$#p2APdQvPk?c41u#GiG?@{DEh*xY<<- z?s~lWD~0-s9*&-YpO?3PwmpV`Hb+V=m7@tQ03u)4dJ%^Lh#rG*$?A}VS`vUrT7@4kawOXhV3?RXhw7Vqc3%?x=R*32Vxd9t)&{i-6fVj156-k57KAg@ZFYQ zO>bTmD=+=1`jeox z^Os&y;R3;m+TaUP>W$8ZHUf$VA~N9v)(|F|5v4V4aFxiqZ+>SpD4DG#p&TmWK3+%s8h2cHMo}hn@?2tfc+^PDH9Ox* zee|Xmq1l(?&s3q1Ib9L51_*_A`BzB(H`NH{cqDwQO8x_zm|6>=m4|Hl^7R(9K`$^D zhdY>82F572vbR)}b(yfMoqd4oe)r^N`#aE*2I@*37YX}%E_muDKChLUCZX15w<;eC zDv4r8o$Mu?rz*4AD6C_s6lWKW44w-llt{N88Qv6+)HrjizK7n^7p%9f=52wu+rD|} zaHn)>Ly;M#M+Odj2-*~i?2b-gE$L9*4FE*vVE$4k{o-PntU?PNmYnH7$RQ+9MyBpY zSt$VPulIb`itQi6Z1Ad8>vgS27E=mfOZ&66HJGn!!LIiP3S1I(hz0G#;Vz{;az+cz znXh9u_HG$JcJY&@4E+^AkOogro0?l%=7F-s9Fa8yie2DrsYx(rVWEL-o0=>?@F#D% zf%KasO4?dbZ+JLIpQCca=VGyi7a0c?fw>Cij%aJ{poLh!>p7AJ@wVsI(9EUQA7F54yQHNF@Pl- zYTL*{W)P8p0S5-l?og@dpG4pd06U!>M7RR3b;5^CmcPP1KdjuI*TA&brk<;VL*Fme5Mnwmu$$;|)RM}{c$08drs=9Xa?^GM%3$TfA_S*np zfT|bQ0}@)pVoFNv26KOJJtHN>sVfW`j5Zd+^EP@e_dNi^L=6r~YUTGXC5b7^%i~Dt z&mmc)bs6qH1UvQg*zzcMr2JV4gWhKD7U~~%C@S+jV33h&K&2vhKLXCil*FIIM=DG1Sx-OCyI7Amyv7oy#Zf8w zy{AX3++p0EF=mAdBG1a#%l9yGlb1&*FN3!MyQj=vI~VQ&nY@F))qQ|J_JeZ>gEzH? z|1x+JsfgHZraZk+!h929*`s#Bi&hNBfjkN(GJu01Mcibs7~CqkOB-C3S{@BV=d?E8 z6E@mkcN~&qW3Jv`>u$-BbKI9UuW_O;)}}WPlC$ ziUg&=T-@Rwl(*kXSXK2{q#%>i>*t0JZIixc-<~+uiC1ksY^GrWsY?C>JsBW9dt^Rz z>(j^(M#diZ0Zqr&@aH+PS)98Kn}1q%R8!OGl4Ctq@=_F zGpKflBM|XG82Bp14t(Q0JkemQTKtIg-nmFszyb8LFG7L?VSwlxOp^AIVosDMf!NmO z5>S0#^R-Ou-(Gt6)3?Z$;PRQIdf`I@(eR5+>ifKmi)I5ZV$eZGrCePi5Sf90m9;Tr zkT+!XK?k4X=VN{BX+4GwRiW4cY7;<&R-?k!K&}JL7hw0nzzxTqQ2=I;w;pKqb$+P4 zg7*{pm;YInfkGsZ4kY}6x7Y08AWW8Jh2ifT#SVOQ82cOd9VYavHk!Z`RW|`=v4*=Y z7>~Vmthbk@h>#g|E~e4DExZKg<#>2`mB9>{LOU2X`*KrIt?D;}@{9UYZ=l0|k!Bwt zs2osBQH&avmKS#TN7=fIAxEA<@^n*S5qQdeJhe?JE#;!VtOL*|MDrCiZE?ILZD42K z5FPFTGM5^yYAPQ{3~Cw zV$GG?mnoT(#MG*`H5SV!83GE(S=-0|MIDYqBGsxH!AKSlZw$cvfa(EQvVA^Aiup*l z7U2K(7*zGz`+eaUI$rJnDH@<45!+iTNP&MMcKA==ij0!WN04-UX~<0wTZUP-nb~l&9&d6X51Vy#BnPydnBD8k`fg z?avA)-5O7)?{1$zf9~k&3fl(0+R*H|PShi6jQ^WxfUR+o>)J(cTB9QMUY|}WMLRn? zmxUvyp+FAzqt#d737LI4@0qY{6)tXYaQOH@j;7o1&z5gLW@TpbfO7=4nW2_q#>fBmG|Mj`dSD1T=} zzkh!*j9FUufU}YNt2F4yK z&7*@q&dcVCfwcY?t{ba>u`h0J?kX^#W>cG)o2vw-Bf(>9zDKJkRoWwY8F!ezqgiCiP}Y3g=kw}7`83==$htGKw>m#Xfp_#N;#kTGyv=E4OZzUJ`#3^GBW z;{QHY3L+j%4m`Ea8EhV{GXP^&Kq$59xxGnX93o$+O2ZSydi?!&b-2Z}luXok(fjwA z_H7G+3m8-}^$)aA;-5Imyn7Ek>M+O+$#5`Zat;n}91G&rQVL-rbhHDRu`dY)Q1KqPBXhVfqyyi6qnQE=Q%WVr6`o2GD6$2R$1+Dxfpv3?jZsXML0V$8^nHK;i+RVR zzXw&#+n0CNvfqJ$)MrM7*6qK|4*zGW79vnQ|J%gw(_oUbnBf1MlR~)wUir^==D8kL zkqc=juOR6b-7Tr6i{%5SWJE}^a=-#avamV^Mrh)h1N0ey`dN8zROo}+-+wf8T+r6} z4B%lDQkf07Kq07V-;^Mi-%U`KmNFldHHb8yg_1P&IUZ|u^dMl4Q)?4-P z$@G2bB_cF2a*u!+<$oO%|JP~feLMM!m0DCM=9xWcg(LC?@7Db;99xl&WMHtF0E{qykyRCT_?o*z9Y+$$meB13aD}P_VRo=1#LvBpSx?lQ_q=O&>N3+WTUD%=g8Bi7fmQeF zbK0Sy z#b#}}j+1pufTro)2jkEp&a;YyvFrI{mvHdPB{!;WRq?rN1YU!LjB22fj0Ft_xL5AC zSuz=V04PLte+r^xy#EZif)kj%W-r5hyTj}|V!1nh{J6w0BSeh^LbHf9?y( zHmE(*y88F$UcL3Sm)^)X9h}GlI3Q5>^x5C_RNn1Mk<=2b-PZViAL-@!5AUT_Sy`!D zWc-RlW@dc)Q7Gu&ksL_;a@g+kD;;~20qdRLzYja<8yc?J_I-Kd2&%OVvSYD4 z47B6RQXz-!U0pjEFupjywW%YPSyFOu5@_h_)yIE250Y=Fo0z17(OUmHFrdD%r^pWG z2R1NvBloO6_IU0U1-;4Esdmrr=`qcXz5CA-ARHDPF%ngD}1E z2pr|@rR!h7+T|P8>Vn(Kg>+%h$PzzJKqXY77=} zntlvc8eG@oz&D?MZ5`O~UnwtjAxG%w&uxGMJsQ0?1AO4{dGUdQFJB%Kg!bKGGivFrA3~r(i)pbO|Mb(LoM6Tm zoAiz8sf_xOEUpPSJ9L%DdO0$!lH z$*aY+hK||{>Pdq3SZTapSH{SR0!sPzEd>f$R(Gv5{@Vhcw z8{EKhT}Ev%P7A(!nZz*;HbKOp`exBo5497IhL> zJ&3&Y%yB(jh2wS8?T>~Oe-#rSt=sZEqj(u?9#3h=>iOV&cl(dijb?iNSESIhTc8wn zoTG!}J_As2`zpu@=EM|G+EY;RVlVJPf%jgC7=r>{@yM8Rzd2oNP=Rb3dVEM`HEyMAiX z=;cIn9cRY2W_luMvSoOy!E);01dQd*11sV`pWVRlDU-Y1(aO)10-ECazxY(!hG8M- zWk>_Vo!v{&Pm>QX|I_ck-qHN0tN-6m-A;o4Itldr0FW#HFYe<1^@~QRDPA>BewC;q Rd}#*+lUIFQ@X$Eu{{Y)ke@y@Y literal 0 HcmV?d00001 From 6b047195c4e38e01cd58e7f81d9b08f476ef7cf7 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Fri, 11 Sep 2015 18:31:47 +0900 Subject: [PATCH 0832/1872] Commit tutorial/ on branch tutorial --- src/doc/ja/tutorial/afterword.rst | 150 ++++ src/doc/ja/tutorial/appendix.rst | 33 + src/doc/ja/tutorial/bibliography.rst | 52 ++ src/doc/ja/tutorial/conf.py | 48 ++ src/doc/ja/tutorial/index.rst | 37 + src/doc/ja/tutorial/interactive_shell.rst | 984 ++++++++++++++++++++++ src/doc/ja/tutorial/interfaces.rst | 309 +++++++ src/doc/ja/tutorial/introduction.rst | 132 +++ src/doc/ja/tutorial/japanesesupport.py | 20 + src/doc/ja/tutorial/latex.rst | 417 +++++++++ src/doc/ja/tutorial/programming.rst | 794 +++++++++++++++++ src/doc/ja/tutorial/sagetex.rst | 233 +++++ src/doc/ja/tutorial/tour.rst | 24 + src/doc/ja/tutorial/tour_advanced.rst | 527 ++++++++++++ src/doc/ja/tutorial/tour_algebra.rst | 409 +++++++++ src/doc/ja/tutorial/tour_assignment.rst | 102 +++ src/doc/ja/tutorial/tour_coercion.rst | 360 ++++++++ src/doc/ja/tutorial/tour_functions.rst | 249 ++++++ src/doc/ja/tutorial/tour_groups.rst | 89 ++ src/doc/ja/tutorial/tour_help.rst | 367 ++++++++ src/doc/ja/tutorial/tour_linalg.rst | 269 ++++++ src/doc/ja/tutorial/tour_numtheory.rst | 172 ++++ src/doc/ja/tutorial/tour_plotting.rst | 229 +++++ src/doc/ja/tutorial/tour_polynomial.rst | 321 +++++++ src/doc/ja/tutorial/tour_rings.rst | 149 ++++ 25 files changed, 6476 insertions(+) create mode 100755 src/doc/ja/tutorial/afterword.rst create mode 100755 src/doc/ja/tutorial/appendix.rst create mode 100755 src/doc/ja/tutorial/bibliography.rst create mode 100755 src/doc/ja/tutorial/conf.py create mode 100755 src/doc/ja/tutorial/index.rst create mode 100755 src/doc/ja/tutorial/interactive_shell.rst create mode 100755 src/doc/ja/tutorial/interfaces.rst create mode 100755 src/doc/ja/tutorial/introduction.rst create mode 100755 src/doc/ja/tutorial/japanesesupport.py create mode 100755 src/doc/ja/tutorial/latex.rst create mode 100755 src/doc/ja/tutorial/programming.rst create mode 100644 src/doc/ja/tutorial/sagetex.rst create mode 100755 src/doc/ja/tutorial/tour.rst create mode 100755 src/doc/ja/tutorial/tour_advanced.rst create mode 100755 src/doc/ja/tutorial/tour_algebra.rst create mode 100755 src/doc/ja/tutorial/tour_assignment.rst create mode 100755 src/doc/ja/tutorial/tour_coercion.rst create mode 100755 src/doc/ja/tutorial/tour_functions.rst create mode 100755 src/doc/ja/tutorial/tour_groups.rst create mode 100755 src/doc/ja/tutorial/tour_help.rst create mode 100755 src/doc/ja/tutorial/tour_linalg.rst create mode 100755 src/doc/ja/tutorial/tour_numtheory.rst create mode 100755 src/doc/ja/tutorial/tour_plotting.rst create mode 100755 src/doc/ja/tutorial/tour_polynomial.rst create mode 100755 src/doc/ja/tutorial/tour_rings.rst diff --git a/src/doc/ja/tutorial/afterword.rst b/src/doc/ja/tutorial/afterword.rst new file mode 100755 index 00000000000..5cee7577c51 --- /dev/null +++ b/src/doc/ja/tutorial/afterword.rst @@ -0,0 +1,150 @@ +========== + あとがき +========== + +なぜPyhtonなのか +================== + +Pythonの強み +------------- + +Sageの実装には主要言語としてPython([Py]_ を参照)が採用されている. +高速性を要する部分のコードはコンパイラ言語で実装されているものの,Pythonには固有の利点がある: + +- **オブジェクト保存機能** が充実している.Pythonは,(ほぼ)いかなるオブジェクトでもディスクファイルあるいはデータベースとして保存するための機能を豊富に備えている. + +- 優秀な **ドキュメント作成支援機能** を備えている. + 関数やパッケージ群のソースコードに対しては,ドキュメントの抽出と全具体例の検証までが自動化されている. + 具体例の自動検証は常時行なわれており,記載通りの動作を保証している. + +- **メモリ管理**: Pythonは,入念に設計された頑健なメモリ管理機能と,循環参照を間違いなく処理するガーベッジコレクタを備えており,異なるファイル内で定義された局所変数群も問題なく扱うことができる. + +- Pythonで利用できる **豊富なパッケージ群** は,Sageユーザにとっても非常に有益であることは間違いない. + 数値解析,線形代数,2次元および3次元グラフィクス,ネットワーキング(例えばtwistedを経由した分散処理とサーバー構築),データベース対応など,幅広い分野のパッケージが用意されている. + +- **高い移植性**: 一般的なプラットフォームでは,Pythonをソースコードからビルドするのは簡単で時間もかからない仕事である. + +- **例外処理**: Pythonは,細部まで考え抜かれ洗練された例外処理システムを備えている. + この例外処理システムを使えば,呼出し先のコードでエラーが発生した場合でもプログラム本体を破綻なく障害から復帰させることが可能だ. + +- **デバッガ**: 何らかの理由でコードがうまく動かない場合,Pythonのデバッガを使って詳細なスタックトレースを実行したり関連変数全ての状態を調べることができるし,スタック内を上下動することも可能だ. + +- **プロファイラ**: Pythonのプロファイラを使えば,実際にコードを動かして関数の呼出し回数と処理時間を調べることができる. + +- **汎用言語**: 数学指向の **独自言語** を開発したMagma, Maple,Mathematica, Matlab,GP/PARI, GAP, Macaulay 2, Simathなどとは違って,Sageは広く普及している汎用言語Pythonを採用している. + オープンソースの代表的成功事例であるPythonは,安定した開発体制下,熟練したソフトウェア技術者多数によって研究開発と最適化が進められている([PyDev]_ を参照). + + +.. _section-mathannoy: + + +前処理パーサ: SageとPython の相違点 +---------------------------------------- + +Pythonの数学機能には混乱を招きがちな面があり,SageにはPythonとは異なる振舞いを示す部分がある. + + +- **べき乗の記法:** ``**`` と ``^`` の意味が異なる. Pythonでは ``^`` は "xor"の意味で,べき乗を意味しない. + したがって,Pythonでは + + :: + + >>> 2^8 + 10 + >>> 3^2 + 1 + >>> 3**2 + 9 + + この ``^`` の使い方は奇妙な感じがするし,「排他的論理和」機能をほとんど使わない純粋な数学研究では無駄でもある. + Sageでは,Pythonに送る前に全コマンド行に対して文字列中にない限り ``^`` を ``**`` に置換する前処理をしている: + + :: + + sage: 2^8 + 256 + sage: 3^2 + 9 + sage: "3^2" + '3^2' + + Sageでは,ビット単位のXOR演算子は ``^^`` である. + 同じ記号は代入演算子 ``^^=`` にも応用されている: + + :: + + sage: 3^^2 + 1 + sage: a = 2 + sage: a ^^= 8 + sage: a + 10 + +- **整数の除算:** Pythonにおける式 ``2/3`` は,数学者が当然と思う値にならない. + Pythonでは, ``m`` と ``n`` がint型であれば, ``m/n`` つまり ``m`` を ``n`` で割った商もint型になる. + ``2/3=0`` となるのはこのためだ. + Pythonコミュニティでは,仕様を変更して ``2/3`` は浮動小数点数 ``0.6666...`` を返し, ``2//3`` は ``0`` を返すよう修正すべきという議論が続いている. + + この問題を解決するために,Sageインタプリタは整数リテラルを ``Integer()`` でラップし,その除算を有理数のコンストラクタとして機能させている. + 具体例を見てみよう: + + :: + + sage: 2/3 + 2/3 + sage: (2/3).parent() + Rational Field + sage: 2//3 + 0 + sage: int(2)/int(3) + 0 + +- **長整数:** Python本体は,C言語由来のint型だけではなく任意精度整数をサポートしている. + Pythonの任意精度整数はGMP提供のものと比べると著しく速度が劣り,通常のintと区別するために末尾に ``L`` を付けて出力される仕様になっている(この仕様はすぐには変更されそうにない). + Sageの任意精度整数はGMP C-ライブラリを使って実装されており,末尾の ``L`` なしで出力される. + + +Sageでは,(一部の人たちが内輪でやっているように)Pythonインタプリタそのものを改造することはせず,Python言語をそのままの形で使っている. +代りにIPythonに対する前処理パーサを開発して,IPythonコマンドラインの振舞いを数学者に馴染めるようにしてある. +これにより既存のPythonプログラムは例外なくSageで使えることになるが,Sageにインポートして使うパッケージを開発する場合には標準的なPythonの書法に従わなければならない. + + +(インターネットで見つけたPythonライブラリをインストールする場合は, ``python`` コマンドではなく ``sage -python`` としてインストール手順に従えばよい. +こうすると, ``sage -python setup.py install`` の意味になる.) + + +Sageプロジェクトを手助けするには? +================================== + +Sageプロジェクトに助力いただけるのなら,たいへん有難い. +実質的なコードの提供からSageドキュメンテーションの追加やバグ報告まで,どんな形であれ大歓迎である. + + +開発者向けの情報については、SageのWebページをご覧いただきたい. +優先順位とカテゴリー順に整理されたSage関連プロジェクトの長いリストが見つかるはずだ. +開発に役立つ情報は `Sage Developer's Guide `_ にも載っているし,Googleグループ ``sage-devel`` も役立つ. + + + +Sageを引用するには +================== + +Sageを使って論文を書く場合は,Sageによる計算が行なわれたことを明記するため,以下の一文を参考文献として引用していただきたい(Version 4.3の部分は実際に使用したバージョン番号に修正してください.): + +:: + + [Sage] William A. Stein et al., Sage Mathematics Software (Version 4.3). + The Sage Development Team, 2009, http://www.sagemath.org. + +さらに,Sageを構成するPARI,GAP,Singular,Maximaなどのシステムの内,どれを計算に利用したのかを特定してそのシステムも引用していただけるようお願いする. +もし計算に使ったソフトウェアがどれなのか確信がもてない場合は, Googleグループ ``sage-devel`` で気軽に尋ねてみよう. +こうした点については, :ref:`section-univariate` 節に詳しい話がある. + + +------------ + +このチュートリアルを最後まで読み終えた方は,どのくらい時間がかかったかGoogleグループ ``sage-devel`` で教えていただければ幸いである. + +どうかSageで楽しんでほしい. + + diff --git a/src/doc/ja/tutorial/appendix.rst b/src/doc/ja/tutorial/appendix.rst new file mode 100755 index 00000000000..598e035f840 --- /dev/null +++ b/src/doc/ja/tutorial/appendix.rst @@ -0,0 +1,33 @@ +.. Appendix +******** +付録 +******** + +.. _section-precedence: + +算術二項演算子の優先順位 +======================================= + +式 ``3^2*4 + 2%5`` は,どのようにして評価されるのだろうか? +その値(38)を決定しているのが,『演算子優先順位表』である.以下に示す順位表は、 +G. Rossum と F. Drakeによる *Python Language Reference Manual* の§5.14 にある表を基にしたものだ. +表中,下へ行くほど演算子の優先順位が高くなっている. + +========================== ================= +演算子 説明 +========================== ================= +or 論理和 +and 論理積 +not 論理否定 +in, not in 包含テスト +is, is not 同一性テスト +>, <=, >, >=, ==, != 比較 ++, - 加算,減算 +\*, /, % 乗算,除算,剰余 +\*\*, ^ べき乗 +========================== ================= + +したがって ``3^2*4 + 2%5`` の値を求めるに際して,Sageはこの式を ``((3^2)*4) + (2%5)`` のように括弧で区切ることになる. +次に ``3^2`` の値 ``9`` を計算し,ついで ``(3^2)*4`` と ``2%5`` 両方の値を求めてから,全てを足し合わせて出来上がりだ. + + diff --git a/src/doc/ja/tutorial/bibliography.rst b/src/doc/ja/tutorial/bibliography.rst new file mode 100755 index 00000000000..db092568660 --- /dev/null +++ b/src/doc/ja/tutorial/bibliography.rst @@ -0,0 +1,52 @@ +************ +Bibliography +************ + +.. [Cyt] Cython, http://www.cython.org. + +.. [Dive] Dive into Python, http://www.diveintopython.net/ から無料でダウンロードできる.Python3対応の日本語版は http://diveintopython3-ja.rdy.jp/ で公開されている. + +.. [GAP] The GAP Group, GAP - Groups, Algorithms, and + Programming, Version 4.4; 2005, http://www.gap-system.org + +.. [GAPkg] GAP Packages, + http://www.gap-system.org/Packages/packages.html + +.. [GP] PARI/GP http://pari.math.u-bordeaux.fr/. + +.. [Ip] The IPython shell http://ipython.scipy.org. + +.. [Jmol] Jmol: Jmol: オープンソース 分子構造 JAVA 3Dビューワ + http://www.jmol.org/. + +.. [Mag] Magma http://magma.maths.usyd.edu.au/magma/. + +.. [Max] Maxima http://maxima.sf.net/ + +.. [NagleEtAl2004] Nagle, Saff, and Snider. + *Fundamentals of Differential Equations*. 6th edition, Addison-Wesley, + 2004. + +.. [Py] The Python language http://www.python.org/ + Reference Manual http://docs.python.org/ref/ref.html. + 日本Pythonユーザ会のサイト http://www.python.jp/ で日本語版ドキュメントが公開されている.感謝. + +.. [PyDev] Guido, Some Guys, and a Mailing List: How Python is + Developed, + http://www.python.org/dev/dev_intro.html. + +.. [Pyr] Pyrex, + http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/. + +.. [PyT] The Python Tutorial http://www.python.org/. + +.. [SA] Sage web site http://www.sagemath.org/. + +.. [Si] G.-M. Greuel, G. Pfister, and H. Schönemann. Singular + 3.0. A Computer Algebra System for Polynomial Computations. Center + for Computer Algebra, University of Kaiserslautern (2005). + http://www.singular.uni-kl.de. + +.. [SJ] William Stein, David Joyner, Sage: System for Algebra and + Geometry Experimentation, Comm. Computer Algebra {39}(2005)61-64. + diff --git a/src/doc/ja/tutorial/conf.py b/src/doc/ja/tutorial/conf.py new file mode 100755 index 00000000000..81ba55bbd30 --- /dev/null +++ b/src/doc/ja/tutorial/conf.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# +# Sage documentation build configuration file, based on that created by +# sphinx-quickstart on Thu Aug 21 20:15:55 2008. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# The contents of this file are pickled, so don't put values in the namespace +# that aren't pickleable (module imports are okay, they're removed automatically). +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +sys.path.append(os.environ['SAGE_DOC']) +from common.conf import * + +# General information about the project. +project = u"Sage チュートリアル" +name = u'tutorial-jp' +language = "ja" + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = project + " v"+release + +# Output file base name for HTML help builder. +htmlhelp_basename = name + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, document class [howto/manual]). +latex_documents = [ + ('index', name+'.tex', project, + u'The Sage Group', 'manual'), +] + +# LaTeX の docclass 設定 +latex_docclass = {'manual': 'jsbook'} + +# Additional LaTeX stuff for the French version +#latex_elements['preamble'] += '\\DeclareUnicodeCharacter{00A0}{\\nobreakspace}\n' + +# the definition of \\at in the standard preamble of the sphinx doc +# conflicts with that in babel/french[b] +latex_elements['preamble'] += '\\let\\at\\undefined' + +# +# html_use_smartypants = False diff --git a/src/doc/ja/tutorial/index.rst b/src/doc/ja/tutorial/index.rst new file mode 100755 index 00000000000..28b0a1eef8e --- /dev/null +++ b/src/doc/ja/tutorial/index.rst @@ -0,0 +1,37 @@ + +Sageチュートリアルへようこそ +================================ + +Sageは,代数学,幾何学,数論,暗号理論,数値解析,および関連諸分野の研究と教育を支援する,フリーなオープンソース数学ソフトウェアである. +Sageの開発モデルとテクノロジーに共通する著しい特徴は,公開,共有,協調と協働の原則の徹底的な遵守である. +我々の目的は言わば実用車の制作であって,車輪を再発明することではない. +総合目標としているのは,Maple,Mathematica,Magma,MATLABに代りうるフリーかつオープンソース化された実用システムの開発である. + +Sageがどんなものか,短時間で知りたければ,まずこのチュートリアルを読んでみていただきたい. +HTML版とPDF版のどちらを読んでもいいし,Sageノートブックを経由することもできる(チュートリアル内容を対話的に実行するには,ノートブックで ``Help`` , 続けて ``Tutorial`` をクリックする). + +この文章の著作権は `Creative Commons Attribution-Share Alike 3.0 License`__ +に準ずる. + +__ http://creativecommons.org/licenses/by-sa/3.0/ + +.. toctree:: + :maxdepth: 2 + + introduction + tour + interactive_shell + interfaces + latex + programming + sagetex + afterword + appendix + bibliography + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/src/doc/ja/tutorial/interactive_shell.rst b/src/doc/ja/tutorial/interactive_shell.rst new file mode 100755 index 00000000000..667c0b1b639 --- /dev/null +++ b/src/doc/ja/tutorial/interactive_shell.rst @@ -0,0 +1,984 @@ +.. _chapter-interactive_shell: + +********************* +対話型シェル +********************* + +このチュートリアルの大部分は,読者が ``sage`` コマンドによってSageインタプリタを起動しているものと前提している. +コマンド ``sage`` は改造版IPythonシェルを起動し,大量の関数やクラス群をインポートしてコマンドプロンプトから利用可能にする. +``$SAGE_ROOT/ipythonrc`` ファイルを編集すれば,さらなるシェル環境のカスタマイズも可能だ. +Sageを起動すると,すぐに次のような画面が現れる: + +.. skip + +:: + + ---------------------------------------------------------------------- + | SAGE Version 3.1.1, Release Date: 2008-05-24 | + | Type notebook() for the GUI, and license() for information. | + ---------------------------------------------------------------------- + + + sage: + +Sageを終了するには,Ctrl-Dと押すか, コマンド ``quit`` あるいは ``exit`` を入力する. + +.. skip + +:: + + sage: quit + Exiting SAGE (CPU time 0m0.00s, Wall time 0m0.89s) + + +"Wall time"は,CPUタイムではなく外界の実経過時間を示している. +CPUタイムはGAPやSingularなどのサブプロセスの消費時間までは勘定に入れてくれないから,実経過時間も計算時間の見積りに必要だ. + +(ターミナルから ``kill -9`` を入力してSageプロセスを停止するのは止めたほうがいい. +``kill -9`` ではMapleなどの子プロセスが停止しなかったり, ``$HOME/.sage/tmp`` 内の一時ファイルが消去されずに終わるなどの恐れがある.) + + +Sageセッション +================= + +*セッション* とは,Sageの起動から終了までの間に行なわれた一連の入出力の総体のことをいう. +Sageは,Sageに対する入力の全てをIPython経由で記録している. +事実,(ノートブック経由ではなく)対話型シェルを使ってSageを動かしているのならば,好きな時に ``%history`` (または ``%hist``) と入力して,それまでの全入力履歴を見ることができる. +IPythonについてもっと知りたければ、Sageプロンプトで ``?`` と入力すれば, "IPython offers numbered prompts ... with input and output caching. All input is saved and can be retrieved as variables (besides the usual arrow key recall). The following GLOBAL variables always exist (so don't overwrite them!)" などと詳しい情報を表示させることができる: + +:: + + _: 前回の入力を呼び出す (対話型シェルとノートブックの両方で通用する) + __: 前々回の入力を呼び出す(対話型シェルのみで通用) + _oh : 全ての入力をリストする(対話型シェルのみで通用) + +ここで例を見てみよう: + +.. skip + +:: + + sage: factor(100) + _1 = 2^2 * 5^2 + sage: kronecker_symbol(3,5) + _2 = -1 + sage: %hist # これが使えるのは対話型シェル上のみ.ノートブックではだめ. + 1: factor(100) + 2: kronecker_symbol(3,5) + 3: %hist + sage: _oh + _4 = {1: 2^2 * 5^2, 2: -1} + sage: _i1 + _5 = 'factor(ZZ(100))\n' + sage: eval(_i1) + _6 = 2^2 * 5^2 + sage: %hist + 1: factor(100) + 2: kronecker_symbol(3,5) + 3: %hist + 4: _oh + 5: _i1 + 6: eval(_i1) + 7: %hist + +以降,このチュートリアル,それに他のSageドキュメンテーションでも出力番号を省略する. + +セッション中は,一連の入力をマクロとして保存しておいて再利用することもできる. + + +.. skip + +:: + + sage: E = EllipticCurve([1,2,3,4,5]) + sage: M = ModularSymbols(37) + sage: %hist + 1: E = EllipticCurve([1,2,3,4,5]) + 2: M = ModularSymbols(37) + 3: %hist + sage: %macro em 1-2 + Macro `em` created. To execute, type its name (without quotes). + + +.. skip + +:: + + sage: E + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over + Rational Field + sage: E = 5 + sage: M = None + sage: em + Executing Macro... + sage: E + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over + Rational Field + +対話型シェルを使っている間も,感嘆符 ``!`` を前置すれば好きなUNIXシェルコマンドを実行することができる. +例えば + +.. skip + +:: + + sage: !ls + auto example.sage glossary.tex t tmp tut.log tut.tex + +のように,カレントディレクトリの内容を表示することができる. + +シェル変数 ``PATH`` の先頭にはSageのbinディレクトリが配置されているから, ``gp`` , ``gap`` , ``singular`` , ``maxima`` などを実行すると,Sageに付属しているプログラムのバージョンを確認することができる. + +.. skip + + +:: + + sage: !gp + Reading GPRC: /etc/gprc ...Done. + + GP/PARI CALCULATOR Version 2.2.11 (alpha) + i686 running linux (ix86/GMP-4.1.4 kernel) 32-bit version + ... + sage: !singular + SINGULAR / Development + A Computer Algebra System for Polynomial Computations / version 3-0-1 + 0< + by: G.-M. Greuel, G. Pfister, H. Schoenemann \ October 2005 + FB Mathematik der Universitaet, D-67653 Kaiserslautern \ + + + +入出力のログをとる +======================== + +Sageセッションのロギングと,セッションの保存(:ref:`section-save` 節を参照)は同じことではない. +入力のログをとるには, ``logstart`` コマンドを使う(オプションで出力のログも可能だ). +詳細については ``logstart?`` と入力してみてほしい. +``logstart`` を使えば,全ての入力と出力のログを残し,将来のセッション時に(そのログファイルをリロードしてやるだけで)入力を再生することも可能になる. + +.. skip + +:: + + was@form:~$ sage + ---------------------------------------------------------------------- + | SAGE Version 3.0.2, Release Date: 2008-05-24 | + | Type notebook() for the GUI, and license() for information. | + ---------------------------------------------------------------------- + + sage: logstart setup + Activating auto-logging. Current session state plus future input saved. + Filename : setup + Mode : backup + Output logging : False + Timestamping : False + State : active + sage: E = EllipticCurve([1,2,3,4,5]).minimal_model() + sage: F = QQ^3 + sage: x,y = QQ['x,y'].gens() + sage: G = E.gens() + sage: + Exiting SAGE (CPU time 0m0.61s, Wall time 0m50.39s). + was@form:~$ sage + ---------------------------------------------------------------------- + | SAGE Version 3.0.2, Release Date: 2008-05-24 | + | Type notebook() for the GUI, and license() for information. | + ---------------------------------------------------------------------- + + sage: load("setup") + Loading log file one line at a time... + Finished replaying log file + sage: E + Elliptic Curve defined by y^2 + x*y = x^3 - x^2 + 4*x + 3 over Rational + Field + sage: x*y + x*y + sage: G + [(2 : 3 : 1)] + +SageをLinux KDEターミナル ``konsole`` 上で使っているなら,以下の手順でセッションを保存することもできる. +まず ``konsole`` 上でSageを起動したら、 "settings"(日本語環境であれば『設定』)を選択し,次に "history"(『履歴』), "set unlimited"(『無制限にする』)の順に選択しておく. +セッションを保存したくなった時点で, "edit"(『編集』)の中の "save history as..."(『履歴を名前を付けて保存』)を選択してセッションを保存するファイル名を入力してやればよい. +いったんファイルとして保存してしまえば,好きなようにxemacsなどのエディタで読み込んだりプリントアウトしたりすることができる. + + + +プロンプト記号はペースト時に無視される +======================================== + +SageセッションあるいはPythonの演算結果を読み込んで,Sage上にコピーしたい場合がある. +厄介なのは、そうした出力に ``>>>`` や ``sage:`` といったプロンプト記号が紛れ込んでいることだ. +しかし実際には,プロンプト記号を含む実行例をSage上へ好きにコピー・ペーストしてやることができる. +デフォルトでSageパーサーはデータをPythonに送る前に行頭の ``>>>`` や ``sage:`` プロンプト記号を除去してくれるからだ. +例えば + +.. skip + +:: + + sage: 2^10 + 1024 + sage: sage: sage: 2^10 + 1024 + sage: >>> 2^10 + 1024 + + +計時コマンド +=============== + +入力行の先頭に ``%time`` コマンドを入れておくと,出力までに要した時間を表示することができる. +例として,べき乗計算を異なった方法で行なった場合の実行時間を比較してみよう. +以下に示した実行時間の値は,動かしているコンピュータ本体やSageのバージョンによって大きく異なる可能性が高い. +まず、Pythonを直に動かしてみると: + +.. skip + +:: + + sage: %time a = int(1938)^int(99484) + CPU times: user 0.66 s, sys: 0.00 s, total: 0.66 s + Wall time: 0.66 + + +上の出力は,実行に計0.66秒かかり, "Wall time" つまりユーザーの実待ち時間もやはり0.66秒だったことを示している. +コンピュータに他のプログラムから大きな負荷がかかっている場合, "Wall time"がCPUタイムよりかなり長くなることがある. + +次に,同じべき乗計算をSage組み込みのInteger型を使って実行した場合の時間を計ってみよう. +SageのInteger型は,Cython経由でGMPライブラリを使って実装されている: + +.. skip + +:: + + sage: %time a = 1938^99484 + CPU times: user 0.04 s, sys: 0.00 s, total: 0.04 s + Wall time: 0.04 + +PARIのC-ライブラリを経由すると + +.. skip + +:: + + sage: %time a = pari(1938)^pari(99484) + CPU times: user 0.05 s, sys: 0.00 s, total: 0.05 s + Wall time: 0.05 + +GMPの方が速いが,その差はわずかだ(Sage用にビルドされたPARIは整数演算にGMPを使っているのだから,納得できる結果である). + + +次の例のように, ``cputime`` コマンドを使えば,一連のコマンドからなるコードブロックの実行時間を計ることもできる: + +:: + + sage: t = cputime() + sage: a = int(1938)^int(99484) + sage: b = 1938^99484 + sage: c = pari(1938)^pari(99484) + sage: cputime(t) # 値には若干の幅がある. + 0.64 + + +.. skip + + +:: + + sage: cputime? + ... + Return the time in CPU second since SAGE started, or with optional + argument t, return the time since time t. + INPUT: + t -- (optional) float, time in CPU seconds + OUTPUT: + float -- time in CPU seconds + + +``walltime`` コマンドの動作は,計測するのが実経過時間である点以外は ``cputime`` コマンドと変わらない. + +上で求めたべき乗を,Sageに取り込まれている各コンピュータ代数システムを使って計算することもできる. +計算を実行するには,使いたいシステムの名前をコマンド名としてそのプログラムのサーバを呼び出す. +いちばん肝心な計測値は,実経過時間(wall time)だ. +しかし,実経過時間とCPUタイムの値が大幅に食い違う場合は,解決すべきパフォーマンス上の問題点の存在を示している可能性がある. + +.. skip + +:: + + sage: time 1938^99484; + CPU times: user 0.01 s, sys: 0.00 s, total: 0.01 s + Wall time: 0.01 + sage: gp(0) + 0 + sage: time g = gp('1938^99484') + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.04 + sage: maxima(0) + 0 + sage: time g = maxima('1938^99484') + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.30 + sage: kash(0) + 0 + sage: time g = kash('1938^99484') + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.04 + sage: mathematica(0) + 0 + sage: time g = mathematica('1938^99484') + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.03 + sage: maple(0) + 0 + sage: time g = maple('1938^99484') + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.11 + sage: gap(0) + 0 + sage: time g = gap.eval('1938^99484;;') + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 1.02 + +以上のテスト計算で最も遅かったのは,GAPとMaximaである(実行結果はホスト ``sage.math.washington.edu`` 上のもの). +各システムとのpexpectインターフェイスにかかる負荷を考えると,上の一連の計測値を最速だったSageの値と比較するのは公平を欠く面があるかもしれない. + + +IPythonトリック +==================== + +すでに述べたように,SageはそのフロントエンドとしてIPythonを援用しており,ユーザはIPythonのコマンドと独自機能を自由に利用することができる. +その全貌については, ご自分で `full IPython documentation +`_ を読んみてほしい. +そのかわり,ここではIPythonの「マジックコマンド」と呼ばれる,お便利なトリックをいくつか紹介させていただこう: + +- ``%bg`` を使えばコマンドをバックグラウンドで実行し, 結果には ``jobs`` でアクセスすることができる.(この機能は ``not tested`` とコメントされている.というのは ``%bg`` 書法がSageの自動テスト機能とは余り相性が良くないからだ.ユーザ各自が入力してやれば,その通り動作するはずである.もちろん,この機能が最も役立つのは実行に時間のかかるコマンドと組み合わせる場合である.) + + 使用例を以下に示す. + + :: + + sage: def quick(m): return 2*m + sage: %bg quick(20) # not tested + Starting job # 0 in a separate thread. + sage: jobs.status() # not tested + Completed jobs: + 0 : quick(20) + sage: jobs[0].result # the actual answer, not tested + 40 + + バックグラウンドに送られるジョブはSageの前処理パーサを経由しないことに注意 -- 詳細は :ref:`section-mathannoy` 節を参照されたい. + パーサを通すための(不器用であるけれども)1つの方法は + + :: + + sage: %bg eval(preparse('quick(20)')) # not tested + + とすることだろう. + + ただし,より安全で簡単なのは前処理パーサを必要としないコマンドで ``%bg`` を使うことだろう. + + +- ``%edit`` (``%ed`` や ``ed`` でもいい)を使ってエディタを起動すれば,複雑なコードの入力が楽になる. + Sageの使用前に,環境変数 :envvar:`EDITOR` に好みのエディタ名を設定しておこう(``export EDITOR=/usr/bin/emacs`` または ``export EDITOR=/usr/bin/vim`` とするか, ``.profile`` ファイルなどで同様の設定をする). + するとSageプロンプトで ``%edit`` を実行すれば設定したエディタが起動する.そのエディタで関数 + + :: + + def some_function(n): + return n**2 + 3*n + 2 + + を定義し,保存したらエディタを終了する. + 以降,このセッション中は ``some_function`` を利用できるようになる. + 内容を編集したければSageプロンプトで ``%edit some_function`` と入力すればよい. + + +- 結果出力を他の用途のために編集したければ, ``%rep`` を実行する. + すると直前に実行したコマンドの出力が編集できるようにSageプロンプト上に配置される.:: + + sage: f(x) = cos(x) + sage: f(x).derivative(x) + -sin(x) + + この段階でSageプロンプトから ``%rep`` を実行すると,新しいSageプロンプトに続いて ``-sin(x)`` が現われる. + カーソルは同じ行末にある. + + +IPythonのクイック レファレンスガイドを見たければ, ``%quickref`` と入力する. +執筆時点(2011年4月)ではSageはIPythonのバージョン0.9.1を採用しており, `documentation for its magic commands +`_ +はオンラインで読むことができる. +マジックコマンドの,ちょっと進んだ機能群についてはIPythonの `ここ +`_ +で文書化されているのが見つかるはずだ. + + +エラーと例外処理 +===================== + +処理中に何かまずいことが起きると,Pythonはふつう『例外』(exception)を発生し,その例外を引き起こした原因を教えてくれることもある. +よくお目にかかることになるのは, ``NameError`` や ``ValueError`` といった名称の例外だ(Pythonレファレンスマニュアル [Py]_ に例外名の包括的なリストがある). +実例を見てみよう: + +:: + + sage: 3_2 + ------------------------------------------------------------ + File "", line 1 + ZZ(3)_2 + ^ + SyntaxError: invalid syntax + + sage: EllipticCurve([0,infinity]) + ------------------------------------------------------------ + Traceback (most recent call last): + ... + TypeError: Unable to coerce Infinity () to Rational + + +何が悪いか調べるには対話型デバッガが役立つこともある. +デバッガを使うには、 ``%pdb`` コマンドによって作動のオン/オフをトグルする(デフォルトはオフ). +作動後は、例外が発生するとデバッガが起動し,プロンプト ``ipdb>`` が表示される. +このデバッガの中から,任意のローカル変数の状態を表示したり,実行スタックを上下して様子を調べることができる. + +.. skip + +:: + + sage: %pdb + Automatic pdb calling has been turned ON + sage: EllipticCurve([1,infinity]) + --------------------------------------------------------------------------- + Traceback (most recent call last) + ... + + ipdb> + + +デバッガから実行できるコマンドの一覧を見るには, ``ipdb>`` プロンプト上で ``?`` を入力する: +:: + + ipdb> ? + + Documented commands (type help ): + ======================================== + EOF break commands debug h l pdef quit tbreak + a bt condition disable help list pdoc r u + alias c cont down ignore n pinfo return unalias + args cl continue enable j next pp s up + b clear d exit jump p q step w + whatis where + + Miscellaneous help topics: + ========================== + exec pdb + + Undocumented commands: + ====================== + retval rv + +Sageに戻るには,Ctrl-Dか ``quit`` を入力する. + + +.. _section-tabcompletion: + +コマンド入力の遡行検索とタブ補完 +================================= + +*遡行検索*: コマンドの冒頭部を打ち込んでから ``Ctrl-p`` (または上向き矢印キー)を押すと,冒頭部が一致する過去の入力行を全て呼び出すことができる. +この機能は,Sageをいったん終了し再起動してからでも有効である. +``Ctrl-r`` を入力すれば,入力ヒストリを逆方向に検索することも可能だ. +この入力行の検索と再利用機能は全て ``readline`` パッケージを経由しており,ほとんどのLinux系システム上で利用できるはずだ. + +タブ補完機能を体験するため,まず3次元ベクトル空間 :math:`V=\QQ^3` を生成しておく: +:: + + sage: V = VectorSpace(QQ,3) + sage: V + Vector space of dimension 3 over Rational Field + +次のような,もっと簡潔な記号法を使ってもよい: + +:: + + sage: V = QQ^3 + + +タブ補完を使えば,簡単に :math:`V` の全メンバ関数を一覧表示することができる. +``V.`` と入力し,ついで ``[tab]`` キーを押すだけだ: + +.. skip + +:: + + sage: V.[tab key] + V._VectorSpace_generic__base_field + ... + V.ambient_space + V.base_field + V.base_ring + V.basis + V.coordinates + ... + V.zero_vector + +関数名の出だし何文字かを打ってから ``[tab キー]`` を押せば,入力した文字で始まる名前の関数だけに候補を絞ることができる. + +.. skip + +:: + + sage: V.i[tab key] + V.is_ambient V.is_dense V.is_full V.is_sparse + +特定の関数について調べたい場合もある. +coordinates関数を例にとると,そのヘルプを表示するには ``V.coordinates?`` と入力すればいいし,ソースコードを見るには ``V.coordinates??`` を入力すればいい. +詳細については次の節で解説する. + + +統合ヘルプシステム +====================== + +Sageの特長の一つは,総合的なヘルプ機能の装備である. +関数名に続けて?を入力すると、その関数のドキュメントを表示することができる. + +.. skip + +:: + + sage: V = QQ^3 + sage: V.coordinates? + Type: instancemethod + Base Class: + String Form: + Namespace: Interactive + File: /home/was/s/local/lib/python2.4/site-packages/sage/modules/f + ree_module.py + Definition: V.coordinates(self, v) + Docstring: + Write v in terms of the basis for self. + + Returns a list c such that if B is the basis for self, then + + sum c_i B_i = v. + + If v is not in self, raises an ArithmeticError exception. + + EXAMPLES: + sage: M = FreeModule(IntegerRing(), 2); M0,M1=M.gens() + sage: W = M.submodule([M0 + M1, M0 - 2*M1]) + sage: W.coordinates(2*M0-M1) + [2, -1] + + +上で見たように,ヘルプ表示には,そのオブジェクトの型,定義されているファイル,現セッションにペーストすることができる使用例付きの解説が含まれる. +使用例のほとんどは常に自動的なテストが行なわれていて,仕様どおりの正確な動作が確認されている. + +もう一つの機能は,Sageのオープンソース精神をよく表すものだ. +``f`` がPythonで書かれた関数であれば ``f??`` と入力すると ``f`` を定義しているソースを表示することができるのだ. +例えば + +.. skip + +:: + + sage: V = QQ^3 + sage: V.coordinates?? + Type: instancemethod + ... + Source: + def coordinates(self, v): + """ + Write $v$ in terms of the basis for self. + ... + """ + return self.coordinate_vector(v).list() + +これを見ると, ``coordinates`` 関数は ``coordinate_vector`` 関数を呼び出して結果をリストに変換しているだけであることが判る. +では ``coordinate_vector`` 関数が何をしているかと言うと: + +.. skip + +:: + + sage: V = QQ^3 + sage: V.coordinate_vector?? + ... + def coordinate_vector(self, v): + ... + return self.ambient_vector_space()(v) + + +``coordinate_vector`` 関数は,入力を生成空間(ambient space)に合わせて型変換するから,これは :math:`v` の係数ベクトルが空間 :math:`V` ではどう変換されるか計算していることと同じである. +:math:`\QQ^3` そのものである空間 :math:`V` が同相なのは当然だ. +部分空間用に、上とは異なる ``coordinate_vector`` 関数も用意されている. +部分空間を作って,どんな関数か見てみることにしよう: + +.. skip + +:: + + sage: V = QQ^3; W = V.span_of_basis([V.0, V.1]) + sage: W.coordinate_vector?? + ... + def coordinate_vector(self, v): + """ + ... + """ + # First find the coordinates of v wrt echelon basis. + w = self.echelon_coordinate_vector(v) + # Next use transformation matrix from echelon basis to + # user basis. + T = self.echelon_to_user_matrix() + return T.linear_combination_of_rows(w) + +(こうした実装の仕方は無駄が多いと思われる方は,どうか我々に連絡して線形代数周りの最適化に力を貸していただきたい.) + + + ``help(コマンド名)`` あるいは ``help(クラス名)`` と入力すれば,知りた いクラスのmanページ型ヘルプファイルを表示することもできる. + + +.. skip + +:: + + sage: help(VectorSpace) + Help on class VectorSpace ... + + class VectorSpace(__builtin__.object) + | Create a Vector Space. + | + | To create an ambient space over a field with given dimension + | using the calling syntax ... + : + : + + +``q`` と入力してヘルプを終えると,中断前のセッション画面がそのまま復帰する. +セッションに干渉することがある ``function_name?`` と違って, ヘルプ表示はセッションの邪魔をしない. +とりわけ便利なのは ``help(モジュール名)`` と入力することだ. +例えばベクトル空間は ``sage.modules.free_module`` で定義されているから,そのモジュール全体に関するドキュメントを見たければ ``help(sage.modules.free_module)`` と実行すればよい. +ヘルプを使ってドキュメントを閲覧している間は, ``/`` と打てば語句検索 ができるし, ``?`` と打てば逆方向に検索することができる. + + + +オブジェクトの保存と読み込み +===================================== + +行列や,あるいはもっと手間のかかる複雑なモジュラーシンボルの空間を扱っていて,後で利用するため結果を保存しておきたくなったとしよう. +そんな場合にはどうすればよいだろうか. +オブジェクトを保存するために各コンピュータ代数システムが提供している方法は,以下の通りである. + + +#. **セッションの保存:** セッション全体の保存と読み込みのみ可能(GAP,Magmaなど). + +#. **統合入出力:** 全オブジェクトの印字が再利用可能な形式で行なわれる(GAPとPARI). + +#. **再実行**: インタープリタによるプログラムの再実行が容易にしてある(Singular,PARI). + + +.. + #. **Save your Game:** Only support saving and loading of complete + sessions (e.g., GAP, Magma). + + #. **Unified Input/Output:** Make every object print in a way that + can be read back in (GP/PARI). + + #. **Eval**: Make it easy to evaluate arbitrary code in the + interpreter (e.g., Singular, PARI). + +Pythonで動くSageでは,全てのオブジェクトのシリアル化(直列化)という,他とは異なる方法が採用されている. +つまりオブジェクトを,その原型を再現可能な形式で文字列に変換するのだ. +これはPARIの統合入出力の考え方に近いが,オブジェクトを複雑な印字形式で画面出力してやる必要がないのが利点だ. +さらに保存と読み込みは(ほとんどの場合)完全に自動化されているから,新たにプログラムを書く必要もない. +そうした機能はPythonに最初から組込まれているものだからである. + + + +ほぼ全てのSageオブジェクト ``x`` は, コマンド ``save(x,ファイル名)`` (あるいは多くの場合 ``x.save(ファイル名)``)を使えば圧縮形式でディスクに保存することができるようになっている. +保存したオブジェクトを読み戻すには, ``load(ファイル名)`` を実行する. + + +.. skip + +:: + + sage: A = MatrixSpace(QQ,3)(range(9))^2 + sage: A + [ 15 18 21] + [ 42 54 66] + [ 69 90 111] + sage: save(A, 'A') + +ここでいったんSageを終了してみよう.再起動後に ``A`` を読み込むには: + + +.. skip + +:: + + sage: A = load('A') + sage: A + [ 15 18 21] + [ 42 54 66] + [ 69 90 111] + +楕円曲線のようなもっと複雑なオブジェクトに対しても,以上と同じやり方が通用する. +メモリ上に配置されていたオブジェクト関連の全データは,そのオブジェクトと共に保存される. +例えば + +.. skip + +:: + + sage: E = EllipticCurve('11a') + sage: v = E.anlist(100000) # ちょっと時間がかかる + sage: save(E, 'E') + sage: quit + +こうして保存された ``E`` は,オブジェクト本体と一緒に :math:`a_n` の冒頭100000個も保存するため,153Kバイトの大きさになる. + + +.. skip + +:: + + ~/tmp$ ls -l E.sobj + -rw-r--r-- 1 was was 153500 2006-01-28 19:23 E.sobj + ~/tmp$ sage [...] + sage: E = load('E') + sage: v = E.anlist(100000) # すぐ終了 + +(Python経由の保存と読み込みには, ``cPickle`` モジュールが使われている. +実際,Sageオブジェクト ``x`` の保存は ``cPickle.dumps(x, 2)`` を実行して行なうことができる.引数 ``2`` に注目.) + + +Sageで保存・読み込みできないのは,GAP, Singular, Maximaなど外部コンピュータ代数システムで作成されたオブジェクトである. +これらは読み込むことができても "invalid"(利用不能)な状態にあると認識される. +GAPでは,相当数のオブジェクトが再構成に使える印字形式を持つ一方,再構成できな場合も多いため印字形式からのオブジェクトの再構成は意図的に禁止されている. + + +.. skip + +:: + + sage: a = gap(2) + sage: a.save('a') + sage: load('a') + Traceback (most recent call last): + ... + ValueError: The session in which this object was defined is no longer + running. + +GP/PARIオブジェクトは,印字形式から十分に再構成可能なため,保存と読み込みも可能になっている. + + +.. skip + +:: + + sage: a = gp(2) + sage: a.save('a') + sage: load('a') + 2 + + +保存したオブジェクトは,異なるアーキテクチャ上の,異なるオペレーティングシステムで動くSageへもロードすることができる. +例えば,32ビット OSX上で保存した大規模行列を64ビット版LinuxのSageへ読み込み,その階段形式を求めてから元のOS X上へ戻すといったことも可能だ. +さらに,オブジェクトの保存までに使ったのとは違うバージョンのSageでオブジェクトを読み込むこともできる場合が多い. +ただし,これは読み書きしたいオブジェクトに関わるコードがバージョン間で大きくは異ならないことが条件となる. +オブジェクトの保存に際しては,その属性の全てがオブジェクトを定義している(ソースコードではなく)クラスと共に保存される. +そのクラスが新バージョンのSageに存在しない場合,配下のオブジェクトを新バージョンでは読み込むことはできない. +しかし古いバージョンで読み込むことはできるはずだから,(``x.__dict__`` で)オブジェクト ``x`` のディクショナリを生成して保存しておけば,それを新しいバージョンで読み込むことができることもある. + + + +テキスト形式で保存する +-------------------------- + +オブジェクトをASCIIテキスト形式で保存しておくこともできる. +手順は,ファイルを書込みモードで開いて,そこに保存すべきオブジェクトの文字列表現を書き込むだけのことだ(このやり方で複数個のオブジェクトを保存することができる). +オブジェクトの書込みを終えたら,ファイルをクローズすればよい. + + +.. skip + +:: + + sage: R. = PolynomialRing(QQ,2) + sage: f = (x+y)^7 + sage: o = open('file.txt','w') + sage: o.write(str(f)) + sage: o.close() + + + +.. _section-save: + +セッション全体の保存と読み込み +==================================== + +Sageは,セッション全体を保存し再ロードするための非常に柔軟な機能を備えている. + + +コマンド ``save_session(セッション名)`` は,現セッション中に定義された全ての変数を、コマンドで指定した ``セッション名`` にディクショナリとして保存する. +(保存を想定していない変数がある場合もまれに見られるが,そうした時はディクショナリに保存されずに終るだけだ.) +保存先は ``.sobj`` ファイルとなり,他の保存済みオブジェクトと全く同じように読み込むことができる. +セッション中に保存したオブジェクトを再びロードすると,変数名をキー,オブジェクトを値とするディクショナリが生成されることになる. + + +実行中のセッションに ``セッション名`` に定義された変数をロードするには, ``load_session(セッション名)`` コマンドを使う. +このコマンドは現セッションとロードされる側のセッション内容を合併するのであって,現セッションで定義した変数が消去されるわけではない. + + +まずSageを起動し,変数をいくつか定義しておく. + +.. skip + +:: + + sage: E = EllipticCurve('11a') + sage: M = ModularSymbols(37) + sage: a = 389 + sage: t = M.T(2003).matrix(); t.charpoly().factor() + _4 = (x - 2004) * (x - 12)^2 * (x + 54)^2 + +次にこのセッションをファイルに保存し,先に定義した変数を残しておく. +``.sobj`` ファイルを確認すると,その大きさは3Kバイトほどとなっている. + + +.. skip + +:: + + sage: save_session('misc') + Saving a + Saving M + Saving t + Saving E + sage: quit + was@form:~/tmp$ ls -l misc.sobj + -rw-r--r-- 1 was was 2979 2006-01-28 19:47 misc.sobj + +仕上げにSageを再起動し,変数をいくつか追加定義してから,先に保存したセッションを読み込んでみよう. + + +.. skip + +:: + + sage: b = 19 + sage: load_session('misc') + Loading a + Loading M + Loading E + Loading t + +保存しておいた変数が再び利用可能になる一方,上で追加した変数 ``b`` は上書きされていないことが分る. + + +.. skip + +:: + + sage: M + Full Modular Symbols space for Gamma_0(37) of weight 2 with sign 0 + and dimension 5 over Rational Field + sage: E + Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational + Field + sage: b + 19 + sage: a + 389 + + + +.. _section-notebook: + +ノートブックインターフェイス +================================== + +Sageノートブックを起動するには、Sageコマンドライン上で + +.. skip + +:: + + sage: notebook() + +と実行する. +これでSageノートブックが起動すると同時に,閲覧用のデフォルトWebブラウザが開かれる. +ノートブックサーバが使用する状態ファイル群は, ``$HOME/.sage/sage\_notebook`` に保存される. + + +起動時に指定できるオプションとして + +.. skip + + +:: + + sage: notebook("ディレクトリ名") + + +とすると,標準ディレクトリ ``$HOME/.sage/sage_notebook`` ではなく指定した ``ディレクトリ名`` のディレクトリにある状態ファイル群を使って新しくノートブックサーバを起動する. +このオプションは,特定のプロジェクトに多数のワークシート群がぶら下がっていたり,同時に複数のノートブックサーバを動かしたい場合に便利だ. + +ノートブックを起動すると、まず ``$HOME/.sage/sage_notebook`` 内に以下のようなファイル群が生成される: + + +:: + + nb.sobj (ノートブックSAGEオブジェクト ファイル) + objects/ (SAGEオブジェクト群を保管するディレクトリ) + worksheets/ (SAGEワークシートを保管するディレクトリ) + + +上のファイル群の作成後,ノートブックはWebサーバの起動を行なう. + + +「ノートブック」(notebook)とはユーザーアカウントの集合であって,各ノートブックにはワークシートを好きな数だけ保持することができる. +ワークシートを新規に作成すると,そのワークシートを定義するデータが ``worksheets/username/number`` ディレクトリに保存される. +これらのディレクトリに必ず出来ているのがファイル ``worksheet.txt`` である. +このプレーンテキストからなるファイルには,ワークシートやSageその他に何によらず変更が加えられた場合,元のワークシートを復元するために必要な全情報が可読形式で保存されている. + + +Sage上で ``notebook?`` と入力すると,ノートブックサーバを起動する方法に関する詳しい情報が得られる. + + +次の図を見ると,Sageノートブックの構造が分る: + +:: + + ---------------------- + | | + | | + | firefox/safari | + | | + | javascript | + | program | + | | + | | + ---------------------- + | ^ + | AJAX | + V | + ---------------------- + | | + | sage | SAGE process 1 + | web | ------------> SAGE process 2 (Python processes) + | server | pexpect SAGE process 3 + | | . + | | . + ---------------------- . + + + +ノートブックからSageコマンド ``コマンド名`` のヘルプを見たければ,ブラウザ表示画面内入力ボックスで ``コマンド名?`` と入力し, ```` を押せばよい(```` ではない). + + +ノートブック上で通用するキーボードショートカットを確認するには, ``Help`` リンクをクリックする. + diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst new file mode 100755 index 00000000000..c38ca5cb10b --- /dev/null +++ b/src/doc/ja/tutorial/interfaces.rst @@ -0,0 +1,309 @@ +.. linkall + +************************* +インターフェイスについて +************************* + +Sageの最大の特長は,多種多様なコンピュータ代数システムを,共通インターフェイスと本格的なプログラミング言語Pythonを用いて一つ屋根の下にまとめ上げている点だ. +これによりSageでは由来の異なるオブジェクト群を組み合わせた演算処理が可能になっている. + +ある1つのインターフェイスに対し, ``console`` メソッドと ``interact`` メソッドは,全く違った機能を果たしている. +GAPを例にとって具体的に見てみよう: + + +#. ``gap.console()``: このメソッドはGAPのコンソールを起動し,命令実行の主体をGAP上へ移す. + Sageの役割は,Linuxのbashシェルのような便利なプログラムランチャとしての役割に限定される. + +#. ``gap.interact()``: このメソッドは,Sageオブジェクト群を使って動作しているGAPインスタンスと情報交換するための便利な径路を提供する. + これを使うと,GAPセッション中に(対話型インタフェイスからでも)Sageオブジェクトをインポートすることができる. + + +.. index: PARI; GP + +GP/PARI +======== + + + +数論関係の演算処理を主目的とするPARIは,コンパクトで非常に練れたプログラムで,高度に最適化されている. +SageからPARIを使うには,大きく異なる2種類のインターフェイスを選ぶことができる: + +- ``gp`` - "**G** o **P** ARI" インタープリタ + +- ``pari`` - PARI Cライブラリ + +以下の例では,同一の計算を二通りのやり方で実行している. +一見同じように見えても実は出力内容は同一ではないし,画面の奥で実際に行なわれている処理過程は二つの方法で全くと言っていいほど異なっているのだ. + +:: + + sage: gp('znprimroot(10007)') + Mod(5, 10007) + sage: pari('znprimroot(10007)') + Mod(5, 10007) + + +第一のやり方では,GPインタープリタが独立したサーバプロセスとして起動され,そのプロセスに文字列 ``'znprimroot(10007)'`` が送られる. +GPは送られて来た文字列を評価し,結果を変数に格納する(変数は子GPプロセス配下の,開放されないメモリ空間内に確保される). +その変数の値が画面表示されて仕上がりになる. +第二のやり方では、独立したプロセスが起動されることはなく,文字列 ``'znprimroot(10007)'`` はPARI Cライブラリ関数群によって処理される. +処理結果はPythonの確保しているヒープ上に配置され,その変数が参照されなくなると使っていたヒープメモリは開放される. +二つのやり方では、生成されるオブジェクトの型からして違っている: + +:: + + sage: type(gp('znprimroot(10007)')) + + sage: type(pari('znprimroot(10007)')) + + +では,どちらの方法を選ぶべきだろうか? +答は目的による、としか言えない. +GPインターフェイスはGP/PARIプログラムをそのまま動作させるのだから,GP/PARIのコマンド入力行から可能なことは全て出来る. +複雑なPARIプログラムを読み込んで走らせたい場合などには向いているだろう. +これと比較すると,(Cライブラリを経由する)PARIインターフェイスはかなり制限がきつい. +まだライブラリのメンバ関数の全てが実装されているわけではないし, +数値積分などを含むコードの多くがPARIインターフェイスからは使えない状態だ. +一方,PARIインターフェイスはGPインターフェイスより大幅に高速で頑強でもある. + +(入力行を評価中にメモリ不足に陥った場合,GPインターフェイスは特に警告することなく自動的にスタックサイズを2倍して評価を再試行する. +必要とされるメモリ量を正しく見積っていなかったとしても処理が頓挫することはまずない. +この有難い仕掛けは,標準のGPインタープリタには備えられていないようだ. +PARI Cライブラリ インターフェイスについて言うと,こちらは生成したオジェクトを直ちにコピーしてPARIスタックから送り出してしまうので,スタックが積み上がることはない. +しかし,どんなオブジェクトも大きさが100MBを越えてはならず,越えて生成された場合はスタックオーバーフローが起きる. +このオブジェクトのコピーが,わずかながら実行効率上の不利を招いているのも確かである.) + +まとめると,SageはPARI Cライブラリを利用してGP/PARIインタープリタと同様の機能を提供しているが,優秀なメモリ管理とプログラミング言語Pythonの援用という利点がある,ということになる. + + +ここで,PythonのリストからPARIのリストを作ってみよう. + +:: + + sage: v = pari([1,2,3,4,5]) + sage: v + [1, 2, 3, 4, 5] + sage: type(v) + + + +PARIのオブジェクトは全て ``py_pari.gen`` 型になる. +各オブジェクトに埋め込まれているPARI由来のデータ型を取得するには,メンバ関数 ``type`` を使う. + +:: + + sage: v.type() + 't_VEC' + +PARIで楕円曲線を生成するには, ``ellinit([1,2,3,4,5])`` と入力する. +Sageの方法も似ているが, ``ellinit`` を先の ``t\_VEC v`` のような任意のPARIオブジェクトに対して呼び出すことができる点が違っている. +:: + + sage: e = v.ellinit() + sage: e.type() + 't_VEC' + sage: pari(e)[:13] + [1, 2, 3, 4, 5, 9, 11, 29, 35, -183, -3429, -10351, 6128487/10351] + +楕円曲線オブジェクトが生成できたので,これを使った計算を試みよう. + +:: + + sage: e.elltors() + [1, [], []] + sage: e.ellglobalred() + [10351, [1, -1, 0, -1], 1] + sage: f = e.ellchangecurve([1,-1,0,-1]) + sage: f[:5] + [1, -1, 0, 4, 3] + +.. index: GAP + +.. _section-gap: + +GAP +=== + +Sageには GAP 4.4.10が付属しており,群論を始めとする計算離散数学に対応している. + +ここでは、例としてGAPの ``IdGroup`` 関数を取り上げることにしよう. +この機能を使うには群論関係の小規模なデータベースが必要だが,標準ではインストールされない. +これは別途インストールしておかなければならないから,後で手順を説明する. + +:: + + sage: G = gap('Group((1,2,3)(4,5), (3,4))') + sage: G + Group( [ (1,2,3)(4,5), (3,4) ] ) + sage: G.Center() + Group( () ) + sage: G.IdGroup() # オプション - database_gapが必要 + [ 120, 34 ] + sage: G.Order() + 120 + + +上と同じ処理を,GAPインタ=フェイスを明示的には呼び出さずにSageから実行するには: + +:: + + sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) + sage: G.center() + Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + sage: G.group_id() # オプションのdatabase_gapパッケージが必要 + [120, 34] + sage: n = G.order(); n + 120 + +(GAPの機能の一部は,二種類の標準外Sageパッケージをインストールしないと使うことができない. +コマンド行から ``sage -optional`` と入力すると,インストール可能なパッケージの一覧が表示される. +その一覧に ``gap\_packages-x.y.z`` といった項目があるから, ``sage -i gap\_packages-x.y.z`` を実行してパッケージをインストールする. +パッケージ ``database\_gap-x.y.z`` のインストールも手順は同じだ. +一部のGPLではないGAPパッケージは,GAPウェブサイト [GAPkg]_ からダウンロードし, ``$SAGE_ROOT/local/lib/gap-4.4.10/pkg`` で解凍してからインストールする必要がある.) + + +Singular +======== + +Singularは,グレブナー基底,多変数多項式のgcd,平面曲線のRieman-Roch空間に対する基底、因数分解などを始めとする各種処理のための,大規模で十分に枯れたライブラリを提供する. +実例として,多変数多項式の因数分解をSageからSingularへのインターフェイスを使って実行してみよう(``...`` は入力しないこと): + +:: + + sage: R1 = singular.ring(0, '(x,y)', 'dp') + sage: R1 + // characteristic : 0 + // number of vars : 2 + // block 1 : ordering dp + // : names x y + // block 2 : ordering C + sage: f = singular('9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + \ + ... 9*x^6*y^4 + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - \ + ... 9*x^12*y^3 - 18*x^13*y^2 + 9*x^16') + +:math:`f` を定義できたので,その内容を表示してから因数分解を試みる. + +:: + + sage: f + 9*x^16-18*x^13*y^2-9*x^12*y^3+9*x^10*y^4-18*x^11*y^2+36*x^8*y^4+18*x^7*y^5-18*x^5*y^6+9*x^6*y^4-18*x^3*y^6-9*x^2*y^7+9*y^8 + sage: f.parent() + Singular + sage: F = f.factorize(); F + [1]: + _[1]=9 + _[2]=x^6-2*x^3*y^2-x^2*y^3+y^4 + _[3]=-x^5+y^2 + [2]: + 1,1,2 + sage: F[1][2] + x^6-2*x^3*y^2-x^2*y^3+y^4 + + +:ref:`section-gap` 節におけるGAPの実行例のように,Singularインターフェイスを直には使わず上の因数分解を行なうこともできる(Sageが実際の計算に裏でSingularインターフェイスを使っていることに変わりない). +以下の例でも, ``...`` は入力しないこと: + +:: + + sage: x, y = QQ['x, y'].gens() + sage: f = 9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4\ + ... + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3\ + ... - 18*x^13*y^2 + 9*x^16 + sage: factor(f) + (9) * (-x^5 + y^2)^2 * (x^6 - 2*x^3*y^2 - x^2*y^3 + y^4) + + + +.. _section-maxima: + +Maxima +====== + +Maximaは,LISP言語の実装の一種と共にSageに同梱されてくる. +(Maximaが標準でプロットに用いる)gnuplotパッケージは,Sageでも非標準パッケージとして公開されている. +Maximaが得意とするのは,記号処理である.Maximaは関数の微分と積分を記号的に実行し,1階の常微分方程式(ODE)と大半の線形2次ODEを解くことができるし,任意次数の線形ODEをラプラス変換することもできる. +さらにMaximaには多様な特殊関数も組込まれており,gnuplotを介したプロット機能も備えている. +(掃き出し法や固有値問題などに始まる)行列操作や行列方程式の解法を実行し,多項式方程式を解くことも可能だ. + +Sage/Maximaインターフェイスの使い方を例示するため,ここでは :math:`i,j` 要素の値が :math:`i/j` で与えられる行列を作成してみよう. +ただし :math:`i,j=1,\ldots,4` とする. + +:: + + sage: f = maxima.eval('ij_entry[i,j] := i/j') + sage: A = maxima('genmatrix(ij_entry,4,4)'); A + matrix([1,1/2,1/3,1/4],[2,1,2/3,1/2],[3,3/2,1,3/4],[4,2,4/3,1]) + sage: A.determinant() + 0 + sage: A.echelon() + matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0]) + sage: A.eigenvalues() + [[0,4],[3,1]] + sage: A.eigenvectors() + [[[0,4],[3,1]],[[[1,0,0,-4],[0,1,0,-2],[0,0,1,-4/3]],[[1,2,3,4]]]] + + +使用例をもう一つ示す: + +:: + + sage: A = maxima("matrix ([1, 0, 0], [1, -1, 0], [1, 3, -2])") + sage: eigA = A.eigenvectors() + sage: V = VectorSpace(QQ,3) + sage: eigA + [[[-2,-1,1],[1,1,1]],[[[0,0,1]],[[0,1,3]],[[1,1/2,5/6]]]] + sage: v1 = V(sage_eval(repr(eigA[1][0][0]))); lambda1 = eigA[0][0][0] + sage: v2 = V(sage_eval(repr(eigA[1][1][0]))); lambda2 = eigA[0][0][1] + sage: v3 = V(sage_eval(repr(eigA[1][2][0]))); lambda3 = eigA[0][0][2] + + sage: M = MatrixSpace(QQ,3,3) + sage: AA = M([[1,0,0],[1, - 1,0],[1,3, - 2]]) + sage: b1 = v1.base_ring() + sage: AA*v1 == b1(lambda1)*v1 + True + sage: b2 = v2.base_ring() + sage: AA*v2 == b2(lambda2)*v2 + True + sage: b3 = v3.base_ring() + sage: AA*v3 == b3(lambda3)*v3 + True + +最後に,Sage経由で ``openmath`` を使ってプロットを行なう際の手順を紹介する. +以下の例題の多くは,Maximaのレファレンスマニュアルのものを修正したものだ. + + +関数の2次元プロットをするには( ``...`` は入力しない) + +:: + + sage: maxima.plot2d('[cos(7*x),cos(23*x)^4,sin(13*x)^3]','[x,0,1]', # not tested + ....: '[plot_format,openmath]') + +次の「ライブ」3次元プロットは,マウスで動かすことができる( ``...`` は入力しない): + +:: + + sage: maxima.plot3d ("2^(-u^2 + v^2)", "[u, -3, 3]", "[v, -2, 2]", # not tested + ....: '[plot_format, openmath]') + sage: maxima.plot3d("atan(-x^2 + y^3/4)", "[x, -4, 4]", "[y, -4, 4]", # not tested + ....: "[grid, 50, 50]",'[plot_format, openmath]') + +次に有名なメビウスの帯を3次元プロットしてみよう( ``...`` は入力しない). + +:: + + sage: maxima.plot3d("[cos(x)*(3 + y*cos(x/2)), sin(x)*(3 + y*cos(x/2)), y*sin(x/2)]", # not tested + ....: "[x, -4, 4]", "[y, -4, 4]", '[plot_format, openmath]') + +プロットの最後の例は,あの「クラインの壺」である( ``...`` は入力しない): + +:: + + sage: maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0") + 5*cos(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0)-10.0 + sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)") + -5*sin(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0) + sage: maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))") + 5*(cos(x/2)*sin(2*y)-sin(x/2)*cos(y)) + sage: maxima.plot3d ("[expr_1, expr_2, expr_3]", "[x, -%pi, %pi]", # not tested + ....: "[y, -%pi, %pi]", "['grid, 40, 40]", '[plot_format, openmath]') diff --git a/src/doc/ja/tutorial/introduction.rst b/src/doc/ja/tutorial/introduction.rst new file mode 100755 index 00000000000..79299043eea --- /dev/null +++ b/src/doc/ja/tutorial/introduction.rst @@ -0,0 +1,132 @@ +************ +はじめに +************ + +このチュートリアルは,3〜4時間あればじゅうぶん読み通すことができるはずだ. +HTML版とPDF版のどちらを読んでもいいし、Sageノートブックを経由することもできる(チュートリアル内容をSageから対話的に実行するには,ノートブックで ``Help``, 続けて ``Tutorial`` をクリックする). + +Sageのかなりの部分がPythonを使って実装されているものの,このチュートリアルを読むについてはPythonの予備知識はいらない. +いずれはPythonを勉強したくなるはずだが(とても面白い言語だ),そんな場合のためには [PyT]_ や [Dive]_ などの優れた教材がフリーでたくさん用意されている. +とにかく手っ取り早くSageを試してみたいだけなら、このチュートリアルがよい出発点になる. +例えばこんな具合だ: + +:: + + sage: 2 + 2 + 4 + sage: factor(-2007) + -1 * 3^2 * 223 + + sage: A = matrix(4,4, range(16)); A + [ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + [12 13 14 15] + + sage: factor(A.charpoly()) + x^2 * (x^2 - 30*x - 80) + + sage: m = matrix(ZZ,2, range(4)) + sage: m[0,0] = m[0,0] - 3 + sage: m + [-3 1] + [ 2 3] + + sage: E = EllipticCurve([1,2,3,4,5]); + sage: E + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Rational Field + sage: E.anlist(10) + [0, 1, 1, 0, -1, -3, 0, -1, -3, -3, -3] + sage: E.rank() + 1 + + sage: k = 1/(sqrt(3)*I + 3/4 + sqrt(73)*5/9); k + 36/(20*sqrt(73) + 36*I*sqrt(3) + 27) + sage: N(k) + 0.165495678130644 - 0.0521492082074256*I + sage: N(k,30) # 精度は30ビット + 0.16549568 - 0.052149208*I + sage: latex(k) + \frac{36}{20 \, \sqrt{73} + 36 i \, \sqrt{3} + 27} + +.. _installation: + +インストール +============== + +まだSageをコンピュータにインストールしていないけれども何かコマンドを実行してはみたいというなら, http://www.sagenb.org 上でオンライン実行してみる手がある. + +Sageを自分のコンピュータへインストールする手順については,本家Sageウェブページ [SA]_ のドキュメンテーション部にある "Sage Installation Guide"を見てほしい. +ここではいくつかコメントしておくだけにしよう. + +#. Sageのダウンロード用ファイルは「バッテリー込み」である. + つまり、SageはPython, IPython, PARI, GAP, Singular, Maxima, NTL, GMPなどを援用して動作するが,これらは全てSageの配布ファイルに含まれているので別途インストールする必要はないということだ. + ただし、MacaulayやKASHなど一部の機能を利用するには関連するオプショナルなSageパッケージをインストールするか,少なくとも使うコンピュータに関連プログラム群がインストール済みでなくてはならない(利用できるオプショナル・パッケージの一覧を見るには, ``sage -optional`` を実行するか,あるいはSageウェブサイトの "Download"ページを見るとよい). + +#. コンパイル済みのバイナリ版Sage(Sageサイトにある)は,ソースコードより簡単かつ速やかにインストールすることができる. + ファイルを入手したら展開して ``sage`` コマンドを実行するだけで出来上がりだ. + +#. SageTeXパッケージを使いたいのならば(SageTeXはSageの処理結果をLaTeX文書に埋め込み可能にしてくれる),使用すべきTeXディストリビューションをSageTeXに教えてやる必要がある. + 設定法については, `Sage installation guide `_ 中の "Make SageTeX known to TeX" を参照してほしい(ローカルシステム上の `ここ <../../en/installation/index.html>`_ にもインストールガイドがある). + 手順はごく簡単で,環境変数を一つ設定するか,あるいはTeX配下のディレクトリにファイルを1個コピーしてやるだけである. + + +SageTeXの利用に関する解説は +``$SAGE_ROOT/local/share/texmf/tex/generic/sagetex/`` にある. +``$SAGE_ROOT`` はSageがインストールされているディレクトリで,例えば ``/opt/sage-4.2.1`` などとなっているはずだ. + + + +Sageの使いかた +================ + +Sageを使うには以下のようなやり方がある. + +- **ノートブック グラフィカル インターフェイス:** レファレンスマニュアルのノートブックに関する節,および以下の :ref:`section-notebook` 節を参照. + +- **対話的コマンドライン:** :ref:`chapter-interactive_shell` 節を参照. + +- **プログラム作成:** Sage上でインタープリタおよびコンパイラを経由してプログラムを書く(:ref:`section-loadattach` 節と :ref:`section-compile` 節を参照).さらに + +- **スクリプト作成:** Sageライブラリを利用するスタンドアロンPythonスクリプトを書く(:ref:`section-standalone` 節を参照). + + + + + +Sageの長期目標 +======================= + +- **有用性**: Sageが想定しているユーザは,数学を学ぶ学生(高校生から大学学部生まで)と教師、そして数学の専門家である. + 代数、幾何、数論、解析学、数値解析などの数学諸分野には,種々の概念や量が現われてくる. + Sageの狙いは、ユーザが数学上の概念や諸量の性質を探ったり,それらの働きを体験する手助けになるようなソフトウェアを提供することである. + Sageを使えば,各種の数学的な実験を容易に対話的に実行することができる. + +- **高速性:** 動作が高速である. + Sageは GMP, PARI, GAP, NTLなど高度に最適化された完成度の高いソフトウェアを援用しており,多くの場合きわめて高速に演算が実行される. + +- **フリーかつオープンソース:** ソースコードは自由に入手可能で,可読性が高くなければならない. + そうすればユーザはSageが行なう処理の詳細を理解することができるし,拡張も容易になる. + 数学者であれば,定理を深く理解するために証明をていねいに読むか,少なくとも証明の流れ程度は追っておくはずである. + 計算システムのユーザも同じことで,演算処理がどのように実行されるのかソースコードを読んで把握できるようであってほしい. + 論文発表する仕事の計算にSageを使っておけば,論文の読者も確実にSageとその全ソースコードを自由に利用できることになる. + Sageでは,仕事に使ったバージョンを保存しておいて再配布することすら許されているのだ. + +- **コンパイルが容易:** Sageは,Linux, OSXあるいはWindowsのユーザがソースコードから容易にコンパイル・ビルドできるようでなくてはならない. + これによりユーザはSageシステムを柔軟に修正することができる. + +- **協調性:** Sageは,PARI, GAP, Singular, Maxima, KASH, Magma, Maple,さらにMathematicaなど多くのコンピュータ代数システムとの頑健なインターフェイスを提供する. + Sageの狙いは、既存の数学ソフトウェアとの統合と拡張である. + +- **豊富な関連文書:** チュートリアル,プログラミングガイド,レファレンスマニュアル,ハウツー類が揃っている. + これには多数の具体例と数学的背景知識の解説も含まれる. + +- **拡張性:** 新しいデータ型をゼロから定義したり,既存のデータ型を利用して作り出すことができる. + さまざまな言語で書いたプログラムをシステムに組み込んで利用することも可能だ. + +- **ユーザーフレンドリー**: ユーザは使用するオブジェクトにどんな属性や機能が組込まれているかを簡単に把握し,さらに関連文書やソースコードなども容易に閲覧できなくてはならない. + 高度のユーザーサポートも提供される. + + + diff --git a/src/doc/ja/tutorial/japanesesupport.py b/src/doc/ja/tutorial/japanesesupport.py new file mode 100755 index 00000000000..6d954e3ddc9 --- /dev/null +++ b/src/doc/ja/tutorial/japanesesupport.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +import re +__RGX = re.compile(r'([^!-~])[\n\r\t]+([^!-~])') + +def trunc_whitespace(app, doctree, docname): + from docutils.nodes import Text, paragraph + if not app.config.japanesesupport_trunc_whitespace: + return + for node in doctree.traverse(Text): + if isinstance(node.parent, paragraph): + newtext = node.astext() + #↓「非ASCII」+「"\n\r\t"たち」+「非ASCII」 + # の場合だけ置換する… + newtext = __RGX.sub(r"\1\2", newtext) + #newtext = newtext.strip() + node.parent.replace(node, Text(newtext)) + +def setup(app): + app.add_config_value('japanesesupport_trunc_whitespace', True, True) + app.connect("doctree-resolved", trunc_whitespace) diff --git a/src/doc/ja/tutorial/latex.rst b/src/doc/ja/tutorial/latex.rst new file mode 100755 index 00000000000..e7d9baf6033 --- /dev/null +++ b/src/doc/ja/tutorial/latex.rst @@ -0,0 +1,417 @@ +********************************* +Sage,LaTexと仲間たち +********************************* + +著者: Rob Beezer (2010-05-23) + +SageとTeX派生の組版システムLaTeXは,緊密な相乗的協働関係にある. +ここでは,最も基本的なものから始めて,かなり特殊かつ難解なものに至るまでの両者の多様な相互関係を概観する. +(このチュートリアルを初めて読む場合は,この節は飛ばしてかまわない) + + +概観 +======== + +SageはLaTeXを多種多様な形で利用している. +利用のメカニズムを理解する早道は,まず三種類の代表的な利用法のあらましを把握しておくことだろう. + +#. Sageでは全オブジェクトに対してLaTeX形式の印字表現が可能になっている. + Sageオブジェクト ``foo`` のLaTeX形式による印字表現を見たければ,SageノートブックまたはSageコマンド入力行で ``latex(foo)`` と実行する. + 出力された文字列をTeXの数式モード( 例えば一対の ``$`` で囲まれた領域 )内で処理すると十分に使える ``foo`` の表現が得られるはずだ. + これについては以下で実例を見る. + + 同じ手順によってSageをLaTeX文書の作成に活用することができる. + 目的のオブジェクトをSage上で作成あるいは計算しておいてから,そのオブジェクトを ``latex()`` 経由で表示した出力をLaTeX文書にカット/ペーストすればよい. + +#. ノートブックインターフェイスは,webブラウザ上で数式を明瞭に表示するため `MathJax `_ を使用するよう設定されている. + MathJaxはJavaScriptで書かれたオープンソースの数式表示エンジンで,現行のブラウザ全てで動作し,TeX形式で表現された数式の全てではないにしても,その大部分を表示することができる. + その目的はTeXで表わされた短い数式を正確に表示することであって,複雑な表や文書構造の表現と管理を支援するものではない. + ノートブックにおける見たところ自動的な数式のレンダリング表示は,数式オブジェクトの ``latex()`` 出力をMathJaxが動作可能なHTML形式に変換して得られたものである. + MathJaxはそれ自身のスケーラブルフォントを利用しており,方程式などTeX形式で表現されたテキストを静的なインライン画像に変換する方法より優れているといえる. + +#. Sageコマンドラインあるいはノートブック上でMathJaxでは処理しきれないほどLaTeXコードが複雑化してしまった場合は,システム上で公開運用されているLaTeXによって処理することもできる. + Sageには,Sage自体をビルドして使用するために必要な物ほとんど全てが含まれているが,TeXはその例外となっている. + 場合によっては,TeXシステムおよび関連の変換ユーティリティ群を別途インストールしなければ欲しい機能が完全には使えないこともあるかもしれない. + + + +ここで ``latex()`` 関数の基本的な用法を試してみよう. + +:: + + sage: var('z') + z + sage: latex(z^12) + z^{12} + sage: latex(integrate(z^4, z)) + \frac{1}{5} \, z^{5} + sage: latex('a string') + \text{\texttt{a{ }string}} + sage: latex(QQ) + \Bold{Q} + sage: latex(matrix(QQ, 2, 3, [[2,4,6],[-1,-1,-1]])) + \left(\begin{array}{rrr} + 2 & 4 & 6 \\ + -1 & -1 & -1 + \end{array}\right) + +ノートブック上ではMathJaxの基本機能は自動的に動作するが,ここでは ``MathJax`` クラスを使ってMathJaxの働きを少しばかり観察してみることにしよう. +``MathJax`` クラスの ``eval`` 関数はSageオブジェクトをLaTeX形式に変換し,さらにCSSの "math"クラスを呼び出すHTMLにラップしてMathJaxを起動する. + +:: + + sage: from sage.misc.latex import MathJax + sage: mj = MathJax() + sage: var('z') + z + sage: mj(z^12) + + sage: mj(QQ) + + sage: mj(ZZ[x]) + + sage: mj(integrate(z^4, z)) + + + + +基本的な使い方 +=================== + +上で概観したように,SageのLaTeX支援機能を利用する最も基本的な方法は ``latex()`` 関数を使って数学オブジェクトのLaTeX形式による印字表現を生成することである. +生成されたLaTeX表現は別仕立てのLaTeX文書に貼り付けて利用すればよい. +この方法はノートブックでもSageコマンドラインでも同じように通用する. + + +もう一つの手軽な方法に ``view()`` コマンドの使用がある. +Sageコマンドラインで ``view(foo)`` を実行すると ``foo`` のLaTeX表現が得られるから,これをLaTeX文書に取り込んで使っているシステムにインストールされたTeXで処理する. +TeXの出力を適切なビューワーで表示して出来上がりである. +使用するTeXのバージョンや,それに応じた出力とビューワーは選択することができる( :ref:`sec-custom-processing` 節を参照). + + +ノートブック上では, ``view(foo)`` コマンドはMathJaxがワークシート上でLaTeX表現を正しくレンダリングできるよう適切なHTMLとCSSの組を生成する. +ユーザーの目に映るのはSageデフォルトのASCII文字出力ではなく,きれいにフォーマットされた数式出力ということになる. +ただしSageの数学オブジェクト全てがMathJaxで表示可能なLaTeX表現をもつとは限らない. +表示できない場合にはMathJaxではなくシステム上のTeXを使って処理し,出力をワークシートに表示可能な画像へ変換することができる. +これに必要な一連の処理をどうやってコントロールするかについては :ref:`sec-custom-generation` 節で解説する. + + +ノートブックにはTeXを利用するための機能があと二つある. +一つはワークシートの最初のセルのすぐ上に並ぶ四つのドロップダウンボックスの右にある "Typeset"ボタンである. +これをチェックしておくと,以降はセルの評価結果はMathJaxで処理されて印刷品質で表示される. +ただし,この機能は遡及的に作用するわけではなく,事前に評価済みのセルについては評価し直してやる必要がある. +つまるところ "Typeset"ボタンにチェックを入れるのは,以降のセル評価出力を ``view()`` コマンドでラップして表示することを意味することになる. + + +ノートブックのTeX支援機能の二つ目は,ワークシートの注釈にTeX形式が利用可能な点である. +ワークシート上でセルの間にカーソルが移動すると青色のバーが現れるから,そこで ```` するとTinyMCEというちょっとしたワードプロセッサが起動する. +これを使えばテキスト入力を行ない,かつWSIWYGエディタ経由でHTMLとCSSを作成して書式付けすることができる. +つまりワークシート内で書式付きテキストを作成し注釈として付加することが可能なわけだ. +一方,ダラー記号(``$``)あるいはダラー記号2つ(``$$``)の間に挟まれた文字列はMathJaxによってインラインあるいはディスプレイ数式として解釈される. + + + +.. _sec-custom-generation: + + +LaTeXコード生成のカスタマイズ +================================== + +``latex()`` コマンドによるLaTeXコードの生成をカスタマイズする方法は何通りも用意されている. +ノートブックでもSageコマンドラインでも,すでに ``latex`` という名前のオブジェクトが定義済みで, ``latex.`` (ピリオド ``.`` に 注意)と入力して ``[Tab]`` キーを押せばメソッドの一覧を表示することができる. + +.. .. +.. There are several ways to customize the actual LaTeX code generated by +.. the ``latex()`` command. In the notebook and at the Sage command-line +.. there is a pre-defined object named ``latex`` which has several methods, +.. which you can list by typing ``latex.``, followed by the tab key +.. (note the period). + +ここでは ``latex.matrix_delimiters`` メソッドに注目してみよう. +このメソッドを使えば,行列を囲む記号を大丸かっこ,角かっこ,中かっこ,縦棒などに変更することができる. +何か形式上の制限があるわけではないから,好きなように組み合わせてかまわない. +LaTeXで使われるバックスラッシュには,Pythonの文字列内でエスケープするためもう1個のバックスラッシュを付ける必要があることに注意. + + +:: + + sage: A = matrix(ZZ, 2, 2, range(4)) + sage: latex(A) + \left(\begin{array}{rr} + 0 & 1 \\ + 2 & 3 + \end{array}\right) + sage: latex.matrix_delimiters(left='[', right=']') + sage: latex(A) + \left[\begin{array}{rr} + 0 & 1 \\ + 2 & 3 + \end{array}\right] + sage: latex.matrix_delimiters(left='\\{', right='\\}') + sage: latex(A) + \left\{\begin{array}{rr} + 0 & 1 \\ + 2 & 3 + \end{array}\right\} + +``latex.vector_delimiters`` メソッドも同様の機能をもつ. + + +(整数,有理数,実数など)標準的な環や体をどんな書体で表示するかは ``latex.blackboard_bold`` メソッドによって制御することができる. +デフォルトではボールド体で表示されるが,手書きの場合にやるように黒板ボールド体(重ね打ち体)を使うこともできる. +それにはSageのビルトインマクロ ``\Bold{}`` を再定義してやればよい. + + +:: + + sage: latex(QQ) + \Bold{Q} + sage: from sage.misc.latex import MathJax + sage: mj=MathJax() + sage: mj(QQ) + + sage: latex.blackboard_bold(True) + sage: mj(QQ) + + sage: latex.blackboard_bold(False) + +新しいマクロやパッケージなどを追加して,TeXの高い拡張性を利用することができる. +まず,ノートブックでMathJaxが短いTeXコードを解釈する際に使われる,自分用のマクロを追加してみよう. + + +:: + + sage: latex.extra_macros() + '' + sage: latex.add_macro("\\newcommand{\\foo}{bar}") + sage: latex.extra_macros() + '\\newcommand{\\foo}{bar}' + sage: var('x y') + (x, y) + sage: latex(x+y) + x + y + sage: from sage.misc.latex import MathJax + sage: mj=MathJax() + sage: mj(x+y) + + + +以上のようなやり方で追加したマクロは,MathJaxでは対応しきれない大規模な処理が発生してシステム上のTeXが呼ばれるような場合にも使われる. +自立したLaTeX文書のプリアンブルを定義する ``latex_extra_preamble`` コマンドの使い方は以下で具体例を示す. +これまで通りPython文字列中ではバックスラッシュが二重になっていることに注意. + + +:: + + sage: latex.extra_macros('') + sage: latex.extra_preamble('') + sage: from sage.misc.latex import latex_extra_preamble + sage: print latex_extra_preamble() + \newcommand{\ZZ}{\Bold{Z}} + ... + \newcommand{\Bold}[1]{\mathbf{#1}} + sage: latex.add_macro("\\newcommand{\\foo}{bar}") + sage: print latex_extra_preamble() + \newcommand{\ZZ}{\Bold{Z}} + ... + \newcommand{\Bold}[1]{\mathbf{#1}} + \newcommand{\foo}{bar} + + +長く複雑なLaTeX表現を処理するために,LaTeXファイルのプリアンブルでパッケージ類を付加してやることができる. +``latex.add_to_preamble`` コマンドを使えば好きなものをプリアンブルに取り込めるし, ``latex.add_package_to_preamble_if_available`` コマンドはプリアンブルへの取り込みを実行する前に,指定したパッケージが利用可能かどうかをチェックしてくれる. + + +以下の例ではプリアンブルでgeometryパッケージを取り込み,ページ上でTeXに割り当てる領域(実質的にはマージン)サイズを指定している. +例によってPython文字列のバックスラッシュは二重になっていることに注意. + + +:: + + sage: from sage.misc.latex import latex_extra_preamble + sage: latex.extra_macros('') + sage: latex.extra_preamble('') + sage: latex.add_to_preamble('\\usepackage{geometry}') + sage: latex.add_to_preamble('\\geometry{letterpaper,total={8in,10in}}') + sage: latex.extra_preamble() + '\\usepackage{geometry}\\geometry{letterpaper,total={8in,10in}}' + sage: print latex_extra_preamble() + \usepackage{geometry}\geometry{letterpaper,total={8in,10in}} + \newcommand{\ZZ}{\Bold{Z}} + ... + \newcommand{\Bold}[1]{\mathbf{#1}} + +あるパッケージの存在確認をした上で取り込みを実行することもできる. +例として,ここでは存在しないはずのパッケージのプリアンブルへの取り込みを試みてみよう. + + +:: + + sage: latex.extra_preamble('') + sage: latex.extra_preamble() + '' + sage: latex.add_to_preamble('\\usepackage{foo-bar-unchecked}') + sage: latex.extra_preamble() + '\\usepackage{foo-bar-unchecked}' + sage: latex.add_package_to_preamble_if_available('foo-bar-checked') + sage: latex.extra_preamble() + '\\usepackage{foo-bar-unchecked}' + + +.. _sec-custom-processing: + + +LaTeX処理のカスタマイズ +============================ + +システムで公開運用されているTeXシステムから好みの種類を指定して,出力形式を変更することも可能だ. +さらに,ノートブックがMathJax(簡易TeX表現用)とTeXシステム(複雑なLaTeX表現用)を使い分ける仕方を制御することができる. + + +``latex.engine()`` コマンドを使えば,複雑なLaTeX表現に遭遇した場合,システム上で運用されているTeXの実行形式 ``latex``, ``pdflatex`` または ``xelatex`` の内どれを使って処理するかを指定することができる. +``view()`` がsageコマンドラインから発行されると,実行形式 ``latex`` が選択されるから,出力はdviファイルとなりsageにおける表示にも(xdviのような)dviビューワーが使われる. +これに対し,TeX実行形式として ``pdflatex`` が設定された状態でsageコマンドラインから ``view()`` を呼ぶと,出力はPDFファイルとなってSageが表示に使用するのはシステム上のPDF表示ユーティリティ(acrobat,okular, evinceなど)となる. + + +ノートブックでは,簡単なTeX表現だからMathJaxで処理できるのか,あるいは複雑なLaTeX表現のためシステム上のTeXを援用すべきなのか,判断の手掛りを与えてやる必要がある. +手掛りとするのは文字列リストで,リストに含まれる文字列が処理対象のLaTeX表現に含まれていたらノートブックはMathJaxを飛ばしてlatex(もしくは ``latex.engine()`` コマンドで指定された実行形式)による処理を開始する. +このリストは ``latex.add_to_mathjax_avoid_list`` および ``latex.mathjax_avoid_list`` コマンドによって指定される. + + +:: + + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() + [] + sage: latex.mathjax_avoid_list(['foo', 'bar']) + sage: latex.mathjax_avoid_list() + ['foo', 'bar'] + sage: latex.add_to_mathjax_avoid_list('tikzpicture') + sage: latex.mathjax_avoid_list() + ['foo', 'bar', 'tikzpicture'] + sage: latex.mathjax_avoid_list([]) + sage: latex.mathjax_avoid_list() + [] + + +ノートブック上で ``view()`` コマンド,あるいは "Typeset"ボタンがチェックされた状態でLaTeX表式が生成されたが, ``latex.mathjax_avoid_list`` によってシステム上のLaTeXが別途必要とされたとしよう. +すると,そのLaTeX表式は(``latex.engine()`` で設定した)指定のTeX実行形式によって処理される. +しかし,Sageは(コマンドライン上のように)外部ビューワーを起動して表示する代わりに,結果をセル出力としてきっちりトリミングした1個の画像に変換してからワークシートに挿入する. + + +変換が実際にどう実行されるかについては,いくつもの要因が影響している. +しかし大勢は,TeX実行形式として何が指定されているか,そして利用可能な変換ユーティリティは何かによって決まるようだ. +``dvips``, ``ps2pdf``, ``dvipng`` そして ``ImageMagick`` に含まれる ``convert`` の四種の優秀な変換ユーティリティがあれば,あらゆる状況に対処できるだろう. +目標はワークシートに挿入して表示可能なPNGファイルを生成することで,LaTeX表式からdvi形式へのLatexエンジンによる変換が成功していれば,dvipngが変換を仕上げてくれる. +LaTeX表式とLatexエンジンの生成するdvi形式にdvipngが扱えないspecial命令が入っている場合には,dvipsでポストスクリプトファイルへ変換する. +ポストスクリプトあるいは ``pdflatex`` エンジンによって出力されたPDFファイルは ``convert`` ユーティリティによってPNG形式へ変換される. +ここで紹介した二つの変換ユーティリティは ``have_dvipng()`` と ``have_convert()`` ルーチンを使って存在を確認することができる. + + +必要な変換プログラムがインストールされていれば変換は自動的に行われる. +ない場合は,何が不足していて,どこからダウンロードすればよいかを告げるエラーメッセージが表示される. + + +どうすれば複雑なLaTeX表式を処理できるのか,その具体例として次節(:ref:`sec-tkz-graph`)ではLaTeXの ``tkz-graph`` パッケージを使って高品位の連結グラフを作成する方法を解説する. +他にも例が見たければ,パッケージ化済みのテストケースが用意されている. +利用するには, 以下で見るように ``sage.misc.latex.LatexExamples`` クラスのインスタンスである ``sage.misc.latex.latex_examples`` オブジェクトをインポートしなければならない. +現在,このクラスには可換図,組合せ論グラフと結び目理論,およびpstricks関連の例題が含まれており,各々がxy, tkz-graph, xypic, pstricksパッケージの使用例になっている. +インポートを終えたら, ``latex_examples`` をタブ補完してパッケージに含まれる実例を表示してみよう. +例題各々で適正な表示に必要なパッケージや手続きが解説されている. +(プリアンブルやlatexエンジン類が全て上手く設定されていても)実際に例題を表示するには ``view()`` を使わなくてはならない. + + + +:: + + sage: from sage.misc.latex import latex_examples + sage: latex_examples.diagram() + LaTeX example for testing display of a commutative diagram produced + by xypic. + + To use, try to view this object -- it won't work. Now try + 'latex.add_to_preamble("\\usepackage[matrix,arrow,curve,cmtip]{xy}")', + and try viewing again -- it should work in the command line but not + from the notebook. In the notebook, run + 'latex.add_to_mathjax_avoid_list("xymatrix")' and try again -- you + should get a picture (a part of the diagram arising from a filtered + chain complex). + + +.. _sec-tkz-graph: + + +具体例: tkz-graphによる連結グラフの作成 +=============================================== + +``tkz-graph`` パッケージを使って高品位の連結グラフ(以降はたんに「グラフ」と呼ぶ)を作成することができる. +このパッケージは ``pgf`` ライブラリの ``tikz`` フロントエンド上に構築されている. +したがってその全構成要素がシステム運用中のTeXで利用可能でなければならないが,TeXシステムによっては必要なパッケージが全て最新になっているとは限らない. +満足すべき結果を得るには,必要なパッケージの最新版をユーザのtexmf配下にインストールする必要が生ずるかもしれない. +個人または公開利用のためのTeXのインストールや管理運用についてはこのチュートリアルの範囲を越えるが,必要な情報は簡単に見つかるはずだ. +必要なファイル類は :ref:`sec-system-wide-tex` 節に挙げられている. + + +まずは土台とするLaTeX文書のプリアンブルで必要なパッケージが付加されることを確認しておこう. +グラフ画像はdviファイルを経由すると正しく生成されないので,latexエンジンとしては ``pdflatex`` プログラムを指定するのが一番だ. +すると,Sageコマンドライン上で ``view(graphs.CompleteGraph(4))`` の実行が可能になり,完結したグラフ `K_4` の適切なPDF画像が生成されるはずだ. + + +ノートブックでも同様の動作を再現するには,グラフを表わすLaTeXコードのMathJaxによる処理を ``mathjax avoid list`` を使って抑止する必要がある. +グラフは ``tikzpicture`` 環境で取り込まれるから,文字列 ``tikzpicture`` を ``mathjax avoid list`` に入れておくとよい. +そうしてからワークシートで ``view(graphs.CompleteGraph(4))`` を実行するとpdflatexがPDFファイルを生成し,ついで ``convert`` ユーティリティが抽出したPNG画像がワークシートの出力セルに挿入されることになる. +ノートブック上でグラフをLaTeXにグラフを処理させるために必要なコマンド操作を以下に示す. + + +:: + + sage: from sage.graphs.graph_latex import setup_latex_preamble + sage: setup_latex_preamble() + sage: latex.extra_preamble() # システムで運用されているTeXの種類に依存 + '\\usepackage{tikz}\n\\usepackage{tkz-graph}\n\\usepackage{tkz-berge}\n' + sage: latex.engine('pdflatex') + sage: latex.add_to_mathjax_avoid_list('tikzpicture') + sage: latex.mathjax_avoid_list() + ['tikz', 'tikzpicture'] + +ここまで設定してから ``view(graphs.CompleteGraph(4))`` のようなコマンドを実行すると, ``tkz-graph`` で表現されたグラフが ``pdflatex`` で処理されてノートブックに挿入される. +LaTeXに ``tkz-graph`` 経由でグラフを描画させる際には多くのオプションが影響するが,詳細はこの節の範囲を越えている. +興味があればレファレンスマニュアル "LaTeX Options for Graphs"の解説を見てほしい. + + + +.. _sec-system-wide-tex: + +TeXシステムの完全な運用 +================================ + +TeXをSageに統合して運用する際,高度な機能の多くはシステムに独立してインストールされたTeXがないと利用できない. +Linux系システムではTeXliveを基にした基本TeXパッケージを採用しているディストリビューションが多く,OSXではTeXshop,WindowsではMikTeXなどが使われている. +``convert`` ユーティリティは `ImageMagick `_ パッケージ(簡単にダウンロード可能)に含まれているし, ``dvipng``, ``ps2pdf`` と ``dvips`` の三つのプログラムはTeXパッケージに同梱されているはずだ. +また ``dvipng`` は http://sourceforge.net/projects/dvipng/ から, ``ps2pdf`` は `Ghostscript `_ の一部として入手することもできる. + + +連結グラフの作画には,PGFライブラリの新しいバージョンに加えて ``tkz-graph.sty`` と ``tkz-arith.sty`` が必要で,さらに ``tkz-berge.sty`` も必要になるかもしれない. +tkz関係のファイルは全て `Altermundus site `_ から入手することができる. + + + +外部プログラム +================= + +TeXとSageのさらなる統合運用に役立つプログラムが三つある. +その一番目がsagetexで,このTeXマクロ集を使えばLaTeX文書からSage上の多様なオブジェクトに対する演算や組み込みコマンド ``latex()`` によるフォーマットなどを実行することができる. +LaTeX文書のコンパイル処理過程で,Sageの演算やLaTeXによるフォーマット支援などの全ての機能も自動的に実行されるのである. +sagetexを使えば,例えば数学試験作成において,問題の計算そのものをSageに実行させて対応する解答を正確に維持管理することなどが可能になる. +詳細は :ref:`sec-sagetex` 節を参照してほしい. + + +tex2swsはLaTeX文書にSageコードを組込むための環境を定義している. +これをしかるべきツールで処理すると,MathJaxで適切に表示される本文と入力セル経由で動作するSageコードが組込まれたSageワークシートが出来上がる. +tex2sws環境を使えばLaTeXで教科書や記事をSageコードのブロックを含んだ形で執筆することができるが,これを変換すると数式混じりの本文は美しく整形され,かつSageコード部分が機能するSageワークシートになるわけである. +現在も開発進行中で,詳細は `tex2sws @ BitBucket `_ を見てほしい. + + +これとは逆に,sws2texはSageワークシートをLaTeX形式に変換してLaTeX関連ツールによる処理を可能にする. +現在も開発中で,詳細は `sws2tex @ BitBucket `_ を見てほしい. + diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst new file mode 100755 index 00000000000..5b70c1be6fd --- /dev/null +++ b/src/doc/ja/tutorial/programming.rst @@ -0,0 +1,794 @@ +================= + プログラミング +================= + +.. _section-loadattach: + +Sageファイルの読み込みと結合 +============================== + +ここでは,独立したファイルに保存したプログラムをSageに読み込む方法を解説する. +まず,ファイル ``example.sage`` に以下のプログラムを保存しておこう: + +.. skip + +:: + + print "Hello World" + print 2^3 + +``example.sage`` ファイルを読み込んで実行するには, ``load`` コマンド を使う. + +.. skip + +:: + + sage: load("example.sage") + Hello World + 8 + +実行中のセッションにSageファイルを結合するには, ``attach`` コマンドが使える: + +.. skip + +:: + + sage: attach("example.sage") + Hello World + 8 + +こうして ``attach`` したファイル ``example.sage`` に変更を加えてからSageで空行を入力すると( ``return`` を押す),Sageは自動的に ``example.sage`` の内容を読み込んで実行する. + +``attach`` は結合したファイルに変更が生じると自動的に読込んで実行してくれるので,デバッグの時にはとりわけ便利なコマンドになる. +これに対し ``load`` の方は,コマンド実行時に一度だけファイルを読込んで実行するだけだ. + +``example.sage`` を読込むとSageは内容をPythonプログラムへと変換し,これをPythonインタプリタが実行する. +このPythonへの変換は最小限に留められていて,整数リテラルを ``Integer()`` で,浮動小数点数リテラルを ``RealNumber()`` でラップし, ``^`` を ``**`` で,また ``R.2`` を ``R.gen(2)`` で置換するなどといった程度である. +変換された ``example.sage`` のコードは, ``example.sage`` と同じディレクトリに ``example.sage.py`` という名前のファイルとして保存されている. +この ``example.sage.py`` に入っているコードは: + +:: + + print "Hello World" + print Integer(2)**Integer(3) + +たしかに整数リテラルはラップされ, ``^`` は ``**`` に置換されている.(Pythonでは ``^`` は「排他的論理和」, ``**`` は「べき乗」を意味する.) + +こうした前処理は ``sage/misc/interpreter.py`` として実装されている. + +コードブロックが改行で開始されているなら,インデントされた複数行のコードをSageにペーストすることができる(ファイルの読込みについてはブロック開始時の改行も不要だ). +しかしSage上にコードを取り込むには,そのコードをファイルに保存してから,先に説明したように ``attach`` するのが一番安全だ. + + +.. _section-compile: + +実行形式の作成 +=============== + +数学的演算処理では実行速度がとりわけ重要になる. +Pythonは使い勝手のよい非常に高水準の言語ではあるが,計算の種類によってはスタティックに型付けされたコンパイラ言語で実行した方が処理速度が数桁も速くなる場合がある. +Sageにも,もし完全にPythonのみで実装していたら遅くて使いものにならなかったはずの機能がある. +そうした状況を切り抜けるために,SageはCythonと呼ばれるコンパイラ言語版Pythonを利用している([Cyt]_ と [Pyr]_). +Cythonは,PythonとCの両方に似ていて,リスト内包表記、条件制御、それに ``+=`` などを含むPythonの構文の大半を使うことができるし,Pythonで書いておいたモジュールをインポートすることも可能だ. +加えて,C言語の変数を自由に宣言し,かつ好きなCライブラリをコード内から直接呼び出すことができる. +Cythonで書いたコードはCに変換され,Cコンパイラでコンパイルされることになる. + +Sageコードの実行形式を作成するには,ソースファイルの拡張子を(``.sage`` ではなく) ``.spyx`` とする. +コマンドラインインターフェイスを使っている場合,実行形式をインタプリタ用コードのときと全く同じやり方で ``attach`` あるいは ``load`` することができる(今のところ,ノートブックインターフェイスではCythonで書いたコードの読込みと結合はできない). +実際のコンパイル処理は,ユーザーが特に何も指定しなくとも裏で実行されている. +作成された実行形式の共有ライブラリは ``$HOME/.sage/temp/hostname/pid/spyx`` に格納されるが,Sageの終了時に消去される. + + +Sageはspyxファイルに対しては前処理をしない. +だから例えばspyxファイル中の ``1/3`` は有理数 :math:`1/3` ではなく0と評価される.Sageライブラリに含まれる関数 ``foo`` をspyxファイルで使用したければ, ``sage.all`` をインポートしてから ``sage.all.foo`` として呼び出す必要がある. + +:: + + import sage.all + def foo(n): + return sage.all.factorial(n) + + + +他ファイル中のC関数を使う +------------------------- + +別途 \*.cファイルで定義されたC関数を使うのも簡単だ. +実例を見てみよう. +まず,同じディレクトリにファイル ``test.c`` と ``test.spyx`` を作り,内容はそれぞれ以下の通りであるとする: + + +純粋にCで書かれたプログラムは ``test.c`` : + +:: + + int add_one(int n) { + return n + 1; + } + +Cythonプログラムが入っているのが ``test.spyx``: + +:: + + cdef extern from "test.c": + int add_one(int n) + + def test(n): + return add_one(n) + +すると,次の手順でCプログラムを取り込むことができる: + +.. skip + +:: + + sage: attach("test.spyx") + Compiling (...)/test.spyx... + sage: test(10) + 11 + +Cythonソースファイルから生成されたC言語コードをコンパイルするために,さらにライブラリ ``foo`` が必要な場合は,元のCythonソースに ``clib foo`` という行を加える. +同様に、他にもCソースファイル ``bar`` が必要ならばCythonソースに取り込みを宣言する行 ``cfile bar`` を加えてコンパイルすればよい. + + +.. _section-standalone: + +スタンドアロンPython/Sageスクリプト +==================================== + +以下のスタンドアロン型Sageスクリプトは,整数や多項式などを因数分解する: + +:: + + #!/usr/bin/env sage -python + + import sys + from sage.all import * + + if len(sys.argv) != 2: + print "Usage: %s "%sys.argv[0] + print "Outputs the prime factorization of n." + sys.exit(1) + + print factor(sage_eval(sys.argv[1])) + +このスクリプトを実行するには, ``SAGE_ROOT`` をPATHに含めておかなければならない. +スクリプト名を ``factor`` とすると,実行は以下のような具合になる: + + +:: + + bash $ ./factor 2006 + 2 * 17 * 59 + bash $ ./factor "32*x^5-1" + (2*x - 1) * (16*x^4 + 8*x^3 + 4*x^2 + 2*x + 1) + + + +データ型 +========= + +Sageに現れるオブジェクトには,全て明確に定義されたデータ型が割り当てられている. +Pythonは豊富な組み込み型を備えているが,それをさらに多彩に拡張しているのがSageのライブラリだ. +Pythonの組み込み型としては,string(文字列),list(リスト),タプル(tuple),int(整数),float(浮動小数点数)などがある. +実際に型を表示してみると: + + +:: + + sage: s = "sage"; type(s) + + sage: s = 'sage'; type(s) # シングルあるいはダブル クォーテーションのどちらも使える + + sage: s = [1,2,3,4]; type(s) + + sage: s = (1,2,3,4); type(s) + + sage: s = int(2006); type(s) + + sage: s = float(2006); type(s) + + +Sageでは,さらに多様な型が加わる. +その一例がベクトル空間である: + +:: + + sage: V = VectorSpace(QQ, 1000000); V + Vector space of dimension 1000000 over Rational Field + sage: type(V) + + +この ``V`` に適用できるのは,あらかじめ定められた特定の関数に限られる. +他の数学ソフトウェアでは,そうした関数の呼び出しに「関数型記法」 ``foo(V,...)`` が用いられているようだ. +これに対し,Sageでは ``V`` の型(クラス)に付属する関数群が定められていて,JAVAやC++に見られるようなオブジェクト指向型の構文 ``V.foo(...)`` で関数呼び出しが行なわれる. +オブジェクト指向の世界では,関数が莫大な数になってもグローバルな名前空間を混乱なく運用することが可能になる. +たとえ機能の異なる関数群が同じ ``foo`` という名前を持っていたとしても,型チェックや場合分け抜きで引数の型に応じた適切な関数が自動的に呼び出されるのである. +さらに,ある関数の名前を他の意味で使い回しても関数そのものは使い続けることができる(例えば ``zeta`` を何かの変数名として使った後でも,リーマンのゼータ関数の0.5における値を求めるには ``s=.5; s.zeta()`` と入力すれば足りる). + + +:: + + sage: zeta = -1 + sage: s=.5; s.zeta() + -1.46035450880959 + + +ごく慣用化している場合については,通常の関数型記法を使うこともできる. +これは便利であると同時に,数学表現にはそもそもオブジェクト指向型記法になじまないものもあるためだ. +ここで少し例を見てみよう. + + +:: + + sage: n = 2; n.sqrt() + sqrt(2) + sage: sqrt(2) + sqrt(2) + sage: V = VectorSpace(QQ,2) + sage: V.basis() + [ + (1, 0), + (0, 1) + ] + sage: basis(V) + [ + (1, 0), + (0, 1) + ] + sage: M = MatrixSpace(GF(7), 2); M + Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 + sage: A = M([1,2,3,4]); A + [1 2] + [3 4] + sage: A.charpoly('x') + x^2 + 2*x + 5 + sage: charpoly(A, 'x') + x^2 + 2*x + 5 + +:math:`A` のメンバ関数を全て表示するには,タブ補完入力を利用すればよい. +:ref:`section-tabcompletion` 節で説明したように,これは ``A.`` と入力してから,キーボードの ``[tab]`` キーを押すだけのことだ. + + +リスト,タプル,シーケンス +=========================== + +リスト型には,任意の型の要素を格納することができる. +(大半のコンピュータ代数システムとは違って)CやC++などと同じように,Sageでもリストの要素番号は :math:`0` から始まる: + + +:: + + sage: v = [2, 3, 5, 'x', SymmetricGroup(3)]; v + [2, 3, 5, 'x', Symmetric group of order 3! as a permutation group] + sage: type(v) + + sage: v[0] + 2 + sage: v[2] + 5 + +リストの要素番号は,Pythonのint型でなくとも平気だ. +SageのIntegerクラスが使えるのは言うまでもない(Rationalクラスを含めて、 ``__index__`` メソッドが有効なクラスであれば何でも使える). + +.. .. +.. (When indexing into a list, it is OK if the index is +.. not a Python int!) +.. A Sage Integer (or Rational, or anything with an ``__index__`` method) +.. will work just fine. + +:: + + sage: v = [1,2,3] + sage: v[2] + 3 + sage: n = 2 # SAGEの整数 + sage: v[n] # 全く問題なし + 3 + sage: v[int(n)] # これも大丈夫 + 3 + +``range`` 関数は,Pythonのint型からなるリストを生成する(SageのIntegerではないことに注意): + +:: + + sage: range(1, 15) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] + +この ``range`` が便利なのは,リスト内包表記を使ってリストを生成する場合だ: + + +:: + + sage: L = [factor(n) for n in range(1, 15)] + sage: print L + [1, 2, 3, 2^2, 5, 2 * 3, 7, 2^3, 3^2, 2 * 5, 11, 2^2 * 3, 13, 2 * 7] + sage: L[12] + 13 + sage: type(L[12]) + + sage: [factor(n) for n in range(1, 15) if is_odd(n)] + [1, 3, 5, 7, 3^2, 11, 13] + +以上のようなリスト内包表記を使ったリスト生成については, [PyT]_ に詳しい. + +.. .. +.. For more about how to create lists using list comprehensions, see +.. [PyT]_. + +とりわけ使い勝手が良いのが,リストのスライシングだ. +リスト ``L`` のスライシング ``L[m:n]`` は, :math:`m` 番目の要素に始まり :math:`n-1` 番目の要素で終わる部分リストを返す. +以下に例を示そう: + +:: + + sage: L = [factor(n) for n in range(1, 20)] + sage: L[4:9] + [5, 2 * 3, 7, 2^3, 3^2] + sage: print L[:4] + [1, 2, 3, 2^2] + sage: L[14:4] + [] + sage: L[14:] + [3 * 5, 2^4, 17, 2 * 3^2, 19] + +タプルはリストに似ているが,これがいったん生成された後は変更できない不変性(immutable)オブジェクトである点で異なる. + + +:: + + sage: v = (1,2,3,4); v + (1, 2, 3, 4) + sage: type(v) + + sage: v[1] = 5 + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +Sageで使われる第三のリスト類似データ型が,シーケンスである. +リストやタプルと違って,シーケンスはPython本体の組み込み型ではない. +デフォルトではシーケンス型は可変だが,以下の例で見るように ``Sequence`` クラスのメソッド ``set_immutable`` を使って不変性を与えることができる. +あるシーケンスの全要素は,シーケンス・ユニバースと呼ばれる共通のペアレントを持つ. + + +:: + + sage: v = Sequence([1,2,3,4/5]) + sage: v + [1, 2, 3, 4/5] + sage: type(v) + + sage: type(v[1]) + + sage: v.universe() + Rational Field + sage: v.is_immutable() + False + sage: v.set_immutable() + sage: v[0] = 3 + Traceback (most recent call last): + ... + ValueError: object is immutable; please change a copy instead. + + +シーケンスはリストから導き出すことができて,リストが使える文脈では常に利用することができる: + +:: + + sage: v = Sequence([1,2,3,4/5]) + sage: isinstance(v, list) + True + sage: list(v) + [1, 2, 3, 4/5] + sage: type(list(v)) + + + +不変性シーケンスの例としては,ベクトル空間の基底系があげられる. +基底系そのものが変わっては困るから,これは当然のことだ. + + +:: + + sage: V = QQ^3; B = V.basis(); B + [ + (1, 0, 0), + (0, 1, 0), + (0, 0, 1) + ] + sage: type(B) + + sage: B[0] = B[1] + Traceback (most recent call last): + ... + ValueError: object is immutable; please change a copy instead. + sage: B.universe() + Vector space of dimension 3 over Rational Field + + +ディクショナリ +=============== + +ディクショナリ(「連想配列」と呼ばれる場合もある)とは,文字列、数値、タプルなどのハッシュ可能なオブジェクトから任意のオブジェクトへの写像のことである. +(ハッシュ可能オブジェクトについての詳細は http://docs.python.org/tut/node7.html と http://docs.python.org/lib/typesmapping.html を参照.) + +:: + + sage: d = {1:5, 'sage':17, ZZ:GF(7)} + sage: type(d) + + sage: d.keys() + [1, 'sage', Integer Ring] + sage: d['sage'] + 17 + sage: d[ZZ] + Finite Field of size 7 + sage: d[1] + 5 + +三番目の例を見ると分るように,ディクショナリのインデックス(キー)として整数環のような複雑なオブジェクトでも使うことができる. + + +上の例のディクショナリは,同じデータを含むリストに直すことができる: + + +.. link + +:: + + sage: d.items() + [(1, 5), ('sage', 17), (Integer Ring, Finite Field of size 7)] + +ディクショナリに含まれるキーと値の対を反復に利用する場合に,よく使われるイディオムがある: + + +:: + + sage: d = {2:4, 3:9, 4:16} + sage: [a*b for a, b in d.iteritems()] + [8, 27, 64] + +最後の出力を見ると判るように,ディクショナリ内は整列されていない. + + + +集合 +===== + +Pythonには集合(set)型が組込まれている. +集合型の主な利点としては,標準的な集合演算が可能になるだけではなく,ある要素が集合に属するかどうかを極めて高速に判定する機能を備えている点があげられる. + +:: + + sage: X = set([1,19,'a']); Y = set([1,1,1, 2/3]) + sage: X + set(['a', 1, 19]) + sage: Y + set([1, 2/3]) + sage: 'a' in X + True + sage: 'a' in Y + False + sage: X.intersection(Y) + set([1]) + +さらに,Sageは(Pythonの組み込み集合型を使って実装されたものも含まれる)独自の集合型を備えており,こちらにはSageに固有の付加機能がいくつか加えられている. +このSage独自の集合型を生成するには, ``Set(...)`` を使う. +例えば + +:: + + sage: X = Set([1,19,'a']); Y = Set([1,1,1, 2/3]) + sage: X + {'a', 1, 19} + sage: Y + {1, 2/3} + sage: X.intersection(Y) + {1} + sage: print latex(Y) + \left\{1, \frac{2}{3}\right\} + sage: Set(ZZ) + Set of elements of Integer Ring + + + +イテレータ +=========== + +イテレータ(iterator)は最近になってPythonに加えられた機能で,数学指向のアプリケーション作成にはとりわけ便利なものだ. +以下で実例を見ていくことにするが,使用法の詳細は [PyT]_ を見てほしい. +まず :math:`10000000` までの非負整数の平方に関するイテレータを作ってみよう. + +:: + + sage: v = (n^2 for n in xrange(10000000)) + sage: v.next() + 0 + sage: v.next() + 1 + sage: v.next() + 4 + +今度は,素数 :math:`p` から :math:`4p+1` の形の素数に関するイテレータを作り,最初の数個を見てみることにする. + + +:: + + sage: w = (4*p + 1 for p in Primes() if is_prime(4*p+1)) + sage: w # 次の行の 0xb0853d6c はランダムに生成された16進数 + + sage: w.next() + 13 + sage: w.next() + 29 + sage: w.next() + 53 + +有限体,整数など,ある種の環にはイテレータが付随している: + +:: + + sage: [x for x in GF(7)] + [0, 1, 2, 3, 4, 5, 6] + sage: W = ((x,y) for x in ZZ for y in ZZ) + sage: W.next() + (0, 0) + sage: W.next() + (0, 1) + sage: W.next() + (0, -1) + + + +ループ,関数,制御文,比較 +============================= + +``for`` ループの一般的な使用法については,これまでに何度も実例を見ている. +Pythonでは、 ``for`` ループ構文はインデントで分節されている. +次のような具合だ: + +:: + + >>> for i in range(5): + ... print(i) + ... + 0 + 1 + 2 + 3 + 4 + + +``for`` 文はコロン ``:`` で終っており,ループの本体すなわち ``print(i)`` がインデントされていることに注意(GAPやMapleに見られる "do"や "od"はない). +Pythonでは,このインデントが重要な役割を果たしている. +以下の例のように,Sageでは ``:`` に続けて ``enter`` キーを押すと自動的にインデントが挿入される. + +:: + + sage: for i in range(5): + ....: print(i) # ここでは[Enter]を2回押す + ....: + 0 + 1 + 2 + 3 + 4 + + +代入には ``=`` 記号,比較には ``==`` 記号を使う: + +:: + + sage: for i in range(15): + ....: if gcd(i,15) == 1: + ....: print(i) + ....: + 1 + 2 + 4 + 7 + 8 + 11 + 13 + 14 + +``if`` , ``for`` および ``while`` 文のブロック構造が,インデントによって決まっているところに注目: + + +:: + + sage: def legendre(a,p): + ... is_sqr_modp=-1 + ... for i in range(p): + ... if a % p == i^2 % p: + ... is_sqr_modp=1 + ... return is_sqr_modp + + sage: legendre(2,7) + 1 + sage: legendre(3,7) + -1 + +むろん,上のコードの目的はPython/Sageによるプログラムの特徴を例示することであって,Legendre記号の効率的な実装にはなっていない. +Sageに付属している関数 ``kronecker`` は,PARIのCライブラリを経由してLegendre記号を効率良く計算する. + + +最後に注意したいのは ``==`` , ``!=`` , ``<=`` , ``>=`` , ``>`` , ``<`` などを使った比較演算では,比較対象の量は可能ならば自動的に同じ型に変換されることだ: + + +:: + + sage: 2 < 3.1; 3.1 <= 1 + True + False + sage: 2/3 < 3/2; 3/2 < 3/1 + True + True + +比較演算は,ほとんどいかなる組合せの二つのオブジェクトに対しても行ないうると考えてよい. +対象となるオブジェクトは,全順序付け(total ordering)されなくても構わない. + + +:: + + sage: 2 < CC(3.1,1) + True + sage: 5 < VectorSpace(QQ,3) # 出力は一定しない。 + True + +記号を含む不等号の判定には ``bool`` 関数を用いる: + +:: + + sage: x < x + 1 + x < x + 1 + sage: bool(x < x + 1) + True + + +Sageにおける異種オブジェクト間の比較演算では,まず対象オブジェクトの共通ペアレント型への正準型強制(変換)が試みられる(「型強制」(coercion)の詳細については :ref:`section-coercion` 節を参照). +比較演算は,この型強制が成功後,変換されたオブジェクトに対して実行される. +変換が不可能であれば,その二つのオブジェクトは等しくないと判定されることになる. +二つの変数が同一のオブジェクトを参照(レファレンス)しているかどうかを調べるには、 ``is`` を使う. +例えばPythonのint型 ``1`` は唯一だが,SageのInteger型 ``1`` は違う: + +:: + + sage: 1 is 2/2 + False + sage: int(1) is int(2)/int(2) + True + sage: 1 is 1 + False + sage: 1 == 2/2 + True + +以下に示す例の,前半の二つの不等式は ``False`` になる. +これは正準写像 :math:`\QQ\to \GF{5}` が存在せず, :math:`\GF{5}` 上の :math:`1` を :math:`1 \in \QQ` と比較する基準がないためである. +一方、後半の不等式は関係する正準写像 :math:`\ZZ \to \GF{5}` が存在するため ``True`` と判定される. +比較する式の左辺右辺を入れ替えても結果は変わらない. + + +:: + + sage: GF(5)(1) == QQ(1); QQ(1) == GF(5)(1) + False + False + sage: GF(5)(1) == ZZ(1); ZZ(1) == GF(5)(1) + True + True + sage: ZZ(1) == QQ(1) + True + +*警告:* Sageにおける比較演算は, :math:`1 \in \GF{5}` は :math:`1 \in \QQ` と等しいとみなすMagmaよりも制限がきつい. + +:: + + sage: magma('GF(5)!1 eq Rationals()!1') # オプションでmagmaが必要 + true + + +プロファイリング +================ + +著者: Martin Albrecht (malb@informatik.uni-bremen.de) + + 「早計な最適化は,あらゆる災厄の源である」 -- ドナルド・クヌース + + +コードのボトルネック,つまり処理時間の大半を費している部分を洗い出さなければならない場面がある. +ボトルネックが判らなければどこを最適化すべきかの判定もできないからだ. +コードのボトルネックを特定する作業のことをプロファイリングと呼ぶが,Python/Sageにはプロファイリングの手段が何通りも用意されている. + + +一番簡単な方法は、対話型シェルで ``prun`` コマンドを実行することだ. +``prun`` は,使われた関数と各関数の処理時間の一覧を表示してくれる. +例として,有限体上の行列積演算(バージョン1.0で、まだ低速だ)をプロファイルしてみよう.その手順は: + + +:: + + sage: k,a = GF(2**8, 'a').objgen() + sage: A = Matrix(k,10,10,[k.random_element() for _ in range(10*10)]) + +.. skip + + +:: + + sage: %prun B = A*A + 32893 function calls in 1.100 CPU seconds + + Ordered by: internal time + + ncalls tottime percall cumtime percall filename:lineno(function) + 12127 0.160 0.000 0.160 0.000 :0(isinstance) + 2000 0.150 0.000 0.280 0.000 matrix.py:2235(__getitem__) + 1000 0.120 0.000 0.370 0.000 finite_field_element.py:392(__mul__) + 1903 0.120 0.000 0.200 0.000 finite_field_element.py:47(__init__) + 1900 0.090 0.000 0.220 0.000 finite_field_element.py:376(__compat) + 900 0.080 0.000 0.260 0.000 finite_field_element.py:380(__add__) + 1 0.070 0.070 1.100 1.100 matrix.py:864(__mul__) + 2105 0.070 0.000 0.070 0.000 matrix.py:282(ncols) + ... + +ここで ``ncalls`` は関数の呼出し回数, ``tottime`` はその関数が費した総時間(配下の関数群の呼出しにかかった時間は除く), ``percall`` は ``tottime`` を ``ncalls`` で割って得られる平均総消費時間, ``cumtime`` は関数本体とそれが呼出している配下の全関数双方の処理にかかった(つまり注目している関数の呼出しから開放までの)全時間, ``percall`` は ``cumtime`` を呼出し回数で割って得られる関数の平均処理時間で, ``filename:lineno(function)`` は各関数の所在情報を示している. +結局のところ, ``prun`` の表示一覧の上位にある関数ほど処理に要する負荷も大きいことが判る. +これで,どこを最適化すべきか考えやすくなるはずだ. + + +これまでと同じように, ``prun?`` と入力するとプロファイラの使い方と表示情報の解釈について詳細を見ることができる. + + +プロファイル情報をオブジェクトとして保存しておいて,後で詳しく調べてもよい: + + +.. skip + +:: + + sage: %prun -r A*A + sage: stats = _ + sage: stats? + +*注意*: ``stats = prun -r A\*A`` と実行すると,文法エラーが表示される. +これは ``prun`` がIPythonのシェルコマンドであって,通常の関数ではないためである. + + +プロファイル情報をグラフィカルに表示したければ,hotshotプロファイラ, ``hotshot2cachetree`` スクリプトと ``kcachegrind`` プログラム(Unix系のみ)などを使えばよい. +上の例と同じ作業をhotshotプロファイラで実行すると: + +.. skip + +:: + + sage: k,a = GF(2**8, 'a').objgen() + sage: A = Matrix(k,10,10,[k.random_element() for _ in range(10*10)]) + sage: import hotshot + sage: filename = "pythongrind.prof" + sage: prof = hotshot.Profile(filename, lineevents=1) + +.. skip + +:: + + sage: prof.run("A*A") + + sage: prof.close() + +得られた結果は,現ディレクトリのファイル ``pythongrind.prof`` に保存されている. +これをcachegrindフォーマットに変換すれば,内容をビジュアル化して把握することができる. + + +システムのコマンドシェルに戻り + +.. skip + +:: + + hotshot2calltree -o cachegrind.out.42 pythongrind.prof + +として変換を実行すると,出力ファイル ``cachegrind.out.42`` 内の情報を ``kcachegrind`` コマンドを使って検討することができる. +ファイルの慣例的名称 ``cachegrind.out.XX`` は残念ながら変更できない. + diff --git a/src/doc/ja/tutorial/sagetex.rst b/src/doc/ja/tutorial/sagetex.rst new file mode 100644 index 00000000000..7c36bd3e8b7 --- /dev/null +++ b/src/doc/ja/tutorial/sagetex.rst @@ -0,0 +1,233 @@ +.. _sec-sagetex: + +=============== + SageTeXを使う +=============== + +SageTeXパッケージを使うと,Sageによる処理結果をLaTeX文書に埋め込むことができるようになる. +利用するためには,まずSageTeXを「インストール」しておかなければならない(:ref:`sec-sagetex_install` 節を参照). + + +具体例 +======= + +ここでは,ごく簡単な例題を通してSageTeXの利用手順を紹介する. +完全な解説ドキュメントと例題ファイルは,ディレクトリ ``SAGE_ROOT/local/share/doc/sagetex`` に置いてある. +``SAGE_ROOT/local/share/texmf/tex/generic/sagetex`` にあるPythonスクリプトは何か役に立つ場面があるはずだ. +以上の ``SAGE_ROOT`` は,Sageをインストールしたディレクトリである. + + +SageTeXの動作を体験するために,まずSageTeXのインストール手続き(:ref:`sec-sagetex_install` 節)を実行し, +以下のテキストを ``st_example.tex`` などという名前で保存しておいてほしい: + + +.. warning:: + + このテキストを "live"ヘルプから表示すると命令未定義エラーになる. + 正常に表示するためには "static"ヘルプで表示すること. + + +.. code-block:: latex + + \documentclass{article} + \usepackage{sagetex} + + \begin{document} + + Using Sage\TeX, one can use Sage to compute things and put them into + your \LaTeX{} document. For example, there are + $\sage{number_of_partitions(1269)}$ integer partitions of $1269$. + You don't need to compute the number yourself, or even cut and paste + it from somewhere. + + Here's some Sage code: + + \begin{sageblock} + f(x) = exp(x) * sin(2*x) + \end{sageblock} + + The second derivative of $f$ is + + \[ + \frac{\mathrm{d}^{2}}{\mathrm{d}x^{2}} \sage{f(x)} = + \sage{diff(f, x, 2)(x)}. + \] + + Here's a plot of $f$ from $-1$ to $1$: + + \sageplot{plot(f, -1, 1)} + + \end{document} + +この ``st_example.tex`` をいつも通りにLaTexで処理する. +するとLaTeXは以下のような文句をつけてくるだろう: + + +:: + + Package sagetex Warning: Graphics file + sage-plots-for-st_example.tex/plot-0.eps on page 1 does not exist. Plot + command is on input line 25. + + Package sagetex Warning: There were undefined Sage formulas and/or + plots. Run Sage on st_example.sagetex.sage, and then run LaTeX on + st_example.tex again. + +注目してほしいのは,LaTeXが通常の処理で生成するファイル群に加えて, ``st_example.sage`` というファイルが出来ていることだ. +これは ``st_example.tex`` の処理畤に生成されたSageスクリプトで,上で見たLaTeX処理時のメッセージは,この ``st_example.sage`` をSageで実行せよという内容である. +その通り実行すると ``st_example.tex`` を再びLaTeXで処理せよと告げられるが,その前に新しいファイル ``st_example.sout`` が生成されていることに注意. +このファイルにはSageの演算結果がLaTeXテキストに挿入して利用可能な形式で保存されている. +プロット画像のEPSファイルを含むディレクトリも新規作成されている. +ここでLaTeX処理を実行すると,Sageの演算結果とプロットの全てがLaTeX文書に収められることになる. + + +上の処理に用いられた各マクロの内容はごく簡単に理解できる. +``sageblock`` 環境はSageコードを入力通りに組版し,ユーザーがSageを動かすとそのコードを実行する. +``\sage{foo}`` とすると, Sage上で ``latex(foo)`` を実行したのと同じ結果がLaTeX文書に挿入される. +プロット命令はやや複雑だが,もっとも単純な場合である ``\sageplot{foo}`` は ``foo.save('filename.eps')`` を実行して得られた画像を文書へ挿入する役割を果たす. + + +要するに,必要な作業は以下の三段階になる: + +- LaTeXで .texファイルを処理 +- 生成された .sageファイルをSageで実行 +- LaTeXで .texファイルを再処理 + + +作業中にLaTeX文書内のSageコマンドを変更しない場合,Sageによる処理は省略することができる. + + +SageTeXは到底以上で語り尽せるものでなく,SageとLaTeXは共に複雑で強力なツールだ. +``SAGE_ROOT/local/share/doc/sagetex`` にあるSageTeXのドキュメントを読むことを強くお勧めする. + + +.. _sec-sagetex_install: + + +TeXにSageTeXの存在を教える +=========================== + +Sageはおおむね自己完結的なシステムなのだが,正しく機能するために外部ツールの介入を要する部分があることも確かだ. +SageTeXもそうした部分の一つである. + + +SageTeXパッケージを使えばSageによる演算やプロットをLaTeX文書に埋め込むことが可能になる. +SageTeXはデフォルトでSageにインストールされるが,LaTeX文書で利用する前に,運用しているTeXシステムへSageTeXの存在を教えておかねばならない. + + + +鍵になるのは, TeXが ``sagetex.sty`` を発見できるかどうかである. +この ``sagetex.sty`` は, ``SAGE_ROOT`` をSageがビルトあるいはインストールされたディレクトリとすると, +``SAGE_ROOT/local/share/texmf/tex/generic/sagetex/`` に置かれているはずだ. +TeXが ``sagetex.sty`` を読めるようにしてやらなければ,SageTeXも動作できないのである. +これを実現するには何通りかのやり方がある. + + +- 第一の,かつ一番簡単な方法は, ``sagetex.sty`` を作成すべきLaTeX文書と同じディレクトリ内にコピーしておくことである. + TeXは組版処理の際に現ディレクトリを必ずサーチするから,この方法は常に有効だ. + + ただし,このやり方には二つのちょっとした問題点がある. + 一つ目は,このやり方では使用しているシステムが重複した ``sagetex.sty`` だらけになってしまうこと. + 二つ目の,もっと厄介な問題は,この状態でSageが更新されてSageTeXも新しいバージョンになった場合,SageTeXを構成するPythonコードやLaTeXコードとの食い違いが生じて実行時にエラーが発生しかねない点である. + + + +- 第二の方法は,環境変数 ``TEXINPUTS`` を利用することである. + bashシェルを使っているなら + + :: + + export TEXINPUTS="SAGE_ROOT/local/share/texmf//:" + + と実行すればよい.ただし ``SAGE_ROOT`` はSageのインストール先ディレクトリである. + 上の実行例では,行末にスラッシュ2個とコロンを付け忘れないでいただきたい. + 実行後は,TeXと関連ツールがSageTeXスタイルファイルを見つけられるようになる. + 上のコマンド行を ``.bashrc`` に付加して保存しておけば設定を永続させることができる. + bash以外のシェルを使っている場合, ``TEXINPUTS`` 変数を設定するためのコマンドも異なる可能性がある. + 設定法については,自分の使っているシェルのドキュメントを参照のこと. + + この方法にも瑕はある. + ユーザがTeXShopやKile,あるいはEmacs/AucTeXなどを使っている場合,必ずしも環境変数を認識してくれるとは限らないのである. + これらのアプリケーションが常にシェル環境を通してLaTeXを起動するわけではないからだ. + + インストール済みのSageを移動したり,新バージョンを旧版とは違う場所にインストールした場合, + 先に紹介したコマンドも新しい ``SAGE_ROOT`` を反映させるように変更する必要がある. + + + +- TeXに ``sagetex.sty`` の在処を教える第三の(かつ最善の)方法は,このスタイルファイルを自分のホームディレクトリのどこか都合のよい所にコピーしておくことだ. + TeXディストリビューションの多くは,パッケージを求めてホームディレクトリにある ``texmf`` ディレクトリを自動的に探索するようになっている. + このディレクトリを正確に特定するには,コマンド + + :: + + kpsewhich -var-value=TEXMFHOME + + を実行する.すると ``/home/drake/texmf`` や ``/Users/drake/Library/texmf`` などと表示されるはずだから, ``SAGE_ROOT/local/share/texmf/`` 内の ``tex/`` ディレクトリをホームディレクトリの ``texmf`` にコピーするには + + :: + + cp -R SAGE_ROOT/local/share/texmf/tex TEXMFHOME + + などとする. + もちろん, ``SAGE_ROOT`` を実際にSageをインストールしたディレクトリとするのはこれまでと同じことで, ``TEXMFHOME`` は上で見た ``kpsewhich`` コマンドの結果で置き換える. + + SageをアップグレードしたらSageTeXがうまく動かなくなったという場合は,上記の手順をもう一度繰り返すだけでSageTeXのSageとTeX関連部分が同期する. + + +.. _sagetex_installation_multiuser: + +- 複数ユーザに対応するシステムでは,以上の手続きを変更して ``sagetex.sty`` を公開運用中のTeXディレクトリにコピーすればよい. + おそらく一番賢いコピー先は ``TEXMFHOME`` ディレクトリではなく,コマンド + + :: + + kpsewhich -var-value=TEXMFLOCAL + + + の実行結果に従うことだろう.出力は ``/usr/local/share/texmf`` のようになるはずで, 上と同じように ``tex`` ディレクトリを ``TEXMFLOCAL`` ディレクトリ内にコピーする. + ついでTeXのパッケージデータベースを更新しなければならないが,これは簡単で,ルート権限で + + :: + + texhash TEXMFLOCAL + + + と実行すればよい.ただし ``TEXMFLOCAL`` を現実に合わせて変更するのは先と同じだ. + これでシステムの全ユーザはSageTeXパッケージへアクセス可能になり,Sageが利用できればSageTeXも使えるようになる. + +.. warning:: + + 肝心なのは,LaTeXが組版処理時に使う ``sagetex.sty`` ファイルと,Sageが援用するSageTeXのバージョンが一致していることである. + Sageを更新したら,あちこちに散らばった古いバージョンの ``sagetex.sty`` を面倒でも全て削除してやらなければいけない. + + SageTeX関連ファイルをホームディレクトリの ``texmf`` ディレクトリ内にコピーしてしまうこと(先に紹介した第三の方法)をお勧めするのは,この面倒があるからである. + 第三の方法にしておけば,Sage更新後もSageTeXを正常に動作させるために必要な作業はディレクトリを一つコピーするだけになる. + + + +SageTeXドキュメント +--------------------- + +厳密にはSageのインストール一式には含まれないものの,ここで +SageTeXのドキュメントが ``SAGE_ROOT/local/share/doc/sagetex/sagetex.pdf`` に配置されていることに触れておきたい. +同じディレクトリには例題ファイルと,これをLaTeXとSageTeXによってすでに組版処理した結果も用意されている(``example.tex`` と ``example.pdf`` を参照). +これらのファイルは `SageTeX bitbucket ページ `_ からダンロードすることもできる. + + + +SageTeXとTeXLive +------------------- + +混乱を招きかねない問題点の一つとして,人気あるTeXディストリビューション +`TeXLive 2009 `_ にSageTeXが含まれている現実があげられる. +これは有り難い感じがするかもしれないが,SageTeXに関して重要なのはSageとLaTeXの各要素が同期していることだ. +SageとSageTeXは共に頻繁にアップデートされるがTeXLiveはそうではないから,その「同期」のところで問題が生じる. +この文の執筆時点(2013年3月)では,多くのLinuxディストリビューションが新しいTeXLiveリリースに移行しつつある. +しかし2009リリースもしぶとく生き残っていて,実はこれがSageTeXに関するバグレポートの主要な発生源になっているのだ. + +このため *強く推奨* させていただきたいのは,SageTeXのLaTeX関連部分は以上で説明したやり方で常にSageからインストールすることである. +上記の手順に従えば,SageTeXのSageおよびLaTeX対応部分の互換性が保証されるから,動作も正常に保たれる. +SageTeXのLaTeX対応部分をTeXLiveから援用することはサポート対象外になる. + + diff --git a/src/doc/ja/tutorial/tour.rst b/src/doc/ja/tutorial/tour.rst new file mode 100755 index 00000000000..2516c94af03 --- /dev/null +++ b/src/doc/ja/tutorial/tour.rst @@ -0,0 +1,24 @@ +**************** +Sage観光ツアー +**************** + +この節では,Sageを使えばどんなことできるのか,その一端をご覧にいれる. +「…を作るにはどうやるの?」という質問全般に答える "Sage Constructions"ドキュメントには,さらに豊富な実例が用意されている. +加えて "Sage Reference Manual"では,数千の具体例が見つかるはずだ.Sageノートブックの ``Help`` リンクをクリックすれば、このツアーの内容を対話的に確認することもできる. + +(このチュートリアルをSageノートブックから閲覧している場合,入力セルの内容を実行するには ``shift-enter`` と押せばよい. ``shift-enter`` を押して実行する前に入力セルの中身を変更することもで きる.Macマシンでは, ``shift-enter`` ではなく ``shift-return`` を押すことになるかもしれない.) + +.. toctree:: + + tour_assignment + tour_help + tour_algebra + tour_plotting + tour_functions + tour_rings + tour_linalg + tour_polynomial + tour_coercion + tour_groups + tour_numtheory + tour_advanced diff --git a/src/doc/ja/tutorial/tour_advanced.rst b/src/doc/ja/tutorial/tour_advanced.rst new file mode 100755 index 00000000000..52f7d16c91c --- /dev/null +++ b/src/doc/ja/tutorial/tour_advanced.rst @@ -0,0 +1,527 @@ + +より進んだ数学 +============================== + + +代数幾何 +------------------ + +Sageでは,任意の代数多様体を定義することができるが,その非自明な機能は :math:`\QQ` 上の環あるいは有限体でしか使えない場合がある. +例として,2本のアフィン平面曲線の和を取り,ついで元の曲線を和の既約成分として分離してみよう. + + +:: + + sage: x, y = AffineSpace(2, QQ, 'xy').gens() + sage: C2 = Curve(x^2 + y^2 - 1) + sage: C3 = Curve(x^3 + y^3 - 1) + sage: D = C2 + C3 + sage: D + Affine Curve over Rational Field defined by + x^5 + x^3*y^2 + x^2*y^3 + y^5 - x^3 - y^3 - x^2 - y^2 + 1 + sage: D.irreducible_components() + [ + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^2 + y^2 - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^3 + y^3 - 1 + ] + +以上の2本の曲線の交わりを取れば,全ての交点を求めてその既約成分を計算することもできる. + + +.. link + +:: + + sage: V = C2.intersection(C3) + sage: V.irreducible_components() + [ + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y - 1, + x, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y, + x - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x + y + 2, + 2*y^2 + 4*y + 3 + ] + +というわけで,点 :math:`(1,0)` および :math:`(0,1)` が双方の曲線上にあるのはすぐ見てとることができるし, +:math:`y` 成分が :math:`2y^2 + 4y + 3=0` を満足する(2次の)点についても同じことだ. + + +Sageでは,3次元射影空間における捻れ3次曲線のトーリック・イデアルを計算することができる: + + +:: + + sage: R. = PolynomialRing(QQ, 4) + sage: I = ideal(b^2-a*c, c^2-b*d, a*d-b*c) + sage: F = I.groebner_fan(); F + Groebner fan of the ideal: + Ideal (b^2 - a*c, c^2 - b*d, -b*c + a*d) of Multivariate Polynomial Ring + in a, b, c, d over Rational Field + sage: F.reduced_groebner_bases () + [[-c^2 + b*d, -b*c + a*d, -b^2 + a*c], + [-c^2 + b*d, b^2 - a*c, -b*c + a*d], + [-c^2 + b*d, b*c - a*d, b^2 - a*c, -c^3 + a*d^2], + [c^3 - a*d^2, -c^2 + b*d, b*c - a*d, b^2 - a*c], + [c^2 - b*d, -b*c + a*d, -b^2 + a*c], + [c^2 - b*d, b*c - a*d, -b^2 + a*c, -b^3 + a^2*d], + [c^2 - b*d, b*c - a*d, b^3 - a^2*d, -b^2 + a*c], + [c^2 - b*d, b*c - a*d, b^2 - a*c]] + sage: F.polyhedralfan() + Polyhedral fan in 4 dimensions of dimension 4 + + + +楕円曲線 +--------------- + +Sageの楕円曲線部門にはPARIの楕円曲線機能の大部分が取り込まれており,Cremonaの管理するオンラインデータベースに接続することもできる(これにはデータベースパッケージを追加する必要がある). +さらに、Second-descentによって楕円曲線の完全Mordell-Weil群を計算するmwrankの機能が使えるし,SEAアルゴリズムの実行や同種写像全ての計算なども可能だ. +:math:`\QQ` 上の曲線群を扱うためのコードは大幅に更新され,Denis Simonによる代数的降下法ソフトウェアも取り込まれている. + + +楕円曲線を生成するコマンド ``EllipticCurve`` には,さまざまな書法がある: + + +- EllipticCurve([:math:`a_1`, :math:`a_2`, :math:`a_3`, :math:`a_4`, :math:`a_6` ]): + 楕円曲線 + + .. math:: y^2+a_1xy+a_3y=x^3+a_2x^2+a_4x+a_6, + + を生成する. + ただし :math:`a_i` は :math:`a_1` のペアレントクラスに合わせて型強制される. + 全ての :math:`a_i` がペアレント :math:`\ZZ` を持つ場合, :math:`a_i` は :math:`\QQ` に型強制される. + + + +- EllipticCurve([:math:`a_4`, :math:`a_6` ]): :math:`a_1=a_2=a_3=0` となる以外は上と同じ. + + +- EllipticCurve(ラベル): Cremonaの(新しい)分類ラベルを指定して,Cremonaデータベースに登録された楕円曲線を生成する. + ラベルは ``"11a"`` や ``"37b2"`` といった文字列で,(以前のラベルと混同しないように)小文字でなければならない. + + +- EllipticCurve(j): :math:`j` -不変量 :math:`j` を持つ楕円曲線を生成する. + + +- EllipticCurve(R,[:math:`a_1`, :math:`a_2`, :math:`a_3`, :math:`a_4`, :math:`a_6` ]): + 最初と同じように :math:`a_i` を指定して環 :math:`R` 上の楕円曲線を生成する. + + +以上の各コンストラクタを実際に動かしてみよう: + + +:: + + sage: EllipticCurve([0,0,1,-1,0]) + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + + sage: EllipticCurve([GF(5)(0),0,1,-1,0]) + Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 + + sage: EllipticCurve([1,2]) + Elliptic Curve defined by y^2 = x^3 + x + 2 over Rational Field + + sage: EllipticCurve('37a') + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + + sage: EllipticCurve_from_j(1) + Elliptic Curve defined by y^2 + x*y = x^3 + 36*x + 3455 over Rational Field + + sage: EllipticCurve(GF(5), [0,0,1,-1,0]) + Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 + +点 :math:`(0,0)` は、 :math:`y^2 + y = x^3 - x` で定義される楕円曲線 :math:`E` 上にある. +Sageを使ってこの点を生成するには, ``E([0,0])`` と入力する. +Sageは,そうした楕円曲線上に点を付け加えていくことができる(楕円曲線は,無限遠点が零元、同一曲線上の3点を加えると0となる加法群としての構造を備えている): + +:: + + sage: E = EllipticCurve([0,0,1,-1,0]) + sage: E + Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field + sage: P = E([0,0]) + sage: P + P + (1 : 0 : 1) + sage: 10*P + (161/16 : -2065/64 : 1) + sage: 20*P + (683916417/264517696 : -18784454671297/4302115807744 : 1) + sage: E.conductor() + 37 + +複素数体上の楕円曲線は, :math:`j` -不変量によって記述される. +Sageでは, :math:`j` -不変量を以下のようにして計算する: + +:: + + sage: E = EllipticCurve([0,0,0,-4,2]); E + Elliptic Curve defined by y^2 = x^3 - 4*x + 2 over Rational Field + sage: E.conductor() + 2368 + sage: E.j_invariant() + 110592/37 + +:math:`E` と同じ :math:`j` -不変量を指定して楕円曲線を作っても,それが :math:`E` と同型になるとは限らない. +次の例でも,2つの曲線は導手(conductor)が異なるため同型にならない. + + +:: + + sage: F = EllipticCurve_from_j(110592/37) + sage: F.conductor() + 37 + +しかし, :math:`F` を2で捻ったツイスト(twist)は同型の曲線になる. + + +.. link + +:: + + sage: G = F.quadratic_twist(2); G + Elliptic Curve defined by y^2 = x^3 - 4*x + 2 over Rational Field + sage: G.conductor() + 2368 + sage: G.j_invariant() + 110592/37 + +楕円曲線に随伴する :math:`L` -級数,あるいはモジュラー形式 :math:`\sum_{n=0}^\infty a_nq^n` の係数 :math:`a_n` を求めることもできる. +計算にはPARIのC-ライブラリを援用している: + +:: + + sage: E = EllipticCurve([0,0,1,-1,0]) + sage: print E.anlist(30) + [0, 1, -2, -3, 2, -2, 6, -1, 0, 6, 4, -5, -6, -2, 2, 6, -4, 0, -12, 0, -4, + 3, 10, 2, 0, -1, 4, -9, -2, 6, -12] + sage: v = E.anlist(10000) + +:math:`a_n` を :math:`n\leq 10^5` の全てについて計算しても1秒ほどしかかからない: + + +.. skip + +:: + + sage: %time v = E.anlist(100000) + CPU times: user 0.98 s, sys: 0.06 s, total: 1.04 s + Wall time: 1.06 + + +楕円曲線を,対応するCremonaの分類ラベルを指定して生成する方法もある. +そうすると,目的の楕円曲線がその階数,玉河数,単数基準(regulator)などの情報と共にプレロードされる: + + +:: + + sage: E = EllipticCurve("37b2") + sage: E + Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational + Field + sage: E = EllipticCurve("389a") + sage: E + Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field + sage: E.rank() + 2 + sage: E = EllipticCurve("5077a") + sage: E.rank() + 3 + +Cremonaのデータベースへ直接にアクセスすることも可能だ. + + +:: + + sage: db = sage.databases.cremona.CremonaDatabase() + sage: db.curves(37) + {'a1': [[0, 0, 1, -1, 0], 1, 1], 'b1': [[0, 1, 1, -23, -50], 0, 3]} + sage: db.allcurves(37) + {'a1': [[0, 0, 1, -1, 0], 1, 1], + 'b1': [[0, 1, 1, -23, -50], 0, 3], + 'b2': [[0, 1, 1, -1873, -31833], 0, 1], + 'b3': [[0, 1, 1, -3, 1], 0, 3]} + + +この方法でデータベースから引き出されるデータは,むろん ``EllipticCurve`` 型のオブジェクトにはならない. +複数のフィールドから構成されたデータベースのレコードであるにすぎない. +デフォルトでSageに付属しているのは,導手が :math:`\leq 10000` の楕円曲線の情報要約からなる,Cremonaのデータベースの小型版である. +オプションで大型版のデータベースも用意されていて,こちらは導手が :math:`120000` までの全ての楕円曲線群の詳細情報を含む(2005年10月時点). +さらに、Sage用の大規模版データベースパッケージ(2GB)では,Stein-Watkinsデータベース上の数千万種の楕円曲線を利用することができる. + + + +ディリクレ指標 +-------------------- + +ディリクレ指標とは, +環 :math:`R` に対する準同型写像 :math:`(\ZZ/N\ZZ)^* \to R^*` を, :math:`\gcd(N,x)>1` なる整数 :math:`x` を0と置くことによって写像 +:math:`\ZZ \to R` へ拡張したものである. + + +:: + + sage: G = DirichletGroup(12) + sage: G.list() + [Dirichlet character modulo 12 of conductor 1 mapping 7 |--> 1, 5 |--> 1, + Dirichlet character modulo 12 of conductor 4 mapping 7 |--> -1, 5 |--> 1, + Dirichlet character modulo 12 of conductor 3 mapping 7 |--> 1, 5 |--> -1, + Dirichlet character modulo 12 of conductor 12 mapping 7 |--> -1, 5 |--> -1] + sage: G.gens() + (Dirichlet character modulo 12 of conductor 4 mapping 7 |--> -1, 5 |--> 1, + Dirichlet character modulo 12 of conductor 3 mapping 7 |--> 1, 5 |--> -1) + sage: len(G) + 4 + +ディリクレ群を作成したので、次にその元を一つ取って演算に使ってみよう. + +.. link + +:: + + sage: G = DirichletGroup(21) + sage: chi = G.1; chi + Dirichlet character modulo 21 of conductor 7 mapping 8 |--> 1, 10 |--> zeta6 + sage: chi.values() + [0, 1, zeta6 - 1, 0, -zeta6, -zeta6 + 1, 0, 0, 1, 0, zeta6, -zeta6, 0, -1, + 0, 0, zeta6 - 1, zeta6, 0, -zeta6 + 1, -1] + sage: chi.conductor() + 7 + sage: chi.modulus() + 21 + sage: chi.order() + 6 + sage: chi(19) + -zeta6 + 1 + sage: chi(40) + -zeta6 + 1 + +この指標に対してガロワ群 :math:`\text{Gal}(\QQ(\zeta_N)/\QQ)` がどう振る舞うか計算したり,法(modulus)の因数分解に相当する直積分解を実行することも可能だ. + +.. link + +:: + + sage: chi.galois_orbit() + [Dirichlet character modulo 21 of conductor 7 mapping 8 |--> 1, 10 |--> zeta6, + Dirichlet character modulo 21 of conductor 7 mapping 8 |--> 1, 10 |--> -zeta6 + 1] + + sage: go = G.galois_orbits() + sage: [len(orbit) for orbit in go] + [1, 2, 2, 1, 1, 2, 2, 1] + + sage: G.decomposition() + [ + Group of Dirichlet characters of modulus 3 over Cyclotomic Field of order + 6 and degree 2, + Group of Dirichlet characters of modulus 7 over Cyclotomic Field of order + 6 and degree 2 + ] + +次に,mod 20,ただし値が :math:`\QQ(i)` 上に収まるディリクレ指標の群を作成する: + +:: + + sage: K. = NumberField(x^2+1) + sage: G = DirichletGroup(20,K) + sage: G + Group of Dirichlet characters of modulus 20 over Number Field in i with defining polynomial x^2 + 1 + + +ついで, ``G`` の不変量をいくつか計算してみよう: + +.. link + +:: + + 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) + + sage: G.unit_gens() + (11, 17) + sage: G.zeta() + -i + sage: G.zeta_order() + 4 + +以下の例では、数体上でディリクレ指標を生成する.1の累乗根については、 ``DirichletGroup`` の3番目の引数として明示的に指定している. + +:: + + sage: x = polygen(QQ, 'x') + sage: K = NumberField(x^4 + 1, 'a'); a = K.0 + sage: b = K.gen(); a == b + True + sage: K + Number Field in a with defining polynomial x^4 + 1 + sage: G = DirichletGroup(5, K, a); G + Group of Dirichlet characters of modulus 5 over Number Field in a with + defining polynomial x^4 + 1 + sage: chi = G.0; chi + Dirichlet character modulo 5 of conductor 5 mapping 2 |--> a^2 + sage: [(chi^i)(2) for i in range(4)] + [1, a^2, -1, -a^2] + + +ここで ``NumberField(x^4 + 1, 'a')`` と指定したのは,Sageに記号 `a` を使って ``K`` の内容(`a` で生成される数体上の多項式 :math:`x^4 + 1`)を表示させるためである. +その時点で記号名 `a` はいったん未定義になるが、 ``a = K.0`` (``a = K.gen()`` としても同じ)が実行されると記号 `a` は多項式 :math:`x^4+1` の根を表すようになる. + + + + +モジュラー形式 +----------------- + +Sageを使ってモジュラー空間の次元,モジュラー・シンポルの空間,Hecke演算子、素因数分解などを含むモジュラー形式に関連した計算を実行することができる. + +モジュラー形式が張る空間の次元を求める関数が数種類用意されている. +例えば + + +:: + + sage: dimension_cusp_forms(Gamma0(11),2) + 1 + sage: dimension_cusp_forms(Gamma0(1),12) + 1 + sage: dimension_cusp_forms(Gamma1(389),2) + 6112 + +次に、レベル :math:`1` ,ウェイト :math:`12` のモジュラー・シンボル空間上でHecke演算子を計算してみよう. + + +:: + + sage: M = ModularSymbols(1,12) + sage: M.basis() + ([X^8*Y^2,(0,0)], [X^9*Y,(0,0)], [X^10,(0,0)]) + sage: t2 = M.T(2) + sage: t2 + Hecke operator T_2 on Modular Symbols space of dimension 3 for Gamma_0(1) + of weight 12 with sign 0 over Rational Field + sage: t2.matrix() + [ -24 0 0] + [ 0 -24 0] + [4860 0 2049] + sage: f = t2.charpoly('x'); f + x^3 - 2001*x^2 - 97776*x - 1180224 + sage: factor(f) + (x - 2049) * (x + 24)^2 + sage: M.T(11).charpoly('x').factor() + (x - 285311670612) * (x - 534612)^2 + +:math:`\Gamma_0(N)` と :math:`\Gamma_1(N)` の空間を生成することもできる. + + +:: + + sage: ModularSymbols(11,2) + Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign + 0 over Rational Field + sage: ModularSymbols(Gamma1(11),2) + Modular Symbols space of dimension 11 for Gamma_1(11) of weight 2 with + sign 0 and over Rational Field + +特性多項式と :math:`q` -展開を計算してみよう. + + +:: + + sage: M = ModularSymbols(Gamma1(11),2) + sage: M.T(2).charpoly('x') + x^11 - 8*x^10 + 20*x^9 + 10*x^8 - 145*x^7 + 229*x^6 + 58*x^5 - 360*x^4 + + 70*x^3 - 515*x^2 + 1804*x - 1452 + sage: M.T(2).charpoly('x').factor() + (x - 3) * (x + 2)^2 * (x^4 - 7*x^3 + 19*x^2 - 23*x + 11) + * (x^4 - 2*x^3 + 4*x^2 + 2*x + 11) + sage: S = M.cuspidal_submodule() + sage: S.T(2).matrix() + [-2 0] + [ 0 -2] + sage: S.q_expansion_basis(10) + [ + q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10) + ] + +モジュラー・シンボルの空間を,指標を指定して生成することも可能だ. + +:: + + sage: G = DirichletGroup(13) + sage: e = G.0^2 + sage: M = ModularSymbols(e,2); M + Modular Symbols space of dimension 4 and level 13, weight 2, character + [zeta6], sign 0, over Cyclotomic Field of order 6 and degree 2 + sage: M.T(2).charpoly('x').factor() + (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)^2 + sage: S = M.cuspidal_submodule(); S + Modular Symbols subspace of dimension 2 of Modular Symbols space of + dimension 4 and level 13, weight 2, character [zeta6], sign 0, over + Cyclotomic Field of order 6 and degree 2 + sage: S.T(2).charpoly('x').factor() + (x + zeta6 + 1)^2 + sage: S.q_expansion_basis(10) + [ + q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10) + ] + +以下の例では,モジュラー形式によって張られる空間に対するHecke演算子の作用を,Sageでどうやって計算するかを示す. + + +:: + + sage: T = ModularForms(Gamma0(11),2) + sage: T + Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of + weight 2 over Rational Field + sage: T.degree() + 2 + sage: T.level() + 11 + sage: T.group() + Congruence Subgroup Gamma0(11) + sage: T.dimension() + 2 + sage: T.cuspidal_subspace() + Cuspidal subspace of dimension 1 of Modular Forms space of dimension 2 for + Congruence Subgroup Gamma0(11) of weight 2 over Rational Field + sage: T.eisenstein_subspace() + Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2 + for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field + sage: M = ModularSymbols(11); M + Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign + 0 over Rational Field + sage: M.weight() + 2 + sage: M.basis() + ((1,0), (1,8), (1,9)) + sage: M.sign() + 0 + +:math:`T_p` は通常のHecke演算子( :math:`p` は素数)を表す. +Hecke演算子 :math:`T_2` , :math:`T_3` , :math:`T_5` はモジュラー・シンボル空間にどんな作用を及ぼすのだろうか? + + +.. link + +:: + + sage: M.T(2).matrix() + [ 3 0 -1] + [ 0 -2 0] + [ 0 0 -2] + sage: M.T(3).matrix() + [ 4 0 -1] + [ 0 -1 0] + [ 0 0 -1] + sage: M.T(5).matrix() + [ 6 0 -1] + [ 0 1 0] + [ 0 0 1] diff --git a/src/doc/ja/tutorial/tour_algebra.rst b/src/doc/ja/tutorial/tour_algebra.rst new file mode 100755 index 00000000000..7d02513277d --- /dev/null +++ b/src/doc/ja/tutorial/tour_algebra.rst @@ -0,0 +1,409 @@ + +代数と微積分の基本 +========================== + +Sageでは,初等的な代数と微積分に関連した多様な演算を実行することができる. +例として,方程式の解を求める,微分や積分を計算する,ラプラス変換の実行などがあげられる. +`Sage Constructions `_ には,さらに多様な具体例が盛られている. + + + +方程式を解く +----------------- + + +方程式を解析的に解く +~~~~~~~~~~~~~~~~~~~~~~~~~ + +``solve`` 関数を使って方程式の解を求めることができる. +これを使うには、まず変数を定義し、ついで対象とする方程式(または方程式系)と解くべき変数を ``solve`` の引数として指定する: + + +:: + + sage: x = var('x') + sage: solve(x^2 + 3*x + 2, x) + [x == -2, x == -1] + +解くべき変数を変更して,解を他の変数で表わすこともできる: + + +:: + + sage: x, b, c = var('x b c') + sage: solve([x^2 + b*x + c == 0],x) + [x == -1/2*b - 1/2*sqrt(b^2 - 4*c), x == -1/2*b + 1/2*sqrt(b^2 - 4*c)] + + +多変数の方程式を解くことも可能だ: + +:: + + sage: x, y = var('x, y') + sage: solve([x+y==6, x-y==4], x, y) + [[x == 5, y == 1]] + + +次のJason Groutによる例題では、Sageを使って連立非線形方程式を解く.まず,この連立方程式の解を記号的に求めてみよう: + + +:: + + sage: var('x y p q') + (x, y, p, q) + sage: eq1 = p+q==9 + sage: eq2 = q*y+p*x==-6 + sage: eq3 = q*y^2+p*x^2==24 + sage: solve([eq1,eq2,eq3,p==1],p,q,x,y) + [[p == 1, q == 8, x == -4/3*sqrt(10) - 2/3, y == 1/6*sqrt(5)*sqrt(2) - 2/3], + [p == 1, q == 8, x == 4/3*sqrt(10) - 2/3, y == -1/6*sqrt(5)*sqrt(2) - 2/3]] + + + +解の数値近似を求めるには,やり方を変えて: + +.. link + +:: + + sage: solns = solve([eq1,eq2,eq3,p==1],p,q,x,y, solution_dict=True) + sage: [[s[p].n(30), s[q].n(30), s[x].n(30), s[y].n(30)] for s in solns] + [[1.0000000, 8.0000000, -4.8830369, -0.13962039], + [1.0000000, 8.0000000, 3.5497035, -1.1937129]] + + +``n`` 関数は解の数値的近似値を表示する. ``n`` の引数は数値精度を表わすビット数を指定している. + + + +方程式を数値的に解く +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +目的の方程式(または方程式系)に対し ``solve`` では厳密解を求めることができないというのは珍しいことではない. +そうした場合には ``find_root`` を使って数値解を求めることができる. +例えば,以下に示す方程式については ``solve`` は何も役に立つことを教えてくれない. + +:: + + sage: theta = var('theta') + sage: solve(cos(theta)==sin(theta), theta) + [sin(theta) == cos(theta)] + + +しかし代りに ``find_root`` を使えば, :math:`0 < \phi < \pi/2` の範囲で上の方程式の数値解を求めることができる. + + +:: + + sage: phi = var('phi') + sage: find_root(cos(phi)==sin(phi),0,pi/2) + 0.785398163397448... + + + +微分,積分,その他 +---------------------------------- + +Sageで多様な関数の微分と積分を計算することができる. +例えば :math:`\sin(u)` を :math:`u` で微分するには,以下のようにする: + +:: + + sage: u = var('u') + sage: diff(sin(u), u) + cos(u) + +:math:`\sin(x^2)` の4次微分を計算するには: + + +:: + + sage: diff(sin(x^2), x, 4) + 16*x^4*sin(x^2) - 48*x^2*cos(x^2) - 12*sin(x^2) + + +:math:`x^2+17y^2` の `x` と `y` それぞれによる偏微分を計算するには: + + +:: + + sage: x, y = var('x,y') + sage: f = x^2 + 17*y^2 + sage: f.diff(x) + 2*x + sage: f.diff(y) + 34*y + + +次は不定積分と定積分だ. :math:`\int x\sin(x^2)\, dx` と :math:`\int_0^1 \frac{x}{x^2+1}\, dx` を計算してみよう. + + +:: + + sage: integral(x*sin(x^2), x) + -1/2*cos(x^2) + sage: integral(x/(x^2+1), x, 0, 1) + 1/2*log(2) + +:math:`\frac{1}{x^2-1}` の部分分数展開を求めるには: + +:: + + sage: f = 1/((1+x)*(x-1)) + sage: f.partial_fraction(x) + -1/2/(x + 1) + 1/2/(x - 1) + + + +.. _section-systems: + +微分方程式を解く +------------------------------ + +Sageを使って常微分方程式を研究することもできる. :math:`x'+x-1=0` を解くには: +:: + + sage: t = var('t') # 変数 t を定義 + sage: x = function('x',t) # x を t の関数とする + sage: DE = diff(x, t) + x - 1 + sage: desolve(DE, [x,t]) + (_C + e^t)*e^(-t) + + +ここでSageはMaxima [Max]_ とインターフェイスしているので,その出力もこれまで見てきたSageの出力とは若干違っている. +上の結果は,上の微分方程式の一般解が :math:`x(t) = e^{-t}(e^{t}+c)` であることを示している. + +ラプラス変換を実行することができる. +:math:`t^2e^t -\sin(t)` のラプラス変換は以下のような手順を踏む: + +:: + + sage: s = var("s") + sage: t = var("t") + sage: f = t^2*exp(t) - sin(t) + sage: f.laplace(t,s) + -1/(s^2 + 1) + 2/(s - 1)^3 + + + +もう少し手間のかかる問題を考えてみよう. +左端が壁に固定された連成バネ各々の、平衡位置からの変位 + + +:: + + |------\/\/\/\/\---|mass1|----\/\/\/\/\/----|mass2| + spring1 spring2 + +は、連立2階微分方程式 + + +.. math:: + + m_1 x_1'' + (k_1+k_2) x_1 - k_2 x_2 = 0 + + m_2 x_2''+ k_2 (x_2-x_1) = 0, + +でモデル化される. +ここで :math:`m_{i}` はおもり *i* の質量, :math:`x_{i}` はそのおもり *i* の平衡位置からの変位,そして :math:`k_{i}` はバネ *i* のバネ定数である. + + +**例題:** 上の問題で各パラメータの値を :math:`m_{1}=2`, :math:`m_{2}=1`, :math:`k_{1}=4`, :math:`k_{2}=2`, :math:`x_{1}(0)=3`, :math:`x_{1}'(0)=0`, :math:`x_{2}(0)=3`, :math:`x_{2}'(0)=0` と置き,Sageを使って解いてみよう. + +**解法:** まず1番目の方程式をラプラス変換する(記号は :math:`x=x_{1}`, :math:`y=x_{2}` に変える): + +:: + + sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") + sage: lde1 = de1.laplace("t","s"); lde1 + 2*(-?%at('diff(x(t),t,1),t=0)+s^2*'laplace(x(t),t,s)-x(0)*s)-2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + + +この出力は読みにくいけれども,意味しているのは + +.. math:: -2x'(0) + 2s^2 \cdot X(s) - 2sx(0) - 2Y(s) + 6X(s) = 0 + +ということだ(ここでは小文字名の関数 :math:`x(t)` のラプラス変換が大文字名の関数 :math:`X(s)` となっている). +2番目の方程式もラプラス変換してやると: + + +:: + + sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") + sage: lde2 = de2.laplace("t","s"); lde2 + -?%at('diff(y(t),t,1),t=0)+s^2*'laplace(y(t),t,s)+2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s)-y(0)*s + +意味するところは + +.. math:: -Y'(0) + s^2Y(s) + 2Y(s) - 2X(s) - sy(0) = 0. + +初期条件 :math:`x(0)`, :math:`x'(0)`, :math:`y(0)` ,および :math:`y'(0)` を代入して得られる2つの方程式を `X` と `Y` について解く: + +:: + + sage: var('s X Y') + (s, X, Y) + sage: eqns = [(2*s^2+6)*X-2*Y == 6*s, -2*X +(s^2+2)*Y == 3*s] + sage: solve(eqns, X,Y) + [[X == 3*(s^3 + 3*s)/(s^4 + 5*s^2 + 4), + Y == 3*(s^3 + 5*s)/(s^4 + 5*s^2 + 4)]] + +この解の逆ラプラス変換を行なうと: + + +:: + + sage: var('s t') + (s, t) + sage: inverse_laplace((3*s^3 + 9*s)/(s^4 + 5*s^2 + 4),s,t) + cos(2*t) + 2*cos(t) + sage: inverse_laplace((3*s^3 + 15*s)/(s^4 + 5*s^2 + 4),s,t) + -cos(2*t) + 4*cos(t) + + +というわけで,求めていた解は + +.. math:: x_1(t) = \cos(2t) + 2\cos(t), \quad x_2(t) = 4\cos(t) - \cos(2t). + +これを媒介変数プロットするには + +:: + + sage: t = var('t') + sage: P = parametric_plot((cos(2*t) + 2*cos(t), 4*cos(t) - cos(2*t) ),\ + ... (t, 0, 2*pi), rgbcolor=hue(0.9)) + sage: show(P) + +各成分ごとにプロットするには + + +:: + + sage: t = var('t') + sage: p1 = plot(cos(2*t) + 2*cos(t), (t,0, 2*pi), rgbcolor=hue(0.3)) + sage: p2 = plot(4*cos(t) - cos(2*t), (t,0, 2*pi), rgbcolor=hue(0.6)) + sage: show(p1 + p2) + + + +プロットについては :ref:`section-plot` 節の,もう少し詳しい説明を見てほしい. +微分方程式については [NagleEtAl2004]_ の5.5節にもっと詳しい解説がある. + + + +オイラーによる連立微分方程式の解法 +---------------------------------------------------- + +次の例では,1階および2階微分方程式に対するオイラーの解法を具体的に解説する. +手始めに1階微分方程式に対する解法の基本的アイデアを復習しておこう.初期値問題が + +.. math:: + + y'=f(x,y), \quad y(a)=c, + +のような形式で与えられており, :math:`b>a` を満足する :math:`x=b` における解の近似値を求めたいものとする. + +微分係数の定義から + +.. math:: y'(x) \approx \frac{y(x+h)-y(x)}{h}, + +ここで :math:`h>0` は与えるべき小さな量である. +この近似式と先の微分方程式を組み合わせると :math:`f(x,y(x))\approx \frac{y(x+h)-y(x)}{h}` が得られる. +これを :math:`y(x+h)` について解くと: + +.. math:: y(x+h) \approx y(x) + h\cdot f(x,y(x)). + + +(他にうまい呼び方も思いつかないので) :math:`h \cdot f(x,y(x))` を "補正項" と呼び, :math:`y(x)` を `y` の "更新前項(old)", :math:`y(x+h)` を `y` の "更新後項(new)"と呼ぶことにすると,上の近似式を + +.. math:: y_{new} \approx y_{old} + h\cdot f(x,y_{old}). + +と表わすことができる. + + +ここで `a` から `b` までの区間を `n` ステップに分割すると :math:`h=\frac{b-a}{n}` と書けるから,ここまでの作業から得られた情報を整理して以下の表のようにまとめることができる. + + +============== ======================= ===================== +:math:`x` :math:`y` :math:`h\cdot f(x,y)` +============== ======================= ===================== +:math:`a` :math:`c` :math:`h\cdot f(a,c)` +:math:`a+h` :math:`c+h\cdot f(a,c)` ... +:math:`a+2h` ... +... +:math:`b=a+nh` ??? ... +============== ======================= ===================== + + +我々の目標は,この表の空欄を上から一行づつ全て埋めていき,最終的に :math:`y(b)` のオイラー法による近似である???に到達することである. + +連立微分方程式に対する解法もアイデアは似ている. + +**例題:** :math:`z''+tz'+z=0`, :math:`z(0)=1`, :math:`z'(0)=0` を満足する :math:`t=1` における :math:`z(t)` を,4ステップのオイラー法を使って数値的に近似してみよう. + +ここでは問題の2階常微分方程式を( :math:`x=z`, :math:`y=z'` として)二つの1階微分方程式に分解してからオイラー法を適用することになる。 + +:: + + sage: t,x,y = PolynomialRing(RealField(10),3,"txy").gens() + sage: f = y; g = -x - y * t + sage: eulers_method_2x2(f,g, 0, 1, 0, 1/4, 1) + t x h*f(t,x,y) y h*g(t,x,y) + 0 1 0.00 0 -0.25 + 1/4 1.0 -0.062 -0.25 -0.23 + 1/2 0.94 -0.12 -0.48 -0.17 + 3/4 0.82 -0.16 -0.66 -0.081 + 1 0.65 -0.18 -0.74 0.022 + +したがって, :math:`z(1)\approx 0.65` が判る. + +点 :math:`(x,y)` をプロットすれば、その曲線としての概形を見ることができる. +それには関数 ``eulers_method_2x2_plot`` を使うが,その前に三つの成分(`t`, `x`, `y`)からなる引数を持つ関数 `f` と `g` を定義しておかなければならない. + +:: + + sage: f = lambda z: z[2] # f(t,x,y) = y + sage: g = lambda z: -sin(z[1]) # g(t,x,y) = -sin(x) + sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) + +この時点で, ``P`` は2系列のプロットを保持していることになる. +`x` と `t` のプロットである ``P[0]`` , および `y` と `t` のプロットである ``P[1]`` である. +これら二つをプロットするには、次のようにする: + +.. link + +:: + + sage: show(P[0] + P[1]) + +(プロットの詳細については :ref:`section-plot` 節を参照.) + + +特殊関数 +----------------- + +数種類の直交多項式と特殊関数が,PARI [GAP]_ およびMaxima [Max]_ を援用して実装されている. +詳細についてはSageレファレンスマニュアルの“Orthogonal polynomials"(直交多項式)と“Special functions"(特殊関数)を参照してほしい. + +:: + + sage: x = polygen(QQ, 'x') + sage: chebyshev_U(2,x) + 4*x^2 - 1 + sage: bessel_I(1,1).n(250) + 0.56515910399248502720769602760986330732889962162109200948029448947925564096 + sage: bessel_I(1,1).n() + 0.565159103992485 + sage: bessel_I(2,1.1).n() + 0.167089499251049 + + +ここで注意したいのは,Sageではこれらの関数群が専ら数値計算に便利なようにラップ(wrap)されている点だ. +記号処理をする場合には,以下の例のようにMaximaインターフェイスをじかに呼び出してほしい. + +:: + + sage: maxima.eval("f:bessel_y(v, w)") + 'bessel_y(v,w)' + sage: maxima.eval("diff(f,w)") + '(bessel_y(v-1,w)-bessel_y(v+1,w))/2' diff --git a/src/doc/ja/tutorial/tour_assignment.rst b/src/doc/ja/tutorial/tour_assignment.rst new file mode 100755 index 00000000000..a480cd12df2 --- /dev/null +++ b/src/doc/ja/tutorial/tour_assignment.rst @@ -0,0 +1,102 @@ + +代入,等式と算術演算 +==================================== + +一部に些細な例外はあるが,Sageはプログラミング言語Pythonに拠っているので,Pythonの入門書があればSageを学ぶ助けになるはずだ. + +Sageでは代入に記号 ``=`` ,比較演算には ``==`` , ``<=`` , ``>=`` , ``<`` と ``>`` を用いる. + +:: + + sage: a = 5 + sage: a + 5 + sage: 2 == 2 + True + sage: 2 == 3 + False + sage: 2 < 3 + True + sage: a == 5 + True + +基本的な演算操作は全て可能だ: +:: + + sage: 2**3 # ** は「べき乗」の意味 + 8 + sage: 2^3 # ^ は**と同じ「べき乗」の意味 (Pythonでは通用しない) + 8 + sage: 10 % 3 # 整数については % はmod, つまり余りを与える + 1 + sage: 10/4 + 5/2 + sage: 10//4 # 整数に対して // は商を返す + 2 + sage: 4 * (10 // 4) + 10 % 4 == 10 + True + sage: 3^2*4 + 2%5 + 38 + +``3^2*4 + 2%5`` のような式の値は,演算子が適用される順序に依存する. +付録にある :ref:`section-precedence` の表を見ると演算子の適用順序が判る. + +Sageでは,一般によく使われる数学関数も豊富に用意されている. +ここでは,ほんの一部しか例を示すことができないが: +:: + sage: sqrt(3.4) + 1.84390889145858 + sage: sin(5.135) + -0.912021158525540 + sage: sin(pi/3) + 1/2*sqrt(3) + +いちばん最後の例のように,数式の中には近似値ではなく「厳密」な値を返してくるものもある. +近似値が欲しいときは関数 ``n`` あるいはメソッド ``n`` を使う(両者とも同じ説明的な名称 ``numerical_approx`` を持つが,関数 ``N`` は ``n`` と同じものだ). +双方の精度ビット数を指定する引数 ``prec`` と有効十進桁数を指定する引数 ``digits`` はオプションで,精度53ビットがデフォルト値になる. +:: + + sage: exp(2) + e^2 + sage: n(exp(2)) + 7.38905609893065 + sage: sqrt(pi).numerical_approx() + 1.77245385090552 + sage: sin(10).n(digits=5) + -0.54402 + sage: N(sin(10),digits=10) + -0.5440211109 + sage: numerical_approx(pi, prec=200) + 3.1415926535897932384626433832795028841971693993751058209749 + +Pythonのデータはダイナミックに型付けされ,変数を通して参照される値にはデータの型情報が付随している. +いずれにせよ、Pythonの変数はそのスコープ内ではいかなる型の変数でも保持することができる: +:: + + sage: a = 5 # aは整数 + sage: type(a) + + sage: a = 5/3 # aは有理数になった + sage: type(a) + + sage: a = 'hello' # ここでaは文字列 + sage: type(a) + + + +プログラミング言語Cでは変数がスタティックに型付けされるから振舞いはかなり異なっていて,整数(int)型として宣言された変数は同じスコープ内では整数しか保持できない. + + +Pythonで取り違えがちな点の一つは, ``0`` で始まる整数リテラルが8進数、つまり基数8の数と見なされるところである. +:: + + sage: 011 + 9 + sage: 8 + 1 + 9 + sage: n = 011 + sage: n.str(8) # nを基数8で文字列表現 + '11' + +この点はC言語と一致している. + diff --git a/src/doc/ja/tutorial/tour_coercion.rst b/src/doc/ja/tutorial/tour_coercion.rst new file mode 100755 index 00000000000..db660c6a926 --- /dev/null +++ b/src/doc/ja/tutorial/tour_coercion.rst @@ -0,0 +1,360 @@ +.. -*- coding: utf-8 -*- + +.. _section-coercion: + +================================ +ペアレント,型変換および型強制 +================================ + +この節の内容はこれまでと比べるとテクニカルな感じがするかもしれない. +しかし,ペアレントと型強制の意味について理解しておかないと,Sageにおける環その他の代数構造を有効かつ効率的に利用することができないのである. + +以下で試みるのは概念の解説であって,それをどうやって実現するかまでは示すことはできない. +実装法に関するチュートリアルは `Sage thematic tutorial `_ にある. + + +元 +-------- + +ある環をPythonを使って実装する場合,その第一歩は目的の環の元 ``X`` を表すクラスを作り, ``__add__`` , ``__sub__`` , ``__mul__`` のようなダブルアンダースコア メソッド(フックメソッド)によって環の公理を保証する演算を実現することだ. + + +Pythonは(ダイナミックではあっても)強い型付けがなされる言語なので,最初のうちは環それぞれを一つのPythonクラスで実装すべきだろうと思うかもしれない. +なんと言っても,Pythonは整数については ```` ,実数については ```` といった具合に型を一つづつ備えているわけだし. +しかし,このやり方はすぐに行き詰まらないわけにはいかない. +環の種類が無限だからと言って,対応するクラスを無限に実装することはできないからだ. + +代りに,群,環,斜体(加除環),可換環,体,代数系などという順で,普遍的な代数構造の実装を目的とするクラスの階層を作りあげようとする人もいるかもしれない. + +しかし,これは明確に異なる環に属する元が同じ型を持ちうることを意味する. +:: + + sage: P. = GF(3)[] + sage: Q. = GF(4,'z')[] + sage: type(x)==type(a) + True + + +一方,数学的には同等の構造物に対して,(例えば密行列と疎行列に対するように)別々のPythonクラスが異なった形で実装されることもありうる. +:: + + sage: P. = PolynomialRing(ZZ) + sage: Q. = PolynomialRing(ZZ, sparse=True) + sage: R. = PolynomialRing(ZZ, implementation='NTL') + sage: type(a); type(b); type(c) + + + + + +以上から,解決すべき問題は二系統あることが分る. +ある二つの元が同じPythonクラス由来のインスタンスであるとすると,付随する ``__add__`` メソッドによる加算が可能になっているはずだ. +しかし,これら二つが数学的には非常に異なる環に属しているのならば,加算は不能にしておきたい. +一方,数学的に同一の環に属している元に対しては,異なる実装に由来していてもそれらの元の加算は可能であるべきだろう. +異なるPythonクラスに由来する限り,これは簡単に実現できることではない. + + +これらの問題に対する解は「型強制」(coercion)と呼ばれており,以降で解説する. + + +しかし,まず肝心なのは,全ての元が自分の帰属先を知っていることだ. +これを可能にするのが ``parent()`` メソッドである: + +.. link + +:: + + sage: a.parent(); b.parent(); c.parent() + Univariate Polynomial Ring in a over Integer Ring + Sparse Univariate Polynomial Ring in b over Integer Ring + Univariate Polynomial Ring in c over Integer Ring (using NTL) + + +ペアレントとカテゴリー +------------------------- + +Pythonが代数構造の元に対応するクラス階層を備えているように,Sageもそれらの元を含む代数構造に対応するクラス群を提供している. +Sageでは元が属する構造物のことを「ペアレント構造」(parent structure)と呼び,基底となるクラスを持つ. +そうしたクラス群は,おおむね数学的概念に沿った形で,集合,環,体などといった順の階層を形成している. + +:: + + sage: isinstance(QQ,Field) + True + sage: isinstance(QQ, Ring) + True + sage: isinstance(ZZ,Field) + False + sage: isinstance(ZZ, Ring) + True + +代数学では,同じ種類の代数構造を共有する物を,いわゆる「圏」(cagegory)と呼ばれるものに集約して扱う. +Sageのクラス階層と圏の階層構造にはそれなりに類似が見られないでもない. +しかし,Pythonクラスについては圏との類似はあまり強調すべきものでもなさそうだ. +いずれにせよ,数学的な意味における圏はSageでも実装されている: + + +:: + + sage: Rings() + Category of rings + sage: ZZ.category() + Category of euclidean domains + sage: ZZ.category().is_subcategory(Rings()) + True + sage: ZZ in Rings() + True + sage: ZZ in Fields() + False + sage: QQ in Fields() + True + +Sageにおけるクラス階層は具体的実装に焦点が当てられている一方,Sageの圏フレームワークではより数学的な構造が重視されている. +圏に対する個々の実装からは独立した,包括的なメソッドとテストを構成することが可能である. + + +Sageにおけるペアレント構造は,Pythonオブジェクトとして唯一のものであると仮定されている. +例えば,いったんある基底環上の多項式環が生成元と共に作成されると,その結果は実記憶上に配置される: + +:: + + sage: RR['x','y'] is RR['x','y'] + True + + + +型とペアレント +-------------------- + +``RingElement`` 型は数学的概念としての「環の元」に完璧に対応しているわけではない. +例えば,正方行列は一つの環に属していると見なしうるにもかかわらず, ``RingElement`` のインスタンスにはならない: + + +:: + + sage: M = Matrix(ZZ,2,2); M + [0 0] + [0 0] + sage: isinstance(M, RingElement) + False + + +*ペアレント* が唯一のものであるとしても,同じSageのペアレントに由来する対等な *元* までが同一になるとは限らない. +この辺りはPythonの(全てではないにしても)整数の振舞いとは違っている. + +:: + + sage: int(1) is int(1) # Pythonのint型 + True + sage: int(-15) is int(-15) + False + sage: 1 is 1 # Sageの整数 + False + + +重要なのは,異なる環に由来する元は,一般にその型ではなくペアレントによって判別されることである: + +:: + + sage: a = GF(2)(1) + sage: b = GF(5)(1) + sage: type(a) is type(b) + True + sage: parent(a) + Finite Field of size 2 + sage: parent(b) + Finite Field of size 5 + +とういうわけで,代数学的な立場からすると **元のペアレントはその型より重要である** ことになる. + + +型変換と型強制 +-------------------------- + +場合によっては,あるペアレント構造に由来する元を,異なるペアレント構造の元へ変換することができる. +そうした変換は明示的に,あるいは暗黙的に行なうことが可能で,後者を *型強制* (coercion)と呼ぶ. + + +読者は,例えばC言語における *型変換* (type conversion)と *型強制* (type coercion)の概念をご存知かもしれない. +Sageにも *型変換* と *型強制* の考えは取り込まれている. +しかし,Sageでは主たる対象が型ではなくペアレントになっているので,Cの型変換とSageにおける変換を混同しないよう注意していただきたい. + +以下の説明はかなり簡略化されているので,詳しい解説と実装情報についてはSageレファレンスマニュアルの型強制に関する節と `thematic tutorial `_ を参照されたい. + +*異なる* 環に属する元同士の演算実行については,両極をなす二つの立場がある: + + +* 異なる環はそれぞれが異なる世界を形作っており,何であれ異なる環由来の元同士で和や積を作ることは意味をなさない. + ``1`` は整数であるのに ``1/2`` が有理数なのだから, ``1 + 1/2`` ですら意味をもちえない. + + +という立場もあるし + +* 環 ``R1`` の元 ``r1`` が何とか他の環 ``R2`` の元と見なしうるなら, ``r1`` と ``R2`` の任意の元に対する全ての算術演算が許される.単位元は全ての体と多くの環に存在し,全て等価と見なしうる. + +と考える立場もありうる. + + + +Sageが宗とするのは歩み寄りだ. +``P1`` と ``P2`` がペアレント構造で ``p1`` が ``P1`` の元であるとき, ``p1`` が ``P2`` に帰属するとする解釈をユーザが明示的に求めることがあるかもしれない. +この解釈があらゆる状況で有意であるとは限らないし, ``P1`` の全ての元に対して適用可能とも言えない. +その解釈が意味を持つかどうかはユーザの判断にかかっているのである. +我々はこうした解釈の要求を, **変換** (conversion) と呼ぶことにする: + + +:: + + sage: a = GF(2)(1) + sage: b = GF(5)(1) + sage: GF(5)(a) == b + True + sage: GF(2)(b) == a + True + + +しかし, *暗黙的* (自動的) 変換については,変換が *全面的* かつ *無矛盾* に行ないうる場合にのみ実行される. +こちらで重視されているのは数学的な厳密さである. + + +そうした暗黙的変換は **型強制** (coercion)と呼ばれる. +型強制が定義できるのならば,結果は型変換と一致しなければならない. +型強制の定義に際して満足されるべき条件は二つある: + + +#. ``P1`` から ``P2`` への型強制は構造保存写像(すなわち環準同形写像)になっていなければならない. + ``P1`` の要素が ``P2`` に写像されるだけでは不十分で,その写像は ``P1`` の代数構造を反映している必要がある. + +#. 型強制は無矛盾に構成されなければならない. + ``P3`` を3つ目のペアレント構造として, ``P1`` から ``P2`` への型強制と + ``P2`` から ``P3`` への型強制を合成すると, ``P1`` から ``P3`` への型強制に一致しなければならない. + 特に ``P1`` から ``P2`` へと ``P2`` から ``P1`` への型強制が存在する場合,この2つの変換を合成すると ``P1`` への恒等写像にならねばならない. + + +したがって, ``GF(2)`` の全ての元は ``GF(5)`` 上へ変換可能であるにも関わらず,型強制は成立しない. +``GF(2)`` と ``GF(5)`` の間には環準同形写像が存在しないからである. + + +二つ目の条件 --- 無矛盾性 --- については,いくぶん説明が難しいところがある. +多変数多項式環を例にとって説明してみたい. +実用上,変数名を維持しない型強制はまず使いものにならないはずだ.であれば: + + +:: + + sage: R1. = ZZ[] + sage: R2 = ZZ['y','x'] + sage: R2.has_coerce_map_from(R1) + True + sage: R2(x) + x + sage: R2(y) + y + + +変数名を維持する環準同形写像が定義できなければ,型強制も成立しない. +しかし,対象とする環の生成元を生成元リスト上の順序に応じて写像してやれば,型変換の方はまだ定義の可能性が残る: + +.. link + +:: + + sage: R3 = ZZ['z','x'] + sage: R3.has_coerce_map_from(R1) + False + sage: R3(x) + z + sage: R3(y) + x + +ところが,そうした順序依存の変換は型強制としては満足すべきものにならない. +``ZZ['x','y']`` から ``ZZ['y','x']`` への変数名維持写像と ``ZZ['y','x']`` から ``ZZ['a','b']`` への順序依存写像を合成すると,結果は変数名も順序も保存しない写像となって無矛盾性が破れてしまうからである. + + +型強制が成立するなら,異なる環に由来する元同士の比較や算術演算の際に利用されるはずである. +これはたしかに便利なのだが,ペアレントの違いを越えた ``==`` 型関係の適用には無理が生じがちなことには注意を要する. +``==`` は *同一の* 環上の元同士の等価関係を表わすが,これは *異なる* 環の元が関わると必ずしも有効なわけではない. +例えば, ``ZZ`` 上の ``1`` と,何か有限体上にあるとした ``1`` は等価であると見なすことができる. +というのは,整数から任意の有限体へは型強制が成り立つからだ. +しかし,一般には二つの異なる有限体環の間に型強制は成立しない. +以下を見ていただきたい: + + +.. link + +:: + + sage: GF(5)(1) == 1 + True + sage: 1 == GF(2)(1) + True + sage: GF(5)(1) == GF(2)(1) + False + sage: GF(5)(1) != GF(2)(1) + True + + +同様にして + + +.. link + +:: + + sage: R3(R1.1) == R3.1 + True + sage: R1.1 == R3.1 + False + sage: R1.1 != R3.1 + True + + +さらに無矛盾性の条件から帰結するのは,厳密な環(例えば有理数 ``QQ``)から厳密ではない環(例えば有限精度の実数 ``RR``)への型強制は成立するが,逆方向は成立しないことである. +``QQ`` から ``RR`` への型強制と ``RR`` から ``QQ`` への変換を合成すると ``QQ`` 上の恒等写像になるはずだが,これは不可能である. +と言うのは,有理数の中には,以下で示すように ``RR`` 上で問題なく扱えるものがあるからだ: + +:: + + sage: RR(1/10^200+1/10^100) == RR(1/10^100) + True + sage: 1/10^200+1/10^100 == 1/10^100 + False + +型強制が成立しない環 ``P1`` と ``P2`` の二つのペアレント由来の元を比較するとき,基準となるペアレント ``P3`` が選択できて ``P1`` と ``P2`` を ``P3`` へ型強制できる場合がある. +そうした状況では型強制がうまく成立するはずだ. +典型的な例は有理数と整数係数の多項式の和の計算で,結果は有理係数の多項式になる. + + +:: + + sage: P1. = ZZ[] + sage: p = 2*x+3 + sage: q = 1/2 + sage: parent(p) + Univariate Polynomial Ring in x over Integer Ring + sage: parent(p+q) + Univariate Polynomial Ring in x over Rational Field + + +この結果は,原則的には ``ZZ['x']`` の有理数体上でも成立する. +しかし,Sageは最も自然に見える *正準* な共通のペアレントを選択しようとする(ここでは ``QQ['x']``). +共通のペアレント候補が複数あってどれも同じく有望そうな場合,Sageは中の一つをランダムに選択するということは *しない* . +これは再現性の高い結果を求めるためで,選択の手段については `thematic tutorial +`_ +に解説がある. + + +以下に示すのは,共通のペアレントへの型強制が成立しない例である: + +:: + + sage: R. = QQ[] + sage: S. = QQ[] + sage: x+y + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for '+': 'Univariate Polynomial Ring in x over Rational Field' and 'Univariate Polynomial Ring in y over Rational Field' + +だめな理由は,Sageが有望そうな候補 ``QQ['x']['y']`` , ``QQ['y']['x']`` , ``QQ['x','y']`` あるいは ``QQ['y','x']`` のどれも選択できないことである. +と言うのも,これら4つの相異なる構造はどれも共通なペアレントとして相応しく,基準となるべき選択肢にならないからだ. + diff --git a/src/doc/ja/tutorial/tour_functions.rst b/src/doc/ja/tutorial/tour_functions.rst new file mode 100755 index 00000000000..b34f7f23595 --- /dev/null +++ b/src/doc/ja/tutorial/tour_functions.rst @@ -0,0 +1,249 @@ +.. _section-functions-issues: + +関数まわりの注意点 +================================= + +関数の定義については紛らわしい側面があって,微積分やプロットなどを行なう際に問題になることがある. +この節で,関連する諸問題について検討してみたい. + +Sageで「関数」と呼ばれるべきものを定義する方法は何通りもある: + +1. :ref:`section-functions` 節で解説されている方法で,Python関数を定義する. +こうして定義された関数はプロット可能だが,微分積分演算はできない. + +:: + + sage: def f(z): return z^2 + sage: type(f) + + sage: f(3) + 9 + sage: plot(f, 0, 2) + + +最終行の書法に注目していただきたい. +これを ``plot(f(z), 0, 2)`` としていたら,エラーになっていたはずである. +``z`` は ``f`` 定義におけるダミー変数であって,定義ブロックの外では未定義になるからだ. +むろん ``f(z)`` のみを実行してもエラーになる. +以下のようにすると切り抜けられるが,どんな場合でも通用するとは限らないので要注意だ(下の第4項を参照). + +.. link +:: + + sage: var('z') # zを変数として定義 + z + sage: f(z) + z^2 + sage: plot(f(z), 0, 2) + + +こうすると ``f(z)`` はシンボリック表現になる.シンボリック表現については,次の項目で解説する. + + + + +2. 「呼び出し可能シンボリック表現」(callable symbolic expression)を定義する. +これはプロットおよび微分積分演算が可能である. + +:: + + sage: g(x) = x^2 + sage: g # gはxをx^2に送る + x |--> x^2 + sage: g(3) + 9 + sage: Dg = g.derivative(); Dg + x |--> 2*x + sage: Dg(3) + 6 + sage: type(g) + + sage: plot(g, 0, 2) + + +``g`` は呼び出し可能シンボリック表現だが, ``g(x)`` の方はこれに関係はあっても異なる種類のオブジェクトである. +やはりプロットと微積分などが可能なのだが,違っている点もあるので注意を要する. +以下の第5項で具体的に説明する. + +.. link + +:: + + sage: g(x) + x^2 + sage: type(g(x)) + + sage: g(x).derivative() + 2*x + sage: plot(g(x), 0, 2) + + + +3. Sageで定義済みの「初等関数」(calculus function)を使う. +これらはプロット可能で,ちょっと工夫すると微分積分もできるようになる. + + +:: + + sage: type(sin) + + sage: plot(sin, 0, 2) + sage: type(sin(x)) + + sage: plot(sin(x), 0, 2) + + +そのままでは ``sin`` は微分演算を受けつけない. +少なくとも ``cos`` にはならない. + + +:: + + sage: f = sin + sage: f.derivative() + Traceback (most recent call last): + ... + AttributeError: ... + + +``sin`` そのままではなく ``f = sin(x)`` とすると微積分を受けつけるようになるが, もっと手堅いのは ``f(x) = sin(x)`` として呼び出し可能シンボリック表現を定義することである. + + +:: + + sage: S(x) = sin(x) + sage: S.derivative() + x |--> cos(x) + + + +まだ注意を要する点が残っているので,説明しておこう: + +4. 意図しない評価が起きることがある. +:: + + sage: def h(x): + ... if x<2: + ... return 0 + ... else: + ... return x-2 + + +ここで ``plot(h(x), 0, 4)`` を実行すると,プロットされるのは `y=x-2` で,複数行にわたって定義しておいた ``h`` ではない. +原因を考えてみよう. +コマンド ``plot(h(x), 0, 4)`` が実行されると,まず ``h(x)`` が評価されるが, これは ``x`` が関数 ``h(x)`` に突っ込まれ ``x<2`` が評価されることを意味する. + +.. link + +:: + + sage: type(x<2) + + + +シンボリック式が評価される際, ``h`` の定義の場合と同じように,その式が明らかに真でないかぎり戻り値は偽になる. +したがって ``h(x)`` は ``x-2`` と評価され,プロットされるのも ``x-2`` になるわけである. + + +解決策はというと, ``plot(h(x), 0, 4)`` ではなく + + +.. link + + + +:: + + sage: plot(h, 0, 4) + + +を実行せよ,ということになる. + + + +5. 意図せず関数が定数になってしまう. +:: + + sage: f = x + sage: g = f.derivative() + sage: g + 1 + + +問題は,例えば ``g(3)`` などと実行するとエラーになって, "ValueError: the number of arguments must be less than or equal to 0."と文句をつけてくることだ. + +.. link + +:: + + sage: type(f) + + sage: type(g) + + + +``g`` は関数ではなく定数になっているので,変数を持たないから何も値を受けつけない. + + +解決策は何通りかある. + +- ``f`` を最初にシンボリック表式として定義しておく. + +:: + + sage: f(x) = x # 'f = x'とはしない + sage: g = f.derivative() + sage: g + x |--> 1 + sage: g(3) + 1 + sage: type(g) + + + +- または ``f`` の定義は元のまま ``g`` をシンボリック表式として定義する. + +:: + + sage: f = x + sage: g(x) = f.derivative() # 'g = f.derivative()'とするかわり + sage: g + x |--> 1 + sage: g(3) + 1 + sage: type(g) + + + +- または ``f`` と ``g`` の定義は元のまま,代入すべき変数を特定する. + +:: + + sage: f = x + sage: g = f.derivative() + sage: g + 1 + sage: g(x=3) # たんに'g(3)'とはしない + 1 + + +おしまいになったが, ``f = x`` と ``f(x) = x`` 各々に対する微分の相違点を示す方法がまだあった. + + +:: + + sage: f(x) = x + sage: g = f.derivative() + sage: g.variables() # gに属する変数は? + () + sage: g.arguments() # gに値を送り込むための引数は? + (x,) + sage: f = x + sage: h = f.derivative() + sage: h.variables() + () + sage: h.arguments() + () + + +ここの例から判るように, ``h(3)`` がエラーになるのは,そもそも ``h`` が引数を受けつけないためである. diff --git a/src/doc/ja/tutorial/tour_groups.rst b/src/doc/ja/tutorial/tour_groups.rst new file mode 100755 index 00000000000..dd02bb0a780 --- /dev/null +++ b/src/doc/ja/tutorial/tour_groups.rst @@ -0,0 +1,89 @@ + +有限群,アーベル群 +============================= + +Sageでは,置換群,有限古典群(例えば :math:`SU(n,q)`),有限行列群(生成元を指定して生成),そしてアーベル群(無限次も可)などの演算が可能である. +これらの機能の大半は,GAPとのインターフェイスを経由して実現されている. + + +まず,例として置換群を生成してみよう. +それには,以下のようにして生成元のリストを指定してやればよい. + + +:: + + sage: G = PermutationGroup(['(1,2,3)(4,5)', '(3,4)']) + sage: G + Permutation Group with generators [(3,4), (1,2,3)(4,5)] + sage: G.order() + 120 + sage: G.is_abelian() + False + sage: G.derived_series() # 結果は変化しがち + [Permutation Group with generators [(1,2,3)(4,5), (3,4)], + Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] + sage: G.center() + Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + sage: G.random_element() # 出力は変化する + (1,5,3)(2,4) + sage: print latex(G) + \langle (3,4), (1,2,3)(4,5) \rangle + +Sageを使えば(LaTeX形式で)指標表を作ることもできる: + + +:: + + sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3)]]) + sage: latex(G.character_table()) + \left(\begin{array}{rrrr} + 1 & 1 & 1 & 1 \\ + 1 & -\zeta_{3} - 1 & \zeta_{3} & 1 \\ + 1 & \zeta_{3} & -\zeta_{3} - 1 & 1 \\ + 3 & 0 & 0 & -1 + \end{array}\right) + +Sageは有限体上の古典群と行列群も扱うことができる: + + +:: + + sage: MS = MatrixSpace(GF(7), 2) + sage: gens = [MS([[1,0],[-1,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: G.conjugacy_class_representatives() + ( + [1 0] [0 6] [0 4] [6 0] [0 6] [0 4] [0 6] [0 6] [0 6] [4 0] + [0 1], [1 5], [5 5], [0 6], [1 2], [5 2], [1 0], [1 4], [1 3], [0 2], + + [5 0] + [0 3] + ) + sage: G = Sp(4,GF(7)) + sage: G + Symplectic Group of degree 4 over Finite Field of size 7 + sage: G.random_element() # 元をランダムに出力 + [5 5 5 1] + [0 2 6 3] + [5 0 1 0] + [4 6 3 4] + sage: G.order() + 276595200 + +(無限次および有限次の)アーベル群を使う演算も可能だ: + + +:: + + sage: F = AbelianGroup(5, [5,5,7,8,9], names='abcde') + sage: (a, b, c, d, e) = F.gens() + sage: d * b**2 * c**3 + b^2*c^3*d + sage: F = AbelianGroup(3,[2]*3); F + Multiplicative Abelian group isomorphic to C2 x C2 x C2 + sage: H = AbelianGroup([2,3], names="xy"); H + Multiplicative Abelian group isomorphic to C2 x C3 + sage: AbelianGroup(5) + Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z + sage: AbelianGroup(5).order() + +Infinity diff --git a/src/doc/ja/tutorial/tour_help.rst b/src/doc/ja/tutorial/tour_help.rst new file mode 100755 index 00000000000..c7f658d6168 --- /dev/null +++ b/src/doc/ja/tutorial/tour_help.rst @@ -0,0 +1,367 @@ +.. _chapter-help: + +ヘルプの利用 +============ + +Sageには充実したドキュメントが組込まれていて,(例えば)関数や定数の名前に続けて疑問符 ``?`` を入力するだけで解説を呼び出すことができる: + +.. skip + +:: + + sage: tan? + Type: + Definition: tan( [noargspec] ) + Docstring: + + The tangent function + + EXAMPLES: + sage: tan(pi) + 0 + sage: tan(3.1415) + -0.0000926535900581913 + sage: tan(3.1415/4) + 0.999953674278156 + sage: tan(pi/4) + 1 + sage: tan(1/2) + tan(1/2) + sage: RR(tan(1/2)) + 0.546302489843790 + sage: log2? + Type: + Definition: log2( [noargspec] ) + Docstring: + + The natural logarithm of the real number 2. + + EXAMPLES: + sage: log2 + log2 + sage: float(log2) + 0.69314718055994529 + sage: RR(log2) + 0.693147180559945 + sage: R = RealField(200); R + Real Field with 200 bits of precision + sage: R(log2) + 0.69314718055994530941723212145817656807550013436025525412068 + sage: l = (1-log2)/(1+log2); l + (1 - log(2))/(log(2) + 1) + sage: R(l) + 0.18123221829928249948761381864650311423330609774776013488056 + sage: maxima(log2) + log(2) + sage: maxima(log2).float() + .6931471805599453 + sage: gp(log2) + 0.6931471805599453094172321215 # 精度は32ビット + 0.69314718055994530941723212145817656807 # 同じく64ビット + sage: sudoku? + File: sage/local/lib/python2.5/site-packages/sage/games/sudoku.py + Type: + Definition: sudoku(A) + Docstring: + + Solve the 9x9 Sudoku puzzle defined by the matrix A. + + EXAMPLE: + sage: A = matrix(ZZ,9,[5,0,0, 0,8,0, 0,4,9, 0,0,0, 5,0,0, + 0,3,0, 0,6,7, 3,0,0, 0,0,1, 1,5,0, 0,0,0, 0,0,0, 0,0,0, 2,0,8, 0,0,0, + 0,0,0, 0,0,0, 0,1,8, 7,0,0, 0,0,4, 1,5,0, 0,3,0, 0,0,2, + 0,0,0, 4,9,0, 0,5,0, 0,0,3]) + sage: A + [5 0 0 0 8 0 0 4 9] + [0 0 0 5 0 0 0 3 0] + [0 6 7 3 0 0 0 0 1] + [1 5 0 0 0 0 0 0 0] + [0 0 0 2 0 8 0 0 0] + [0 0 0 0 0 0 0 1 8] + [7 0 0 0 0 4 1 5 0] + [0 3 0 0 0 2 0 0 0] + [4 9 0 0 5 0 0 0 3] + sage: sudoku(A) + [5 1 3 6 8 7 2 4 9] + [8 4 9 5 2 1 6 3 7] + [2 6 7 3 4 9 5 8 1] + [1 5 8 4 6 3 9 7 2] + [9 7 4 2 1 8 3 6 5] + [3 2 6 7 9 5 4 1 8] + [7 8 2 9 3 4 1 5 6] + [6 3 5 1 7 2 8 9 4] + [4 9 1 8 5 6 7 2 3] + +さらにSageでは,関数名の最初の何文字かを入力して ``TAB`` キーを打つと候補が表示される,タブ補完機能を使うことができる. +例えば ``ta`` と入力して ``TAB`` キーを押せば、Sageは ``tachyon, tan, tanh,taylor`` を表示してくる. +この機能を使えば関数やオブジェクトなどの名称を容易に探しあてることができるはずだ. + + +.. _section-functions: + +関数, インデントおよび数え上げ +==================================== + +Sageで新しい関数を定義するには, ``def`` 命令を使い、変数名を並べた後にコロン ``:`` を付ける. +以下に例を示そう: + +:: + + sage: def is_even(n): + ... return n%2 == 0 + ... + sage: is_even(2) + True + sage: is_even(3) + False + +*注意* : チュートリアルをどの形式で閲覧しているかにもよるが,上のコード例の2行目には三点ドット ``...`` が見えているはずだ. +この三点ドットは入力しないこと. +三点ドットは,コードがインデントされていることを示しているだけだからだ. +そうした場面では,常に構文ブロックの末尾で一度 ``Return/Enter`` を押して空行を挿入し,関数定義を終了してやらねばならない. + +引数の型を指定していないことに注意.複数個の引数を指定し,その各々にデフォルト値を割り当てることもできる. +例えば、以下の関数では引数 ``divisor`` の値が指定されない場合, ``divisor=2`` がデフォルト値になる: + +:: + + sage: def is_divisible_by(number, divisor=2): + ... return number%divisor == 0 + sage: is_divisible_by(6,2) + True + sage: is_divisible_by(6) + True + sage: is_divisible_by(6, 5) + False + + +関数を呼び出すときには,特定の引数へ明示的に値を代入することもできる. +引数への明示的な代入を行なう場合,関数に渡す引数の順序は任意になる: + +.. link + +:: + + sage: is_divisible_by(6, divisor=5) + False + sage: is_divisible_by(divisor=2, number=6) + True + + +Pythonの構文ブロックは,他の多くの言語のように中括弧やbegin-endで括ることによって示されるわけではない. +代りに、Pythonでは構文構造に正確に対応したインデンテーション(字下げ)によってブロックを示す. +次の例は, ``return`` ステートメントが関数内の他のコードと同じようにインデントされていないために,文法エラーになっている: + +.. skip + +:: + + sage: def even(n): + ... v = [] + ... for i in range(3,n): + ... if i % 2 == 0: + ... v.append(i) + ... return v + Syntax Error: + return v + +しかし正しくインデントし直せば,この関数はきちんと動くようになる: + +:: + + sage: def even(n): + ... v = [] + ... for i in range(3,n): + ... if i % 2 == 0: + ... v.append(i) + ... return v + sage: even(10) + [4, 6, 8] + +行末にセミコロンは必要ない. +ほとんどの場合,行末は改行記号によって示される. +しかし,1行に複数のステートメントをセミコロンで区切って書き込むこともできる: + +:: + + sage: a = 5; b = a + 3; c = b^2; c + 64 + +1行の内容を複数行に分けて書きたければ,各行末にバックスラッシュをつければよい: + +:: + + sage: 2 + \ + ... 3 + 5 + + +Sageでは,一定範囲の整数の数え上げによって反復を制御する. +例えば,以下のコードの1行目はC++やJavaにおける ``for(i=0; i<3; i++)`` と全く同じ意味になる: + + +:: + + sage: for i in range(3): + ... print i + 0 + 1 + 2 + + +次の例の最初の行は, ``for(i=2;i<5;i++)`` に対応している. + + +:: + + sage: for i in range(2,5): + ... print i + 2 + 3 + 4 + + +``range`` の三つ目の引数は増分値を与えるので, +次のコードは ``for(i=1;i<6;i+=2)`` と同じ意味になる. + +:: + + sage: for i in range(1,6,2): + ... print i + 1 + 3 + 5 + + +Sageで計算した値を見映えよく表形式に並べて表示したくなることもあるだろう. +そんなとき役立つのが文字列フォーマットだ. +以下では,各列幅がきっかり6文字分の表を作り,整数とその2乗、3乗の値を並べてみる. + + +:: + + sage: for i in range(5): + ... print '%6s %6s %6s'%(i, i^2, i^3) + 0 0 0 + 1 1 1 + 2 4 8 + 3 9 27 + 4 16 64 + + +Sageにおける最も基本的なデータ構造はリストで,名前の示すとおり任意のオブジェクトの並びのことである. +上で使った ``range`` も、整数のリストを生成している: + +:: + + sage: range(2,10) + [2, 3, 4, 5, 6, 7, 8, 9] + +もう少し複雑なリストの例として: + +:: + + sage: v = [1, "hello", 2/3, sin(x^3)] + sage: v + [1, 'hello', 2/3, sin(x^3)] + +多くのプログラミング言語と同じように,リスト添字は0から始まる. + + +.. link + +:: + + sage: v[0] + 1 + sage: v[3] + sin(x^3) + + + +``v`` の長さを取得するには ``len(v)`` を使い, ``v`` の末尾に新しいオブジェクトを追加するには ``v.append(obj)`` ,そして ``v`` の :math:`i` 番目の要素を削除するためには ``del v[i]`` とする: + + +.. link + + +:: + + sage: len(v) + 4 + sage: v.append(1.5) + sage: v + [1, 'hello', 2/3, sin(x^3), 1.50000000000000] + sage: del v[1] + sage: v + [1, 2/3, sin(x^3), 1.50000000000000] + + + +もう一つの重要なデータ構造がディクショナリ(連想配列とも言う)である. +ディクショナリの振舞いはリストに似ているが,異なるのはその添字付けに基本的にいかなるオブジェクトでも使うことができる点だ(ただし添字は不変性オブジェクトでなければならない). + +:: + + sage: d = {'hi':-2, 3/8:pi, e:pi} + sage: d['hi'] + -2 + sage: d[e] + pi + + + +クラスを使えば自分で新しいデータ型を定義することも可能だ. +クラスによる数学オブジェクトのカプセル化は,Sageプログラムを見通しよく構成するための強力な方法である. +以下では, *n* までの正の偶数のリストを表すクラスを定義してみよう. +定義には組み込み型 ``list`` を使っている. +:: + + sage: class Evens(list): + ... def __init__(self, n): + ... self.n = n + ... list.__init__(self, range(2, n+1, 2)) + ... def __repr__(self): + ... return "Even positive numbers up to n." + + +オブジェクトの生成時には初期化のために ``__init__`` メソッドが呼ばれ, ``__repr__`` メソッドはオブジェクトを印字する. +``__init__`` メソッドの2行目ではリストコンストラクタを使った. +クラス ``Evens`` のオブジェクトを生成するには以下のようにする: + + +.. link + + +:: + + sage: e = Evens(10) + sage: e + Even positive numbers up to n. + + +``e`` の印字には,我々が定義した ``__repr__`` メソッドが使われている. +オブジェクトに含まれる偶数のリストを表示するには, ``list`` 関数を使う: + + +.. link + + +:: + + sage: list(e) + [2, 4, 6, 8, 10] + + +``n`` 属性にアクセスし、 ``e`` をリストのように扱うこともできる. + + +.. link + + +:: + + sage: e.n + 10 + sage: e[2] + 6 diff --git a/src/doc/ja/tutorial/tour_linalg.rst b/src/doc/ja/tutorial/tour_linalg.rst new file mode 100755 index 00000000000..e2a0a0b7f4a --- /dev/null +++ b/src/doc/ja/tutorial/tour_linalg.rst @@ -0,0 +1,269 @@ +.. _section-linalg: + +線形代数 +============== + +Sageには線形代数で常用されるツールが揃っていて,例えば行列の特性多項式の計算、階段形式、跡(トレース)、各種の分解などの操作が可能である. + +行列の生成と積演算の手順は,簡単かつ自然なものだ: + + +:: + + sage: A = Matrix([[1,2,3],[3,2,1],[1,1,1]]) + sage: w = vector([1,1,-4]) + sage: w*A + (0, 0, 0) + sage: A*w + (-9, 1, -2) + sage: kernel(A) + Free module of degree 3 and rank 1 over Integer Ring + Echelon basis matrix: + [ 1 1 -4] + + +Sageでは,行列 :math:`A` の核空間は「左」核空間,すなわち :math:`wA=0` を満足するベクトル :math:`w` が張る空間をさす. + +.. + Note that in Sage, the kernel of a matrix :math:`A` is the + "left kernel", i.e. the space of vectors :math:`w` such that + :math:`wA=0`. + +行列方程式もメソッド ``solve_right`` を使って簡単に解くことができる. +``A.solve_right(Y)`` と実行すれば, :math:`AX=Y` を満たす行列(またはベクトル) :math:`X` が得られる. + + +.. link + +:: + + sage: Y = vector([0, -4, -1]) + sage: X = A.solve_right(Y) + sage: X + (-2, 1, 0) + sage: A * X # 解のチェック... + (0, -4, -1) + + +``solve_right`` の代わりにバックスラッシュ ``\`` を使うこともできる. +つまり ``A.solve_right(Y)`` ではなく ``A \ Y`` と書くわけである. + +.. link + +:: + + sage: A \ Y + (-2, 1, 0) + + + +解がない場合は,Sageはエラーを返してくる: + +.. skip + +:: + + sage: A.solve_right(w) + Traceback (most recent call last): + ... + ValueError: matrix equation has no solutions + + +同様にして, :math:`XA=Y` を満足する :math:`X` を求めるには ``A.solve_left(Y)`` とすればよい. + + +Sageは固有値と固有ベクトルの計算もしてくれる: + + +:: + + sage: A = matrix([[0, 4], [-1, 0]]) + sage: A.eigenvalues () + [-2*I, 2*I] + sage: B = matrix([[1, 3], [3, 1]]) + sage: B.eigenvectors_left() + [(4, [ + (1, 1) + ], 1), (-2, [ + (1, -1) + ], 1)] + + +( ``eigenvectors_left`` の出力は,三つ組タプル(固有値,固有ベクトル,多重度)のリストになっている.) + +``QQ`` または ``RR`` 上の固有値と固有ベクトルはMaximaを使って計算することもできる( 後半の :ref:`section-maxima` 節を参照). + + + +:ref:`section-rings` 節で述べたように,行列の性質の中には,その行列がどんな環の上で定義されているかに影響を受けるものがある. +以下では, ``matrix`` コマンドの最初の引数を使って,Sageに生成すべき行列が整数の行列( ``ZZ`` の場合) なのか,有理数の行列(``QQ``)なのか,あるいは実数の行列(``RR``)なのかを指定している. + + +:: + + sage: AZ = matrix(ZZ, [[2,0], [0,1]]) + sage: AQ = matrix(QQ, [[2,0], [0,1]]) + sage: AR = matrix(RR, [[2,0], [0,1]]) + sage: AZ.echelon_form() + [2 0] + [0 1] + sage: AQ.echelon_form() + [1 0] + [0 1] + sage: AR.echelon_form() + [ 1.00000000000000 0.000000000000000] + [0.000000000000000 1.00000000000000] + + +浮動小数点型の実数または複素数上で定義された行列の固有値と固有ベクトルを計算するためには,対象とする行列を,それぞれ ``RDF`` (Real Double Field)または ``CDF`` (Complex Double Field)上で定義しておかなければならない. +もし環を指定しないまま行列に浮動小数点型の実数あるいは複素数が使われる場合,その行列はデフォルトでそれぞれ ``RR`` あるいは ``CC`` 体上で定義される. +この場合,以下の演算があらゆる状況で実行可能になるとは限らない. + + +:: + + sage: ARDF = matrix(RDF, [[1.2, 2], [2, 3]]) + sage: ARDF.eigenvalues() + [-0.0931712199461, 4.29317121995] + sage: ACDF = matrix(CDF, [[1.2, I], [2, 3]]) + sage: ACDF.eigenvectors_right() + [(0.881845698329 - 0.820914065343*I, [(0.750560818381, -0.616145932705 + 0.238794153033*I)], 1), + (3.31815430167 + 0.820914065343*I, [(0.145594698293 + 0.37566908585*I, 0.915245825866)], 1)] + + + +行列の空間 +------------- + +有理数型の要素からなる `3 \times 3` 行列の空間 +:math:`\text{Mat}_{3\times 3}(\QQ)` を生成してみよう: + +:: + + sage: M = MatrixSpace(QQ,3) + sage: M + Full MatrixSpace of 3 by 3 dense matrices over Rational Field + + +(3行4列の行列空間を生成したければ ``MatrixSpace(QQ,3,4)`` とする. +列数を省略するとデフォルトで行数に合わせられるから, ``MatrixSpace(QQ,3)`` は ``MatrixSpace(QQ,3,3)`` と同じ意味になる.) +行列の空間は基底系を備えており,Sageはこれをリストとして保存している: + +.. link + +:: + + sage: B = M.basis() + sage: len(B) + 9 + sage: B[1] + [0 1 0] + [0 0 0] + [0 0 0] + +``M`` の元の一つとして行列を生成してみよう. + + +.. link + +:: + + sage: A = M(range(9)); A + [0 1 2] + [3 4 5] + [6 7 8] + + +ついで,その既約階段形式と核を計算する. + +.. link + +:: + + sage: A.echelon_form() + [ 1 0 -1] + [ 0 1 2] + [ 0 0 0] + sage: A.kernel() + Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: + [ 1 -2 1] + +次に,有限体上で定義された行列による計算を実行してみる. + + +:: + + sage: M = MatrixSpace(GF(2),4,8) + sage: A = M([1,1,0,0, 1,1,1,1, 0,1,0,0, 1,0,1,1, + ... 0,0,1,0, 1,1,0,1, 0,0,1,1, 1,1,1,0]) + sage: A + [1 1 0 0 1 1 1 1] + [0 1 0 0 1 0 1 1] + [0 0 1 0 1 1 0 1] + [0 0 1 1 1 1 1 0] + sage: rows = A.rows() + sage: A.columns() + [(1, 0, 0, 0), (1, 1, 0, 0), (0, 0, 1, 1), (0, 0, 0, 1), + (1, 1, 1, 1), (1, 0, 1, 1), (1, 1, 0, 1), (1, 1, 1, 0)] + sage: rows + [(1, 1, 0, 0, 1, 1, 1, 1), (0, 1, 0, 0, 1, 0, 1, 1), + (0, 0, 1, 0, 1, 1, 0, 1), (0, 0, 1, 1, 1, 1, 1, 0)] + +上に現れた行ベクトル系(rows)によって張られる `\GF{2}` の部分空間を作成する. + + +.. link + +:: + + sage: V = VectorSpace(GF(2),8) + sage: S = V.subspace(rows) + sage: S + Vector space of degree 8 and dimension 4 over Finite Field of size 2 + Basis matrix: + [1 0 0 0 0 1 0 0] + [0 1 0 0 1 0 1 1] + [0 0 1 0 1 1 0 1] + [0 0 0 1 0 0 1 1] + sage: A.echelon_form() + [1 0 0 0 0 1 0 0] + [0 1 0 0 1 0 1 1] + [0 0 1 0 1 1 0 1] + [0 0 0 1 0 0 1 1] + + +Sageは `S` の基底として, `S` の生成元行列の既約階段形式の非ゼロ行を使用している. + + +疎行列の線形代数 +--------------------- + +SageではPID(単項イデアル整域)上の疎行列に関する線形代数を扱うことができる. + +:: + + sage: M = MatrixSpace(QQ, 100, sparse=True) + sage: A = M.random_element(density = 0.05) + sage: E = A.echelon_form() + + +Sageで使われている多重モジュラーアルゴリズムは,正方行列ではうまく働く(非正方行列ではいまひとつである): + +:: + + sage: M = MatrixSpace(QQ, 50, 100, sparse=True) + sage: A = M.random_element(density = 0.05) + sage: E = A.echelon_form() + sage: M = MatrixSpace(GF(2), 20, 40, sparse=True) + sage: A = M.random_element() + sage: E = A.echelon_form() + +Pythonでは,大文字小文字が区別されることに注意: + +:: + + sage: M = MatrixSpace(QQ, 10,10, Sparse=True) + Traceback (most recent call last): + ... + TypeError: __classcall__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/ja/tutorial/tour_numtheory.rst b/src/doc/ja/tutorial/tour_numtheory.rst new file mode 100755 index 00000000000..32e0a6e0f8a --- /dev/null +++ b/src/doc/ja/tutorial/tour_numtheory.rst @@ -0,0 +1,172 @@ +.. Number Theory + +数論 +============= + +Sageは数論関連の多彩な機能を備えている. +例えば,以下のようにして :math:`\ZZ/N\ZZ` 上の演算を実行することができる: + +:: + + sage: R = IntegerModRing(97) + sage: a = R(2) / R(3) + sage: a + 33 + sage: a.rational_reconstruction() + 2/3 + sage: b = R(47) + sage: b^20052005 + 50 + sage: b.modulus() + 97 + sage: b.is_square() + True + +Sageは数論では標準となっている関数群を装備している.例えば + + +:: + + sage: gcd(515,2005) + 5 + sage: factor(2005) + 5 * 401 + sage: c = factorial(25); c + 15511210043330985984000000 + sage: [valuation(c,p) for p in prime_range(2,23)] + [22, 10, 6, 3, 2, 1, 1, 1] + sage: next_prime(2005) + 2011 + sage: previous_prime(2005) + 2003 + sage: divisors(28); sum(divisors(28)); 2*28 + [1, 2, 4, 7, 14, 28] + 56 + 56 + +という具合で,申し分なしだ. + + +Sageの ``sigma(n,k)`` 関数は, ``n`` の商の :math:`k` 乗の和を計算する: + +:: + + sage: sigma(28,0); sigma(28,1); sigma(28,2) + 6 + 56 + 1050 + +以下では,拡張ユークリッド互除法,オイラーの :math:`\phi` -関数,そして中国剰余定理を見てみよう: + + +:: + + sage: d,u,v = xgcd(12,15) + sage: d == u*12 + v*15 + True + sage: n = 2005 + sage: inverse_mod(3,n) + 1337 + sage: 3 * 1337 + 4011 + sage: prime_divisors(n) + [5, 401] + sage: phi = n*prod([1 - 1/p for p in prime_divisors(n)]); phi + 1600 + sage: euler_phi(n) + 1600 + sage: prime_to_m_part(n, 5) + 401 + +次に, :math:`3n+1` 問題をちょっと調べてみる. + +:: + + sage: n = 2005 + sage: for i in range(1000): + ... n = 3*odd_part(n) + 1 + ... if odd_part(n)==1: + ... print i + ... break + 38 + +最後に,中国剰余定理を確かめてみよう. + + +:: + + sage: x = crt(2, 1, 3, 5); x + 11 + sage: x % 3 # x mod 3 = 2 + 2 + sage: x % 5 # x mod 5 = 1 + 1 + sage: [binomial(13,m) for m in range(14)] + [1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1] + sage: [binomial(13,m)%2 for m in range(14)] + [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1] + sage: [kronecker(m,13) for m in range(1,13)] + [1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1] + sage: n = 10000; sum([moebius(m) for m in range(1,n)]) + -23 + sage: Partitions(4).list() + [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] + + + +:math:`p` \-進数 +------------------------ + +Sageには :math:`p` \-進数体も組込まれている. +ただし,いったん生成された :math:`p` \-進数体については,後でその精度を変更することはできないことを注意しておく. + + +:: + + sage: K = Qp(11); K + 11-adic Field with capped relative precision 20 + sage: a = K(211/17); a + 4 + 4*11 + 11^2 + 7*11^3 + 9*11^5 + 5*11^6 + 4*11^7 + 8*11^8 + 7*11^9 + + 9*11^10 + 3*11^11 + 10*11^12 + 11^13 + 5*11^14 + 6*11^15 + 2*11^16 + + 3*11^17 + 11^18 + 7*11^19 + O(11^20) + sage: b = K(3211/11^2); b + 10*11^-2 + 5*11^-1 + 4 + 2*11 + O(11^18) + +:math:`p` \-進数体あるいは :math:`QQ` 以外の数体上に整数環を実装するために多大の労力が投入されてきている. +興味ある読者はGoogleグループ ``sage-support`` で専門家に詳細を聞いてみてほしい. + + +``NumberField`` クラスには,すでに多くの関連メソッドが実装されている. + + +:: + + sage: R. = PolynomialRing(QQ) + sage: K = NumberField(x^3 + x^2 - 2*x + 8, 'a') + sage: K.integral_basis() + [1, 1/2*a^2 + 1/2*a, a^2] + +.. link + +:: + + sage: K.galois_group(type="pari") + Galois group PARI group [6, -1, 2, "S3"] of degree 3 of the Number Field + in a with defining polynomial x^3 + x^2 - 2*x + 8 + +.. link + +:: + + sage: K.polynomial_quotient_ring() + Univariate Quotient Polynomial Ring in a over Rational Field with modulus + x^3 + x^2 - 2*x + 8 + sage: K.units() + (3*a^2 + 13*a + 13,) + sage: K.discriminant() + -503 + sage: K.class_group() + Class group of order 1 of Number Field in a with + defining polynomial x^3 + x^2 - 2*x + 8 + sage: K.class_number() + 1 diff --git a/src/doc/ja/tutorial/tour_plotting.rst b/src/doc/ja/tutorial/tour_plotting.rst new file mode 100755 index 00000000000..87a3a62efbc --- /dev/null +++ b/src/doc/ja/tutorial/tour_plotting.rst @@ -0,0 +1,229 @@ +.. _section-plot: + +プロットする +================== + +Sageを使って2次元および3次元のグラフを作成することができる. + + +2次元プロット +--------------------- + +Sageの2次元プロット機能を使うと,円,直線,多辺形の描画はもちろん, +直交座標系における関数のプロット,極座標プロット、等高線プロット,ベクトル場プロットを行うことができる. +以下では、その具体例を見ていくことにしよう.さらにSageによるプロットの具体例を見たければ, :ref:`section-systems` 節と :ref:`section-maxima` 節,および `Sage Constructions `_ を参照してほしい. + +次のコマンドは原点を中心とした半径1の黄色い円を描く: +:: + + sage: circle((0,0), 1, rgbcolor=(1,1,0)) + Graphics object consisting of 1 graphics primitive + +円を塗りつぶすこともできる: + +:: + + sage: circle((0,0), 1, rgbcolor=(1,1,0), fill=True) + Graphics object consisting of 1 graphics primitive + +円を生成して,それを変数に収めておくこともできる. +ただし,それだけでは描画は実行されない. + +:: + + sage: c = circle((0,0), 1, rgbcolor=(1,1,0)) + +描画するには,以下のように ``c.show()`` または ``show(c)`` などとする: + +.. link + +:: + + sage: c.show() + +かわりに ``c.save('filename.png')`` などとすれば,プロット ``c`` は画像としてファイルに保存される. + +ところで「円」がどちらかと言えば「楕円」に見えるのは,軸が縦横で異なってスケールされるからだ. +これを直すには: + +.. link + +:: + + sage: c.show(aspect_ratio=1) + + + +同じことはコマンド ``show(c, aspect_ratio=1)`` としても可能だし,画像ファイルとして保存したければ ``c.save('filename.png', aspect_ratio=1)`` と実行してもよい. + + +初等関数のプロットも簡単だ: + +:: + + sage: plot(cos, (-5,5)) + Graphics object consisting of 1 graphics primitive + +変数を特定しておけば,媒介変数プロットも可能になる: + +:: + + sage: x = var('x') + sage: parametric_plot((cos(x),sin(x)^3),(x,0,2*pi),rgbcolor=hue(0.6)) + + +プロットにおける座標軸の交点は,それがグラフの描画範囲にない限り表示されないことに注意しておいてほしい. +描画範囲として十分大きな値を指定するために,科学記法(指数記法)を用いる必要があるかもしれない. + +:: + + sage: plot(x^2,(x,300,500)) + Graphics object consisting of 1 graphics primitive + +複数のプロットをまとめて描画するには,それらを足し合わせればよい: + +:: + + sage: x = var('x') + sage: p1 = parametric_plot((cos(x),sin(x)),(x,0,2*pi),rgbcolor=hue(0.2)) + sage: p2 = parametric_plot((cos(x),sin(x)^2),(x,0,2*pi),rgbcolor=hue(0.4)) + sage: p3 = parametric_plot((cos(x),sin(x)^3),(x,0,2*pi),rgbcolor=hue(0.6)) + sage: show(p1+p2+p3, axes=false) + + +塗りつぶし図形を生成するには,まず図形の頂点からなるリストを生成し(以下の例の ``L``),次に ``polygon`` コマンドで頂点をつないで閉領域を作るとよい. +ここでは,例として緑色の三角形を描画してみる: + +:: + + sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)),\ + ... 2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] + sage: p = polygon(L, rgbcolor=(1/8,3/4,1/2)) + sage: p + Graphics object consisting of 1 graphics primitive + +``show(p, axes=false)`` と入力して座標軸なしの図を表示してみよう. + +図形プロットに文字列を加えることができる: + +:: + + sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100),\ + ... 6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] + sage: p = polygon(L, rgbcolor=(1/8,1/4,1/2)) + sage: t = text("hypotrochoid", (5,4), rgbcolor=(1,0,0)) + sage: show(p+t) + + +次に出てくるarcsinのグラフは、微積分の教師が黒板にたびたび描くものだ. +主値だけではなく複数の分岐を含めてプロットするには, :math:`x` が :math:`-2\pi` から :math:`2\pi` までの :math:`y=\sin(x)` のグラフを傾き45度の線について反転させて描いてやればよい. +これをSageで実行するには,以下のコマンドを使う: + +:: + + sage: v = [(sin(x),x) for x in srange(-2*float(pi),2*float(pi),0.1)] + sage: line(v) + Graphics object consisting of 1 graphics primitive + +正接(tan)関数はsin関数よりも値域が広いので,arcsinと同じ作戦で逆正接関数のグラフを描くには *x* -軸の最大値と最小値を調節してやる必要がある: + +:: + + sage: v = [(tan(x),x) for x in srange(-2*float(pi),2*float(pi),0.01)] + sage: show(line(v), xmin=-20, xmax=20) + +Sageでは、(対象となる関数は限られるが)極座標プロット、等高線プロット、ベクトル場プロットも可能だ. +ここでは,例として等高線プロットを見ておこう: + +:: + + sage: f = lambda x,y: cos(x*y) + sage: contour_plot(f, (-4, 4), (-4, 4)) + Graphics object consisting of 1 graphics primitive + + + +3次元プロット +----------------------- + +Sageでは3次元プロットも作成することができる. +ノートブック上でもREPL(コマンドライン)上でも,3次元プロットの表示はデフォルトでオープンソースパッケージ [Jmol]_ によって行なわれる. +Jmolではマウスによる描画の回転と拡大縮小が可能だ. + +``plot3d`` を使って `f(x, y) = z` 形式の関数をプロットしてみよう: + +:: + + sage: x, y = var('x,y') + sage: plot3d(x^2 + y^2, (x,-2,2), (y,-2,2)) + Graphics3d Object + +代りに ``parametric_plot3d`` を使い, `x, y, z` 各々が1あるいは2個のパラメター(いわゆる媒介変数,記号 `u` や `v` などが使われることが多い)で決定されるパラメトリック曲面として描画することもできる. +上の関数を媒介変数表示してプロットするには: + +:: + + sage: u, v = var('u, v') + sage: f_x(u, v) = u + sage: f_y(u, v) = v + sage: f_z(u, v) = u^2 + v^2 + sage: parametric_plot3d([f_x, f_y, f_z], (u, -2, 2), (v, -2, 2)) + Graphics3d Object + +Sageで3次元曲面プロットを行うための第三の方法が ``implicit_plot3d`` の使用で,これは(空間内の点の集合を定義する) `f(x, y, z) = 0` を満足する関数の等高線を描画する. +ここでは古典的な表式を使って球面を作画してみよう: + +:: + + sage: x, y, z = var('x, y, z') + sage: implicit_plot3d(x^2 + y^2 + z^2 - 4, (x,-2, 2), (y,-2, 2), (z,-2, 2)) + Graphics3d Object + +以下で,さらにいくつかの3次元プロットを示しておこう: + +.. `Yellow Whitney's umbrella `__: + +`ホィットニーの傘 `__: + +:: + + sage: u, v = var('u,v') + sage: fx = u*v + sage: fy = u + sage: fz = v^2 + sage: parametric_plot3d([fx, fy, fz], (u, -1, 1), (v, -1, 1), + ... frame=False, color="yellow") + Graphics3d Object + +`クロスキャップ(十字帽) `__: + +:: + + sage: u, v = var('u,v') + sage: fx = (1+cos(v))*cos(u) + sage: fy = (1+cos(v))*sin(u) + sage: fz = -tanh((2/3)*(u-pi))*sin(v) + sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), + ... frame=False, color="red") + Graphics3d Object + +ねじれトーラス(twisted torus): + +:: + + sage: u, v = var('u,v') + sage: fx = (3+sin(v)+cos(u))*cos(2*v) + sage: fy = (3+sin(v)+cos(u))*sin(2*v) + sage: fz = sin(u)+2*cos(v) + sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), + ... frame=False, color="red") + Graphics3d Object + +レムニスケート(連珠形, leminscate): + +:: + + sage: x, y, z = var('x,y,z') + sage: f(x, y, z) = 4*x^2 * (x^2 + y^2 + z^2 + z) + y^2 * (y^2 + z^2 - 1) + sage: implicit_plot3d(f, (x, -0.5, 0.5), (y, -1, 1), (z, -1, 1)) + Graphics3d Object diff --git a/src/doc/ja/tutorial/tour_polynomial.rst b/src/doc/ja/tutorial/tour_polynomial.rst new file mode 100755 index 00000000000..38e463a986d --- /dev/null +++ b/src/doc/ja/tutorial/tour_polynomial.rst @@ -0,0 +1,321 @@ +.. _section-poly: + +多項式 +=========== + +この節では,Sage上で多項式を生成し利用する方法について解説する. + + +.. _section-univariate: + + +1変数多項式 +---------------------- + +多項式環を生成するには,三通りのやり方がある. + +:: + + sage: R = PolynomialRing(QQ, 't') + sage: R + Univariate Polynomial Ring in t over Rational Field + +このやり方では,多項式環を生成し,画面表示時の変数名として(文字列) ``t`` を割り当てている. +ただし,これはSage内で使うために記号 ``t`` を定義しているわけではないから,( :math:`t^2+1` のようにして) ``R`` 上の多項式を入力するときには使えないことを注意しておく. + +これに代わるやり方として + +.. link + +:: + + sage: S = QQ['t'] + sage: S == R + True + +があるが, 記号 ``t`` については最初の方法と同じ問題が残る. + +第三の,とても便利な方法が + +:: + + sage: R. = PolynomialRing(QQ) + +とするか +:: + + sage: R. = QQ['t'] + +あるいはまた + +:: + + sage: R. = QQ[] + +とすることである. + +最後の方法には,多項式の変数として変数 ``t`` が定義される余禄がついてくるので,以下のようにして簡単に ``R`` の元を構成することができる. +(第三の方法が,Magmaにおけるコンストラクタ記法によく似ていることに注意.Magmaと同じように,Sageでも多様なオブジェクトでコンストラクタ記法を使うことができる.) + +.. link + +:: + + sage: poly = (t+1) * (t+2); poly + t^2 + 3*t + 2 + sage: poly in R + True + +どの方法で多項式環を定義していても,その変数を :math:`0` 番目の生成元として取り出すことができる: + +:: + + sage: R = PolynomialRing(QQ, 't') + sage: t = R.0 + sage: t in R + True + + +Sageでは,複素数も多項式環と似た構成法で生成されている. +すなわち,実数体上に記号 ``i`` を生成元として構成されているのが複素数であると見なすことができるのだ. +それを示すのが: + +:: + + sage: CC + Complex Field with 53 bits of precision + sage: CC.0 # CCの0番目の生成元 + 1.00000000000000*I + + +多項式環を生成するときは,以下のように環と生成元の両方を同時に作るか,あるいは生成元のみを作るか選ぶことができる: + +:: + + sage: R, t = QQ['t'].objgen() + sage: t = QQ['t'].gen() + sage: R, t = objgen(QQ['t']) + sage: t = gen(QQ['t']) + +最後に, :math:`\QQ[t]` 上の演算を試してみよう. + +:: + + sage: R, t = QQ['t'].objgen() + sage: f = 2*t^7 + 3*t^2 - 15/19 + sage: f^2 + 4*t^14 + 12*t^9 - 60/19*t^7 + 9*t^4 - 90/19*t^2 + 225/361 + sage: cyclo = R.cyclotomic_polynomial(7); cyclo + t^6 + t^5 + t^4 + t^3 + t^2 + t + 1 + sage: g = 7 * cyclo * t^5 * (t^5 + 10*t + 2) + sage: g + 7*t^16 + 7*t^15 + 7*t^14 + 7*t^13 + 77*t^12 + 91*t^11 + 91*t^10 + 84*t^9 + + 84*t^8 + 84*t^7 + 84*t^6 + 14*t^5 + sage: F = factor(g); F + (7) * t^5 * (t^5 + 10*t + 2) * (t^6 + t^5 + t^4 + t^3 + t^2 + t + 1) + sage: F.unit() + 7 + sage: list(F) + [(t, 5), (t^5 + 10*t + 2, 1), (t^6 + t^5 + t^4 + t^3 + t^2 + t + 1, 1)] + + +因数分解の際には,定数(倍)部がきちんと分離して記録されていることに注目. + + +仕事中に,例えば ``R.cyclotomic_polynomial`` 関数を頻繁に使う必要があったとしよう. +研究発表の際には,Sage本体だけではなく,円周等分多項式の実質的な計算に使われたコンポーネントを突きとめて引用するのが筋だ. +この場合、 ``R.cyclotomic_polynomial??`` と入力してソースコードを表示すると,すぐに ``f = pari.polcyclo(n)`` という行が見つかるはずだ. +これで円周等分多項式の計算にPARIが使われていることが判ったのだから,発表の際にはPARIも引用することができる. + +多項式同士で割算すると,結果は(Sageが自動的に生成する)有理数体の元になる. + + +:: + + sage: x = QQ['x'].0 + sage: f = x^3 + 1; g = x^2 - 17 + sage: h = f/g; h + (x^3 + 1)/(x^2 - 17) + sage: h.parent() + Fraction Field of Univariate Polynomial Ring in x over Rational Field + +``QQ[x]`` の有理数体上でローラン級数による級数展開を計算することができる: + +:: + + sage: R. = LaurentSeriesRing(QQ); R + Laurent Series Ring in x over Rational Field + sage: 1/(1-x) + O(x^10) + 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + O(x^10) + + +異なる変数名を割り当てて生成した1変数多項式環は,ぞれぞれ異なる環と見なされる. + + +:: + + sage: R. = PolynomialRing(QQ) + sage: S. = PolynomialRing(QQ) + sage: x == y + False + sage: R == S + False + sage: R(y) + x + sage: R(y^2 - 17) + x^2 - 17 + + +環は変数名によって識別される. +同じ変数 ``x`` を使うと,異なる環をもう1つ作ったつもりでいても,そうはならないことに注意してほしい. + + +:: + + sage: R = PolynomialRing(QQ, "x") + sage: T = PolynomialRing(QQ, "x") + sage: R == T + True + sage: R is T + True + sage: R.0 == T.0 + True + +Sageでは,任意の基底環上で巾級数環およびローラン級数環を扱うことができる. +以下の例では, :math:`\GF{7}[[T]]` の元を生成し,ついでその逆数をとって :math:`\GF{7}((T))` の元を作っている. + +:: + + sage: R. = PowerSeriesRing(GF(7)); R + Power Series Ring in T over Finite Field of size 7 + sage: f = T + 3*T^2 + T^3 + O(T^4) + sage: f^3 + T^3 + 2*T^4 + 2*T^5 + O(T^6) + sage: 1/f + T^-1 + 4 + T + O(T^2) + sage: parent(1/f) + Laurent Series Ring in T over Finite Field of size 7 + +巾級数環を生成するには,二重括弧を使う省略記法を用いることもできる: + + +:: + + sage: GF(7)[['T']] + Power Series Ring in T over Finite Field of size 7 + + + +多変数多項式 +------------------------ + +複数個の変数を含む多項式を扱うには,まず多項式環と変数を宣言する. +:: + + sage: R = PolynomialRing(GF(5),3,"z") # 3 = 変数の数 + sage: R + Multivariate Polynomial Ring in z0, z1, z2 over Finite Field of size 5 + + +1変数の多項式を定義したときと同じように,他の方法もある: + +:: + + sage: GF(5)['z0, z1, z2'] + Multivariate Polynomial Ring in z0, z1, z2 over Finite Field of size 5 + sage: R. = GF(5)[]; R + Multivariate Polynomial Ring in z0, z1, z2 over Finite Field of size 5 + + +さらに,変数名を1文字にしたければ,以下のような略記法を使えばよい: +:: + + sage: PolynomialRing(GF(5), 3, 'xyz') + Multivariate Polynomial Ring in x, y, z over Finite Field of size 5 + + +ここで,ちょっと計算してみよう. + +:: + sage: z = GF(5)['z0, z1, z2'].gens() + sage: z + (z0, z1, z2) + sage: (z[0]+z[1]+z[2])^2 + z0^2 + 2*z0*z1 + z1^2 + 2*z0*z2 + 2*z1*z2 + z2^2 + +多項式環を生成するには,もっと数学寄りの記号法を使うこともできる. + + +:: + + sage: R = GF(5)['x,y,z'] + sage: x,y,z = R.gens() + sage: QQ['x'] + Univariate Polynomial Ring in x over Rational Field + sage: QQ['x,y'].gens() + (x, y) + sage: QQ['x'].objgens() + (Univariate Polynomial Ring in x over Rational Field, (x,)) + + +Sageの多変数多項式は,多項式に対する分配表現(distributive representation)とPyhonのディクショナリを使って実装されている. +gcdやイデアルのグレブナー基底の計算にはSingular [Si]_ を経由している部分がある. + +:: + + sage: R, (x, y) = PolynomialRing(RationalField(), 2, 'xy').objgens() + sage: f = (x^3 + 2*y^2*x)^2 + sage: g = x^2*y^2 + sage: f.gcd(g) + x^2 + + +次に, :math:`f` と :math:`g` から生成されるイデアル :math:`(f,g)` を求めてみる. +これには ``(f,g)`` に ``R`` を掛けてやるだけでよい(``ideal([f,g])`` あるいは ``ideal(f,g)`` としても同じだ). + +.. link + + +:: + + sage: I = (f, g)*R; I + Ideal (x^6 + 4*x^4*y^2 + 4*x^2*y^4, x^2*y^2) of Multivariate Polynomial + Ring in x, y over Rational Field + sage: B = I.groebner_basis(); B + [x^6, x^2*y^2] + sage: x^2 in I + False + + +ちなみに,上のグレブナー基底はリストではなく不変性シーケンスとして与えられている. +これは,基底がユニバースまたは親クラスとなっているため変更できないことを意味している(グレブナー基底が変えられてしまうとその基底系に依存するルーチン群も働かなくなるから当然のことだ). + +.. link + + +:: + + sage: B.parent() + Category of sequences in Multivariate Polynomial Ring in x, y over Rational + Field + sage: B.universe() + Multivariate Polynomial Ring in x, y over Rational Field + sage: B[1] = x + Traceback (most recent call last): + ... + ValueError: object is immutable; please change a copy instead. + +(種類はまだ十分ではないものの)可換代数の中にはSigular経由でSage上に実装されているものがある. +例えば, :math:`I`: の準素分解および随伴素イデアルを求めることができる: + + +.. link + +:: + + sage: I.primary_decomposition() + [Ideal (x^2) of Multivariate Polynomial Ring in x, y over Rational Field, + Ideal (y^2, x^6) of Multivariate Polynomial Ring in x, y over Rational Field] + sage: I.associated_primes() + [Ideal (x) of Multivariate Polynomial Ring in x, y over Rational Field, + Ideal (y, x) of Multivariate Polynomial Ring in x, y over Rational Field] diff --git a/src/doc/ja/tutorial/tour_rings.rst b/src/doc/ja/tutorial/tour_rings.rst new file mode 100755 index 00000000000..c62410b7812 --- /dev/null +++ b/src/doc/ja/tutorial/tour_rings.rst @@ -0,0 +1,149 @@ +.. _section-rings: + +基本的な環 +============= + +行列やベクトル,あるいは多項式を定義する際,定義の土台となる「環」を指定することが有利に働くだけではなく,不可欠ですらある場合がある. +*環* (ring)とは,和と積が質よくふるまうことが保証されている数学的構造物のことだ. +これまで聞いたことがなかったとしても,以下にあげる四つの広く使われている環についてだけは知っておくべきだろう: + +* 整数 `\{..., -1, 0, 1, 2, ...\}`, Sageでは ``ZZ`` で呼ぶ. +* 有理数 -- つまり整数による分数あるいは比 -- ``QQ`` で呼ぶ. +* 実数, ``RR`` で呼ぶ. +* 複素数, ``CC`` で呼ぶ. + +これらの環の違いについて意識しておきたいのは,例えば同じ多項式であってもそれがどの環の上で定義されるかによって異なった扱いがなされることがあるからだ. +具体例をあげると,多項式 `x^2-2` は二つの根 `\pm \sqrt{2}` を持つ. +両方とも有理数ではないから,もし有理係数の多項式として扱うのならばこの多項式は因数分解できない. +しかし,実係数の多項式として扱うのなら分解可能だ. +とすれば,求める情報を確実に得られる環を指定しておきたくなるのも当然だろう. +以下の二つのコマンドは,有理係数と実係数の多項式の集合を定義する. +集合はそれぞれ ``ratpoly`` と ``realpoly`` と命名されているが,大切なのはその名前ではない. +むしろ注意すべきは,各々の集合で使われる *変数名* を定義しているのが文字列 ``.`` と ``.`` であることである. + + +:: + + sage: ratpoly. = PolynomialRing(QQ) + sage: realpoly. = PolynomialRing(RR) + + +ここで `x^2-2` の因数分解の様子を見てみよう: + +.. link + +:: + + sage: factor(t^2-2) + t^2 - 2 + sage: factor(z^2-2) + (z - 1.41421356237310) * (z + 1.41421356237310) + + +以上と同様の注意点は,行列に対しても通用する. +既約行階段形式は元の行列がどんな環の上で定義されているかに依存するし,固有値と固有ベクトルも同様である. +多項式の構成法については :ref:`section-poly` 節に,行列に関しては :ref:`section-linalg` 節にもっと詳しい解説がある. + + +記号 ``I`` は :math:`-1` の平方根を表わし, ``i`` は ``I`` と同義である. +言うまでもなく,これは有理数ではない. + + +:: + + sage: i # -1の平方根 + I + sage: i in QQ + False + + +上のコードは,変数 ``i`` が反復制御に使われるなどして,違った値が割り当てられていたら予期した結果にならないことがある. +そんな場合には,次のように入力すると元の虚数単位 ``i`` として復活する: + +:: + + sage: reset('i') + + + +複素数の定義には一つ微妙な点がある. +すでに述べたように記号 ``i`` は `-1` の平方根を表わすが,これはあくまでも `-1` の *形式的* あるいは *シンボリック* な平方根である. +一方, ``CC(i)`` または ``CC.0`` を実行すると戻ってくるのは `-1` の *複素* 平方根である. +異なる種類の数同士の演算は,いわゆる「型強制」(coercion)によって可能になる. +これについては :ref:`section-coercion` 節を参照. + + +:: + + sage: i = CC(i) # 複素浮動小数点数 + sage: i == CC.0 + True + sage: a, b = 4/3, 2/3 + sage: z = a + b*i + sage: z + 1.33333333333333 + 0.666666666666667*I + sage: z.imag() # 虚部 + 0.666666666666667 + sage: z.real() == a # 比較の前に自動的に型変換される + True + sage: a + b + 2 + sage: 2*b == a + True + sage: parent(2/3) + Rational Field + sage: parent(4/2) + Rational Field + sage: 2/3 + 0.1 # 加算の前に自動型変換 + 0.766666666666667 + sage: 0.1 + 2/3 # SAGEの型変換規則は対称的である + 0.766666666666667 + + +もう少しSageで基本となる環の実例をあげておこう. +先に示したように,有理数の環は ``QQ`` あるいは ``RationalField()`` で参照することができる(*体(field)* とは積演算が可換で,非零元が常に逆元をもつ環のことである. +したがって有理数は体を構成するが整数は体にならない). + +:: + + sage: RationalField() + Rational Field + sage: QQ + Rational Field + sage: 1/2 in QQ + True + + +有理数でもある小数は有理数に「型強制」することができるから, +例えば小数 ``1.2`` は ``QQ`` に属すると見なされる( :ref:`section-coercion` 節を参照). +しかし, `\pi` と `\sqrt{2}` は有理数にはならない: + + +:: + + sage: 1.2 in QQ + True + sage: pi in QQ + False + sage: pi in RR + True + sage: sqrt(2) in QQ + False + sage: sqrt(2) in CC + True + + +より高度な数学で利用するため,Sageには有限体,p-進整数,代数環,多項式環,そして行列環などが用意されている. +以下ではその中のいくつかを構成してみよう. + + +:: + + sage: GF(3) + Finite Field of size 3 + sage: GF(27, 'a') # 素数体でなければ生成元の命名が必要 + Finite Field in a of size 3^3 + sage: Zp(5) + 5-adic Ring with capped relative precision 20 + sage: sqrt(3) in QQbar # QQの代数的閉包(拡大) + True From 5fa0fc4cd9fbad037e9b32085cd64adb43108a29 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Fri, 11 Sep 2015 19:22:50 +0900 Subject: [PATCH 0833/1872] Minor modification on index.rst --- src/doc/ja/a_tour_of_sage/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/ja/a_tour_of_sage/index.rst b/src/doc/ja/a_tour_of_sage/index.rst index 2ffd822be17..46c8f23f845 100755 --- a/src/doc/ja/a_tour_of_sage/index.rst +++ b/src/doc/ja/a_tour_of_sage/index.rst @@ -32,7 +32,7 @@ Sageで :math:`2 \times 2` 行列の逆行列を計算してみよう. [ -2 1] [ 3/2 -1/2] -初等的な関数を積分してみる. +初等的な関数を積分する. :: @@ -131,4 +131,4 @@ Sageでは,1億を正整数の和として表す仕方を計算するにも5 Sageにおけるアルゴリズム群の利用 ================================== -Sageの利用とは,オープンソース計算アルゴリズムの世界最大級の集大成を利用することを意味している. +Sageを使うということは,オープンソース計算アルゴリズムの世界最大級の集大成を利用できることを意味している. From b925f7c8f3b82027ae18e05f0bd93e0e9969ae04 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 11 Sep 2015 08:43:38 -0700 Subject: [PATCH 0834/1872] trac 6101: add domain and codomain methods. change _repr_ for chain maps and chain homotopies. --- .../homology/algebraic_topological_model.py | 12 +- src/sage/homology/cell_complex.py | 2 +- src/sage/homology/chain_complex_homspace.py | 12 +- src/sage/homology/chain_complex_morphism.py | 114 ++++++++++++------ src/sage/homology/chain_homotopy.py | 63 ++++++++-- .../homology_vector_space_with_basis.py | 16 ++- .../homology/simplicial_complex_morphism.py | 20 ++- 7 files changed, 180 insertions(+), 59 deletions(-) diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index fd6e5c385ed..d36dacc7ff6 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -68,7 +68,7 @@ def algebraic_topological_model(K, base_ring=None): Given an algebraic topological model for `K`, it is then easy to compute cup products and cohomology operations on the cohomology - of `K`, as described in [G-DR]_ and [PR]_. + of `K`, as described in [G-DR03]_ and [PR]_. Implementation details: the cell complex `K` must have a :meth:`cell_complex.GenericCellComplex.n_cells` method from which @@ -87,7 +87,7 @@ def algebraic_topological_model(K, base_ring=None): Note that from the chain contraction ``\phi``, one can recover the chain maps `\pi` and `\iota` via ``phi.pi()`` and ``phi.iota()``. Then one can recover `C` and `M` from, for - example, ``phi.pi()._domain`` and ``phi.pi()._codomain``, + example, ``phi.pi().domain()`` and ``phi.pi().codomain()``, respectively. EXAMPLES:: @@ -116,7 +116,13 @@ def algebraic_topological_model(K, base_ring=None): sage: M.dual().degree_of_differential() 1 sage: phi.dual() - Chain homotopy between Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field and Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain homotopy between + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field + and Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field In degree 0, the inclusion of the homology `M` into the chain complex `C` sends the homology generator to a single vertex:: diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 6645dcff009..7329bf174b0 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -718,7 +718,7 @@ def algebraic_topological_model(self, base_ring=None): Note that from the chain contraction ``H``, one can recover the chain maps `\pi` and `\iota` via ``H.pi()`` and ``H.iota()``. Then one can recover `C` and `M` from, for - example, ``H.pi()._domain`` and ``H.pi()._codomain``, + example, ``H.pi().domain()`` and ``H.pi().codomain()``, respectively. EXAMPLES:: diff --git a/src/sage/homology/chain_complex_homspace.py b/src/sage/homology/chain_complex_homspace.py index d63f9e690e7..5cd61825cb8 100644 --- a/src/sage/homology/chain_complex_homspace.py +++ b/src/sage/homology/chain_complex_homspace.py @@ -23,7 +23,9 @@ sage: i = H.identity() sage: x = i.associated_chain_complex_morphism(augmented=True) sage: x - Chain complex morphism from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 4 nonzero terms over Integer Ring + To: Chain complex with at most 4 nonzero terms over Integer Ring sage: x._matrix_dictionary {-1: [1], 0: [1 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0] @@ -62,11 +64,15 @@ sage: i = A.identity() sage: x = i.associated_chain_complex_morphism() sage: x - Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: y = x*4 sage: z = y*y sage: (y+z) - Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: f = x._matrix_dictionary sage: C = S.chain_complex() sage: G = Hom(C,C) diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index 72c6c006f14..7ead3532c88 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -27,7 +27,9 @@ sage: G = Hom(C,C) sage: x = G(f) sage: x - Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] @@ -71,8 +73,9 @@ def is_ChainComplexMorphism(x): sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() sage: x # indirect doctest - Chain complex morphism from Chain complex with at most 7 nonzero terms over - Integer Ring to Chain complex with at most 7 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 7 nonzero terms over Integer Ring + To: Chain complex with at most 7 nonzero terms over Integer Ring sage: is_ChainComplexMorphism(x) True """ @@ -101,9 +104,9 @@ def __init__(self, matrices, C, D, check=True): sage: G = Hom(C,C) sage: x = G(f) sage: x - Chain complex morphism from Chain complex with at most 2 nonzero terms - over Integer Ring to Chain complex with at most 2 nonzero terms over - Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] @@ -117,9 +120,9 @@ def __init__(self, matrices, C, D, check=True): sage: Y = simplicial_complexes.Simplex(0) sage: g = Hom(X,Y)({0:0, 1:0}) sage: g.associated_chain_complex_morphism() - Chain complex morphism from Chain complex with at most 2 nonzero - terms over Integer Ring to Chain complex with at most 1 nonzero terms - over Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 1 nonzero terms over Integer Ring Check that an error is raised if the matrices are the wrong size:: @@ -130,7 +133,9 @@ def __init__(self, matrices, C, D, check=True): ... ValueError: matrix in degree 0 is not the right size sage: Hom(C,D)({0: matrix(2, 1, [1, 1])}) # 2x1 is right. - Chain complex morphism from Chain complex with at most 1 nonzero terms over Integer Ring to Chain complex with at most 1 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 1 nonzero terms over Integer Ring + To: Chain complex with at most 1 nonzero terms over Integer Ring """ if not C.base_ring() == D.base_ring(): raise NotImplementedError('morphisms between chain complexes of different' @@ -181,6 +186,34 @@ def __init__(self, matrices, C, D, check=True): self._domain = C self._codomain = D + def domain(self): + """ + The domain of this chain map + + EXAMPLES:: + + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f.domain() + Chain complex with at most 2 nonzero terms over Integer Ring + """ + return self._domain + + def codomain(self): + """ + The codomain of this chain map + + EXAMPLES:: + + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f.codomain() + Chain complex with at most 3 nonzero terms over Integer Ring + """ + return self._codomain + def in_degree(self, n): """ The matrix representing this morphism in degree n @@ -213,9 +246,9 @@ def in_degree(self, n): return self._matrix_dictionary[n] except KeyError: from sage.matrix.constructor import zero_matrix - rows = self._codomain.free_module_rank(n) - cols = self._domain.free_module_rank(n) - return zero_matrix(self._domain.base_ring(), rows, cols) + rows = self.codomain().free_module_rank(n) + cols = self.domain().free_module_rank(n) + return zero_matrix(self.domain().base_ring(), rows, cols) def dual(self): """ @@ -234,21 +267,23 @@ def dual(self): sage: f.in_degree(0) [1 1] sage: f.dual() - Chain complex morphism from Chain complex with at most 1 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 1 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: f.dual().in_degree(0) [1] [1] - sage: ascii_art(f._domain) + sage: ascii_art(f.domain()) [-1] [ 1] 0 <-- C_0 <----- C_1 <-- 0 - sage: ascii_art(f.dual()._codomain) + sage: ascii_art(f.dual().codomain()) [-1 1] 0 <-- C_1 <-------- C_0 <-- 0 """ matrix_dict = self._matrix_dictionary matrices = {i: matrix_dict[i].transpose() for i in matrix_dict} - return ChainComplexMorphism(matrices, self._codomain.dual(), self._domain.dual()) + return ChainComplexMorphism(matrices, self.codomain().dual(), self.domain().dual()) def __neg__(self): """ @@ -281,7 +316,7 @@ def __neg__(self): f = dict() for i in self._matrix_dictionary.keys(): f[i] = -self._matrix_dictionary[i] - return ChainComplexMorphism(f, self._domain, self._codomain) + return ChainComplexMorphism(f, self.domain(), self.codomain()) def __add__(self,x): """ @@ -311,12 +346,12 @@ def __add__(self,x): [0 0 0 2]} """ - if not isinstance(x,ChainComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._matrix_dictionary.keys() != x._matrix_dictionary.keys(): + if not isinstance(x,ChainComplexMorphism) or self.codomain() != x.codomain() or self.domain() != x.domain() or self._matrix_dictionary.keys() != x._matrix_dictionary.keys(): raise TypeError("Unsupported operation.") f = dict() for i in self._matrix_dictionary.keys(): f[i] = self._matrix_dictionary[i] + x._matrix_dictionary[i] - return ChainComplexMorphism(f, self._domain, self._codomain) + return ChainComplexMorphism(f, self.domain(), self.codomain()) def __mul__(self,x): """ @@ -383,25 +418,27 @@ def __mul__(self,x): sage: f = ChainComplexMorphism({}, C0, C1) sage: g = ChainComplexMorphism({}, C1, C2) sage: g * f - Chain complex morphism from Chain complex with at most 1 nonzero terms over Integer Ring to Chain complex with at most 1 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 1 nonzero terms over Integer Ring + To: Chain complex with at most 1 nonzero terms over Integer Ring sage: f._matrix_dictionary {0: [], 1: []} sage: g._matrix_dictionary {1: [], 2: []} """ - if not isinstance(x,ChainComplexMorphism) or self._domain != x._codomain: + if not isinstance(x,ChainComplexMorphism) or self.domain() != x.codomain(): try: - y = self._domain.base_ring()(x) + y = self.domain().base_ring()(x) except TypeError: raise TypeError("multiplication is not defined") f = dict() for i in self._matrix_dictionary: f[i] = self._matrix_dictionary[i] * y - return ChainComplexMorphism(f,self._domain,self._codomain) + return ChainComplexMorphism(f,self.domain(),self.codomain()) f = dict() for i in self._matrix_dictionary: f[i] = self._matrix_dictionary[i]*x.in_degree(i) - return ChainComplexMorphism(f,x._domain,self._codomain) + return ChainComplexMorphism(f,x.domain(),self.codomain()) def __rmul__(self,x): """ @@ -419,13 +456,13 @@ def __rmul__(self,x): False """ try: - y = self._domain.base_ring()(x) + y = self.domain().base_ring()(x) except TypeError: raise TypeError("multiplication is not defined") f = dict() for i in self._matrix_dictionary.keys(): f[i] = y * self._matrix_dictionary[i] - return ChainComplexMorphism(f,self._domain,self._codomain) + return ChainComplexMorphism(f,self.domain(),self.codomain()) def __sub__(self,x): """ @@ -468,8 +505,9 @@ def __eq__(self,x): sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() sage: x - Chain complex morphism from Trivial chain complex over Integer Ring - to Trivial chain complex over Integer Ring + Chain complex morphism + From: Trivial chain complex over Integer Ring + To: Trivial chain complex over Integer Ring sage: f = x._matrix_dictionary sage: C = S.chain_complex() sage: G = Hom(C,C) @@ -478,8 +516,8 @@ def __eq__(self,x): True """ return isinstance(x,ChainComplexMorphism) \ - and self._codomain == x._codomain \ - and self._domain == x._domain \ + and self.codomain() == x.codomain() \ + and self.domain() == x.domain() \ and self._matrix_dictionary == x._matrix_dictionary def _repr_(self): @@ -493,11 +531,13 @@ def _repr_(self): sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() sage: x - Chain complex morphism from Trivial chain complex over Integer Ring - to Trivial chain complex over Integer Ring + Chain complex morphism + From: Trivial chain complex over Integer Ring + To: Trivial chain complex over Integer Ring sage: x._repr_() - 'Chain complex morphism from Trivial chain complex over Integer Ring - to Trivial chain complex over Integer Ring' + 'Chain complex morphism\n From: Trivial chain complex over Integer Ring\n To: Trivial chain complex over Integer Ring' """ - return "Chain complex morphism from {} to {}".format(self._domain, self._codomain) - + s = 'Chain complex morphism' + s += '\n From: {}'.format(self.domain()) + s += '\n To: {}'.format(self.codomain()) + return s diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index f3e83c286a2..91efdf724e6 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -105,7 +105,9 @@ class ChainHomotopy(SageObject): Note that the maps `f` and `g` are stored in the attributes ``H._f`` and ``H._g``:: sage: H._f - Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: H._f.in_degree(0) [1] sage: H._g.in_degree(0) @@ -309,6 +311,38 @@ def in_degree(self, n): cols = self._domain.free_module_rank(n) return zero_matrix(self._domain.base_ring(), rows, cols) + def domain(self): + """ + The domain of this chain homotopy. + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: f = Hom(C, D)({}) + sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) + sage: H.domain() + Chain complex with at most 1 nonzero terms over Integer Ring + """ + return self._domain + + def codomain(self): + """ + The domain of this chain homotopy. + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: f = Hom(C, D)({}) + sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) + sage: H.codomain() + Chain complex with at most 1 nonzero terms over Integer Ring + """ + return self._codomain + def dual(self): """ Dual chain homotopy to this one. @@ -349,9 +383,18 @@ def _repr_(self): sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: g = Hom(C,D)({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1)}, f, g) - Chain homotopy between Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring and Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain homotopy between + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring + and Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring """ - return 'Chain homotopy between {} and {}'.format(self._f, self._g) + s = 'Chain homotopy between' + s += '\n {}'.format('\n '.join(self._f._repr_().split('\n'))) + s += '\n and {}'.format('\n '.join(self._g._repr_().split('\n'))) + return s class ChainContraction(ChainHomotopy): r""" @@ -478,7 +521,9 @@ def pi(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.pi() - Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field sage: phi.pi().in_degree(0) # Every vertex represents a homology class. [1 1 1 1] sage: phi.pi().in_degree(1) # No homology in degree 1. @@ -500,7 +545,9 @@ def iota(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.iota() - Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field Lifting the degree zero homology class gives a single vertex:: @@ -531,7 +578,9 @@ def dual(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.iota() - Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field Lifting the degree zero homology class gives a single vertex, but the degree zero cohomology class needs to be detected on @@ -559,6 +608,6 @@ def dual(self): [1] """ matrix_dict = self._matrix_dictionary - deg = self._domain.degree_of_differential() + deg = self.domain().degree_of_differential() matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} return ChainContraction(matrices, self.iota().dual(), self.pi().dual()) diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index f6e7ba78e90..b9d7dbb00f0 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -195,15 +195,25 @@ def contraction(self): sage: H1 = simplicial_complexes.Simplex(2).homology_with_basis(1, QQ) sage: H1.contraction() - Chain homotopy between Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field and Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain homotopy between + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field + and Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field From the chain contraction, one can also recover the maps `\pi` and `\iota`:: sage: phi = H1.contraction() sage: phi.pi() - Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 1 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 1 nonzero terms over Rational Field sage: phi.iota() - Chain complex morphism from Chain complex with at most 1 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 1 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field """ return self._contraction diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py index 0ff13d5f7f8..18853ec07a5 100644 --- a/src/sage/homology/simplicial_complex_morphism.py +++ b/src/sage/homology/simplicial_complex_morphism.py @@ -274,7 +274,9 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= Simplicial complex morphism {0: 0, 1: 1, 2: 2} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} sage: a = x.associated_chain_complex_morphism() sage: a - Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: a._matrix_dictionary {0: [0 0 0] [0 1 0] @@ -288,13 +290,21 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= [0 0 1], 2: []} sage: x.associated_chain_complex_morphism(augmented=True) - Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 4 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(cochain=True) - Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(augmented=True,cochain=True) - Chain complex morphism from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 4 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(base_ring=GF(11)) - Chain complex morphism from Chain complex with at most 2 nonzero terms over Finite Field of size 11 to Chain complex with at most 3 nonzero terms over Finite Field of size 11 + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Finite Field of size 11 + To: Chain complex with at most 3 nonzero terms over Finite Field of size 11 Some simplicial maps which reverse the orientation of a few simplices:: From d65ba8d4471ed0e64543a989f0d08c9e2fd02d40 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 11 Sep 2015 11:15:09 -0700 Subject: [PATCH 0835/1872] trac 19179: change _repr_ for chain maps, chain homotopies --- src/sage/homology/chain_complex_morphism.py | 114 +++++++++++++------- src/sage/homology/chain_homotopy.py | 63 +++++++++-- 2 files changed, 133 insertions(+), 44 deletions(-) diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index 72c6c006f14..7ead3532c88 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -27,7 +27,9 @@ sage: G = Hom(C,C) sage: x = G(f) sage: x - Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] @@ -71,8 +73,9 @@ def is_ChainComplexMorphism(x): sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() sage: x # indirect doctest - Chain complex morphism from Chain complex with at most 7 nonzero terms over - Integer Ring to Chain complex with at most 7 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 7 nonzero terms over Integer Ring + To: Chain complex with at most 7 nonzero terms over Integer Ring sage: is_ChainComplexMorphism(x) True """ @@ -101,9 +104,9 @@ def __init__(self, matrices, C, D, check=True): sage: G = Hom(C,C) sage: x = G(f) sage: x - Chain complex morphism from Chain complex with at most 2 nonzero terms - over Integer Ring to Chain complex with at most 2 nonzero terms over - Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] @@ -117,9 +120,9 @@ def __init__(self, matrices, C, D, check=True): sage: Y = simplicial_complexes.Simplex(0) sage: g = Hom(X,Y)({0:0, 1:0}) sage: g.associated_chain_complex_morphism() - Chain complex morphism from Chain complex with at most 2 nonzero - terms over Integer Ring to Chain complex with at most 1 nonzero terms - over Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 1 nonzero terms over Integer Ring Check that an error is raised if the matrices are the wrong size:: @@ -130,7 +133,9 @@ def __init__(self, matrices, C, D, check=True): ... ValueError: matrix in degree 0 is not the right size sage: Hom(C,D)({0: matrix(2, 1, [1, 1])}) # 2x1 is right. - Chain complex morphism from Chain complex with at most 1 nonzero terms over Integer Ring to Chain complex with at most 1 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 1 nonzero terms over Integer Ring + To: Chain complex with at most 1 nonzero terms over Integer Ring """ if not C.base_ring() == D.base_ring(): raise NotImplementedError('morphisms between chain complexes of different' @@ -181,6 +186,34 @@ def __init__(self, matrices, C, D, check=True): self._domain = C self._codomain = D + def domain(self): + """ + The domain of this chain map + + EXAMPLES:: + + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f.domain() + Chain complex with at most 2 nonzero terms over Integer Ring + """ + return self._domain + + def codomain(self): + """ + The codomain of this chain map + + EXAMPLES:: + + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f.codomain() + Chain complex with at most 3 nonzero terms over Integer Ring + """ + return self._codomain + def in_degree(self, n): """ The matrix representing this morphism in degree n @@ -213,9 +246,9 @@ def in_degree(self, n): return self._matrix_dictionary[n] except KeyError: from sage.matrix.constructor import zero_matrix - rows = self._codomain.free_module_rank(n) - cols = self._domain.free_module_rank(n) - return zero_matrix(self._domain.base_ring(), rows, cols) + rows = self.codomain().free_module_rank(n) + cols = self.domain().free_module_rank(n) + return zero_matrix(self.domain().base_ring(), rows, cols) def dual(self): """ @@ -234,21 +267,23 @@ def dual(self): sage: f.in_degree(0) [1 1] sage: f.dual() - Chain complex morphism from Chain complex with at most 1 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 1 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: f.dual().in_degree(0) [1] [1] - sage: ascii_art(f._domain) + sage: ascii_art(f.domain()) [-1] [ 1] 0 <-- C_0 <----- C_1 <-- 0 - sage: ascii_art(f.dual()._codomain) + sage: ascii_art(f.dual().codomain()) [-1 1] 0 <-- C_1 <-------- C_0 <-- 0 """ matrix_dict = self._matrix_dictionary matrices = {i: matrix_dict[i].transpose() for i in matrix_dict} - return ChainComplexMorphism(matrices, self._codomain.dual(), self._domain.dual()) + return ChainComplexMorphism(matrices, self.codomain().dual(), self.domain().dual()) def __neg__(self): """ @@ -281,7 +316,7 @@ def __neg__(self): f = dict() for i in self._matrix_dictionary.keys(): f[i] = -self._matrix_dictionary[i] - return ChainComplexMorphism(f, self._domain, self._codomain) + return ChainComplexMorphism(f, self.domain(), self.codomain()) def __add__(self,x): """ @@ -311,12 +346,12 @@ def __add__(self,x): [0 0 0 2]} """ - if not isinstance(x,ChainComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._matrix_dictionary.keys() != x._matrix_dictionary.keys(): + if not isinstance(x,ChainComplexMorphism) or self.codomain() != x.codomain() or self.domain() != x.domain() or self._matrix_dictionary.keys() != x._matrix_dictionary.keys(): raise TypeError("Unsupported operation.") f = dict() for i in self._matrix_dictionary.keys(): f[i] = self._matrix_dictionary[i] + x._matrix_dictionary[i] - return ChainComplexMorphism(f, self._domain, self._codomain) + return ChainComplexMorphism(f, self.domain(), self.codomain()) def __mul__(self,x): """ @@ -383,25 +418,27 @@ def __mul__(self,x): sage: f = ChainComplexMorphism({}, C0, C1) sage: g = ChainComplexMorphism({}, C1, C2) sage: g * f - Chain complex morphism from Chain complex with at most 1 nonzero terms over Integer Ring to Chain complex with at most 1 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 1 nonzero terms over Integer Ring + To: Chain complex with at most 1 nonzero terms over Integer Ring sage: f._matrix_dictionary {0: [], 1: []} sage: g._matrix_dictionary {1: [], 2: []} """ - if not isinstance(x,ChainComplexMorphism) or self._domain != x._codomain: + if not isinstance(x,ChainComplexMorphism) or self.domain() != x.codomain(): try: - y = self._domain.base_ring()(x) + y = self.domain().base_ring()(x) except TypeError: raise TypeError("multiplication is not defined") f = dict() for i in self._matrix_dictionary: f[i] = self._matrix_dictionary[i] * y - return ChainComplexMorphism(f,self._domain,self._codomain) + return ChainComplexMorphism(f,self.domain(),self.codomain()) f = dict() for i in self._matrix_dictionary: f[i] = self._matrix_dictionary[i]*x.in_degree(i) - return ChainComplexMorphism(f,x._domain,self._codomain) + return ChainComplexMorphism(f,x.domain(),self.codomain()) def __rmul__(self,x): """ @@ -419,13 +456,13 @@ def __rmul__(self,x): False """ try: - y = self._domain.base_ring()(x) + y = self.domain().base_ring()(x) except TypeError: raise TypeError("multiplication is not defined") f = dict() for i in self._matrix_dictionary.keys(): f[i] = y * self._matrix_dictionary[i] - return ChainComplexMorphism(f,self._domain,self._codomain) + return ChainComplexMorphism(f,self.domain(),self.codomain()) def __sub__(self,x): """ @@ -468,8 +505,9 @@ def __eq__(self,x): sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() sage: x - Chain complex morphism from Trivial chain complex over Integer Ring - to Trivial chain complex over Integer Ring + Chain complex morphism + From: Trivial chain complex over Integer Ring + To: Trivial chain complex over Integer Ring sage: f = x._matrix_dictionary sage: C = S.chain_complex() sage: G = Hom(C,C) @@ -478,8 +516,8 @@ def __eq__(self,x): True """ return isinstance(x,ChainComplexMorphism) \ - and self._codomain == x._codomain \ - and self._domain == x._domain \ + and self.codomain() == x.codomain() \ + and self.domain() == x.domain() \ and self._matrix_dictionary == x._matrix_dictionary def _repr_(self): @@ -493,11 +531,13 @@ def _repr_(self): sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() sage: x - Chain complex morphism from Trivial chain complex over Integer Ring - to Trivial chain complex over Integer Ring + Chain complex morphism + From: Trivial chain complex over Integer Ring + To: Trivial chain complex over Integer Ring sage: x._repr_() - 'Chain complex morphism from Trivial chain complex over Integer Ring - to Trivial chain complex over Integer Ring' + 'Chain complex morphism\n From: Trivial chain complex over Integer Ring\n To: Trivial chain complex over Integer Ring' """ - return "Chain complex morphism from {} to {}".format(self._domain, self._codomain) - + s = 'Chain complex morphism' + s += '\n From: {}'.format(self.domain()) + s += '\n To: {}'.format(self.codomain()) + return s diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index f3e83c286a2..ee17dbff578 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -105,7 +105,9 @@ class ChainHomotopy(SageObject): Note that the maps `f` and `g` are stored in the attributes ``H._f`` and ``H._g``:: sage: H._f - Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: H._f.in_degree(0) [1] sage: H._g.in_degree(0) @@ -309,6 +311,38 @@ def in_degree(self, n): cols = self._domain.free_module_rank(n) return zero_matrix(self._domain.base_ring(), rows, cols) + def domain(self): + """ + The domain of this chain homotopy. + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: f = Hom(C, D)({}) + sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) + sage: H.domain() + Chain complex with at most 1 nonzero terms over Integer Ring + """ + return self._domain + + def codomain(self): + """ + The domain of this chain homotopy. + + EXAMPLES:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: f = Hom(C, D)({}) + sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) + sage: H.codomain() + Chain complex with at most 1 nonzero terms over Integer Ring + """ + return self._codomain + def dual(self): """ Dual chain homotopy to this one. @@ -349,9 +383,18 @@ def _repr_(self): sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: g = Hom(C,D)({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1)}, f, g) - Chain homotopy between Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring and Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain homotopy between + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring + and Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring """ - return 'Chain homotopy between {} and {}'.format(self._f, self._g) + s = 'Chain homotopy between' + s += '\n {}'.format('\n '.join(self._f._repr_().split('\n'))) + s += '\n and {}'.format('\n '.join(self._g._repr_().split('\n'))) + return s class ChainContraction(ChainHomotopy): r""" @@ -478,7 +521,9 @@ def pi(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.pi() - Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field sage: phi.pi().in_degree(0) # Every vertex represents a homology class. [1 1 1 1] sage: phi.pi().in_degree(1) # No homology in degree 1. @@ -500,7 +545,9 @@ def iota(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.iota() - Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field Lifting the degree zero homology class gives a single vertex:: @@ -531,7 +578,9 @@ def dual(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.iota() - Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field Lifting the degree zero homology class gives a single vertex, but the degree zero cohomology class needs to be detected on @@ -559,6 +608,6 @@ def dual(self): [1] """ matrix_dict = self._matrix_dictionary - deg = self._domain.degree_of_differential() + deg = self.domain().degree_of_differential() matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} return ChainContraction(matrices, self.iota().dual(), self.pi().dual()) From f70e3a28db358383ee6f542b490963868ce9550f Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 11 Sep 2015 11:21:14 -0700 Subject: [PATCH 0836/1872] trac 19179: doctest fixes for _repr_ changes --- src/sage/homology/chain_complex_homspace.py | 12 ++++++++--- .../homology/simplicial_complex_morphism.py | 20 ++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/sage/homology/chain_complex_homspace.py b/src/sage/homology/chain_complex_homspace.py index d63f9e690e7..5cd61825cb8 100644 --- a/src/sage/homology/chain_complex_homspace.py +++ b/src/sage/homology/chain_complex_homspace.py @@ -23,7 +23,9 @@ sage: i = H.identity() sage: x = i.associated_chain_complex_morphism(augmented=True) sage: x - Chain complex morphism from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 4 nonzero terms over Integer Ring + To: Chain complex with at most 4 nonzero terms over Integer Ring sage: x._matrix_dictionary {-1: [1], 0: [1 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0] @@ -62,11 +64,15 @@ sage: i = A.identity() sage: x = i.associated_chain_complex_morphism() sage: x - Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: y = x*4 sage: z = y*y sage: (y+z) - Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: f = x._matrix_dictionary sage: C = S.chain_complex() sage: G = Hom(C,C) diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py index 75b4d0172a2..df999d572ae 100644 --- a/src/sage/homology/simplicial_complex_morphism.py +++ b/src/sage/homology/simplicial_complex_morphism.py @@ -274,7 +274,9 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= Simplicial complex morphism {0: 0, 1: 1, 2: 2} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} sage: a = x.associated_chain_complex_morphism() sage: a - Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: a._matrix_dictionary {0: [0 0 0] [0 1 0] @@ -288,13 +290,21 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= [0 0 1], 2: []} sage: x.associated_chain_complex_morphism(augmented=True) - Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 4 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(cochain=True) - Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(augmented=True,cochain=True) - Chain complex morphism from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring + Chain complex morphism + From: Chain complex with at most 4 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(base_ring=GF(11)) - Chain complex morphism from Chain complex with at most 2 nonzero terms over Finite Field of size 11 to Chain complex with at most 3 nonzero terms over Finite Field of size 11 + Chain complex morphism + From: Chain complex with at most 2 nonzero terms over Finite Field of size 11 + To: Chain complex with at most 3 nonzero terms over Finite Field of size 11 Some simplicial maps which reverse the orientation of a few simplices:: From 6cd5b7ce9415262fef8c2402130273e159d7607f Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 11 Sep 2015 11:24:27 -0700 Subject: [PATCH 0837/1872] trac 6102: doctest fixes for _repr_ changes --- src/sage/homology/algebraic_topological_model.py | 12 +++++++++--- src/sage/homology/cell_complex.py | 2 +- .../homology/homology_vector_space_with_basis.py | 16 +++++++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index fd6e5c385ed..d36dacc7ff6 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -68,7 +68,7 @@ def algebraic_topological_model(K, base_ring=None): Given an algebraic topological model for `K`, it is then easy to compute cup products and cohomology operations on the cohomology - of `K`, as described in [G-DR]_ and [PR]_. + of `K`, as described in [G-DR03]_ and [PR]_. Implementation details: the cell complex `K` must have a :meth:`cell_complex.GenericCellComplex.n_cells` method from which @@ -87,7 +87,7 @@ def algebraic_topological_model(K, base_ring=None): Note that from the chain contraction ``\phi``, one can recover the chain maps `\pi` and `\iota` via ``phi.pi()`` and ``phi.iota()``. Then one can recover `C` and `M` from, for - example, ``phi.pi()._domain`` and ``phi.pi()._codomain``, + example, ``phi.pi().domain()`` and ``phi.pi().codomain()``, respectively. EXAMPLES:: @@ -116,7 +116,13 @@ def algebraic_topological_model(K, base_ring=None): sage: M.dual().degree_of_differential() 1 sage: phi.dual() - Chain homotopy between Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field and Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain homotopy between + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field + and Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field In degree 0, the inclusion of the homology `M` into the chain complex `C` sends the homology generator to a single vertex:: diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 6645dcff009..7329bf174b0 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -718,7 +718,7 @@ def algebraic_topological_model(self, base_ring=None): Note that from the chain contraction ``H``, one can recover the chain maps `\pi` and `\iota` via ``H.pi()`` and ``H.iota()``. Then one can recover `C` and `M` from, for - example, ``H.pi()._domain`` and ``H.pi()._codomain``, + example, ``H.pi().domain()`` and ``H.pi().codomain()``, respectively. EXAMPLES:: diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index f6e7ba78e90..b9d7dbb00f0 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -195,15 +195,25 @@ def contraction(self): sage: H1 = simplicial_complexes.Simplex(2).homology_with_basis(1, QQ) sage: H1.contraction() - Chain homotopy between Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field and Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain homotopy between + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field + and Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field From the chain contraction, one can also recover the maps `\pi` and `\iota`:: sage: phi = H1.contraction() sage: phi.pi() - Chain complex morphism from Chain complex with at most 3 nonzero terms over Rational Field to Chain complex with at most 1 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 1 nonzero terms over Rational Field sage: phi.iota() - Chain complex morphism from Chain complex with at most 1 nonzero terms over Rational Field to Chain complex with at most 3 nonzero terms over Rational Field + Chain complex morphism + From: Chain complex with at most 1 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field """ return self._contraction From 048061cb41ace2fb9563cf99bb2f7f9fcbe80516 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 11 Sep 2015 11:38:58 -0700 Subject: [PATCH 0838/1872] trac 6101: add homology_morphism to ref manual --- src/doc/en/reference/homology/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/homology/index.rst b/src/doc/en/reference/homology/index.rst index c948e30c555..0524030d31c 100644 --- a/src/doc/en/reference/homology/index.rst +++ b/src/doc/en/reference/homology/index.rst @@ -26,6 +26,7 @@ cell complexes. sage/homology/homology_group sage/homology/homology_vector_space_with_basis sage/homology/algebraic_topological_model + sage/homology/homology_morphism sage/homology/matrix_utils sage/interfaces/chomp From 9791f5bf370666d65b8e5e9237460b49dc64d089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 11 Sep 2015 21:49:07 +0200 Subject: [PATCH 0839/1872] trac #18937 new patchbot 2.4.3 with enhanced trust control --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index e801e6e5156..b4af6341a82 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=9f7d1d3df8dbb8821d8d077f3ffb6ba94d464372 -md5=54155d5531d615928011387185f48b34 -cksum=3140942259 +sha1=15118651d1d2d32327d425528b4d4fc4b1cac6aa +md5=a01538fa40d938392b4bd6d5a7c60bb6 +cksum=1454859190 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 8e8299dcc06..35cee72dcbf 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.2 +2.4.3 From 914341e07afd70770cb8299989924bbf84e77552 Mon Sep 17 00:00:00 2001 From: Valentin Buciumas Date: Fri, 11 Sep 2015 16:24:14 -0700 Subject: [PATCH 0840/1872] last patch --- .../root_system/integrable_representations.py | 135 ++++++++++++++++-- 1 file changed, 123 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index ab8842f370f..38a0fcc6023 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -5,6 +5,7 @@ #***************************************************************************** # Copyright (C) 2014, 2105 Daniel Bump # Travis Scrimshaw +# Twisted Affine case: Valentin Buciumas # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ @@ -20,7 +21,7 @@ from sage.combinat.root_system.weyl_characters import WeylCharacterRing # TODO: Make this a proper parent and implement actions -class IntegrableRepresentation(UniqueRepresentation, CategoryObject): +class IntegrableRepresentation(CategoryObject, UniqueRepresentation): r""" An irreducible integrable highest weight representation of an affine Lie algebra. @@ -42,6 +43,9 @@ class IntegrableRepresentation(UniqueRepresentation, CategoryObject): .. [KacPeterson] Kac and Peterson. *Infinite-dimensional Lie algebras, theta functions and modular forms*. Adv. in Math. 53 (1984), no. 2, 125-264. + + .. [Carter] Carter, *Lie algebras of finite and affine type*. Cambridge + University Press, 2005 If `\Lambda` is a dominant integral weight for an affine root system, there exists a unique integrable representation `V=V_\Lambda` of highest @@ -147,6 +151,28 @@ class IntegrableRepresentation(UniqueRepresentation, CategoryObject): 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 + + Two examples for twisted affine types:: + + sage: Lambda = RootSystem(['G',2,1]).dual.weight_lattice(extended=true).fundamental_weights() + sage: V = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[2]) + sage: V.print_strings() # long time + 6*Lambdacheck[0]: 4 28 100 320 944 2460 6064 14300 31968 69020 144676 293916 + 4*Lambdacheck[0] + Lambdacheck[2]: 4 22 84 276 800 2124 5288 12470 28116 61056 128304 261972 + 3*Lambdacheck[0] + Lambdacheck[1]: 2 16 58 192 588 1568 3952 9520 21644 47456 100906 207536 + Lambdacheck[0] + Lambdacheck[1] + Lambdacheck[2]: 1 6 26 94 294 832 2184 5388 12634 28390 61488 128976 + 2*Lambdacheck[1] - deltacheck: 2 8 32 120 354 980 2576 6244 14498 32480 69776 145528 + 2*Lambdacheck[0] + 2*Lambdacheck[2]: 2 12 48 164 492 1344 3428 8256 18960 41844 89208 184512 + 3*Lambdacheck[2] - deltacheck: 4 16 60 208 592 1584 4032 9552 21728 47776 101068 207888 + sage: Lambda = RootSystem(['A',6,2]).weight_lattice(extended=true).fundamental_weights() + sage: V = IntegrableRepresentation(Lambda[0]+2*Lambda[1]) + sage: V.print_strings() # long time + 5*Lambda[0]: 3 42 378 2508 13707 64650 272211 1045470 3721815 12425064 39254163 118191378 + 3*Lambda[0] + Lambda[2]: 1 23 234 1690 9689 47313 204247 800029 2893198 9786257 31262198 95035357 + Lambda[0] + 2*Lambda[1]: 1 14 154 1160 6920 34756 153523 612354 2248318 7702198 24875351 76341630 + Lambda[0] + Lambda[1] + Lambda[3] - 2*delta: 6 87 751 4779 25060 113971 464842 1736620 6034717 19723537 61152367 181068152 + Lambda[0] + 2*Lambda[2] - 2*delta: 3 54 499 3349 18166 84836 353092 1341250 4725259 15625727 48938396 146190544 + Lambda[0] + 2*Lambda[3] - 4*delta: 15 195 1539 9186 45804 200073 789201 2866560 9723582 31120281 94724550 275919741 """ def __init__(self, Lam): """ @@ -160,16 +186,13 @@ def __init__(self, Lam): """ CategoryObject.__init__(self, base=ZZ, category=Modules(ZZ)) - 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() 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() @@ -594,7 +617,9 @@ def _freudenthal_roots_real(self, nu): r""" Return the set of real positive roots `\alpha \in \Delta^+` in ``self`` such that `\nu - \alpha \in Q^+`. - + + See [Kac] Proposition 6.3 for the way to compute the set of real roots for twisted affine case. + INPUT: - ``nu`` -- an element in `Q` @@ -616,9 +641,52 @@ def _freudenthal_roots_real(self, nu): for al in self._classical_positive_roots: 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): - ret.append(al+ir) + """ + changed the way you compute the set of real roots for twisted affine case, see [Kac] page 83 + """ + from sage.combinat.root_system.cartan_type import CartanType + if self._cartan_type == CartanType(['B',self._classical_rank,1]).dual() or self._cartan_type == CartanType(['C',self._classical_rank,1]).dual() or self._cartan_type == CartanType(['F',4,1]).dual(): #case A^2_{2l-1} or case D^2_{l+1} or case E^2_6: + for al in self._classical_roots: + if self._inner_qq(al,al) == 2: #if al is a short root: + for ir in self._freudenthal_roots_imaginary(nu-al): + ret.append(al+ir) + else: + for ir in self._freudenthal_roots_imaginary(nu-al): + if 2*ir in self._freudenthal_roots_imaginary(nu-al): + ret.append(al+2*ir) + + elif self._cartan_type == CartanType(['BC',self._classical_rank,2]): #case A^2_{2l} + for al in self._classical_roots: + if self._inner_qq(al,al) == 2: #if al is a short root: + for ir in self._freudenthal_roots_imaginary(nu-al): + ret.append(al+ir) + else: + for ir in self._freudenthal_roots_imaginary(nu-al): + if 2*ir in self._freudenthal_roots_imaginary(nu-al): + ret.append(al+2*ir) + for ir in self._freudenthal_roots_imaginary(2*nu-al)[::2]: + n = [x//2 for x in self._from_weight_helper(al+ir)] + alpha = self._Q.simple_roots() + if sum([val*alpha[i] for i,val in enumerate(n)]) not in ret: + ret.append(sum([val*alpha[i] for i,val in enumerate(n)])) + + elif self._cartan_type == CartanType(['D',4,3]) or self._cartan_type == CartanType(['G',2,1]).dual(): # case D^3_4 in the Kac/Stembridge notation + for al in self._classical_roots: + if self._inner_qq(al,al) == 2: #if al is a short root: + for ir in self._freudenthal_roots_imaginary(nu-al): + ret.append(al+ir) + else: + for ir in self._freudenthal_roots_imaginary(nu-al): + if 3*ir in self._freudenthal_roots_imaginary(nu-al): + ret.append(al+3*ir) + + + else: # untwisted case + 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): @@ -654,7 +722,11 @@ def _m_freudenthal(self, n): """ Compute the weight multiplicity using the Freudenthal multiplicity formula in ``self``. - + The multiplicities of the imaginary roots for the twisted + affine case are different than those for the untwisted case, + see [Carter]_ Corollary 18.10 for general type and Corollary + 18.15 for `A^2_{2l}` + EXAMPLES:: sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() @@ -672,10 +744,49 @@ 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): 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) + + from sage.combinat.root_system.cartan_type import CartanType + + if self._cartan_type == CartanType(['B',self._classical_rank,1]).dual(): + list = self._freudenthal_roots_imaginary(self._Lam - mu) + dict = {key:list[key-1] for key in range(1,len(list)+1)} + for k in dict: # k is a positive number, dict[k] is k*delta + num += (self._classical_rank-k%2) * self._freudenthal_accum(mu, dict[k]) + + + elif self._cartan_type == CartanType(['BC',self._classical_rank,2]): + for al in self._freudenthal_roots_imaginary(self._Lam - mu): + num += self._classical_rank * self._freudenthal_accum(mu, al) + + elif self._cartan_type == CartanType(['C',self._classical_rank,1]).dual(): + list = self._freudenthal_roots_imaginary(self._Lam - mu) + dict = {key:list[key-1] for key in range(1,len(list)+1)} + for k in dict: # k is a positive number, dict[k] is k*delta + num += (self._classical_rank-(self._classical_rank -1)*(k%2)) * self._freudenthal_accum(mu, dict[k]) + + elif self._cartan_type == CartanType(['F',4,1]).dual(): + list = self._freudenthal_roots_imaginary(self._Lam - mu) + dict = {key:list[key-1] for key in range(1,len(list)+1)} + for k in dict: # k is a positive number, dict[k] is k*delta + num += (4 - 2*(k%2)) * self._freudenthal_accum(mu, dict[k]) + + elif self._cartan_type == CartanType(['D',4,3]) or self._cartan_type == CartanType(['G',2,1]).dual(): + list = self._freudenthal_roots_imaginary(self._Lam - mu) + dict = {key:list[key-1] for key in range(1,len(list)+1)} + for k in dict: # k is a positive number, dict[k] is k*delta + if k%3 == 0: + num += 2 * self._freudenthal_accum(mu, dict[k]) + else: + num += self._freudenthal_accum(mu, dict[k]) + + else: + for al in self._freudenthal_roots_imaginary(self._Lam - mu): + num += self._classical_rank * self._freudenthal_accum(mu, al) + + try: return ZZ(num / den) except TypeError: From 635279f80bc2d818526698b875a8ee37466900c9 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 11 Sep 2015 22:33:24 -0300 Subject: [PATCH 0841/1872] Trac 18411: a bounded_number_of_tuples function --- src/sage/misc/misc.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index e3a3e453223..915eaf14e93 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -1722,7 +1722,26 @@ def random_sublist(X, s): return [a for a in X if random.random() <= s] +def bounded_number_of_tuples(elements, repeat, bound): + r""" + Return at most ``bound`` number of ``repeat``-tuples of ``elements``. + + TESTS:: + sage: from sage.misc.misc import bounded_number_of_tuples + sage: l = bounded_number_of_tuples([0,1,2,3], 2, 3) + sage: l # random + [(0,3), (1,2), (3,4)] + sage: len(l) + 3 + """ + from itertools import product + tuples = product(elements, repeat=repeat) + if len(elements) ** repeat < bound: + return tuples + else: + from sage.misc.prandom import sample + return sample(list(tuples), bound) def powerset(X): r""" From 1b609030c2cc72a286e1ddc2576b7e6eb4389f9a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 7 Sep 2015 16:37:56 -0300 Subject: [PATCH 0842/1872] Trac 18411: remove occurrences of CartesianProduct We remove occurrences of CartesianProduct in the code and examples. Depending on the context, it is replaced by cartesian_product or itertools.product. --- src/sage/algebras/clifford_algebra.py | 10 ++--- src/sage/algebras/schur_algebra.py | 4 +- src/sage/categories/additive_semigroups.py | 4 +- ...distributive_magmas_and_additive_magmas.py | 4 +- src/sage/categories/domains.py | 8 ++-- src/sage/categories/euclidean_domains.py | 43 +++++++++---------- src/sage/categories/semigroups.py | 4 +- src/sage/categories/sets_cat.py | 18 ++------ src/sage/combinat/affine_permutation.py | 18 +++++--- src/sage/combinat/composition.py | 13 ++++-- src/sage/combinat/composition_signed.py | 6 +-- src/sage/combinat/crystals/tensor_product.py | 4 +- src/sage/combinat/enumerated_sets.py | 2 +- src/sage/combinat/integer_vector.py | 4 +- src/sage/combinat/k_tableau.py | 4 +- src/sage/combinat/ncsf_qsym/ncsf.py | 3 +- src/sage/combinat/ordered_tree.py | 6 ++- src/sage/combinat/partition_tuple.py | 5 ++- src/sage/combinat/quickref.py | 2 +- .../rigged_configurations/kleber_tree.py | 7 ++- .../rigged_configurations.py | 20 ++++----- src/sage/combinat/root_system/plot.py | 4 +- .../root_system/root_lattice_realizations.py | 13 +++--- src/sage/combinat/set_partition.py | 5 +-- src/sage/combinat/similarity_class_type.py | 5 +-- .../combinat/species/composition_species.py | 26 +++++------ src/sage/game_theory/normal_form_game.py | 5 +-- .../hyperplane_arrangement/arrangement.py | 14 +++--- src/sage/geometry/integral_points.pyx | 7 +-- src/sage/geometry/polyhedron/base.py | 9 ++-- src/sage/geometry/polyhedron/base_ZZ.py | 4 +- src/sage/misc/sage_unittest.py | 4 +- src/sage/repl/image.py | 5 ++- src/sage/rings/padics/padic_generic.py | 37 ++++++---------- src/sage/rings/quotient_ring.py | 8 ++-- src/sage/schemes/toric/divisor.py | 24 +++++------ src/sage/schemes/toric/points.py | 26 +++++------ src/sage/sets/family.py | 5 +-- src/sage/sets/finite_set_maps.py | 5 ++- src/sage/symbolic/random_tests.py | 34 ++++++++------- .../tests/french_book/nonlinear_doctest.py | 3 +- 41 files changed, 214 insertions(+), 218 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index b419d985be3..46576ec137f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1830,9 +1830,9 @@ def lifted_bilinear_form(self, M): sage: M = Matrix(QQ, [[1, 2, 3], [2, 3, 4], [3, 4, 5]]) sage: Eform = E.lifted_bilinear_form(M) sage: Eform - Bilinear Form from Cartesian product of The exterior algebra of rank 3 over - Rational Field, The exterior algebra of rank 3 over Rational Field to - Rational Field + Bilinear Form from The exterior algebra of rank 3 over Rational + Field (+) The exterior algebra of rank 3 over Rational Field to + Rational Field sage: Eform(x*y, y*z) -1 sage: Eform(x*y, y) @@ -1903,8 +1903,8 @@ def lifted_form(x, y): # typing (:trac:`17124`). result += cx * cy * matr.determinant() return result - from sage.combinat.cartesian_product import CartesianProduct - return PoorManMap(lifted_form, domain=CartesianProduct(self, self), + from sage.categories.cartesian_product import cartesian_product + return PoorManMap(lifted_form, domain=cartesian_product([self, self]), codomain=self.base_ring(), name="Bilinear Form") diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 7ef9cfabbde..83e05c2ee04 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -29,11 +29,11 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +import itertools from sage.categories.all import AlgebrasWithBasis from sage.categories.rings import Rings 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 @@ -465,7 +465,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 itertools.product(range(1, self._n + 1), repeat=self._r): if schur_representative_from_index(i, v) == xi: ret.append(tuple(i)) return self.sum_of_monomials(ret) diff --git a/src/sage/categories/additive_semigroups.py b/src/sage/categories/additive_semigroups.py index 7f9c2de9b5c..755b6d0fcaf 100644 --- a/src/sage/categories/additive_semigroups.py +++ b/src/sage/categories/additive_semigroups.py @@ -80,8 +80,8 @@ def _test_additive_associativity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from sage.combinat.cartesian_product import CartesianProduct - for x,y,z in tester.some_elements(CartesianProduct(S,S,S)): + from itertools import product + for x,y,z in product(S, repeat=3): tester.assert_((x + y) + z == x + (y + z)) class Homsets(HomsetsCategory): diff --git a/src/sage/categories/distributive_magmas_and_additive_magmas.py b/src/sage/categories/distributive_magmas_and_additive_magmas.py index ebcb996bdaf..463b2e92dd7 100644 --- a/src/sage/categories/distributive_magmas_and_additive_magmas.py +++ b/src/sage/categories/distributive_magmas_and_additive_magmas.py @@ -73,8 +73,8 @@ def _test_distributivity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from sage.combinat.cartesian_product import CartesianProduct - for x,y,z in tester.some_elements(CartesianProduct(S,S,S)): + from sage.misc.misc import bounded_number_of_tuples + for x,y,z in bounded_number_of_tuples(tester.some_elements(), 3, tester._max_runs): # left distributivity tester.assert_(x * (y + z) == (x * y) + (x * z)) # right distributivity diff --git a/src/sage/categories/domains.py b/src/sage/categories/domains.py index 2e9b9ec2db1..bd59791a8fd 100644 --- a/src/sage/categories/domains.py +++ b/src/sage/categories/domains.py @@ -84,10 +84,10 @@ def _test_zero_divisors(self, **options): # Filter out zero S = [s for s in tester.some_elements() if not s.is_zero()] - from sage.combinat.cartesian_product import CartesianProduct - for a,b in tester.some_elements(CartesianProduct(S,S)): - p = a * b - tester.assertFalse(p.is_zero()) + for a in S: + for b in S: + p = a * b + tester.assertFalse(p.is_zero()) class ElementMethods: pass diff --git a/src/sage/categories/euclidean_domains.py b/src/sage/categories/euclidean_domains.py index dc7364599ad..75ed869b14f 100644 --- a/src/sage/categories/euclidean_domains.py +++ b/src/sage/categories/euclidean_domains.py @@ -87,16 +87,16 @@ def _test_euclidean_degree(self, **options): tester.assertGreaterEqual(a.euclidean_degree(), min_degree) tester.assertEqual(a.euclidean_degree() == min_degree, a.is_unit()) - from sage.combinat.cartesian_product import CartesianProduct - for a,b in tester.some_elements(CartesianProduct(S,S)): - p = a * b - # For rings which are not exact, we might get something that - # acts like a zero divisor. - # Therefore we skip the product if it evaluates to zero. - # Let the category of Domains handle the test for zero divisors. - if p.is_zero(): - continue - tester.assertLessEqual(a.euclidean_degree(), p.euclidean_degree()) + for a in S: + for b in S: + p = a * b + # For rings which are not exact, we might get something that + # acts like a zero divisor. + # Therefore we skip the product if it evaluates to zero. + # Let the category of Domains handle the test for zero divisors. + if p.is_zero(): + continue + tester.assertLessEqual(a.euclidean_degree(), p.euclidean_degree()) def _test_quo_rem(self, **options): r""" @@ -114,18 +114,17 @@ def _test_quo_rem(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - - from sage.combinat.cartesian_product import CartesianProduct - for a,b in tester.some_elements(CartesianProduct(S,S)): - if b.is_zero(): - tester.assertRaises(ZeroDivisionError, lambda: a.quo_rem(b)) - else: - q,r = a.quo_rem(b) - tester.assertIn(q, self) - tester.assertIn(r, self) - tester.assertEqual(a,q*b+r) - if r != 0: - tester.assertLess(r.euclidean_degree(), b.euclidean_degree()) + for a in S: + for b in S: + if b.is_zero(): + tester.assertRaises(ZeroDivisionError, lambda: a.quo_rem(b)) + else: + q,r = a.quo_rem(b) + tester.assertIn(q, self) + tester.assertIn(r, self) + tester.assertEqual(a,q*b+r) + if r != 0: + tester.assertLess(r.euclidean_degree(), b.euclidean_degree()) class ElementMethods: @abstract_method diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index e230ff38bb8..24f21e7d132 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -114,8 +114,8 @@ def _test_associativity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from sage.combinat.cartesian_product import CartesianProduct - for x,y,z in tester.some_elements(CartesianProduct(S,S,S)): + from itertools import product + for x,y,z in product(S, repeat=3): tester.assert_((x * y) * z == x * (y * z)) @abstract_method(optional=True) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 82072b367b3..d2ae0e45569 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1188,13 +1188,8 @@ def _test_elements_eq_symmetric(self, **options): tester = self._tester(**options) S = list(tester.some_elements()) + [None, 0] n = tester._max_runs - from sage.combinat.cartesian_product import CartesianProduct - S = CartesianProduct(S,S) - if len(S) > n: - from random import sample - S = sample(S, n) - - for x, y in S: + from sage.misc.misc import bounded_number_of_tuples + for x,y in bounded_number_of_tuples(S, 2, tester._max_runs): tester.assertEqual(x==y, y==x, LazyFormat("non symmetric equality: %s but %s")%( print_compare(x, y), print_compare(y, x))) @@ -1280,14 +1275,9 @@ def _test_elements_neq(self, **options): """ tester = self._tester(**options) S = list(tester.some_elements()) + [None, 0] - n = tester._max_runs - from sage.combinat.cartesian_product import CartesianProduct - S = CartesianProduct(S,S) - if len(S) > n: - from random import sample - S = sample(S, n) - for x,y in S: + from sage.misc.misc import bounded_number_of_tuples + for x,y in bounded_number_of_tuples(S, 2, tester._max_runs): tester.assertNotEqual(x == y, x != y, LazyFormat("__eq__ and __ne__ inconsistency:\n" " %s == %s returns %s but %s != %s returns %s")%( diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 42910e4469d..b9ad2739432 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -778,16 +778,18 @@ def to_lehmer_code(self, typ='decreasing', side='right'): EXAMPLES:: + sage: import itertools sage: A=AffinePermutationGroup(['A',7,1]) sage: p=A([3, -1, 0, 6, 5, 4, 10, 9]) - sage: CP=CartesianProduct( ('increasing','decreasing'),('left','right') ) - sage: for a in CP: - ....: p.to_lehmer_code(a[0],a[1]) + sage: orders = ('increasing','decreasing') + sage: sides = ('left','right') + sage: for o,s in itertools.product(orders, sides): + ....: p.to_lehmer_code(o,s) [2, 3, 2, 0, 1, 2, 0, 0] [2, 2, 0, 0, 2, 1, 0, 3] [3, 1, 0, 0, 2, 1, 0, 3] [0, 3, 3, 0, 1, 2, 0, 1] - sage: for a in CP: + sage: for a in itertools.product(orders, sides): ....: A.from_lehmer_code(p.to_lehmer_code(a[0],a[1]), a[0],a[1])==p True True @@ -2198,15 +2200,17 @@ def from_lehmer_code(self, C, typ='decreasing', side='right'): EXAMPLES:: + sage: import itertools sage: A=AffinePermutationGroup(['A',7,1]) sage: p=A([3, -1, 0, 6, 5, 4, 10, 9]) sage: p.to_lehmer_code() [0, 3, 3, 0, 1, 2, 0, 1] sage: A.from_lehmer_code(p.to_lehmer_code())==p True - sage: CP=CartesianProduct( ('increasing','decreasing'),('left','right') ) - sage: for a in CP: - ....: A.from_lehmer_code(p.to_lehmer_code(a[0],a[1]),a[0],a[1])==p + sage: orders = ('increasing','decreasing') + sage: sides = ('left','right') + sage: for o,s in itertools.product(orders,sides): + ....: A.from_lehmer_code(p.to_lehmer_code(o,s),o,s)==p True True True diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 028a1d5d980..7dcf7b93d73 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -33,9 +33,10 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent +from sage.sets.set import Set from sage.rings.all import ZZ from combinat import CombinatorialElement -from cartesian_product import CartesianProduct +from sage.categories.cartesian_product import cartesian_product from integer_list import IntegerListsLex import __builtin__ from sage.rings.integer import Integer @@ -748,10 +749,16 @@ def finer(self): sage: C = Composition([3,2]).finer() sage: C.cardinality() 8 - sage: list(C) + sage: C.list() [[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 2, 1, 1], [1, 2, 2], [2, 1, 1, 1], [2, 1, 2], [3, 1, 1], [3, 2]] + + sage: Composition([]).finer() + {[]} """ - return CartesianProduct(*[Compositions(i) for i in self]).map(Composition.sum) + if not self: + return Set([self]) + else: + return cartesian_product([Compositions(i) for i in self]).map(Composition.sum) def is_finer(self, co2): """ diff --git a/src/sage/combinat/composition_signed.py b/src/sage/combinat/composition_signed.py index 918fcf2241f..0b23b034d2f 100644 --- a/src/sage/combinat/composition_signed.py +++ b/src/sage/combinat/composition_signed.py @@ -16,8 +16,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +import itertools + from composition import Compositions_n, Composition -import cartesian_product from sage.rings.all import Integer from sage.rings.arith import binomial import __builtin__ @@ -130,8 +131,7 @@ def __iter__(self): """ for comp in Compositions_n.__iter__(self): l = len(comp) - a = [[1,-1] for i in range(l)] - for sign in cartesian_product.CartesianProduct(*a): + for sign in itertools.product([-1,1], repeat=l): yield [ sign[i]*comp[i] for i in range(l)] from sage.structure.sage_object import register_unpickle_override diff --git a/src/sage/combinat/crystals/tensor_product.py b/src/sage/combinat/crystals/tensor_product.py index 8c746d07ebc..2a18470946a 100644 --- a/src/sage/combinat/crystals/tensor_product.py +++ b/src/sage/combinat/crystals/tensor_product.py @@ -36,11 +36,11 @@ from sage.structure.element import parent from sage.structure.global_options import GlobalOptions from sage.categories.category import Category +from sage.categories.cartesian_product import cartesian_product from sage.categories.classical_crystals import ClassicalCrystals from sage.categories.regular_crystals import RegularCrystals from sage.categories.sets_cat import Sets from sage.combinat.root_system.cartan_type import CartanType -from sage.combinat.cartesian_product import CartesianProduct from sage.combinat.combinat import CombinatorialElement from sage.combinat.partition import Partition from sage.combinat.tableau import Tableau @@ -808,7 +808,7 @@ def __init__(self, crystals, **options): raise ValueError("you need to specify the Cartan type if the tensor product list is empty") else: self._cartan_type = crystals[0].cartan_type() - self.cartesian_product = CartesianProduct(*self.crystals) + self.cartesian_product = cartesian_product(self.crystals) self.module_generators = self def _repr_(self): diff --git a/src/sage/combinat/enumerated_sets.py b/src/sage/combinat/enumerated_sets.py index a39220a900e..45302254778 100644 --- a/src/sage/combinat/enumerated_sets.py +++ b/src/sage/combinat/enumerated_sets.py @@ -15,7 +15,7 @@ - :class:`~sage.combinat.subset.Subsets`, :class:`~sage.combinat.combination.Combinations` - :class:`~sage.combinat.permutation.Arrangements`, :class:`~sage.combinat.tuple.Tuples` - :class:`~sage.sets.finite_enumerated_set.FiniteEnumeratedSet` -- :class:`~DisjointUnionEnumeratedSets`, :class:`~CartesianProduct` +- :class:`~DisjointUnionEnumeratedSets` Integer lists ------------- diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index b11ce3136da..f159ed56e7b 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -27,6 +27,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +import itertools import misc from __builtin__ import list as builtinlist from sage.categories.enumerated_sets import EnumeratedSets @@ -34,7 +35,6 @@ from sage.rings.integer import Integer from sage.rings.arith import binomial from sage.rings.infinity import PlusInfinity -import cartesian_product import functools from sage.combinat.integer_list import IntegerListsLex @@ -1221,7 +1221,7 @@ def __iter__(self): """ for iv in IntegerVectors(self.n, len(self.comp)): blocks = [ IntegerVectors(iv[i], self.comp[i], max_slope=0).list() for i in range(len(self.comp))] - for parts in cartesian_product.CartesianProduct(*blocks): + for parts in itertools.product(*blocks): res = [] for part in parts: res += part diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 12d7a0da215..80850a88a3d 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -4211,9 +4211,9 @@ def marked_given_unmarked_and_weight_iterator( cls, unmarkedT, k, weight ): if td == {}: # the tableau is empty yield StrongTableau( unmarkedT, k, [] ) else: - allmarkings = cartesian_product.CartesianProduct(*[td[v] for v in td.keys()]) + import itertools dsc = Composition(weight).descents() - for m in allmarkings: + for m in itertools.product(*td.values()): if all(((m[i][1]-m[i][0] = HyperplaneArrangements(QQ) sage: chessboard = [] sage: N = 8 - sage: for x0, y0 in CartesianProduct(range(N+1), range(N+1)): - ....: chessboard.extend([x-x0, y-y0]) + sage: for x0 in range(N+1): + ....: for y0 in range(N+1): + ....: chessboard.extend([x-x0, y-y0]) sage: chessboard = H(chessboard) sage: len(chessboard.vertices()) 81 sage: chessboard.vertices(exclude_sandwiched=True) ((0, 0), (0, 8), (8, 0), (8, 8)) """ + import itertools from sage.matroids.all import Matroid - from sage.combinat.cartesian_product import CartesianProduct R = self.parent().base_ring() parallels = self._parallel_hyperplanes() A_list = [parallel[0][1] for parallel in parallels] @@ -1390,7 +1391,7 @@ def skip(b_list): for row, i in enumerate(indices): lhs[row] = A_list[i] b_list = [b_list_list[i] for i in indices] - for b in CartesianProduct(*b_list): + for b in itertools.product(*b_list): for i in range(d): rhs[i] = b[i] vertex = lhs.solve_right(rhs) @@ -1454,8 +1455,9 @@ def regions(self): sage: chessboard = [] sage: N = 8 - sage: for x0, y0 in CartesianProduct(range(N+1), range(N+1)): - ....: chessboard.extend([x-x0, y-y0]) + sage: for x0 in range(N+1): + ....: for y0 in range(N+1): + ....: chessboard.extend([x-x0, y-y0]) sage: chessboard = H(chessboard) sage: len(chessboard.bounded_regions()) # long time, 359 ms on a Core i7 64 diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx index bde90c18d6d..f6e8d64000c 100644 --- a/src/sage/geometry/integral_points.pyx +++ b/src/sage/geometry/integral_points.pyx @@ -10,13 +10,14 @@ Cython helper methods to compute integral points in polyhedra. # http://www.gnu.org/licenses/ #***************************************************************************** +from itertools import product +import copy + from sage.matrix.constructor import matrix, column_matrix, vector, diagonal_matrix from sage.rings.all import QQ, RR, ZZ, gcd, lcm from sage.rings.integer cimport Integer from sage.combinat.permutation import Permutation -from sage.combinat.cartesian_product import CartesianProduct from sage.misc.all import prod, uniq -import copy ############################################################################## # The basic idea to enumerate the lattice points in the parallelotope @@ -209,7 +210,7 @@ cpdef loop_over_parallelotope_points(e, d, VDinv, R, lattice, A=None, b=None): s = ZZ.zero() # summation variable gen = lattice(0) q_times_d = vector(ZZ, dim) - for base in CartesianProduct(*[ range(0,i) for i in e ]): + for base in product(*[ range(0,i) for i in e ]): for i in range(0, dim): s = ZZ.zero() for j in range(0, dim): diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 57c7b9f9282..c35247cb40c 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -12,6 +12,7 @@ # http://www.gnu.org/licenses/ ######################################################################## +import itertools import six from sage.structure.element import Element, coerce_binop, is_Vector @@ -26,8 +27,6 @@ from sage.graphs.graph import Graph -from sage.combinat.cartesian_product import CartesianProduct - from constructor import Polyhedron @@ -433,8 +432,8 @@ def _is_subpolyhedron(self, other): True """ return all( other_H.contains(self_V) - for other_H, self_V in - CartesianProduct(other.Hrepresentation(), self.Vrepresentation()) ) + for other_H in other.Hrepresentation() \ + for self_V in self.Vrepresentation()) def plot(self, point=None, line=None, polygon=None, # None means unspecified by the user @@ -3867,7 +3866,7 @@ def lattice_polytope(self, envelope=False): vertices = [] for v in self.vertex_generator(): vbox = [ set([floor(x),ceil(x)]) for x in v ] - vertices.extend( CartesianProduct(*vbox) ) + vertices.extend( itertools.product(*vbox) ) # construct the (enveloping) lattice polytope from sage.geometry.lattice_polytope import LatticePolytope diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 27ca55bb882..3ea87dbc011 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -548,8 +548,8 @@ def _subpoly_parallel_facets(self): edge_vectors.append([ v_prim*i for i in range(d+1) ]) origin = self.ambient_space().zero() parent = self.parent() - from sage.combinat.cartesian_product import CartesianProduct - for edges in CartesianProduct(*edge_vectors): + from itertools import product + for edges in product(*edge_vectors): v = [] point = origin for e in edges: diff --git a/src/sage/misc/sage_unittest.py b/src/sage/misc/sage_unittest.py index f2a6d1d9e54..519d1e97801 100644 --- a/src/sage/misc/sage_unittest.py +++ b/src/sage/misc/sage_unittest.py @@ -527,12 +527,12 @@ def some_elements(self, S=None): sage: list(tester.some_elements()) [0, 1, 2, 3, 4] - sage: C = CartesianProduct(Z, Z, Z, Z) + sage: C = cartesian_product([Z]*4) sage: len(C) 390625 sage: tester = InstanceTester(C, elements = C, max_runs=4) sage: list(tester.some_elements()) - [[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 2], [0, 0, 0, 3]] + [(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)] """ if S is None: if self._elements is None: diff --git a/src/sage/repl/image.py b/src/sage/repl/image.py index 34e065a094c..174703ca40d 100644 --- a/src/sage/repl/image.py +++ b/src/sage/repl/image.py @@ -14,8 +14,9 @@ sage: from sage.repl.image import Image sage: img = Image('RGB', (256, 256), 'white') sage: pixels = img.pixels() - sage: for x, y in CartesianProduct(range(img.width()), range(img.height())): - ....: pixels[x, y] = (x, y, 100) + sage: for x in range(img.width()): + ....: for y in range(img.height()): + ....: pixels[x, y] = (x, y, 100) sage: img 256x256px 24-bit RGB image sage: type(img) diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 1fba8833650..bdf70b5eb23 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -24,6 +24,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** + +from sage.misc.prandom import sample +from sage.misc.misc import bounded_number_of_tuples + from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.fields import Fields from sage.rings.infinity import infinity @@ -34,6 +38,7 @@ from sage.rings.padics.precision_error import PrecisionError from sage.misc.cachefunc import cached_method + class pAdicGeneric(PrincipalIdealDomain, LocalGeneric): def __init__(self, base, p, prec, print_mode, names, element_class, category=None): """ @@ -518,12 +523,7 @@ def _test_add(self, **options): tester.assertEqual(y.precision_absolute(),x.precision_absolute()) tester.assertEqual(y.precision_relative(),x.precision_relative()) - from sage.combinat.cartesian_product import CartesianProduct - elements = CartesianProduct(elements, elements) - if len(elements) > tester._max_runs: - from random import sample - elements = sample(elements, tester._max_runs) - for x,y in elements: + for x,y in bounded_number_of_tuples(elements, 2, tester._max_runs): z = x + y tester.assertIs(z.parent(), self) tester.assertEqual(z.precision_absolute(), min(x.precision_absolute(), y.precision_absolute())) @@ -552,19 +552,14 @@ def _test_sub(self, **options): """ tester = self._tester(**options) - elements = tester.some_elements() + elements = list(tester.some_elements()) for x in elements: y = x - self.zero() tester.assertEqual(y, x) tester.assertEqual(y.precision_absolute(), x.precision_absolute()) tester.assertEqual(y.precision_relative(), x.precision_relative()) - from sage.combinat.cartesian_product import CartesianProduct - elements = CartesianProduct(elements, elements) - if len(elements) > tester._max_runs: - from random import sample - elements = sample(elements, tester._max_runs) - for x,y in elements: + for x,y in bounded_number_of_tuples(elements, 2, tester._max_runs): z = x - y tester.assertIs(z.parent(), self) tester.assertEqual(z.precision_absolute(), min(x.precision_absolute(), y.precision_absolute())) @@ -628,12 +623,8 @@ def _test_mul(self, **options): """ tester = self._tester(**options) - from sage.combinat.cartesian_product import CartesianProduct - elements = CartesianProduct(tester.some_elements(), tester.some_elements()) - if len(elements) > tester._max_runs: - from random import sample - elements = sample(elements, tester._max_runs) - for x,y in elements: + elements = list(tester.some_elements()) + for x,y in bounded_number_of_tuples(elements, 2, tester._max_runs): z = x * y tester.assertIs(z.parent(), self) tester.assertLessEqual(z.precision_relative(), min(x.precision_relative(), y.precision_relative())) @@ -659,12 +650,8 @@ def _test_div(self, **options): """ tester = self._tester(**options) - from sage.combinat.cartesian_product import CartesianProduct - elements = CartesianProduct(tester.some_elements(), tester.some_elements()) - if len(elements) > tester._max_runs: - from random import sample - elements = sample(elements, tester._max_runs) - for x,y in elements: + elements = list(tester.some_elements()) + for x,y in bounded_number_of_tuples(elements, 2, tester._max_runs): try: z = x / y except (ZeroDivisionError, PrecisionError, ValueError): diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index f268c22cf0b..7ab13cf160e 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -29,11 +29,12 @@ ``x - I.reduce(x) in I``). Here is a toy example:: sage: from sage.rings.noncommutative_ideals import Ideal_nc + sage: from itertools import product sage: class PowerIdeal(Ideal_nc): ... def __init__(self, R, n): ... self._power = n ... self._power = n - ... Ideal_nc.__init__(self,R,[R.prod(m) for m in CartesianProduct(*[R.gens()]*n)]) + ... Ideal_nc.__init__(self,R,[R.prod(m) for m in product(R.gens(), repeat=n)]) ... def reduce(self,x): ... R = self.ring() ... return add([c*R(m) for m,c in x if len(m) = FreeAlgebra(QQ, implementation='letterplace') - sage: Q3 = F.quo(F*[F.prod(m) for m in CartesianProduct(*[F.gens()]*3)]*F) + sage: Q3 = F.quo(F*[F.prod(m) for m in product(F.gens(), repeat=3)]*F) sage: Q3 Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*x*x, x*x*y, x*x*z, x*y*x, x*y*y, x*y*z, x*z*x, x*z*y, x*z*z, y*x*x, y*x*y, y*x*z, y*y*x, y*y*y, y*y*z, y*z*x, y*z*y, y*z*z, z*x*x, z*x*y, z*x*z, z*y*x, z*y*y, z*y*z, z*z*x, z*z*y, z*z*z) sage: Q3.0*Q3.1-Q3.1*Q3.0 xbar*ybar - ybar*xbar sage: Q3.0*(Q3.1*Q3.2)-(Q3.1*Q3.2)*Q3.0 0 - sage: Q2 = F.quo(F*[F.prod(m) for m in CartesianProduct(*[F.gens()]*2)]*F) + sage: Q2 = F.quo(F*[F.prod(m) for m in product(F.gens(), repeat=2)]*F) sage: Q2.is_commutative() True diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 1eed28a1390..92bfa8ba654 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -1168,16 +1168,16 @@ def is_ample(self): Example 6.1.3, 6.1.11, 6.1.17 of [CLS]_:: + sage: from itertools import product sage: fan = Fan(cones=[(0,1), (1,2), (2,3), (3,0)], - ... rays=[(-1,2), (0,1), (1,0), (0,-1)]) + ....: rays=[(-1,2), (0,1), (1,0), (0,-1)]) sage: F2 = ToricVariety(fan,'u1, u2, u3, u4') sage: def D(a,b): return a*F2.divisor(2) + b*F2.divisor(3) - ... - sage: [ (a,b) for a,b in CartesianProduct(range(-3,3),range(-3,3)) - ... if D(a,b).is_ample() ] + sage: [ (a,b) for a,b in product(range(-3,3), repeat=2) + ....: if D(a,b).is_ample() ] [(1, 1), (1, 2), (2, 1), (2, 2)] - sage: [ (a,b) for a,b in CartesianProduct(range(-3,3),range(-3,3)) - ... if D(a,b).is_nef() ] + sage: [ (a,b) for a,b in product(range(-3,3), repeat=2) + ....: if D(a,b).is_nef() ] [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] @@ -1246,16 +1246,16 @@ def is_nef(self): Example 6.1.3, 6.1.11, 6.1.17 of [CLS]_:: + sage: from itertools import product sage: fan = Fan(cones=[(0,1), (1,2), (2,3), (3,0)], - ... rays=[(-1,2), (0,1), (1,0), (0,-1)]) + ....: rays=[(-1,2), (0,1), (1,0), (0,-1)]) sage: F2 = ToricVariety(fan,'u1, u2, u3, u4') sage: def D(a,b): return a*F2.divisor(2) + b*F2.divisor(3) - ... - sage: [ (a,b) for a,b in CartesianProduct(range(-3,3),range(-3,3)) - ... if D(a,b).is_ample() ] + sage: [ (a,b) for a,b in product(range(-3,3), repeat=2) + ....: if D(a,b).is_ample() ] [(1, 1), (1, 2), (2, 1), (2, 2)] - sage: [ (a,b) for a,b in CartesianProduct(range(-3,3),range(-3,3)) - ... if D(a,b).is_nef() ] + sage: [ (a,b) for a,b in product(range(-3,3), repeat=2) + ....: if D(a,b).is_nef() ] [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] """ diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py index ca902bf97eb..aedb22ac2db 100644 --- a/src/sage/schemes/toric/points.py +++ b/src/sage/schemes/toric/points.py @@ -35,10 +35,9 @@ #***************************************************************************** - +import itertools from copy import copy -from sage.combinat.cartesian_product import CartesianProduct from sage.misc.all import powerset, prod from sage.misc.cachefunc import cached_method from sage.rings.arith import gcd @@ -220,7 +219,7 @@ def _Chow_group_free(self): units = self.units() result = [] ker = self.rays().matrix().integer_kernel().matrix() - for phases in CartesianProduct(*([units] * ker.nrows())): + for phases in itertools.product(units, repeat=ker.nrows()): phases = tuple(prod(mu**exponent for mu, exponent in zip(phases, column)) for column in ker.columns()) result.append(phases) @@ -288,9 +287,10 @@ def rescalings(self): if len(tors) == 0: # optimization for smooth fans return free result = set(free) - for f, t in CartesianProduct(free, tors): - phases = tuple(x*y for x, y in zip(f, t)) - result.add(phases) + for f in free: + for t in tors: + phases = tuple(x*y for x, y in zip(f, t)) + result.add(phases) return tuple(sorted(result)) def orbit(self, point): @@ -390,7 +390,7 @@ def coordinate_iter(self): patch = copy(big_torus) for i in cone.ambient_ray_indices(): patch[i] = [zero] - for p in CartesianProduct(*patch): + for p in itertools.product(*patch): yield tuple(p) def __iter__(self): @@ -869,7 +869,7 @@ def solutions_serial(self, inhomogeneous_equations, log_range): OUTPUT: All solutions (as tuple of log inhomogeneous coordinates) in - the Cartesian product of the ranges. + the cartesian product of the ranges. EXAMPLES:: @@ -881,10 +881,10 @@ def solutions_serial(self, inhomogeneous_equations, log_range): sage: ffe.solutions_serial([s^2-1, s^6-s^2], [range(6)]) sage: list(_) - [[0], [3]] + [(0,), (3,)] """ - from sage.combinat.cartesian_product import CartesianProduct - for log_t in CartesianProduct(*log_range): + from itertools import product + for log_t in product(*log_range): t = self.ambient.exp(log_t) if all(poly(t) == 0 for poly in inhomogeneous_equations): yield log_t @@ -909,14 +909,14 @@ def solutions(self, inhomogeneous_equations, log_range): sage: ffe.solutions([s^2-1, s^6-s^2], [range(6)]) sage: sorted(_) - [[0], [3]] + [(0,), (3,)] """ # Do simple cases in one process (this includes most doctests) if len(log_range) <= 2: for log_t in self.solutions_serial(inhomogeneous_equations, log_range): yield log_t raise StopIteration - # Parallelize the outermost loop of the Cartesian product + # Parallelize the outermost loop of the cartesian product work = [([[r]] + log_range[1:],) for r in log_range[0]] from sage.parallel.decorate import Parallel parallel = Parallel() diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index 90f3a4f437b..b7bde0ee90c 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -1009,10 +1009,7 @@ def cardinality(self): Check that :trac:`15195` is fixed:: - sage: C = CartesianProduct(PositiveIntegers(), [1,2,3]) - sage: C.cardinality() - +Infinity - sage: F = Family(C, lambda x: x) + sage: F = Family(PositiveIntegers(), lambda x: x) sage: F.cardinality() +Infinity """ diff --git a/src/sage/sets/finite_set_maps.py b/src/sage/sets/finite_set_maps.py index daec1e077fd..a79e5e14cdb 100644 --- a/src/sage/sets/finite_set_maps.py +++ b/src/sage/sets/finite_set_maps.py @@ -18,6 +18,8 @@ #***************************************************************************** +import itertools + from sage.structure.parent import Parent from sage.rings.integer import Integer from sage.structure.unique_representation import UniqueRepresentation @@ -25,7 +27,6 @@ from sage.categories.monoids import Monoids from sage.categories.enumerated_sets import EnumeratedSets from sage.sets.finite_enumerated_set import FiniteEnumeratedSet -from sage.combinat.cartesian_product import CartesianProduct from sage.sets.integer_range import IntegerRange from sage.sets.finite_set_map_cy import ( FiniteSetMap_MN, FiniteSetMap_Set, @@ -338,7 +339,7 @@ def __iter__(self): sage: FiniteSetMaps(1,1).list() [[0]] """ - for v in CartesianProduct(*([range(self._n)]*self._m)): + for v in itertools.product(range(self._n), repeat=self._m): yield self._from_list_(v) def _from_list_(self, v): diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index a2164f69bda..ab1dbc7c093 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -333,42 +333,44 @@ def assert_strict_weak_order(a,b,c, cmp_func): sage: x = [SR(unsigned_infinity), SR(oo), -SR(oo)] sage: cmp = matrix(3,3) - sage: indices = list(CartesianProduct(range(0,3),range(0,3))) - sage: for i,j in CartesianProduct(range(0,3),range(0,3)): - ... cmp[i,j] = x[i].__cmp__(x[j]) + sage: for i in range(3): + ....: for j in range(3): + ....: cmp[i,j] = x[i].__cmp__(x[j]) sage: cmp [ 0 -1 -1] [ 1 0 -1] [ 1 1 0] """ + from itertools import product from sage.matrix.constructor import matrix - from sage.combinat.cartesian_product import CartesianProduct from sage.combinat.permutation import Permutations x = (a,b,c) cmp = matrix(3,3) - indices = list(CartesianProduct(range(0,3),range(0,3))) - for i,j in indices: - cmp[i,j] = (cmp_func(x[i], x[j]) == 1) # or -1, doesn't matter + for i in range(3): + for j in range(3): + cmp[i,j] = (cmp_func(x[i], x[j]) == 1) # or -1, doesn't matter msg = 'The binary relation failed to be a strict weak order on the elements\n' msg += ' a = '+str(a)+'\n' msg += ' b = '+str(b)+'\n' msg += ' c = '+str(c)+'\n' msg += str(cmp) - for i in range(0,3): # irreflexivity + for i in range(3): + # irreflexivity if cmp[i,i]: raise ValueError(msg) - for i,j in indices: # asymmetric - if i==j: continue - #if x[i] == x[j]: continue - if cmp[i,j] and cmp[j,i]: raise ValueError(msg) + # asymmetric + for j in range(i): + if cmp[i,j] and cmp[j,i]: raise ValueError(msg) - for i,j,k in Permutations([0,1,2]): # transitivity + def incomparable(i,j): + return not (cmp[i,j] or cmp[j,i]) + + for i,j,k in Permutations([0,1,2]): + # transitivity if cmp[i,j] and cmp[j,k] and not cmp[i,k]: raise ValueError(msg) - def incomparable(i,j): - return (not cmp[i,j]) and (not cmp[j,i]) - for i,j,k in Permutations([0,1,2]): # transitivity of equivalence + # transitivity of equivalence if incomparable(i,j) and incomparable(j,k) and not incomparable(i,k): raise ValueError(msg) def test_symbolic_expression_order(repetitions=100): diff --git a/src/sage/tests/french_book/nonlinear_doctest.py b/src/sage/tests/french_book/nonlinear_doctest.py index cb175085117..e51096a073e 100644 --- a/src/sage/tests/french_book/nonlinear_doctest.py +++ b/src/sage/tests/french_book/nonlinear_doctest.py @@ -37,10 +37,11 @@ Sage example in ./nonlinear.tex, line 231:: + sage: from itertools import product sage: def build_complex_roots(degree): ....: R. = PolynomialRing(CDF, 'x') ....: v = [] - ....: for c in CartesianProduct(*[[-1, 1]] * (degree + 1)): + ....: for c in product([-1, 1], repeat=degree+1): ....: v.extend(R(c).roots(multiplicities=False)) ....: return v sage: data = build_complex_roots(12) # long time From bec57ae177f554f2641bfb944e124975929107c3 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 11 Sep 2015 22:48:16 -0300 Subject: [PATCH 0843/1872] Trac 18411: cartesian_product works with tuple/list/set/frozenset --- src/sage/categories/cartesian_product.py | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index 3e0065247a3..464b47f6638 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -105,6 +105,43 @@ class CartesianProductFunctor(CovariantFunctorialConstruction): _functor_category = "CartesianProducts" symbol = " (+) " + def __call__(self, args): + r""" + Functorial construction application. + + Specializes the generic ``__call__`` from + :class:`CartesianProductFunctor` to handle the case of some Python + objects. + + EXAMPLES:: + + sage: cartesian_product([[0,1], ('a','b','c')]) + The cartesian product of ({0, 1}, {'a', 'b', 'c'}) + sage: _.category() + Category of Cartesian products of finite enumerated sets + + sage: cartesian_product([set([0,1,2]), [0,1]) + The cartesian product of ({0, 1, 2}, {0, 1}) + sage: _.category() + Category of Cartesian products of sets + """ + if any(type(arg) is tuple or \ + type(arg) is list or \ + type(arg) is set or \ + type(arg) is frozenset for arg in args): + aargs = [] + from sage.sets.set import Set + from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + for arg in args: + if type(arg) is tuple or type(arg) is list: + aargs.append(FiniteEnumeratedSet(arg)) + elif type(arg) is set or type(arg) is frozenset: + aargs.append(Set(arg)) + else: + aargs.append(arg) + args = aargs + return super(CartesianProductFunctor, self).__call__(args) + cartesian_product = CartesianProductFunctor() """ The cartesian product functorial construction. From 7dbb66393238c05738d0f12990b9fd7b28716d70 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 11 Sep 2015 23:16:26 -0300 Subject: [PATCH 0844/1872] Trac 18411: move iteration of cartesian products to Sets --- src/sage/categories/enumerated_sets.py | 92 ---------------- src/sage/categories/finite_enumerated_sets.py | 2 +- src/sage/categories/sets_cat.py | 103 +++++++++++++++++- 3 files changed, 103 insertions(+), 94 deletions(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 1cbe3103953..5a327bbbf51 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -715,98 +715,6 @@ def rank(self): class CartesianProducts(CartesianProductsCategory): class ParentMethods: - def __iter__(self): - r""" - Return a lexicographic iterator for the elements of this cartesian product. - - EXAMPLES:: - - sage: A = FiniteEnumeratedSets()(["a", "b"]) - sage: B = FiniteEnumeratedSets().example(); B - An example of a finite enumerated set: {1,2,3} - sage: C = cartesian_product([A, B, A]); C - The cartesian product of ({'a', 'b'}, An example of a finite enumerated set: {1,2,3}, {'a', 'b'}) - sage: C in FiniteEnumeratedSets() - True - sage: list(C) - [('a', 1, 'a'), ('a', 1, 'b'), ('a', 2, 'a'), ('a', 2, 'b'), ('a', 3, 'a'), ('a', 3, 'b'), - ('b', 1, 'a'), ('b', 1, 'b'), ('b', 2, 'a'), ('b', 2, 'b'), ('b', 3, 'a'), ('b', 3, 'b')] - sage: C.__iter__.__module__ - 'sage.categories.enumerated_sets' - - sage: F22 = GF(2).cartesian_product(GF(2)) - sage: list(F22) - [(0, 0), (0, 1), (1, 0), (1, 1)] - - sage: C = cartesian_product([Permutations(10)]*4) - sage: it = iter(C) - sage: next(it) - ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - sage: next(it) - ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]) - - .. WARNING:: - - The elements are returned in lexicographic order, - which gives a valid enumeration only if all - factors, but possibly the first one, are - finite. So the following one is fine:: - - sage: it = iter(cartesian_product([ZZ, GF(2)])) - sage: [next(it) for _ in range(10)] - [(0, 0), (0, 1), (1, 0), (1, 1), - (-1, 0), (-1, 1), (2, 0), (2, 1), - (-2, 0), (-2, 1)] - - But this one is not:: - - sage: it = iter(cartesian_product([GF(2), ZZ])) - sage: [next(it) for _ in range(10)] - doctest:...: UserWarning: Sage is not able to determine - whether the factors of this cartesian product are - finite. The lexicographic ordering might not go through - all elements. - [(0, 0), (0, 1), (0, -1), (0, 2), (0, -2), - (0, 3), (0, -3), (0, 4), (0, -4), (0, 5)] - - .. NOTE:: - - Here it would be faster to use :func:`itertools.product` for sets - of small size. But the latter expands all factor in memory! - So we can not reasonably use it in general. - - ALGORITHM: - - Recipe 19.9 in the Python Cookbook by Alex Martelli - and David Ascher. - """ - if any(f not in Sets().Finite() for f in self.cartesian_factors()[1:]): - from warnings import warn - warn("Sage is not able to determine whether the factors of " - "this cartesian product are finite. The lexicographic " - "ordering might not go through all elements.") - - # visualize an odometer, with "wheels" displaying "digits"...: - factors = list(self.cartesian_factors()) - wheels = map(iter, factors) - digits = [next(it) for it in wheels] - while True: - yield self._cartesian_product_of_elements(digits) - for i in range(len(digits)-1, -1, -1): - try: - digits[i] = next(wheels[i]) - break - except StopIteration: - wheels[i] = iter(factors[i]) - digits[i] = next(wheels[i]) - else: - break def first(self): r""" diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index 1cce141f25e..32f87b1242c 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -503,7 +503,7 @@ class ParentMethods: # Sets.CartesianProducts and from EnumeratedSets.Finite. random_element = Sets.CartesianProducts.ParentMethods.random_element.__func__ cardinality = Sets.CartesianProducts.ParentMethods.cardinality.__func__ - __iter__ = EnumeratedSets.CartesianProducts.ParentMethods.__iter__.__func__ + __iter__ = Sets.CartesianProducts.ParentMethods.__iter__.__func__ def last(self): r""" diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index d2ae0e45569..b85cf6a45b7 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1976,6 +1976,101 @@ def example(self): class ParentMethods: + def __iter__(self): + r""" + Return a lexicographic iterator for the elements of this cartesian product. + + EXAMPLES:: + + sage: for x,y in cartesian_product([Set([1,2]), Set(['a','b'])]): + ....: print x,y + + sage: A = FiniteEnumeratedSets()(["a", "b"]) + sage: B = FiniteEnumeratedSets().example(); B + An example of a finite enumerated set: {1,2,3} + sage: C = cartesian_product([A, B, A]); C + The cartesian product of ({'a', 'b'}, An example of a finite enumerated set: {1,2,3}, {'a', 'b'}) + sage: C in FiniteEnumeratedSets() + True + sage: list(C) + [('a', 1, 'a'), ('a', 1, 'b'), ('a', 2, 'a'), ('a', 2, 'b'), ('a', 3, 'a'), ('a', 3, 'b'), + ('b', 1, 'a'), ('b', 1, 'b'), ('b', 2, 'a'), ('b', 2, 'b'), ('b', 3, 'a'), ('b', 3, 'b')] + sage: C.__iter__.__module__ + 'sage.categories.enumerated_sets' + + sage: F22 = GF(2).cartesian_product(GF(2)) + sage: list(F22) + [(0, 0), (0, 1), (1, 0), (1, 1)] + + sage: C = cartesian_product([Permutations(10)]*4) + sage: it = iter(C) + sage: next(it) + ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + sage: next(it) + ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]) + + .. WARNING:: + + The elements are returned in lexicographic order, + which gives a valid enumeration only if all + factors, but possibly the first one, are + finite. So the following one is fine:: + + sage: it = iter(cartesian_product([ZZ, GF(2)])) + sage: [next(it) for _ in range(10)] + [(0, 0), (0, 1), (1, 0), (1, 1), + (-1, 0), (-1, 1), (2, 0), (2, 1), + (-2, 0), (-2, 1)] + + But this one is not:: + + sage: it = iter(cartesian_product([GF(2), ZZ])) + sage: [next(it) for _ in range(10)] + doctest:...: UserWarning: Sage is not able to determine + whether the factors of this cartesian product are + finite. The lexicographic ordering might not go through + all elements. + [(0, 0), (0, 1), (0, -1), (0, 2), (0, -2), + (0, 3), (0, -3), (0, 4), (0, -4), (0, 5)] + + .. NOTE:: + + Here it would be faster to use :func:`itertools.product` for sets + of small size. But the latter expands all factor in memory! + So we can not reasonably use it in general. + + ALGORITHM: + + Recipe 19.9 in the Python Cookbook by Alex Martelli + and David Ascher. + """ + if any(f not in Sets().Finite() for f in self.cartesian_factors()[1:]): + from warnings import warn + warn("Sage is not able to determine whether the factors of " + "this cartesian product are finite. The lexicographic " + "ordering might not go through all elements.") + + # visualize an odometer, with "wheels" displaying "digits"...: + factors = list(self.cartesian_factors()) + wheels = map(iter, factors) + digits = [next(it) for it in wheels] + while True: + yield self._cartesian_product_of_elements(digits) + for i in range(len(digits)-1, -1, -1): + try: + digits[i] = next(wheels[i]) + break + except StopIteration: + wheels[i] = iter(factors[i]) + digits[i] = next(wheels[i]) + else: + break @cached_method def an_element(self): @@ -2024,7 +2119,13 @@ def is_finite(self): True """ f = self.cartesian_factors() - return any(c.is_empty() for c in f) or all(c.is_finite() for c in f) + try: + # Note: some parent might not implement "is_empty". So we + # carefully isolate this test. + return any(c.is_empty() for c in f) + except Exception: + pass + return all(c.is_finite() for c in f) def cardinality(self): r""" From 4fbb4ae372d77b363780eae9d06703ea47e8dbed Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 11 Sep 2015 23:16:46 -0300 Subject: [PATCH 0845/1872] Trac 18411: refine category of Set(...) --- src/sage/sets/set.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 83d8bdfd5e0..12ef7a8667e 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -36,14 +36,19 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.element import Element -from sage.structure.parent import Parent, Set_generic + from sage.misc.latex import latex -import sage.rings.infinity +from sage.misc.prandom import choice from sage.misc.misc import is_iterator + +from sage.structure.element import Element +from sage.structure.parent import Parent, Set_generic + from sage.categories.sets_cat import Sets from sage.categories.enumerated_sets import EnumeratedSets +import sage.rings.infinity + def Set(X=frozenset()): r""" Create the underlying set of ``X``. @@ -224,7 +229,12 @@ def __init__(self, X): if isinstance(X, (int,long)) or is_Integer(X): # The coercion model will try to call Set_object(0) raise ValueError('underlying object cannot be an integer') - Parent.__init__(self, category=Sets()) + + category = Sets() + if X in Sets().Finite() or isinstance(X, (tuple,list,set,frozenset)): + category = Sets().Finite() + + Parent.__init__(self, category=category) self.__object = X def __hash__(self): @@ -685,6 +695,21 @@ def __init__(self, X): """ Set_object.__init__(self, X) + def random_element(self): + r""" + Return a random element in this set. + + EXAMPLES:: + + sage: Set([1,2,3]).random_element() # random + 2 + """ + try: + return self.object().random_element() + except AttributeError: + # TODO: this very slow! + return choice(self.list()) + def is_finite(self): r""" Return ``True`` as this is a finite set. From 10df21841341b144bff58847011bae02cd852be9 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 11 Sep 2015 23:17:16 -0300 Subject: [PATCH 0846/1872] Trac 18411: fix combinat tutorial --- src/sage/combinat/tutorial.py | 126 +++++++++++++++------------------- 1 file changed, 57 insertions(+), 69 deletions(-) diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index 40156bb03a9..7671f270aaf 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -61,8 +61,8 @@ sage: Suits = Set(["Hearts", "Diamonds", "Spades", "Clubs"]) sage: Values = Set([2, 3, 4, 5, 6, 7, 8, 9, 10, - ... "Jack", "Queen", "King", "Ace"]) - sage: Cards = CartesianProduct(Values, Suits) + ....: "Jack", "Queen", "King", "Ace"]) + sage: Cards = cartesian_product([Values, Suits]) There are `4` suits and `13` possible values, and therefore `4\times 13=52` cards in the poker deck:: @@ -77,21 +77,7 @@ Draw a card at random:: sage: Cards.random_element() # random - [6, 'Clubs'] - -A small technical digression is necessary here. The elements of a -Cartesian product are returned in the form of lists:: - - sage: type(Cards.random_element()) - - -A ``Python`` list not being immutable, it cannot be an element of a set, which -would cause us a problem later. We will therefore redefine our -Cartesian product so that its elements are represented by tuples:: - - sage: Cards = CartesianProduct(Values, Suits).map(tuple) - sage: Cards.an_element() - ('King', 'Hearts') + (6, 'Clubs') Now we can define a set of cards:: @@ -136,7 +122,7 @@ We will construct the set of all flushes, so as to determine how many there are:: - sage: Flushes = CartesianProduct(Subsets(Values, 5), Suits) + sage: Flushes = cartesian_product([Subsets(Values, 5), Suits]) sage: Flushes.cardinality() 5148 @@ -157,7 +143,7 @@ function tests whether a given hand is a flush or not:: sage: def is_flush(hand): - ... return len(set(suit for (val, suit) in hand)) == 1 + ....: return len(set(suit for (val, suit) in hand)) == 1 We now draw 10000 hands at random, and count the number of flushes obtained (this takes about 10 seconds):: @@ -165,9 +151,9 @@ sage: n = 10000 sage: nflush = 0 sage: for i in range(n): # long time - ... hand = Hands.random_element() - ... if is_flush(hand): - ... nflush += 1 + ....: hand = Hands.random_element() + ....: if is_flush(hand): + ....: nflush += 1 sage: print n, nflush # random 10000 18 @@ -1029,7 +1015,7 @@ comprehensions provide a much pleasanter syntax:: sage: for s in Subsets(3): - ... print s + ....: print s {} {1} {2} @@ -1095,7 +1081,7 @@ sage: def mersenne(p): return 2^p -1 sage: [ is_prime(p) - ... for p in range(1000) if is_prime(mersenne(p)) ] + ....: for p in range(1000) if is_prime(mersenne(p)) ] [True, True, True, True, True, True, True, True, True, True, True, True, True, True] @@ -1107,24 +1093,24 @@ difference in the length of the calculations:: sage: all( is_prime(mersenne(p)) - ... for p in range(1000) if is_prime(p) ) + ....: for p in range(1000) if is_prime(p) ) False sage: all( [ is_prime(mersenne(p)) - ... for p in range(1000) if is_prime(p)] ) + ....: for p in range(1000) if is_prime(p)] ) False We now try to find the smallest counter-example. In order to do this, we use the ``Sage`` function ``exists``:: sage: exists( (p for p in range(1000) if is_prime(p)), - ... lambda p: not is_prime(mersenne(p)) ) + ....: lambda p: not is_prime(mersenne(p)) ) (True, 11) Alternatively, we could construct an interator on the counter-examples:: sage: counter_examples = \ - ... (p for p in range(1000) - ... if is_prime(p) and not is_prime(mersenne(p))) + ....: (p for p in range(1000) + ....: if is_prime(p) and not is_prime(mersenne(p))) sage: next(counter_examples) 11 sage: next(counter_examples) @@ -1138,10 +1124,10 @@ sage: cubes = [t**3 for t in range(-999,1000)] sage: exists([(x,y) for x in cubes for y in cubes], # long time (3s, 2012) - ... lambda (x,y): x+y == 218) + ....: lambda (x,y): x+y == 218) (True, (-125, 343)) sage: exists(((x,y) for x in cubes for y in cubes), # long time (2s, 2012) - ... lambda (x,y): x+y == 218) + ....: lambda (x,y): x+y == 218) (True, (-125, 343)) Which of the last two is more economical in terms of time? In terms @@ -1236,7 +1222,7 @@ :: sage: counter_examples = (p for p in Primes() - ... if not is_prime(mersenne(p))) + ....: if not is_prime(mersenne(p))) sage: for p in counter_examples: print p # not tested 11 23 @@ -1278,23 +1264,23 @@ apply a function to all the elements:: sage: list(itertools.imap(lambda z: z.cycle_type(), - ... Permutations(3))) + ....: Permutations(3))) [[1, 1, 1], [2, 1], [2, 1], [3], [3], [2, 1]] or select the elements satisfying a certain condition:: sage: list(itertools.ifilter(lambda z: z.has_pattern([1,2]), - ... Permutations(3))) + ....: Permutations(3))) [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]] In all these situations, ``attrcall`` can be an advantageous alternative to creating an anonymous function:: sage: list(itertools.imap(lambda z: z.cycle_type(), - ... Permutations(3))) + ....: Permutations(3))) [[1, 1, 1], [2, 1], [2, 1], [3], [3], [2, 1]] sage: list(itertools.imap(attrcall("cycle_type"), - ... Permutations(3))) + ....: Permutations(3))) [[1, 1, 1], [2, 1], [2, 1], [3], [3], [2, 1]] Implementation of new interators @@ -1304,8 +1290,8 @@ instead of ``return`` in a function:: sage: def f(n): - ... for i in range(n): - ... yield i + ....: for i in range(n): + ....: yield i After the ``yield``, execution is not halted, but only suspended, ready to be continued from the same point. The result of the function is @@ -1338,12 +1324,12 @@ generate all words of a given length on a given alphabet:: sage: def words(alphabet,l): - ... if l == 0: - ... yield [] - ... else: - ... for word in words(alphabet, l-1): - ... for l in alphabet: - ... yield word + [l] + ....: if l == 0: + ....: yield [] + ....: else: + ....: for word in words(alphabet, l-1): + ....: for l in alphabet: + ....: yield word + [l] sage: [ w for w in words(['a','b'], 3) ] [['a', 'a', 'a'], ['a', 'a', 'b'], ['a', 'b', 'a'], ['a', 'b', 'b'], ['b', 'a', 'a'], ['b', 'a', 'b'], @@ -1367,13 +1353,13 @@ `w_1` and `w_2` are Dyck words:: sage: def dyck_words(l): - ... if l==0: - ... yield '' - ... else: - ... for k in range(l): - ... for w1 in dyck_words(k): - ... for w2 in dyck_words(l-k-1): - ... yield '('+w1+')'+w2 + ....: if l==0: + ....: yield '' + ....: else: + ....: for k in range(l): + ....: for w1 in dyck_words(k): + ....: for w2 in dyck_words(l-k-1): + ....: yield '('+w1+')'+w2 Here are all the Dyck words of length `4`:: @@ -1423,27 +1409,29 @@ Consider a large Cartesian product:: - sage: C = CartesianProduct(Compositions(8), Permutations(20)); C - Cartesian product of Compositions of 8, Standard permutations of 20 + sage: C = cartesian_product([Compositions(8), Permutations(20)]); C + The cartesian product of (Compositions of 8, Standard permutations of 20) sage: C.cardinality() 311411457046609920000 -Clearly, it is impractical to construct the list of all the elements of -this Cartesian product. For the moment, the contruction -``CartesianProduct`` ignores the algebraic properties of its arguments. -This is partially corrected in Sage 4.4.4, with the construction -``cartesian_product``. Eventually, these two constructions will be merged -and, in the following example, `H` will be equipped with the -usual combinatorial operations and also its structure as a product -group:: +Clearly, it is impractical to construct the list of all the elements of this +Cartesian product! And, in the following example, `H` is equipped with the +usual combinatorial operations and also its structure as a product group:: sage: G = DihedralGroup(4) sage: H = cartesian_product([G,G]) + sage: H in Groups() + True + sage: t = H.an_element() + sage: t + ((1,2,3,4), (1,2,3,4)) + sage: t*t + ((1,3)(2,4), (1,3)(2,4)) We now construct the union of two existing disjoint sets:: sage: C = DisjointUnionEnumeratedSets( - ... [ Compositions(4), Permutations(3)] ) + ....: [ Compositions(4), Permutations(3)] ) sage: C Disjoint union of Family (Compositions of 4, Standard permutations of 3) @@ -1482,7 +1470,7 @@ necessary to interrupt it at some point:: sage: for p in U: # not tested - ... print p + ....: print p [] [1] [1, 2] @@ -1540,14 +1528,14 @@ `4` and `2` respectively:: sage: IntegerVectors(10, 3, min_part = 2, max_part = 5, - ... inner = [2, 4, 2]).list() + ....: inner = [2, 4, 2]).list() [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] The compositions of `5` with each part at most `3`, and with length `2` or `3`:: sage: Compositions(5, max_part = 3, - ... min_length = 2, max_length = 3).list() + ....: min_length = 2, max_length = 3).list() [[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [1, 3, 1], [1, 2, 2], [1, 1, 3]] @@ -1565,12 +1553,12 @@ examples:: sage: IntegerListsLex(10, length=3, - ... min_part = 2, max_part = 5, - ... floor = [2, 4, 2]).list() + ....: min_part = 2, max_part = 5, + ....: floor = [2, 4, 2]).list() [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] sage: IntegerListsLex(5, min_part = 1, max_part = 3, - ... min_length = 2, max_length = 3).list() + ....: min_length = 2, max_length = 3).list() [[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [1, 3, 1], [1, 2, 2], [1, 1, 3]] @@ -1842,7 +1830,7 @@ selecting only the children which are planar:: sage: [len(list(graphs(n, property = lambda G: G.is_planar()))) - ... for n in range(7)] + ....: for n in range(7)] [1, 1, 2, 4, 11, 33, 142] In a similar fashion, one can generate any family of graphs closed From 4ed09ecce4b1bd1028b6046cfa9cb0f74e690c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 12 Sep 2015 09:47:03 +0200 Subject: [PATCH 0847/1872] trac #18937 patchbot 2.4.4 bugfix for broken 2.4.3 --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index b4af6341a82..cea65720c5d 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=15118651d1d2d32327d425528b4d4fc4b1cac6aa -md5=a01538fa40d938392b4bd6d5a7c60bb6 -cksum=1454859190 +sha1=b9fd210e0fc8da23b9968777f6014d23970d1dc1 +md5=2ff4eb8cf4dac6ed24bb4c0962e782bc +cksum=672259990 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 35cee72dcbf..79a614418f7 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.3 +2.4.4 From fc5821b36722f172d3c78da33cc42a7f6151997a Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Sat, 12 Sep 2015 17:25:07 +0900 Subject: [PATCH 0848/1872] sin_plot.png included. --- src/doc/ja/a_tour_of_sage/sin_plot.png | Bin 18520 -> 30132 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/doc/ja/a_tour_of_sage/sin_plot.png b/src/doc/ja/a_tour_of_sage/sin_plot.png index 925264764f198f9f7f4e9d753d684eb180e1d048..ef4e87c69c170a7cd7302c21b87ab66df5d8c18c 100644 GIT binary patch literal 30132 zcmcG$byStz_Xh|UE^+Bb32Bg0LAtx8;UaZKLK^9YD+mJ8-2&2e0Ria?$cu!4QX*;4 z(%o}-zrR>(X8xF&wZ_F-J`2w|&w2LQ@!6lfk5M{LRES`AVHg+~L~5#vdKefGI0gph zAs!C+%}*Wu3Gf%ThrF5r9{3Z8XZ;2Pg9$@TQO>|O=WlL+C;epZYF85P%v2HkY`u*X z?=1ZL_p~}9cj2GUR3S5Ly|#j%@SWUozVpuX_9Wbi(DWAgJujHtuW8#b%#oRC{lxYp zVcHfyUX3ZapA8!?3?CEI8}0gBBhA{xwUJGRO=IKg_v+?U(LF=2o$8A1^Wc%6l-o5m zts5JyM;(icJJ&99EQzY2r1E&o;j~2$*Kq!Q`a?$v55IkiC_uB^K0G3XQZs{xH_y0G zU?izLp#oCr_Q8r4#(O)Lv{wf~_U|GQkeJ((ZHg<%YOU0+;H6geda>_?~wmb+efhb z{Lc%F+&TaAf)@r@|NVUXg8v@!e|-TDLGyw?kFfKP@M_cMUs;Yd-JL-fuUyD)1t3oh zHKJw=+?Asjb;Gzg-s;WuS%{L@X%}4MxK$UnKRO7TpFbRHI}UI7`1nMF&OJk`Z|AA< z%OaOwJqS4)I{n@+P3ePm&5OoQ>RrA2J>CD0&88#1fR z{2Ti3tyE>@_^s^W31#{TOA!A%XJIm@Se{;9Kll3Y<)18!jghADn@3~e62B`fgiujY z*_&5r?vTk3@7}v%eJBJCyqJ}123z#vLe=XS7=#;E8Wps*-o?;)`ZRhqKZG&#qn@Fm zp=T)`KIZtitZw4vO>Hpr@7x`y06gZe5zIZjnp#@Wd2IPNSQY_%XE!JFoHzXZ#5Gdk z2`_q0!ow5VmpElGxp|Q3mN>-p7}v+HVJ>9MY=gH}xBn{t65Dq)Ae2EO^yV@jIT}Qa zfM7GTaoyUgn082)sBzbU#Qu({3uZ(lGA<4=tArQD56m+mXZ2{huexet`ArX)ysDcH!v3Lv00iTO zlar#MA(gU<3KrPW*FR&-h^uq!%!nRl))k9_A~>E-Fk#28;xSje(z$H5UwV}Y6% zkT2}(4ntEJ4+lFR*#6I0?uLG=NBxdO*J~;QZBe9FalMg9B0AeH?>;JYB5U`DNK$z& zRN%@&fKA7T-pDW)eCD(6vjcRwKH4VzOK{MU0}~@Izw*AC;@SB$a`7hUU7N&OT0)r| za+x(ZSJt)m@+QZt2%nizx0u$bHt)*+d6AQL-eI#8o7v@>3VQKI3gyDEn>mUSzPm>P zAWy+ z8IZZMM>uI-YvFw@>R{mF!nk|aw#&klrvY{!RX9{xtN!M6$`tt^P|hOY>IgBbScnBp z)6S9N!EY9sV`AMT2_`*l>nbwWdc(i9g&s`R!*%2!pnkJfh>qs(x@6bUWgg<3oW`1* zq=bKx0h0K&`;1JVPGqoar%jvseb8PXIAGP9@dara$+8zt@6pi$UDrZxUxZki2w#L0-T$Z5-v+B9fN&!*2d z=Cp1_CIfsqT8sU}0OEM%FAfi1bK9nWD4An{s5ZO*TGhnqv42^oR|(p|0WvrQzD7m| zafbf$e(rBMeN~e%B2Y5HmMrO@Y-6smv3$|8MX#w;`(m7toH33OO3jxv6BgYgKM*G6 z|M;VK;u`QWSe#E(rO|VJFQ#kL$NK7?cYlaUFk79tKVu6cgP3u!N7IY3oEg9N$a8m` zQq9+V;|xSDyKM4>3hwaoX#_t09u5Oi-P+F_Ssd4UYd4fCFq)nb<~3P|}!3imHDVfI1}0 z7je@t<)WW9s_!dsa5y!kBwT({d*jvzgH@G%ow+YoyB)W@ossn7CyR@7?+fR8dG1+{^OTzl)xKA0iFxmWb~n}) zdp>C{6fz_rB~`CwXQ+?x`<)jMO6P*X7(#z~HX7zag#QYOIb&pOx1cR%=2>@ZfZ%j& zWZOJAcUMCgJssV#V7x=t6!4)mH8SAuR@unW$=VQ~d1&DE0Xk2L_b#o{`NhAE!2R5F zWv>0)f8C?B^vY4c<{-xMv(#bk&S$|G>qxMLQf;glnxWxT14`=X7$xL#P8hDz$Kb;v zbgYPa#*3YWccx00%J@|_LjpUc3&wFY10nwY0uu1XMm?vLF8tN@(?Z^pH2(aI;oHR= z()3%^$3y4-I(&ValxvrlxU5^#LH)f>0sF7VD0H6tm&g+aURc$OL{)1NGHxFYC0bSQ z}lsSKX`WCcn{Dk<c2xl`C#;w)emR z5Jg1VKomB#E@r1s~8YwQeTebnYo<>VB52 zdhvDf!L}iX4{gFpI)Cc2zUp<6t&2V)^Y?N(yJakKn#8R$&>N64t!HN%9}Wm`{_yaI z_D-VPMv2zIbVekV*7-%ls^$GOzM?QHstM}|&1H$fA!L31ds@~^zdfZp@2f2Dd1|;5 z0N9pe;J&jtWKpVu&r3Z#Jo2-*e*WX5vmbE` zShxEiaKAF9s(nkaU~_6UwxnloH76!iM`R_pwcFe?!*Ffdo+<1%CXpkK9G0q^U)fXO zM|8{GF_d_=t_SpbZ1I6SVjyW4ppRa$NRlB!`Cr7asym0YowFl((2@L6=_Ea3n%?jk zF;CSgSKbHtSLdx>lyKeNSoG7Tw_>D8 zzyFDS;ozWt7Hnt7NzDrnO-rNx@ZkeubtE?~ZqxIw7&Og;m{C(I3B&=$u(087mV@=3 zQRy=1N9AJuA3qeWAKeT}RrSLVC)@K}_wRQb8k?tj=kM>ke`wX*f0;!9TwRVrWavq| z-Sy_?6z1YpO}I_N7jD+GZgglHDKkUWi?QidUXggn&>ilbRLGE&Cko@Sh)B_x{BfQ> zuHyi?+P4z);P4+dx4&?QO8k$6fq?^N|uiXLzbxkSP#7;RB^6acRTbfEvupp=$zuG+UMJ5|NF_?g#T!;N?CBHp`DvT?b-?D-K-#mO z7o_nqrt8WGEp4p(>XV6*y#t?EWY6b3Rzn5t{x;uFw|7lfQ_PWDV+^(-E~~Cq0$9$% zf1RC;9Dgq8WF8}QJ*M|30QotRe&irgNUvz^|NSyY@{WqVJv{|Qd1d?P`_?QmmYEl> z>029<2aAqQDO&@{*Nu_bk+72%d@{%{tHjHHV$qN_E1RNfKCgU@`d)fo8eX%Hq$hJ8 zBrYF+;$X<$;z#^PwuKeyY2&)D)%11Eb3NNt9a4PttQ6;-MS~K_P zv8Sr)zOj*$=S->SUmPCoi6llHd%r7Y2L{REiK2ffB^5M)^go`ld+jHK@tmfA=vsuc8~(WYv_F&$$Q2yetA z`RV(jPr^kQc-ANBR6Zi z7>kRG-}G7ep8kx)T+*`&3|3uS8U#sspbC4&5{BEqSP@zl*6THSqW0-TAdWxfU-o8RWaVkv-(iy=BzqbT z8RB&i))1# zs>7hWw%YyQGyY&%w|?E+MDD#b`Wpwaz@AECCnQ^uP?t3}6r0V5@CcflCsi8hkpmY* z0pry$`-t)O?Z<`+%pa5MYujng!bs>tO*bzIK-o{O5e=9mVXGm4i|wM*{&hhy9J2umi;hhU|;}e-4GqsT0Kq?6IJ~sTS{ntUZ7Zf{KMrpy_rY| z&&?hSY7Mb0vkC8C8uXFMaZ;+Z%yIf-8z)9I_~9wFSnJ!wmq+S}LikYn>eLS_09*5~sw6M-gYSy^ zK3t=IeQ#O5eAzXp5c^JV_*qQF?hfS>e)V{A@WJg0NE`eI%x{Y|))B?O5AE$l{A=*5 z9)y?#bN0u_D4a}(FnGrFfT0%jyrB>tOWlI!4~VIuQ-RFcQCcwYF038siW%}4SugsWxi8I$4UFSU02m%{0^#G^-_Z_)aPd$iDt#-$PMQUg z+$gxHrZOAptebc^{+52Y-+m(WJqYPxPN{SAFyO*Jb^o&JYtU_g#%&c8WFQp-tFRWnxQFO#PWTM5E_j%H$-;yc5THEk}Fo_XZjDVs0Jx1?*)c5Zr90>5zKeL5O+tU35N(Y%)Npjo_yi!~! zUbo|_OWAcqW+whVH<=(w7^HSbnx9X|TO-Bg_tV(lD z91gxYYI?CRiG6=&-TuIN&@ctK ziKVF&r;!f_DT|+&j;RJRHF_Onv3J7yBz{QbJ)rTeRBsWC|o&iC33{oQ}{Ld&IKj*|h`(II*>Xoc0{!u-e- z<`_bT?ZQc&I01x=um-V?QXNsw?v_L9J=9gH(NwPfm}{ykQ3!v)DP`y#E6SEJ@(*ru zvfk2+MpqjG`Q8JysMSMSa0h7DJNa;ncj&Ay=+MA)cJ>jOWFCm)^5Ee`l?9&$_E-DN zSa+0X(j4ZJRV&*7g=enT6aFl%kghg4J~hDeKs}*TnSufyai3$ig=v`nLN+JvmnY1NpI*WmaEak{dlS<~zz#s%`>l<@Ph?r%(n1z!nhtQ|UBav2x?vMA%=0)X&L>nX$Cq%0{Rp_!B7 zFroZJvK{`{EYw9|sjg*m)zgg!JwGh5yU`dZ;M<ALcE zn)^tmrKNS}WZVmdv4X{wf_~aMab?#lzIA?RKO_DUWpF=Izw~b-=QJ(DWLq-^tSV5^ z*jMmG2rMARg`%$yIB}6Y`;(lm{^)&g3cAoSk(V;dm3XR9X@n7{A|>qU)5tXmDh#NR zwAEm@RhI_Rh8)Hld7FEn9$rirOPJH*)r#)YQ84$QmLD7)z6n@nyJL*cD-Kt?4UwL= z87~_peB~Wl;B6E=_;n8uns43ZYTBTBW;IPyU(&^S&ax%uFHb&GWuy?r3L?=UL)9Hu z6b0o%Y04vuyAKZ^W0Z$^?f+3DBq8~IxGowh%E9?Nox6RsYJVFW#w)j~OtSfAVvD81 z%ZreVn;c&p9{g>A7_fgWj~bqch&-seQX(ZJ)-N#_h$=uP;lI#JNcJvyA%3)+<#^l z)3{Hc*?1a^&X|4FxsLJgl6ZvqHr6j2uDGIrs}Xh{Gu}>2FM30Q0v`)&!SxUor+RTdCkD6#S)b;P<3Hpa`*f45Dk{C{`7|7H3=}Vq+PVlN z&)D3C`1Y5GcsO#jRysGdcv%h#!j=<2_W3qG{`Xvq#|wLVIY-CM;`b-#=jR&R6Q9E8 z$~fFnrVLwlEcne8>Wmn6BN)re{{4eC zIJih5$MzuMw~);qX!)1rsc!M0EGxQ)n+VKbpLGC?0<5_AcFOhYKXd?MAXoEAO3~sT z%G)IKi%@8q#g?4Fy$C#_qHF?;aD94gyGHvxRwss%bZo#(u(7g&q5>si@|i6$b>^txD8`Q8=--?!DxUZ4 zpIw6~%-X&^8=N6D1z|^A7fS%R5+Z}WvCKY2;MWjV!W!Sjhmn|mFUs$lKY@Qxy^hOc z4A>f^GB`CCnaLM}uLH@5dg6Vrdwv~|EsPmSaF)t;974o$8(JZ9)7)icq4oD~ky=Zo>^qtbKTSknb- zjJ{9MYjUg5#JS;3Jv_QBl~kji)M-Jp&NP?(`fj zqjopJh@rHJ9p~>%v#8hjT4LGi?UCi9yL9}APSh~oF!1TUpH#U4K?D%}2+QLWCMX+8 z48&153LCHiC_j&lTQ+Sb{EQnV+VX}t%^qk0NO|K5n6J!2ABw{*u#L201Mg8#tjwlp zWKhCErm%WwzwROIqS>WQOEKU74{&r3#qM9Rd!U9vHbpALB5Y$EsYZVq8)ZEN*W}iV zRLTI6@gm#7!FqPqu}P{W!XEc_1GvPWy~j%qFCGhF_QwMjz4UEdmPv!q2D7|jKmufl z9(=nlLsL|?)CO_deIzuzs8^G%z0F-6q0~X029{v%nV}cONJ+s+H%|-B|3`W0kJ`+P<{aE6R zY$d!uooMd+WOa9JkV4Y@P^QcWIeXS=V@d&1D4U*O4H@AW8;akK2M+ zbJE3Y0xD(K!>A}XlfB@AT$_ibreyhS1)!+y!hRxX2Yb7)Ci~d+xb9J=K#n#icS~DW>5SAQZN)zK8g{$pyc;Ry!-?s$G-b@QuNImwjLKi%2{z3Hb6dxjUf-e*8NzZ_TC|dR`_oLHyEEq@dk!1YYl$ zB{pWv+boc}gGC&cI~DhAMN*wibVwOXtzO`9@g$q5TfAuvv#G}(9RB@KlM9G>+aM_D zIH;Em1=4Xo2Hqge_cjSLI*2>r#A$alIZXet`bh>Ce^pl!K}?MR?vo2e*&nBNRVk0F z9Ug(RG;#mJ+5MIMPX-&@Aw_$70XkqIz}bWitoJ<2qQ5nr`nC0NipkC1RLD8~2CIGtm&p*Rb80zY5oGj5I7h?%{ z!-XtY&tJ1Eib_^-(iT~K3Gy^3iMOi|*v0`aI4XRY#giK#OPkqw=W4aMx@ClU6*I$q zu+}YxE$42@zN?1$6W{eLc7RTbmpCnol$ms1(I;7d4-;0Ed3gASZuy^XNN5dzfU|q_ z`aVM)EhsGKNI9XJ_iS(gInTvQjh%bLY zX4vY5>e)4Y%pe};a3$Ah#H|o+`(IP*>R{q~y}bh?vjjFa`<5vTyvbqd zN-=EM3=xaUV}LSAO-T>e5Qd=n(P+H3=DZUZjB}UsZUJ-Rj5l)(<1dm4U@)eh(5RnO^c$hT3C2NE%%rK2I=8JEd)|z zWbCe*&Ce&Xe)Ml_8+~ol^V%K>RrEj%-GzJK_O#d*e9g-f4Gn*Zr1HE@Sj=du=w(7_ zM&OMCsKbSdjU|0X%ON|=o`~VnrZok<>?ZlUc;W0^fAkBHE5Vs8^6FCrI@)TRr}E=0 zpdQ0AUn~1;RX`A(V=pEuVA)Ta2*c2N#A)O9yX$WpgiaKDp1eU-@%kbkrqftr6VoT? z>{d5JEKgs}A2c=(O~r&kv2RR2{B%-&3y6 zz5n~I<>j>0{JgR+>so%R=pr)teQ9uz#io7cWNDFEi{CS3A>rDzoBeskFWu46=<^Yu_wPTO`wVosw(AZu2krzMkE|Oa42_3`U(}7#^9nv3 zm?x%$N1##(Fcdd!@7*PTr1xSi-Nb-xJU)yX&Vl`0H&OEYtKhP;*w{O*8@@noqr$^+ zWlrTX`Cy-qu0N}U?u1y%zZZVtc))>*j$yasBqUBFLQ)mW@uBH?O%bJ=YRJ^{nKBpDL0lQ4*k3MKoHN){bEaR>|nY}IAlZ-BI@@o8x3L8r2XTntA$~e zi6cdhAA#pgW{*5VW05Q=+&d>d-ky&EHKV|zO3U14Z9hLTfXl!B_;K6ABE41T6pq)M zAoE8=*yS)f8j&0An**rnYzP5fzh;lIW$IQOLxbgFox*u4jpgHz5hNxVmpG)dYtbot z?wzf%pki77OoPB@a3b2)(5XLv*z$aT;s5>7NPvNIoaUF@|IC^fZ`WH9XJz<|&dAHp zZX=cXYcrEg z^i?26>zeWRH-%9}NLEc-VAXWq{V4j#k9x;95|4MB5*kJ7NAp=@kyT-(^_(Rk1iuE>IH+vyCLx)>iH$9PX{6mp|RNkhWQ z7+-q%;AfrB+owG?(h+!CE4Oax=?B%WxbJ2LsxpL-%}HY=fN2?aNOh|#YO)JE%<0{Q zSjYIDy+k>ES%@1%PkFwyOZw!No+>dhIa%=jJvOMKH+tMEU1Ic}URUVG1U9+IQHt6L75nl)4fQXN;qH#QJ|x!z0h5;OS_18qm$315Kci+AN+0rnDFJHuS}gT1d11r7I#-{q7!}}9CGIV zu6!VnF>QoUURFN5sOXwcQ;H^A3@+<=Zk`%uQ)qNAQ_C7kjUjnBrr>+I*I(y6E1V+} z!kB;ghx6;qOcZD{qsF)`d=b$JBW9bNegD?=@9y@JjGhPn?6cB3Iy(C3R)9H_X2?Pv zQ+(;_a{BeYE{yDnmRe~VfL!Jh$;|RhPoK%p5*v**c#_;p+geU9T~q<64e)^$CQX`6 z8<<-n!X7}W@Tv-!*IBh{`< zHJ82rH0(D!TZ}3JUK$&f!P50KOgB#&gG3w*$1>Xm7rmh&SqqZEm7a(?HeXp-TzJT%45l_7)sOODd%X@!vb6VG0x|J&~v)!Kv+;%g!**Ro$kfkgxlX0a*rSU z;_{r$P>-dd_!T+4WS*wc>md$u@u>VezWavd&l^`sK~bR zBi4R%N~+ROcRd3OVPQfoxta?Duj~Vo%4(vrO2LK~AMTPu$v8eRuxPUFcU>=yCA@JS zww+xioeCYve_^nHe;&mW~=_V=n zD{d}(Rz*D3!T?I_w0j^Ue|x(9Hw8C4>%&rbk9?+D87nI8o(Lyu;%cKg%*Nx&m`Qy3 zrBksD>A#ijfsVR5GSKKs+jxi_FK_rv2x8GRJhB(Y#U&_Sf{@%E;H&$E;;A7Eq5XAuk$>V@R_K=zs@k;Hjq)j<8JZ!PvdBh9z83JIE@^B zM#*B}KbwY*mM2adYU z7EKD_XVR!;0Woio3&|R~$M;!*T6p@ka~78Yr)Ufb-#CA<}Yy|o)Lt}af zl1O$@y38wWuMz;@HX zs_2x>aB@K$;YDi^haki2WL+)KN=~$9T zUVWH(9>8p=5U#H;Krj&#W(Z%C`g&E}%yu(qEvx{XJ0HkC>=2HQR%8X}L42!6eq)-T zF_}Ezlo_=@(5`U6~-&O4`TDq&xa>PZxv^+`SZ} z)l;N`9C~o#J>qF#sAlLdQ>P3^06lZTsQPFH3q9=VbWOcw#b>3ch%r=GoLd zmlU`)zeC-;yd>wb`Z8<_nBl`SzrpUObv?7I+1WOm9GbqDA4M(Bej#RtyCC}^Q3A7# zxS)6fYGUrV`vH%aRe(fm^&g2l_>fJuif3-Pz8X+ll2}a4seDb4Tx;o*%L}_4vdj{T zH@$R2y}~0qK78{q^US=hpvg#jM;XB&#cfIl;laZlYC;eC;0_&c+zE$h5XkVfV4Vdu zkPx1-qV~UZ3$UZ|f}hTzBzAJH{O#}W#`$1#-l`U6cQ~GQ{uEEDj?R+w*Q+(%mOKkv z{@ebin&f<;nM*t}<-Tsc$siS}&15*{`M%is0AypZA-E;tLmy=T`dac=@_TC?>?UdZ5v z24C{;&vyfi<7jL^>8Y`QYb~N z*2B04yLhMCHvXfF7#b`st?eFN4phfN4htS`W%Kj}s4=D*4=!yUP3PviBA8m@3e@%| zy9ZAu2*u(5F3E*Dgtx;PmCsVbY}64QyO6Q(cvVkRgYVU*_Il|M8+E?MD=i7V4h}*Z z8sRv7U(!U}Pv^;}=arEUmkmB?1KIJv8xvDpQ|WGd1-ZHRzR3fX_8|RL5eK%B_=$R* zP0S5(nk8gtM}R0SjJ$rF3XXvaYV$yX@cQJv{e5 z%jf++IvKtO0T>6l&`oS!~UG0)5LCf`wd+yUnF}?z$>Gy7YwT^ zzn=-UGo^q0cn!ZQ=z>l6+}U-geKC!%{%E{UZ+ftnw7_x*^FGpMuv^@N!$k2hgKK+Y z)wN4l1$W2=XO}G*vc=@gdSQ3MQVL@i`2RFfrg&*jO zovKc*_#F)66|%U`*BFpjFHqjH{9z8s&jFnREvMJlN44WSf1 zCFpN9pqEZX4>1FJTmJh68QG4>s%%xSy{}-d>*Db0YL=RMJ^&+;l;y)KDH)2@3h<1= zbOFDu%bLWgY0kyws6}O)Vp07Eof*OTy^(!dT84^KlrGePQyt!`BLh?3x0TeS=Ct^$ zn&~Jd;fvwGa0rjeXFH@#K!IJ~9O=)`pWif&)qvx044M7``|v?@wz(W%)O&c=uRXz@ zx@5p{wHdv!m3qme|GUnyRx9m?YF}mTp!bEh;Ht*!>}$1?A7_T0Sf3Yzjq$5C9DMQ{ zX6#m2fqQ+``t{)D(%7Oa$4?Qu<>hOtyGI&`>Zk0i{txi~0VO2dm0-?|u zmGt(e;6*^!%H8sBHL&B6<(Ad=*QsBGRxgLU^`-~B-;jQ`L{5T&7>Hm1GO-#MsSDKC z_a8)EUtbP&?~emwG?{Zg#CykL!0zQ;anSt#WA>`jX{%p;H1x*s`r=|<0yk5K>QsOE z89O<8G#ICSCun6PJ$g|6X7I5NV*U4IH_JAFP-F%@#rci47)zEnRHDIi3wx7J)G{uf zGMfx%>?ot!H0OY}i_y;GtUno|e9|)$Z203ABg;^bUea|{US@kcP1iuDYH_bmZt`vx zvRwyXE$sx=wj2}#ljX@*2nRjE{;5rCJL!_LvlOa@Ps*^OTj$U$^SBZagLBl*50e($3(~R7U&mB}gq%jcyxfh9^4nCp{%f~S z`o&09cv;sxkj90cciyoSN6mwQmu{LrGwbJK!+OiAb?(5;nameP9}WkdO<|I;Q9Fz8 z@tff~_`Ih0p2G12X!V}OIpJ(__>-=f(mcrZRabiE;|J{+ft#kbaT4iHEf^)qnX4Qv zSSz)QpFiVmx0J$^l!{F3R$HXD=XMHFI%zGSnb0D{ykuMADvs{%r#*L8lxK})6PwRW zzf)4%y`Y5kTh+wd?r4TNPRIRf$j`l60OvO6TQt{i5x05R=9bJ_5wP{`HJ-DX#F5Y0 zk(2-Fv!#{nVvOCz%h;3Ga}ABtj!z@HXC@{Uj=`ynH4kJ=U@LMWQC-?(dnyVL|-B%irXWP8(#BP4Yv|($V=h zEekL88=Ko^O;5*-^6{|`E^7@&UbDl<(}D!E8w+l4y~(#DB%Elu0ennb6u02GN&2XLX%tS}l2{PcUO>ByQrsWhHe9NzkU0 zor?;V+TDxC3fbp8SQHG};_osGrpv$nFfU!!+zc_cG!G5Awp%*i{KD7zcRO|UCb0rs!Z7ix@6AFvCIh~>9L%HNs*A_@U^f(w#**>QtdVDbP0F)$Mq8K zz@=91Z(9YTPbDQeSLWi=F7A3bs^ufk&wor#s8U_l3$%5`Jny$|I=(r#9O&Yq#@g}8PShTL66O|op2rYmgM1&CUHGH$;oK#5ZIji(BElC z2Wz#|(tP0n>2W0*!Jn(1fn5%wnBcD6z?7C)?6k!}lkoh;pCT=O$z~%sTh+>}iV&_`K^Y{)t7eM@OIU-t0ec-&!~unW?>rykS~( zaTfBaQS4a^76G>!mq~*stigp3vX>r!(3|t5*p0EwsOE4D9`yIWG$UspzU>D=EK2V{ z2zHIWPY|j9Jw0Mri9tg`7cZoiRAe9v*WLlE88IN}#j_O2)}ME5A-6_@If@^zTrV`c zq%N)yJjjrkUMoAq(xx|=otLbX112e z)shMSefsge&3kT~HUuVs)T-Tf`do?HxI>_~R4g1o*ZgZr-1bIppeGtIY1Uqxe)AX)1tpd_`cvb927-w2 z&km$*{k$|_r-SA}*QLPm)@)>L(3a!ru$?p(`ofE#r@Q_>%EDhQd@hX-fc9&Dv775F z+mTZ2wCvy$%j;#!-A@$S!vXW2U74=8s@BAC3m&_;_19jkK3ON#Tz+cFOWwJpCO01daaa|cw-L?V_CiEUQ*)^}-J)mbYGKFTTttT97L7~x=mq|F zFTlldRCZ3yEA;FF2Ns?Fvz`Tu8SyQjw$|2Nm5@V~(|<%dA8mTkUD3jqeowOh zw1uTQG?|0jNj0744hDvX1=ZC=mgnEnKh(^A&j^83zE_-bKU6>z7kw~rx6;C|>Xa@o zUt=S2yS;*awWhK+ra)5A)Z{%CAbkEMFbn|VMkm?l&x^qJTTFB&32HkyifIMreFx|D z{3OMF>ngmsxDw*d{>}_vu#@9gzw!hPu>YW4kx*-&x`jafaA$sy0F>XK1A35=mDNMj zb=sGbf8f7$nWdDm1K~*}wSVyfU0K^1otMW*NlpE$hB7s2-t1Q5XqT>lmA90xo%@5s z7v>=yc)S$PeMRi=wE67(GYcvn?IPx{z7u+0d;v%rT-PxBP*j8kh%&0Q{4zsB0r|(N ze?`-$Ez=F>1iy|kP3>3KZscp5Os-Ffe30`y3q%?k8%HK3ksq2H1e%+h!<$`lS3Syf zk}dsMFvcd>w#}L(V~s5mXDnuFJUBKsw^ji&AI-$iml~q|f*cTa!EKL_O=(U5CN>9YZCf9d|YJ8r>0*}eviG9r{aKXMv)xn=WDt*!kv zi3>UL35f((rNGU*cg4j}37_ru!@MX*V+(%BXWQ53b&v4xsc0dBt~M?Ef#3N$F%fQ; z=Z8ZgbNLYX%`ZEo&kR#}`JRUbU05ShoY4)ov4@-iCmZ<@#9i5Nusz|N~*IAM1lpK5K}lO4&Uqx!9lBzF>F+B=!~A*sX^(=N8DA*Lj*Hh&bg5L*i! zbU>-|PFmA9g+e!lWXX@;-p?aeNVSE?Apxh^u@P;=pUcHh8<)QL4U-tG{z6Dfc~ zGN}F&yN@U)revsl?yT>LNaCFeGRV9kWd^qbhkUYJB3ARH>Lop(M&vb#EhorJ^GZbZ^g$W zWNdXAe^4`*#FHJVB%sJ_8BAep_S5OcdDc2pAot<%E=n{sn8c|F1~npn)=;rqpfKWk z_zKc8<8^@fiWD9^OijS82-jz2Ua-s0y|MT|TKmqRsJgDp?iM7d4N6jy(14Ob0m&da zBbg>QDmiB)MF0UB`etfoYW_@>RsOh_)936H z_C9;BwJw5wL%HP&cnNJ?ivn_eq2*=Nq^u}<4fRUy;90S?X{zLGliwSByG2wnpHb%P z$$EP-=-G1m++cAMDj&0p@%fYGa&&`k!ME?DB za{hz#QuMNkx<_9n=9VfJQopfJ#1rD9e^6QS2ovT-8Rp^ z#zf4PM0gYP9nGDnD!hE3e*fTy=5PU(1FuWg)D%cjor4r)9ec`r=>5fNfQd@EYJ%TS zde=M>I020QTkWB9cHBYc;?x~qY+kSFJ2R@YT+B?DHo5ZFqLP({g31PqQ;1_Vg4@A?FwJpBpFxV&e-P$70 zS@!U=)WT+Uwk7idGDCVnw7Q{#f?}u~JcU;<0r)j^k|A}tN%I@T10NdolV*<#{S^n6 zh1>`|Pt05vB%aD*W@iu0-=1uu5)b?{tYy;tWrM_VBmudyXzA z^;hJ_3q(u{7i=a_ptvFPG)2)7Z?Q2dW;(rPt3DWag6RHA6Gmga*F20{99P1Rr`<>lNe*5RZ(h z7iaUyFORrnMcYiAOul*v#O1P z&Y9o2&KI})q7L~Ts=e7~CU02lXPs>v`AK#L=X{;;asm3n{MX1||n#4u1Cl81|F^AyWC0p%Gx54^|Y-8@@aW?f$Tktz1iH&dG zoEs@z;sNCP3x|K>BY)|~$H~@L--H3vF zrYoe#FFJ%ddI_bZs!E_n+E|%)t|Y8^x{X9L^4=|~;<537GRRq@`^Wmh3WJ9{1ha=t znVE5Wpj;VX3M7Vt=~x>|Z=)3gmkwm{UhAk;RAgeQ4u z#j3ZKs+`dS!sy!VA3r-jV61K8KaTr(w88YAcYefZs9)1@IwAshgfBJV(Fh3`d^p3B z`2$l>rVQ@EWoD~BqSIdZSR{Z{WKaLPZRSi`hpS_1%I%;0{&)d}dmCZc_~SFi*&x^S z0jLY!%FMh;bb1R{C%V$Ja^mxYU1&i8$Os>hwQsRR0x0t)K>Rf4qS(=~-aGd3bncBe;~qo&6S z=2uEmLsS{?Mn;CWuaohGu>xNj#)1Vxj+P!o|CT}FzRCjy1{nzy3*PW+%&z_uX}okM zkz6#K{@rK$C%fne56uD>>9#nSqQ4-}AfwHlrx`dp!Z1*_^(q`I&48Z^PWkc&N(NMF zMjyoyw)W&hi>@r;@elK#TB%L+wMA%zIW9<^a4e@|s_0wZyv|)hO%fy5v+{$PcnJ9I zaX|HE@^W*t3V1{c;1PqEc?nZo&{Na>GmicJRc=CQkB8b;!IISIy!DHo7>AEIuzi`Ch^ zIwnTRxmnc;-w0IYdwX{M>r!$HzC{OqRx^le7!nlI|$WBab?P+906eftfH#Ut`iVpEC0 z^GmxBJ)rFX>$_6cd-1!!G(P*)bsWk6_2Gv zjDvrA^Ukb+gF=w`JKSwhw3AUleMFj$fz&!vnA*4Y(A^!Li)l3`?OZxEAHnz;VsPK;^JptAz|T4 zz}@}t(D-I{ezkhe^~`jm$)19Y52fXCc-`S7sYk-D^7i|`p7X36zyL7*$B!;&K^A+O zXGIcHYDzr`$>|;@37~u*MojEv3r;!9Kr>cpOMpsHgV;`A|9t7Se8Fi5i3SI6>rCIP za2EsznigbheO9IJx6d_us~a0fSNI*2vK+B-amm@(umObP-}Ak}vzeZgqI(=dFeN5~ zG}dItgV8GAgVDY-8X-o7zY-e8oCmJT;X$cyqh+~3a+Eus1fMZ8CL1S7pRN|GuNDYBX3v}yZ zh{2g*wMe-GR#_kWBMFr#i8|R`f&?@+3Vl8pGuS(1V`Y`p z)4NyaFdu!k-Fn~2z~<>EObF(2>d*2|r|Tda)^|_P;X6zzD!>lEj9Ca7AQ&iv$94oD z=(wU%y1J-Laju4n2WPV&I!^EI5OT(0=D=NF@5@XUV92fv@CQ@c=l!v^)@{xvTpD4P z8ag$l546ureSD~i#E$8;IqB8UsGBF_`yP|@q zH-5qnThTAkHyt1Mb_90CVjg5pZ8W*D%!}S&c53nhxBk;2)!g zAkf$GMs&l(UF89uFh#V&z!pflFf}A6DdNqKTP%D2{S>yBok3^-2eJ>vcr+(r{lup4 zj&$5=!%978(y6S3w#nW(u0_*el(_QeE#_NZD&YO%iXE+yk&&6GwV}YGSs|Fb7_o?H z`zE_NKLGwr9=q!Uq&CY*9f=#tcNpmRwPIDO<)QJqWlls_z|bpS}IJvhK9knBUSwh@Ox#YH*rJrs@p zXVU;N${GtQk4r9E%(2Hx|2F_6RNm_K{|x|Xf(1YpJ_S9bq@+~S(|c81ayE0Ntov&G zHn@O-8)ednV|91pGNftwgr!>VBC{=N_uC%H zK~QuP4wVfaz?R1!KI?(FEJ(W8!K6`c9uKA7@d$d63V7?pEree!`i60nfJBt%>004R zGtk%z5cNKUK&-8;9i^FwLc`Xrx61=>mFhd~^Or>^CU#-9x8fSffoJ1m zcsWo6Dq*-fBD7^+tk|UQCQ>2;@E5BsmW;Ute{+rFCPjVLeTqX4`FxDv=Eu*An_olW zN`0UyGc0JF@}7(A#+6%f-s_LE;q%}d2o#!MC?MwKd9LOwr zM-;6o7pFXfU0-ZE;h@XCLAaP)ndSQ*);-lpkOhE9T|4<1WkYV700_KvVCT|pe*_>F zyY>C1y0L3M<4pnguaG5mY#`F{KYa*E z%1&}Cj{DZla`~Tzpz<`{ra`pK{2Jfe>+=Qq%3~2~pRk=jdandhpF48v!-D`&a@E`B z#2K(~_j$h$nLb0!dRI{U%SLef?K9{F?+{&L1_Tw{!Q~}ksh6pfUK4lTb;4NhVmUpq zFiUZOk@7yCu_rzCf)Rw(dvh6{WK^>%i z9`18kt?``{LhB_zQ(E8L|6i>~;;xED6{u#_#M>5oZhLp&A}e9X04xtm7E1+0>6piv z!JvJ5)C1+acObK|pDz{k4dt7-+&7m=;+6#trBHImZ$F5v!b z!`sY^0j2`kyZcI`jfyE@u>#VfKR(a=0mL%f8d-q`CDxJ zFbae4rD~>XqSm>kMG*10Fi=& z`gog=hbnEZDKWBO1_(<`0w^#UX^P2?AbT(c8N!vS3{AtQ#`^?z|19PF%E)6<{C>Cc zS6Wqta-%U)Mc(MfZdkX{9lM z0y}meUzl0>N4o}nKDPj}07nOK>7JIGiV?C`#7CZ!BKi0*7Gl2#8|2NwV!X>mRx>>% zZAeC8fc@*d?8Q|}S6o1T6vQ5kwT?L2*Pvq{k;7j<6N7Xu47|yc3wipJ!r<ObZ%U>1eZf+`Dh*Y?gX162lJZ#5fFu$Or(x46ccnmx_)#P42aLVtJ^!Jg z6}l9e)hGRXswLt#4NK3DP6)MHsV3Mb&{q@ubZ z)@HOY*5$uP+*JZx6OOSQLh_A2tmETuoi3P#Z^%IuJ-9%+@ zC*X{~#t07dS4h*IHVqc?%*@FnvpJg@a2If*qynm|e?Sp~6v^|51KqAs_)y-}#xxW_ z^53qG%WK{c1=N^lDUu=fIAb7$-vkukw-3P8ZlFXP(;Yu~w6UG68Ua%RMVu>TkVUv> zh8GC3GrNiH2y{VVV70|TbRLe*-OC59mA4T$dz)*YhboghuVaxozPG}$ILK&cbX8Pc z40Y`0>syD@32Z549$$%bvOrprP+28Z>TQa%2_Pv_Aa0JZ63ECr^=+>1f?5#E0^;SZ zpz=j{*Q%wDh<9KogB&AER<&MSieU_Zi5#H95ys^Abwj#0A2FfZ_xVryb7cT=OD~YD zpiN0Cmo)4b>ui&L0hCdKv)LMY8_d!=7kR6 zkjrUQ7Z;)6NeY0vtk_5x)j+QdQxZfr{t_lO%RcwifU^qhj* z7f~OL*n+2ui}%l{#n=tNiU-sR;6qB^VrFTCzJrp#Li9{UkhJk$W6jB5!9x>UZp5d=c?kISV}${FEGTs z1d35Q!)?yhs_D-i)k;3SF}+t9dSgkP1n7nkzm))MjPONNL#>TjDPed45P;1tW|=B? z{{dFpwXuq4Nv8500Gs5#XYM~0&z3UKMmTbf4j%|94r^?~by8+%NeHHbg8}=^d@4Q? zTwP3EvB;-YiGsk*g)eU@rD;H?e(v_>&nY(g0O3dCCgXkqMsSte^W+%i<|gKR^c?Y- zEUCR%!j!dJ^eu@zkX1G70f;1r76M-Wv+)Oa#F){$0S6oTiAvuEJ3T}Ie|mnAzo3UVWC%=8!A}E+e7}lTld-VoT}A(C>2{#saNQK#%o$xu zqiIzxE~y+K26e~dS%z&d!yI2SPRYoUogmPz9c@2IxkaeUTe}^01*P#JKuZpfsK9SK zivOh&P_e}(HKcOXpYB2 z-i=YZDB!+O@ynAg+4`jER%&K;YWEm8*5Uesb#cEl0|JI8d?)jqcWD2sW%FV~cfG2u z9%cCb>zsx_L50w*LHQFhFAwM^0&CxOLA%Z*b0=ovgN4L$JI~v{*bV=N)M3q3je-V` z22+1D5Ety$&j-YDLqO$$V&5~>e~W~J1Cz>Ay@x(M4On@PXWz{C$vyPmsMQ7` zJK6P|Fclpa50VFewv+8rsLM)N!G78`0+9z~+Y=9MG5BZP#7n_&(x&28ff1vK8cOiz z;j}~Nway6| zw+D^yQYTpNL{g;N>2k&bKnSF~34VM~VIc=U{1ZF>IPxt}lfnA~Dq+vWPF|wS?q;ZI zGc8g2?WHf;h#v>KLfCY0#>=^100E}Kkv2unWROP-?QSb6Bc*7!@ylWrzP&W%0^*Vs zrEEiw%$chab}0n(e7|tlE1^OZ=y6bgpP6~vj#e>MXcL|%I6q(6y<%X%aQU_EfS{Ft zoi9_oEYDV)g#`+LwTMVnb)aGc;$#me;sZDQz{Ngs61WZ$iy_@jzZ$JroNv9l96x|S z$mFo!2)N|i>0!e>6uWKPBrky9YE2h?g2DSRvAQCL2RLmS*EWLh-)z)gFdIVX8K%IK z^sH@W1(CkK&K&JpEAqOi(2swliNO(C9Cm-1cp+B?<2`rne95Fokb5#mLzJu`GE$_*t6t4pfTl&HrLdBcw<&bhM4Q$DA=NKF4>$%-zp3?o@cSSg8>B4y7dHLT3VoFtr7qFr|-j)-cBtVz~{} zkVBonNJ|8UUE^B#Sj>X541<%?siF+hj|Nxtk28bWACnaPij^mcOzm##3B6rsV)!;g zSk-lV^OnWOClx1BU%qG%g~NKA93giAW(sfag69|ihDYbl&Za)+KMoiyr1`bcPNO2&}`t|o;HLmL_8hMf-Ldnta zF`pU2GVTWrTzZHTQ+u$<-HrwFlv@!kz)9)Lh7%WJRW_XeZaMr%ZpQ6}%2y9o)(>L? z$DfW~00D%~Vhkt`7L~&b@9I^3Z34*>yB5)gFxH86J|d-A14FOZi-_|{>+Fa~cPy{y z>S}XV${k^o2Y+E#86Qylfs#G|^oq>tYyTS+IqT%BA+;+9{n%)OfN zZoN-D-snLJSNOI!a+R?s{x{d%<_*6sw{v_H0kYc`2)W+N$mH{_?opQtE=CD{v>zBG zL9^G>{Qd1TXRyNsOS*B0%m5_cTAKno4$399;aKTvH@{ab) z#bjK}oQrH!uye5@%N#;XZlj5SLMw$cTo6!{2X9A);lIR+!WIs}#gc7vNyAB6oOTV;nBbuIxHBrh?B4@iTGCYWZMeI`%MfGWO$p&>J~AMs`9m zBltt!zP_n!KvQyAe+$YsEqM_|POfZeYsb--a^AJ|tq<>?*L!g(qfSj2pI^c}s-p~l z)&J2tJ^et%KP+Cq(90Rd#SiW@QCaZ;ZY$9ZchGlsHy=Kzl%lwl#W)Ab=C%D?##k7% z0h3Nw%QgCm`ra=NC)nHmm?8d@iYgPg?BtaT6N>4RQE-R%4L_NG|3po9#r~F#S^gwP zX#e3RPcz_OD_;0K&-E$9`&dwL&WiklQ0_YF%IS>B@96kyuZnTNM{<6*Mt&Y05c+-Zc?5AWsJmWWIP6~hb=u4E-a-BCT$FaH zt`2ZJdjhp#o8D?)^L`tE+sc5V-^WLWx~#tAeH`cG?>S+JcRfOwwh$k=wKRg(MxffR z@R9hU{5EKOWa_P(DLS_drcrO-rW~j&d3~=QonaUCM7h^21qCFs&j*-MeA~MW!mduQ zgM$-YG&%W%Y*sfwWNxgkE}t;&o2aU{_58s=tMdj_3G}~w3E$Bk$iOZo&9>a`Rdf3S{LMj_pEQ^> z)vY#^2XtAp1A#Kr(Pk1o`?DNyu#+>XxB4c)>`UCHLt=M((Eeihk2&LsMzKIf&o7y3`SU1#Wi;iz*g89&kvB`_Epy6F z%NlJ}a>!sHM24f?k*w#&=P2N8*| z?hM*Aj?{n-Qu_0^VC|HaC0JX76#*;>z)-`n49mS-Q&Z0Ah>XlcA>kY1wBkMWK{A*i zFa}8KyO-BA%U5|f4gFj9hvY6xc57;x#&pdjF^Uz%-IK9Wy}jmdIH5QEWHGRpk{V*r z(gNA3$~^8Dgsju2n17pPMCDtsAsY^#*KNxHtG@kr4dms}x3WkU;00IYePMStF&;P< zg6Vkm_b-14k&AKmZnj%{`cD@Ov*W!T7lmcyF@!CL?wYTxh_eEO?A%Z^jj$`D)XEo7z5z-DWKLSlPpHs3 zy8RMg8-8+6?W}GM&;ph>0nVC$;D~yz&|4I~FYdQeIgwS0biMGhugDJyrNj5ZINP|n zX~)V-gMaURcDoB^UjzJX+=t4_M>2WpGI>Ka+N^2slK2ZXL-yAQl7YX>OnC=Df#-6Ri7C8%IYqFl2p0!yi9?X1{*@nwO6+U$ankZFi}+(PbrC zHA5gLEsYY?L)M1#m7e*JaYk=%Z50SDxww1#mdm}G7_Yp}Ms15}e8nS(nk=~qW#egz zbhP8xv+o_%-iw3-H)ynaO{awAD*(J2wfN}8{g|68FV(Fe_eL^TMG*3+tk!@XN%$s< zcBBP-Y+%u1ydu3IMftY**f7HPqIQy6!yx_A&BWJC@-Enmot%;=BhC2gFP5dH{S-kJ zRl^}=>HP8Ujauzl4avwlXcJp&YEy0MjFIk?m9@3#-%!G+0NgT{J80WNs}MO8lhc5X zeU$rQSI%@jPwT*S?tjk0e_pT*xhsal?qQ3|HeFeP!;XUsy@6ceMODf&8Xj&Zi(MJ& z>nY3_7$>!yKYq0!99LVD(y`f~g|4%E;mdFy1AfHD{sD@<*};FBI)DFUCEVM@$JFbE z?_PR7RkDfgy!{*xcsniKMVy3`S@)dlPy5tV8smsGFKvwY1?{CY?u}F|i;4bB{3`X+ z5g@Y(ajT_)6W`nWkZ|l=WF#2>I@sSwW6!QfcRaVYwETW?cBCYN_%!t6WsoN4@(Kac zwA!W6^%z|<*CrFkE5g1x)e)=EU~SWD+?JNER5lL79#27boI-+v#hxOn_3rO&tYT?J zKdCkU}c_2_hXog=+= z0s_cnJ7dz#^Qx(8M@epd&*?f-aongyc}R4Asmy@J*yWTno^io4M>%6aPuW zE#tB_Nn&E~Vr&?JN&~fQ(~CD+1_l{UIiEAcR19AGOcIXuDX*`Lj4V&h8fE;2gaZF< z`XX1p23&+hyn5a_g;UOS2C_z)icW6<0@ zg;v^;82Eu9%bl89^)?tGFwM74P4V+CfA z{hfiT0pCdQ#;gNmo&nW>u8eQmT!#Bs8-3tWxvit^q(%7i+vP>^wXqzj{Ch;$W++w{ zX_Zs;`TF`&R%%49?T*iL88tVa&_ZuWNc|g7{TPb9EUO6*|H{b>Ihkyo*9xW}?>hoV zNObqBh0x*X8#{NPy|_XRcq712!YU*9w;i{?61ZIKNV(9^@aeK5@$Y~E$(X!%-7B#2 z`80YgFx>^MfBtA~QDNWLXMaab~_Fo*-# zE*yVIe@0QIZ%@1F;jm+X9QxW)a{l`ZWv`v5r)$rYL=hMRV9CfN@)0X98{FROK)EfK zhyee?xC#F_$Z2|cDGHNgY_PA$Ggf~0&HL*#(!P*tq4nh#%{o0L>|KQ(HqI|X~f5FtsjLFHtQeMdUgX;@eP}tZ_ zeAfRwuC`DaKNPX5H5Fd@H}>v-$Mm_9^`W9tfl%Cnyo{ds|9CvcwXFdfFLHGqSVeSo|ggv9_H& zkQwiHVKd@%+Cic6LK*_8qDPrwwY0!@C#*a@krsnlqm$JZN}`OULtK9J9N2(xpAJH& zi&MrP?I6%<3Vd9>{VeN(rJ8MK<}i`J<)sL>+EgV3avmJ8gaK5ILLQ5O1h2cyRgo0^ zm9(AFiC&BlNGmF~N!iT0G$$vg(BD{3Z|G!irM9Xn*JIxIXzgNjR9m4yMT(cQ|5N-s zqt}<(CR`VX_2E+4P)OHCwBCF`?3nY?&*x-lm!39fIt@l5dk4A z1hNAhC2!$Y42=@5FbI;_JaSz|;=DTg1>m0A6U%WlH zXz;j-_zJCjOH*!M0WA^lumJ*b*<&!yV0n~cSk4u`ZTamjlaqX-!^;OZ)4mvAdHswd zCh&^J@4YssPfvfpJ$LW(p;x`37w2B3hePUT^UV#Z`P7*|2fi{y;4|$szDR@r10O#M zB!wUvi*w*CA(JQnzx^`Tu)NbT=bV#~!7-`{PQ)n`q5!A$gS-fwN7Kju@fXH@Um4i0 za5{c@-02boJ!3hiO?5nXy~=$x7menNi;sWe^#mLvRruZRIn$`NnJ5n0YuCQdY<^#L zSNP{IG{)jDEA^xKdjF8=fzR3bMt2i}~0YSm@Dq7o4IW zxQyG}+)*5EtD|ro9UUHi{;)qE!5^g3M@mTog6D&Rh`pqkE63Mv_mD$S%T;iO0tw2| zq`IfZ;3lWl{g;z+p4u7RE1!t=@9`jmplq>(2!?YH{EyWc?zQAiPxHYHF%GMJU*t9L z1%0X4At;m{Z9KR!Y^LGlH03$-#Ciz5&;{Pt!a|H@kZ>huQdUct@YCw(jL}{vfgm@N z4@GZF?k)awsrB9+;j7d)gr%mX*&KT=Znk|Dkp!_vO(QDlbo!QU|V6FhtZx;P&v&>pfD64Aqp3neZ4Ync+IDBX#p@B1rD( z%?9UZwIikY`J+0 zNWeze<3)g#1@CD%3 zZoXqg8{F|M8mRNz7)G96OQ{6WG%O#8p|~f660DCcsCX!`$g$YYg<3B7a4gl)iTWT= zLMOwot7z7$SbxfJ;01!+^0~9eRN?H}j<*L#CH}d(iMaL{7Dhs*bp84%UddyU-)}!X zHku7%&zs`>-gVU4osmjShCA#Ay_EZW3NB9T?ffZ-9g{1!$nvtY6<0?wAHJ{i@W;KS zjHx?l4KFQSZEx~Fu`^!|rVc6$_(f{HsIi!t)UQy!;se0EXMGZgAoP+C^9^LqqZJH4z-*!;x{tHbR@hWjs#du=HwCaP?nOJu-e7bDfXcwDL;|Cu;M_t^Lq?T$I<@ zPL5p`Di5|$%~W}lejuP`LXQ~H+?ttI-O1v)*SSw<^H{hS} z`E$($k?tI(=;)-IC5hpg^!!a5eArP7EFU{ zwGwB(5fcHE;Yp%#{zqN@?v;GK*M*+wmT+ui3hN!zSPfmHq`ig^Vw}EW=5kalESdvAy2&THt=gvNcI}Ha_AOl=gL!bHN zD7#|^TcgpgEpKd`|+Swd;;d|6oFy}RZ8Kfp}yC zM)lsb4EbG|Dno@udSW@b9oQvi@9)u_W0=y0C7g1;Mf~LUB2MZ;z81o2o@L0!b~=n*m60OO1*+nZ=K z%SvXe-NqG6+V>Kf=?cb(NC8~G#O-mV#V{|AO%9zp|pHtVYNXb z79TM^o3^9E&&qi?7j7Iv4PG;X#jpB<=8Rd_fm%k3rT zW-qp}EPG7S8^x~GjWMXPxJC*)XK?m9{=A*yhZT0v-%!%-Nu_(~w*z0@lbX4-_=+q; zO%`LEuOpO)cU#KYNxBL_?f-JAaD;^#UENVZoO8t=C7-63W1@L~WUMvPP%3!{oOuGQ zvT~?rqc8vi&v@Bw-p#leCdL=AoP}I+!1rVF3_xZ|zHBTWI;;8Gzy6qQZuZ<2T#_ip zW_i+=z4q97s_N#W48c09nwspLWz^RQsT^m3bma5s@L-7CKTI92~zowrbtv zF>#^Jp^r^((0NqpQV7-_^;rlN&rf0&e4doJYTGq02R^>Ls$r5|=H)W;;{p`u`6!T< zeH2T{WQ*^v)DOb*p3Dh`i6xxum2(`&@uH9cSged*xh^!fqr{a=Q?WY}ffBVxS6G9~ zdVL{GOb~*mN%dY+z5nnbE+r-Z_}CX99Pnr}eEsXW4!42Ro9*xH2&G@WkMifb>5Yaf zOGMf2~zoepTgvtRBTVkPxR+`L0KnTBiO5%&HpfrsxYq@xkC&Zh1p_x1uYx z{Vh|iIj<}^A1>}x3+VeF!Wiz~>3yGN!A;(Ncw={+rBa*-qOl!jbDg5jym;~A?2h-G zdo{aE$nkM+@p1tL6EC;*apgY9x_dvb{+#cfrx^I=T)Fa2F^CtED`9VNo|>fkIIx=* z(-jx>}S1Y3=h6FnS}qxQQ`L%%4B*C(Nqi zx-Rp&4djsA7t;?k7>TW?%k~x4F{D~uNy-l8`HwLUOx}J80_kR|zm7`Ge<67xsQ5KR zfjQhAo0_p717$eBXhEpw+B!*X(VMeIK1 zf5h0*Pwas#l>y?PwPDolgZSg9pcJK+##f7h^@<}Syph;{Omddgx-v2$16us2ZW1K~vJHc6z~;l5dCBZD{&fppLO(!>B4G_-TWPI#Kl<9kwgS1}2+A}VUs zlY|et1d^C(`iRTDg9A(DFOx-$;U~1qDTs?b3b&0i#@7coi7M6OLz2ZZ=1e?1D|yzM9dZEa zMVytfTIl;>T$geX3cQkfRhv(IMqf6c2jG9%|K#-r9Cz0JJz2Cv>m|Jdo4$t~9VJWK zpvYZ?tx?_Xr}26JA%C#DM;7n5T0W^%>n)Dt<&N4NX7_}neLSoObBmsW%m_mp-&B2J zuH&}vvmUqmQ|OLi>5E6YiE}Rw_zi5vLe35owwtLDDs>j}2diT@94DZ_*_Mm(B#0tY zBXg9WQKg2&%q8oQd!6_{o*7{`_(PWl+I4sKNpk7<(Z7c}1(orJwr1AWVDI1-`rMNf z84mV{Aw?O8~J+>2;Q&#E2?12*VmI*3|wYw;2j#XCH2;ki@ryoiP=Z%AmuB3c7 zRRqG=w>`R-v9SJF9&|$AyQv`>+3$_c|DH|@*4b@B_1?TeocKjZqg8tDwkevMyLabw z94!rAPGJVe2F>q=Bbm1pGnOo-#lS{abcN=amq z{@xpvqV@o$=l^&VLWSV=U#~@hrev}ILKVdNdE;6-$&xW=xk^$7dqi0lS>E!5L87!? zM|-guQq6l+gixm|s&TA?|EhjB~@WSdP=Lq7LB@%YFA0liWE$vq^pSt_v zSB#pH?U3SFx$;cg*sj@R9gfL^#*Rpi4R9GtIo|x}C6H)tJ&okyMGZV(Ob@ZMEe;4c z0@-3}S*s8mXm@sk!q}p&szzo$Ej|MIpM;3+nVKci{@Y`u|0p7-%A{e6RX^Nzjlriw_T(_cC?3s2lb7U&@&ZLK#$P$L;&=QPxJBoniRU#Bz3~n#7?rg<|(BqWK#BkSPmUoI~>7 zjyz8lD^M?W2kVd`{36tzOVpYzCBT2`!V^et1;i^`hCD_4Dit%x`9&8&=yVq*iFUn@ z*B)1-Y?){5&v55k;vz#A3^zr)8Iq&{k)-B}9 z-bNL7igM@5P32ej?5*AbsIboor$VT!M~#A8KJPYbeDjK^UF3OcEJ9+?ZRy3B|MHM{ zeF5yMkBxdXmDICD*-1njfDP>2Sn@W&1JwB)7<}mO*ie1F2mo>$uTReB; zOp78kklyGLWdX;H>Lng-_T~dO%`Bx4bUJ2>$&7h<1Rel~3X?Q~0hp@C5J+5GRTY0U-~O8mI2Pl%fqvcQx>!y$X1We zQ2+X5v2s53L+f^AM!2luVVf*RL|f`b*GjbE5NCoSXn(>Ox&4mv=d|bMl}`>~mMNSV z>#L)3qw5nsDCylunZxhl<&Ft;XA>8b4oM2F`!n2E(Z`P*99~TDLL5mM?TxyX&ZzU0 z3>p0OmgnfNUCUO8VCE4NOyJ1ZE`Hejma;!nCFy(P!ylie#}GwJwhhp-oT?Y5i=HYM0=Z+!dCF+|<7_-N00DB|dlr+GsZ2vaFhmSJ(=LPiYVW^I*9lAVa{uZPw@D@NB{4(8&= zc6P_ylRsbASLWsX=FLX+7tQG&=%v`WiP6c)jB#;s+=7B?!DQ5kwRIR5A^3)i%`i?g zPgX&+c&`+<4P?NsIv3HDgJ3>gKeLnEs9s0Q4E^q+OJ04?m6|QBc(iZEd$+Hy7Jyuh zF)U@OD8!KrqQ#w-h;F(sQ{`0+Uwf*O?;LGj%$#GPCW}DAoXxmj`9OWZMr9Tf%XR%^ zv^*hRFrlObK#zPAH}xoCo7lkx;=mViW#Za$U%d9ls#Zh9cCnt1w zw-+vZj{mI0-3(Fm80R$b&avk@^re%7mpi1uqbF-du-6JJ9#);W`vf`du58pR0Lu29 zwp>uQp?_ncqmlLSoncag z>sm%kzFnZ$uh+~R9|E?eZgp?^17IDMWKXXBWjL;iy{2r3ylXbU$0DL6F`qnj7a38d3q@az`}vAv z5Sw3S`eu6vPe;C58bN!tM1t!oE%v?2CN8kZ`T%+Nt=aH}PDe?&yKC#kC$5 z=*t^MJ_zG|vO`$;2Db(xKr$%5d9$05)-T)Vj`(s@NVDVnOBs)~O5Alz#r`Zk&Vzn6 z$KhilR$Tz$_vv?P3=6?Sd-hR@GtaZ7Em)5IN z1K=F6DZiK&j5ZIS#Nc&F_rsa^$$frbw?1;uNt2UUyFWh}m$=0EN&2j2&Ynn4>Lyv| z11G2AlG0N6vuCUkZR~({qmPij`3@vTGG?oMCl0+Z9zp85Og%9`mgJ+GyPqSJkiMpQ z8e}Ydpmn>yHxq%Nar@OYgjMZG>ZeDUL@!l?)cnfHX`n8qP<}DeBRRdJ~27rRb zTO&MFEm&mqb&DDfMAqwgnfzQghU<=WpMjLguV=ASDdAS)BWUE{M-w3_P~kqbG^pWF zke@g=`%H^MZY90x?xm?c1l4qWA%EGiN?_`Zp<-cF^ou#q)2`t zkpCg8l&{QUml(gG?Lc<#?*0BuSb`DrefLT<_x4m{{I>rhYRGPMzBDe!$p3=>iCF~c zycrCkI$gVGx5LNYoTx21xJew?+Cq0T@X3rbtc}I!=-}N|{$jr&zV_Al(@koM0uH@& z?}eM4i_v_W7%c(!Lpd9)|Si84sx6?g<#x4E0&#ru>Vwc2{@9HcJ(gMdP!FwT04(qk>6U z*$OI}{uEJ(w>YERhiIxYEs+?mi+dw&b%Of0{SHtAWjS&0_E*KmG>(6f<%Plf=Mt0y zj=#>ijlX;}JaGjYcn`Y6)4xgk=PqPTY1!X{a+j)Hi|M4?yk;mD)dDU8mZ`YqaMHhY z^;=eIw5pUk=bnkM!Jb*<{wBcpc&v!}7_Min0NqH1Jv+E@s7#Vf=ioOl!whkGI)C_YHDazy$okgI6Gr{B-b$wLI5S z9?uULzSSI=gw7@7u21UqcxE5FmvOtX*8omg)HBNza}^}LKy3K^hoJvy5COr( z1v|KNzG@XK=fez3tkOR+~ za?#8>zXxNy*Ro_m$#AU(=Qd`KgKNoK)Irf?Up*@|Yy!Qnf8Up0 z{ByWYd#FkhpCDS3ivkTmcZKsY=)`n%5Dvu9Qqw=hV!y<%8kAVv&&pTDzq?Su)bVwv zqtPn?`{`>(!T_6l=WaJqr1Kg?V}8NZ$`6FOvw?X1w-?~bRV^d?E)-D%;QXNJiDdD{ z#<&-1v{cM|_QS>x5Y_ID^GRaVwQBNjwvV^EL4WFZS}7b*w>=w!74bUW1iL?EUK z1ET)4p}iXM8YaO{O|9Hp7xZwsL-l9;wAU2P+J@Fo+n6ldHwWQx9rooY_VzAfn)iPb z2E>~v^pD)~o)lY5p)R(}c&S^`!|=K5k-M^Cz{Z2TwKY7z&3;wzG?u#$mqz*vsuyp~ zAE9;3)b0@nvix26SWowT(~9j0AB{r8_=KIwv(d_U{#EYQlf8%u zDWaD1AO`l$R15LE;9>fVRor(wYM{P;hnMl*W8D%$=E`l)%Fw3WFYS)*mc}ocjXNu| zRz!0YYE}JuyU@iVw~_`pv8Aq5&f;iNj#r?vXT;bgsYllxc0^ApL}243qw`I>QtiET z#3mMek(ny&LPk(=7}%Xa?T_v$tUn*bTR)hG%GY~Tc(N*{*X8`@a2ZGhBcjvmX9$wW z*Pt4Muve5}j*#}!9tYfff*}vak>#%&cjT%z9xk39p~{4B*!Ho#to!otaPkbzuU7A$ z{@_O7tXy<8N%YTGv$I<;7XRD)hI~w}k**Cyh~0Gb)5BdoABkd*^@b%lD8kYkfdB+; zNwfGpmpD8AUP}fQzk)i6i0A?hiv4RjztPjZP4$^)0`w!hEEm*AusaAp8^hu}CUs5+ zFDq!zc?MWC7Psjd@B^;sZ&r%PDiqZDi2zwoy94JOHRQq%GP&8}AX3N#Yp=I3-0%vQ z0o&$37flMx60b*8#7JdzZtF}o=V-28cnrOZ0KSc;l~8uRO=)TA?VmAfx*t-Qr8AZb z%d=>RIGBM8!s^`T&p_mS6Rrh^O$G?&>zdoUNw}At@6Sr*@jG#woxhOg6gj&V$l(F~ zD)FxcbU3d5%wP}m`7@m-#$kMai@3J}Ai%&U1K51m-I1MY_f9(7JCv-afY#j*T=J?l z1drnHWNA0O_u|)TwVbQ-FZv?lx7_k|bs9CG%?J?SKo4CS${!0i!(JqMJ;qz8C}cTG zXA1Hr-cZ9GE9`?6dAByG?0smx>_^UeN-$dp2q4_uu>{5+;0^a`>-|eOV>w2Yv&4>md+w;y*v-;B*6UoIg`4*LVV|KWGH|2BESYH<8 zDtZ6Dz8Eg~MN}H9eg*EdsiM6#(qqz|SHCMs?*kJEPQsJliO3WK&Zk|gS=P9E(P+3{FK=qFH zd`}~{4LEQ3ej^#~YlIR7{dpu(OpQVO9*-u;GisGD(yv-0lai`u=06Kr+8q3u3&)#V zSe!SYfQp;uqIZXzol9g6IQD=33Q-PWqKmU8%FcRyspweLaRPm`UT=gPI3BwIO*fEG zD;Cx>OS#X4;X*It(jH)&2J7p$k!Om2M^7xnp=3^1sv%h*r5U)7m^)XG-<;Rb)QpRY zN^cA%vz=~v_s6?d{nJfoz@b00w>V!9Wfl<^&tDoZ0Z2P@MyMtJ^^eAAz^NWQ$x3lg zjOW+O97r7bG8h{dXZ>fkori}9w=z=7Intq(hsZB;UDT)?cOWQA2ysjpiQN6;jbPWQ zSFhyq;Jk|oMh^?OJULFo$iYD=i%$33WS3rFRqaKd9nVV?8dSOFJo)%nx(djwSa6)x z(jFPNx^NCpD9nBt0U8F>EtQPEuYd?kDID{098+Bx9}CaRUGY(RxULBm^WJnRiWf90 zIM|wBKA1-q?j-(K`S_<(0g(BlGiqw2fT>3}Nm|lgnpp0>`HOQ`M#r%E(hY~FK8rv~ zxvEyylyO5;J12x&Gdqd&@uPH)#4o=GHUr(32dapGz{$OD9=$_HgJC}sZZ%yP3FF9HXjftq4! z0FQIU!P3>POMrItkcrvt`AiQ*pos@FH2qBJy|86Cs6=i?)eb3hj(v9+LK(rn57iV% z0Q(haE80xxA5XdYyXx@1o}bdut_~Kkbe*Dnsk)GTB+W1##A=b^mRUP6;a;!s~gliFP{*w20 zAnKDq@=_;QK%LWQNX6;2#Vv) zhjLskBdW8~P56A5UC>yR5K$&hL zuyx>6A`R`;jXWGNAL`>cIt^+2Z$i7H*y#=J}n>%Qm`Uz|~oQr&$D6BVaP2 zlGWF(t?HX3rqNP#_J~9x3mwL*R`1^$VFI@lqr@O}Khh^I>L$Ra(hu%?6u7R}60n*5 zsP-nVnVP!BeO$sCsEgm|^NU^Qy8(hH>qfdpZ+Gxs_LG!*YI|k%LJM2KoqucXnC7k% z$u+N5X4%u$9c0>*G5eqg3Q}B84{!j#7aTRS1O@XVdkT_d40J1cTk8&P?N2P@#ZHf3 zc{YKru0t47qyvO=S0ZTypz^WySe#qa1;m#J&i+l$N__Kyj;<@pReI z4Blho7;yrO#?dOy5~*X1DGhi(KTD%eBm%5`a#vg`Gw_Bn1fF5_Q3%khhCRD3ZbaMj z4s9RIYj{@y&c%gII`SjXbsIp1)V_-|X-3{#lR_CG{Cl;)5msxuN26x5&{ za|`#`Qi)oYF;R+|<0=C99IMSEr0s4LA1Wb$^lKXr53FCxUFf0=6;M0Y*!D&Xf> zsOaGucM6%a0er{yxJNuB>s_{U4{dmzS@E&mWeMXCG|UJ8e+VxV6z)w}#InExRp7red13EFLHDPz50w}YwRh8}t&KBj;g;PpZf2L=3L zR|lnz;Avb*{CH_mFrc_)uU~cS0HeTSKgr9RKc7B%w61)WOE>zMw~)r}W?eDp-+;-n z=!l0WgWfQbIpC*~B;Y$pjs1?4==E8{SOihWr#(kNo1W`TS$Fx{ME1mPR8AZ0)qg6g z`?FHZgihL3Ya%&)pM8_XR3E#!r67uo`m^yrMkc4m`NVYU0-NDK*A z71mE2Xdmsy2fGcMXsl0QtK8a{E+;Y5xPzOR_LKyAjsG(@)CueqlBz0kpiicfsaV4o z=$hl*SFA)ZiA8%s_ZwI=A-S*1V_LdZ1E~yrf(hLc$_#hX*6_94(b91XMi=iduu@>j zOK6q}d;$oQmbWI&8EP^YnDvU}7-Xa*wuqKK0B%R_$I<||>&i!=46iLVS$bnFQ0<{F z(_@YV3k8s}+~Z?_lKJE#IWsR`nSC=5Ed#3Gj{1I8IL%MCNSc^V?!@@GRyn!-n4om6*7SQ(uhF0z%I&*SAgJkANcZXm1MZUAm z;n8Gpgka6Hj&6q!2g>QFA(Aw(S567|`7 zCx3UW2a%(pk-;7wDNwI(GcK`xNXAmuvNsB%3?$5f+&Io}lK}x{U5weXpm~30bq)H` zyo}iu_wq`g2h?IvDJ%x<*WE~_+@Gl<=hn&Jh!@bm&E%~3IP=ndQ&I|uMhJ8_tIaX0 z7o`)Dcu#&&(@D|NDGAoFx~Jz6-##yxAZo54c1}EHU+K*$_-O(b~V%%~C;%-_k?D=B~Iu8H&okQ?Io*eO5(gc$1sXWsEU_KENhWDEqF^XyCNKUL|2FGRzV zOV5>Wy^L7)7|u^BGnL<{1l~xQ<7c|{bx!jkvkwC2{<}0s3=Omm}Y| zW;Ak*8pum<1zR75t0q=C_U!6iUIBY)mwese&~XF$vlNX6TVU zq<=KC7snkSWf=tceO0>(14fZo%X=agfO3pzE1mfZqB+9hG7$Mdc_(9uRZ_~J5G;$! zx9G})Pv85Sg8vul%D+xW8@ChRym8HIBVl?pU`X8w*;pBmS zI~s6i)pKPtTxkso%y2$C*)2;qDm28RhS56PzhAdB6ILfj>fpu3rpF}A$p3muC94y` zY#!YaNYvP-lB6W<^Tbj>QQz(|F?g=b8X;&qA?1^}5iXgryZTj{mm@L5ppl1pH$*4rm-gDw;}SoR-~=@9z@ zM@j}Po{@S$OQX;jAaouvF|pBp2zuO*;&Gn-a_yRgEwUf|nX~HbpeLPnf)nt!yvE)? zop9fyqLKus^)$#p2APdQvPk?c41u#GiG?@{DEh*xY<<- z?s~lWD~0-s9*&-YpO?3PwmpV`Hb+V=m7@tQ03u)4dJ%^Lh#rG*$?A}VS`vUrT7@4kawOXhV3?RXhw7Vqc3%?x=R*32Vxd9t)&{i-6fVj156-k57KAg@ZFYQ zO>bTmD=+=1`jeox z^Os&y;R3;m+TaUP>W$8ZHUf$VA~N9v)(|F|5v4V4aFxiqZ+>SpD4DG#p&TmWK3+%s8h2cHMo}hn@?2tfc+^PDH9Ox* zee|Xmq1l(?&s3q1Ib9L51_*_A`BzB(H`NH{cqDwQO8x_zm|6>=m4|Hl^7R(9K`$^D zhdY>82F572vbR)}b(yfMoqd4oe)r^N`#aE*2I@*37YX}%E_muDKChLUCZX15w<;eC zDv4r8o$Mu?rz*4AD6C_s6lWKW44w-llt{N88Qv6+)HrjizK7n^7p%9f=52wu+rD|} zaHn)>Ly;M#M+Odj2-*~i?2b-gE$L9*4FE*vVE$4k{o-PntU?PNmYnH7$RQ+9MyBpY zSt$VPulIb`itQi6Z1Ad8>vgS27E=mfOZ&66HJGn!!LIiP3S1I(hz0G#;Vz{;az+cz znXh9u_HG$JcJY&@4E+^AkOogro0?l%=7F-s9Fa8yie2DrsYx(rVWEL-o0=>?@F#D% zf%KasO4?dbZ+JLIpQCca=VGyi7a0c?fw>Cij%aJ{poLh!>p7AJ@wVsI(9EUQA7F54yQHNF@Pl- zYTL*{W)P8p0S5-l?og@dpG4pd06U!>M7RR3b;5^CmcPP1KdjuI*TA&brk<;VL*Fme5Mnwmu$$;|)RM}{c$08drs=9Xa?^GM%3$TfA_S*np zfT|bQ0}@)pVoFNv26KOJJtHN>sVfW`j5Zd+^EP@e_dNi^L=6r~YUTGXC5b7^%i~Dt z&mmc)bs6qH1UvQg*zzcMr2JV4gWhKD7U~~%C@S+jV33h&K&2vhKLXCil*FIIM=DG1Sx-OCyI7Amyv7oy#Zf8w zy{AX3++p0EF=mAdBG1a#%l9yGlb1&*FN3!MyQj=vI~VQ&nY@F))qQ|J_JeZ>gEzH? z|1x+JsfgHZraZk+!h929*`s#Bi&hNBfjkN(GJu01Mcibs7~CqkOB-C3S{@BV=d?E8 z6E@mkcN~&qW3Jv`>u$-BbKI9UuW_O;)}}WPlC$ ziUg&=T-@Rwl(*kXSXK2{q#%>i>*t0JZIixc-<~+uiC1ksY^GrWsY?C>JsBW9dt^Rz z>(j^(M#diZ0Zqr&@aH+PS)98Kn}1q%R8!OGl4Ctq@=_F zGpKflBM|XG82Bp14t(Q0JkemQTKtIg-nmFszyb8LFG7L?VSwlxOp^AIVosDMf!NmO z5>S0#^R-Ou-(Gt6)3?Z$;PRQIdf`I@(eR5+>ifKmi)I5ZV$eZGrCePi5Sf90m9;Tr zkT+!XK?k4X=VN{BX+4GwRiW4cY7;<&R-?k!K&}JL7hw0nzzxTqQ2=I;w;pKqb$+P4 zg7*{pm;YInfkGsZ4kY}6x7Y08AWW8Jh2ifT#SVOQ82cOd9VYavHk!Z`RW|`=v4*=Y z7>~Vmthbk@h>#g|E~e4DExZKg<#>2`mB9>{LOU2X`*KrIt?D;}@{9UYZ=l0|k!Bwt zs2osBQH&avmKS#TN7=fIAxEA<@^n*S5qQdeJhe?JE#;!VtOL*|MDrCiZE?ILZD42K z5FPFTGM5^yYAPQ{3~Cw zV$GG?mnoT(#MG*`H5SV!83GE(S=-0|MIDYqBGsxH!AKSlZw$cvfa(EQvVA^Aiup*l z7U2K(7*zGz`+eaUI$rJnDH@<45!+iTNP&MMcKA==ij0!WN04-UX~<0wTZUP-nb~l&9&d6X51Vy#BnPydnBD8k`fg z?avA)-5O7)?{1$zf9~k&3fl(0+R*H|PShi6jQ^WxfUR+o>)J(cTB9QMUY|}WMLRn? zmxUvyp+FAzqt#d737LI4@0qY{6)tXYaQOH@j;7o1&z5gLW@TpbfO7=4nW2_q#>fBmG|Mj`dSD1T=} zzkh!*j9FUufU}YNt2F4yK z&7*@q&dcVCfwcY?t{ba>u`h0J?kX^#W>cG)o2vw-Bf(>9zDKJkRoWwY8F!ezqgiCiP}Y3g=kw}7`83==$htGKw>m#Xfp_#N;#kTGyv=E4OZzUJ`#3^GBW z;{QHY3L+j%4m`Ea8EhV{GXP^&Kq$59xxGnX93o$+O2ZSydi?!&b-2Z}luXok(fjwA z_H7G+3m8-}^$)aA;-5Imyn7Ek>M+O+$#5`Zat;n}91G&rQVL-rbhHDRu`dY)Q1KqPBXhVfqyyi6qnQE=Q%WVr6`o2GD6$2R$1+Dxfpv3?jZsXML0V$8^nHK;i+RVR zzXw&#+n0CNvfqJ$)MrM7*6qK|4*zGW79vnQ|J%gw(_oUbnBf1MlR~)wUir^==D8kL zkqc=juOR6b-7Tr6i{%5SWJE}^a=-#avamV^Mrh)h1N0ey`dN8zROo}+-+wf8T+r6} z4B%lDQkf07Kq07V-;^Mi-%U`KmNFldHHb8yg_1P&IUZ|u^dMl4Q)?4-P z$@G2bB_cF2a*u!+<$oO%|JP~feLMM!m0DCM=9xWcg(LC?@7Db;99xl&WMHtF0E{qykyRCT_?o*z9Y+$$meB13aD}P_VRo=1#LvBpSx?lQ_q=O&>N3+WTUD%=g8Bi7fmQeF zbK0Sy z#b#}}j+1pufTro)2jkEp&a;YyvFrI{mvHdPB{!;WRq?rN1YU!LjB22fj0Ft_xL5AC zSuz=V04PLte+r^xy#EZif)kj%W-r5hyTj}|V!1nh{J6w0BSeh^LbHf9?y( zHmE(*y88F$UcL3Sm)^)X9h}GlI3Q5>^x5C_RNn1Mk<=2b-PZViAL-@!5AUT_Sy`!D zWc-RlW@dc)Q7Gu&ksL_;a@g+kD;;~20qdRLzYja<8yc?J_I-Kd2&%OVvSYD4 z47B6RQXz-!U0pjEFupjywW%YPSyFOu5@_h_)yIE250Y=Fo0z17(OUmHFrdD%r^pWG z2R1NvBloO6_IU0U1-;4Esdmrr=`qcXz5CA-ARHDPF%ngD}1E z2pr|@rR!h7+T|P8>Vn(Kg>+%h$PzzJKqXY77=} zntlvc8eG@oz&D?MZ5`O~UnwtjAxG%w&uxGMJsQ0?1AO4{dGUdQFJB%Kg!bKGGivFrA3~r(i)pbO|Mb(LoM6Tm zoAiz8sf_xOEUpPSJ9L%DdO0$!lH z$*aY+hK||{>Pdq3SZTapSH{SR0!sPzEd>f$R(Gv5{@Vhcw z8{EKhT}Ev%P7A(!nZz*;HbKOp`exBo5497IhL> zJ&3&Y%yB(jh2wS8?T>~Oe-#rSt=sZEqj(u?9#3h=>iOV&cl(dijb?iNSESIhTc8wn zoTG!}J_As2`zpu@=EM|G+EY;RVlVJPf%jgC7=r>{@yM8Rzd2oNP=Rb3dVEM`HEyMAiX z=;cIn9cRY2W_luMvSoOy!E);01dQd*11sV`pWVRlDU-Y1(aO)10-ECazxY(!hG8M- zWk>_Vo!v{&Pm>QX|I_ck-qHN0tN-6m-A;o4Itldr0FW#HFYe<1^@~QRDPA>BewC;q Rd}#*+lUIFQ@X$Eu{{Y)ke@y@Y From 57b82e3e3fdc7a4d07d0fe4d248f0c99557ce4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 12 Sep 2015 11:55:37 +0200 Subject: [PATCH 0849/1872] trax #18411 fixing a typo and doctest continuation --- src/sage/categories/cartesian_product.py | 2 +- src/sage/rings/quotient_ring.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index 464b47f6638..f9e96ed94f1 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -120,7 +120,7 @@ def __call__(self, args): sage: _.category() Category of Cartesian products of finite enumerated sets - sage: cartesian_product([set([0,1,2]), [0,1]) + sage: cartesian_product([set([0,1,2]), [0,1]]) The cartesian product of ({0, 1, 2}, {0, 1}) sage: _.category() Category of Cartesian products of sets diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index 7ab13cf160e..343b72fe3a9 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -31,14 +31,14 @@ sage: from sage.rings.noncommutative_ideals import Ideal_nc sage: from itertools import product sage: class PowerIdeal(Ideal_nc): - ... def __init__(self, R, n): - ... self._power = n - ... self._power = n - ... Ideal_nc.__init__(self,R,[R.prod(m) for m in product(R.gens(), repeat=n)]) - ... def reduce(self,x): - ... R = self.ring() - ... return add([c*R(m) for m,c in x if len(m) = FreeAlgebra(QQ, 3) sage: I3 = PowerIdeal(F,3); I3 Twosided Ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, x*z*y, From b650e6924e656cc3810091633ac379eadaeef741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 12 Sep 2015 16:16:49 +0200 Subject: [PATCH 0850/1872] trac #18411 fixing some doctests --- src/sage/categories/finite_enumerated_sets.py | 2 +- src/sage/categories/homset.py | 2 +- src/sage/categories/sets_cat.py | 2 +- src/sage/combinat/sidon_sets.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index 32f87b1242c..1c795543d62 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -496,7 +496,7 @@ class ParentMethods: 'sage.categories.sets_cat' sage: C.__iter__.__module__ - 'sage.categories.enumerated_sets' + 'sage.categories.sets_cat' """ # Ambiguity resolution between methods inherited from diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 412352a9035..31e467885cf 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -859,7 +859,7 @@ def __call__(self, x=None, y=None, check=True, **options): sage: H = Hom(Set([1,2,3]), Set([1,2,3])) sage: f = H( lambda x: 4-x ) sage: f.parent() - Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of sets + Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of finite sets sage: f(1), f(2), f(3) # todo: not implemented sage: H = Hom(ZZ, QQ, Sets()) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index b85cf6a45b7..2a4f6dd7002 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -231,7 +231,7 @@ def _call_(self, X, enumerated_set_if_possible = False): in the future:: sage: S = Sets()([1, 2, 3]); S.category() - Category of sets + Category of finite sets sage: S = Sets()([1, 2, 3], True); S.category() Category of facade finite enumerated sets """ diff --git a/src/sage/combinat/sidon_sets.py b/src/sage/combinat/sidon_sets.py index 47a0055ec81..d595cb2b554 100644 --- a/src/sage/combinat/sidon_sets.py +++ b/src/sage/combinat/sidon_sets.py @@ -46,12 +46,12 @@ def sidon_sets(N, g = 1): sage: S.cardinality() 8 sage: S.category() - Category of sets + Category of finite sets sage: sid = S.an_element() sage: sid {2} sage: sid.category() - Category of sets + Category of finite sets TESTS:: From 0dcfed91905b5fefdf2e1d4871e59516fee8dbec Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 11:07:38 -0300 Subject: [PATCH 0851/1872] Trac 18411: fix combinat/partition_tuple --- src/sage/combinat/partition_tuple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index fc2cb20db4a..cb1db060707 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -1563,7 +1563,7 @@ def _element_constructor_(self, mu): """ # one way or another these two cases need to be treated separately - if mu==[] or mu==[[]]: + if mu == [] or mu == () or mu == [[]]: return Partition([]) # As partitions are 1-tuples of partitions we need to treat them separately From 613cef5652f98414665200f388e8e41a0a1cd4f3 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 11:35:36 -0300 Subject: [PATCH 0852/1872] Trac 18411: fix testing issues The current testing framework does not care of _max_runs and wanted to run the tests over an increible amount of elements. This commit fixes the issue. --- src/sage/categories/additive_semigroups.py | 4 +-- src/sage/categories/euclidean_domains.py | 42 +++++++++++----------- src/sage/categories/semigroups.py | 4 +-- src/sage/misc/misc.py | 17 +++++---- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/sage/categories/additive_semigroups.py b/src/sage/categories/additive_semigroups.py index 755b6d0fcaf..df6ea42fce9 100644 --- a/src/sage/categories/additive_semigroups.py +++ b/src/sage/categories/additive_semigroups.py @@ -80,8 +80,8 @@ def _test_additive_associativity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from itertools import product - for x,y,z in product(S, repeat=3): + from sage.misc.misc import bounded_number_of_tuples + for x,y,z in bounded_number_of_tuples(S, 3, tester._max_runs): tester.assert_((x + y) + z == x + (y + z)) class Homsets(HomsetsCategory): diff --git a/src/sage/categories/euclidean_domains.py b/src/sage/categories/euclidean_domains.py index 75ed869b14f..9c701893fc9 100644 --- a/src/sage/categories/euclidean_domains.py +++ b/src/sage/categories/euclidean_domains.py @@ -87,16 +87,16 @@ def _test_euclidean_degree(self, **options): tester.assertGreaterEqual(a.euclidean_degree(), min_degree) tester.assertEqual(a.euclidean_degree() == min_degree, a.is_unit()) - for a in S: - for b in S: - p = a * b - # For rings which are not exact, we might get something that - # acts like a zero divisor. - # Therefore we skip the product if it evaluates to zero. - # Let the category of Domains handle the test for zero divisors. - if p.is_zero(): - continue - tester.assertLessEqual(a.euclidean_degree(), p.euclidean_degree()) + from sage.misc.misc import bounded_number_of_tuples + for a,b in bounded_number_of_tuples(S, 2, tester._max_runs): + p = a * b + # For rings which are not exact, we might get something that + # acts like a zero divisor. + # Therefore we skip the product if it evaluates to zero. + # Let the category of Domains handle the test for zero divisors. + if p.is_zero(): + continue + tester.assertLessEqual(a.euclidean_degree(), p.euclidean_degree()) def _test_quo_rem(self, **options): r""" @@ -114,17 +114,17 @@ def _test_quo_rem(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - for a in S: - for b in S: - if b.is_zero(): - tester.assertRaises(ZeroDivisionError, lambda: a.quo_rem(b)) - else: - q,r = a.quo_rem(b) - tester.assertIn(q, self) - tester.assertIn(r, self) - tester.assertEqual(a,q*b+r) - if r != 0: - tester.assertLess(r.euclidean_degree(), b.euclidean_degree()) + from sage.misc.misc import bounded_number_of_tuples + for a,b in bounded_number_of_tuples(S, 2, tester._max_runs): + if b.is_zero(): + tester.assertRaises(ZeroDivisionError, lambda: a.quo_rem(b)) + else: + q,r = a.quo_rem(b) + tester.assertIn(q, self) + tester.assertIn(r, self) + tester.assertEqual(a,q*b+r) + if r != 0: + tester.assertLess(r.euclidean_degree(), b.euclidean_degree()) class ElementMethods: @abstract_method diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 24f21e7d132..3a3777ffda9 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -114,8 +114,8 @@ def _test_associativity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from itertools import product - for x,y,z in product(S, repeat=3): + from sage.misc.misc import bounded_number_of_tuples + for x,y,z in bounded_number_of_tuples(S, 3, tester._max_runs): tester.assert_((x * y) * z == x * (y * z)) @abstract_method(optional=True) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 915eaf14e93..62e8911c214 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -1724,24 +1724,27 @@ def random_sublist(X, s): def bounded_number_of_tuples(elements, repeat, bound): r""" - Return at most ``bound`` number of ``repeat``-tuples of ``elements``. + Return an iterator over at most ``bound`` number of ``repeat``-tuples of + ``elements``. TESTS:: sage: from sage.misc.misc import bounded_number_of_tuples sage: l = bounded_number_of_tuples([0,1,2,3], 2, 3) - sage: l # random + sage: list(l) # random [(0,3), (1,2), (3,4)] sage: len(l) 3 + sage: l = bounded_number_of_tuples(range(50), 3, 10) + sage: len(list(l)) + 10 """ - from itertools import product - tuples = product(elements, repeat=repeat) if len(elements) ** repeat < bound: - return tuples + from itertools import product + return product(elements, repeat=repeat) else: - from sage.misc.prandom import sample - return sample(list(tuples), bound) + from sage.misc.prandom import sample, choice + return (tuple(choice(elements) for _ in range(repeat)) for _ in range(bound)) def powerset(X): r""" From 3cc80709f3285c6fa012475681a6a74fdc0f4bf3 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 11:37:40 -0300 Subject: [PATCH 0853/1872] Trac 18411: fix composition signed --- src/sage/combinat/composition_signed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/composition_signed.py b/src/sage/combinat/composition_signed.py index 0b23b034d2f..eff46c83d51 100644 --- a/src/sage/combinat/composition_signed.py +++ b/src/sage/combinat/composition_signed.py @@ -131,7 +131,7 @@ def __iter__(self): """ for comp in Compositions_n.__iter__(self): l = len(comp) - for sign in itertools.product([-1,1], repeat=l): + for sign in itertools.product([1,-1], repeat=l): yield [ sign[i]*comp[i] for i in range(l)] from sage.structure.sage_object import register_unpickle_override From 4e507769605e20213ea92e64bd73cbb7b1d0195b Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 12 Sep 2015 09:24:00 -0700 Subject: [PATCH 0854/1872] trac 19179: hashing of chain maps, chain homotopies --- src/sage/homology/chain_complex_morphism.py | 18 ++++++++++++++++++ src/sage/homology/chain_homotopy.py | 21 ++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index 7ead3532c88..8756b31b448 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -182,6 +182,12 @@ def __init__(self, matrices, C, D, check=True): mC = matrices[i+d] * C.differential(i) if mC != Dm: raise ValueError('matrices must define a chain complex morphism') + self._matrix_dictionary = {} + for i in matrices: + m = matrices[i] + # Use immutable matrices because they're hashable. + m.set_immutable() + self._matrix_dictionary[i] = m self._matrix_dictionary = matrices self._domain = C self._codomain = D @@ -520,6 +526,18 @@ def __eq__(self,x): and self.domain() == x.domain() \ and self._matrix_dictionary == x._matrix_dictionary + def __hash__(self): + """ + TESTS:: + + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: hash(f) # random + 17 + """ + return hash(self.domain()) ^ hash(self.codomain()) ^ hash(tuple(self._matrix_dictionary.items())) + def _repr_(self): """ Return the string representation of ``self``. diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index ee17dbff578..01f15542d9b 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -197,7 +197,12 @@ def __init__(self, matrices, f, g=None): g = ChainComplexMorphism(g_data, domain, codomain) self._domain = domain self._codomain = codomain - self._matrix_dictionary = matrices + self._matrix_dictionary = {} + for i in matrices: + m = matrices[i] + # Use immutable matrices because they're hashable. + m.set_immutable() + self._matrix_dictionary[i] = m self._f = f self._g = g @@ -371,6 +376,20 @@ def dual(self): matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} return ChainHomotopy(matrices, self._f.dual(), self._g.dual()) + def __hash__(self): + """ + TESTS:: + + sage: from sage.homology.chain_homotopy import ChainHomotopy + sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 + sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 + sage: f = Hom(C, D)({}) + sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) + sage: hash(H) # random + 314159265358979 + """ + return hash(self._f) ^ hash(self._g) ^ hash(tuple(self._matrix_dictionary.items())) + def _repr_(self): """ String representation From 70949c7a0b4206ce99e834f09f488bd682f9ca1c Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 14:19:41 -0300 Subject: [PATCH 0855/1872] Trac 18411: fix two doctests --- src/sage/categories/sets_cat.py | 4 ++++ src/sage/misc/misc.py | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 2a4f6dd7002..030b8b68e58 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1984,6 +1984,10 @@ def __iter__(self): sage: for x,y in cartesian_product([Set([1,2]), Set(['a','b'])]): ....: print x,y + 1 a + 1 b + 2 a + 2 b sage: A = FiniteEnumeratedSets()(["a", "b"]) sage: B = FiniteEnumeratedSets().example(); B diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 62e8911c214..02bda8aa568 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -1731,10 +1731,11 @@ def bounded_number_of_tuples(elements, repeat, bound): sage: from sage.misc.misc import bounded_number_of_tuples sage: l = bounded_number_of_tuples([0,1,2,3], 2, 3) - sage: list(l) # random - [(0,3), (1,2), (3,4)] - sage: len(l) + sage: l + at ...> + sage: len(list(l)) 3 + sage: l = bounded_number_of_tuples(range(50), 3, 10) sage: len(list(l)) 10 From 9beb0234950b59a7f755c05753e55f0c8637d454 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 14:31:10 -0300 Subject: [PATCH 0856/1872] Trac 18411: bound number of tests for Domains --- src/sage/categories/domains.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/domains.py b/src/sage/categories/domains.py index bd59791a8fd..be23ff4205a 100644 --- a/src/sage/categories/domains.py +++ b/src/sage/categories/domains.py @@ -84,10 +84,10 @@ def _test_zero_divisors(self, **options): # Filter out zero S = [s for s in tester.some_elements() if not s.is_zero()] - for a in S: - for b in S: - p = a * b - tester.assertFalse(p.is_zero()) + from sage.misc.misc import bounded_number_of_tuples + for a,b in bounded_number_of_tuples(S, 2, tester._max_runs): + p = a * b + tester.assertFalse(p.is_zero()) class ElementMethods: pass From 65808258b9bf22e5b7d6bb1543f7e2ee30634337 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 14:40:31 -0300 Subject: [PATCH 0857/1872] Trac 18411: fix is_empty --- src/sage/categories/sets_cat.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 030b8b68e58..b881cd83949 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -2126,9 +2126,11 @@ def is_finite(self): try: # Note: some parent might not implement "is_empty". So we # carefully isolate this test. - return any(c.is_empty() for c in f) + test = any(c.is_empty() for c in f) except Exception: pass + else: + if test: return test return all(c.is_finite() for c in f) def cardinality(self): From d0f900a9b5e6cbf8640807a7be46c96a33f8363f Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 19:46:39 -0300 Subject: [PATCH 0858/1872] Trac 18411: remove two final occurrences --- src/sage/categories/rings.py | 15 ++++++++------- src/sage/combinat/root_system/plot.py | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index dd4f4e3912c..ec0eb6797bb 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -580,14 +580,15 @@ def quotient(self, I, names=None): sage: F. = FreeAlgebra(QQ) sage: from sage.rings.noncommutative_ideals import Ideal_nc + sage: from itertools import product sage: class PowerIdeal(Ideal_nc): - ... def __init__(self, R, n): - ... self._power = n - ... Ideal_nc.__init__(self,R,[R.prod(m) for m in CartesianProduct(*[R.gens()]*n)]) - ... def reduce(self,x): - ... R = self.ring() - ... return add([c*R(m) for m,c in x if len(m) Date: Sat, 12 Sep 2015 20:25:25 -0300 Subject: [PATCH 0859/1872] Trac 18411: hash for EnumeratedSetFromIterator --- src/sage/sets/set_from_iterator.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/sets/set_from_iterator.py b/src/sage/sets/set_from_iterator.py index 3ab4303cf7f..3546b11f6a3 100644 --- a/src/sage/sets/set_from_iterator.py +++ b/src/sage/sets/set_from_iterator.py @@ -180,6 +180,24 @@ def __init__(self, f, args=None, kwds=None, name=None, category=None, cache=Fals *getattr(self, '_args', ()), **getattr(self, '_kwds', {})))) + def __hash__(self): + r""" + A simple hash using the first elements of the set. + + EXAMPLES:: + + sage: from sage.sets.set_from_iterator import EnumeratedSetFromIterator + sage: E = EnumeratedSetFromIterator(xsrange, (1,200)) + sage: hash(E) + 4600916458883504074 # 64-bit + -2063607862 # 32-bit + """ + try: + return hash(self._cache[:13]) + except AttributeError: + from itertools import islice + return hash(tuple(islice(self, 13))) + def __reduce__(self): r""" Support for pickle. From 4c50a1c201712abfb567c119e0eec1fa9f8c99b2 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 23:07:42 -0300 Subject: [PATCH 0860/1872] Trac 18411: more explicit call in CombinatorialFreeModule --- src/sage/combinat/free_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 323562aa98d..7773a5d187f 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -21,7 +21,7 @@ import sage.structure.element from sage.combinat.family import Family from sage.sets.finite_enumerated_set import FiniteEnumeratedSet -from sage.combinat.cartesian_product import CartesianProduct +from sage.combinat.cartesian_product import CartesianProduct_iters from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.misc.cachefunc import cached_method from sage.misc.all import lazy_attribute @@ -2194,7 +2194,7 @@ def __init__(self, modules, **options): """ from sage.categories.tensor import tensor self._sets = modules - CombinatorialFreeModule.__init__(self, modules[0].base_ring(), CartesianProduct(*[module.basis().keys() for module in modules]).map(tuple), **options) + CombinatorialFreeModule.__init__(self, modules[0].base_ring(), CartesianProduct_iters(*[module.basis().keys() for module in modules]).map(tuple), **options) # the following is not the best option, but it's better than nothing. self._print_options['tensor_symbol'] = options.get('tensor_symbol', tensor.symbol) From 321067f0c83cdb19e3b3e52ac215511f9ebf620a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 12 Sep 2015 20:25:43 -0300 Subject: [PATCH 0861/1872] Trac 18411: deprecate CartesianProduct --- src/sage/combinat/cartesian_product.py | 114 ++++++++++++++++++------- 1 file changed, 83 insertions(+), 31 deletions(-) diff --git a/src/sage/combinat/cartesian_product.py b/src/sage/combinat/cartesian_product.py index 125eabd2928..20fd7eb4a14 100644 --- a/src/sage/combinat/cartesian_product.py +++ b/src/sage/combinat/cartesian_product.py @@ -31,9 +31,12 @@ def CartesianProduct(*iters): EXAMPLES:: sage: cp = CartesianProduct([1,2], [3,4]); cp - Cartesian product of [1, 2], [3, 4] + doctest:...: DeprecationWarning: CartesianProduct is deprecated. Use + cartesian_product instead + See http://trac.sagemath.org/18411 for details. + The cartesian product of ({1, 2}, {3, 4}) sage: cp.list() - [[1, 3], [1, 4], [2, 3], [2, 4]] + [(1, 3), (1, 4), (2, 3), (2, 4)] Note that you must not use a generator-type object that is returned by a function (using "yield"). They cannot be copied or @@ -48,22 +51,56 @@ def CartesianProduct(*iters): ValueError: generators are not allowed, see the documentation (type "CartesianProduct?") for a workaround - You either create a list of all values or you use - :class:`sage.combinat.misc.IterableFunctionCall` to make a - (copy-able) iterator:: + The usage of iterable is also deprecated, so the following will no longer be + supported:: sage: from sage.combinat.misc import IterableFunctionCall - sage: CartesianProduct(IterableFunctionCall(a, 3), IterableFunctionCall(b)).list() - [[3, 'a'], [3, 'b'], [6, 'a'], [6, 'b']] - - See the documentation for - :class:`~sage.combinat.misc.IterableFunctionCall` for more - information. + sage: C = CartesianProduct(IterableFunctionCall(a, 3), IterableFunctionCall(b)) + doctest:...: DeprecationWarning: Usage of IterableFunctionCall in + CartesianProduct is deprecated. You can use EnumeratedSetFromIterator + (in sage.sets.set_from_iterator) instead. + See http://trac.sagemath.org/18411 for details. + sage: list(C) + doctest:...: UserWarning: Sage is not able to determine whether the + factors of this cartesian product are finite. The lexicographic ordering + might not go through all elements. + [(3, 'a'), (3, 'b'), (6, 'a'), (6, 'b')] + + You might use + :class:`~sage.sets.set_from_iterator.EnumeratedSetFromIterator` for that + purpose.:: + + sage: from sage.sets.set_from_iterator import EnumeratedSetFromIterator + sage: A = EnumeratedSetFromIterator(a, (3,), category=FiniteEnumeratedSets()) + sage: B = EnumeratedSetFromIterator(b, category=FiniteEnumeratedSets()) + sage: C = cartesian_product([A, B]) + sage: C.list() + [(3, 'a'), (3, 'b'), (6, 'a'), (6, 'b')] """ if any(isgenerator(i) for i in iters): raise ValueError('generators are not allowed, see the documentation '+ '(type "CartesianProduct?") for a workaround') - return CartesianProduct_iters(*iters) + + from sage.misc.superseded import deprecation + deprecation(18411, "CartesianProduct is deprecated. Use cartesian_product instead") + + from sage.combinat.misc import IterableFunctionCall + from sage.sets.set_from_iterator import EnumeratedSetFromIterator + deprecate_ifc = False + iiters = [] + for a in iters: + if isinstance(a, IterableFunctionCall): + deprecate_ifc = True + iiters.append(EnumeratedSetFromIterator(a.f, a.args, a.kwargs)) + else: + iiters.append(a) + iters = tuple(iiters) + + if deprecate_ifc: + deprecation(18411, """Usage of IterableFunctionCall in CartesianProduct is deprecated. You can use EnumeratedSetFromIterator (in sage.sets.set_from_iterator) instead.""") + + from sage.categories.cartesian_product import cartesian_product + return cartesian_product(iters) class CartesianProduct_iters(CombinatorialClass): def __init__(self, *iters): @@ -84,13 +121,20 @@ def __contains__(self, x): """ EXAMPLES:: - sage: cp = CartesianProduct([1,2],[3,4]) + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: cp = CartesianProduct_iters([1,2],[3,4]) sage: [1,3] in cp True sage: [1,2] in cp False sage: [1, 3, 1] in cp False + + Note that it differs with the behavior of cartesian products:: + + sage: cp = cartesian_product([[1,2], [3,4]]) + sage: [1,3] in cp + False """ try: return len(x) == len(self.iters) and all(x[i] in self.iters[i] for i in range(len(self.iters))) @@ -101,7 +145,8 @@ def __repr__(self): """ EXAMPLES:: - sage: CartesianProduct(range(2), range(3)) + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: CartesianProduct_iters(range(2), range(3)) Cartesian product of [0, 1], [0, 1, 2] """ return "Cartesian product of " + ", ".join(map(str, self.iters)) @@ -113,18 +158,19 @@ def cardinality(self): EXAMPLES:: - sage: CartesianProduct(range(2), range(3)).cardinality() + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: CartesianProduct_iters(range(2), range(3)).cardinality() 6 - sage: CartesianProduct(range(2), xrange(3)).cardinality() + sage: CartesianProduct_iters(range(2), xrange(3)).cardinality() 6 - sage: CartesianProduct(range(2), xrange(3), xrange(4)).cardinality() + sage: CartesianProduct_iters(range(2), xrange(3), xrange(4)).cardinality() 24 This works correctly for infinite objects:: - sage: CartesianProduct(ZZ, QQ).cardinality() + sage: CartesianProduct_iters(ZZ, QQ).cardinality() +Infinity - sage: CartesianProduct(ZZ, []).cardinality() + sage: CartesianProduct_iters(ZZ, []).cardinality() 0 """ return self._mrange.cardinality() @@ -145,15 +191,16 @@ def __len__(self): EXAMPLES:: - sage: C = CartesianProduct(xrange(3), xrange(4)) + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: C = CartesianProduct_iters(xrange(3), xrange(4)) sage: len(C) 12 - sage: C = CartesianProduct(ZZ, QQ) + sage: C = CartesianProduct_iters(ZZ, QQ) sage: len(C) Traceback (most recent call last): ... TypeError: cardinality does not fit into a Python int. - sage: C = CartesianProduct(ZZ, []) + sage: C = CartesianProduct_iters(ZZ, []) sage: len(C) 0 """ @@ -165,9 +212,10 @@ def list(self): EXAMPLES:: - sage: CartesianProduct(range(3), range(3)).list() + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: CartesianProduct_iters(range(3), range(3)).list() [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]] - sage: CartesianProduct('dog', 'cat').list() + sage: CartesianProduct_iters('dog', 'cat').list() [['d', 'c'], ['d', 'a'], ['d', 't'], @@ -191,9 +239,10 @@ def __iter__(self): EXAMPLES:: - sage: [e for e in CartesianProduct(range(3), range(3))] + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: [e for e in CartesianProduct_iters(range(3), range(3))] [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]] - sage: [e for e in CartesianProduct('dog', 'cat')] + sage: [e for e in CartesianProduct_iters('dog', 'cat')] [['d', 'c'], ['d', 'a'], ['d', 't'], @@ -213,9 +262,10 @@ def is_finite(self): EXAMPLES:: - sage: CartesianProduct(ZZ, []).is_finite() + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: CartesianProduct_iters(ZZ, []).is_finite() True - sage: CartesianProduct(4,4).is_finite() + sage: CartesianProduct_iters(4,4).is_finite() Traceback (most recent call last): ... ValueError: Unable to determine whether this product is finite @@ -237,14 +287,15 @@ def unrank(self, x): EXAMPLES:: - sage: C = CartesianProduct(xrange(1000), xrange(1000), xrange(1000)) + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: C = CartesianProduct_iters(xrange(1000), xrange(1000), xrange(1000)) sage: C[238792368] [238, 792, 368] Check for :trac:`15919`:: sage: FF = IntegerModRing(29) - sage: C = CartesianProduct(FF, FF, FF) + sage: C = CartesianProduct_iters(FF, FF, FF) sage: C.unrank(0) [0, 0, 0] """ @@ -271,7 +322,8 @@ def random_element(self): EXAMPLES:: - sage: CartesianProduct('dog', 'cat').random_element() + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: CartesianProduct_iters('dog', 'cat').random_element() ['d', 'a'] """ return [rnd.choice(_) for _ in self.iters] From 40a4f8de0667cc03c9d14aa4772ad1e692928cd7 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Sun, 13 Sep 2015 16:05:33 +0900 Subject: [PATCH 0862/1872] ex attribute of files deleted from ja-branch --- src/doc/ja/tutorial/afterword.rst | 0 src/doc/ja/tutorial/appendix.rst | 0 src/doc/ja/tutorial/bibliography.rst | 0 src/doc/ja/tutorial/conf.py | 0 src/doc/ja/tutorial/index.rst | 0 src/doc/ja/tutorial/interactive_shell.rst | 0 src/doc/ja/tutorial/interfaces.rst | 0 src/doc/ja/tutorial/introduction.rst | 0 src/doc/ja/tutorial/japanesesupport.py | 0 src/doc/ja/tutorial/latex.rst | 0 src/doc/ja/tutorial/programming.rst | 0 src/doc/ja/tutorial/tour.rst | 0 src/doc/ja/tutorial/tour_advanced.rst | 0 src/doc/ja/tutorial/tour_algebra.rst | 0 src/doc/ja/tutorial/tour_assignment.rst | 0 src/doc/ja/tutorial/tour_coercion.rst | 0 src/doc/ja/tutorial/tour_functions.rst | 0 src/doc/ja/tutorial/tour_groups.rst | 0 src/doc/ja/tutorial/tour_help.rst | 0 src/doc/ja/tutorial/tour_linalg.rst | 0 src/doc/ja/tutorial/tour_numtheory.rst | 0 src/doc/ja/tutorial/tour_plotting.rst | 0 src/doc/ja/tutorial/tour_polynomial.rst | 0 src/doc/ja/tutorial/tour_rings.rst | 0 24 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/doc/ja/tutorial/afterword.rst mode change 100755 => 100644 src/doc/ja/tutorial/appendix.rst mode change 100755 => 100644 src/doc/ja/tutorial/bibliography.rst mode change 100755 => 100644 src/doc/ja/tutorial/conf.py mode change 100755 => 100644 src/doc/ja/tutorial/index.rst mode change 100755 => 100644 src/doc/ja/tutorial/interactive_shell.rst mode change 100755 => 100644 src/doc/ja/tutorial/interfaces.rst mode change 100755 => 100644 src/doc/ja/tutorial/introduction.rst mode change 100755 => 100644 src/doc/ja/tutorial/japanesesupport.py mode change 100755 => 100644 src/doc/ja/tutorial/latex.rst mode change 100755 => 100644 src/doc/ja/tutorial/programming.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_advanced.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_algebra.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_assignment.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_coercion.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_functions.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_groups.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_help.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_linalg.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_numtheory.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_plotting.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_polynomial.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_rings.rst diff --git a/src/doc/ja/tutorial/afterword.rst b/src/doc/ja/tutorial/afterword.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/appendix.rst b/src/doc/ja/tutorial/appendix.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/bibliography.rst b/src/doc/ja/tutorial/bibliography.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/conf.py b/src/doc/ja/tutorial/conf.py old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/index.rst b/src/doc/ja/tutorial/index.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/interactive_shell.rst b/src/doc/ja/tutorial/interactive_shell.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/introduction.rst b/src/doc/ja/tutorial/introduction.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/japanesesupport.py b/src/doc/ja/tutorial/japanesesupport.py old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/latex.rst b/src/doc/ja/tutorial/latex.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour.rst b/src/doc/ja/tutorial/tour.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_advanced.rst b/src/doc/ja/tutorial/tour_advanced.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_algebra.rst b/src/doc/ja/tutorial/tour_algebra.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_assignment.rst b/src/doc/ja/tutorial/tour_assignment.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_coercion.rst b/src/doc/ja/tutorial/tour_coercion.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_functions.rst b/src/doc/ja/tutorial/tour_functions.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_groups.rst b/src/doc/ja/tutorial/tour_groups.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_help.rst b/src/doc/ja/tutorial/tour_help.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_linalg.rst b/src/doc/ja/tutorial/tour_linalg.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_numtheory.rst b/src/doc/ja/tutorial/tour_numtheory.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_plotting.rst b/src/doc/ja/tutorial/tour_plotting.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_polynomial.rst b/src/doc/ja/tutorial/tour_polynomial.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_rings.rst b/src/doc/ja/tutorial/tour_rings.rst old mode 100755 new mode 100644 From 6b7367c6ea93e1a7f921e036d6208a4a51d4ae6b Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Sun, 13 Sep 2015 16:07:05 +0900 Subject: [PATCH 0863/1872] delete x-attribute of files from tutorial-branch --- src/doc/ja/tutorial/afterword.rst | 0 src/doc/ja/tutorial/appendix.rst | 0 src/doc/ja/tutorial/bibliography.rst | 0 src/doc/ja/tutorial/conf.py | 0 src/doc/ja/tutorial/index.rst | 0 src/doc/ja/tutorial/interactive_shell.rst | 0 src/doc/ja/tutorial/interfaces.rst | 0 src/doc/ja/tutorial/introduction.rst | 0 src/doc/ja/tutorial/japanesesupport.py | 0 src/doc/ja/tutorial/latex.rst | 0 src/doc/ja/tutorial/programming.rst | 0 src/doc/ja/tutorial/tour.rst | 0 src/doc/ja/tutorial/tour_advanced.rst | 0 src/doc/ja/tutorial/tour_algebra.rst | 0 src/doc/ja/tutorial/tour_assignment.rst | 0 src/doc/ja/tutorial/tour_coercion.rst | 0 src/doc/ja/tutorial/tour_functions.rst | 0 src/doc/ja/tutorial/tour_groups.rst | 0 src/doc/ja/tutorial/tour_help.rst | 0 src/doc/ja/tutorial/tour_linalg.rst | 0 src/doc/ja/tutorial/tour_numtheory.rst | 0 src/doc/ja/tutorial/tour_plotting.rst | 0 src/doc/ja/tutorial/tour_polynomial.rst | 0 src/doc/ja/tutorial/tour_rings.rst | 0 24 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/doc/ja/tutorial/afterword.rst mode change 100755 => 100644 src/doc/ja/tutorial/appendix.rst mode change 100755 => 100644 src/doc/ja/tutorial/bibliography.rst mode change 100755 => 100644 src/doc/ja/tutorial/conf.py mode change 100755 => 100644 src/doc/ja/tutorial/index.rst mode change 100755 => 100644 src/doc/ja/tutorial/interactive_shell.rst mode change 100755 => 100644 src/doc/ja/tutorial/interfaces.rst mode change 100755 => 100644 src/doc/ja/tutorial/introduction.rst mode change 100755 => 100644 src/doc/ja/tutorial/japanesesupport.py mode change 100755 => 100644 src/doc/ja/tutorial/latex.rst mode change 100755 => 100644 src/doc/ja/tutorial/programming.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_advanced.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_algebra.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_assignment.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_coercion.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_functions.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_groups.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_help.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_linalg.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_numtheory.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_plotting.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_polynomial.rst mode change 100755 => 100644 src/doc/ja/tutorial/tour_rings.rst diff --git a/src/doc/ja/tutorial/afterword.rst b/src/doc/ja/tutorial/afterword.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/appendix.rst b/src/doc/ja/tutorial/appendix.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/bibliography.rst b/src/doc/ja/tutorial/bibliography.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/conf.py b/src/doc/ja/tutorial/conf.py old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/index.rst b/src/doc/ja/tutorial/index.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/interactive_shell.rst b/src/doc/ja/tutorial/interactive_shell.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/introduction.rst b/src/doc/ja/tutorial/introduction.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/japanesesupport.py b/src/doc/ja/tutorial/japanesesupport.py old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/latex.rst b/src/doc/ja/tutorial/latex.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour.rst b/src/doc/ja/tutorial/tour.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_advanced.rst b/src/doc/ja/tutorial/tour_advanced.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_algebra.rst b/src/doc/ja/tutorial/tour_algebra.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_assignment.rst b/src/doc/ja/tutorial/tour_assignment.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_coercion.rst b/src/doc/ja/tutorial/tour_coercion.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_functions.rst b/src/doc/ja/tutorial/tour_functions.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_groups.rst b/src/doc/ja/tutorial/tour_groups.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_help.rst b/src/doc/ja/tutorial/tour_help.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_linalg.rst b/src/doc/ja/tutorial/tour_linalg.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_numtheory.rst b/src/doc/ja/tutorial/tour_numtheory.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_plotting.rst b/src/doc/ja/tutorial/tour_plotting.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_polynomial.rst b/src/doc/ja/tutorial/tour_polynomial.rst old mode 100755 new mode 100644 diff --git a/src/doc/ja/tutorial/tour_rings.rst b/src/doc/ja/tutorial/tour_rings.rst old mode 100755 new mode 100644 From 3d701665eee6fd509a8edbef239544aa0d079484 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Sun, 13 Sep 2015 16:09:01 +0900 Subject: [PATCH 0864/1872] deletes x-attribute of *.{py,rst} from a_tour branch --- src/doc/ja/a_tour_of_sage/conf.py | 0 src/doc/ja/a_tour_of_sage/index.rst | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/doc/ja/a_tour_of_sage/conf.py mode change 100755 => 100644 src/doc/ja/a_tour_of_sage/index.rst diff --git a/src/doc/ja/a_tour_of_sage/conf.py b/src/doc/ja/a_tour_of_sage/conf.py old mode 100755 new mode 100644 diff --git a/src/doc/ja/a_tour_of_sage/index.rst b/src/doc/ja/a_tour_of_sage/index.rst old mode 100755 new mode 100644 From 61aa576861e6a227bdfdfe4dfa15bb78b6d28729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 13 Sep 2015 17:55:14 +0200 Subject: [PATCH 0865/1872] trac #18937 version 2.4.5 --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index cea65720c5d..a22531aa99c 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=b9fd210e0fc8da23b9968777f6014d23970d1dc1 -md5=2ff4eb8cf4dac6ed24bb4c0962e782bc -cksum=672259990 +sha1=7c0c2bd9966c15733b97ee5a5e0870c22e44661c +md5=4923739c0bf31fcfbe13ad6c9b421290 +cksum=2215322151 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 79a614418f7..59aa62c1fa4 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.4 +2.4.5 From 650ccb608a2dd526191826613fc7cbfaa6d82892 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Mon, 14 Sep 2015 11:49:21 +0900 Subject: [PATCH 0866/1872] Some line-formatting. --- src/doc/ja/tutorial/appendix.rst | 1 + src/doc/ja/tutorial/tour_assignment.rst | 1 + src/doc/ja/tutorial/tour_functions.rst | 1 + 3 files changed, 3 insertions(+) diff --git a/src/doc/ja/tutorial/appendix.rst b/src/doc/ja/tutorial/appendix.rst index 598e035f840..b67d0382180 100644 --- a/src/doc/ja/tutorial/appendix.rst +++ b/src/doc/ja/tutorial/appendix.rst @@ -1,4 +1,5 @@ .. Appendix + ******** 付録 ******** diff --git a/src/doc/ja/tutorial/tour_assignment.rst b/src/doc/ja/tutorial/tour_assignment.rst index a480cd12df2..2ec2cbb0927 100644 --- a/src/doc/ja/tutorial/tour_assignment.rst +++ b/src/doc/ja/tutorial/tour_assignment.rst @@ -43,6 +43,7 @@ Sageでは代入に記号 ``=`` ,比較演算には ``==`` , ``<=`` , ``>= Sageでは,一般によく使われる数学関数も豊富に用意されている. ここでは,ほんの一部しか例を示すことができないが: + :: sage: sqrt(3.4) 1.84390889145858 diff --git a/src/doc/ja/tutorial/tour_functions.rst b/src/doc/ja/tutorial/tour_functions.rst index b34f7f23595..85278972b5c 100644 --- a/src/doc/ja/tutorial/tour_functions.rst +++ b/src/doc/ja/tutorial/tour_functions.rst @@ -28,6 +28,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り 以下のようにすると切り抜けられるが,どんな場合でも通用するとは限らないので要注意だ(下の第4項を参照). .. link + :: sage: var('z') # zを変数として定義 From c2eeac83b37d9de3a547001fd704a1fb089c626c Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 12:05:53 -0300 Subject: [PATCH 0867/1872] Trac 18411: removed unused import --- src/sage/symbolic/random_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index ab1dbc7c093..6b6e5944dbe 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -341,7 +341,6 @@ def assert_strict_weak_order(a,b,c, cmp_func): [ 1 0 -1] [ 1 1 0] """ - from itertools import product from sage.matrix.constructor import matrix from sage.combinat.permutation import Permutations x = (a,b,c) From 07c9c4258f68999ecf4e2659890a3385c8f8aa0e Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 14 Sep 2015 08:16:40 -0700 Subject: [PATCH 0868/1872] trac 19179: delete extra line --- src/sage/homology/chain_complex_morphism.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index 8756b31b448..03a62ec89a7 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -188,7 +188,6 @@ def __init__(self, matrices, C, D, check=True): # Use immutable matrices because they're hashable. m.set_immutable() self._matrix_dictionary[i] = m - self._matrix_dictionary = matrices self._domain = C self._codomain = D From d269e6fbc05b555845d0a32ea0359ee3c8bb19de Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 13:30:35 -0300 Subject: [PATCH 0869/1872] Trac 18411: use Sets.__call__ to make parents --- src/sage/categories/cartesian_product.py | 26 +++++-------- src/sage/categories/sets_cat.py | 49 ++++++++++++------------ src/sage/combinat/free_module.py | 9 +++-- 3 files changed, 38 insertions(+), 46 deletions(-) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index f9e96ed94f1..fd77d3787a4 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -14,6 +14,8 @@ from sage.categories.covariant_functorial_construction import CovariantFunctorialConstruction, CovariantConstructionCategory +native_python_containers = set([tuple, list, set, frozenset]) + class CartesianProductFunctor(CovariantFunctorialConstruction): """ A singleton class for the Cartesian product functor. @@ -110,8 +112,9 @@ def __call__(self, args): Functorial construction application. Specializes the generic ``__call__`` from - :class:`CartesianProductFunctor` to handle the case of some Python - objects. + :class:`CovariantFunctorialConstruction` to handle the case of some + Python objects. Namely ``frozenset``, ``list``, ``set`` and ``tuple``. + See the examples below. EXAMPLES:: @@ -125,21 +128,10 @@ def __call__(self, args): sage: _.category() Category of Cartesian products of sets """ - if any(type(arg) is tuple or \ - type(arg) is list or \ - type(arg) is set or \ - type(arg) is frozenset for arg in args): - aargs = [] - from sage.sets.set import Set - from sage.sets.finite_enumerated_set import FiniteEnumeratedSet - for arg in args: - if type(arg) is tuple or type(arg) is list: - aargs.append(FiniteEnumeratedSet(arg)) - elif type(arg) is set or type(arg) is frozenset: - aargs.append(Set(arg)) - else: - aargs.append(arg) - args = aargs + if any(type(arg) in native_python_containers for arg in args): + from sage.categories.sets_cat import Sets + S = Sets() + args = [S(a, enumerated_set=True) for a in args] return super(CartesianProductFunctor, self).__call__(args) cartesian_product = CartesianProductFunctor() diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index b881cd83949..c02cc5557da 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -205,9 +205,17 @@ def super_categories(self): """ return [SetsWithPartialMaps()] - def _call_(self, X, enumerated_set_if_possible = False): + def _call_(self, X, enumerated_set=False): r""" - Construct an object in this category from the data in ``X``. + Construct an object in this category from the data ``X``. + + INPUT: + + - ``X`` -- an object to be converted into a set + + - ``enumerated_set`` -- if set to ``True`` and the input is either a + Python tuple or a Python list then the output will be a finite + enumerated set. EXAMPLES:: @@ -216,33 +224,24 @@ def _call_(self, X, enumerated_set_if_possible = False): sage: Sets()([1, 2, 3]) {1, 2, 3} - .. note:: + sage: S = Sets()([1, 2, 3]); S.category() + Category of finite sets + sage: S = Sets()([1, 2, 3], enumerated_set=True); S.category() + Category of facade finite enumerated sets - Using ``Sets()(A)`` used to implement some sort of - forgetful functor into the ``Sets()`` category. This - feature has been removed, because it was not consistent - with the semantic of :meth:`Category.__call__`. Proper - forgetful functors will eventually be implemented, with - another syntax. + .. NOTE:: - - ``enumerated_set_if_possible`` -- an option to ask Sage to - try to build an ``EnumeratedSets()`` rather that a - ``Sets()`` if possible. This is experimental an may change - in the future:: - - sage: S = Sets()([1, 2, 3]); S.category() - Category of finite sets - sage: S = Sets()([1, 2, 3], True); S.category() - Category of facade finite enumerated sets + Using ``Sets()(A)`` used to implement some sort of forgetful functor + into the ``Sets()`` category. This feature has been removed, because + it was not consistent with the semantic of :meth:`Category.__call__`. + Proper forgetful functors will eventually be implemented, with + another syntax. """ - import sage.sets.all - if enumerated_set_if_possible: + if enumerated_set and type(X) in (tuple,list): from sage.categories.enumerated_sets import EnumeratedSets - try: - return EnumeratedSets()(X) - except NotImplementedError: - pass - return sage.sets.all.Set(X) + return EnumeratedSets()(X) + from sage.sets.set import Set + return Set(X) def example(self, choice = None): """ diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 7773a5d187f..76eebd3e78c 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1288,10 +1288,11 @@ def __init__(self, R, basis_keys, element_class = None, category = None, prefix= if element_class is not None: self.Element = element_class - # The following is needed by e.g. root systems that don't call - # the classcall and passes lists as basis_keys - if isinstance(basis_keys, (list, tuple)): - basis_keys = FiniteEnumeratedSet(basis_keys) + # The following is to ensure that basis keys is indeed a parent. + # tuple/list are converted to FiniteEnumeratedSet and set/frozenset to + # Set + # (e.g. root systems passes lists) + basis_keys = Sets()(basis_keys, enumerated_set=True) # ignore the optional 'key' since it only affects CachedRepresentation kwds.pop('key', None) From e7a2ff2e36fe378e05f4cb14adb4999c579b11ec Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 13:31:02 -0300 Subject: [PATCH 0870/1872] Trac 18411: bounded_number_of_tuples -> some_tuples --- src/sage/categories/additive_semigroups.py | 4 +-- ...distributive_magmas_and_additive_magmas.py | 4 +-- src/sage/categories/domains.py | 4 +-- src/sage/categories/euclidean_domains.py | 8 +++--- src/sage/categories/semigroups.py | 4 +-- src/sage/categories/sets_cat.py | 8 +++--- src/sage/misc/misc.py | 25 +++++++++++-------- src/sage/rings/padics/padic_generic.py | 10 ++++---- 8 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/sage/categories/additive_semigroups.py b/src/sage/categories/additive_semigroups.py index df6ea42fce9..bb45bd19e8b 100644 --- a/src/sage/categories/additive_semigroups.py +++ b/src/sage/categories/additive_semigroups.py @@ -80,8 +80,8 @@ def _test_additive_associativity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from sage.misc.misc import bounded_number_of_tuples - for x,y,z in bounded_number_of_tuples(S, 3, tester._max_runs): + from sage.misc.misc import some_tuples + for x,y,z in some_tuples(S, 3, tester._max_runs): tester.assert_((x + y) + z == x + (y + z)) class Homsets(HomsetsCategory): diff --git a/src/sage/categories/distributive_magmas_and_additive_magmas.py b/src/sage/categories/distributive_magmas_and_additive_magmas.py index 463b2e92dd7..c0c3a53bb80 100644 --- a/src/sage/categories/distributive_magmas_and_additive_magmas.py +++ b/src/sage/categories/distributive_magmas_and_additive_magmas.py @@ -73,8 +73,8 @@ def _test_distributivity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from sage.misc.misc import bounded_number_of_tuples - for x,y,z in bounded_number_of_tuples(tester.some_elements(), 3, tester._max_runs): + from sage.misc.misc import some_tuples + for x,y,z in some_tuples(tester.some_elements(), 3, tester._max_runs): # left distributivity tester.assert_(x * (y + z) == (x * y) + (x * z)) # right distributivity diff --git a/src/sage/categories/domains.py b/src/sage/categories/domains.py index be23ff4205a..2cdbb4cd2ce 100644 --- a/src/sage/categories/domains.py +++ b/src/sage/categories/domains.py @@ -84,8 +84,8 @@ def _test_zero_divisors(self, **options): # Filter out zero S = [s for s in tester.some_elements() if not s.is_zero()] - from sage.misc.misc import bounded_number_of_tuples - for a,b in bounded_number_of_tuples(S, 2, tester._max_runs): + from sage.misc.misc import some_tuples + for a,b in some_tuples(S, 2, tester._max_runs): p = a * b tester.assertFalse(p.is_zero()) diff --git a/src/sage/categories/euclidean_domains.py b/src/sage/categories/euclidean_domains.py index 9c701893fc9..b9d29a79a29 100644 --- a/src/sage/categories/euclidean_domains.py +++ b/src/sage/categories/euclidean_domains.py @@ -87,8 +87,8 @@ def _test_euclidean_degree(self, **options): tester.assertGreaterEqual(a.euclidean_degree(), min_degree) tester.assertEqual(a.euclidean_degree() == min_degree, a.is_unit()) - from sage.misc.misc import bounded_number_of_tuples - for a,b in bounded_number_of_tuples(S, 2, tester._max_runs): + from sage.misc.misc import some_tuples + for a,b in some_tuples(S, 2, tester._max_runs): p = a * b # For rings which are not exact, we might get something that # acts like a zero divisor. @@ -114,8 +114,8 @@ def _test_quo_rem(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from sage.misc.misc import bounded_number_of_tuples - for a,b in bounded_number_of_tuples(S, 2, tester._max_runs): + from sage.misc.misc import some_tuples + for a,b in some_tuples(S, 2, tester._max_runs): if b.is_zero(): tester.assertRaises(ZeroDivisionError, lambda: a.quo_rem(b)) else: diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 3a3777ffda9..3f5b85b517c 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -114,8 +114,8 @@ def _test_associativity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from sage.misc.misc import bounded_number_of_tuples - for x,y,z in bounded_number_of_tuples(S, 3, tester._max_runs): + from sage.misc.misc import some_tuples + for x,y,z in some_tuples(S, 3, tester._max_runs): tester.assert_((x * y) * z == x * (y * z)) @abstract_method(optional=True) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index c02cc5557da..a11bf635213 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1187,8 +1187,8 @@ def _test_elements_eq_symmetric(self, **options): tester = self._tester(**options) S = list(tester.some_elements()) + [None, 0] n = tester._max_runs - from sage.misc.misc import bounded_number_of_tuples - for x,y in bounded_number_of_tuples(S, 2, tester._max_runs): + from sage.misc.misc import some_tuples + for x,y in some_tuples(S, 2, tester._max_runs): tester.assertEqual(x==y, y==x, LazyFormat("non symmetric equality: %s but %s")%( print_compare(x, y), print_compare(y, x))) @@ -1275,8 +1275,8 @@ def _test_elements_neq(self, **options): tester = self._tester(**options) S = list(tester.some_elements()) + [None, 0] - from sage.misc.misc import bounded_number_of_tuples - for x,y in bounded_number_of_tuples(S, 2, tester._max_runs): + from sage.misc.misc import some_tuples + for x,y in some_tuples(S, 2, tester._max_runs): tester.assertNotEqual(x == y, x != y, LazyFormat("__eq__ and __ne__ inconsistency:\n" " %s == %s returns %s but %s != %s returns %s")%( diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 02bda8aa568..8deb81cad68 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -1722,30 +1722,33 @@ def random_sublist(X, s): return [a for a in X if random.random() <= s] -def bounded_number_of_tuples(elements, repeat, bound): +def some_tuples(elements, repeat, bound): r""" Return an iterator over at most ``bound`` number of ``repeat``-tuples of ``elements``. TESTS:: - sage: from sage.misc.misc import bounded_number_of_tuples - sage: l = bounded_number_of_tuples([0,1,2,3], 2, 3) + sage: from sage.misc.misc import some_tuples + sage: l = some_tuples([0,1,2,3], 2, 3) sage: l - at ...> + sage: len(list(l)) 3 - sage: l = bounded_number_of_tuples(range(50), 3, 10) + sage: l = some_tuples(range(50), 3, 10) sage: len(list(l)) 10 + + .. TODO:: + + Currently, this only return an iterator over the first element of the + cartesian product. It would be smarter to return something more + "random like" as it is used in tests. However, this should remain + deterministic. """ - if len(elements) ** repeat < bound: - from itertools import product - return product(elements, repeat=repeat) - else: - from sage.misc.prandom import sample, choice - return (tuple(choice(elements) for _ in range(repeat)) for _ in range(bound)) + from itertools import islice, product + return islice(product(elements, repeat=repeat), bound) def powerset(X): r""" diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index bdf70b5eb23..b3ad322f18a 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -26,7 +26,7 @@ from sage.misc.prandom import sample -from sage.misc.misc import bounded_number_of_tuples +from sage.misc.misc import some_tuples from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.fields import Fields @@ -523,7 +523,7 @@ def _test_add(self, **options): tester.assertEqual(y.precision_absolute(),x.precision_absolute()) tester.assertEqual(y.precision_relative(),x.precision_relative()) - for x,y in bounded_number_of_tuples(elements, 2, tester._max_runs): + for x,y in some_tuples(elements, 2, tester._max_runs): z = x + y tester.assertIs(z.parent(), self) tester.assertEqual(z.precision_absolute(), min(x.precision_absolute(), y.precision_absolute())) @@ -559,7 +559,7 @@ def _test_sub(self, **options): tester.assertEqual(y.precision_absolute(), x.precision_absolute()) tester.assertEqual(y.precision_relative(), x.precision_relative()) - for x,y in bounded_number_of_tuples(elements, 2, tester._max_runs): + for x,y in some_tuples(elements, 2, tester._max_runs): z = x - y tester.assertIs(z.parent(), self) tester.assertEqual(z.precision_absolute(), min(x.precision_absolute(), y.precision_absolute())) @@ -624,7 +624,7 @@ def _test_mul(self, **options): tester = self._tester(**options) elements = list(tester.some_elements()) - for x,y in bounded_number_of_tuples(elements, 2, tester._max_runs): + for x,y in some_tuples(elements, 2, tester._max_runs): z = x * y tester.assertIs(z.parent(), self) tester.assertLessEqual(z.precision_relative(), min(x.precision_relative(), y.precision_relative())) @@ -651,7 +651,7 @@ def _test_div(self, **options): tester = self._tester(**options) elements = list(tester.some_elements()) - for x,y in bounded_number_of_tuples(elements, 2, tester._max_runs): + for x,y in some_tuples(elements, 2, tester._max_runs): try: z = x / y except (ZeroDivisionError, PrecisionError, ValueError): From 1812a5e458ec074907d0b43405415697c3ea1faa Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 14 Sep 2015 20:49:22 +0200 Subject: [PATCH 0871/1872] rename doc-index-file --- .../rings/asymptotic_expansions_index.rst | 41 +++++++++++++- .../reference/rings/asymptotic_ring_index.rst | 54 ------------------- 2 files changed, 40 insertions(+), 55 deletions(-) delete mode 100644 src/doc/en/reference/rings/asymptotic_ring_index.rst diff --git a/src/doc/en/reference/rings/asymptotic_expansions_index.rst b/src/doc/en/reference/rings/asymptotic_expansions_index.rst index aad5f4bf10d..17f65ac58f9 100644 --- a/src/doc/en/reference/rings/asymptotic_expansions_index.rst +++ b/src/doc/en/reference/rings/asymptotic_expansions_index.rst @@ -1,11 +1,50 @@ Asymptotic Expansions ===================== + +The Asymptotic Ring +------------------- + +The asymptotic ring, as well as its main documentation is contained in +the module + +- :doc:`sage/rings/asymptotic/asymptotic_ring`. + + +Supplements +----------- + +Behind the scenes of working with asymptotic expressions a couple of +additional classes and tools turn up. For instance the growth in each +summand is managed in growth groups, see below. + + +Growth Groups +^^^^^^^^^^^^^ + +The growth of a summand of an asymptotic expression is managed in + +- :doc:`sage/rings/asymptotic/growth_group` and + +- :doc:`sage/rings/asymptotic/growth_group_cartesian`. + + +Term Monoids +^^^^^^^^^^^^ + +A summand of an asymptotic expression is basically a term out of the following monoid: + +- :doc:`sage/rings/asymptotic/term_monoid`. + + +Asymptotic Expansions --- Table of Contents +------------------------------------------- + .. toctree:: + sage/rings/asymptotic/asymptotic_ring sage/rings/asymptotic/growth_group sage/rings/asymptotic/growth_group_cartesian sage/rings/asymptotic/term_monoid - sage/rings/asymptotic/asymptotic_ring .. include:: ../footer.txt diff --git a/src/doc/en/reference/rings/asymptotic_ring_index.rst b/src/doc/en/reference/rings/asymptotic_ring_index.rst deleted file mode 100644 index a89a694f3ec..00000000000 --- a/src/doc/en/reference/rings/asymptotic_ring_index.rst +++ /dev/null @@ -1,54 +0,0 @@ -Asymptotic Ring -=============== - -The Asymptotic Ring -------------------- - -The asymptotic ring, as well as its main documentation is contained in -the module - -- :doc:`sage/rings/asymptotic/asymptotic_ring`. - -Supplements ------------ - -Behind the scenes of working with asymptotic expressions a couple of -additional classes and tools turn up. For instance the growth in each -summand is managed in growth groups, see below. - - -Growth Groups -^^^^^^^^^^^^^ - -The growth of a summand of an asymptotic expression is managed in - -- :doc:`sage/rings/asymptotic/growth_group` and - -- :doc:`sage/rings/asymptotic/growth_group_cartesian`. - -Term Monoids -^^^^^^^^^^^^ - -A summand of an asymptotic expression is basically a term out of the following monoid: - -- :doc:`sage/rings/asymptotic/term_monoid`. - -Miscellaneous -^^^^^^^^^^^^^ - -Various useful functions and tools are collected in - -- :doc:`sage/rings/asymptotic/misc`. - -Asymptotic Ring --- Table of Contents -------------------------------------- - -.. toctree:: - - sage/rings/asymptotic/asymptotic_ring - sage/rings/asymptotic/growth_group - sage/rings/asymptotic/growth_group_cartesian - sage/rings/asymptotic/term_monoid - sage/rings/asymptotic/misc - -.. include:: ../footer.txt From 0720b14855eebe533acae7e82df47c1e0023ff52 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 14 Sep 2015 21:12:28 +0200 Subject: [PATCH 0872/1872] fix doctests: update since TestSuite now checks for cardinality --- src/sage/rings/asymptotic/growth_group.py | 3 +++ src/sage/rings/asymptotic/term_monoid.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 84c7c9b4135..0858855c30a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3346,6 +3346,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): sage: TestSuite(GrowthGroup('x^ZZ')).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass + running ._test_cardinality() . . . pass running ._test_category() . . . pass running ._test_elements() . . . Running the test suite of self.an_element() @@ -3370,6 +3371,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): sage: TestSuite(GrowthGroup('QQ^y')).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass + running ._test_cardinality() . . . pass running ._test_category() . . . pass running ._test_elements() . . . Running the test suite of self.an_element() @@ -3394,6 +3396,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): sage: TestSuite(GrowthGroup('x^QQ * log(x)^ZZ')).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass + running ._test_cardinality() . . . pass running ._test_category() . . . pass running ._test_elements() . . . Running the test suite of self.an_element() diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index db7e3195dab..c0c667c7e27 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3149,6 +3149,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: TestSuite(TermMonoid('exact', GrowthGroup('x^ZZ'), QQ)).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass + running ._test_cardinality() . . . pass running ._test_category() . . . pass running ._test_elements() . . . Running the test suite of self.an_element() @@ -3173,6 +3174,7 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: TestSuite(TermMonoid('O', GrowthGroup('x^QQ'), ZZ)).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass + running ._test_cardinality() . . . pass running ._test_category() . . . pass running ._test_elements() . . . Running the test suite of self.an_element() From 9aba4b6a3fae816bc02ec69161fb994a29755ee0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 14 Sep 2015 21:20:13 +0200 Subject: [PATCH 0873/1872] make entry in reference/index --- src/doc/en/reference/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/index.rst b/src/doc/en/reference/index.rst index 5972217c39d..85c52019900 100644 --- a/src/doc/en/reference/index.rst +++ b/src/doc/en/reference/index.rst @@ -78,6 +78,7 @@ Calculus * :doc:`Symbolic Calculus ` * :doc:`Mathematical Constants ` * :doc:`Elementary and Special Functions ` +* :doc:`Asymptotic Expansions ` (experimental) Geometry and Topology --------------------- From 70abf65739587016ed71a953585ff56af33e325b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 14 Sep 2015 21:20:23 +0200 Subject: [PATCH 0874/1872] include misc --- .../en/reference/rings/asymptotic_expansions_index.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/doc/en/reference/rings/asymptotic_expansions_index.rst b/src/doc/en/reference/rings/asymptotic_expansions_index.rst index 17f65ac58f9..ad1107a5f44 100644 --- a/src/doc/en/reference/rings/asymptotic_expansions_index.rst +++ b/src/doc/en/reference/rings/asymptotic_expansions_index.rst @@ -37,6 +37,14 @@ A summand of an asymptotic expression is basically a term out of the following m - :doc:`sage/rings/asymptotic/term_monoid`. +Miscellaneous +^^^^^^^^^^^^^ + +Various useful functions and tools are collected in + +- :doc:`sage/rings/asymptotic/misc`. + + Asymptotic Expansions --- Table of Contents ------------------------------------------- @@ -46,5 +54,6 @@ Asymptotic Expansions --- Table of Contents sage/rings/asymptotic/growth_group sage/rings/asymptotic/growth_group_cartesian sage/rings/asymptotic/term_monoid + sage/rings/asymptotic/misc .. include:: ../footer.txt From 3661ec0ae95037ee2fc46f5751f7c5063f9f0c9d Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 21:38:16 -0300 Subject: [PATCH 0875/1872] Trac 18411: more explicit error catch in sets_cat --- src/sage/categories/sets_cat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index a11bf635213..52d6711aa9e 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -2126,7 +2126,7 @@ def is_finite(self): # Note: some parent might not implement "is_empty". So we # carefully isolate this test. test = any(c.is_empty() for c in f) - except Exception: + except (AttributeError, NotImplementedError): pass else: if test: return test @@ -2163,7 +2163,7 @@ def cardinality(self): # Note: some parent might not implement "is_empty". So we # carefully isolate this test. is_empty = any(c.is_empty() for c in f) - except Exception: + except (AttributeError,NotImplementedError): pass else: if is_empty: From 7d127096e22a75454920002b7557ef52d620ba9a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 21:39:00 -0300 Subject: [PATCH 0876/1872] Trac 18411: composition: FiniteEnumeratedSet instead of Set --- src/sage/combinat/composition.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 7dcf7b93d73..4b7ada989d5 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -34,6 +34,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.sets.set import Set +from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.rings.all import ZZ from combinat import CombinatorialElement from sage.categories.cartesian_product import cartesian_product @@ -756,7 +757,7 @@ def finer(self): {[]} """ if not self: - return Set([self]) + return FiniteEnumeratedSet([self]) else: return cartesian_product([Compositions(i) for i in self]).map(Composition.sum) From 35b76c63ab45d06c15b7efcde33da4448f259b00 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 21:39:42 -0300 Subject: [PATCH 0877/1872] Trac 18411: simpler code in root_lattice_realizations.py --- .../combinat/root_system/root_lattice_realizations.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index b8ac3e17795..c8a055c07a9 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -796,7 +796,6 @@ def positive_real_roots(self): from sage.categories.cartesian_product import cartesian_product from sage.combinat.root_system.root_system import RootSystem - from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.sets.positive_integers import PositiveIntegers from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets @@ -814,19 +813,19 @@ def lift(x): # Add all of the delta shifts delta = self.null_root() if self.cartan_type().is_untwisted_affine(): - C = cartesian_product([PositiveIntegers(), FiniteEnumeratedSet(Q.roots())]) + C = cartesian_product([PositiveIntegers(), Q.roots()]) F = Family(C, lambda x: lift(x[1]) + x[0]*delta) D = DisjointUnionEnumeratedSets([P, F]) elif self.cartan_type().type() == 'BC' or self.cartan_type().dual().type() == 'BC': - Cs = cartesian_product([PositiveIntegers(), FiniteEnumeratedSet(Q.short_roots())]) - Cl = cartesian_product([PositiveIntegers(), FiniteEnumeratedSet(Q.long_roots())]) + Cs = cartesian_product([PositiveIntegers(), Q.short_roots()]) + Cl = cartesian_product([PositiveIntegers(), Q.long_roots()]) Fs = Family(Cl, lambda x: (lift(x[1]) + (2*x[0]-1)*delta) / 2) Fm = Family(Cs, lambda x: lift(x[1]) + x[0]*delta) Fl = Family(Cl, lambda x: lift(x[1]) + 2*x[0]*delta) D = DisjointUnionEnumeratedSets([P, Fs, Fm, Fl]) else: # Other twisted types - Cs = cartesian_product([PositiveIntegers(), FiniteEnumeratedSet(Q.short_roots())]) - Cl = cartesian_product([PositiveIntegers(), FiniteEnumeratedSet(Q.long_roots())]) + Cs = cartesian_product([PositiveIntegers(), Q.short_roots()]) + Cl = cartesian_product([PositiveIntegers(), Q.long_roots()]) Fs = Family(Cs, lambda x: lift(x[1]) + x[0]*delta) if self.cartan_type().dual() == 'G': # D_4^3 k = 3 From 643e2f7843dafb911f4ef79254d43dab2c5f6d58 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 21:40:07 -0300 Subject: [PATCH 0878/1872] Trac 18411: restore some tests in family.py --- src/sage/sets/family.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index b7bde0ee90c..b76b81f2ddd 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -1009,7 +1009,10 @@ def cardinality(self): Check that :trac:`15195` is fixed:: - sage: F = Family(PositiveIntegers(), lambda x: x) + sage: C = cartesian_product([PositiveIntegers(), [1,2,3]]) + sage: C.cardinality() + +Infinity + sage: F = Family(C, lambda x: x) sage: F.cardinality() +Infinity """ From 6f7b37948715d7d18eb7a49f726f44772e6e204f Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 21:40:27 -0300 Subject: [PATCH 0879/1872] Trac 18411: use itertools.product instead of product --- src/sage/geometry/integral_points.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx index f6e8d64000c..3881ba5fce7 100644 --- a/src/sage/geometry/integral_points.pyx +++ b/src/sage/geometry/integral_points.pyx @@ -10,8 +10,8 @@ Cython helper methods to compute integral points in polyhedra. # http://www.gnu.org/licenses/ #***************************************************************************** -from itertools import product import copy +import itertools from sage.matrix.constructor import matrix, column_matrix, vector, diagonal_matrix from sage.rings.all import QQ, RR, ZZ, gcd, lcm @@ -210,7 +210,7 @@ cpdef loop_over_parallelotope_points(e, d, VDinv, R, lattice, A=None, b=None): s = ZZ.zero() # summation variable gen = lattice(0) q_times_d = vector(ZZ, dim) - for base in product(*[ range(0,i) for i in e ]): + for base in itertools.product(*[ range(0,i) for i in e ]): for i in range(0, dim): s = ZZ.zero() for j in range(0, dim): From 2741384297a389204b4e299b702482ae5b7ff8bc Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 21:41:10 -0300 Subject: [PATCH 0880/1872] Trac 18411: small edits in combinat/tutorial.py --- src/sage/combinat/tutorial.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index 7671f270aaf..907dcc0fbb8 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -633,7 +633,7 @@ {2, 4} but this should be used with care because some sets have a -natural indexing other than by `(0,\dots)`. +natural indexing other than by `(0, 1, \dots)`. Conversely, one can calculate the position of an object in this order:: @@ -654,7 +654,7 @@ which is roughly `2\cdot 10^{19728}`:: - sage: n.ndigits() # long time + sage: n.ndigits() 19729 or ask for its `237102124`-th element:: @@ -1552,7 +1552,7 @@ the consecutive differences between the parts. Here are some more examples:: - sage: IntegerListsLex(10, length=3, + sage: IntegerListsLex(10, length = 3, ....: min_part = 2, max_part = 5, ....: floor = [2, 4, 2]).list() [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] @@ -1565,10 +1565,10 @@ sage: IntegerListsLex(5, min_part = 1, max_slope = -1).list() [[5], [4, 1], [3, 2]] - sage: list(Compositions(5, max_length=2)) + sage: list(Compositions(5, max_length = 2)) [[5], [4, 1], [3, 2], [2, 3], [1, 4]] - sage: list(IntegerListsLex(5, max_length=2, min_part=1)) + sage: list(IntegerListsLex(5, max_length = 2, min_part = 1)) [[5], [4, 1], [3, 2], [2, 3], [1, 4]] The point of the model of ``IntegerListsLex`` is in the compromise From ca0a9077452a1d127019c5aa1d9a0b9810e3df1b Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 14 Sep 2015 21:47:07 -0300 Subject: [PATCH 0881/1872] Trac 18411: explanations about the transition --- src/sage/combinat/cartesian_product.py | 50 ++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/cartesian_product.py b/src/sage/combinat/cartesian_product.py index 20fd7eb4a14..8a4184de70d 100644 --- a/src/sage/combinat/cartesian_product.py +++ b/src/sage/combinat/cartesian_product.py @@ -25,8 +25,7 @@ def CartesianProduct(*iters): """ - Returns the combinatorial class of the Cartesian product of - \*iters. + This is deprecated. Use ``cartesian_product`` instead. EXAMPLES:: @@ -103,6 +102,53 @@ def CartesianProduct(*iters): return cartesian_product(iters) class CartesianProduct_iters(CombinatorialClass): + r""" + Cartesian product of finite sets. + + This class will be soonly deprecated (see :trac:`18411` and :trac:`19195`). + One should instead use the functorial construction + :class:`cartesian_product `. + The main differences in behavior are: + + - at creation: as many argument as there are factors with + ``CartesianProduct`` whereas only a list of factors for + ``cartesian_product``; + + - representation of elements: a Python list for ``CartesianProduct`` versus + a dedicated element class for ``cartesian_product``; + + - membership test: because the objects are different the membership tests + differ. + + All of these is illustrated in the examples below. + + EXAMPLES:: + + sage: F1 = ['a', 'b'] + sage: F2 = [1, 2, 3, 4] + sage: F3 = Permutations(3) + sage: from sage.combinat.cartesian_product import CartesianProduct_iters + sage: C = CartesianProduct_iters(F1, F2, F3) + sage: c = cartesian_product([F1, F2, F3]) + + sage: type(C.an_element()) + + sage: type(c.an_element()) + + + sage: l = ['a', 1, Permutation([3,2,1])] + sage: l in C + True + sage: l in c + False + sage: elt = c(l) + sage: elt + ('a', 1, [3, 2, 1]) + sage: elt in c + True + sage: elt.parent() is c + True + """ def __init__(self, *iters): """ TESTS:: From f71f7fac22538903327fa1ed78aa0c36055892f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 15 Sep 2015 15:18:20 +0200 Subject: [PATCH 0882/1872] version 2.4.6 --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index a22531aa99c..8071e26bf7e 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=7c0c2bd9966c15733b97ee5a5e0870c22e44661c -md5=4923739c0bf31fcfbe13ad6c9b421290 -cksum=2215322151 +sha1=5e23aabb8ed9851ef6d04fc3209a1a4f16e4de6c +md5=2717b61c5de5b76312370f1099c90ef8 +cksum=183944074 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 59aa62c1fa4..7bf4b6a8aef 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.5 +2.4.6 From 855f5078cd89e78bedc1edd18bc700f1c837ce07 Mon Sep 17 00:00:00 2001 From: Stefan Kraemer Date: Tue, 15 Sep 2015 16:33:07 +0200 Subject: [PATCH 0883/1872] Bugfix for hyperbolic_arc and hyperbolic_polygon --- src/sage/plot/hyperbolic_arc.py | 3 ++- src/sage/plot/hyperbolic_polygon.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/plot/hyperbolic_arc.py b/src/sage/plot/hyperbolic_arc.py index 1e658fc84d5..11ab9e85277 100644 --- a/src/sage/plot/hyperbolic_arc.py +++ b/src/sage/plot/hyperbolic_arc.py @@ -7,6 +7,7 @@ """ #***************************************************************************** # Copyright (C) 2011 Hartmut Monien , +# 2015 Stefan Kraemer # # Distributed under the terms of the GNU General Public License (GPL) # @@ -70,7 +71,7 @@ def _hyperbolic_arc(self, z0, z3, first=False): the hyperbolic arc between the complex numbers z0 and z3 in the hyperbolic plane. """ - if (z0-z3).real() == 0: + if abs((z0-z3).real()) < 10.**(-3): self.path.append([(z0.real(),z0.imag()), (z3.real(),z3.imag())]) return z0, z3 = (CC(z0), CC(z3)) diff --git a/src/sage/plot/hyperbolic_polygon.py b/src/sage/plot/hyperbolic_polygon.py index e6465183e04..7bc97f336ca 100644 --- a/src/sage/plot/hyperbolic_polygon.py +++ b/src/sage/plot/hyperbolic_polygon.py @@ -8,7 +8,8 @@ """ #***************************************************************************** # Copyright (C) 2011 Hartmut Monien , -# 2014 Vincent Delecroix <20100.delecroix@gmail.com> +# 2014 Vincent Delecroix <20100.delecroix@gmail.com>, +# 2015 Stefan Kraemer # # Distributed under the terms of the GNU General Public License (GPL) # @@ -85,7 +86,7 @@ def _hyperbolic_arc(self, z0, z3, first=False): the hyperbolic arc between the complex numbers z0 and z3 in the hyperbolic plane. """ - if (z0-z3).real() == 0: + if abs((z0-z3).real()) < 10.**(-3): self.path.append([(z0.real(), z0.imag()), (z3.real(), z3.imag())]) return z0, z3 = (CC(z0), CC(z3)) From 9978ba275365f1e16135d26fab4243231352b9d4 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 15 Sep 2015 17:59:48 -0300 Subject: [PATCH 0884/1872] Trac 18411: more spaces in categories/rings.py --- src/sage/categories/rings.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index ec0eb6797bb..41e312055f3 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -584,13 +584,13 @@ def quotient(self, I, names=None): sage: class PowerIdeal(Ideal_nc): ....: def __init__(self, R, n): ....: self._power = n - ....: Ideal_nc.__init__(self,R,[R.prod(m) for m in product(R.gens(), repeat=n)]) - ....: def reduce(self,x): + ....: Ideal_nc.__init__(self, R, [R.prod(m) for m in product(R.gens(), repeat=n)]) + ....: def reduce(self, x): ....: R = self.ring() - ....: return add([c*R(m) for m,c in x if len(m) Date: Tue, 15 Sep 2015 18:10:33 -0300 Subject: [PATCH 0885/1872] Trac 18411: the empty cartesian product --- src/sage/categories/cartesian_product.py | 26 ++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index fd77d3787a4..10effb44943 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -112,8 +112,13 @@ def __call__(self, args): Functorial construction application. Specializes the generic ``__call__`` from - :class:`CovariantFunctorialConstruction` to handle the case of some - Python objects. Namely ``frozenset``, ``list``, ``set`` and ``tuple``. + :class:`CovariantFunctorialConstruction` to: + + - handle the case of some Python containes. Namely ``frozenset``, + ``list``, ``set`` and ``tuple``. + + - handle the case of the empty list. + See the examples below. EXAMPLES:: @@ -127,11 +132,28 @@ def __call__(self, args): The cartesian product of ({0, 1, 2}, {0, 1}) sage: _.category() Category of Cartesian products of sets + + Check that the empty product is handled correctly: + + sage: C = cartesian_product([]) + sage: C + The cartesian product of () + sage: C.cardinality() + 1 + sage: C.an_element() + () + sage: C.category() + Category of Cartesian products of sets """ if any(type(arg) in native_python_containers for arg in args): from sage.categories.sets_cat import Sets S = Sets() args = [S(a, enumerated_set=True) for a in args] + elif not args: + from sage.categories.sets_cat import Sets + from sage.sets.cartesian_product import CartesianProduct + return CartesianProduct((), Sets().CartesianProducts()) + return super(CartesianProductFunctor, self).__call__(args) cartesian_product = CartesianProductFunctor() From 07cc001e5c45b27a68088d175699732847adcc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 15 Sep 2015 23:23:34 +0200 Subject: [PATCH 0886/1872] 18411: Fixed unused import --- src/sage/combinat/composition.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 4b7ada989d5..6958656bd4a 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -33,7 +33,6 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.sets.set import Set from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.rings.all import ZZ from combinat import CombinatorialElement From 7c103df59914913d77102a559686d932d1918f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 15 Sep 2015 23:29:50 +0200 Subject: [PATCH 0887/1872] 18411: cleanup spacing for optional arguments --- src/sage/combinat/tutorial.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index 907dcc0fbb8..03b7058fc92 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -1527,21 +1527,21 @@ and length `3`, with parts bounded below by `2`, `4` and `2` respectively:: - sage: IntegerVectors(10, 3, min_part = 2, max_part = 5, - ....: inner = [2, 4, 2]).list() + sage: IntegerVectors(10, 3, min_part=2, max_part=5, + ....: inner=[2, 4, 2]).list() [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] The compositions of `5` with each part at most `3`, and with length `2` or `3`:: - sage: Compositions(5, max_part = 3, - ....: min_length = 2, max_length = 3).list() + sage: Compositions(5, max_part=3, + ....: min_length=2, max_length=3).list() [[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [1, 3, 1], [1, 2, 2], [1, 1, 3]] The strictly decreasing partitions of `5`:: - sage: Partitions(5, max_slope = -1).list() + sage: Partitions(5, max_slope=-1).list() [[5], [4, 1], [3, 2]] These sets share the same underlying algorithmic structure, implemented @@ -1552,23 +1552,23 @@ the consecutive differences between the parts. Here are some more examples:: - sage: IntegerListsLex(10, length = 3, - ....: min_part = 2, max_part = 5, - ....: floor = [2, 4, 2]).list() + sage: IntegerListsLex(10, length=3, + ....: min_part=2, max_part=5, + ....: floor=[2, 4, 2]).list() [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] - sage: IntegerListsLex(5, min_part = 1, max_part = 3, - ....: min_length = 2, max_length = 3).list() + sage: IntegerListsLex(5, min_part=1, max_part=3, + ....: min_length=2, max_length=3).list() [[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [1, 3, 1], [1, 2, 2], [1, 1, 3]] - sage: IntegerListsLex(5, min_part = 1, max_slope = -1).list() + sage: IntegerListsLex(5, min_part=1, max_slope=-1).list() [[5], [4, 1], [3, 2]] - sage: list(Compositions(5, max_length = 2)) + sage: list(Compositions(5, max_length=2)) [[5], [4, 1], [3, 2], [2, 3], [1, 4]] - sage: list(IntegerListsLex(5, max_length = 2, min_part = 1)) + sage: list(IntegerListsLex(5, max_length=2, min_part=1)) [[5], [4, 1], [3, 2], [2, 3], [1, 4]] The point of the model of ``IntegerListsLex`` is in the compromise From a35ef8a704cc966a3a118c84b50a46e3cd6f6245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 15 Sep 2015 23:36:21 +0200 Subject: [PATCH 0888/1872] 18411: proofreading --- src/sage/combinat/cartesian_product.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/cartesian_product.py b/src/sage/combinat/cartesian_product.py index 8a4184de70d..e0f292fc1a4 100644 --- a/src/sage/combinat/cartesian_product.py +++ b/src/sage/combinat/cartesian_product.py @@ -25,7 +25,7 @@ def CartesianProduct(*iters): """ - This is deprecated. Use ``cartesian_product`` instead. + This is deprecated. Use :obj:`cartesian_product` instead. EXAMPLES:: @@ -105,20 +105,21 @@ class CartesianProduct_iters(CombinatorialClass): r""" Cartesian product of finite sets. - This class will be soonly deprecated (see :trac:`18411` and :trac:`19195`). + This class will soon be deprecated (see :trac:`18411` and :trac:`19195`). One should instead use the functorial construction :class:`cartesian_product `. The main differences in behavior are: - - at creation: as many argument as there are factors with - ``CartesianProduct`` whereas only a list of factors for - ``cartesian_product``; + - construction: ``CartesianProduct`` takes as many argument as + there are factors whereas ``cartesian_product`` takes a single + list (or iterable) of factors; - - representation of elements: a Python list for ``CartesianProduct`` versus - a dedicated element class for ``cartesian_product``; + - representation of elements: elements are represented by plain + Python list for ``CartesianProduct`` versus a custom element + class for ``cartesian_product``; - - membership test: because the objects are different the membership tests - differ. + - membership testing: because of the above, plain Python lists are + not considered as elements of a ``cartesian_product``. All of these is illustrated in the examples below. From 22f8b77a3cc2223863396f8d422fbbeec51d1656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 15 Sep 2015 23:39:38 +0200 Subject: [PATCH 0889/1872] 18411: proofreading --- src/sage/categories/cartesian_product.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index 10effb44943..4f37caa3c9b 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -111,13 +111,14 @@ def __call__(self, args): r""" Functorial construction application. - Specializes the generic ``__call__`` from + This specializes the generic ``__call__`` from :class:`CovariantFunctorialConstruction` to: - - - handle the case of some Python containes. Namely ``frozenset``, - ``list``, ``set`` and ``tuple``. - - handle the case of the empty list. + - handle the following plain Python containers as input: + :class:`frozenset`, :class:`list`, :class:`set` and + :class:`tuple`. + + - handle the empty list of factors. See the examples below. From 2e4a415d7859d3968f612932b36c98318e1823d2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 16 Sep 2015 08:53:06 +0200 Subject: [PATCH 0890/1872] rename title --- src/sage/rings/asymptotic/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index adb86fd31dc..4416e26d423 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -1,5 +1,5 @@ r""" -Asymptotic Ring --- Miscellaneous +Asymptotic Expansions --- Miscellaneous AUTHORS: From e9ed00562a257b8fff6ae85384944c40c48f13f1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 16 Sep 2015 09:02:34 +0200 Subject: [PATCH 0891/1872] fix docstring (:: instead of :) --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/growth_group.py | 4 ++-- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 1cc9acac3a5..155c4740ced 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1093,7 +1093,7 @@ def some_elements(self): An iterator. - EXAMPLES: + EXAMPLES:: sage: from itertools import islice sage: A = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 4601128bcc3..d74443d0235 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -698,7 +698,7 @@ def some_elements(self): An iterator. - EXAMPLES: + EXAMPLES:: sage: import sage.rings.asymptotic.growth_group as agg sage: tuple(agg.MonomialGrowthGroup(ZZ, 'z').some_elements()) @@ -994,7 +994,7 @@ def exponent(self): r""" The exponent of this growth element. - EXAMPLES: + EXAMPLES:: sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.MonomialGrowthGroup(ZZ, 'x') diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 823f7986515..a2216b8158a 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1018,7 +1018,7 @@ def some_elements(self): An iterator. - EXAMPLES: + EXAMPLES:: sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm @@ -1802,7 +1802,7 @@ def some_elements(self): An iterator. - EXAMPLES: + EXAMPLES:: sage: from itertools import islice sage: import sage.rings.asymptotic.growth_group as agg From b06cc7f2214b94c24a071e7fe06eb39772ce3a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 16 Sep 2015 11:25:38 +0200 Subject: [PATCH 0892/1872] trac #18937 changes to patchbot SPKG.txt --- build/pkgs/patchbot/SPKG.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build/pkgs/patchbot/SPKG.txt b/build/pkgs/patchbot/SPKG.txt index 93c9d3da752..c34994b3818 100644 --- a/build/pkgs/patchbot/SPKG.txt +++ b/build/pkgs/patchbot/SPKG.txt @@ -4,7 +4,12 @@ Apply branches and run tests on open Sage tickets. -The patchbot is used to automate the testing of git branches. It has two different aspects: a server side and a client side. +The patchbot is used to automate the testing of git branches. It has two +different aspects: a server side and a client side. + +Instructions for using the client side can be found at + +http://wiki.sagemath.org/buildbot/details == License == @@ -18,4 +23,4 @@ https://github.com/robertwb/sage-patchbot/ == Dependencies == -python, sage-scripts +python, python-dateutil, sage-scripts From 92a2a6fb4bce16667412a5d206133d6128b25c00 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 16 Sep 2015 15:21:47 +0200 Subject: [PATCH 0893/1872] trac #19224: swtich OA(k,n)+* strongly regular graphs --- src/sage/graphs/strongly_regular_db.pyx | 69 ++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index f4bde1c2a36..5db46f95372 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -668,6 +668,72 @@ def is_taylor_twograph_srg(int v,int k,int l,int mu): return (TaylorTwographSRG, q) return +def is_switch_OA_srg(int v,int k,int l,int mu): + r""" + Test whether some *switch* `OA(k,n)+*` is `(v,k,\lambda,\mu)`-strongly regular. + + The "switch* `OA(k,n)+*` graphs appear on `Andries Brouwer's database + `__ and are built by + adding an isolated vertex to a + :meth:`~sage.graphs.graph_generators.GraphGenerators.OrthogonalArrayBlockGraph`, + and a :meth:`Seidel switching ` a set of disjoint + `n`-cocliques. + + INPUT: + + - ``v,k,l,mu`` (integers) + + OUTPUT: + + A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if the + parameters match, and ``None`` otherwise. + + EXAMPLES:: + + sage: from sage.graphs.strongly_regular_db import is_switch_OA_srg + sage: t = is_switch_OA_srg(170, 78, 35, 36); t + (.switch_OA_srg ...>, 6, 13) + sage: g = t[0](*t[1:]); g + Graph on 170 vertices + sage: g.is_strongly_regular(parameters=True) + (170, 78, 35, 36) + sage: t = is_switch_OA_srg(5,5,5,5); t + + TESTS:: + + sage: is_switch_OA_srg(290, 136, 63, 64) + (.switch_OA_srg at ..., 8, 17) + sage: is_switch_OA_srg(626, 300, 143, 144) + (.switch_OA_srg at ..., 12, 25) + sage: is_switch_OA_srg(842, 406, 195, 196) + (.switch_OA_srg at ..., 14, 29) + + """ + n_2_p_1 = v + if not is_square(n_2_p_1-1): + return None + + from sage.combinat.designs.orthogonal_arrays import orthogonal_array + from math import sqrt + cdef int n = int(sqrt(n_2_p_1-1)) + + cdef int c = k/n + if (k % n or + l != c*c-1 or + k != 1+(c-1)*(c+1)+(n-c)*(n-c-1) or + not orthogonal_array(c+1,n,existence=True)): + return None + + def switch_OA_srg(c,n): + from itertools import izip + OA = map(tuple,orthogonal_array(c+1,n,resolvable=True)) + g = Graph([OA,lambda x,y: any(xx==yy for xx,yy in izip(x,y))],loops=False) + g.add_vertex(0) + g.seidel_switching(OA[:c*n]) + return g + + return (switch_OA_srg,c,n) + cdef eigenvalues(int v,int k,int l,int mu): r""" Return the eigenvalues of a (v,k,l,mu)-strongly regular graph. @@ -1741,7 +1807,8 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint is_unitary_dual_polar, is_RSHCD, is_twograph_descendant_of_srg, - is_taylor_twograph_srg] + is_taylor_twograph_srg, + is_switch_OA_srg] # Going through all test functions, for the set of parameters and its # complement. From 3eefe25707084aab19d3b2088ea6d90a6d142eae Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 16 Sep 2015 17:04:40 +0200 Subject: [PATCH 0894/1872] correct typo in AUTHORS --- src/sage/categories/pushout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 821b8cd99a6..1d9c385b159 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3579,7 +3579,7 @@ def pushout(R, S): AUTHORS: - Robert Bradshaw - - Peter Bruin(Peter Bruin -..- -- + - Peter Bruin - Simon King - Daniel Krenn - David Roe From 5fe52e47875db849cc7e13201a656905ac3e063a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 16 Sep 2015 17:08:42 +0200 Subject: [PATCH 0895/1872] fix doctests since name of cartesian product functor has changed --- src/sage/categories/pushout.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 1d9c385b159..7637092e2fd 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -314,7 +314,7 @@ def common_base(self, other_functor, self_bases, other_bases): Traceback (most recent call last): ... CoercionException: No common base ("join") found for - FractionField(Integer Ring) and CartesianProductFunctor(Integer Ring). + FractionField(Integer Ring) and The cartesian_product functorial construction(Integer Ring). """ self._raise_common_base_exception_( other_functor, self_bases, other_bases) @@ -343,7 +343,7 @@ def _raise_common_base_exception_(self, other_functor, Traceback (most recent call last): ... CoercionException: No common base ("join") found for - FractionField(Integer Ring) and CartesianProductFunctor(Rational Field). + FractionField(Integer Ring) and The cartesian_product functorial construction(Rational Field). """ if not isinstance(self_bases, (tuple, list)): self_bases = (self_bases,) @@ -687,14 +687,14 @@ def common_base(self, other_functor, self_bases, other_bases): Traceback (most recent call last): ... CoercionException: No common base ("join") found for - CartesianProductFunctor(Integer Ring) and FractionField(Integer Ring): + The cartesian_product functorial construction(Integer Ring) and FractionField(Integer Ring): (Multivariate) functors are inkompatibel. sage: pushout(cartesian_product([ZZ]), cartesian_product([ZZ, QQ])) # indirect doctest Traceback (most recent call last): ... CoercionException: No common base ("join") found for - CartesianProductFunctor(Integer Ring) and - CartesianProductFunctor(Integer Ring, Rational Field): + The cartesian_product functorial construction(Integer Ring) and + The cartesian_product functorial construction(Integer Ring, Rational Field): Functors need the same number of arguments. """ if self != other_functor: From 60b9375bd3733f5b0a1a802504b8348a8feb6795 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 16 Sep 2015 17:42:31 +0200 Subject: [PATCH 0896/1872] revert changes in base_ring of category_object and adapt doctests This will be on a separate ticket --- src/sage/categories/pushout.py | 12 +++++++----- src/sage/structure/category_object.pyx | 4 ---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 7637092e2fd..89bb5284bbc 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -644,15 +644,17 @@ class MultivariateConstructionFunctor(ConstructionFunctor): sage: from sage.categories.pushout import pushout sage: from sage.sets.cartesian_product import CartesianProduct - sage: A = cartesian_product((QQ['z'],)) - sage: B = cartesian_product((ZZ['t']['z'],)) + sage: A = cartesian_product((QQ['z'], QQ)) + sage: B = cartesian_product((ZZ['t']['z'], QQ)) sage: pushout(A, B) - The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) + The cartesian product of (Univariate Polynomial Ring in z over + Univariate Polynomial Ring in t over Rational Field, + Rational Field) sage: A.construction() (The cartesian_product functorial construction, - (Univariate Polynomial Ring in z over Rational Field,)) + (Univariate Polynomial Ring in z over Rational Field, Rational Field)) sage: pushout(A, B) - The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field,) + The cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field, Rational Field) """ def common_base(self, other_functor, self_bases, other_bases): r""" diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index e82ca3bd7ac..be78efcf49a 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -623,10 +623,6 @@ cdef class CategoryObject(sage_object.SageObject): category) so as not to pollute the namespace of all category objects. """ - try: - return super(CategoryObject, self).base_ring() - except AttributeError: - pass return self._base def base(self): From c16587c8b549dde5891f00ec9be10426889c7424 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 16 Sep 2015 19:33:25 +0200 Subject: [PATCH 0897/1872] fix bug (tower has only one entry which is None) --- src/sage/categories/pushout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 89bb5284bbc..cdefa9be244 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3656,7 +3656,7 @@ def pushout(R, S): Ss.pop() Z = Rs.pop() - if Z is None: + if Z is None and R_tower[-1][0] is not None: Z = R_tower[-1][0].common_base(S_tower[-1][0], R_tower[-1][1], S_tower[-1][1]) R_tower = expand_tower(R_tower[:len(Rs)]) S_tower = expand_tower(S_tower[:len(Ss)]) From 4a6174f7e86903243009162bd2e0b6bf6120c2b2 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Wed, 16 Sep 2015 23:03:09 +0200 Subject: [PATCH 0898/1872] improved a short description --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 97f93f29dc0..68f193c8f7a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1231,8 +1231,8 @@ def _coerce_map_from_(self, S): def gens_monomial(self): r""" - Return a monomial generator of this growth group, in case - one exists. + Return a tuple containing monomial generators of this growth + group. INPUT: From 80786754e17a3a8866f48386b341374363b7c047 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 16 Sep 2015 15:23:39 -0700 Subject: [PATCH 0899/1872] coordinates enabled for PG designs --- src/sage/combinat/designs/block_design.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index 9dee5f2ec5d..d516efce18e 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -165,7 +165,7 @@ def are_hyperplanes_in_projective_geometry_parameters(v, k, lmbda, return_parame return (True, (q,d)) if return_parameters else True -def ProjectiveGeometryDesign(n, d, F, algorithm=None, check=True): +def ProjectiveGeometryDesign(n, d, F, algorithm=None, coordinates=None, check=True): """ Return a projective geometry design. @@ -188,6 +188,10 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, check=True): GAP's "design" package must be available in this case, and that it can be installed with the ``gap_packages`` spkg. + - ``coordinates`` -- ``None`` by default. In this case and also if + ``algorithm="gap"``, the ground set is indexed by integers, + Otherwise it is indexed by coordinates in `F^{n+1}`. + EXAMPLES: The set of `d`-dimensional subspaces in a `n`-dimensional projective space @@ -203,6 +207,12 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, check=True): sage: PG.is_t_design(return_parameters=True) (True, (2, 85, 5, 1)) + Use coordinates:: + + sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3),coordinates=1) + sage: PG.blocks()[0] + [(1, 0, 0), (1, 0, 1), (1, 0, 2), (0, 0, 1)] + Check that the constructor using gap also works:: sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm="gap") # optional - gap_packages (design package) @@ -224,7 +234,10 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, check=True): m.set_immutable() b.append(points[m]) blocks.append(b) - return BlockDesign(len(points), blocks, name="ProjectiveGeometryDesign", check=check) + B = BlockDesign(len(points), blocks, name="ProjectiveGeometryDesign", check=check) + if not coordinates is None: + B.relabel({i:p[0] for p,i in points.iteritems()}) + return B if algorithm == "gap": # Requires GAP's Design from sage.interfaces.gap import gap gap.load_package("design") From 8d7562fa257f1a8e199352b812fd27718c563967 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 16 Sep 2015 23:45:06 -0700 Subject: [PATCH 0900/1872] GQ(q+1,q-1) and GQ(q-1,q+1) implemented and recognised in DB TODO: non-classical hyperovals, for completeness... --- .../graphs/generators/classical_geometries.py | 146 +++++++++++++++++- src/sage/graphs/graph_generators.py | 4 + src/sage/graphs/strongly_regular_db.pyx | 78 +++++++++- 3 files changed, 218 insertions(+), 10 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index cae8a1e9e30..d78aabdc0ed 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -21,6 +21,8 @@ from math import sin, cos, pi from sage.graphs.graph import Graph from sage.graphs import graph +from sage.rings.arith import is_prime_power +from sage.rings.finite_rings.constructor import FiniteField def SymplecticPolarGraph(d, q, algorithm=None): r""" @@ -87,7 +89,6 @@ def SymplecticPolarGraph(d, q, algorithm=None): G = _polar_graph(d, q, libgap.SymplecticGroup(d, q)) elif algorithm == None: # faster for small (q<4) fields - from sage.rings.finite_rings.constructor import FiniteField from sage.modules.free_module import VectorSpace from sage.schemes.projective.projective_space import ProjectiveSpace from sage.matrix.constructor import identity_matrix, block_matrix, zero_matrix @@ -187,7 +188,6 @@ def AffineOrthogonalPolarGraph(d,q,sign="+"): s = 0 from sage.interfaces.gap import gap - from sage.rings.finite_rings.constructor import FiniteField from sage.modules.free_module import VectorSpace from sage.matrix.constructor import Matrix from sage.libs.gap.libgap import libgap @@ -287,7 +287,6 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): """ from sage.schemes.projective.projective_space import ProjectiveSpace - from sage.rings.finite_rings.constructor import FiniteField from sage.modules.free_module_element import free_module_element as vector from sage.matrix.constructor import Matrix from sage.libs.gap.libgap import libgap @@ -491,7 +490,6 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): """ from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph - from sage.rings.arith import is_prime_power p, k = is_prime_power(q,get_data=True) if k==0: raise ValueError('q must be a prime power') @@ -635,7 +633,6 @@ def UnitaryPolarGraph(m, q, algorithm="gap"): elif algorithm == None: # slow on large examples from sage.schemes.projective.projective_space import ProjectiveSpace - from sage.rings.finite_rings.constructor import FiniteField from sage.modules.free_module_element import free_module_element as vector from __builtin__ import sum as psum Fq = FiniteField(q**2, 'a') @@ -697,7 +694,6 @@ def NonisotropicUnitaryPolarGraph(m, q): Disc. Math. 13(1975), pp 357--381. http://dx.doi.org/10.1016/0012-365X(75)90057-6 """ - from sage.rings.arith import is_prime_power p, k = is_prime_power(q,get_data=True) if k==0: raise ValueError('q must be a prime power') @@ -881,12 +877,10 @@ def TaylorTwographDescendantSRG(q, clique_partition=None): ... ValueError: q must be an odd prime power """ - from sage.rings.arith import is_prime_power p, k = is_prime_power(q,get_data=True) if k==0 or p==2: raise ValueError('q must be an odd prime power') from sage.schemes.projective.projective_space import ProjectiveSpace - from sage.rings.finite_rings.constructor import FiniteField from sage.modules.free_module_element import free_module_element as vector from sage.rings.finite_rings.integer_mod import mod from __builtin__ import sum @@ -941,3 +935,139 @@ def TaylorTwographSRG(q): G.seidel_switching(sum(l[:(q**2+1)/2],[])) G.name("Taylor two-graph SRG") return G + +def AhrensSzekeresGQ(q, dual=False): + r""" + Return the collinearity graph of GQ AS(q) or its dual + + INPUT: + + - ``q`` -- a power of an odd prime number + + - ``dual`` -- if ``False`` (default), return the graph of `GQ(q-1,q+1)`. + Otherwise return the graph of `GQ(q+1,q-1)`. + + `AS(q)` is a generalised quadrangle (GQ) of order `(q-1,q+1)`, see 3.1.5 in [PT09]_. + Let `q` be an odd prime power. Then the points are elements of `F_q^3`, + and lines are of the form + + * `(\sigma, a, b), \sigma\in F_q` + * `(a, \sigma, b), \sigma\in F_q` + * `(c \sigma^2 - b \sigma + a, -2 c \sigma + b, \sigma), \sigma\in F_q` + + where `a`, `b`, `c` are arbitrary elements of `F_q`. + + EXAMPLES:: + + sage: g=graphs.AhrensSzekeresGQ(5); g + AS(5); GQ(4, 6): Graph on 125 vertices + sage: g.is_strongly_regular(parameters=True) + (125, 28, 3, 7) + sage: g=graphs.AhrensSzekeresGQ(5,dual=True); g + AS(5)*; GQ(6, 4): Graph on 175 vertices + sage: g.is_strongly_regular(parameters=True) + (175, 30, 5, 5) + + REFERENCE: + + .. [PT09] S. Payne, J. A. Thas. + Finite generalized quadrangles. + European Mathematical Society, + 2nd edition, 2009. + """ + from sage.combinat.designs.incidence_structures import IncidenceStructure + p, k = is_prime_power(q,get_data=True) + if k==0 or p==2: + raise ValueError('q must be an odd prime power') + F = FiniteField(q, 'a') + L = [] + for a in F: + for b in F: + L.append(tuple(map(lambda s: (s, a, b), F))) + L.append(tuple(map(lambda s: (a, s, b), F))) + for c in F: + L.append(tuple(map(lambda s: (c*s**2 - b*s + a, -2*c*s + b, s), F))) + if dual: + G = IncidenceStructure(L).intersection_graph() + G.name('AS('+str(q)+')*; GQ'+str((q+1,q-1))) + else: + G = IncidenceStructure(L).dual().intersection_graph() + G.name('AS('+str(q)+'); GQ'+str((q-1,q+1))) + return G + +def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): + r""" + Return the collinearity graph of GQ T_2*(q) or its dual + + INPUT: + + - ``q`` -- a power of two + + - ``dual`` -- if ``False`` (default), return the graph of `GQ(q-1,q+1)`. + Otherwise return the graph of `GQ(q+1,q-1)`. + + - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane + meeting every line in 0 or 2 points) in the plane of points with 0th coordinate + 0 in `PG(3,q)` over the field ``field``. By default, ``hyperoval`` and + ``field`` are not specified, and constructed on the fly. + + - ``field`` -- an instance of a finite field of order `q`, must be provided + if ``hyperoval`` is provided. + + - ``checkhyperoval`` -- (default: ``False``) if ``True``, + check ``hyperoval`` for correctness. + + `T_2^*(q)` is a generalised quadrangle (GQ) of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. + Let `q=2^k` and `\Theta=PG(3,q)`. Fix a plane `\Pi \subset \Theta` and + a hyperoval `O \subset \Pi`. The points of the GQ are the points of `\Theta` + outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi` + that meet `\Pi` in a point of `O`. + + + EXAMPLES:: + + sage: g=graphs.T2starGQ(4); g + T2*(O,4); GQ(3, 5): Graph on 64 vertices + sage: g.is_strongly_regular(parameters=True) + (64, 18, 2, 6) + sage: g=graphs.T2starGQ(4,dual=True); g + T2*(O,4)*; GQ(5, 3): Graph on 96 vertices + sage: g.is_strongly_regular(parameters=True) + (96, 20, 4, 4) + """ + from sage.combinat.designs.incidence_structures import IncidenceStructure + from sage.combinat.designs.block_design import ProjectiveGeometryDesign as PG + from sage.modules.free_module_element import free_module_element as vector + + p, k = is_prime_power(q,get_data=True) + if k==0 or p!=2: + raise ValueError('q must be a power of 2') + if field is None: + F = FiniteField(q, 'a') + else: + F = field + + Theta = PG(3,1,F,coordinates=1) + Pi = set(filter(lambda x: x[0]==F.zero(), Theta.ground_set())) + if hyperoval is None: + O = filter(lambda x: x[1]+x[2]*x[3]==0 or (x[1]==1 and x[2]==0 and x[3]==0), Pi) + O = set(O) + else: + O = set(hyperoval) + + if checkhyperoval: + if len(O) != q+2: + raise RunTimeError("incorrect hyperoval size") + for L in Theta.blocks(): + if Pi.issubset(L): + if not len(O.intersection(L)) in [0,2]: + raise RunTimeError("incorrect hyperoval") + L = map(lambda z: filter(lambda y: not y in O, z), + filter(lambda x: len(O.intersection(x)) == 1, Theta.blocks())) + if dual: + G = IncidenceStructure(L).intersection_graph() + G.name('T2*(O,'+str(q)+')*; GQ'+str((q+1,q-1))) + else: + G = IncidenceStructure(L).dual().intersection_graph() + G.name('T2*(O,'+str(q)+'); GQ'+str((q-1,q+1))) + return G diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 74f0cb3bbd3..a192f992fdb 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -234,6 +234,7 @@ def __append_to_doc(methods): __append_to_doc( ["AffineOrthogonalPolarGraph", + "AhrensSzekeresGQ", "NonisotropicOrthogonalPolarGraph", "NonisotropicUnitaryPolarGraph", "OrthogonalPolarGraph", @@ -241,6 +242,7 @@ def __append_to_doc(methods): "SymplecticPolarGraph", "TaylorTwographDescendantSRG", "TaylorTwographSRG", + "T2starGQ", "UnitaryDualPolarGraph", "UnitaryPolarGraph"]) @@ -1995,6 +1997,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None ########################################################################### import sage.graphs.generators.classical_geometries AffineOrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.AffineOrthogonalPolarGraph) + AhrensSzekeresGQ = staticmethod(sage.graphs.generators.classical_geometries.AhrensSzekeresGQ) NonisotropicOrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph) NonisotropicUnitaryPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.NonisotropicUnitaryPolarGraph) OrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.OrthogonalPolarGraph) @@ -2004,6 +2007,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None TaylorTwographDescendantSRG = \ staticmethod(sage.graphs.generators.classical_geometries.TaylorTwographDescendantSRG) TaylorTwographSRG = staticmethod(sage.graphs.generators.classical_geometries.TaylorTwographSRG) + T2starGQ = staticmethod(sage.graphs.generators.classical_geometries.T2starGQ) UnitaryDualPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.UnitaryDualPolarGraph) UnitaryPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.UnitaryPolarGraph) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 6aa69bdfc8d..7ff9dc2b13d 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -857,6 +857,81 @@ def is_unitary_dual_polar(int v,int k,int l,int mu): from sage.graphs.generators.classical_geometries import UnitaryDualPolarGraph return (UnitaryDualPolarGraph, 5, p**t) +@cached_function +def is_GQqmqp(int v,int k,int l,int mu): + r""" + Test whether some `GQ(q-1,q+1)` or `GQ(q+1,q-1)`-graph is `(v,k,\lambda,\mu)`-srg. + + INPUT: + + - ``v,k,l,mu`` (integers) + + OUTPUT: + + A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one + exists, and ``None`` otherwise. + + EXAMPLES:: + + sage: from sage.graphs.strongly_regular_db import is_GQqmqp + sage: t = is_GQqmqp(27,10,1,5); t + (, 3, False) + sage: g = t[0](*t[1:]); g + AS(3); GQ(2, 4): Graph on 27 vertices + sage: t = is_GQqmqp(45,12,3,3); t + (, 3, True) + sage: g = t[0](*t[1:]); g + AS(3)*; GQ(4, 2): Graph on 45 vertices + sage: g.is_strongly_regular(parameters=True) + (45, 12, 3, 3) + sage: t = is_GQqmqp(16,6,2,2); t + (, 2, True) + sage: g = t[0](*t[1:]); g + T2*(O,2)*; GQ(3, 1): Graph on 16 vertices + sage: g.is_strongly_regular(parameters=True) + (16, 6, 2, 2) + sage: t = is_GQqmqp(64,18,2,6); t + (, 4, False) + sage: g = t[0](*t[1:]); g + T2*(O,4); GQ(3, 5): Graph on 64 vertices + sage: g.is_strongly_regular(parameters=True) + (64, 18, 2, 6) + + TESTS:: + + sage: (S,T)=(127,129) + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t + (, 128, False) + sage: (S,T)=(129,127) + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t + (, 128, True) + sage: (S,T)=(124,126) + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t + (, 125, False) + sage: (S,T)=(126,124) + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t + (, 125, True) + sage: t = is_GQqmqp(5,5,5,5); t + """ + # do we have GQ(s,t)? we must have mu=t+1, s=l+1, + # v=(s+1)(st+1), k=s(t+1) + S=l+1 + T=mu-1 + if (v == (S+1)*(S*T+1) and + k == S*(T+1) and + (S+T) % 2 == 0): + q = (S+T)/2 + p, k = is_prime_power(q, get_data=True) + if p % 2 == 0: + from sage.graphs.generators.classical_geometries import T2starGQ as F + else: + from sage.graphs.generators.classical_geometries import AhrensSzekeresGQ as F + if k != 0: + if (S,T) == (q-1, q+1): + return (F, q, False) + elif (S,T) == (q+1, q-1): + return (F, q, True) + @cached_function def is_twograph_descendant_of_srg(int v, int k0, int l, int mu): r""" @@ -2058,8 +2133,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint is_steiner, is_affine_polar, is_orthogonal_polar, is_NOodd, is_NOperp_F5, is_NO_F2, is_NO_F3, is_NU, - is_unitary_polar, - is_unitary_dual_polar, + is_unitary_polar, is_unitary_dual_polar, is_GQqmqp, is_RSHCD, is_twograph_descendant_of_srg, is_taylor_twograph_srg] From 1de29de8ab7afe7805a4a3d8bb62c77dc1e3b76f Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 16 Sep 2015 23:48:57 -0700 Subject: [PATCH 0901/1872] removed explicit graphs that we can now build (thanks to this ticket and NONU) --- src/sage/graphs/strongly_regular_db.pyx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 7ff9dc2b13d..245ddf0d5f0 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -2073,20 +2073,8 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint ( 27, 16, 10, 8): [SchlaefliGraph], ( 36, 14, 4, 6): [Graph,('c~rLDEOcKTPO`U`HOIj@MWFLQFAaRIT`HIWqPsQQJ'+ 'DXGLqYM@gRLAWLdkEW@RQYQIErcgesClhKefC_ygSGkZ`OyHETdK[?lWStCapVgKK')], - ( 40, 12, 2, 4): [Graph,('g}iS[A@_S@OA_BWQIGaPCQE@CcQGcQECXAgaOdS@a'+ - 'CWEEAOIBH_HW?scb?f@GMBGGhIPGaQoh?q_bD_pGPq_WI`T_DBU?R_dECsSARGgogBO'+ - '{_IPBKZ?DI@Wgt_E?MPo{_?')], - ( 45, 12, 3, 3): [Graph,('l~}CKMF_C?oB_FPCGaICQOaH@DQAHQ@Ch?aJHAQ@G'+ - 'P_CQAIGcAJGO`IcGOY`@IGaGHGaKSCDI?gGDgGcE_@OQAg@PCSO_hOa`GIDADAD@XCI'+ - 'ASDKB?oKOo@_SHCc?SGcGd@A`B?bOOHGQH?ROQOW`?XOPa@C_hcGo`CGJK')], ( 50, 7, 0, 1): [HoffmanSingletonGraph], ( 56, 10, 0, 2): [SimsGewirtzGraph], - ( 64, 18, 2, 6): [Graph,('~?@?~aK[A@_[?O@_B_?O?K?B_?A??K??YQQPHGcQQ'+ - 'CaPIOHAX?POhAPIC`GcgSAHDE?PCiC@BCcDADIG_QCocS@AST?OOceGG@QGcKcdCbCB'+ - 'gIEHAScIDDOy?DAWaEg@IQO?maHPOhAW_dBCX?s@HOpKD@@GpOpHO?bCbHGOaGgpWQQ'+ - '?PDDDw@A_CSRIS_P?GeGpg`@?EOcaJGccbDC_dLAc_pHOe@`ocEGgo@sRo?WRAbAcPc'+ - '?iCiHEKBO_hOiOWpOSGSTBQCUAW_DDIWOqHBO?gghw_?`kOAXH?\\Ds@@@CpIDKOpc@'+ - 'OCoeIS_YOgGATGaqAhKGA?cqDOwQKGc?')], ( 77, 16, 0, 4): [M22Graph], ( 81, 50, 31, 30): [SRG_81_50_31_30], (100, 22, 0, 6): [HigmanSimsGraph], From 3318570ec262afdaaf26041c3dfc34e89840f927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 17 Sep 2015 10:39:47 +0200 Subject: [PATCH 0902/1872] trac #18937 patchbot 2.4.7, no more needing dateutil, better log --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index 8071e26bf7e..7cebb66b8e2 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=5e23aabb8ed9851ef6d04fc3209a1a4f16e4de6c -md5=2717b61c5de5b76312370f1099c90ef8 -cksum=183944074 +sha1=be2fcb7039c02f37669f5ea078fb2868730df67c +md5=3ebebd93ce6194dee6263270a6419970 +cksum=2163763617 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 7bf4b6a8aef..e30309f735e 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.6 +2.4.7 From 0690e716b925505dc34b77338af0da8f35fc53a4 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 17 Sep 2015 12:43:34 +0200 Subject: [PATCH 0903/1872] improve language in cartesian_product docstring --- src/sage/categories/sets_cat.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 29cedf59072..c7fac3edb28 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1409,13 +1409,14 @@ def cartesian_product(*parents, **kwargs): - ``parents`` -- a list (or other iterable) of parents. - ``category`` -- (default: ``None``) the category the - cartesian product belongs to. If ``None``, then + cartesian product belongs to. If ``None`` is passed, + then :meth:`~sage.categories.covariant_functorial_construction.CovariantFactorialConstruction.category_from_parents` - is used the determine category. + is used to determine the category. - - ``extra_category`` -- (default: ``None``) this category is - added to the cartesian product additionally to the - categories obtained from the parents. + - ``extra_category`` -- (default: ``None``) a category + that is added to the cartesian product in addition + to the categories obtained from the parents. - other keyword arguments will passed on to the class used for this cartesian product (see also From 0a74ff134169bd9e1fa9d50eb061f69c19fe351e Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Thu, 17 Sep 2015 15:57:48 +0200 Subject: [PATCH 0904/1872] typos, language, and punctuation. --- src/sage/sets/cartesian_product.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index ccf0410dc5f..8a3fef2e508 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -301,7 +301,7 @@ class CartesianProductPosets(CartesianProduct): - ``category`` -- a subcategory of ``Sets().CartesianProducts() & Posets()``. - - ``order`` -- a string or function specifing an order less or equal. + - ``order`` -- a string or function specifying an order less or equal. It can be one of the following: - ``'lex'`` -- elements are ordered lexicographically. @@ -348,7 +348,7 @@ class CartesianProductPosets(CartesianProduct): def __init__(self, sets, category, order, **kwargs): r""" - See :class:`CartesianProductPosets` for details, + See :class:`CartesianProductPosets` for details. TESTS:: @@ -375,7 +375,7 @@ def __init__(self, sets, category, order, **kwargs): def le(self, left, right): r""" - Tests if ``left`` is smaller or equal to ``right``. + Tests if ``left`` is less than or equal to ``right``. INPUT: @@ -390,7 +390,7 @@ def le(self, left, right): .. NOTE:: This method uses the order defined on creation of this - cartesian product. See :class:`CartesianProductPosets` + cartesian product. See :class:`CartesianProductPosets`. EXAMPLES:: From 4076a47f7b7ec9c4a6d7e161429e25b0bc5231a1 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 17 Sep 2015 17:10:05 -0700 Subject: [PATCH 0905/1872] added examples and tests for user-supplied hyperoval in T_2*(O), and small bug fixed --- .../graphs/generators/classical_geometries.py | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index d78aabdc0ed..ad34b7be04f 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -1008,7 +1008,8 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane meeting every line in 0 or 2 points) in the plane of points with 0th coordinate - 0 in `PG(3,q)` over the field ``field``. By default, ``hyperoval`` and + 0 in `PG(3,q)` over the field ``field``. Each point of ``hyperoval`` must be a length 4 + vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and ``field`` are not specified, and constructed on the fly. - ``field`` -- an instance of a finite field of order `q`, must be provided @@ -1018,13 +1019,16 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): check ``hyperoval`` for correctness. `T_2^*(q)` is a generalised quadrangle (GQ) of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. - Let `q=2^k` and `\Theta=PG(3,q)`. Fix a plane `\Pi \subset \Theta` and - a hyperoval `O \subset \Pi`. The points of the GQ are the points of `\Theta` + Let `q=2^k` and `\Theta=PG(3,q)`. Fix a plane `\Pi \subset \Theta` and a + `hyperoval `__ + `O \subset \Pi`. The points of the GQ are the points of `\Theta` outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi` that meet `\Pi` in a point of `O`. - EXAMPLES:: + EXAMPLES: + + using the built-in construction:: sage: g=graphs.T2starGQ(4); g T2*(O,4); GQ(3, 5): Graph on 64 vertices @@ -1034,6 +1038,29 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): T2*(O,4)*; GQ(5, 3): Graph on 96 vertices sage: g.is_strongly_regular(parameters=True) (96, 20, 4, 4) + + supplying your own hyperoval:: + + sage: F=GF(4,'b') + sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) + sage: g=graphs.T2starGQ(4, hyperoval=O, field=F); g + T2*(O,4); GQ(3, 5): Graph on 64 vertices + sage: g.is_strongly_regular(parameters=True) + (64, 18, 2, 6) + + TESTS:: + + sage: F=GF(4,'b') # repeating a point... + sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) + sage: graphs.T2starGQ(4, hyperoval=O, field=F, checkhyperoval=True) + Traceback (most recent call last): + ... + RuntimeError: incorrect hyperoval size + sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) + sage: graphs.T2starGQ(4, hyperoval=O, field=F, checkhyperoval=True) + Traceback (most recent call last): + ... + RuntimeError: incorrect hyperoval """ from sage.combinat.designs.incidence_structures import IncidenceStructure from sage.combinat.designs.block_design import ProjectiveGeometryDesign as PG @@ -1053,15 +1080,16 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): O = filter(lambda x: x[1]+x[2]*x[3]==0 or (x[1]==1 and x[2]==0 and x[3]==0), Pi) O = set(O) else: + map(lambda x: x.set_immutable(), hyperoval) O = set(hyperoval) if checkhyperoval: if len(O) != q+2: - raise RunTimeError("incorrect hyperoval size") + raise RuntimeError("incorrect hyperoval size") for L in Theta.blocks(): - if Pi.issubset(L): + if set(L).issubset(Pi): if not len(O.intersection(L)) in [0,2]: - raise RunTimeError("incorrect hyperoval") + raise RuntimeError("incorrect hyperoval") L = map(lambda z: filter(lambda y: not y in O, z), filter(lambda x: len(O.intersection(x)) == 1, Theta.blocks())) if dual: From 258f4f316283342dd927a11280c1955873cd1c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 18 Sep 2015 13:45:09 +0200 Subject: [PATCH 0906/1872] trac #19188 fixing doctest continuation ....: ; plus a few doctests fixed --- src/doc/ja/tutorial/interfaces.rst | 12 +++---- src/doc/ja/tutorial/programming.rst | 10 +++--- src/doc/ja/tutorial/tour_algebra.rst | 8 ++--- src/doc/ja/tutorial/tour_functions.rst | 10 +++--- src/doc/ja/tutorial/tour_groups.rst | 4 +-- src/doc/ja/tutorial/tour_help.rst | 48 +++++++++++++------------- src/doc/ja/tutorial/tour_linalg.rst | 2 +- src/doc/ja/tutorial/tour_numtheory.rst | 8 ++--- src/doc/ja/tutorial/tour_plotting.rst | 18 +++++----- 9 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst index c38ca5cb10b..580bc2e3648 100644 --- a/src/doc/ja/tutorial/interfaces.rst +++ b/src/doc/ja/tutorial/interfaces.rst @@ -177,9 +177,9 @@ Singularは,グレブナー基底,多変数多項式のgcd,平面曲線の // block 1 : ordering dp // : names x y // block 2 : ordering C - sage: f = singular('9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + \ - ... 9*x^6*y^4 + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - \ - ... 9*x^12*y^3 - 18*x^13*y^2 + 9*x^16') + sage: f = singular('9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + + ....: 9*x^6*y^4 + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - + ....: 9*x^12*y^3 - 18*x^13*y^2 + 9*x^16') :math:`f` を定義できたので,その内容を表示してから因数分解を試みる. @@ -206,9 +206,9 @@ Singularは,グレブナー基底,多変数多項式のgcd,平面曲線の :: sage: x, y = QQ['x, y'].gens() - sage: f = 9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4\ - ... + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3\ - ... - 18*x^13*y^2 + 9*x^16 + sage: f = 9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4 + ....: + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3 + ....: - 18*x^13*y^2 + 9*x^16 sage: factor(f) (9) * (-x^5 + y^2)^2 * (x^6 - 2*x^3*y^2 - x^2*y^3 + y^4) diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst index 5b70c1be6fd..20c58c754e0 100644 --- a/src/doc/ja/tutorial/programming.rst +++ b/src/doc/ja/tutorial/programming.rst @@ -599,11 +599,11 @@ Pythonでは,このインデントが重要な役割を果たしている. :: sage: def legendre(a,p): - ... is_sqr_modp=-1 - ... for i in range(p): - ... if a % p == i^2 % p: - ... is_sqr_modp=1 - ... return is_sqr_modp + ....: is_sqr_modp=-1 + ....: for i in range(p): + ....: if a % p == i^2 % p: + ....: is_sqr_modp=1 + ....: return is_sqr_modp sage: legendre(2,7) 1 diff --git a/src/doc/ja/tutorial/tour_algebra.rst b/src/doc/ja/tutorial/tour_algebra.rst index 7d02513277d..00518832a09 100644 --- a/src/doc/ja/tutorial/tour_algebra.rst +++ b/src/doc/ja/tutorial/tour_algebra.rst @@ -216,7 +216,7 @@ Sageを使って常微分方程式を研究することもできる. :math:`x' sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") sage: lde1 = de1.laplace("t","s"); lde1 - 2*(-?%at('diff(x(t),t,1),t=0)+s^2*'laplace(x(t),t,s)-x(0)*s)-2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + 2*(-%at('diff(x(t),t,1),t=0)+s^2*'laplace(x(t),t,s)-x(0)*s)-2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) この出力は読みにくいけれども,意味しているのは @@ -231,7 +231,7 @@ Sageを使って常微分方程式を研究することもできる. :math:`x' sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") sage: lde2 = de2.laplace("t","s"); lde2 - -?%at('diff(y(t),t,1),t=0)+s^2*'laplace(y(t),t,s)+2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s)-y(0)*s + -%at('diff(y(t),t,1),t=0)+s^2*'laplace(y(t),t,s)+2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s)-y(0)*s 意味するところは @@ -270,8 +270,8 @@ Sageを使って常微分方程式を研究することもできる. :math:`x' :: sage: t = var('t') - sage: P = parametric_plot((cos(2*t) + 2*cos(t), 4*cos(t) - cos(2*t) ),\ - ... (t, 0, 2*pi), rgbcolor=hue(0.9)) + sage: P = parametric_plot((cos(2*t) + 2*cos(t), 4*cos(t) - cos(2*t) ), + ....: (t, 0, 2*pi), rgbcolor=hue(0.9)) sage: show(P) 各成分ごとにプロットするには diff --git a/src/doc/ja/tutorial/tour_functions.rst b/src/doc/ja/tutorial/tour_functions.rst index 85278972b5c..e365bf36e5e 100644 --- a/src/doc/ja/tutorial/tour_functions.rst +++ b/src/doc/ja/tutorial/tour_functions.rst @@ -124,10 +124,10 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り :: sage: def h(x): - ... if x<2: - ... return 0 - ... else: - ... return x-2 + ....: if x < 2: + ....: return 0 + ....: else: + ....: return x - 2 ここで ``plot(h(x), 0, 4)`` を実行すると,プロットされるのは `y=x-2` で,複数行にわたって定義しておいた ``h`` ではない. @@ -156,7 +156,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り :: sage: plot(h, 0, 4) - + Graphics object consisting of 1 graphics primitive を実行せよ,ということになる. diff --git a/src/doc/ja/tutorial/tour_groups.rst b/src/doc/ja/tutorial/tour_groups.rst index dd02bb0a780..294bda023ad 100644 --- a/src/doc/ja/tutorial/tour_groups.rst +++ b/src/doc/ja/tutorial/tour_groups.rst @@ -24,7 +24,7 @@ Sageでは,置換群,有限古典群(例えば :math:`SU(n,q)`),有限行 Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] - sage: G.random_element() # 出力は変化する + sage: G.random_element() # random 出力は変化する (1,5,3)(2,4) sage: print latex(G) \langle (3,4), (1,2,3)(4,5) \rangle @@ -62,7 +62,7 @@ Sageは有限体上の古典群と行列群も扱うことができる: sage: G = Sp(4,GF(7)) sage: G Symplectic Group of degree 4 over Finite Field of size 7 - sage: G.random_element() # 元をランダムに出力 + sage: G.random_element() # random 元をランダムに出力 [5 5 5 1] [0 2 6 3] [5 0 1 0] diff --git a/src/doc/ja/tutorial/tour_help.rst b/src/doc/ja/tutorial/tour_help.rst index c7f658d6168..90cdcec6314 100644 --- a/src/doc/ja/tutorial/tour_help.rst +++ b/src/doc/ja/tutorial/tour_help.rst @@ -108,8 +108,8 @@ Sageで新しい関数を定義するには, ``def`` 命令を使い、変数 :: sage: def is_even(n): - ... return n%2 == 0 - ... + ....: return n % 2 == 0 + ....: sage: is_even(2) True sage: is_even(3) @@ -126,7 +126,7 @@ Sageで新しい関数を定義するには, ``def`` 命令を使い、変数 :: sage: def is_divisible_by(number, divisor=2): - ... return number%divisor == 0 + ....: return number % divisor == 0 sage: is_divisible_by(6,2) True sage: is_divisible_by(6) @@ -157,11 +157,11 @@ Pythonの構文ブロックは,他の多くの言語のように中括弧やbe :: sage: def even(n): - ... v = [] - ... for i in range(3,n): - ... if i % 2 == 0: - ... v.append(i) - ... return v + ....: v = [] + ....: for i in range(3, n): + ....: if i % 2 == 0: + ....: v.append(i) + ....: return v Syntax Error: return v @@ -170,11 +170,11 @@ Pythonの構文ブロックは,他の多くの言語のように中括弧やbe :: sage: def even(n): - ... v = [] - ... for i in range(3,n): - ... if i % 2 == 0: - ... v.append(i) - ... return v + ....: v = [] + ....: for i in range(3,n): + ....: if i % 2 == 0: + ....: v.append(i) + ....: return v sage: even(10) [4, 6, 8] @@ -191,8 +191,8 @@ Pythonの構文ブロックは,他の多くの言語のように中括弧やbe :: - sage: 2 + \ - ... 3 + sage: (2 + + ....: 3) 5 @@ -203,7 +203,7 @@ Sageでは,一定範囲の整数の数え上げによって反復を制御す :: sage: for i in range(3): - ... print i + ....: print i 0 1 2 @@ -215,7 +215,7 @@ Sageでは,一定範囲の整数の数え上げによって反復を制御す :: sage: for i in range(2,5): - ... print i + ....: print i 2 3 4 @@ -227,7 +227,7 @@ Sageでは,一定範囲の整数の数え上げによって反復を制御す :: sage: for i in range(1,6,2): - ... print i + ....: print i 1 3 5 @@ -241,7 +241,7 @@ Sageで計算した値を見映えよく表形式に並べて表示したくな :: sage: for i in range(5): - ... print '%6s %6s %6s'%(i, i^2, i^3) + ....: print '%6s %6s %6s' % (i, i^2, i^3) 0 0 0 1 1 1 2 4 8 @@ -318,11 +318,11 @@ Sageにおける最も基本的なデータ構造はリストで,名前の示 :: sage: class Evens(list): - ... def __init__(self, n): - ... self.n = n - ... list.__init__(self, range(2, n+1, 2)) - ... def __repr__(self): - ... return "Even positive numbers up to n." + ....: def __init__(self, n): + ....: self.n = n + ....: list.__init__(self, range(2, n+1, 2)) + ....: def __repr__(self): + ....: return "Even positive numbers up to n." オブジェクトの生成時には初期化のために ``__init__`` メソッドが呼ばれ, ``__repr__`` メソッドはオブジェクトを印字する. diff --git a/src/doc/ja/tutorial/tour_linalg.rst b/src/doc/ja/tutorial/tour_linalg.rst index e2a0a0b7f4a..088d0c70550 100644 --- a/src/doc/ja/tutorial/tour_linalg.rst +++ b/src/doc/ja/tutorial/tour_linalg.rst @@ -196,7 +196,7 @@ Sageは固有値と固有ベクトルの計算もしてくれる: sage: M = MatrixSpace(GF(2),4,8) sage: A = M([1,1,0,0, 1,1,1,1, 0,1,0,0, 1,0,1,1, - ... 0,0,1,0, 1,1,0,1, 0,0,1,1, 1,1,1,0]) + ....: 0,0,1,0, 1,1,0,1, 0,0,1,1, 1,1,1,0]) sage: A [1 1 0 0 1 1 1 1] [0 1 0 0 1 0 1 1] diff --git a/src/doc/ja/tutorial/tour_numtheory.rst b/src/doc/ja/tutorial/tour_numtheory.rst index 32e0a6e0f8a..4e091a77f66 100644 --- a/src/doc/ja/tutorial/tour_numtheory.rst +++ b/src/doc/ja/tutorial/tour_numtheory.rst @@ -84,10 +84,10 @@ Sageの ``sigma(n,k)`` 関数は, ``n`` の商の :math:`k` 乗の和を計算 sage: n = 2005 sage: for i in range(1000): - ... n = 3*odd_part(n) + 1 - ... if odd_part(n)==1: - ... print i - ... break + ....: n = 3 * odd_part(n) + 1 + ....: if odd_part(n) == 1: + ....: print i + ....: break 38 最後に,中国剰余定理を確かめてみよう. diff --git a/src/doc/ja/tutorial/tour_plotting.rst b/src/doc/ja/tutorial/tour_plotting.rst index 87a3a62efbc..c9e94b61e65 100644 --- a/src/doc/ja/tutorial/tour_plotting.rst +++ b/src/doc/ja/tutorial/tour_plotting.rst @@ -70,7 +70,7 @@ Sageの2次元プロット機能を使うと,円,直線,多辺形の描画 sage: x = var('x') sage: parametric_plot((cos(x),sin(x)^3),(x,0,2*pi),rgbcolor=hue(0.6)) - + Graphics object consisting of 1 graphics primitive プロットにおける座標軸の交点は,それがグラフの描画範囲にない限り表示されないことに注意しておいてほしい. 描画範囲として十分大きな値を指定するために,科学記法(指数記法)を用いる必要があるかもしれない. @@ -96,8 +96,8 @@ Sageの2次元プロット機能を使うと,円,直線,多辺形の描画 :: - sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)),\ - ... 2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] + sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)), + ....: 2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)] sage: p = polygon(L, rgbcolor=(1/8,3/4,1/2)) sage: p Graphics object consisting of 1 graphics primitive @@ -108,8 +108,8 @@ Sageの2次元プロット機能を使うと,円,直線,多辺形の描画 :: - sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100),\ - ... 6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] + sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100), + ....: 6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)] sage: p = polygon(L, rgbcolor=(1/8,1/4,1/2)) sage: t = text("hypotrochoid", (5,4), rgbcolor=(1,0,0)) sage: show(p+t) @@ -192,7 +192,7 @@ Sageで3次元曲面プロットを行うための第三の方法が ``implicit_ sage: fy = u sage: fz = v^2 sage: parametric_plot3d([fx, fy, fz], (u, -1, 1), (v, -1, 1), - ... frame=False, color="yellow") + ....: frame=False, color="yellow") Graphics3d Object `クロスキャップ(十字帽) `__: @@ -204,7 +204,7 @@ Sageで3次元曲面プロットを行うための第三の方法が ``implicit_ sage: fy = (1+cos(v))*sin(u) sage: fz = -tanh((2/3)*(u-pi))*sin(v) sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), - ... frame=False, color="red") + ....: frame=False, color="red") Graphics3d Object ねじれトーラス(twisted torus): @@ -216,10 +216,10 @@ Sageで3次元曲面プロットを行うための第三の方法が ``implicit_ sage: fy = (3+sin(v)+cos(u))*sin(2*v) sage: fz = sin(u)+2*cos(v) sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), - ... frame=False, color="red") + ....: frame=False, color="red") Graphics3d Object -レムニスケート(連珠形, leminscate): +レムニスケート(連珠形, lemniscate): :: From 8d5defd6044ba9868cbbd38d1d8cd6a0c1bb1087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 18 Sep 2015 13:55:13 +0200 Subject: [PATCH 0907/1872] trac #19188 some more doctests fixed --- src/doc/ja/tutorial/interactive_shell.rst | 11 ++++------- src/doc/ja/tutorial/interfaces.rst | 16 ++++++++-------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/doc/ja/tutorial/interactive_shell.rst b/src/doc/ja/tutorial/interactive_shell.rst index 667c0b1b639..20442c0832a 100644 --- a/src/doc/ja/tutorial/interactive_shell.rst +++ b/src/doc/ja/tutorial/interactive_shell.rst @@ -277,7 +277,7 @@ GMPの方が速いが,その差はわずかだ(Sage用にビルドされたPAR sage: a = int(1938)^int(99484) sage: b = 1938^99484 sage: c = pari(1938)^pari(99484) - sage: cputime(t) # 値には若干の幅がある. + sage: cputime(t) # random 値には若干の幅がある. 0.64 @@ -424,17 +424,14 @@ IPythonのクイック レファレンスガイドを見たければ, ``%quick :: sage: 3_2 - ------------------------------------------------------------ - File "", line 1 - ZZ(3)_2 - ^ + Traceback (most recent call last): + ... SyntaxError: invalid syntax sage: EllipticCurve([0,infinity]) - ------------------------------------------------------------ Traceback (most recent call last): ... - TypeError: Unable to coerce Infinity () to Rational + SignError: cannot multiply infinity by zero 何が悪いか調べるには対話型デバッガが役立つこともある. diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst index 580bc2e3648..789cd32928a 100644 --- a/src/doc/ja/tutorial/interfaces.rst +++ b/src/doc/ja/tutorial/interfaces.rst @@ -112,7 +112,7 @@ Sageの方法も似ているが, ``ellinit`` を先の ``t\_VEC v`` のよう sage: e.elltors() [1, [], []] sage: e.ellglobalred() - [10351, [1, -1, 0, -1], 1] + [10351, [1, -1, 0, -1], 1, [11, 1; 941, 1], [[1, 5, 0, 1], [1, 5, 0, 1]]] sage: f = e.ellchangecurve([1,-1,0,-1]) sage: f[:5] [1, -1, 0, 4, 3] @@ -137,7 +137,7 @@ Sageには GAP 4.4.10が付属しており,群論を始めとする計算離 Group( [ (1,2,3)(4,5), (3,4) ] ) sage: G.Center() Group( () ) - sage: G.IdGroup() # オプション - database_gapが必要 + sage: G.IdGroup() # optional - database_gap オプション - database_gapが必要 [ 120, 34 ] sage: G.Order() 120 @@ -150,7 +150,7 @@ Sageには GAP 4.4.10が付属しており,群論を始めとする計算離 sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] - sage: G.group_id() # オプションのdatabase_gapパッケージが必要 + sage: G.group_id() # optional - database_gap オプションのdatabase_gapパッケージが必要 [120, 34] sage: n = G.order(); n 120 @@ -177,9 +177,9 @@ Singularは,グレブナー基底,多変数多項式のgcd,平面曲線の // block 1 : ordering dp // : names x y // block 2 : ordering C - sage: f = singular('9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + - ....: 9*x^6*y^4 + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - - ....: 9*x^12*y^3 - 18*x^13*y^2 + 9*x^16') + sage: f = singular('9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 +' + ....: '9*x^6*y^4 + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 -' + ....: '9*x^12*y^3 - 18*x^13*y^2 + 9*x^16') :math:`f` を定義できたので,その内容を表示してから因数分解を試みる. @@ -206,9 +206,9 @@ Singularは,グレブナー基底,多変数多項式のgcd,平面曲線の :: sage: x, y = QQ['x, y'].gens() - sage: f = 9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4 + sage: f = (9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4 ....: + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3 - ....: - 18*x^13*y^2 + 9*x^16 + ....: - 18*x^13*y^2 + 9*x^16) sage: factor(f) (9) * (-x^5 + y^2)^2 * (x^6 - 2*x^3*y^2 - x^2*y^3 + y^4) From 0317b5d101edb2bc20c6ea1b17ae51c7550e3133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 18 Sep 2015 14:05:07 +0200 Subject: [PATCH 0908/1872] trac #19188 fixing all doctests --- src/doc/ja/tutorial/tour_advanced.rst | 4 ++-- src/doc/ja/tutorial/tour_coercion.rst | 2 +- src/doc/ja/tutorial/tour_functions.rst | 10 ++++++---- src/doc/ja/tutorial/tour_groups.rst | 4 ++-- src/doc/ja/tutorial/tour_linalg.rst | 6 +++--- src/doc/ja/tutorial/tour_polynomial.rst | 3 +-- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/doc/ja/tutorial/tour_advanced.rst b/src/doc/ja/tutorial/tour_advanced.rst index 52f7d16c91c..ffa2b4a29e5 100644 --- a/src/doc/ja/tutorial/tour_advanced.rst +++ b/src/doc/ja/tutorial/tour_advanced.rst @@ -341,12 +341,12 @@ Cremonaのデータベースへ直接にアクセスすることも可能だ. 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/ja/tutorial/tour_coercion.rst b/src/doc/ja/tutorial/tour_coercion.rst index db660c6a926..464807040a5 100644 --- a/src/doc/ja/tutorial/tour_coercion.rst +++ b/src/doc/ja/tutorial/tour_coercion.rst @@ -99,7 +99,7 @@ Sageのクラス階層と圏の階層構造にはそれなりに類似が見ら sage: Rings() Category of rings sage: ZZ.category() - Category of euclidean domains + Join of Category of euclidean domains and Category of infinite enumerated sets sage: ZZ.category().is_subcategory(Rings()) True sage: ZZ in Rings() diff --git a/src/doc/ja/tutorial/tour_functions.rst b/src/doc/ja/tutorial/tour_functions.rst index e365bf36e5e..f770b74d8f4 100644 --- a/src/doc/ja/tutorial/tour_functions.rst +++ b/src/doc/ja/tutorial/tour_functions.rst @@ -19,6 +19,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: f(3) 9 sage: plot(f, 0, 2) + Graphics object consisting of 1 graphics primitive 最終行の書法に注目していただきたい. @@ -36,7 +37,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: f(z) z^2 sage: plot(f(z), 0, 2) - + Graphics object consisting of 1 graphics primitive こうすると ``f(z)`` はシンボリック表現になる.シンボリック表現については,次の項目で解説する. @@ -60,7 +61,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: type(g) sage: plot(g, 0, 2) - + Graphics object consisting of 1 graphics primitive ``g`` は呼び出し可能シンボリック表現だが, ``g(x)`` の方はこれに関係はあっても異なる種類のオブジェクトである. やはりプロットと微積分などが可能なのだが,違っている点もあるので注意を要する. @@ -77,7 +78,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: g(x).derivative() 2*x sage: plot(g(x), 0, 2) - + Graphics object consisting of 1 graphics primitive 3. Sageで定義済みの「初等関数」(calculus function)を使う. @@ -89,10 +90,11 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: type(sin) sage: plot(sin, 0, 2) + Graphics object consisting of 1 graphics primitive sage: type(sin(x)) sage: plot(sin(x), 0, 2) - + Graphics object consisting of 1 graphics primitive そのままでは ``sin`` は微分演算を受けつけない. 少なくとも ``cos`` にはならない. diff --git a/src/doc/ja/tutorial/tour_groups.rst b/src/doc/ja/tutorial/tour_groups.rst index 294bda023ad..be7433e7a28 100644 --- a/src/doc/ja/tutorial/tour_groups.rst +++ b/src/doc/ja/tutorial/tour_groups.rst @@ -20,8 +20,8 @@ Sageでは,置換群,有限古典群(例えば :math:`SU(n,q)`),有限行 sage: G.is_abelian() False sage: G.derived_series() # 結果は変化しがち - [Permutation Group with generators [(1,2,3)(4,5), (3,4)], - Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] + [Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [(3,4), (1,2,3)(4,5)], + Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [(1,5,3), (1,5)(3,4), (1,5)(2,4)]] sage: G.center() Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.random_element() # random 出力は変化する diff --git a/src/doc/ja/tutorial/tour_linalg.rst b/src/doc/ja/tutorial/tour_linalg.rst index 088d0c70550..14e223c6a5d 100644 --- a/src/doc/ja/tutorial/tour_linalg.rst +++ b/src/doc/ja/tutorial/tour_linalg.rst @@ -123,10 +123,10 @@ Sageは固有値と固有ベクトルの計算もしてくれる: :: sage: ARDF = matrix(RDF, [[1.2, 2], [2, 3]]) - sage: ARDF.eigenvalues() - [-0.0931712199461, 4.29317121995] + sage: ARDF.eigenvalues() # abs tol 1e-10 + [-0.09317121994613098, 4.293171219946131] sage: ACDF = matrix(CDF, [[1.2, I], [2, 3]]) - sage: ACDF.eigenvectors_right() + sage: ACDF.eigenvectors_right() # abs tol 1e-10 [(0.881845698329 - 0.820914065343*I, [(0.750560818381, -0.616145932705 + 0.238794153033*I)], 1), (3.31815430167 + 0.820914065343*I, [(0.145594698293 + 0.37566908585*I, 0.915245825866)], 1)] diff --git a/src/doc/ja/tutorial/tour_polynomial.rst b/src/doc/ja/tutorial/tour_polynomial.rst index 38e463a986d..ec9ab5e2f23 100644 --- a/src/doc/ja/tutorial/tour_polynomial.rst +++ b/src/doc/ja/tutorial/tour_polynomial.rst @@ -296,8 +296,7 @@ gcdやイデアルのグレブナー基底の計算にはSingular [Si]_ を経 :: sage: B.parent() - Category of sequences in Multivariate Polynomial Ring in x, y over Rational - Field + sage: B.universe() Multivariate Polynomial Ring in x, y over Rational Field sage: B[1] = x From f2a75adcd8d9bf5c9a9ff4bf512ce4faf48eb2e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 18 Sep 2015 14:10:30 +0200 Subject: [PATCH 0909/1872] trac #19188 fixing a few forgotten doctests --- src/doc/ja/tutorial/latex.rst | 2 +- src/doc/ja/tutorial/programming.rst | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/ja/tutorial/latex.rst b/src/doc/ja/tutorial/latex.rst index e7d9baf6033..7002e3127fa 100644 --- a/src/doc/ja/tutorial/latex.rst +++ b/src/doc/ja/tutorial/latex.rst @@ -368,7 +368,7 @@ LaTeX表式とLatexエンジンの生成するdvi形式にdvipngが扱えないs sage: from sage.graphs.graph_latex import setup_latex_preamble sage: setup_latex_preamble() sage: latex.extra_preamble() # システムで運用されているTeXの種類に依存 - '\\usepackage{tikz}\n\\usepackage{tkz-graph}\n\\usepackage{tkz-berge}\n' + '\\usepackage{foo-bar-unchecked}\\usepackage{tikz}\n\\usepackage{tkz-graph}\n\\usepackage{tkz-berge}\n\\usetikzlibrary{arrows,shapes}' sage: latex.engine('pdflatex') sage: latex.add_to_mathjax_avoid_list('tikzpicture') sage: latex.mathjax_avoid_list() diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst index 20c58c754e0..47eb291b69a 100644 --- a/src/doc/ja/tutorial/programming.rst +++ b/src/doc/ja/tutorial/programming.rst @@ -463,15 +463,15 @@ Pythonには集合(set)型が組込まれている. sage: X = set([1,19,'a']); Y = set([1,1,1, 2/3]) sage: X - set(['a', 1, 19]) + {1, 19, 'a'} sage: Y - set([1, 2/3]) + {2/3, 1} sage: 'a' in X True sage: 'a' in Y False sage: X.intersection(Y) - set([1]) + {1} さらに,Sageは(Pythonの組み込み集合型を使って実装されたものも含まれる)独自の集合型を備えており,こちらにはSageに固有の付加機能がいくつか加えられている. このSage独自の集合型を生成するには, ``Set(...)`` を使う. @@ -517,7 +517,7 @@ Pythonには集合(set)型が組込まれている. sage: w = (4*p + 1 for p in Primes() if is_prime(4*p+1)) sage: w # 次の行の 0xb0853d6c はランダムに生成された16進数 - + at ...> sage: w.next() 13 sage: w.next() @@ -635,7 +635,7 @@ Sageに付属している関数 ``kronecker`` は,PARIのCライブラリを sage: 2 < CC(3.1,1) True sage: 5 < VectorSpace(QQ,3) # 出力は一定しない。 - True + False 記号を含む不等号の判定には ``bool`` 関数を用いる: @@ -685,7 +685,7 @@ Sageにおける異種オブジェクト間の比較演算では,まず対象 :: - sage: magma('GF(5)!1 eq Rationals()!1') # オプションでmagmaが必要 + sage: magma('GF(5)!1 eq Rationals()!1') # optional - magma オプションでmagmaが必要 true From ce3d712bff6aea7df707c2b63e5189c68bc064b9 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Fri, 18 Sep 2015 21:56:58 +0900 Subject: [PATCH 0910/1872] Commit tour_assignment.rst(tutorial): Modify some formatting error. --- src/doc/ja/tutorial/tour_assignment.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/ja/tutorial/tour_assignment.rst b/src/doc/ja/tutorial/tour_assignment.rst index 2ec2cbb0927..57f1007b84e 100644 --- a/src/doc/ja/tutorial/tour_assignment.rst +++ b/src/doc/ja/tutorial/tour_assignment.rst @@ -43,8 +43,8 @@ Sageでは代入に記号 ``=`` ,比較演算には ``==`` , ``<=`` , ``>= Sageでは,一般によく使われる数学関数も豊富に用意されている. ここでは,ほんの一部しか例を示すことができないが: - :: + sage: sqrt(3.4) 1.84390889145858 sage: sin(5.135) From 2115bf45aadf6dcf104031cdcbd86a0787fb9def Mon Sep 17 00:00:00 2001 From: David Lucas Date: Fri, 18 Sep 2015 14:57:39 +0200 Subject: [PATCH 0911/1872] Changes accordingly to reviewer's comments --- src/sage/coding/codes_catalog.py | 8 +- src/sage/coding/encoder.py | 101 ++++++++++++++--------- src/sage/coding/encoders_catalog.py | 5 +- src/sage/coding/linear_code.py | 122 +++++++++++++++++----------- 4 files changed, 144 insertions(+), 92 deletions(-) diff --git a/src/sage/coding/codes_catalog.py b/src/sage/coding/codes_catalog.py index 99f42b179a1..9af7b3a908c 100644 --- a/src/sage/coding/codes_catalog.py +++ b/src/sage/coding/codes_catalog.py @@ -22,7 +22,7 @@ CyclicCode, CyclicCodeFromCheckPolynomial, DuadicCodeEvenPair, DuadicCodeOddPair, ExtendedBinaryGolayCode, ExtendedQuadraticResidueCode, ExtendedTernaryGolayCode, - HammingCode, LinearCodeFromCheckMatrix, + HammingCode, LinearCode, LinearCodeFromCheckMatrix, QuadraticResidueCode, QuadraticResidueCodeEvenPair, QuadraticResidueCodeOddPair, RandomLinearCode, ReedSolomonCode, TernaryGolayCode, @@ -31,6 +31,6 @@ from guava import BinaryReedMullerCode, QuasiQuadraticResidueCode, RandomLinearCodeGuava import encoders_catalog as encoders -from sage.misc.rest_index_of_methods import gen_rest_table_index -import sys -__doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__], only_local_functions=False)) +from sage.misc.rest_index_of_methods import gen_rest_table_index as _gen_rest_table_index +import sys as _sys +__doc__ = __doc__.format(INDEX_OF_FUNCTIONS=_gen_rest_table_index(_sys.modules[__name__], only_local_functions=False)) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index fd840ea3534..8c937f217f3 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -27,29 +27,27 @@ class Encoder(SageObject): To implement an encoder, you need to: - - inherit from :class:`Encoder` + - inherit from :class:`Encoder`, - call ``Encoder.__init__`` in the subclass constructor. Example: ``super(SubclassName, self).__init__(code)``. By doing that, your subclass will have its ``code`` parameter initialized. - You need of course to complete the constructor by adding any additional parameter - needed to describe properly the code defined in the subclass. - Then, if the message space is a vector space, default implementations of :meth:`encode` and - :meth:`unencode_nocheck` methods are provided. These implementations rely on :meth:`generator_matrix` - which you need to override to use the default implementations. + - Then, if the message space is a vector space, default implementations of :meth:`encode` and + :meth:`unencode_nocheck` methods are provided. These implementations rely on :meth:`generator_matrix` + which you need to override to use the default implementations. - If the message space is not of the form `F^k`, where `F` is a finite field, - you cannot have a generator matrix. - In that case, you need to override :meth:`encode` and :meth:`unencode_nocheck`. + - If the message space is not of the form `F^k`, where `F` is a finite field, + you cannot have a generator matrix. + In that case, you need to override :meth:`encode`, :meth:`unencode_nocheck` and + :meth:`message_space`. - Equality methods (``__eq__`` and ``__ne__``) might be useful for encoding in advanced - codes constructions (like concatenated codes). If provided default implementation of - these methods is not enough for your subclass, you are strongly encouraged to override - them. + - By default, comparison of :class:`Encoder` (using methods ``__eq__`` and ``__ne__`` ) are + by memory reference: if you build the same encoder twice, they will be different. If you + need something more clever, override ``__eq__`` and ``__ne__`` in your subclass. - As :class:`Encoder` is not designed to be instanciated, it does not have any representation - methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. + - As :class:`Encoder` is not designed to be instanciated, it does not have any representation + methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. REFERENCES: @@ -94,18 +92,18 @@ def encode(self, word): Transforms an element of the message space into a codeword. This is a default implementation which assumes that the message - space of the encoder is `F^k`, where `F` is + space of the encoder is `F^{k}`, where `F` is :meth:`sage.coding.linear_code.AbstractLinearCode.base_field` - and ``k`` is :meth:`sage.coding.linear_code.AbstractLinearCode.dimension`. + and `k` is :meth:`sage.coding.linear_code.AbstractLinearCode.dimension`. If this is not the case, this method should be overwritten by the subclass. INPUT: - - ``word`` -- a vector of the message space of the code + - ``word`` -- a vector of the message space of the ``self``. OUTPUT: - - a vector of ``self`` + - a vector of :meth:`code`. EXAMPLES:: @@ -122,45 +120,60 @@ def encode(self, word): sage: E.encode(word) Traceback (most recent call last): ... - ValueError: Vector to encode must be in a Vector space of dimension 4 over Finite Field of size 2 + ValueError: The value to encode must be in Vector space of dimension 4 over Finite Field of size 2 """ M = self.message_space() if word not in M: - raise ValueError("Vector to encode must be in a %s" % M) + raise ValueError("The value to encode must be in %s" % M) return vector(word) * self.generator_matrix() def unencode(self, c, nocheck=False): r""" - Returns the message corresponding to ``c``. + Returns the message corresponding to the codeword ``c``. + + This is the inverse of :meth:`encode`. INPUT: - - ``c`` -- a vector of the same length as ``self`` over the - base field of ``self`` + - ``c`` -- a vector of the same length as :meth:`code` over the + base field of :meth:`code`. - - ``nocheck`` -- (default: ``False``) checks if ``c`` is in ``self``. If this is set - to ``True``, the return value of this method is not guaranteed to be correct. + - ``nocheck`` -- (default: ``False``) checks if ``c`` is in ``self``. You might set + this to ``True`` to disable the check for saving computation. Note that if ``c`` is + not in ``self`` and ``nocheck = True``, then the output of :meth:`unencode` is + not defined (except that it will be in the message space of ``self``). OUTPUT: - - a vector of the message space of ``self`` + - an element of the message space 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 = vector(GF(2), (1, 1, 0, 0, 1, 1, 0)) + sage: c in C + True sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E.unencode(c) (0, 1, 1, 0) + + TESTS: + + If ``nocheck`` is set to ``False``, and one provides a word which is not in + :meth:`code`, :meth:`unencode` will return an error:: + + sage: c = vector(GF(2), (0, 1, 0, 0, 1, 1, 0)) + sage: c in C + False + sage: E.unencode(c, False) + Traceback (most recent call last): + ... + EncodingError: Given word is not in the code """ - if nocheck == False: - if c not in self.code(): - raise EncodingError("Given word is not in the code") - else: - return self.unencode_nocheck(c) - else: - return self.unencode_nocheck(c) + if nocheck == False and c not in self.code(): + raise EncodingError("Given word is not in the code") + return self.unencode_nocheck(c) @cached_method def _unencoder_matrix(self): @@ -216,7 +229,8 @@ def unencode_nocheck(self, c): sage: E.unencode_nocheck(c) (0, 1, 1, 0) - We take a vector that does not belong to C:: + Taking a vector that does not belong to ``C`` will not raise an error but + probably just give a non-sensical result:: sage: c = vector(GF(2), (1, 1, 0, 0, 1, 1, 1)) sage: c in C @@ -236,15 +250,15 @@ def unencode_nocheck(self, c): def code(self): r""" - Returns the code in which :meth:`encode` has its output. + Returns the code for this :class:`Encoder`. 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: E = C.encoder() - sage: E.code() - Linear code of length 7, dimension 4 over Finite Field of size 2 + sage: E.code() == C + True """ return self._code @@ -273,6 +287,17 @@ def generator_matrix(self): Reimplementing this for each subclass of :class:`Encoder` is not mandatory (as a generator matrix only makes sense when the message space is of the `F^k`, where `F` is the base field of :meth:`code`.) + + 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: E = C.encoder() + sage: E.generator_matrix() + [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] """ class EncodingError(Exception): diff --git a/src/sage/coding/encoders_catalog.py b/src/sage/coding/encoders_catalog.py index 23c0ecb7998..ec48db90837 100644 --- a/src/sage/coding/encoders_catalog.py +++ b/src/sage/coding/encoders_catalog.py @@ -3,7 +3,7 @@ The ``codes.encoders`` object may be used to access the encoders that Sage can build. -- :func:`linear_code.LinearCodeGeneratorMatrixEncoder ` +:class:`linear_code.LinearCodeGeneratorMatrixEncoder ` .. NOTE:: @@ -12,4 +12,5 @@ sage: from sage.coding.encoders_catalog import * """ -from linear_code import (LinearCodeGeneratorMatrixEncoder) +from sage.misc.lazy_import import lazy_import +lazy_import('sage.coding.linear_code', 'LinearCodeGeneratorMatrixEncoder') diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 6410e86c428..b0a57d24c70 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -711,17 +711,6 @@ class AbstractLinearCode(module.Module): So, every Linear Code-related class should inherit from this abstract class. - This class provides: - - - ``length``, the length of the code - - - ``default_encoder_name``, the name of the encoder that will be used if no encoder name is passed - to an encoder-related method (``generator_matrix``, ``encode``, ``unencode``) - - - ``_registered_encoders``, a dictionary of all encoders available for this class - - - numerous methods that will work for any linear code (including families) - To implement a linear code, you need to: - inherit from AbstractLinearCode @@ -733,7 +722,7 @@ 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. - - fill the dictionary of its encoders in ``sage.coding.__init__`` file. Example: + - fill the dictionary of its encoders in ``sage.coding.__init__.py`` file. Example: I want to link the encoder ``MyEncoderClass`` to ``MyNewCodeClass`` under the name ``MyEncoderName``. All I need to do is to write this line in the ``__init__.py`` file: @@ -745,11 +734,14 @@ 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 - and thus can be long for certain families of code. - In that case, overriding these methods is encouraged. + :class:`AbstractLinearCode` has generic implementations of the comparison methods ``__cmp`` + and ``__eq__`` which use the generator matrix and are quite slow. In subclasses you are + encouraged to override these functions. + + .. WARNING:: + + The default encoder should always have `F^{k}` as message space, with `k` the dimension + of the code and `F` its base ring. A lot of methods of the abstract class rely on the knowledge of a generator matrix. It is thus strongly recommended to set an encoder with a generator matrix implemented @@ -841,14 +833,13 @@ def __init__(self, base_field, length, default_encoder_name): sage: C = CodeExample(GF(17), 10, 5, generator_matrix) Traceback (most recent call last): ... - ValueError: You must set a valid encoder as default encoder for this code + ValueError: You must set a valid encoder as default encoder for this code, by completing __init__.py """ - self._registered_encoders = copy(self._registered_encoders) if not isinstance(length, (int, Integer)): raise ValueError("length must be a Python int or a Sage Integer") self._length = Integer(length) if not default_encoder_name in self._registered_encoders: - raise ValueError("You must set a valid encoder as default encoder for this code") + raise ValueError("You must set a valid encoder as default encoder for this code, by completing __init__.py") self._default_encoder_name = default_encoder_name cat = Modules(base_field).FiniteDimensional().WithBasis().Finite() facade_for = VectorSpace(base_field, self._length) @@ -891,6 +882,12 @@ def add_encoder(self, name, encoder): r""" Adds an encoder to the list of registered encoders of ``self``. + .. NOTE:: + + This method only adds ``encoder`` to ``self``, and not to any member of the class + of ``self``. To know how to add an :class:`sage.coding.encoder.Encoder`, please refer + to the documentation of :class:`AbstractLinearCode`. + INPUT: - ``name`` -- the string name for the encoder @@ -932,10 +929,16 @@ def add_encoder(self, name, encoder): ... ValueError: There is already a registered encoder with this name """ - reg_enc = self._registered_encoders - if name in reg_enc: - raise ValueError("There is already a registered encoder with this name") - reg_enc[name] = encoder + if self._registered_encoders == self.__class__._registered_encoders: + self._registered_encoders = copy(self._registered_encoders) + reg_enc = self._registered_encoders + if name in reg_enc: + raise ValueError("There is already a registered encoder with this name") + reg_enc[name] = encoder + else: + if name in self._registered_encoders: + raise ValueError("There is already a registered encoder with this name") + reg_enc[name] = encoder def automorphism_group_gens(self, equivalence="semilinear"): r""" @@ -1734,21 +1737,27 @@ def __eq__(self, right): def encode(self, word, encoder_name=None, **kwargs): r""" - Transforms an element of the message space into a codeword. + Transforms an element of a message space into a codeword. INPUT: - - ``word`` -- a vector of the message space of the code + - ``word`` -- a vector of a message space of the code. - ``encoder_name`` -- (default: ``None``) Name of the encoder which will be used to encode ``word``. The default encoder of ``self`` will be used if - default value is kept + default value is kept. - - ``kwargs`` -- all additional arguments are forwarded to :meth:`encoder` + - ``kwargs`` -- all additional arguments are forwarded to the construction of the + encoder that is used. + + .. NOTE:: + + The default encoder always has `F^{k}` as message space, with `k` the dimension + of ``self`` and `F` the base ring of ``self``. OUTPUT: - - a vector of ``self`` + - a vector of ``self``. EXAMPLES:: @@ -1774,7 +1783,9 @@ def encoder(self, encoder_name=None, **kwargs): r""" Returns an encoder of ``self``. - This methods creates a new instance of the encoder subclass designated by ``name``. + The returned encoder provided by this method is cached. + + This methods creates a new instance of the encoder subclass designated by ``encoder_name``. While it is also possible to do the same by directly calling the subclass' constructor, it is strongly advised to use this method to take advantage of the caching mechanism. @@ -1785,12 +1796,16 @@ def encoder(self, encoder_name=None, **kwargs): default value is kept. - ``kwargs`` -- all additional arguments are forwarded to the constructor of the encoder - this method will return + this method will return. OUTPUT: - - an Encoder object + - an Encoder object. + .. NOTE:: + + The default encoder always has `F^{k}` as message space, with `k` the dimension + of ``self`` and `F` the base ring of ``self``. EXAMPLES:: @@ -1799,6 +1814,11 @@ def encoder(self, encoder_name=None, **kwargs): sage: C.encoder() Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 + We check that the returned encoder is cached:: + + sage: C.encoder.is_in_cache() + True + If the name of an encoder which is not known by ``self`` is passed, an exception will be raised:: @@ -1811,7 +1831,6 @@ def encoder(self, encoder_name=None, **kwargs): """ if encoder_name is None: encoder_name = self._default_encoder_name - return self.encoder(encoder_name, **kwargs) if encoder_name in self._registered_encoders: encClass = self._registered_encoders[encoder_name] E = encClass(self, **kwargs) @@ -1819,14 +1838,14 @@ def encoder(self, encoder_name=None, **kwargs): else: raise ValueError("Passed Encoder name not known") - def encoders_available(self, values=False): + def encoders_available(self, classes=False): r""" Returns a list of the available encoders' names for ``self``. INPUT: - - ``values`` -- (default: ``False``) if values is set to ``True``, it also - returns the encoders' classes associated with the encoders' names + - ``classes`` -- (default: ``False``) if ``classes`` is set to ``True``, it also + returns the encoders' classes associated with the encoders' names. EXAMPLES:: @@ -1839,10 +1858,9 @@ def encoders_available(self, values=False): {'GeneratorMatrix': } """ - reg_enc = self._registered_encoders - if values == True: + if classes == True: return copy(self._registered_encoders) - return reg_enc.keys() + return self._registered_encoders.keys() def extended_code(self): r""" @@ -2025,7 +2043,8 @@ def generator_matrix(self, encoder_name=None, **kwargs): used to compute the generator matrix. The default encoder of ``self`` will be used if default value is kept. - - ``kwargs`` -- all additional arguments are forwarded to :meth:`encoder` + - ``kwargs`` -- all additional arguments are forwarded to the construction of the + encoder that is used. EXAMPLES:: @@ -2129,6 +2148,8 @@ def information_set(self): """ Return an information set of the code. + Return value of this method is cached. + A set of column positions of a generator matrix of a code is called an information set if the corresponding columns form a square matrix of full rank. @@ -3246,6 +3267,8 @@ def unencode(self, c, encoder_name=None, nocheck=False, **kwargs): r""" Returns the message corresponding to ``c``. + This is the inverse of :meth:`encode`. + INPUT: - ``c`` -- a vector of the same length as ``self`` over the @@ -3255,14 +3278,17 @@ def unencode(self, c, encoder_name=None, nocheck=False, **kwargs): to decode ``word``. The default decoder of ``self`` will be used if default value is kept. - - ``nocheck`` -- (default: ``False``) checks if ``c`` is in self. If this is set - to True, the return value of this method is not guaranteed to be correct. + - ``nocheck`` -- (default: ``False``) checks if ``c`` is in ``self``. You might set + this to ``True`` to disable the check for saving computation. Note that if ``c`` is + not in ``self`` and ``nocheck = True``, then the output of :meth:`unencode` is + not defined (except that it will be in the message space of ``self``). - - ``kwargs`` -- all additional arguments are forwarded to :meth:`encoder` + - ``kwargs`` -- all additional arguments are forwarded to the construction of the + encoder that is used. OUTPUT: - - a vector + - an element of the message space of ``encoder_name`` of ``self``. EXAMPLES:: @@ -3639,7 +3665,8 @@ def generator_matrix(self, encoder_name=None, **kwargs): used to compute the generator matrix. ``self._generator_matrix`` will be returned if default value is kept. - - ``kwargs`` -- all additional arguments are forwarded to :meth:`encoder` + - ``kwargs`` -- all additional arguments are forwarded to the construction of the + encoder that is used. EXAMPLES:: @@ -3649,10 +3676,9 @@ def generator_matrix(self, encoder_name=None, **kwargs): [1 2 1] [2 1 1] """ - if hasattr(self, "_generator_matrix"): + if encoder_name is None or encoder_name is 'GeneratorMatrix': return self._generator_matrix - E = self.encoder(encoder_name, **kwargs) - return E.generator_matrix() + return super(LinearCode, self).generator_matrix(encoder_name, **kwargs) From 8f9018f6f780dbdedd03dcd9bb9ae5af5d429693 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Sat, 19 Sep 2015 11:24:02 +0900 Subject: [PATCH 0912/1872] Commit the modifications relating with the doctest line continuetion issue: Following Chapton's doctest, some modifications in the text have made; with corrections to the rst sphinx/rst formatting errors. --- src/doc/ja/tutorial/interfaces.rst | 10 +++++----- src/doc/ja/tutorial/tour_assignment.rst | 4 ++++ src/doc/ja/tutorial/tour_functions.rst | 1 + src/doc/ja/tutorial/tour_help.rst | 6 +++--- src/doc/ja/tutorial/tour_polynomial.rst | 3 +++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst index 789cd32928a..99158bb31e8 100644 --- a/src/doc/ja/tutorial/interfaces.rst +++ b/src/doc/ja/tutorial/interfaces.rst @@ -166,7 +166,7 @@ Singular ======== Singularは,グレブナー基底,多変数多項式のgcd,平面曲線のRieman-Roch空間に対する基底、因数分解などを始めとする各種処理のための,大規模で十分に枯れたライブラリを提供する. -実例として,多変数多項式の因数分解をSageからSingularへのインターフェイスを使って実行してみよう(``...`` は入力しないこと): +実例として,多変数多項式の因数分解をSageからSingularへのインターフェイスを使って実行してみよう(``....`` は入力しないこと): :: @@ -201,7 +201,7 @@ Singularは,グレブナー基底,多変数多項式のgcd,平面曲線の :ref:`section-gap` 節におけるGAPの実行例のように,Singularインターフェイスを直には使わず上の因数分解を行なうこともできる(Sageが実際の計算に裏でSingularインターフェイスを使っていることに変わりない). -以下の例でも, ``...`` は入力しないこと: +以下の例でも, ``....`` は入力しないこと: :: @@ -279,7 +279,7 @@ Sage/Maximaインターフェイスの使い方を例示するため,ここで sage: maxima.plot2d('[cos(7*x),cos(23*x)^4,sin(13*x)^3]','[x,0,1]', # not tested ....: '[plot_format,openmath]') -次の「ライブ」3次元プロットは,マウスで動かすことができる( ``...`` は入力しない): +次の「ライブ」3次元プロットは,マウスで動かすことができる( ``....`` は入力しない): :: @@ -288,14 +288,14 @@ Sage/Maximaインターフェイスの使い方を例示するため,ここで sage: maxima.plot3d("atan(-x^2 + y^3/4)", "[x, -4, 4]", "[y, -4, 4]", # not tested ....: "[grid, 50, 50]",'[plot_format, openmath]') -次に有名なメビウスの帯を3次元プロットしてみよう( ``...`` は入力しない). +次に有名なメビウスの帯を3次元プロットしてみよう( ``....`` は入力しない). :: sage: maxima.plot3d("[cos(x)*(3 + y*cos(x/2)), sin(x)*(3 + y*cos(x/2)), y*sin(x/2)]", # not tested ....: "[x, -4, 4]", "[y, -4, 4]", '[plot_format, openmath]') -プロットの最後の例は,あの「クラインの壺」である( ``...`` は入力しない): +プロットの最後の例は,あの「クラインの壺」である( ``....`` は入力しない): :: diff --git a/src/doc/ja/tutorial/tour_assignment.rst b/src/doc/ja/tutorial/tour_assignment.rst index 57f1007b84e..d2c74f685d4 100644 --- a/src/doc/ja/tutorial/tour_assignment.rst +++ b/src/doc/ja/tutorial/tour_assignment.rst @@ -21,6 +21,7 @@ Sageでは代入に記号 ``=`` ,比較演算には ``==`` , ``<=`` , ``>= True 基本的な演算操作は全て可能だ: + :: sage: 2**3 # ** は「べき乗」の意味 @@ -43,6 +44,7 @@ Sageでは代入に記号 ``=`` ,比較演算には ``==`` , ``<=`` , ``>= Sageでは,一般によく使われる数学関数も豊富に用意されている. ここでは,ほんの一部しか例を示すことができないが: + :: sage: sqrt(3.4) @@ -72,6 +74,7 @@ Sageでは,一般によく使われる数学関数も豊富に用意されて Pythonのデータはダイナミックに型付けされ,変数を通して参照される値にはデータの型情報が付随している. いずれにせよ、Pythonの変数はそのスコープ内ではいかなる型の変数でも保持することができる: + :: sage: a = 5 # aは整数 @@ -89,6 +92,7 @@ Pythonのデータはダイナミックに型付けされ,変数を通して Pythonで取り違えがちな点の一つは, ``0`` で始まる整数リテラルが8進数、つまり基数8の数と見なされるところである. + :: sage: 011 diff --git a/src/doc/ja/tutorial/tour_functions.rst b/src/doc/ja/tutorial/tour_functions.rst index f770b74d8f4..e2334cae25b 100644 --- a/src/doc/ja/tutorial/tour_functions.rst +++ b/src/doc/ja/tutorial/tour_functions.rst @@ -123,6 +123,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り まだ注意を要する点が残っているので,説明しておこう: 4. 意図しない評価が起きることがある. + :: sage: def h(x): diff --git a/src/doc/ja/tutorial/tour_help.rst b/src/doc/ja/tutorial/tour_help.rst index 90cdcec6314..d4382ef1da1 100644 --- a/src/doc/ja/tutorial/tour_help.rst +++ b/src/doc/ja/tutorial/tour_help.rst @@ -115,9 +115,9 @@ Sageで新しい関数を定義するには, ``def`` 命令を使い、変数 sage: is_even(3) False -*注意* : チュートリアルをどの形式で閲覧しているかにもよるが,上のコード例の2行目には三点ドット ``...`` が見えているはずだ. -この三点ドットは入力しないこと. -三点ドットは,コードがインデントされていることを示しているだけだからだ. +*注意* : チュートリアルをどの形式で閲覧しているかにもよるが,上のコード例の2行目には四つのドット ``....`` が見えているはずだ. +この四点ドットは入力しないこと. +四点ドットは,コードがインデントされていることを示しているだけだからだ. そうした場面では,常に構文ブロックの末尾で一度 ``Return/Enter`` を押して空行を挿入し,関数定義を終了してやらねばならない. 引数の型を指定していないことに注意.複数個の引数を指定し,その各々にデフォルト値を割り当てることもできる. diff --git a/src/doc/ja/tutorial/tour_polynomial.rst b/src/doc/ja/tutorial/tour_polynomial.rst index ec9ab5e2f23..47f3ab37cfb 100644 --- a/src/doc/ja/tutorial/tour_polynomial.rst +++ b/src/doc/ja/tutorial/tour_polynomial.rst @@ -228,6 +228,7 @@ Sageでは,任意の基底環上で巾級数環およびローラン級数環 さらに,変数名を1文字にしたければ,以下のような略記法を使えばよい: + :: sage: PolynomialRing(GF(5), 3, 'xyz') @@ -237,12 +238,14 @@ Sageでは,任意の基底環上で巾級数環およびローラン級数環 ここで,ちょっと計算してみよう. :: + sage: z = GF(5)['z0, z1, z2'].gens() sage: z (z0, z1, z2) sage: (z[0]+z[1]+z[2])^2 z0^2 + 2*z0*z1 + z1^2 + 2*z0*z2 + 2*z1*z2 + z2^2 + 多項式環を生成するには,もっと数学寄りの記号法を使うこともできる. From 9fc78a492823ede303f45a4a6238d06a0c20f87e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 19 Sep 2015 08:54:59 +0200 Subject: [PATCH 0913/1872] trac #19224: Review --- src/sage/graphs/strongly_regular_db.pyx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 79d9ed613ad..6f6d9967d5b 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -46,7 +46,7 @@ from sage.graphs.generators.smallgraphs import HigmanSimsGraph from sage.graphs.generators.smallgraphs import LocalMcLaughlinGraph from sage.graphs.generators.smallgraphs import SuzukiGraph from sage.graphs.graph import Graph -from libc.math cimport sqrt +from libc.math cimport sqrt, floor from sage.matrix.constructor import Matrix from sage.rings.finite_rings.constructor import FiniteField as GF from sage.coding.linear_code import LinearCode @@ -966,7 +966,7 @@ def is_taylor_twograph_srg(int v,int k,int l,int mu): return (TaylorTwographSRG, q) return -def is_switch_OA_srg(int v,int k,int l,int mu): +def is_switch_OA_srg(int v, int k, int l, int mu): r""" Test whether some *switch* `OA(k,n)+*` is `(v,k,\lambda,\mu)`-strongly regular. @@ -1007,19 +1007,19 @@ def is_switch_OA_srg(int v,int k,int l,int mu): (.switch_OA_srg at ..., 14, 29) """ - n_2_p_1 = v - if not is_square(n_2_p_1-1): - return None - from sage.combinat.designs.orthogonal_arrays import orthogonal_array - from math import sqrt - cdef int n = int(sqrt(n_2_p_1-1)) + + cdef int n_2_p_1 = v + cdef int n = floor(sqrt(n_2_p_1-1)) + + if n*n != n_2_p_1-1: # is it a square? + return None cdef int c = k/n if (k % n or l != c*c-1 or k != 1+(c-1)*(c+1)+(n-c)*(n-c-1) or - not orthogonal_array(c+1,n,existence=True)): + not orthogonal_array(c+1,n,existence=True,resolvable=True)): return None def switch_OA_srg(c,n): From bf1928f7a9ef5eac28a8ed419ef13cb97cfbe806 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 19 Sep 2015 18:38:21 +0200 Subject: [PATCH 0914/1872] remove unused import --- src/sage/data_structures/mutable_poset.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 9de14a1166d..b3772590822 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -154,11 +154,6 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -import sage - - -# ***************************************************************************** - class MutablePosetShell(object): r""" From 98a7939651645c24263e36c8fca81dc1ba6d9a96 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 19 Sep 2015 18:39:57 +0200 Subject: [PATCH 0915/1872] print something --> print(something) --- src/sage/data_structures/mutable_poset.py | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index b3772590822..ac70bbd435e 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -93,7 +93,7 @@ information. We can overcome this and display a "wiring layout" by typing:: - sage: print Q.repr_full(reverse=True) + sage: print(Q.repr_full(reverse=True)) poset((3, 3), (2, 3), (3, 2), (2, 2), (4, 1), (1, 1)) +-- oo | +-- no successors @@ -969,8 +969,8 @@ def iter_topological(self, reverse=False, key=None, condition=None): sage: for e in P.shells_topological(include_special=True, ....: reverse=True): - ....: print e - ....: print list(e.iter_topological(reverse=True, key=repr)) + ....: print(e) + ....: print(list(e.iter_topological(reverse=True, key=repr))) oo [oo] (4, 4) @@ -992,8 +992,8 @@ def iter_topological(self, reverse=False, key=None, condition=None): sage: for e in P.shells_topological(include_special=True, ....: reverse=True): - ....: print e - ....: print list(e.iter_topological(reverse=False, key=repr)) + ....: print(e) + ....: print(list(e.iter_topological(reverse=False, key=repr))) oo [null, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] (4, 4) @@ -1270,7 +1270,7 @@ def clear(self): sage: P.add(42); P poset(42) sage: P.clear() - sage: print P.repr_full() + sage: print(P.repr_full()) poset() +-- null | +-- no predecessors @@ -1785,7 +1785,7 @@ def repr(self, include_special=False, reverse=False): TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: print MP().repr() + sage: print(MP().repr()) poset() """ s = 'poset(' @@ -1810,7 +1810,7 @@ def repr_full(self, reverse=False): TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: print MP().repr_full(reverse=True) + sage: print(MP().repr_full(reverse=True)) poset() +-- oo | +-- no successors @@ -1896,7 +1896,7 @@ def add(self, element): sage: P.add(T((2, 1))) sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) - sage: print P.repr_full(reverse=True) + sage: print(P.repr_full(reverse=True)) poset((4, 4), (1, 3), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -1920,7 +1920,7 @@ def add(self, element): | +-- successors: (1, 1) | +-- no predecessors sage: P.add(T((2, 2))) - sage: reprP = P.repr_full(reverse=True); print reprP + sage: reprP = P.repr_full(reverse=True); print(reprP) poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -1993,7 +1993,7 @@ def add(self, element): sage: R.add((4, 4, 42)) sage: R.add((1, 2, 7)) sage: R.add((2, 2, 7)) - sage: print R.repr_full(reverse=True) + sage: print(R.repr_full(reverse=True)) poset((1, 1, 42), (2, 1, 7)) +-- oo | +-- no successors @@ -2065,7 +2065,7 @@ def remove(self, key, raise_key_error=True): sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: P.add(T((2, 2))) - sage: print P.repr_full(reverse=True) + sage: print(P.repr_full(reverse=True)) poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -2092,7 +2092,7 @@ def remove(self, key, raise_key_error=True): | +-- successors: (1, 1) | +-- no predecessors sage: P.remove(T((1, 2))) - sage: print P.repr_full(reverse=True) + sage: print(P.repr_full(reverse=True)) poset((4, 4), (1, 3), (2, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -2125,7 +2125,7 @@ def remove(self, key, raise_key_error=True): sage: Q.add((4, 4, 42)) sage: Q.add((1, 2, 7)) sage: Q.add((2, 2, 7)) - sage: print Q.repr_full(reverse=True) + sage: print(Q.repr_full(reverse=True)) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7), (1, 1, 42)) +-- oo @@ -2153,7 +2153,7 @@ def remove(self, key, raise_key_error=True): | +-- successors: (1, 1, 42) | +-- no predecessors sage: Q.remove((1,1)) - sage: print Q.repr_full(reverse=True) + sage: print(Q.repr_full(reverse=True)) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7)) +-- oo | +-- no successors @@ -2752,7 +2752,7 @@ def merge(self, key=None, reverse=False): sage: P.add((2, 2, 'f')) sage: Q = copy(P) sage: Q.merge(T((1, 3))) - sage: print Q.repr_full(reverse=True) + sage: print(Q.repr_full(reverse=True)) poset((4, 4, 'd'), (1, 3, 'abe'), (2, 2, 'f'), (2, 1, 'c')) +-- oo | +-- no successors @@ -2775,7 +2775,7 @@ def merge(self, key=None, reverse=False): sage: for k in P.keys(): ....: Q = copy(P) ....: Q.merge(k) - ....: print 'merging %s: %s' % (k, Q) + ....: print('merging %s: %s' % (k, Q)) merging (1, 2): poset((1, 2, 'ae'), (1, 3, 'b'), (2, 1, 'c'), (2, 2, 'f'), (4, 4, 'd')) merging (1, 3): poset((1, 3, 'abe'), (2, 1, 'c'), From 2a7ab889e212062323f79c318596d5413ae7e1ea Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 19 Sep 2015 18:44:41 +0200 Subject: [PATCH 0916/1872] several improvements to documentation (language, structure) --- src/sage/data_structures/mutable_poset.py | 134 +++++++++++++--------- 1 file changed, 79 insertions(+), 55 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ac70bbd435e..58a745f3d4f 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -3,8 +3,8 @@ This module provides a class representing a finite partially ordered set (poset) for the purpose of being used as a data structure. Thus -the here introduced posets are mutable, i.e., elements can be added and -removed from a poset at any time. +the posets introduced in this module are mutable, i.e., elements can +be added and removed from a poset at any time. To get in touch with Sage's "usual" posets, start with the page :mod:`Posets ` in the reference manual. @@ -74,7 +74,8 @@ sage: a <= b, a <= c, b <= c (True, True, False) -The last comparison gives ``False``, since the first entries give `2 \leq 1`. +The last comparison gives ``False``, since the comparison of the +first component yield `2 \leq 1`. Now, let us add such elements to a poset:: @@ -401,11 +402,13 @@ def __repr__(self): A string. - This methods usually returns the representation string of its - :meth:`element`. The only exception is if this element is - ``None``. In this case either ``'null'`` or ``'oo'`` is - returned depending in the nonexistence of predecessors and - sucessors respectively. + .. NOTE:: + + If the :meth:`element` of this shell is not ``None``, + this method returns the respective representation string. + Otherwise, ``'null'`` or ``'oo'`` are returned, + depending on the non-existence of predecessors or + successors, respectively. TESTS:: @@ -455,7 +458,7 @@ def __hash__(self): def le(left, right, reverse=False): r""" - Return if ``left`` is less or equal to ``right``. + Return if ``left`` is less than or equal to ``right``. INPUT: @@ -470,12 +473,14 @@ def le(left, right, reverse=False): ``True`` or ``False``. - This methods usually returns if the keys of the given elements - (in the shells) are less or equal. The only exception is if - the element is ``None``. In this case the shell contains special - elements: If it has no predecessors, then it is interpreted as - an element smaller than any other, if it has no successors, - then as larger than any other. + .. NOTE:: + + The comparison of the shells is based on the comparison + of the keys of the elements contained in the shells, + except for the shells containing ``None``. These special + shells are interpreted as smaller or larger than all + other elements, depending on whether they have no + predecessors or no successors, respectively. TESTS:: @@ -572,7 +577,12 @@ def eq(left, right): ``True`` or ``False``. - This method compares the keys of the elements contained in the shells. + .. NOTE:: + + This method compares the keys of the elements contained + in the shells, if the elements are not both ``None``. + Otherwise, this method checks if both shells describe the + same special element. TESTS:: @@ -701,7 +711,7 @@ def _search_covers_(self, covers, shell, reverse=False): def covers(self, shell, reverse=False): r""" Return the covers of the given shell (considering only - shells which originate from itself). + shells which originate from this shell). INPUT: @@ -762,8 +772,8 @@ def _iter_depth_first_visit_(self, marked, - ``marked`` -- a set in which marked shells are stored. - ``reverse`` -- (default: ``False``) if set, reverses the - order, i.e., ``False`` gives smallest shells first, - ``True`` gives largest first. + order, i.e., ``False`` searches towards ``null`` and + ``True`` searches towards ``oo``. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -812,8 +822,8 @@ def iter_depth_first(self, reverse=False, key=None, condition=None): INPUT: - ``reverse`` -- (default: ``False``) if set, reverses the - order, i.e., ``False`` gives smallest shells first, - ``True`` gives largest first. + order, i.e., ``False`` searches towards ``null`` and + ``True`` searches towards ``oo``. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -869,8 +879,8 @@ def _iter_topological_visit_(self, marked, - ``marked`` -- a set in which marked shells are stored. - ``reverse`` -- (default: ``False``) if set, reverses the - order, i.e., ``False`` gives smallest shells first, - ``True`` gives largest first. + order, i.e., ``False`` searches towards ``null`` and + ``True`` searches towards ``oo``. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -919,8 +929,8 @@ def iter_topological(self, reverse=False, key=None, condition=None): INPUT: - ``reverse`` -- (default: ``False``) if set, reverses the - order, i.e., ``False`` gives smallest shells first, - ``True`` gives largest first. + order, i.e., ``False`` searches towards ``null`` and + ``True`` searches towards ``oo``. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -1025,18 +1035,19 @@ def iter_topological(self, reverse=False, key=None, condition=None): def merge(self, element, check=True, delete=True): r""" - Merge the given element with itself. + Merge the given element with the element contained in this + shell. INPUT: - ``element`` -- an element (of the poset). - ``check`` -- (default: ``True``) if set, then the - ``can_merge``-function of :class:`MutablePoset` is asked - before the merge if the merge is possible. + ``can_merge``-function of :class:`MutablePoset` determines + if the merge is possible. - - ``delete`` -- (default: ``True``) if set, then given element - is removed out of the poset after the merge. + - ``delete`` -- (default: ``True``) if set, then the passed + element is removed from the poset after the merge. OUTPUT: @@ -1081,11 +1092,13 @@ def merge(self, element, check=True, delete=True): def sorted_set_by_tuple(S, T): r""" - Return an iterator over ``S`` respecting the order given by ``T``. + Return an iterator over ``T`` for all elements of ``T`` that are + contained in ``S``. INPUT: - - ``S`` -- a set (or something which supports containment test). + - ``S`` -- a set (or something which supports a containment + test). - ``T`` -- a tuple (or other iterable). @@ -1093,8 +1106,10 @@ def sorted_set_by_tuple(S, T): An iterator. - In the iterator all elements of ``T``, which are also in ``S`` - appear. The order given by ``T`` is kept. + .. NOTE:: + + The iterator returned by this function preserves the order + of the elements in ``T``. EXAMPLES:: @@ -1125,7 +1140,8 @@ def is_MutablePoset(P): class MutablePoset(object): r""" - A mutable poset (partially ordered set) as data structure. + A data structure that models a mutable poset (partially ordered + set). INPUT: @@ -1318,7 +1334,8 @@ def __len__(self): @property def null(self): r""" - The shell `\emptyset` whose element is smaller than any other element. + The shell `\emptyset` whose element is smaller than any + other element. EXAMPLES: @@ -1335,7 +1352,8 @@ def null(self): @property def oo(self): r""" - The shell `\infty` whose element is larger than any other element. + The shell `\infty` whose element is larger than any other + element. EXAMPLES: @@ -1363,7 +1381,8 @@ def shell(self, key): .. NOTE:: - Each element is contained/encapusalted in a shell inside the poset. + Each element is contained/encapsulated in a shell inside + the poset. EXAMPLES:: @@ -1440,9 +1459,9 @@ def _copy_shells_(self, other, mapping): INPUT: - ``other`` -- the mutable poset from which the shells - should be copied this poset. + should be copied to this poset. - - ``mapping`` -- a function which is applied on each of the elements. + - ``mapping`` -- a function that is applied to every element. OUTPUT: @@ -1534,7 +1553,8 @@ def shells(self, include_special=False, reverse=False): .. NOTE:: - Each element is contained/encapusalted in a shell inside the poset. + Each element is contained/encapsulated in a shell inside + the poset. EXAMPLES:: @@ -1572,8 +1592,8 @@ def shells_topological(self, include_special=False, - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a - tie). If this is ``None``, no sorting according to the reprsentation - string occurs. + tie). If this is ``None``, no sorting according to the + representation string occurs. OUTPUT: @@ -1581,7 +1601,8 @@ def shells_topological(self, include_special=False, .. NOTE:: - Each element is contained/encapusalted in a shell inside the poset. + Each element is contained/encapsulated in a shell inside + the poset. EXAMPLES:: @@ -2321,7 +2342,7 @@ def union(left, *right): def union_update(self, other): r""" - Update the poset with the union of itself and another poset. + Update this poset with the union of itself and another poset. INPUT: @@ -2488,7 +2509,7 @@ def intersection(left, *right): def intersection_update(self, other): r""" - Update the poset with the intersection of itself and another poset. + Update this poset with the intersection of itself and another poset. INPUT: @@ -2554,7 +2575,7 @@ def symmetric_difference(left, right): def symmetric_difference_update(self, other): r""" - Update the poset with the symmetric difference of itself and + Update this poset with the symmetric difference of itself and another poset. INPUT: @@ -2896,14 +2917,15 @@ def minimal_elements(self): def map(self, function, topological=False, reverse=False): r""" - Applies the given ``function`` on each element. + Applies the given ``function`` to each element of this poset. INPUT: - - ``function`` -- a function mapping an existing element to a new element. + - ``function`` -- a function mapping an existing element to + a new element. - - ``topological`` -- (default: ``False``) if set, then the mapping is done - in topological order, otherwise unordered. + - ``topological`` -- (default: ``False``) if set, then the + mapping is done in topological order, otherwise unordered. - ``reverse`` -- is passed on to topological ordering. @@ -2940,14 +2962,16 @@ def map(self, function, topological=False, reverse=False): def mapped(self, function): r""" - Return a poset where on each element the given ``function`` was applied. + Return a poset where on each element the given ``function`` + was applied. INPUT: - - ``function`` -- a function mapping an existing element to a new element. + - ``function`` -- a function mapping an existing element to + a new element. - - ``topological`` -- (default: ``False``) if set, then the mapping is done - in topological order, otherwise unordered. + - ``topological`` -- (default: ``False``) if set, then the + mapping is done in topological order, otherwise unordered. - ``reverse`` -- is passed on to topological ordering. From a4c43b71c81cc75b152a99d80754c1cb47104613 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 19 Sep 2015 18:45:33 +0200 Subject: [PATCH 0917/1872] fixed two examples-blocks --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 58a745f3d4f..3c6ad8e8bc7 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1337,7 +1337,7 @@ def null(self): The shell `\emptyset` whose element is smaller than any other element. - EXAMPLES: + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() @@ -1355,7 +1355,7 @@ def oo(self): The shell `\infty` whose element is larger than any other element. - EXAMPLES: + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP() From a867d3a36f5a068b6e7e3d00f95a5c4331960a6b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 19 Sep 2015 18:46:07 +0200 Subject: [PATCH 0918/1872] indentation (PEP 8) --- src/sage/data_structures/mutable_poset.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3c6ad8e8bc7..7cc1774013f 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -799,8 +799,8 @@ def _iter_depth_first_visit_(self, marked, sage: list(P.oo._iter_depth_first_visit_(marked, True)) [oo, 42, 5, null] """ - if condition is not None and \ - not self.is_special() and not condition(self): + if (condition is not None and + not self.is_special() and not condition(self)): return if self in marked: return @@ -907,7 +907,7 @@ def _iter_topological_visit_(self, marked, [oo, 42, 5, null] """ if (condition is not None and - not self.is_special() and not condition(self)): + not self.is_special() and not condition(self)): return if self in marked: return @@ -1492,8 +1492,8 @@ def _copy_shells_(self, other, mapping): self._null_ = other._null_._copy_all_linked_(memo, self, mapping) self._oo_ = memo[id(other._oo_)] self._shells_ = dict((f.key, f) for f in - iter(memo[id(e)] - for e in other._shells_.itervalues())) + iter(memo[id(e)] for e in + other._shells_.itervalues())) def copy(self, mapping=None): @@ -1576,7 +1576,7 @@ def shells(self, include_special=False, reverse=False): def shells_topological(self, include_special=False, - reverse=False, key=None): + reverse=False, key=None): r""" Return an iterator over all shells in topological order. From c1f8877b7dcea0e1c677d350d7f5d41be02169c8 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Sat, 19 Sep 2015 18:46:23 +0200 Subject: [PATCH 0919/1872] improved errors and added two doctests --- src/sage/data_structures/mutable_poset.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 7cc1774013f..c7c0ac011a3 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2028,9 +2028,17 @@ def add(self, element): +-- null | +-- successors: (2, 1, 7) | +-- no predecessors + + :: + + sage: P = MP() + sage: P.add(None) + Traceback (most recent call last): + ... + ValueError: None is not an allowed element. """ if element is None: - raise ValueError('None is not allowed as element.') + raise ValueError('None is not an allowed element.') key = self.get_key(element) if key in self._shells_: @@ -2197,9 +2205,17 @@ def remove(self, key, raise_key_error=True): +-- null | +-- successors: (1, 2, 7), (2, 1, 7) | +-- no predecessors + + :: + + sage: P = MP() + sage: P.remove(None) + Traceback (most recent call last): + ... + ValueError: None is not an allowed key. """ if key is None: - raise ValueError('None is not allowed as key.') + raise ValueError('None is not an allowed key.') try: shell = self._shells_[key] From 23d3c15e8ccc401d14135d69c62c071a43afe2b3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 19 Sep 2015 22:58:21 -0500 Subject: [PATCH 0920/1872] Implementation of free Zinbiel algebras. --- src/doc/en/reference/algebras/index.rst | 2 + src/sage/algebras/catalog.py | 2 + src/sage/algebras/free_zinbiel_algebra.py | 258 ++++++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 src/sage/algebras/free_zinbiel_algebra.py diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index f80229432e5..d11483e5646 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -25,6 +25,8 @@ Algebras sage/algebras/free_algebra_quotient sage/algebras/free_algebra_quotient_element + sage/algebras/free_zinbiel_algebra + sage/algebras/group_algebra sage/algebras/iwahori_hecke_algebra diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index da062022b5d..262e8113f44 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -16,6 +16,7 @@ - :class:`algebras.FiniteDimensional ` - :class:`algebras.Free ` +- :class:`algebras.FreeZinbiel ` - :class:`algebras.PreLieAlgebra ` - :func:`algebras.GradedCommutative ` @@ -48,6 +49,7 @@ from sage.misc.lazy_import import lazy_import lazy_import('sage.algebras.nil_coxeter_algebra', 'NilCoxeterAlgebra', 'NilCoxeter') +lazy_import('sage.algebras.free_zinbiel_algebra', 'FreeZinbielAlgebra', 'FreeZinbiel') lazy_import('sage.algebras.hall_algebra', 'HallAlgebra', 'Hall') lazy_import('sage.algebras.jordan_algebra', 'JordanAlgebra', 'Jordan') lazy_import('sage.algebras.shuffle_algebra', 'ShuffleAlgebra', 'Shuffle') diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py new file mode 100644 index 00000000000..55e0d266702 --- /dev/null +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -0,0 +1,258 @@ +""" +Free Zinbiel Algebras + +AUTHORS: + +- Travis Scrimshaw (2015-09): initial version +""" + +#***************************************************************************** +# Copyright (C) 2015 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.monoids.free_monoid import FreeMonoid +from sage.monoids.free_monoid_element import FreeMonoidElement + +from sage.misc.cachefunc import cached_method +from sage.categories.magmatic_algebras import MagmaticAlgebras +from sage.categories.rings import Rings +from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement +from sage.combinat.words.words import Words +from sage.combinat.words.alphabet import Alphabet +from sage.structure.element import generic_power +from sage.sets.family import Family + +class FreeZinbielAlgebra(CombinatorialFreeModule): + r""" + The free Zinbiel algebra on `n` generators. + + Let `R` be a ring. A *Zinbiel algebra* is a non-associative + algebra with multiplication `\circ` that satisfies + + .. MATH:: + + a \circ (b \circ c) = a \circ (b \circ c) + a \circ (c \circ b). + + Zinbiel algebras were first introduced by Loday as the Koszul + dual to Leibniz algebras (hence the name coined by Lemaire). + + Zinbiel algebras are divided power algebras, in that for + + .. MATH:: + + x^{\circ n} = \bigl(x \circ (x \circ \cdots \circ( x \circ x) \cdots + ) \bigr) + + we have + + .. MATH:: + + x^{\circ m} \circ x^{\circ n} = \binom{n+m-1}{m} x^{n+m} + + and + + .. MATH:: + + \underbrace{\bigl( ( x \circ \cdots \circ x \circ (x \circ x) \cdots + ) \bigr)}_{n+1 \text{ times}} = n! x^n. + + .. NOTE:: + + This implies that Zinbiel algebras are not power associative. + + To every Zinbiel algebra, we can construct a corresponding commutative + associative algebra by using the symmetrized product: + + .. MATH:: + + a * b = a \circ b + b \circ a. + + The free Zinbiel algebra on `n` generators is isomorphic as `R`-modules + to the reduced tensor algebra `\bar{T}(R^n)` with the product + + .. MATH:: + + (x_0 x_1 \cdots x_p) \circ (x_{p+1} x_{p+2} \cdots x_{p+q}) + = \sum_{\simga \in S_{p,q}} x_0 (x_{\sigma(1)} x_{\sigma(2)} + \cdots x_{\sigma(p+q)}, + + where `S_{p,q}` is the set of `(p,q)`-shuffles. + + The free Zinbiel algebra is free as a divided power algebra. Moreover, + the corresponding commutative algebra is isomorphic to the (non-unital) + shuffle algebra. + + INPUT: + + - ``R`` -- a ring + - ``n`` -- (optional) the number of generators + - ``names`` -- the generator names + + .. WARNING:: + + Currently the basis is indexed all words over the variables, + incuding the empty word. This is a slight abuse as it is suppose + to be the indexed by all non-empty words. + + EXAMPLES: + + We create the free Zinbiel algebra and check the defining relation:: + + sage: Z. = algebras.FreeZinbiel(QQ) + sage: (x*y)*z + Z[xyz] + Z[xzy] + sage: x*(y*z) + x*(z*y) + Z[xyz] + Z[xzy] + + We see that the Zinbiel algebra is not associative, nor even + power associative:: + + sage: x*(y*z) + Z[xyz] + sage: x*(x*x) + Z[xxx] + sage: (x*x)*x + 2*Z[xxx] + + We verify that it is a divided powers algebra:: + + sage: (x*(x*x)) * (x*(x*(x*x))) + 15*Z[xxxxxxx] + sage: binomial(3+4-1,4) + 15 + sage: (x*(x*(x*x))) * (x*(x*x)) + 20*Z[xxxxxxx] + sage: binomial(3+4-1,3) + 20 + sage: ((x*x)*x)*x + 6*Z[xxxx] + sage: (((x*x)*x)*x)*x + 24*Z[xxxx] + + REFERENCES: + + - :wikipedia:`Zinbiel_algebra` + .. [Loday95] Jean-Louis Loday. + *Cup-product for Leibniz cohomology and dual Leibniz algebras*. + Math. Scand., pp. 189--196 (1995). + http://www.math.uiuc.edu/K-theory/0015/cup_product.pdf + .. [LV12] Jean-Louis Loday and Bruno Vallette. *Algebraic Operads*. + Springer-Verlag Berlin Heidelberg (2012). + :doi:`10.1007/978-3-642-30362-3`. + """ + @staticmethod + def __classcall_private__(cls, R, n=None, names=None): + """ + Standardize input to ensure a unqiue representation. + + TESTS:: + + sage: Z1. = algebras.FreeZinbiel(QQ) + sage: Z2. = algebras.FreeZinbiel(QQ, 3) + sage: Z3 = algebras.FreeZinbiel(QQ, 3, 'x,y,z') + sage: Z4. = algebras.FreeZinbiel(QQ, 'x,y,z') + sage: Z1 is Z2 and Z1 is Z3 and Z1 is Z4 + True + """ + if isinstance(n, (list,tuple)): + names = n + n = len(names) + elif isinstance(n, str): + names = n.split(',') + n = len(names) + elif isinstance(names, str): + names = names.split(',') + elif n is None: + n = len(names) + return super(FreeZinbielAlgebra, cls).__classcall__(cls, R, n, tuple(names)) + + def __init__(self, R, n, names): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: Z. = algebras.FreeZinbiel(QQ) + sage: TestSuite(Z).run() + """ + if R not in Rings: + raise TypeError("argument R must be a ring") + indices = Words(Alphabet(n, names=names)) + cat = MagmaticAlgebras(R).WithBasis() + self._n = n + CombinatorialFreeModule.__init__(self, R, indices, prefix='Z', + category=cat) + self._assign_names(names) + + def _repr_term(self, t): + """ + Return a string representation of the basis element indexed by ``t``. + + EXAMPLES:: + + sage: Z. = algebras.FreeZinbiel(QQ) + sage: Z._repr_term(Z._indices('xyzxxy')) + 'Z[xyzxxy]' + """ + return "{!s}[{!s}]".format(self._print_options['prefix'], repr(t)[6:]) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: Z. = algebras.FreeZinbiel(QQ) + sage: Z + Free Zinbiel algebra on generators (Z[x], Z[y], Z[z]) over Rational Field + """ + return "Free Zinbiel algebra on generators {} over {}".format( + self.gens(), self.base_ring()) + + @cached_method + def algebra_generators(self): + """ + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: Z. = algebras.FreeZinbiel(QQ) + sage: list(Z.algebra_generators()) + [Z[x], Z[y], Z[z]] + """ + A = self.variable_names() + return Family( A, lambda g: self.monomial(self._indices(g)) ) + + @cached_method + def gens(self): + """ + Return the generators of ``self``. + + EXAMPLES:: + + sage: Z. = algebras.FreeZinbiel(QQ) + sage: Z.gens() + (Z[x], Z[y], Z[z]) + """ + return tuple(self.algebra_generators()) + + def product_on_basis(self, x, y): + """ + Return the product of the basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: Z. = algebras.FreeZinbiel(QQ) + sage: (x*y)*z # indirect doctest + Z[xyz] + Z[xzy] + sage: x^4 + 3*Z[xxxx] + """ + if not x: + return self.monomial(y) + x0 = self._indices(x[0]) + return self.sum_of_monomials(x0 + sh for sh in x[1:].shuffle(y)) + From 6eec443d7dc8e7cde8cdabc7e0b85cdb15ec8b84 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Sun, 20 Sep 2015 21:12:51 +0900 Subject: [PATCH 0921/1872] Commit a modification in tutorial/interactive_shell.rst A misleading text on the help example has been modified. --- src/doc/ja/tutorial/interactive_shell.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/ja/tutorial/interactive_shell.rst b/src/doc/ja/tutorial/interactive_shell.rst index 20442c0832a..8113acfb611 100644 --- a/src/doc/ja/tutorial/interactive_shell.rst +++ b/src/doc/ja/tutorial/interactive_shell.rst @@ -609,7 +609,7 @@ Sageの特長の一つは,総合的なヘルプ機能の装備である. ``coordinate_vector`` 関数は,入力を生成空間(ambient space)に合わせて型変換するから,これは :math:`v` の係数ベクトルが空間 :math:`V` ではどう変換されるか計算していることと同じである. -:math:`\QQ^3` そのものである空間 :math:`V` が同相なのは当然だ. +:math:`V` は :math:`\QQ^3` そのものだから,すでに同じ構造になっている. 部分空間用に、上とは異なる ``coordinate_vector`` 関数も用意されている. 部分空間を作って,どんな関数か見てみることにしよう: From 5a0384c60fb35730a87d96db3a983d0cf27610d6 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 20 Sep 2015 22:51:38 +0200 Subject: [PATCH 0922/1872] trac #19224: Rework the doctests --- src/sage/graphs/strongly_regular_db.pyx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 6f6d9967d5b..77b8983ab66 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -988,17 +988,13 @@ def is_switch_OA_srg(int v, int k, int l, int mu): EXAMPLES:: - sage: from sage.graphs.strongly_regular_db import is_switch_OA_srg - sage: t = is_switch_OA_srg(170, 78, 35, 36); t - (.switch_OA_srg ...>, 6, 13) - sage: g = t[0](*t[1:]); g + sage: graphs.strongly_regular_graph(170, 78, 35, 36) # indirect doctest Graph on 170 vertices - sage: g.is_strongly_regular(parameters=True) - (170, 78, 35, 36) - sage: t = is_switch_OA_srg(5,5,5,5); t TESTS:: + sage: from sage.graphs.strongly_regular_db import is_switch_OA_srg + sage: t = is_switch_OA_srg(5,5,5,5); t sage: is_switch_OA_srg(290, 136, 63, 64) (.switch_OA_srg at ..., 8, 17) sage: is_switch_OA_srg(626, 300, 143, 144) From c82406924c97e4a7096db8b26e69b58eaf3ded43 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Mon, 21 Sep 2015 15:21:25 +0900 Subject: [PATCH 0923/1872] A typo, and a misplaced space removed(interactive_shell.rst) --- src/doc/ja/tutorial/interactive_shell.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/ja/tutorial/interactive_shell.rst b/src/doc/ja/tutorial/interactive_shell.rst index 8113acfb611..592a8827871 100644 --- a/src/doc/ja/tutorial/interactive_shell.rst +++ b/src/doc/ja/tutorial/interactive_shell.rst @@ -610,7 +610,7 @@ Sageの特長の一つは,総合的なヘルプ機能の装備である. ``coordinate_vector`` 関数は,入力を生成空間(ambient space)に合わせて型変換するから,これは :math:`v` の係数ベクトルが空間 :math:`V` ではどう変換されるか計算していることと同じである. :math:`V` は :math:`\QQ^3` そのものだから,すでに同じ構造になっている. -部分空間用に、上とは異なる ``coordinate_vector`` 関数も用意されている. +部分空間用に,上とは異なる ``coordinate_vector`` 関数も用意されている. 部分空間を作って,どんな関数か見てみることにしよう: .. skip @@ -634,7 +634,7 @@ Sageの特長の一つは,総合的なヘルプ機能の装備である. (こうした実装の仕方は無駄が多いと思われる方は,どうか我々に連絡して線形代数周りの最適化に力を貸していただきたい.) - ``help(コマンド名)`` あるいは ``help(クラス名)`` と入力すれば,知りた いクラスのmanページ型ヘルプファイルを表示することもできる. +``help(コマンド名)`` あるいは ``help(クラス名)`` と入力すれば,知りた いクラスのmanページ型ヘルプファイルを表示することもできる. .. skip From 154cc6f676ebd0f531bba1d6b282f55f246ba180 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 21 Sep 2015 09:58:44 +0200 Subject: [PATCH 0924/1872] Integrated reviewer's comments --- src/sage/coding/encoder.py | 18 +++++++++++++----- src/sage/coding/linear_code.py | 15 +++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 8c937f217f3..6569ba13c11 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -97,6 +97,12 @@ def encode(self, word): and `k` is :meth:`sage.coding.linear_code.AbstractLinearCode.dimension`. If this is not the case, this method should be overwritten by the subclass. + .. NOTE:: + + :meth:`encode` is a partial function over ``self``'s :meth:`message_space`. + One should use the exception :class:`EncodingError` to catch attempts + to encode words that are outside of the message space. + INPUT: - ``word`` -- a vector of the message space of the ``self``. @@ -191,13 +197,16 @@ def _unencoder_matrix(self): sage: C = LinearCode(G) sage: E = C.encoder() sage: E._unencoder_matrix() + ( [0 0 1 1] [0 1 0 1] [1 1 1 0] - [0 1 1 1] + [0 1 1 1], (0, 1, 2, 3) + ) """ - Gt = self.generator_matrix().matrix_from_columns(self.code().information_set()) - return Gt.inverse() + info_set = self.code().information_set() + Gt = self.generator_matrix().matrix_from_columns(info_set) + return (Gt.inverse(), info_set) def unencode_nocheck(self, c): r""" @@ -243,8 +252,7 @@ def unencode_nocheck(self, c): sage: c == c1 False """ - U = self._unencoder_matrix() - info_set = self.code().information_set() + U, info_set = self._unencoder_matrix() cc = vector( c[i] for i in info_set ) return cc * U diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index a6d2140abe0..39e25a56853 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1811,7 +1811,7 @@ def encoder(self, encoder_name=None, **kwargs): 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.encoder() - Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 + Generator matrix-based encoder for Linear code of length 7, dimension 4 over Finite Field of size 2 We check that the returned encoder is cached:: @@ -3266,8 +3266,7 @@ def unencode(self, c, encoder_name=None, nocheck=False, **kwargs): INPUT: - - ``c`` -- a vector of the same length as ``self`` over the - base field of ``self`` + - ``c`` -- a codeword of ``self`` - ``encoder_name`` -- (default: ``None``) name of the decoder which will be used to decode ``word``. The default decoder of ``self`` will be used if @@ -3695,7 +3694,7 @@ def __init__(self, code): sage: C = LinearCode(G) sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E - Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 + Generator matrix-based encoder for Linear code of length 7, dimension 4 over Finite Field of size 2 """ super(LinearCodeGeneratorMatrixEncoder, self).__init__(code) @@ -3709,9 +3708,9 @@ def _repr_(self): sage: C = LinearCode(G) sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: E - Generator matrix-based encoder for the Linear code of length 7, dimension 4 over Finite Field of size 2 + Generator matrix-based encoder for Linear code of length 7, dimension 4 over Finite Field of size 2 """ - return "Generator matrix-based encoder for the %s" % self.code() + return "Generator matrix-based encoder for %s" % self.code() def _latex_(self): r""" @@ -3723,9 +3722,9 @@ def _latex_(self): sage: C = LinearCode(G) sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: latex(E) - \textnormal{Generator matrix-based encoder for the }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2} + \textnormal{Generator matrix-based encoder for }[7, 4]\textnormal{ Linear code over }\Bold{F}_{2} """ - return "\\textnormal{Generator matrix-based encoder for the }%s" % self.code()._latex_() + return "\\textnormal{Generator matrix-based encoder for }%s" % self.code()._latex_() @cached_method def generator_matrix(self): From 28ea9d6dc83982fd240604493a28097866720996 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 16:56:56 +0200 Subject: [PATCH 0925/1872] Revert "print something --> print(something)" This reverts commit 98a7939651645c24263e36c8fca81dc1ba6d9a96. --- src/sage/data_structures/mutable_poset.py | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index c7c0ac011a3..f18cea3df56 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -94,7 +94,7 @@ information. We can overcome this and display a "wiring layout" by typing:: - sage: print(Q.repr_full(reverse=True)) + sage: print Q.repr_full(reverse=True) poset((3, 3), (2, 3), (3, 2), (2, 2), (4, 1), (1, 1)) +-- oo | +-- no successors @@ -979,8 +979,8 @@ def iter_topological(self, reverse=False, key=None, condition=None): sage: for e in P.shells_topological(include_special=True, ....: reverse=True): - ....: print(e) - ....: print(list(e.iter_topological(reverse=True, key=repr))) + ....: print e + ....: print list(e.iter_topological(reverse=True, key=repr)) oo [oo] (4, 4) @@ -1002,8 +1002,8 @@ def iter_topological(self, reverse=False, key=None, condition=None): sage: for e in P.shells_topological(include_special=True, ....: reverse=True): - ....: print(e) - ....: print(list(e.iter_topological(reverse=False, key=repr))) + ....: print e + ....: print list(e.iter_topological(reverse=False, key=repr)) oo [null, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] (4, 4) @@ -1286,7 +1286,7 @@ def clear(self): sage: P.add(42); P poset(42) sage: P.clear() - sage: print(P.repr_full()) + sage: print P.repr_full() poset() +-- null | +-- no predecessors @@ -1806,7 +1806,7 @@ def repr(self, include_special=False, reverse=False): TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: print(MP().repr()) + sage: print MP().repr() poset() """ s = 'poset(' @@ -1831,7 +1831,7 @@ def repr_full(self, reverse=False): TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: print(MP().repr_full(reverse=True)) + sage: print MP().repr_full(reverse=True) poset() +-- oo | +-- no successors @@ -1917,7 +1917,7 @@ def add(self, element): sage: P.add(T((2, 1))) sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) - sage: print(P.repr_full(reverse=True)) + sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -1941,7 +1941,7 @@ def add(self, element): | +-- successors: (1, 1) | +-- no predecessors sage: P.add(T((2, 2))) - sage: reprP = P.repr_full(reverse=True); print(reprP) + sage: reprP = P.repr_full(reverse=True); print reprP poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -2014,7 +2014,7 @@ def add(self, element): sage: R.add((4, 4, 42)) sage: R.add((1, 2, 7)) sage: R.add((2, 2, 7)) - sage: print(R.repr_full(reverse=True)) + sage: print R.repr_full(reverse=True) poset((1, 1, 42), (2, 1, 7)) +-- oo | +-- no successors @@ -2094,7 +2094,7 @@ def remove(self, key, raise_key_error=True): sage: P.add(T((4, 4))) sage: P.add(T((1, 2))) sage: P.add(T((2, 2))) - sage: print(P.repr_full(reverse=True)) + sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -2121,7 +2121,7 @@ def remove(self, key, raise_key_error=True): | +-- successors: (1, 1) | +-- no predecessors sage: P.remove(T((1, 2))) - sage: print(P.repr_full(reverse=True)) + sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (2, 2), (2, 1), (1, 1)) +-- oo | +-- no successors @@ -2154,7 +2154,7 @@ def remove(self, key, raise_key_error=True): sage: Q.add((4, 4, 42)) sage: Q.add((1, 2, 7)) sage: Q.add((2, 2, 7)) - sage: print(Q.repr_full(reverse=True)) + sage: print Q.repr_full(reverse=True) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7), (1, 1, 42)) +-- oo @@ -2182,7 +2182,7 @@ def remove(self, key, raise_key_error=True): | +-- successors: (1, 1, 42) | +-- no predecessors sage: Q.remove((1,1)) - sage: print(Q.repr_full(reverse=True)) + sage: print Q.repr_full(reverse=True) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7)) +-- oo | +-- no successors @@ -2789,7 +2789,7 @@ def merge(self, key=None, reverse=False): sage: P.add((2, 2, 'f')) sage: Q = copy(P) sage: Q.merge(T((1, 3))) - sage: print(Q.repr_full(reverse=True)) + sage: print Q.repr_full(reverse=True) poset((4, 4, 'd'), (1, 3, 'abe'), (2, 2, 'f'), (2, 1, 'c')) +-- oo | +-- no successors @@ -2812,7 +2812,7 @@ def merge(self, key=None, reverse=False): sage: for k in P.keys(): ....: Q = copy(P) ....: Q.merge(k) - ....: print('merging %s: %s' % (k, Q)) + ....: print 'merging %s: %s' % (k, Q) merging (1, 2): poset((1, 2, 'ae'), (1, 3, 'b'), (2, 1, 'c'), (2, 2, 'f'), (4, 4, 'd')) merging (1, 3): poset((1, 3, 'abe'), (2, 1, 'c'), From 39ae466eea0e2daae13d78b23aa74ddaee687b81 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:02:11 +0200 Subject: [PATCH 0926/1872] correct oo, null --- src/sage/data_structures/mutable_poset.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index f18cea3df56..788086f1126 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -772,8 +772,8 @@ def _iter_depth_first_visit_(self, marked, - ``marked`` -- a set in which marked shells are stored. - ``reverse`` -- (default: ``False``) if set, reverses the - order, i.e., ``False`` searches towards ``null`` and - ``True`` searches towards ``oo``. + order, i.e., ``False`` searches towards ``'oo'`` and + ``True`` searches towards ``'null'``. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -822,8 +822,8 @@ def iter_depth_first(self, reverse=False, key=None, condition=None): INPUT: - ``reverse`` -- (default: ``False``) if set, reverses the - order, i.e., ``False`` searches towards ``null`` and - ``True`` searches towards ``oo``. + order, i.e., ``False`` searches towards ``'oo'`` and + ``True`` searches towards ``'null'``. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -879,8 +879,8 @@ def _iter_topological_visit_(self, marked, - ``marked`` -- a set in which marked shells are stored. - ``reverse`` -- (default: ``False``) if set, reverses the - order, i.e., ``False`` searches towards ``null`` and - ``True`` searches towards ``oo``. + order, i.e., ``False`` searches towards ``'oo'`` and + ``True`` searches towards ``'null'``. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a @@ -929,8 +929,8 @@ def iter_topological(self, reverse=False, key=None, condition=None): INPUT: - ``reverse`` -- (default: ``False``) if set, reverses the - order, i.e., ``False`` searches towards ``null`` and - ``True`` searches towards ``oo``. + order, i.e., ``False`` searches towards ``'oo'`` and + ``True`` searches towards ``'null'``. - ``key`` -- (default: ``None``) a function used for sorting the direct successors of a shell (used in case of a From fd7c881001b0dc480e596e61578aa87afa80e638 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:04:18 +0200 Subject: [PATCH 0927/1872] Applies --> Apply in one-line of docstring --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 788086f1126..2b94c70080b 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1461,7 +1461,7 @@ def _copy_shells_(self, other, mapping): - ``other`` -- the mutable poset from which the shells should be copied to this poset. - - ``mapping`` -- a function that is applied to every element. + - ``mapping`` -- a function that is applied to each element. OUTPUT: @@ -2933,7 +2933,7 @@ def minimal_elements(self): def map(self, function, topological=False, reverse=False): r""" - Applies the given ``function`` to each element of this poset. + Apply the given ``function`` to each element of this poset. INPUT: From dabad1f4c953f9a4e0f973f2ee7c46cbb0d15752 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:08:35 +0200 Subject: [PATCH 0928/1872] remove reverse in is_{null|oo} since not needed --- src/sage/data_structures/mutable_poset.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 2b94c70080b..165fd6c9d20 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -338,16 +338,11 @@ def is_special(self): return self.element is None - def is_null(self, reverse=False): + def is_null(self): r""" Return if this shell contains the null-element, i.e., the element smaller than any possible other element. - INPUT: - - - ``reverse`` -- (default: ``False``) if set, then returns - if the element is the largest possible. - OUTPUT: ``True`` or ``False``. @@ -361,19 +356,14 @@ def is_null(self, reverse=False): sage: P.oo.is_null() False """ - return self.element is None and not self.predecessors(reverse) + return self.element is None and not self.predecessors() - def is_oo(self, reverse=False): + def is_oo(self): r""" Return if this shell contains the infinity-element, i.e., the element larger than any possible other element. - INPUT: - - - ``reverse`` -- (default: ``False``) if set, then returns - if the element is the smallest possible. - OUTPUT: ``True`` or ``False``. @@ -387,7 +377,7 @@ def is_oo(self, reverse=False): sage: P.oo.is_oo() True """ - return self.element is None and not self.successors(reverse) + return self.element is None and not self.successors() def __repr__(self): From 33c410238a9352d08b5634a60b6ed30b8f0d3aad Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:09:49 +0200 Subject: [PATCH 0929/1872] mark doctests in .le as indirect --- src/sage/data_structures/mutable_poset.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 165fd6c9d20..5ee48ece35f 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -480,23 +480,23 @@ def le(left, right, reverse=False): sage: e = MutablePosetShell(P, (1, 2)) sage: z = P.null sage: oo = P.oo - sage: z <= e + sage: z <= e # indirect doctest True - sage: e <= oo + sage: e <= oo # indirect doctest True - sage: z <= oo + sage: z <= oo # indirect doctest True - sage: oo <= z + sage: oo <= z # indirect doctest False - sage: oo <= e + sage: oo <= e # indirect doctest False - sage: e <= z + sage: e <= z # indirect doctest False - sage: z <= z + sage: z <= z # indirect doctest True - sage: oo <= oo + sage: oo <= oo # indirect doctest True - sage: e <= e + sage: e <= e # indirect doctest True :: From b31fac80d649c8351e20d90dfdff39d28c91d21f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:15:39 +0200 Subject: [PATCH 0930/1872] rewrite a couple of one-line descriptions --- src/sage/data_structures/mutable_poset.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 5ee48ece35f..386ac8bb65d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -605,7 +605,10 @@ def eq(left, right): def _copy_all_linked_(self, memo, poset, mapping): r""" - Helper function for :meth:`MutablePoset.copy`. + Return a copy of all shells linked to this shell + (including a copy of this shell). + + This is a helper function for :meth:`MutablePoset.copy`. INPUT: @@ -651,7 +654,9 @@ def _copy_all_linked_(self, memo, poset, mapping): def _search_covers_(self, covers, shell, reverse=False): r""" - Helper function for :meth:`covers`. + Search for cover shells of this shell. + + This is a helper function for :meth:`covers`. INPUT: @@ -755,7 +760,9 @@ def _iter_depth_first_visit_(self, marked, reverse=False, key=None, condition=None): r""" - Helper function for :meth:`iter_depth_first`. + Return an iterator over all shells in depth first order. + + This is a helper function for :meth:`iter_depth_first`. INPUT: @@ -862,7 +869,9 @@ def _iter_topological_visit_(self, marked, reverse=False, key=None, condition=None): r""" - Helper function for :meth:`iter_topological`. + Return an iterator over all shells in topological order. + + This is a helper function for :meth:`iter_topological`. INPUT: @@ -1444,7 +1453,7 @@ def get_key(self, element): def _copy_shells_(self, other, mapping): r""" - Helper function for copying shells. + Copy shells from another poset. INPUT: From 17e921ffeb31ed529f9686ed5c54d48e36b248cf Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:19:19 +0200 Subject: [PATCH 0931/1872] remove sorted_set_by_tuple only used once --- src/sage/data_structures/mutable_poset.py | 41 ++--------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 386ac8bb65d..9b7b80c79bb 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1089,39 +1089,6 @@ def merge(self, element, check=True, delete=True): # ***************************************************************************** -def sorted_set_by_tuple(S, T): - r""" - Return an iterator over ``T`` for all elements of ``T`` that are - contained in ``S``. - - INPUT: - - - ``S`` -- a set (or something which supports a containment - test). - - - ``T`` -- a tuple (or other iterable). - - OUTPUT: - - An iterator. - - .. NOTE:: - - The iterator returned by this function preserves the order - of the elements in ``T``. - - EXAMPLES:: - - sage: from sage.data_structures.mutable_poset import sorted_set_by_tuple - sage: tuple(sorted_set_by_tuple({3, 4, 6}, (5, 4, 1, 2, 3, 6))) - (4, 3, 6) - """ - return iter(ell for ell in T if ell in S) - - -# ***************************************************************************** - - def is_MutablePoset(P): r""" Tests if ``P`` inherits from :class:`MutablePoset`. @@ -1533,7 +1500,7 @@ def copy(self, mapping=None): __copy__ = copy - def shells(self, include_special=False, reverse=False): + def shells(self, include_special=False): r""" Return an iterator over all shells. @@ -1543,9 +1510,6 @@ def shells(self, include_special=False, reverse=False): including shells containing a smallest element (`\emptyset`) and a largest element (`\infty`). - - ``reverse`` -- (default: ``False``) if set, the order is - reversed. This only affects the shells `\emptyset` and `\infty`. - OUTPUT: An iterator. @@ -1849,8 +1813,7 @@ def repr_full(self, reverse=False): if shell.successors(rev): s = '| +-- ' + what + ': ' s += ', '.join(repr(e) for e in - sorted_set_by_tuple(shell.successors(rev), - sortedshells)) + sortedshells if e in shell.successors(rev)) else: s = '| +-- no ' + what strings.append(s) From 7af4b6bf109a4eeb1f09a386ecbf5cdeb51a0cbe Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:26:03 +0200 Subject: [PATCH 0932/1872] remove reverse keyword from shells --- src/sage/data_structures/mutable_poset.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 9b7b80c79bb..06bc611ccf2 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1527,15 +1527,13 @@ def shells(self, include_special=False): () sage: tuple(P.shells(include_special=True)) (null, oo) - sage: tuple(P.shells(include_special=True, reverse=True)) - (oo, null) """ if include_special: - yield self.null if not reverse else self.oo + yield self.null for e in self._shells_.itervalues(): yield e if include_special: - yield self.oo if not reverse else self.null + yield self.oo def shells_topological(self, include_special=False, From a49a20db5ec0d19d50621de6286ddc11e737735f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:28:47 +0200 Subject: [PATCH 0933/1872] add comment in code to make it clear what happens --- src/sage/data_structures/mutable_poset.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 06bc611ccf2..4d2590097aa 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2010,6 +2010,8 @@ def add(self, element): smaller = self.null.covers(new, reverse=False) larger = self.oo.covers(new, reverse=True) + # In the following we first search towards oo (reverse=False) and + # then towards null (reverse=True; everything is "inverted"). for reverse in (False, True): sm = smaller if not reverse else larger la = larger if not reverse else smaller From 89b82093fecc685245c824ab9284a67c198be50f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:37:51 +0200 Subject: [PATCH 0934/1872] change left/right to self/other --- src/sage/data_structures/mutable_poset.py | 86 ++++++++++------------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 4d2590097aa..d3deb224d0a 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -446,15 +446,13 @@ def __hash__(self): return hash(self.key) - def le(left, right, reverse=False): + def le(self, other, reverse=False): r""" - Return if ``left`` is less than or equal to ``right``. + Return whether this shell is less than or equal to ``other``. INPUT: - - ``left`` -- a shell. - - - ``right`` -- a shell. + - ``other`` -- a shell. - ``reverse`` -- (default: ``False``) if set, then return ``right <= left`` instead. @@ -521,46 +519,44 @@ def le(left, right, reverse=False): True """ if reverse: - left, right = (right, left) + return other.le(self, reverse=False) - if left.element is None: - if not left.predecessors(): + if self.element is None: + if not self.predecessors(): # null on the left return True else: # oo on the left - if right.element is None: + if other.element is None: # null or oo on the right - return not right.successors() + return not other.successors() else: # not null, not oo on the right return False - if right.element is None: - if not right.successors(): + if other.element is None: + if not other.successors(): # oo on the right return True else: # null on the right - if left.element is None: + if self.element is None: # null or oo on the left - return not left.predecessors() + return not self.predecessors() else: # not null, not oo on the right return False - return left.key <= right.key + return self.key <= other.key __le__ = le - def eq(left, right): + def eq(self, other): r""" - Return if ``left`` is equal to ``right``. + Return whether this shell is equal to ``other``. INPUT: - - ``left`` -- a shell. - - ``right`` -- a shell. OUTPUT: @@ -595,9 +591,9 @@ def eq(left, right): sage: oo == z False """ - if left.element is None and right.element is None: - return left.is_null() == right.is_null() - return left.key == right.key + if self.element is None and other.element is None: + return self.is_null() == other.is_null() + return self.key == other.key __eq__ = eq @@ -2280,15 +2276,13 @@ def pop(self, **kwargs): return shell.element - def union(left, *right): + def union(self, *other): r""" Return the union of the given posets as a new poset INPUT: - - ``left`` -- a poset. - - - ``right`` -- a poset or an iterable. In the latter case the + - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. OUTPUT: @@ -2312,9 +2306,9 @@ def union(left, *right): sage: P.union(P, Q, Q, P) poset(3, 4, 7, 8, 42) """ - new = left.copy() - for r in right: - new.update(r) + new = self.copy() + for o in other: + new.update(o) return new @@ -2370,16 +2364,14 @@ def union_update(self, other): """ - def difference(left, *right): + def difference(self, *other): r""" Return a new poset where all elements of this poset, which are contained in one of the other given posets, are removed. INPUT: - - ``left`` -- a poset. - - - ``right`` -- a poset or an iterable. In the latter case the + - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. OUTPUT: @@ -2407,9 +2399,9 @@ def difference(left, *right): sage: P.difference(Q, P) poset() """ - new = left.copy() - for r in right: - new.difference_update(r) + new = self.copy() + for o in other: + new.difference_update(o) return new @@ -2447,15 +2439,13 @@ def difference_update(self, other): self.discard(key) - def intersection(left, *right): + def intersection(self, *other): r""" Return the intersection of the given posets as a new poset INPUT: - - ``left`` -- a poset. - - - ``right`` -- a poset or an iterable. In the latter case the + - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. OUTPUT: @@ -2479,9 +2469,9 @@ def intersection(left, *right): sage: P.intersection(P, Q, Q, P) poset(42) """ - new = left.copy() - for r in right: - new.intersection_update(r) + new = self.copy() + for o in other: + new.intersection_update(o) return new @@ -2520,15 +2510,13 @@ def intersection_update(self, other): self.discard(key) - def symmetric_difference(left, right): + def symmetric_difference(self, other): r""" Return the symmetric difference of two posets as a new poset. INPUT: - - ``left`` -- a poset. - - - ``right`` -- a poset. + - ``other`` -- a poset. OUTPUT: @@ -2546,8 +2534,8 @@ def symmetric_difference(left, right): sage: P.symmetric_difference(Q) poset(3, 4, 7, 8) """ - new = left.copy() - new.symmetric_difference_update(right) + new = self.copy() + new.symmetric_difference_update(other) return new From 1d52f6c6351e6eb9e92c6033b12e09c4754b8110 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 21 Sep 2015 17:46:39 +0200 Subject: [PATCH 0935/1872] add a note to the set operations methods --- src/sage/data_structures/mutable_poset.py | 66 +++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d3deb224d0a..bae921007e1 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2289,6 +2289,12 @@ def union(self, *other): A poset. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2325,6 +2331,12 @@ def union_update(self, other): Nothing. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + .. TODO:: Use the already existing information in the other poset to speed @@ -2378,6 +2390,12 @@ def difference(self, *other): A poset. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2418,6 +2436,12 @@ def difference_update(self, other): Nothing. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2452,6 +2476,12 @@ def intersection(self, *other): A poset. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2488,6 +2518,12 @@ def intersection_update(self, other): Nothing. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2522,6 +2558,12 @@ def symmetric_difference(self, other): A poset. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2552,6 +2594,12 @@ def symmetric_difference_update(self, other): Nothing. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2583,6 +2631,12 @@ def is_disjoint(self, other): Nothing. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2620,6 +2674,12 @@ def is_subset(self, other): Nothing. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2661,6 +2721,12 @@ def is_superset(self, other): Nothing. + .. NOTE:: + + If this poset uses a ``key``-function, then all + comparisons are performed on the keys of the elements (and + not on the elements themselves). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From cc2d23212d2eded850f29a6344767e06306cfb1b Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 21 Sep 2015 19:57:20 +0200 Subject: [PATCH 0936/1872] Add some "no dependencies" --- build/pkgs/autotools/dependencies | 5 +++++ build/pkgs/boehm_gc/dependencies | 5 +++++ build/pkgs/boost_cropped/dependencies | 5 +++++ build/pkgs/buckygen/dependencies | 5 +++++ build/pkgs/cephes/dependencies | 5 +++++ build/pkgs/cliquer/dependencies | 5 +++++ build/pkgs/combinatorial_designs/dependencies | 5 +++++ build/pkgs/compilerwrapper/dependencies | 5 +++++ build/pkgs/cryptominisat/dependencies | 5 +++++ build/pkgs/d3js/dependencies | 5 +++++ build/pkgs/database_cremona_ellcurve/dependencies | 5 +++++ build/pkgs/database_jones_numfield/dependencies | 5 +++++ build/pkgs/database_stein_watkins/dependencies | 5 +++++ build/pkgs/database_stein_watkins_mini/dependencies | 5 +++++ build/pkgs/database_symbolic_data/dependencies | 5 +++++ build/pkgs/graphs/dependencies | 5 +++++ build/pkgs/iconv/dependencies | 5 +++++ build/pkgs/libogg/dependencies | 5 +++++ build/pkgs/lrcalc/dependencies | 5 +++++ build/pkgs/nauty/dependencies | 5 +++++ build/pkgs/ncurses/dependencies | 5 +++++ build/pkgs/openssl/dependencies | 5 +++++ build/pkgs/pari_galdata/dependencies | 5 +++++ build/pkgs/pari_seadata_small/dependencies | 5 +++++ build/pkgs/patch/dependencies | 5 +++++ build/pkgs/planarity/dependencies | 5 +++++ build/pkgs/plantri/dependencies | 5 +++++ build/pkgs/polytopes_db/dependencies | 5 +++++ build/pkgs/rubiks/dependencies | 5 +++++ build/pkgs/rw/dependencies | 5 +++++ build/pkgs/saclib/dependencies | 5 +++++ build/pkgs/symmetrica/dependencies | 5 +++++ build/pkgs/sympow/dependencies | 5 +++++ build/pkgs/termcap/dependencies | 5 +++++ build/pkgs/valgrind/dependencies | 5 +++++ build/pkgs/zeromq/dependencies | 5 +++++ build/pkgs/zlib/dependencies | 5 +++++ 37 files changed, 185 insertions(+) create mode 100644 build/pkgs/autotools/dependencies create mode 100644 build/pkgs/boehm_gc/dependencies create mode 100644 build/pkgs/boost_cropped/dependencies create mode 100644 build/pkgs/buckygen/dependencies create mode 100644 build/pkgs/cephes/dependencies create mode 100644 build/pkgs/cliquer/dependencies create mode 100644 build/pkgs/combinatorial_designs/dependencies create mode 100644 build/pkgs/compilerwrapper/dependencies create mode 100644 build/pkgs/cryptominisat/dependencies create mode 100644 build/pkgs/d3js/dependencies create mode 100644 build/pkgs/database_cremona_ellcurve/dependencies create mode 100644 build/pkgs/database_jones_numfield/dependencies create mode 100644 build/pkgs/database_stein_watkins/dependencies create mode 100644 build/pkgs/database_stein_watkins_mini/dependencies create mode 100644 build/pkgs/database_symbolic_data/dependencies create mode 100644 build/pkgs/graphs/dependencies create mode 100644 build/pkgs/iconv/dependencies create mode 100644 build/pkgs/libogg/dependencies create mode 100644 build/pkgs/lrcalc/dependencies create mode 100644 build/pkgs/nauty/dependencies create mode 100644 build/pkgs/ncurses/dependencies create mode 100644 build/pkgs/openssl/dependencies create mode 100644 build/pkgs/pari_galdata/dependencies create mode 100644 build/pkgs/pari_seadata_small/dependencies create mode 100644 build/pkgs/patch/dependencies create mode 100644 build/pkgs/planarity/dependencies create mode 100644 build/pkgs/plantri/dependencies create mode 100644 build/pkgs/polytopes_db/dependencies create mode 100644 build/pkgs/rubiks/dependencies create mode 100644 build/pkgs/rw/dependencies create mode 100644 build/pkgs/saclib/dependencies create mode 100644 build/pkgs/symmetrica/dependencies create mode 100644 build/pkgs/sympow/dependencies create mode 100644 build/pkgs/termcap/dependencies create mode 100644 build/pkgs/valgrind/dependencies create mode 100644 build/pkgs/zeromq/dependencies create mode 100644 build/pkgs/zlib/dependencies diff --git a/build/pkgs/autotools/dependencies b/build/pkgs/autotools/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/autotools/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/boehm_gc/dependencies b/build/pkgs/boehm_gc/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/boehm_gc/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/boost_cropped/dependencies b/build/pkgs/boost_cropped/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/boost_cropped/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/buckygen/dependencies b/build/pkgs/buckygen/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/buckygen/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/cephes/dependencies b/build/pkgs/cephes/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/cephes/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/cliquer/dependencies b/build/pkgs/cliquer/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/cliquer/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/combinatorial_designs/dependencies b/build/pkgs/combinatorial_designs/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/combinatorial_designs/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/compilerwrapper/dependencies b/build/pkgs/compilerwrapper/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/compilerwrapper/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/cryptominisat/dependencies b/build/pkgs/cryptominisat/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/cryptominisat/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/d3js/dependencies b/build/pkgs/d3js/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/d3js/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/database_cremona_ellcurve/dependencies b/build/pkgs/database_cremona_ellcurve/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/database_cremona_ellcurve/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/database_jones_numfield/dependencies b/build/pkgs/database_jones_numfield/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/database_jones_numfield/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/database_stein_watkins/dependencies b/build/pkgs/database_stein_watkins/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/database_stein_watkins/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/database_stein_watkins_mini/dependencies b/build/pkgs/database_stein_watkins_mini/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/database_stein_watkins_mini/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/database_symbolic_data/dependencies b/build/pkgs/database_symbolic_data/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/database_symbolic_data/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/graphs/dependencies b/build/pkgs/graphs/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/graphs/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/iconv/dependencies b/build/pkgs/iconv/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/iconv/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/libogg/dependencies b/build/pkgs/libogg/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/libogg/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/lrcalc/dependencies b/build/pkgs/lrcalc/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/lrcalc/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/nauty/dependencies b/build/pkgs/nauty/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/nauty/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/ncurses/dependencies b/build/pkgs/ncurses/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/ncurses/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/openssl/dependencies b/build/pkgs/openssl/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/openssl/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/pari_galdata/dependencies b/build/pkgs/pari_galdata/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/pari_galdata/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/pari_seadata_small/dependencies b/build/pkgs/pari_seadata_small/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/pari_seadata_small/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/patch/dependencies b/build/pkgs/patch/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/patch/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/planarity/dependencies b/build/pkgs/planarity/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/planarity/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/plantri/dependencies b/build/pkgs/plantri/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/plantri/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/polytopes_db/dependencies b/build/pkgs/polytopes_db/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/polytopes_db/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/rubiks/dependencies b/build/pkgs/rubiks/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/rubiks/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/rw/dependencies b/build/pkgs/rw/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/rw/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/saclib/dependencies b/build/pkgs/saclib/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/saclib/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/symmetrica/dependencies b/build/pkgs/symmetrica/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/symmetrica/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/sympow/dependencies b/build/pkgs/sympow/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/sympow/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/termcap/dependencies b/build/pkgs/termcap/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/termcap/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/valgrind/dependencies b/build/pkgs/valgrind/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/valgrind/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/zeromq/dependencies b/build/pkgs/zeromq/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/zeromq/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/zlib/dependencies b/build/pkgs/zlib/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/zlib/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. From d4cc95be16dcf1b402bea40ae73f83833487b8ce Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 21 Sep 2015 14:17:54 -0700 Subject: [PATCH 0937/1872] addressing referee's remarks --- src/sage/combinat/designs/block_design.py | 8 +-- .../graphs/generators/classical_geometries.py | 49 ++++++++++--------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index d516efce18e..a34356d25eb 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -165,7 +165,7 @@ def are_hyperplanes_in_projective_geometry_parameters(v, k, lmbda, return_parame return (True, (q,d)) if return_parameters else True -def ProjectiveGeometryDesign(n, d, F, algorithm=None, coordinates=None, check=True): +def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=False, check=True): """ Return a projective geometry design. @@ -188,7 +188,7 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, coordinates=None, check=Tr GAP's "design" package must be available in this case, and that it can be installed with the ``gap_packages`` spkg. - - ``coordinates`` -- ``None`` by default. In this case and also if + - ``point_coordinates`` -- ``False`` by default. In this case and also if ``algorithm="gap"``, the ground set is indexed by integers, Otherwise it is indexed by coordinates in `F^{n+1}`. @@ -209,7 +209,7 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, coordinates=None, check=Tr Use coordinates:: - sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3),coordinates=1) + sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3),point_coordinates=1) sage: PG.blocks()[0] [(1, 0, 0), (1, 0, 1), (1, 0, 2), (0, 0, 1)] @@ -235,7 +235,7 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, coordinates=None, check=Tr b.append(points[m]) blocks.append(b) B = BlockDesign(len(points), blocks, name="ProjectiveGeometryDesign", check=check) - if not coordinates is None: + if point_coordinates: B.relabel({i:p[0] for p,i in points.iteritems()}) return B if algorithm == "gap": # Requires GAP's Design diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index ad34b7be04f..defb5e6ae37 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -739,7 +739,7 @@ def UnitaryDualPolarGraph(m, q): EXAMPLES: - The point graph of a generalized quadrangle of order (8,4):: + The point graph of a generalized quadrangle (see [GQwiki]_, [PT09]_) of order (8,4):: sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices @@ -940,14 +940,8 @@ def AhrensSzekeresGQ(q, dual=False): r""" Return the collinearity graph of GQ AS(q) or its dual - INPUT: - - - ``q`` -- a power of an odd prime number - - - ``dual`` -- if ``False`` (default), return the graph of `GQ(q-1,q+1)`. - Otherwise return the graph of `GQ(q+1,q-1)`. - - `AS(q)` is a generalised quadrangle (GQ) of order `(q-1,q+1)`, see 3.1.5 in [PT09]_. + `AS(q)` is a generalised quadrangle (GQ, see [GQwiki]_) of order `(q-1,q+1)`, + see 3.1.5 in [PT09]_. Let `q` be an odd prime power. Then the points are elements of `F_q^3`, and lines are of the form @@ -957,6 +951,13 @@ def AhrensSzekeresGQ(q, dual=False): where `a`, `b`, `c` are arbitrary elements of `F_q`. + INPUT: + + - ``q`` -- a power of an odd prime number + + - ``dual`` -- if ``False`` (default), return the graph of `GQ(q-1,q+1)`. + Otherwise return the graph of `GQ(q+1,q-1)`. + EXAMPLES:: sage: g=graphs.AhrensSzekeresGQ(5); g @@ -970,6 +971,9 @@ def AhrensSzekeresGQ(q, dual=False): REFERENCE: + .. [GQwiki] `Generalized quadrangle + `__ + .. [PT09] S. Payne, J. A. Thas. Finite generalized quadrangles. European Mathematical Society, @@ -995,10 +999,18 @@ def AhrensSzekeresGQ(q, dual=False): G.name('AS('+str(q)+'); GQ'+str((q-1,q+1))) return G -def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): +def T2starGQ(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): r""" Return the collinearity graph of GQ T_2*(q) or its dual + `T_2^*(q)` is a generalised quadrangle (GQ, see [GQwiki]_) + of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. + Let `q=2^k` and `\Theta=PG(3,q)`. Fix a plane `\Pi \subset \Theta` and a + `hyperoval `__ + `O \subset \Pi`. The points of the GQ are the points of `\Theta` + outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi` + that meet `\Pi` in a point of `O`. + INPUT: - ``q`` -- a power of two @@ -1015,16 +1027,9 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): - ``field`` -- an instance of a finite field of order `q`, must be provided if ``hyperoval`` is provided. - - ``checkhyperoval`` -- (default: ``False``) if ``True``, + - ``check_hyperoval`` -- (default: ``True``) if ``True``, check ``hyperoval`` for correctness. - `T_2^*(q)` is a generalised quadrangle (GQ) of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. - Let `q=2^k` and `\Theta=PG(3,q)`. Fix a plane `\Pi \subset \Theta` and a - `hyperoval `__ - `O \subset \Pi`. The points of the GQ are the points of `\Theta` - outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi` - that meet `\Pi` in a point of `O`. - EXAMPLES: @@ -1052,12 +1057,12 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): sage: F=GF(4,'b') # repeating a point... sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) - sage: graphs.T2starGQ(4, hyperoval=O, field=F, checkhyperoval=True) + sage: graphs.T2starGQ(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) - sage: graphs.T2starGQ(4, hyperoval=O, field=F, checkhyperoval=True) + sage: graphs.T2starGQ(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval @@ -1074,7 +1079,7 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): else: F = field - Theta = PG(3,1,F,coordinates=1) + Theta = PG(3, 1, F, point_coordinates=1) Pi = set(filter(lambda x: x[0]==F.zero(), Theta.ground_set())) if hyperoval is None: O = filter(lambda x: x[1]+x[2]*x[3]==0 or (x[1]==1 and x[2]==0 and x[3]==0), Pi) @@ -1083,7 +1088,7 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, checkhyperoval=False): map(lambda x: x.set_immutable(), hyperoval) O = set(hyperoval) - if checkhyperoval: + if check_hyperoval and (not hyperoval is None): if len(O) != q+2: raise RuntimeError("incorrect hyperoval size") for L in Theta.blocks(): From 2a62ef16861fb421358f3d5f636cc9fc97e59011 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 21 Sep 2015 23:11:09 -0700 Subject: [PATCH 0938/1872] further doc fixes --- .../graphs/generators/classical_geometries.py | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index defb5e6ae37..28fd7c71831 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -938,16 +938,15 @@ def TaylorTwographSRG(q): def AhrensSzekeresGQ(q, dual=False): r""" - Return the collinearity graph of GQ AS(q) or its dual + Return the collinearity graph of the generalized quadrangle `AS(q)`, or of its dual - `AS(q)` is a generalised quadrangle (GQ, see [GQwiki]_) of order `(q-1,q+1)`, - see 3.1.5 in [PT09]_. - Let `q` be an odd prime power. Then the points are elements of `F_q^3`, - and lines are of the form + Let `q` be an odd prime power. `AS(q)` is a generalized quadrangle [GQwiki]_ of + order `(q-1,q+1)`, see 3.1.5 in [PT09]_. Its points are elements + of `F_q^3`, and lines are sets of size `q` of the form - * `(\sigma, a, b), \sigma\in F_q` - * `(a, \sigma, b), \sigma\in F_q` - * `(c \sigma^2 - b \sigma + a, -2 c \sigma + b, \sigma), \sigma\in F_q` + * `\{ (\sigma, a, b) \mid \sigma\in F_q \}` + * `\{ (a, \sigma, b) \mid \sigma\in F_q \}` + * `\{ (c \sigma^2 - b \sigma + a, -2 c \sigma + b, \sigma) \mid \sigma\in F_q \}`, where `a`, `b`, `c` are arbitrary elements of `F_q`. @@ -955,8 +954,8 @@ def AhrensSzekeresGQ(q, dual=False): - ``q`` -- a power of an odd prime number - - ``dual`` -- if ``False`` (default), return the graph of `GQ(q-1,q+1)`. - Otherwise return the graph of `GQ(q+1,q-1)`. + - ``dual`` -- if ``False`` (default), return the collinearity graph of `GQ(q-1,q+1)`. + Otherwise return the collinearity graph of `GQ(q+1,q-1)`. EXAMPLES:: @@ -1001,13 +1000,12 @@ def AhrensSzekeresGQ(q, dual=False): def T2starGQ(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): r""" - Return the collinearity graph of GQ T_2*(q) or its dual + Return the collinearity graph of the generalized quadrangle `T_2*(q)`, or of its dual - `T_2^*(q)` is a generalised quadrangle (GQ, see [GQwiki]_) - of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. - Let `q=2^k` and `\Theta=PG(3,q)`. Fix a plane `\Pi \subset \Theta` and a + Let `q=2^k` and `\Theta=PG(3,q)`. `T_2^*(q)` is a generalised quadrangle [GQwiki]_ + of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. Fix a plane `\Pi \subset \Theta` and a `hyperoval `__ - `O \subset \Pi`. The points of the GQ are the points of `\Theta` + `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of `\Theta` outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi` that meet `\Pi` in a point of `O`. From 6bb228fab7fbd1ccb7b5b9d061dc48bdcdc9409c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 09:30:13 +0200 Subject: [PATCH 0939/1872] use SageObject instead of object --- src/sage/data_structures/mutable_poset.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index bae921007e1..ed21211482d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -155,8 +155,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.structure.sage_object import SageObject -class MutablePosetShell(object): + +class MutablePosetShell(SageObject): r""" A shell for an element of a :class:`mutable poset `. @@ -198,6 +200,7 @@ def __init__(self, poset, element): self._element_ = element self._predecessors_ = set() self._successors_ = set() + super(MutablePosetShell, self).__init__() @property @@ -1100,7 +1103,7 @@ def is_MutablePoset(P): return isinstance(P, MutablePoset) -class MutablePoset(object): +class MutablePoset(SageObject): r""" A data structure that models a mutable poset (partially ordered set). @@ -1227,6 +1230,7 @@ def __init__(self, data=None, key=None, merge=None, can_merge=None): raise TypeError('%s is not iterable; do not know what to ' 'do with it.' % (data,)) self.union_update(it) + super(MutablePoset, self).__init__() def clear(self): From 07591351097bc4c28294ca358fee5c4e0a27b28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 22 Sep 2015 11:20:20 +0300 Subject: [PATCH 0940/1872] Change default of facade to true in order_ideals_lattice(). --- src/sage/categories/finite_posets.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index 06ff1fa25f6..ffddd4bbbb0 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -1678,7 +1678,7 @@ def toggling_orbit_iter(self, vs, oideal, element_constructor=set, stop=True, ch next = self.order_ideal_toggles(next, vs) yield element_constructor(next) - def order_ideals_lattice(self, as_ideals=True, facade=False): + def order_ideals_lattice(self, as_ideals=True, facade=True): r""" Return the lattice of order ideals of a poset ``self``, ordered by inclusion. @@ -1703,7 +1703,7 @@ def order_ideals_lattice(self, as_ideals=True, facade=False): EXAMPLES:: - sage: P = Posets.PentagonPoset(facade = True) + sage: P = Posets.PentagonPoset() sage: P.cover_relations() [[0, 1], [0, 2], [1, 4], [2, 3], [3, 4]] sage: J = P.order_ideals_lattice(); J @@ -1727,8 +1727,11 @@ def order_ideals_lattice(self, as_ideals=True, facade=False): sage: J.cover_relations() [[{}, {0}], [{0}, {0, 2}], [{0}, {0, 1}], [{0, 2}, {0, 1, 2}], [{0, 1}, {0, 1, 2}], [{0, 1, 2}, {0, 1, 2, 3}]] - .. NOTE:: we use facade posets in the examples above just - to ensure a nicer ordering in the output. + sage: P = Poset({1:[2]}) + sage: J_facade = P.order_ideals_lattice() + sage: J_nonfacade = P.order_ideals_lattice(facade=False) + sage: type(J_facade[0]) == type(J_nonfacade[0]) + False """ from sage.combinat.posets.lattices import LatticePoset if as_ideals: From 097ac4e9452facc25f8a11dd1996d101683af825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 22 Sep 2015 11:43:05 +0300 Subject: [PATCH 0941/1872] New default value for facade: None. (=take it from the poset) --- src/sage/categories/finite_posets.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index ffddd4bbbb0..06e741dd0fa 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -1678,7 +1678,7 @@ def toggling_orbit_iter(self, vs, oideal, element_constructor=set, stop=True, ch next = self.order_ideal_toggles(next, vs) yield element_constructor(next) - def order_ideals_lattice(self, as_ideals=True, facade=True): + def order_ideals_lattice(self, as_ideals=True, facade=None): r""" Return the lattice of order ideals of a poset ``self``, ordered by inclusion. @@ -1700,6 +1700,9 @@ def order_ideals_lattice(self, as_ideals=True, facade=True): - ``as_ideals`` -- Boolean, if ``True`` (default) returns a poset on the set of order ideals, otherwise on the set of antichains + - ``facade`` -- Boolean or ``None`` (default). Whether to + return a facade lattice or not. By default return facade + lattice if the poset is a facade poset. EXAMPLES:: @@ -1734,6 +1737,8 @@ def order_ideals_lattice(self, as_ideals=True, facade=True): False """ from sage.combinat.posets.lattices import LatticePoset + if facade is None: + facade = self._is_facade if as_ideals: from sage.misc.misc import attrcall from sage.sets.set import Set From b8a54e6de68b7e3a38c63a348e8ae7d191fd7afa Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 12:44:23 +0200 Subject: [PATCH 0942/1872] move poset-code from sets.cartesian_product to combinat.posets.cartesian_product --- src/sage/combinat/posets/cartesian_product.py | 427 ++++++++++++++++++ src/sage/sets/cartesian_product.py | 413 ----------------- 2 files changed, 427 insertions(+), 413 deletions(-) create mode 100644 src/sage/combinat/posets/cartesian_product.py diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py new file mode 100644 index 00000000000..7dcf2ae0649 --- /dev/null +++ b/src/sage/combinat/posets/cartesian_product.py @@ -0,0 +1,427 @@ +""" +Cartesian products of Posets + +AUTHORS: + +- Daniel Krenn (2015) + +""" +#***************************************************************************** +# Copyright (C) 2015 Daniel Krenn +# +# 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.sets.cartesian_product import CartesianProduct + + +class CartesianProductPosets(CartesianProduct): + r""" + A class implementing cartesian products of posets (and elements + thereof). Compared to :class:`CartesianProduct` you are able to + specify an order for comparison of the elements. + + INPUT: + + - ``sets`` -- a tuple of parents. + + - ``category`` -- a subcategory of + ``Sets().CartesianProducts() & Posets()``. + + - ``order`` -- a string or function specifying an order less or equal. + It can be one of the following: + + - ``'lex'`` -- elements are ordered lexicographically. + + - ``'components'`` -- an element is less or equal to another + element, if less or equal is true for all its components + (cartesian projections). + + - a function ``order_le(left, right)``, which performs the comparison. + + Other keyword arguments (``kwargs``) are passed to the constructor + of :class:`CartesianProduct`. + + EXAMPLES:: + + sage: P = Poset((srange(3), lambda left, right: left <= right)) + sage: Cl = cartesian_product((P, P), order='lex') + sage: Cl((1, 1)) <= Cl((2, 0)) + True + sage: Cc = cartesian_product((P, P), order='components') + sage: Cc((1, 1)) <= Cc((2, 0)) + False + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: Cs = cartesian_product((P, P), order=le_sum) + sage: Cs((1, 1)) <= Cs((2, 0)) + True + + TESTS:: + + sage: Cc.category() + Join of Category of finite posets and + Category of Cartesian products of finite enumerated sets + sage: Cs.category() + Join of Category of finite posets and + Category of Cartesian products of finite enumerated sets + + .. SEEALSO: + + :class:`CartesianProduct` + """ + + def __init__(self, sets, category, order, **kwargs): + r""" + See :class:`CartesianProductPosets` for details. + + TESTS:: + + sage: P = Poset((srange(3), lambda left, right: left <= right)) + sage: Cl = cartesian_product((P, P), order='notexisting') + Traceback (most recent call last): + ... + ValueError: No order 'notexisting' known. + """ + if isinstance(order, str): + try: + self._le_ = getattr(self, 'le_' + order) + except AttributeError: + raise ValueError("No order '%s' known." % (order,)) + else: + self._le_ = order + + super(CartesianProductPosets, self).__init__( + sets, category, **kwargs) + from sage.categories.posets import Posets + self._refine_category_(Posets()) + + + def le(self, left, right): + r""" + Tests if ``left`` is less than or equal to ``right``. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the order defined on creation of this + cartesian product. See :class:`CartesianProductPosets`. + + EXAMPLES:: + + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C.le(C((1/3, 2)), C((2, 1/3))) + True + sage: C.le(C((2, 1/3)), C((1/3, 2))) + False + sage: C.le(C((1/3, 2)), C((2, 2))) + True + sage: C.le(C((2, 2)), C((1/3, 2))) + False + """ + return self._le_(left, right) + + + def le_lex(self, left, right): + r""" + Tests if ``left`` is lexicographically smaller or equal + to ``right``. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: P = Poset((srange(2), lambda left, right: left <= right)) + sage: Q = cartesian_product((P, P), order='lex') + sage: T = [Q((0, 0)), Q((1, 1)), Q((0, 1)), Q((1, 0))] + sage: for a in T: + ....: for b in T: + ....: assert(Q.le(a, b) == (a <= b)) + ....: print '%s <= %s = %s' % (a, b, a <= b) + (0, 0) <= (0, 0) = True + (0, 0) <= (1, 1) = True + (0, 0) <= (0, 1) = True + (0, 0) <= (1, 0) = True + (1, 1) <= (0, 0) = False + (1, 1) <= (1, 1) = True + (1, 1) <= (0, 1) = False + (1, 1) <= (1, 0) = False + (0, 1) <= (0, 0) = False + (0, 1) <= (1, 1) = True + (0, 1) <= (0, 1) = True + (0, 1) <= (1, 0) = True + (1, 0) <= (0, 0) = False + (1, 0) <= (1, 1) = True + (1, 0) <= (0, 1) = False + (1, 0) <= (1, 0) = True + """ + for l, r, S in \ + zip(left.value, right.value, self.cartesian_factors()): + if l == r: + continue + if S.le(l, r): + return True + if S.le(r, l): + return False + return True # equal + + + def le_components(self, left, right): + r""" + Tests if ``left`` is component-wise smaller or equal + to ``right``. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + A boolean. + + The comparison is ``True`` if the result of the + comparision in each component is ``True``. + + EXAMPLES:: + + sage: P = Poset((srange(2), lambda left, right: left <= right)) + sage: Q = cartesian_product((P, P), order='components') + sage: T = [Q((0, 0)), Q((1, 1)), Q((0, 1)), Q((1, 0))] + sage: for a in T: + ....: for b in T: + ....: assert(Q.le(a, b) == (a <= b)) + ....: print '%s <= %s = %s' % (a, b, a <= b) + (0, 0) <= (0, 0) = True + (0, 0) <= (1, 1) = True + (0, 0) <= (0, 1) = True + (0, 0) <= (1, 0) = True + (1, 1) <= (0, 0) = False + (1, 1) <= (1, 1) = True + (1, 1) <= (0, 1) = False + (1, 1) <= (1, 0) = False + (0, 1) <= (0, 0) = False + (0, 1) <= (1, 1) = True + (0, 1) <= (0, 1) = True + (0, 1) <= (1, 0) = False + (1, 0) <= (0, 0) = False + (1, 0) <= (1, 1) = True + (1, 0) <= (0, 1) = False + (1, 0) <= (1, 0) = True + """ + return all( + S.le(l, r) + for l, r, S in + zip(left.value, right.value, self.cartesian_factors())) + + + class Element(CartesianProduct.Element): + + def _le_(self, other): + r""" + Return if this element is less or equal to ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method calls :meth:`CartesianProductPosets.le`. Override + it in inherited class to change this. + + It can be assumed that this element and ``other`` have + the same parent. + + TESTS:: + + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) <= C((2, 1/3)) # indirect doctest + True + sage: C((1/3, 2)) <= C((2, 2)) # indirect doctest + True + """ + return self.parent().le(self, other) + + + def __le__(self, other): + r""" + Return if this element is less than or equal to ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the coercion framework to find a + suitable common parent. + + This method can be deleted once :trac:`10130` is fixed and + provides these methods automatically. + + TESTS:: + + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) <= C((2, 1/3)) + True + sage: C((1/3, 2)) <= C((2, 2)) + True + """ + from sage.structure.element import have_same_parent + if have_same_parent(self, other): + return self._le_(other) + + from sage.structure.element import get_coercion_model + import operator + try: + return get_coercion_model().bin_op(self, other, operator.le) + except TypeError: + return False + + + def __ge__(self, other): + r""" + Return if this element is greater than or equal to ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the coercion framework to find a + suitable common parent. + + This method can be deleted once :trac:`10130` is fixed and + provides these methods automatically. + + TESTS:: + + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) >= C((2, 1/3)) + False + sage: C((1/3, 2)) >= C((2, 2)) + False + """ + return other.__le__(self) + + + def __lt__(self, other): + r""" + Return if this element is less than ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the coercion framework to find a + suitable common parent. + + This method can be deleted once :trac:`10130` is fixed and + provides these methods automatically. + + TESTS:: + + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) < C((2, 1/3)) + True + sage: C((1/3, 2)) < C((2, 2)) + True + """ + return not self == other and self.__le__(other) + + + def __gt__(self, other): + r""" + Return if this element is greater than ``other``. + + INPUT: + + - ``other`` -- an element. + + OUTPUT: + + A boolean. + + .. NOTE:: + + This method uses the coercion framework to find a + suitable common parent. + + This method can be deleted once :trac:`10130` is fixed and + provides these methods automatically. + + TESTS:: + + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: def le_sum(left, right): + ....: return (sum(left) < sum(right) or + ....: sum(left) == sum(right) and left[0] <= right[0]) + sage: C = cartesian_product((QQ, QQ), order=le_sum) + sage: C((1/3, 2)) > C((2, 1/3)) + False + sage: C((1/3, 2)) > C((2, 2)) + False + """ + return not self == other and other.__le__(self) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 8a3fef2e508..ef2a064b44b 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -286,416 +286,3 @@ def __iter__(self): 1 """ return iter(self.value) - - -class CartesianProductPosets(CartesianProduct): - r""" - A class implementing cartesian products of posets (and elements - thereof). Compared to :class:`CartesianProduct` you are able to - specify an order for comparison of the elements. - - INPUT: - - - ``sets`` -- a tuple of parents. - - - ``category`` -- a subcategory of - ``Sets().CartesianProducts() & Posets()``. - - - ``order`` -- a string or function specifying an order less or equal. - It can be one of the following: - - - ``'lex'`` -- elements are ordered lexicographically. - - - ``'components'`` -- an element is less or equal to another - element, if less or equal is true for all its components - (cartesian projections). - - - a function ``order_le(left, right)``, which performs the comparison. - - Other keyword arguments (``kwargs``) are passed to the constructor - of :class:`CartesianProduct`. - - EXAMPLES:: - - sage: P = Poset((srange(3), lambda left, right: left <= right)) - sage: P.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: Cl = cartesian_product((P, P), order='lex') - sage: Cl((1, 1)) <= Cl((2, 0)) - True - sage: Cc = cartesian_product((P, P), order='components') - sage: Cc((1, 1)) <= Cc((2, 0)) - False - sage: def le_sum(left, right): - ....: return (sum(left) < sum(right) or - ....: sum(left) == sum(right) and left[0] <= right[0]) - sage: Cs = cartesian_product((P, P), order=le_sum) - sage: Cs((1, 1)) <= Cs((2, 0)) - True - - TESTS:: - - sage: Cc.category() - Join of Category of finite posets and - Category of Cartesian products of finite enumerated sets - sage: Cs.category() - Join of Category of finite posets and - Category of Cartesian products of finite enumerated sets - - .. SEEALSO: - - :class:`CartesianProduct` - """ - - def __init__(self, sets, category, order, **kwargs): - r""" - See :class:`CartesianProductPosets` for details. - - TESTS:: - - sage: P = Poset((srange(3), lambda left, right: left <= right)) - sage: P.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: Cl = cartesian_product((P, P), order='notexisting') - Traceback (most recent call last): - ... - ValueError: No order 'notexisting' known. - """ - if isinstance(order, str): - try: - self._le_ = getattr(self, 'le_' + order) - except AttributeError: - raise ValueError("No order '%s' known." % (order,)) - else: - self._le_ = order - - super(CartesianProductPosets, self).__init__( - sets, category, **kwargs) - from sage.categories.posets import Posets - self._refine_category_(Posets()) - - - def le(self, left, right): - r""" - Tests if ``left`` is less than or equal to ``right``. - - INPUT: - - - ``left`` -- an element. - - - ``right`` -- an element. - - OUTPUT: - - A boolean. - - .. NOTE:: - - This method uses the order defined on creation of this - cartesian product. See :class:`CartesianProductPosets`. - - EXAMPLES:: - - sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: def le_sum(left, right): - ....: return (sum(left) < sum(right) or - ....: sum(left) == sum(right) and left[0] <= right[0]) - sage: C = cartesian_product((QQ, QQ), order=le_sum) - sage: C.le(C((1/3, 2)), C((2, 1/3))) - True - sage: C.le(C((2, 1/3)), C((1/3, 2))) - False - sage: C.le(C((1/3, 2)), C((2, 2))) - True - sage: C.le(C((2, 2)), C((1/3, 2))) - False - """ - return self._le_(left, right) - - - def le_lex(self, left, right): - r""" - Tests if ``left`` is lexicographically smaller or equal - to ``right``. - - INPUT: - - - ``left`` -- an element. - - - ``right`` -- an element. - - OUTPUT: - - A boolean. - - EXAMPLES:: - - sage: P = Poset((srange(2), lambda left, right: left <= right)) - sage: P.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: Q = cartesian_product((P, P), order='lex') - sage: T = [Q((0, 0)), Q((1, 1)), Q((0, 1)), Q((1, 0))] - sage: for a in T: - ....: for b in T: - ....: assert(Q.le(a, b) == (a <= b)) - ....: print '%s <= %s = %s' % (a, b, a <= b) - (0, 0) <= (0, 0) = True - (0, 0) <= (1, 1) = True - (0, 0) <= (0, 1) = True - (0, 0) <= (1, 0) = True - (1, 1) <= (0, 0) = False - (1, 1) <= (1, 1) = True - (1, 1) <= (0, 1) = False - (1, 1) <= (1, 0) = False - (0, 1) <= (0, 0) = False - (0, 1) <= (1, 1) = True - (0, 1) <= (0, 1) = True - (0, 1) <= (1, 0) = True - (1, 0) <= (0, 0) = False - (1, 0) <= (1, 1) = True - (1, 0) <= (0, 1) = False - (1, 0) <= (1, 0) = True - """ - for l, r, S in \ - zip(left.value, right.value, self.cartesian_factors()): - if l == r: - continue - if S.le(l, r): - return True - if S.le(r, l): - return False - return True # equal - - - def le_components(self, left, right): - r""" - Tests if ``left`` is component-wise smaller or equal - to ``right``. - - INPUT: - - - ``left`` -- an element. - - - ``right`` -- an element. - - OUTPUT: - - A boolean. - - The comparison is ``True`` if the result of the - comparision in each component is ``True``. - - EXAMPLES:: - - sage: P = Poset((srange(2), lambda left, right: left <= right)) - sage: P.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: Q = cartesian_product((P, P), order='components') - sage: T = [Q((0, 0)), Q((1, 1)), Q((0, 1)), Q((1, 0))] - sage: for a in T: - ....: for b in T: - ....: assert(Q.le(a, b) == (a <= b)) - ....: print '%s <= %s = %s' % (a, b, a <= b) - (0, 0) <= (0, 0) = True - (0, 0) <= (1, 1) = True - (0, 0) <= (0, 1) = True - (0, 0) <= (1, 0) = True - (1, 1) <= (0, 0) = False - (1, 1) <= (1, 1) = True - (1, 1) <= (0, 1) = False - (1, 1) <= (1, 0) = False - (0, 1) <= (0, 0) = False - (0, 1) <= (1, 1) = True - (0, 1) <= (0, 1) = True - (0, 1) <= (1, 0) = False - (1, 0) <= (0, 0) = False - (1, 0) <= (1, 1) = True - (1, 0) <= (0, 1) = False - (1, 0) <= (1, 0) = True - """ - return all( - S.le(l, r) - for l, r, S in - zip(left.value, right.value, self.cartesian_factors())) - - - class Element(CartesianProduct.Element): - - def _le_(self, other): - r""" - Return if this element is less or equal to ``other``. - - INPUT: - - - ``other`` -- an element. - - OUTPUT: - - A boolean. - - .. NOTE:: - - This method calls :meth:`CartesianProductPosets.le`. Override - it in inherited class to change this. - - It can be assumed that this element and ``other`` have - the same parent. - - TESTS:: - - sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: def le_sum(left, right): - ....: return (sum(left) < sum(right) or - ....: sum(left) == sum(right) and left[0] <= right[0]) - sage: C = cartesian_product((QQ, QQ), order=le_sum) - sage: C((1/3, 2)) <= C((2, 1/3)) # indirect doctest - True - sage: C((1/3, 2)) <= C((2, 2)) # indirect doctest - True - """ - return self.parent().le(self, other) - - - def __le__(self, other): - r""" - Return if this element is less than or equal to ``other``. - - INPUT: - - - ``other`` -- an element. - - OUTPUT: - - A boolean. - - .. NOTE:: - - This method uses the coercion framework to find a - suitable common parent. - - This method can be deleted once :trac:`10130` is fixed and - provides these methods automatically. - - TESTS:: - - sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: def le_sum(left, right): - ....: return (sum(left) < sum(right) or - ....: sum(left) == sum(right) and left[0] <= right[0]) - sage: C = cartesian_product((QQ, QQ), order=le_sum) - sage: C((1/3, 2)) <= C((2, 1/3)) - True - sage: C((1/3, 2)) <= C((2, 2)) - True - """ - from sage.structure.element import have_same_parent - if have_same_parent(self, other): - return self._le_(other) - - from sage.structure.element import get_coercion_model - import operator - try: - return get_coercion_model().bin_op(self, other, operator.le) - except TypeError: - return False - - - def __ge__(self, other): - r""" - Return if this element is greater than or equal to ``other``. - - INPUT: - - - ``other`` -- an element. - - OUTPUT: - - A boolean. - - .. NOTE:: - - This method uses the coercion framework to find a - suitable common parent. - - This method can be deleted once :trac:`10130` is fixed and - provides these methods automatically. - - TESTS:: - - sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: def le_sum(left, right): - ....: return (sum(left) < sum(right) or - ....: sum(left) == sum(right) and left[0] <= right[0]) - sage: C = cartesian_product((QQ, QQ), order=le_sum) - sage: C((1/3, 2)) >= C((2, 1/3)) - False - sage: C((1/3, 2)) >= C((2, 2)) - False - """ - return other.__le__(self) - - - def __lt__(self, other): - r""" - Return if this element is less than ``other``. - - INPUT: - - - ``other`` -- an element. - - OUTPUT: - - A boolean. - - .. NOTE:: - - This method uses the coercion framework to find a - suitable common parent. - - This method can be deleted once :trac:`10130` is fixed and - provides these methods automatically. - - TESTS:: - - sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: def le_sum(left, right): - ....: return (sum(left) < sum(right) or - ....: sum(left) == sum(right) and left[0] <= right[0]) - sage: C = cartesian_product((QQ, QQ), order=le_sum) - sage: C((1/3, 2)) < C((2, 1/3)) - True - sage: C((1/3, 2)) < C((2, 2)) - True - """ - return not self == other and self.__le__(other) - - - def __gt__(self, other): - r""" - Return if this element is greater than ``other``. - - INPUT: - - - ``other`` -- an element. - - OUTPUT: - - A boolean. - - .. NOTE:: - - This method uses the coercion framework to find a - suitable common parent. - - This method can be deleted once :trac:`10130` is fixed and - provides these methods automatically. - - TESTS:: - - sage: QQ.CartesianProduct = sage.sets.cartesian_product.CartesianProductPosets - sage: def le_sum(left, right): - ....: return (sum(left) < sum(right) or - ....: sum(left) == sum(right) and left[0] <= right[0]) - sage: C = cartesian_product((QQ, QQ), order=le_sum) - sage: C((1/3, 2)) > C((2, 1/3)) - False - sage: C((1/3, 2)) > C((2, 2)) - False - """ - return not self == other and other.__le__(self) From d316db5296f4d1c7e40231e5627c89cb02e5fc20 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 12:44:43 +0200 Subject: [PATCH 0943/1872] set CartesianProduct in category Posets --- src/sage/categories/posets.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index 5dc0113ada8..257a8ebc917 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -683,6 +683,10 @@ def is_antichain_of_poset(self, o): """ return all(not self.lt(x,y) for x in o for y in o) + CartesianProductPosets = LazyImport( + 'sage.combinat.posets.cartesian_product', 'CartesianProductPosets') + CartesianProduct = CartesianProductPosets + class ElementMethods: pass # TODO: implement xy, x>=y appropriately once #10130 is resolved From 3b9a41e9af79a4dadbd59115eb476b0b24a09a1f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 12:50:04 +0200 Subject: [PATCH 0944/1872] rename order 'components' to 'product' --- src/sage/combinat/posets/cartesian_product.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 7dcf2ae0649..78077451ad1 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -36,7 +36,7 @@ class CartesianProductPosets(CartesianProduct): - ``'lex'`` -- elements are ordered lexicographically. - - ``'components'`` -- an element is less or equal to another + - ``'product'`` -- an element is less or equal to another element, if less or equal is true for all its components (cartesian projections). @@ -51,7 +51,7 @@ class CartesianProductPosets(CartesianProduct): sage: Cl = cartesian_product((P, P), order='lex') sage: Cl((1, 1)) <= Cl((2, 0)) True - sage: Cc = cartesian_product((P, P), order='components') + sage: Cc = cartesian_product((P, P), order='product') sage: Cc((1, 1)) <= Cc((2, 0)) False sage: def le_sum(left, right): @@ -191,7 +191,7 @@ def le_lex(self, left, right): return True # equal - def le_components(self, left, right): + def le_product(self, left, right): r""" Tests if ``left`` is component-wise smaller or equal to ``right``. @@ -212,7 +212,7 @@ def le_components(self, left, right): EXAMPLES:: sage: P = Poset((srange(2), lambda left, right: left <= right)) - sage: Q = cartesian_product((P, P), order='components') + sage: Q = cartesian_product((P, P), order='product') sage: T = [Q((0, 0)), Q((1, 1)), Q((0, 1)), Q((1, 0))] sage: for a in T: ....: for b in T: From 3b3b2fb607a6fe8b20419170bf935d494af1efca Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 22 Sep 2015 13:24:11 +0200 Subject: [PATCH 0945/1872] object --> SageObject --- src/sage/data_structures/mutable_poset.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index bae921007e1..daf731cd188 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -155,8 +155,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.structure.sage_object import SageObject -class MutablePosetShell(object): + +class MutablePosetShell(SageObject): r""" A shell for an element of a :class:`mutable poset `. @@ -1100,7 +1102,7 @@ def is_MutablePoset(P): return isinstance(P, MutablePoset) -class MutablePoset(object): +class MutablePoset(SageObject): r""" A data structure that models a mutable poset (partially ordered set). From c0f27c3c0e12740ff4848444be88e608bc527b88 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 13:40:47 +0200 Subject: [PATCH 0946/1872] define default order=product --- src/sage/combinat/posets/cartesian_product.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 78077451ad1..cc33a50c456 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -75,7 +75,7 @@ class CartesianProductPosets(CartesianProduct): :class:`CartesianProduct` """ - def __init__(self, sets, category, order, **kwargs): + def __init__(self, sets, category, order=None, **kwargs): r""" See :class:`CartesianProductPosets` for details. @@ -87,7 +87,9 @@ def __init__(self, sets, category, order, **kwargs): ... ValueError: No order 'notexisting' known. """ - if isinstance(order, str): + if order is None: + self._le_ = self.le_product + elif isinstance(order, str): try: self._le_ = getattr(self, 'le_' + order) except AttributeError: From e87db1a0f635bb81e3510dfa7ca1617e31462380 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 13:41:04 +0200 Subject: [PATCH 0947/1872] rewrite (simplify) join of category --- src/sage/combinat/posets/cartesian_product.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index cc33a50c456..598b2a55bab 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -97,10 +97,10 @@ def __init__(self, sets, category, order=None, **kwargs): else: self._le_ = order + from sage.categories.posets import Posets + category = category & Posets() super(CartesianProductPosets, self).__init__( sets, category, **kwargs) - from sage.categories.posets import Posets - self._refine_category_(Posets()) def le(self, left, right): From 5f54aecc2a188ccf2711946c655c271386ae32c6 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 22 Sep 2015 13:57:21 +0200 Subject: [PATCH 0948/1872] explicitly forbid coercion from MutablePoset into the AsymptoticRing --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index acc42983787..c72b8482677 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1017,6 +1017,9 @@ def _coerce_map_from_(self, R): sage: AR_QQ.has_coerce_map_from(ZZ) True """ + from sage.data_structures.mutable_poset import MutablePoset + if R == MutablePoset: + return if self.coefficient_ring.has_coerce_map_from(R): return True elif isinstance(R, AsymptoticRing): From 6714aaaf749e2618e44fba307c0e0a389a4e73c1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 15:48:31 +0200 Subject: [PATCH 0949/1872] add comment pointing to #19269 in doctests using QQ as poset --- src/sage/combinat/posets/cartesian_product.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 598b2a55bab..a5535980736 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -124,7 +124,7 @@ def le(self, left, right): EXAMPLES:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -267,7 +267,7 @@ def _le_(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -302,7 +302,7 @@ def __le__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -346,7 +346,7 @@ def __ge__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -381,7 +381,7 @@ def __lt__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -416,7 +416,7 @@ def __gt__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) From 7bc65a7dbba9451510759e5575f70ac4a52e3587 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 22 Sep 2015 16:22:22 +0200 Subject: [PATCH 0950/1872] base_ring --> base_ring() --- src/sage/rings/asymptotic/term_monoid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 560153707ef..f13b8253f4f 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2075,7 +2075,7 @@ def some_elements(self): """ return iter(self(g, c) for g, c in product_diagonal( self.growth_group.some_elements(), - iter(c for c in self.base_ring.some_elements() if c != 0))) + iter(c for c in self.base_ring().some_elements() if c != 0))) class ExactTerm(TermWithCoefficient): From 298773edaa680205c4f7cccd1840f5ee28a63e3f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 17:08:29 +0200 Subject: [PATCH 0951/1872] explain keyword order better --- src/sage/combinat/posets/cartesian_product.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index a5535980736..4253a23b5e8 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -40,7 +40,8 @@ class CartesianProductPosets(CartesianProduct): element, if less or equal is true for all its components (cartesian projections). - - a function ``order_le(left, right)``, which performs the comparison. + - A function which performs the comparison `\leq`. It takes two + input arguments and outputs a boolean. Other keyword arguments (``kwargs``) are passed to the constructor of :class:`CartesianProduct`. From 08469c7b76adfcd243fce084c1c8f2a94daa058e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 17:12:39 +0200 Subject: [PATCH 0952/1872] add module to reference/combinat docs --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/posets/__init__.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index fddfaab81e4..47cc6fb9aad 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -161,6 +161,7 @@ Comprehensive Module list sage/combinat/permutation_nk sage/combinat/posets/__init__ sage/combinat/posets/all + sage/combinat/posets/cartesian_product sage/combinat/posets/elements sage/combinat/posets/hasse_diagram sage/combinat/posets/incidence_algebras diff --git a/src/sage/combinat/posets/__init__.py b/src/sage/combinat/posets/__init__.py index fb7d037e33c..16aea997936 100644 --- a/src/sage/combinat/posets/__init__.py +++ b/src/sage/combinat/posets/__init__.py @@ -15,6 +15,8 @@ - :ref:`sage.combinat.posets.incidence_algebras` +- :ref:`sage.combinat.posets.cartesian_product` + - :ref:`sage.combinat.tamari_lattices` - :ref:`sage.combinat.interval_posets` - :ref:`sage.combinat.shard_order` From 98c252fc4bf3e204c5f366115953c12c74bad701 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 17:21:11 +0200 Subject: [PATCH 0953/1872] allow tuples as category --- src/sage/combinat/posets/cartesian_product.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 4253a23b5e8..171eda29b6d 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -83,10 +83,13 @@ def __init__(self, sets, category, order=None, **kwargs): TESTS:: sage: P = Poset((srange(3), lambda left, right: left <= right)) - sage: Cl = cartesian_product((P, P), order='notexisting') + sage: C = cartesian_product((P, P), order='notexisting') Traceback (most recent call last): ... ValueError: No order 'notexisting' known. + sage: C = cartesian_product((P, P), category=(Groups(),)) + sage: C.category() + Join of Category of groups and Category of posets """ if order is None: self._le_ = self.le_product @@ -98,8 +101,11 @@ def __init__(self, sets, category, order=None, **kwargs): else: self._le_ = order + from sage.categories.category import Category from sage.categories.posets import Posets - category = category & Posets() + if not isinstance(category, tuple): + category = (category,) + category = Category.join(category + (Posets(),)) super(CartesianProductPosets, self).__init__( sets, category, **kwargs) From eb711e9cfb42ba6c993e1131da2298f45097e355 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 17:29:33 +0200 Subject: [PATCH 0954/1872] add TestSuite --- src/sage/combinat/posets/cartesian_product.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 171eda29b6d..3ab615560cd 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -52,8 +52,8 @@ class CartesianProductPosets(CartesianProduct): sage: Cl = cartesian_product((P, P), order='lex') sage: Cl((1, 1)) <= Cl((2, 0)) True - sage: Cc = cartesian_product((P, P), order='product') - sage: Cc((1, 1)) <= Cc((2, 0)) + sage: Cp = cartesian_product((P, P), order='product') + sage: Cp((1, 1)) <= Cp((2, 0)) False sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or @@ -64,12 +64,14 @@ class CartesianProductPosets(CartesianProduct): TESTS:: - sage: Cc.category() + sage: Cl.category() Join of Category of finite posets and Category of Cartesian products of finite enumerated sets - sage: Cs.category() + sage: TestSuite(Cl).run() + sage: Cp.category() Join of Category of finite posets and Category of Cartesian products of finite enumerated sets + sage: TestSuite(Cp).run() .. SEEALSO: From ca4a844746ef444eff10808002c022ac6c111cd0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 17:33:57 +0200 Subject: [PATCH 0955/1872] minor rephrase of docstring --- src/sage/combinat/posets/cartesian_product.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 3ab615560cd..9412255c0f4 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -114,7 +114,7 @@ def __init__(self, sets, category, order=None, **kwargs): def le(self, left, right): r""" - Tests if ``left`` is less than or equal to ``right``. + Test whether ``left`` is less than or equal to ``right``. INPUT: @@ -152,7 +152,7 @@ def le(self, left, right): def le_lex(self, left, right): r""" - Tests if ``left`` is lexicographically smaller or equal + Test whether ``left`` is lexicographically smaller or equal to ``right``. INPUT: @@ -204,7 +204,7 @@ def le_lex(self, left, right): def le_product(self, left, right): r""" - Tests if ``left`` is component-wise smaller or equal + Test whether ``left`` is component-wise smaller or equal to ``right``. INPUT: From 693b0bd6b4e5bd6f49afc6db055b066856ae01e5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 17:34:08 +0200 Subject: [PATCH 0956/1872] add a native order option --- src/sage/combinat/posets/cartesian_product.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 9412255c0f4..f6574991fd2 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -34,6 +34,9 @@ class CartesianProductPosets(CartesianProduct): - ``order`` -- a string or function specifying an order less or equal. It can be one of the following: + - ``'native'`` -- elements are ordered by their native ordering, + i.e., the order the wrapped elements (tuples) provide. + - ``'lex'`` -- elements are ordered lexicographically. - ``'product'`` -- an element is less or equal to another @@ -252,6 +255,50 @@ def le_product(self, left, right): zip(left.value, right.value, self.cartesian_factors())) + def le_native(self, left, right): + r""" + Test whether ``left`` is smaller or equal to ``right`` in the order + provided by the elements themselves. + + INPUT: + + - ``left`` -- an element. + + - ``right`` -- an element. + + OUTPUT: + + A boolean. + + EXAMPLES:: + + sage: P = Poset((srange(2), lambda left, right: left <= right)) + sage: Q = cartesian_product((P, P), order='native') + sage: T = [Q((0, 0)), Q((1, 1)), Q((0, 1)), Q((1, 0))] + sage: for a in T: + ....: for b in T: + ....: assert(Q.le(a, b) == (a <= b)) + ....: print '%s <= %s = %s' % (a, b, a <= b) + (0, 0) <= (0, 0) = True + (0, 0) <= (1, 1) = True + (0, 0) <= (0, 1) = True + (0, 0) <= (1, 0) = True + (1, 1) <= (0, 0) = False + (1, 1) <= (1, 1) = True + (1, 1) <= (0, 1) = False + (1, 1) <= (1, 0) = False + (0, 1) <= (0, 0) = False + (0, 1) <= (1, 1) = True + (0, 1) <= (0, 1) = True + (0, 1) <= (1, 0) = True + (1, 0) <= (0, 0) = False + (1, 0) <= (1, 1) = True + (1, 0) <= (0, 1) = False + (1, 0) <= (1, 0) = True + """ + return left.value <= right.value + + class Element(CartesianProduct.Element): def _le_(self, other): From f3b1387b378ce406e04c6f45c6629595a46640c8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 22 Sep 2015 17:42:17 +0200 Subject: [PATCH 0957/1872] use Posets.ChainPosets in a doctest --- src/sage/combinat/posets/cartesian_product.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index f6574991fd2..4a68fe27db7 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -136,18 +136,18 @@ def le(self, left, right): EXAMPLES:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed + sage: P = Posets.ChainPoset(10) sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) - sage: C = cartesian_product((QQ, QQ), order=le_sum) - sage: C.le(C((1/3, 2)), C((2, 1/3))) + sage: C = cartesian_product((P, P), order=le_sum) + sage: C.le(C((1, 6)), C((6, 1))) True - sage: C.le(C((2, 1/3)), C((1/3, 2))) + sage: C.le(C((6, 1)), C((1, 6))) False - sage: C.le(C((1/3, 2)), C((2, 2))) + sage: C.le(C((1, 6)), C((6, 6))) True - sage: C.le(C((2, 2)), C((1/3, 2))) + sage: C.le(C((6, 6)), C((1, 6))) False """ return self._le_(left, right) From bfe6b60683f8e6a3f7024cdee6f48e4607db389a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 22 Sep 2015 11:00:51 -0500 Subject: [PATCH 0958/1872] Fixing documtation. --- src/sage/algebras/free_zinbiel_algebra.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index 55e0d266702..6d0b6497c2c 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -76,7 +76,7 @@ class FreeZinbielAlgebra(CombinatorialFreeModule): .. MATH:: (x_0 x_1 \cdots x_p) \circ (x_{p+1} x_{p+2} \cdots x_{p+q}) - = \sum_{\simga \in S_{p,q}} x_0 (x_{\sigma(1)} x_{\sigma(2)} + = \sum_{\sigma \in S_{p,q}} x_0 (x_{\sigma(1)} x_{\sigma(2)} \cdots x_{\sigma(p+q)}, where `S_{p,q}` is the set of `(p,q)`-shuffles. @@ -135,6 +135,7 @@ class FreeZinbielAlgebra(CombinatorialFreeModule): REFERENCES: - :wikipedia:`Zinbiel_algebra` + .. [Loday95] Jean-Louis Loday. *Cup-product for Leibniz cohomology and dual Leibniz algebras*. Math. Scand., pp. 189--196 (1995). From 2b7736294074261e90e184ddd454b928833e160e Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 22 Sep 2015 10:43:57 -0700 Subject: [PATCH 0959/1872] changed the default of point_coordinates, added a doctest --- src/sage/combinat/designs/block_design.py | 16 +++++++++++----- .../combinat/designs/incidence_structures.py | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index a34356d25eb..ce1fc319b8c 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -165,7 +165,7 @@ def are_hyperplanes_in_projective_geometry_parameters(v, k, lmbda, return_parame return (True, (q,d)) if return_parameters else True -def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=False, check=True): +def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, check=True): """ Return a projective geometry design. @@ -188,9 +188,9 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=False, c GAP's "design" package must be available in this case, and that it can be installed with the ``gap_packages`` spkg. - - ``point_coordinates`` -- ``False`` by default. In this case and also if - ``algorithm="gap"``, the ground set is indexed by integers, - Otherwise it is indexed by coordinates in `F^{n+1}`. + - ``point_coordinates`` -- ``True`` by default. Ignored and assumed to be ``False`` if + ``algorithm="gap"``. If ``True``, the ground set is indexed by coordinates in `F^{n+1}`. + Otherwise the ground set is indexed by integers, EXAMPLES: @@ -209,10 +209,16 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=False, c Use coordinates:: - sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3),point_coordinates=1) + sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3)) sage: PG.blocks()[0] [(1, 0, 0), (1, 0, 1), (1, 0, 2), (0, 0, 1)] + Use indexing by integers:: + + sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3),point_coordinates=0) + sage: PG.blocks()[0] + [0, 1, 2, 12] + Check that the constructor using gap also works:: sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm="gap") # optional - gap_packages (design package) diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index b34aae434a3..95af7ec2635 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -398,7 +398,7 @@ def __contains__(self, block): True sage: ["Am", "I", "finally", "done ?"] in IS False - sage: IS = designs.ProjectiveGeometryDesign(3, 1, GF(2)) + sage: IS = designs.ProjectiveGeometryDesign(3, 1, GF(2), point_coordinates=False) sage: [3,8,7] in IS True sage: [3,8,9] in IS From 5e0a6d77628c9637daf180a2e9b0dbdf0a869b4e Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 22 Sep 2015 10:58:57 -0700 Subject: [PATCH 0960/1872] updated is_GQqmqp to make reviewer happier --- src/sage/graphs/strongly_regular_db.pyx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 2c80a283bd9..b5b0e05ab1a 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -918,20 +918,20 @@ def is_GQqmqp(int v,int k,int l,int mu): # v=(s+1)(st+1), k=s(t+1) S=l+1 T=mu-1 + q = (S+T)//2 + p, w = is_prime_power(q, get_data=True) if (v == (S+1)*(S*T+1) and k == S*(T+1) and - (S+T) % 2 == 0): - q = (S+T)/2 - p, k = is_prime_power(q, get_data=True) + q == p**w and + (S+T)/2 == q): if p % 2 == 0: from sage.graphs.generators.classical_geometries import T2starGQ as F else: from sage.graphs.generators.classical_geometries import AhrensSzekeresGQ as F - if k != 0: - if (S,T) == (q-1, q+1): - return (F, q, False) - elif (S,T) == (q+1, q-1): - return (F, q, True) + if (S,T) == (q-1, q+1): + return (F, q, False) + elif (S,T) == (q+1, q-1): + return (F, q, True) @cached_function def is_twograph_descendant_of_srg(int v, int k0, int l, int mu): From 5f5706434f184eafc41ed4c0dad9b76abe1293b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 22 Sep 2015 21:08:16 +0200 Subject: [PATCH 0961/1872] trac #18937 patchbot version 2.4.8 (bugfix) --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index 7cebb66b8e2..0138cd1c8e6 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=be2fcb7039c02f37669f5ea078fb2868730df67c -md5=3ebebd93ce6194dee6263270a6419970 -cksum=2163763617 +sha1=32b2209e7fd8050ee8555cbd9fe695c770850b16 +md5=cffdb67332a325ab801c9f7f15c1b4ee +cksum=2059267430 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index e30309f735e..f041bc6dba2 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.7 +2.4.8 From b5a2fcd90050e59021aef77f1a803aaeb65f4c55 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 22 Sep 2015 22:32:46 -0700 Subject: [PATCH 0962/1872] Graph Graph Graph... --- .../graphs/generators/classical_geometries.py | 18 +++++++-------- src/sage/graphs/graph_generators.py | 8 +++---- src/sage/graphs/strongly_regular_db.pyx | 22 ++++++++++--------- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 28fd7c71831..93b26c39755 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -936,7 +936,7 @@ def TaylorTwographSRG(q): G.name("Taylor two-graph SRG") return G -def AhrensSzekeresGQ(q, dual=False): +def AhrensSzekeresGQGraph(q, dual=False): r""" Return the collinearity graph of the generalized quadrangle `AS(q)`, or of its dual @@ -959,11 +959,11 @@ def AhrensSzekeresGQ(q, dual=False): EXAMPLES:: - sage: g=graphs.AhrensSzekeresGQ(5); g + sage: g=graphs.AhrensSzekeresGQGraph(5); g AS(5); GQ(4, 6): Graph on 125 vertices sage: g.is_strongly_regular(parameters=True) (125, 28, 3, 7) - sage: g=graphs.AhrensSzekeresGQ(5,dual=True); g + sage: g=graphs.AhrensSzekeresGQGraph(5,dual=True); g AS(5)*; GQ(6, 4): Graph on 175 vertices sage: g.is_strongly_regular(parameters=True) (175, 30, 5, 5) @@ -998,7 +998,7 @@ def AhrensSzekeresGQ(q, dual=False): G.name('AS('+str(q)+'); GQ'+str((q-1,q+1))) return G -def T2starGQ(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): +def T2starGQGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): r""" Return the collinearity graph of the generalized quadrangle `T_2*(q)`, or of its dual @@ -1033,11 +1033,11 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): using the built-in construction:: - sage: g=graphs.T2starGQ(4); g + sage: g=graphs.T2starGQGraph(4); g T2*(O,4); GQ(3, 5): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) - sage: g=graphs.T2starGQ(4,dual=True); g + sage: g=graphs.T2starGQGraph(4,dual=True); g T2*(O,4)*; GQ(5, 3): Graph on 96 vertices sage: g.is_strongly_regular(parameters=True) (96, 20, 4, 4) @@ -1046,7 +1046,7 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): sage: F=GF(4,'b') sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) - sage: g=graphs.T2starGQ(4, hyperoval=O, field=F); g + sage: g=graphs.T2starGQGraph(4, hyperoval=O, field=F); g T2*(O,4); GQ(3, 5): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) @@ -1055,12 +1055,12 @@ def T2starGQ(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): sage: F=GF(4,'b') # repeating a point... sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) - sage: graphs.T2starGQ(4, hyperoval=O, field=F) + sage: graphs.T2starGQGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) - sage: graphs.T2starGQ(4, hyperoval=O, field=F) + sage: graphs.T2starGQGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index d6ce9e5c69f..25c012b0bd2 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -235,7 +235,7 @@ def __append_to_doc(methods): __append_to_doc( ["AffineOrthogonalPolarGraph", - "AhrensSzekeresGQ", + "AhrensSzekeresGQGraph", "NonisotropicOrthogonalPolarGraph", "NonisotropicUnitaryPolarGraph", "OrthogonalPolarGraph", @@ -243,7 +243,7 @@ def __append_to_doc(methods): "SymplecticPolarGraph", "TaylorTwographDescendantSRG", "TaylorTwographSRG", - "T2starGQ", + "T2starGQGraph", "UnitaryDualPolarGraph", "UnitaryPolarGraph"]) @@ -1999,7 +1999,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None ########################################################################### import sage.graphs.generators.classical_geometries AffineOrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.AffineOrthogonalPolarGraph) - AhrensSzekeresGQ = staticmethod(sage.graphs.generators.classical_geometries.AhrensSzekeresGQ) + AhrensSzekeresGQGraph = staticmethod(sage.graphs.generators.classical_geometries.AhrensSzekeresGQGraph) NonisotropicOrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph) NonisotropicUnitaryPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.NonisotropicUnitaryPolarGraph) OrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.OrthogonalPolarGraph) @@ -2009,7 +2009,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None TaylorTwographDescendantSRG = \ staticmethod(sage.graphs.generators.classical_geometries.TaylorTwographDescendantSRG) TaylorTwographSRG = staticmethod(sage.graphs.generators.classical_geometries.TaylorTwographSRG) - T2starGQ = staticmethod(sage.graphs.generators.classical_geometries.T2starGQ) + T2starGQGraph = staticmethod(sage.graphs.generators.classical_geometries.T2starGQGraph) UnitaryDualPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.UnitaryDualPolarGraph) UnitaryPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.UnitaryPolarGraph) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index b5b0e05ab1a..3b78d8a7963 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -876,23 +876,23 @@ def is_GQqmqp(int v,int k,int l,int mu): sage: from sage.graphs.strongly_regular_db import is_GQqmqp sage: t = is_GQqmqp(27,10,1,5); t - (, 3, False) + (, 3, False) sage: g = t[0](*t[1:]); g AS(3); GQ(2, 4): Graph on 27 vertices sage: t = is_GQqmqp(45,12,3,3); t - (, 3, True) + (, 3, True) sage: g = t[0](*t[1:]); g AS(3)*; GQ(4, 2): Graph on 45 vertices sage: g.is_strongly_regular(parameters=True) (45, 12, 3, 3) sage: t = is_GQqmqp(16,6,2,2); t - (, 2, True) + (, 2, True) sage: g = t[0](*t[1:]); g T2*(O,2)*; GQ(3, 1): Graph on 16 vertices sage: g.is_strongly_regular(parameters=True) (16, 6, 2, 2) sage: t = is_GQqmqp(64,18,2,6); t - (, 4, False) + (, 4, False) sage: g = t[0](*t[1:]); g T2*(O,4); GQ(3, 5): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) @@ -902,16 +902,16 @@ def is_GQqmqp(int v,int k,int l,int mu): sage: (S,T)=(127,129) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t - (, 128, False) + (, 128, False) sage: (S,T)=(129,127) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t - (, 128, True) + (, 128, True) sage: (S,T)=(124,126) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t - (, 125, False) + (, 125, False) sage: (S,T)=(126,124) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t - (, 125, True) + (, 125, True) sage: t = is_GQqmqp(5,5,5,5); t """ # do we have GQ(s,t)? we must have mu=t+1, s=l+1, @@ -925,9 +925,11 @@ def is_GQqmqp(int v,int k,int l,int mu): q == p**w and (S+T)/2 == q): if p % 2 == 0: - from sage.graphs.generators.classical_geometries import T2starGQ as F + from sage.graphs.generators.classical_geometries\ + import T2starGQGraph as F else: - from sage.graphs.generators.classical_geometries import AhrensSzekeresGQ as F + from sage.graphs.generators.classical_geometries\ + import AhrensSzekeresGQGraph as F if (S,T) == (q-1, q+1): return (F, q, False) elif (S,T) == (q+1, q-1): From 4ac40147cd398c65cb524a8dfe59f7d5060788c6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 23 Sep 2015 09:36:32 +0200 Subject: [PATCH 0963/1872] remove kwargs in CartesianProduct since not needed --- src/sage/sets/cartesian_product.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index ef2a064b44b..b91844303f1 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -53,7 +53,7 @@ class CartesianProduct(UniqueRepresentation, Parent): .. automethod:: _cartesian_product_of_elements """ - def __init__(self, sets, category, flatten=False, **kwargs): + def __init__(self, sets, category, flatten=False): r""" INPUT: @@ -77,11 +77,8 @@ def __init__(self, sets, category, flatten=False, **kwargs): sage: cartesian_product([ZZ, ZZ], blub=None) Traceback (most recent call last): ... - TypeError: unknown parameters: blub + TypeError: __init__() got an unexpected keyword argument 'blub' """ - if kwargs: - raise TypeError('unknown parameters: %s' % - ', '.join(str(k) for k in kwargs.iterkeys())) self._sets = tuple(sets) Parent.__init__(self, category=category) From 8de4188efff6b534e881dbe8e7071f026f47a317 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:16:16 +0200 Subject: [PATCH 0964/1872] Trac #17693: minor language adjustments --- src/sage/data_structures/mutable_poset.py | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index daf731cd188..be2ae5ccc25 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -63,8 +63,9 @@ ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) -It is equipped with a `\leq`-operation which makes `a \leq b` if all -entries of `a` are at most `b`. For example, we have +It is equipped with a `\leq`-operation such that `a \leq b` if all +entries of `a` are at most the corresponding entry of `b`. For +example, we have :: @@ -75,7 +76,7 @@ (True, True, False) The last comparison gives ``False``, since the comparison of the -first component yield `2 \leq 1`. +first component checks whether `2 \leq 1`. Now, let us add such elements to a poset:: @@ -90,7 +91,7 @@ poset((1, 1), (2, 2), (2, 3), (3, 2), (3, 3), (4, 1)) In the representation above, the elements are sorted topologically, -smallest first. This does not show (directly) more structural +smallest first. This does not (directly) show more structural information. We can overcome this and display a "wiring layout" by typing:: @@ -778,7 +779,7 @@ def _iter_depth_first_visit_(self, marked, shell to ``True`` (include in iteration) or ``False`` (do not include). ``None`` is equivalent to a function returning always ``True``. Note that the iteration does not go beyond a - not shell included shell. + not included shell. OUTPUT: @@ -828,7 +829,7 @@ def iter_depth_first(self, reverse=False, key=None, condition=None): shell to ``True`` (include in iteration) or ``False`` (do not include). ``None`` is equivalent to a function returning always ``True``. Note that the iteration does not go beyond a - not shell included shell. + not included shell. OUTPUT: @@ -887,7 +888,7 @@ def _iter_topological_visit_(self, marked, shell to ``True`` (include in iteration) or ``False`` (do not include). ``None`` is equivalent to a function returning always ``True``. Note that the iteration does not go beyond a - not shell included shell. + not included shell. OUTPUT: @@ -937,7 +938,7 @@ def iter_topological(self, reverse=False, key=None, condition=None): shell to ``True`` (include in iteration) or ``False`` (do not include). ``None`` is equivalent to a function returning always ``True``. Note that the iteration does not go beyond a - not shell included shell. + not included shell. OUTPUT: @@ -1043,8 +1044,8 @@ def merge(self, element, check=True, delete=True): ``can_merge``-function of :class:`MutablePoset` determines if the merge is possible. - - ``delete`` -- (default: ``True``) if set, then the passed - element is removed from the poset after the merge. + - ``delete`` -- (default: ``True``) if set, then `element` + is removed from the poset after the merge. OUTPUT: @@ -1125,14 +1126,14 @@ class MutablePoset(SageObject): - ``merge`` -- a function which merges its second argument (an element) to its first (again an element) and returns the result (as an element). If the return value is ``None``, the element is - removed out of the poset. + removed from the poset. This hook is called by :meth:`merge`. Moreover it is used during :meth:`add` when an element (more precisely its key) is already in this poset. ``merge`` is ``None`` (default) is equivalent to ``merge`` - returns its first argument. Note that it is not allowed that the + returning its first argument. Note that it is not allowed that the key of the returning element differs from the key of the first input parameter. @@ -1144,7 +1145,7 @@ class MutablePoset(SageObject): in this poset. ``can_merge`` is ``None`` (default) is equivalent to ``can_merge`` - returns ``True`` in all cases. + returning ``True`` in all cases. OUTPUT: @@ -1857,7 +1858,7 @@ def add(self, element): INPUT: - ``element`` -- an object (hashable and supporting comparison - with the operator ``<=``. + with the operator ``<=``). OUTPUT: From 740852e2897cfb1e4903150f110c8c242ba153f3 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:17:53 +0200 Subject: [PATCH 0965/1872] Trac #17693: command instead of description for short descriptions --- src/sage/data_structures/mutable_poset.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index be2ae5ccc25..3b3fada85ed 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -266,7 +266,7 @@ def predecessors(self, reverse=False): INPUT: - - ``reverse`` -- (default: ``False``) if set, then returns + - ``reverse`` -- (default: ``False``) if set, then return successors instead. OUTPUT: @@ -293,7 +293,7 @@ def successors(self, reverse=False): INPUT: - - ``reverse`` -- (default: ``False``) if set, then returns + - ``reverse`` -- (default: ``False``) if set, then return predecessors instead. OUTPUT: @@ -813,7 +813,7 @@ def _iter_depth_first_visit_(self, marked, def iter_depth_first(self, reverse=False, key=None, condition=None): r""" - Iterates over all shells in depth first order. + Iterate over all shells in depth first order. INPUT: @@ -922,7 +922,7 @@ def _iter_topological_visit_(self, marked, def iter_topological(self, reverse=False, key=None, condition=None): r""" - Iterates over all shells in topological order. + Iterate over all shells in topological order. INPUT: @@ -1090,7 +1090,7 @@ def merge(self, element, check=True, delete=True): def is_MutablePoset(P): r""" - Tests if ``P`` inherits from :class:`MutablePoset`. + Test whether ``P`` inherits from :class:`MutablePoset`. TESTS:: @@ -1463,7 +1463,7 @@ def _copy_shells_(self, other, mapping): def copy(self, mapping=None): r""" - Creates a shallow copy. + Create a shallow copy. INPUT: @@ -1822,7 +1822,7 @@ def repr_full(self, reverse=False): def contains(self, key): r""" - Tests if ``key`` is encapsulated by one of the poset's elements. + Test whether ``key`` is encapsulated by one of the poset's elements. INPUT: From 347656c7dec2fef3ed8f43c5f24e5ade977b35f3 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:18:53 +0200 Subject: [PATCH 0966/1872] Trac #17693: language adjustment: whether instead of if --- src/sage/data_structures/mutable_poset.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3b3fada85ed..7fe73a0c7e2 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -316,7 +316,7 @@ def successors(self, reverse=False): def is_special(self): r""" - Return if this shell contains either the null-element, i.e., the + Return whether this shell contains either the null-element, i.e., the element smaller than any possible other element or the infinity-element, i.e., the element larger than any possible other element. @@ -343,7 +343,7 @@ def is_special(self): def is_null(self): r""" - Return if this shell contains the null-element, i.e., the element + Return whether this shell contains the null-element, i.e., the element smaller than any possible other element. OUTPUT: @@ -364,7 +364,7 @@ def is_null(self): def is_oo(self): r""" - Return if this shell contains the infinity-element, i.e., the element + Return whether this shell contains the infinity-element, i.e., the element larger than any possible other element. OUTPUT: @@ -570,7 +570,7 @@ def eq(self, other): This method compares the keys of the elements contained in the shells, if the elements are not both ``None``. - Otherwise, this method checks if both shells describe the + Otherwise, this method checks whether both shells describe the same special element. TESTS:: @@ -1042,7 +1042,7 @@ def merge(self, element, check=True, delete=True): - ``check`` -- (default: ``True``) if set, then the ``can_merge``-function of :class:`MutablePoset` determines - if the merge is possible. + whether the merge is possible. - ``delete`` -- (default: ``True``) if set, then `element` is removed from the poset after the merge. @@ -1137,7 +1137,7 @@ class MutablePoset(SageObject): key of the returning element differs from the key of the first input parameter. - - ``can_merge`` -- a function which checks if its second argument + - ``can_merge`` -- a function which checks whether its second argument can be merged to its first. This hook is called by :meth:`merge`. Moreover it is used during @@ -2623,7 +2623,7 @@ def symmetric_difference_update(self, other): def is_disjoint(self, other): r""" - Return if another poset is disjoint to this poset. + Return whether another poset is disjoint to this poset. INPUT: @@ -2665,7 +2665,7 @@ def is_disjoint(self, other): def is_subset(self, other): r""" - Return if another poset contains this poset, i.e., if this poset + Return whether another poset contains this poset, i.e., whether this poset is a subset of the other poset. INPUT: @@ -2712,7 +2712,7 @@ def is_subset(self, other): def is_superset(self, other): r""" - Return if this poset contains another poset, i.e., if this poset + Return whether this poset contains another poset, i.e., whether this poset is a superset of the other poset. INPUT: @@ -2780,7 +2780,7 @@ def merge(self, key=None, reverse=False): Nothing. This method tests all (not necessarily direct) successors and - predecessors of the given element if they can be merged with + predecessors of the given element whether they can be merged with the element itself. This is done by the ``can_merge``-function of :class:`MutablePoset`. If this merge is possible, then it is performed by calling :class:`MutablePoset`'s From 4774baac95a8490280253fc3de41a12c896fc6b4 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:20:05 +0200 Subject: [PATCH 0967/1872] Trac #17693: corrections in documentation --- src/sage/data_structures/mutable_poset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 7fe73a0c7e2..bc8c1566bdd 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -560,7 +560,7 @@ def eq(self, other): INPUT: - - ``right`` -- a shell. + - ``other`` -- a shell. OUTPUT: @@ -881,7 +881,7 @@ def _iter_topological_visit_(self, marked, ``True`` searches towards ``'null'``. - ``key`` -- (default: ``None``) a function used for sorting - the direct successors of a shell (used in case of a + the direct predecessors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. - ``condition`` -- (default: ``None``) a function mapping a @@ -931,7 +931,7 @@ def iter_topological(self, reverse=False, key=None, condition=None): ``True`` searches towards ``'null'``. - ``key`` -- (default: ``None``) a function used for sorting - the direct successors of a shell (used in case of a + the direct predeccessors of a shell (used in case of a tie). If this is ``None``, no sorting occurs. - ``condition`` -- (default: ``None``) a function mapping a From fe5d2f1dec3f35eeaf2a4e525e4fe3e9807d17a7 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:20:23 +0200 Subject: [PATCH 0968/1872] Trac #17693: additional doctest --- src/sage/data_structures/mutable_poset.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index bc8c1566bdd..df363c4d911 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -579,6 +579,7 @@ def eq(self, other): sage: P = MP() sage: from sage.data_structures.mutable_poset import MutablePosetShell sage: e = MutablePosetShell(P, (1, 2)) + sage: f = MutablePosetShell(P, (2, 1)) sage: z = P.null sage: oo = P.oo sage: z == z @@ -587,6 +588,8 @@ def eq(self, other): True sage: e == e True + sage: e == f + False sage: z == e False sage: e == oo From e4f1fea624a794d32d2e3380a8eb42ee6888af4f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:21:01 +0200 Subject: [PATCH 0969/1872] Trac #17693: fix indentations and whitespace --- src/sage/data_structures/mutable_poset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index df363c4d911..c8228185c12 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -676,7 +676,7 @@ def _search_covers_(self, covers, shell, reverse=False): Note that ``False`` is returned if we do not have ``self <= shell``. - TESTS:: + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: class T(tuple): @@ -979,7 +979,7 @@ def iter_topological(self, reverse=False, key=None, condition=None): :: sage: for e in P.shells_topological(include_special=True, - ....: reverse=True): + ....: reverse=True): ....: print e ....: print list(e.iter_topological(reverse=True, key=repr)) oo @@ -1002,7 +1002,7 @@ def iter_topological(self, reverse=False, key=None, condition=None): :: sage: for e in P.shells_topological(include_special=True, - ....: reverse=True): + ....: reverse=True): ....: print e ....: print list(e.iter_topological(reverse=False, key=repr)) oo @@ -1548,7 +1548,7 @@ def shells_topological(self, include_special=False, - ``include_special`` -- (default: ``False``) if set, then including shells containing a smallest element (`\emptyset`) and a largest element (`\infty`). - + - ``reverse`` -- (default: ``False``) -- if set, reverses the order, i.e., ``False`` gives smallest elements first, ``True`` gives largest first. From 254951dad86ad94fa55c91f3f811497614490493 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:21:40 +0200 Subject: [PATCH 0970/1872] Trac #17693: add keyword in doctest for clarity --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index c8228185c12..8b52bbc4494 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -795,7 +795,7 @@ def _iter_depth_first_visit_(self, marked, sage: P.add(42) sage: P.add(5) sage: marked = set() - sage: list(P.oo._iter_depth_first_visit_(marked, True)) + sage: list(P.oo._iter_depth_first_visit_(marked, reverse=True)) [oo, 42, 5, null] """ if (condition is not None and @@ -904,7 +904,7 @@ def _iter_topological_visit_(self, marked, sage: P.add(42) sage: P.add(5) sage: marked = set() - sage: list(P.null._iter_topological_visit_(marked, True)) + sage: list(P.null._iter_topological_visit_(marked, reverse=True)) [oo, 42, 5, null] """ if (condition is not None and From f7bce7e8aff4e25a23b57d1052ff13df302120e5 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:22:06 +0200 Subject: [PATCH 0971/1872] Trac #17693: remove superfluous doctest --- src/sage/data_structures/mutable_poset.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8b52bbc4494..41192935b46 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1405,7 +1405,6 @@ def get_key(self, element): TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: from sage.data_structures.mutable_poset import MutablePosetShell sage: P = MP() sage: P.get_key(None) is None True From ed96cbcf9d58ab262082d1c8dbac00c8b0af6b5f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:29:43 +0200 Subject: [PATCH 0972/1872] Trac #17693: alternative implementation of covers --- src/sage/data_structures/mutable_poset.py | 63 ++++------------------- 1 file changed, 9 insertions(+), 54 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 41192935b46..01a83adcbc2 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -654,57 +654,6 @@ def _copy_all_linked_(self, memo, poset, mapping): return new - def _search_covers_(self, covers, shell, reverse=False): - r""" - Search for cover shells of this shell. - - This is a helper function for :meth:`covers`. - - INPUT: - - - ``covers`` -- a set which finally contains all covers. - - - ``shell`` -- the shell for which to find the covering shells. - - - ``reverse`` -- (default: ``False``) if not set, then find - the lower covers, otherwise find the upper covers. - - OUTPUT: - - ``True`` or ``False``. - - Note that ``False`` is returned if we do not have - ``self <= shell``. - - TESTS:: - - sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: class T(tuple): - ....: def __le__(left, right): - ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1, 1))) - sage: P.add(T((1, 3, 1))) - sage: P.add(T((2, 1, 2))) - sage: P.add(T((4, 4, 2))) - sage: P.add(T((1, 2, 2))) - sage: P.add(T((2, 2, 2))) - sage: e = P.shell(T((2, 2, 2))); e - (2, 2, 2) - sage: covers = set() - sage: P.null._search_covers_(covers, e) - True - sage: sorted(covers, key=lambda c: repr(c.element)) - [(1, 2, 2), (2, 1, 2)] - """ - if not self.le(shell, reverse) or self == shell: - return False - if not any([e._search_covers_(covers, shell, reverse) - for e in self.successors(reverse)]): - covers.add(self) - return True - - def covers(self, shell, reverse=False): r""" Return the covers of the given shell (considering only @@ -753,9 +702,15 @@ def covers(self, shell, reverse=False): ....: key=lambda c: repr(c.element)) [(4, 4)] """ - covers = set() - self._search_covers_(covers, shell, reverse) - return covers + if self == shell: + return set() + covers = set().union(*(e.covers(shell, reverse) + for e in self.successors(reverse) + if e.le(shell, reverse))) + if covers: + return covers + else: + return set([self]) def _iter_depth_first_visit_(self, marked, From ec15597efaf476e4d1cc822877e77a3ec740d78d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 10:31:40 +0200 Subject: [PATCH 0973/1872] Trac #17693: alternative implementation add --- src/sage/data_structures/mutable_poset.py | 24 ++++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 41192935b46..61d334f77d8 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2008,20 +2008,16 @@ def add(self, element): return new = MutablePosetShell(self, element) - smaller = self.null.covers(new, reverse=False) - larger = self.oo.covers(new, reverse=True) - - # In the following we first search towards oo (reverse=False) and - # then towards null (reverse=True; everything is "inverted"). - for reverse in (False, True): - sm = smaller if not reverse else larger - la = larger if not reverse else smaller - for shell in sm: - for e in shell.successors(reverse).intersection(la): - e.predecessors(reverse).remove(shell) - shell.successors(reverse).remove(e) - new.predecessors(reverse).add(shell) - shell.successors(reverse).add(new) + new._predecessors_ = self.null.covers(new, reverse=False) + new._successors_ = self.oo.covers(new, reverse=True) + + for s in new.predecessors(): + for l in s.successors().intersection(new.successors()): + l.predecessors().remove(s) + s.successors().remove(l) + s.successors().add(new) + for l in new.successors(): + l.predecessors().add(new) self._shells_[key] = new From d0435eb70960ec1755e15b9ac4ac705e009e3c7c Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 23 Sep 2015 10:53:19 +0200 Subject: [PATCH 0974/1872] Replaced import of linear_code module by a lazy_import --- src/sage/coding/all.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 84e1b6e81f5..e753a13d621 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -62,11 +62,12 @@ elias_bound_asymp, mrrw1_bound_asymp) -from linear_code import (LinearCode, LinearCodeFromVectorSpace, - best_known_linear_code, - best_known_linear_code_www, - bounds_minimum_distance, - self_orthogonal_binary_codes) +lazy_import("sage.coding.linear_code", ["LinearCode",\ + "LinearCodeFromVectorSpace",\ + "best_known_linear_code",\ + "best_known_linear_code_www",\ + "bounds_minimum_distance", + "self_orthogonal_binary_codes"]) from sd_codes import self_dual_codes_binary From 42cf082c47cee522e61b4a4067b7c431d0c2268a Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Wed, 23 Sep 2015 05:55:53 -0500 Subject: [PATCH 0975/1872] handle empty matroids --- src/sage/matroids/matroid.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index bd705e8f433..4a879f7e638 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6741,7 +6741,8 @@ cdef class Matroid(SageObject): from sage.matroids.union_matroid import MatroidSum, PartitionMatroid if self.loops(): raise ValueError("Cannot partition matroids with loops.") - + if self.size()==0: + return [set()] # doubling search for minimum independent sets that partitions the groundset n = self.size() r = self.rank() From b8c0cc769e88462e6da06bec09351fd5c30cb69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Wed, 23 Sep 2015 23:07:30 +1200 Subject: [PATCH 0976/1872] Upgrade networkx to 1.10 --- build/pkgs/networkx/checksums.ini | 6 +++--- build/pkgs/networkx/package-version.txt | 2 +- src/sage/graphs/generic_graph.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/pkgs/networkx/checksums.ini b/build/pkgs/networkx/checksums.ini index 50122f00a66..9aaf119a3b8 100644 --- a/build/pkgs/networkx/checksums.ini +++ b/build/pkgs/networkx/checksums.ini @@ -1,4 +1,4 @@ tarball=networkx-VERSION.tar.gz -sha1=d6c1524724d3e47f7621bb2072863463924bfb99 -md5=b4a9e68ecd1b0164446ee432d2e20bd0 -cksum=3256827710 +sha1=99292e464c25be5e96de295752880bf5e5f1848a +md5=eb7a065e37250a4cc009919dacfe7a9d +cksum=2520536431 diff --git a/build/pkgs/networkx/package-version.txt b/build/pkgs/networkx/package-version.txt index a8fdfda1c78..c044b1a3269 100644 --- a/build/pkgs/networkx/package-version.txt +++ b/build/pkgs/networkx/package-version.txt @@ -1 +1 @@ -1.8.1 +1.10 diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b005ae8e4be..4c6305adc27 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -14560,9 +14560,9 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, sage: D.shortest_path(4, 9, algorithm='BFS') [4, 3, 2, 1, 8, 9] sage: D.shortest_path(4, 9, algorithm='Dijkstra_NetworkX') - [4, 3, 2, 1, 8, 9] + [4, 17, 16, 12, 13, 9] sage: D.shortest_path(4, 9, algorithm='Dijkstra_Bid_NetworkX') - [4, 3, 2, 1, 8, 9] + [4, 17, 16, 12, 13, 9] sage: D.shortest_path(4, 9, algorithm='Dijkstra_Bid') [4, 3, 19, 0, 10, 9] sage: D.shortest_path(5, 5) From 3062471726c26fa0727f594f75ad73f26037683b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 23 Sep 2015 14:02:57 +0200 Subject: [PATCH 0977/1872] cross-review changes: use `` instead of ` once --- src/sage/data_structures/mutable_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 7d45fe15260..6731748956d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1048,7 +1048,7 @@ def merge(self, element, check=True, delete=True): ``can_merge``-function of :class:`MutablePoset` determines whether the merge is possible. - - ``delete`` -- (default: ``True``) if set, then `element` + - ``delete`` -- (default: ``True``) if set, then ``element`` is removed from the poset after the merge. OUTPUT: From 9945e9f3d6d7e594ad42bd224f61de3c69df490a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 23 Sep 2015 14:40:02 +0200 Subject: [PATCH 0978/1872] Trac #17693, comment 36, 4: lists instead of .add --- src/sage/data_structures/mutable_poset.py | 267 ++++++---------------- 1 file changed, 76 insertions(+), 191 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 6731748956d..a114273951a 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -49,7 +49,13 @@ We see that they elements are sorted using `\leq` which exists on the integers `\ZZ`. Since this is even a total order, we could have used a -more efficient data structure. +more efficient data structure. Alternativly, we can write +:: + + sage: MP([42, 7, 13, 3]) + poset(3, 7, 13, 42) + +to add several elements at once on construction. A less boring Example @@ -80,14 +86,8 @@ Now, let us add such elements to a poset:: - sage: Q = MP() - sage: Q.add(T((1, 1))) - sage: Q.add(T((3, 3))) - sage: Q.add(T((4, 1))) - sage: Q.add(T((3, 2))) - sage: Q.add(T((2, 3))) - sage: Q.add(T((2, 2))) - sage: Q + sage: Q = MP([T((1, 1)), T((3, 3)), T((4, 1)), + ....: T((3, 2)), T((2, 3)), T((2, 2))]); Q poset((1, 1), (2, 2), (2, 3), (3, 2), (3, 3), (4, 1)) In the representation above, the elements are sorted topologically, @@ -683,13 +683,8 @@ def _search_covers_(self, covers, shell, reverse=False): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1, 1))) - sage: P.add(T((1, 3, 1))) - sage: P.add(T((2, 1, 2))) - sage: P.add(T((4, 4, 2))) - sage: P.add(T((1, 2, 2))) - sage: P.add(T((2, 2, 2))) + sage: P = MP([T((1, 1, 1)), T((1, 3, 1)), T((2, 1, 2)), + ....: T((4, 4, 2)), T((1, 2, 2)), T((2, 2, 2))]) sage: e = P.shell(T((2, 2, 2))); e (2, 2, 2) sage: covers = set() @@ -738,13 +733,8 @@ def covers(self, shell, reverse=False): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: e = P.shell(T((2, 2))); e (2, 2) sage: sorted(P.null.covers(e), @@ -849,13 +839,8 @@ def iter_depth_first(self, reverse=False, key=None, condition=None): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: list(P.null.iter_depth_first(reverse=False, key=repr)) [null, (1, 1), (1, 2), (1, 3), (4, 4), oo, (2, 2), (2, 1)] sage: list(P.oo.iter_depth_first(reverse=True, key=repr)) @@ -969,13 +954,8 @@ def iter_topological(self, reverse=False, key=None, condition=None): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) :: @@ -1062,11 +1042,8 @@ def merge(self, element, check=True, delete=True): ....: return (left[0], ''.join(sorted(left[1] + right[1]))) sage: def can_add(left, right): ....: return left[0] <= right[0] - sage: P = MP(key=lambda c: c[0], merge=add, can_merge=can_add) - sage: P.add((1, 'a')) - sage: P.add((3, 'b')) - sage: P.add((2, 'c')) - sage: P.add((4, 'd')) + sage: P = MP([(1, 'a'), (3, 'b'), (2, 'c'), (4, 'd')], + ....: key=lambda c: c[0], merge=add, can_merge=can_add) sage: P poset((1, 'a'), (2, 'c'), (3, 'b'), (4, 'd')) sage: P.shell(2).merge((3, 'b')) @@ -1443,11 +1420,8 @@ def _copy_shells_(self, other, mapping): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2))]) sage: Q = MP() sage: Q._copy_shells_(P, lambda e: e) sage: P.repr_full() == Q.repr_full() @@ -1483,12 +1457,8 @@ def copy(self, mapping=None): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2))]) sage: Q = copy(P) # indirect doctest sage: P.repr_full() == Q.repr_full() True @@ -1574,13 +1544,8 @@ def shells_topological(self, include_special=False, sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: list(P.shells_topological()) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] sage: list(P.shells_topological(reverse=True)) @@ -1613,10 +1578,7 @@ def elements(self, **kwargs): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3) - sage: P.add(42) - sage: P.add(7) + sage: P = MP([3, 42, 7]) sage: [(v, type(v)) for v in sorted(P.elements())] [(3, ), (7, ), @@ -1657,13 +1619,8 @@ def elements_topological(self, **kwargs): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: [(v, type(v)) for v in P.elements_topological()] [((1, 1), ), ((1, 2), ), @@ -1691,10 +1648,7 @@ def keys(self, **kwargs): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP(key=lambda c: -c) - sage: P.add(3) - sage: P.add(42) - sage: P.add(7) + sage: P = MP([3, 42, 7], key=lambda c: -c) sage: [(v, type(v)) for v in sorted(P.keys())] [(-42, ), (-7, ), @@ -1731,13 +1685,8 @@ def keys_topological(self, **kwargs): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP(key=lambda c: c[0]) - sage: P.add((1, 1)) - sage: P.add((1, 3)) - sage: P.add((2, 1)) - sage: P.add((4, 4)) - sage: P.add((1, 2)) - sage: P.add((2, 2)) + sage: P = MP([(1, 1), (1, 3), (2, 1), (4, 4), (1, 2), (2, 2)], + ....: key=lambda c: c[0]) sage: [(v, type(v)) for v in P.keys_topological()] [(1, ), (2, ), @@ -1874,12 +1823,8 @@ def add(self, element): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2))]) sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (1, 2), (2, 1), (1, 1)) +-- oo @@ -1970,13 +1915,9 @@ def add(self, element): TESTS:: - sage: R = MP(key=lambda k: T(k[2:3])) - sage: R.add((1, 1, 42)) - sage: R.add((1, 3, 42)) - sage: R.add((2, 1, 7)) - sage: R.add((4, 4, 42)) - sage: R.add((1, 2, 7)) - sage: R.add((2, 2, 7)) + sage: R = MP([(1, 1, 42), (1, 3, 42), (2, 1, 7), + ....: (4, 4, 42), (1, 2, 7), (2, 2, 7)], + ....: key=lambda k: T(k[2:3])) sage: print R.repr_full(reverse=True) poset((1, 1, 42), (2, 1, 7)) +-- oo @@ -2052,13 +1993,8 @@ def remove(self, key, raise_key_error=True): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: print P.repr_full(reverse=True) poset((4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)) +-- oo @@ -2112,13 +2048,9 @@ def remove(self, key, raise_key_error=True): TESTS:: - sage: Q = MP(key=lambda k: T(k[0:2])) - sage: Q.add((1, 1, 42)) - sage: Q.add((1, 3, 42)) - sage: Q.add((2, 1, 7)) - sage: Q.add((4, 4, 42)) - sage: Q.add((1, 2, 7)) - sage: Q.add((2, 2, 7)) + sage: Q = MP([(1, 1, 42), (1, 3, 42), (2, 1, 7), + ....: (4, 4, 42), (1, 2, 7), (2, 2, 7)], + ....: key=lambda k: T(k[0:2])) sage: print Q.repr_full(reverse=True) poset((4, 4, 42), (1, 3, 42), (2, 2, 7), (1, 2, 7), (2, 1, 7), (1, 1, 42)) @@ -2224,13 +2156,8 @@ def discard(self, key, raise_key_error=False): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: P.discard(T((1, 2))) sage: P.remove(T((1, 2))) Traceback (most recent call last): @@ -2305,11 +2232,9 @@ def union(self, *other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.union(Q) poset(3, 4, 7, 8, 42) @@ -2353,11 +2278,9 @@ def union_update(self, other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.union_update(Q) sage: P @@ -2406,11 +2329,9 @@ def difference(self, *other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.difference(Q) poset(3, 7) @@ -2452,11 +2373,9 @@ def difference_update(self, other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.difference_update(Q) sage: P @@ -2492,11 +2411,9 @@ def intersection(self, *other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.intersection(Q) poset(42) @@ -2534,11 +2451,9 @@ def intersection_update(self, other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.intersection_update(Q) sage: P @@ -2574,11 +2489,9 @@ def symmetric_difference(self, other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.symmetric_difference(Q) poset(3, 4, 7, 8) @@ -2610,11 +2523,9 @@ def symmetric_difference_update(self, other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.symmetric_difference_update(Q) sage: P @@ -2647,11 +2558,9 @@ def is_disjoint(self, other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.is_disjoint(Q) False @@ -2690,11 +2599,9 @@ def is_subset(self, other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.is_subset(Q) False @@ -2737,11 +2644,9 @@ def is_superset(self, other): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP() - sage: P.add(3); P.add(42); P.add(7); P + sage: P = MP([3, 42, 7]); P poset(3, 7, 42) - sage: Q = MP() - sage: Q.add(4); Q.add(8); Q.add(42); Q + sage: Q = MP([4, 8, 42]); Q poset(4, 8, 42) sage: P.is_superset(Q) False @@ -2803,13 +2708,9 @@ def merge(self, key=None, reverse=False): ....: ''.join(sorted(left[2] + right[2]))) sage: def can_add(left, right): ....: return key(left) >= key(right) - sage: P = MP(key=key, merge=add, can_merge=can_add) - sage: P.add((1, 1, 'a')) - sage: P.add((1, 3, 'b')) - sage: P.add((2, 1, 'c')) - sage: P.add((4, 4, 'd')) - sage: P.add((1, 2, 'e')) - sage: P.add((2, 2, 'f')) + sage: P = MP([(1, 1, 'a'), (1, 3, 'b'), (2, 1, 'c'), + ....: (4, 4, 'd'), (1, 2, 'e'), (2, 2, 'f')], + ....: key=key, merge=add, can_merge=can_add) sage: Q = copy(P) sage: Q.merge(T((1, 3))) sage: print Q.repr_full(reverse=True) @@ -2908,12 +2809,8 @@ def maximal_elements(self): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 1))) - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((1, 2)), T((2, 2))]) sage: list(P.maximal_elements()) [(1, 3), (2, 2)] """ @@ -2940,12 +2837,8 @@ def minimal_elements(self): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: list(P.minimal_elements()) [(1, 2), (2, 1)] """ @@ -2983,12 +2876,8 @@ def map(self, function, topological=False, reverse=False): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: P.map(lambda e: str(e)) sage: P poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') @@ -3024,12 +2913,8 @@ def mapped(self, function): sage: class T(tuple): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) - sage: P = MP() - sage: P.add(T((1, 3))) - sage: P.add(T((2, 1))) - sage: P.add(T((4, 4))) - sage: P.add(T((1, 2))) - sage: P.add(T((2, 2))) + sage: P = MP([T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: P.mapped(lambda e: str(e)) poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') """ From 57457eb26536a776cfd024f3f881f731d14021a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 23 Sep 2015 15:15:24 +0200 Subject: [PATCH 0979/1872] trac #18937 version 2.4.9, forcing the doc to build so that tests can pass --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index 0138cd1c8e6..a5f3f2d4a37 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=32b2209e7fd8050ee8555cbd9fe695c770850b16 -md5=cffdb67332a325ab801c9f7f15c1b4ee -cksum=2059267430 +sha1=f4e1cb57aca1f8225e1c2baca228dccf232c424d +md5=6d67b4ea3c3559135a5edc2c01f776cd +cksum=1760773179 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index f041bc6dba2..3f5987a5cb2 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.8 +2.4.9 From b73b175cbcc8aa8a28a84cfb3466d058406e48c4 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 23 Sep 2015 08:03:25 -0700 Subject: [PATCH 0980/1872] replace GQ by more appropriate things, and remove extra condition in if --- .../graphs/generators/classical_geometries.py | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 93b26c39755..f7e92ae13d5 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -954,8 +954,8 @@ def AhrensSzekeresGQGraph(q, dual=False): - ``q`` -- a power of an odd prime number - - ``dual`` -- if ``False`` (default), return the collinearity graph of `GQ(q-1,q+1)`. - Otherwise return the collinearity graph of `GQ(q+1,q-1)`. + - ``dual`` -- if ``False`` (default), return the collinearity graph of `AS(q)`. + Otherwise return the collinearity graph of the dual `AS(q)`. EXAMPLES:: @@ -1000,7 +1000,7 @@ def AhrensSzekeresGQGraph(q, dual=False): def T2starGQGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): r""" - Return the collinearity graph of the generalized quadrangle `T_2*(q)`, or of its dual + Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual Let `q=2^k` and `\Theta=PG(3,q)`. `T_2^*(q)` is a generalised quadrangle [GQwiki]_ of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. Fix a plane `\Pi \subset \Theta` and a @@ -1013,14 +1013,16 @@ def T2starGQGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=Tru - ``q`` -- a power of two - - ``dual`` -- if ``False`` (default), return the graph of `GQ(q-1,q+1)`. - Otherwise return the graph of `GQ(q+1,q-1)`. + - ``dual`` -- if ``False`` (default), return the graph of `T_2^*(O)`. + Otherwise return the graph of the dual `T_2^*(O)`. - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane meeting every line in 0 or 2 points) in the plane of points with 0th coordinate 0 in `PG(3,q)` over the field ``field``. Each point of ``hyperoval`` must be a length 4 vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and - ``field`` are not specified, and constructed on the fly. + ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval`` + we build is the classical one, i.e. a conic with the point of intersection of its + tangent lines. - ``field`` -- an instance of a finite field of order `q`, must be provided if ``hyperoval`` is provided. @@ -1085,14 +1087,13 @@ def T2starGQGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=Tru else: map(lambda x: x.set_immutable(), hyperoval) O = set(hyperoval) - - if check_hyperoval and (not hyperoval is None): - if len(O) != q+2: - raise RuntimeError("incorrect hyperoval size") - for L in Theta.blocks(): - if set(L).issubset(Pi): - if not len(O.intersection(L)) in [0,2]: - raise RuntimeError("incorrect hyperoval") + if check_hyperoval: + if len(O) != q+2: + raise RuntimeError("incorrect hyperoval size") + for L in Theta.blocks(): + if set(L).issubset(Pi): + if not len(O.intersection(L)) in [0,2]: + raise RuntimeError("incorrect hyperoval") L = map(lambda z: filter(lambda y: not y in O, z), filter(lambda x: len(O.intersection(x)) == 1, Theta.blocks())) if dual: From 605b2dfc685a8eb0e3caf1163a0adad5c47b9f9a Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 23 Sep 2015 10:48:42 -0700 Subject: [PATCH 0981/1872] typo in a graph docstring --- src/sage/graphs/generators/families.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 05efc1dc10b..303383ef39f 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -46,7 +46,7 @@ def JohnsonGraph(n, k): sage: g.is_vertex_transitive() True - The complement of the Johnson graph `J(n,2)` is isomorphic to the Knesser + The complement of the Johnson graph `J(n,2)` is isomorphic to the Kneser Graph `K(n,2)`. In paritcular the complement of `J(5,2)` is isomorphic to the Petersen graph. :: From fac62d77f4a1bc26cdb92140d61c306ab5028636 Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Wed, 23 Sep 2015 13:14:48 -0500 Subject: [PATCH 0982/1872] add test --- src/sage/matroids/matroid.pyx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 4a879f7e638..e7bd6db34eb 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6731,6 +6731,9 @@ cdef class Matroid(SageObject): True sage: sum(map(len,P))==len(M.groundset()) True + sage: from sage.matroids.advanced import * + sage: BasisMatroid().partition() + [set()] ALGORITHM: From 79f01f9100ea8e9d8275ba72e712bcb478343102 Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Wed, 23 Sep 2015 13:20:13 -0500 Subject: [PATCH 0983/1872] should return empty set --- src/sage/matroids/matroid.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index e7bd6db34eb..2a6d7f3d92f 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6733,7 +6733,7 @@ cdef class Matroid(SageObject): True sage: from sage.matroids.advanced import * sage: BasisMatroid().partition() - [set()] + [] ALGORITHM: @@ -6745,7 +6745,7 @@ cdef class Matroid(SageObject): if self.loops(): raise ValueError("Cannot partition matroids with loops.") if self.size()==0: - return [set()] + return [] # doubling search for minimum independent sets that partitions the groundset n = self.size() r = self.rank() From 614d77d52a5c1a5ecce18d5340883f7e4ad1555d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:51:24 +0200 Subject: [PATCH 0984/1872] Trac #17716: insert/fix documentation links --- src/sage/rings/asymptotic/asymptotic_ring.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index c72b8482677..db4eab90633 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -15,7 +15,7 @@ - `O`-terms `O(g)` (see :wikipedia:`Big O notation `; also called *Bachmann--Landau notation*) for some :mod:`growth group - element ` `g` (:ref:`see below + element ` `g` (:ref:`see below `). Examples of such elements can found :ref:`below `. @@ -207,7 +207,7 @@ class AsymptoticExpression(sage.rings.ring_element.RingElement): EXAMPLES: There are several ways to create asymptotic expressions; usually - this is done by using the corresponding rings/parents:: + this is done by using the corresponding :class:`asymptotic rings `:: sage: R_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R_x Asymptotic Ring over Rational Field @@ -993,7 +993,7 @@ def _coerce_map_from_(self, R): There are two possible cases: either ``R`` coerces in the :meth:`coefficient_ring` of this asymptotic ring, or ``R`` itself is an asymptotic ring, where both the - meth:`growth_group` and the :meth:`coefficient_ring` coerce into + :meth:`growth_group` and the :meth:`coefficient_ring` coerce into the :meth:`growth_group` and the :meth:`coefficient_ring` of this asymptotic ring, respectively. @@ -1070,9 +1070,10 @@ def gens(self): .. NOTE:: Generators do not necessarily exist. This depends on the - underlying growth group. For example, monomial growth - groups have a generator, and exponential growth groups - don't. + underlying growth group. For example, + :class:`monomial growth groups ` + have a generator, and exponential growth groups + do not. EXAMPLES:: From b92eb2aaad47de86a91bca52e0c554dd035811e8 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:53:13 +0200 Subject: [PATCH 0985/1872] Trac #17716: minor language issues --- src/sage/rings/asymptotic/asymptotic_ring.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index db4eab90633..8fbd59b77cd 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -18,7 +18,7 @@ element ` `g` (:ref:`see below `). -Examples of such elements can found :ref:`below `. +Examples of such elements can be found :ref:`below `. .. _asymptotic_ring_growth: @@ -27,7 +27,7 @@ The elements of a :mod:`growth group ` are equipped with a partial -ordering and usually contains a variable. Examples are (among many +order and usually contain a variable. Examples are (among many other possibilities) - elements of the form `z^q` for some integer or rational `q` (growth @@ -43,7 +43,7 @@ a^y \cdot y^q` (this corresponds to an element of the growth group ``x^QQ * \log(x)^ZZ * QQ^y * y^QQ``). -The ordering in all these examples is the growth as `x`, `y`, or `z` +The order in all these examples is the growth as `x`, `y`, or `z` (independently) tend to `\infty`. For elements only using the variable `z` this means, `g_1 \leq g_2` if @@ -108,11 +108,11 @@ sage: B.an_element() # not tested -Arithemtical Operations +Arithmetical Operations ----------------------- With the asymptotic rings constructed above (or more precisely with -their elements) we can do a lot of different arithmetical +their elements) we can do a lot of arithmetical calculations. We start our calculations in the ring @@ -349,7 +349,7 @@ def summands(self): def __nonzero__(self): r""" - Return if this asymptotic expression is not identically zero. + Return whether this asymptotic expression is not identically zero. INPUT: @@ -510,7 +510,7 @@ def _sub_(self, other): def _mul_term_(self, term): r""" - Helper method: multiply this asymptotic expression with the + Helper method: multiply this asymptotic expression by the asymptotic term ``term``. INPUT: @@ -537,7 +537,7 @@ def _mul_term_(self, term): def _mul_(self, other): r""" - Multiply ``other`` to this asymptotic expression. + Multiply ``other`` by this asymptotic expression. INPUT: @@ -557,7 +557,7 @@ def _mul_(self, other): .. TODO:: - The current implementation is the school book + The current implementation is the standard long multiplication. More efficient variants like Karatsuba multiplication, or methods that exploit the structure of the underlying poset shall be implemented at a later @@ -978,7 +978,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): def _coerce_map_from_(self, R): r""" - Return if ``R`` coerces into this asymptotic ring. + Return whether ``R`` coerces into this asymptotic ring. INPUT: From 61017c72e6e6c6d56a022616151bc867e67b5624 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:54:29 +0200 Subject: [PATCH 0986/1872] Trac #17716: use next function instead of next method (Python3 compatible) --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 8fbd59b77cd..3e940869800 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -607,7 +607,7 @@ def __pow__(self, power): (P.growth_group, self, power)) from sage.rings.asymptotic.term_monoid import TermWithCoefficient - expr = self.summands.elements().next() + expr = next(self.summands.elements()) if isinstance(expr, TermWithCoefficient): new_growth = expr.growth**power new_coeff = expr.coefficient**power From 0dc81e8cea8a6e7f3cb840069a9cde28d35498f2 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:55:13 +0200 Subject: [PATCH 0987/1872] Trac #17716: language --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 3e940869800..a57ce50f04a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -596,7 +596,7 @@ def __pow__(self, power): from sage.rings.integer_ring import ZZ if power not in ZZ: raise NotImplementedError('Taking the sum %s to the ' - 'non-integer power %s not ' + 'non-integer power %s is not ' 'implemented.' % (self, power)) return super(AsymptoticExpression, self).__pow__(power) From 6f0d60f3bccf90ef0ae1b9b61d6b8b4dcb248bcf Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:55:27 +0200 Subject: [PATCH 0988/1872] Trac #17716: simplified doctest --- src/sage/rings/asymptotic/asymptotic_ring.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index a57ce50f04a..120075c68ee 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1042,9 +1042,8 @@ def _repr_(self): EXAMPLES:: - sage: import sage.rings.asymptotic.growth_group as agg - sage: MG = agg.GrowthGroup('x^ZZ') - sage: AR = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ) + sage: AR = AsymptoticRing(growth_group='x^ZZ', + ....: coefficient_ring=ZZ) sage: repr(AR) # indirect doctest 'Asymptotic Ring over Integer Ring' """ From 8b29f921611e7cfd17a16d4170fc3108c3469131 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:55:58 +0200 Subject: [PATCH 0989/1872] Trac #17716: additional doctests --- src/sage/rings/asymptotic/asymptotic_ring.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 120075c68ee..4f7f6640943 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -591,6 +591,17 @@ def __pow__(self, power): ValueError: Growth Group y^ZZ disallows taking y to the power of 1/7. sage: (x^(1/2) + O(x^0))^15 x^(15/2) + O(x^7) + sage: (y^2+O(y))^(1/2) + Traceback (most recent call last): + ... + NotImplementedError: Taking the sum y^2 + O(y) to the + non-integer power 1/2 is not implemented. + sage: (y^2+O(y))^(-2) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for '/': + 'Asymptotic Ring over Integer Ring' and 'Asymptotic + Ring over Integer Ring' """ if len(self.summands) > 1: from sage.rings.integer_ring import ZZ @@ -635,6 +646,8 @@ def O(self): sage: AR. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) sage: O(x) O(x) + sage: type(O(x)) + sage: expr = 42 * x^42 + x^10 + O(x^2); expr 42*x^42 + x^10 + O(x^2) sage: expr.O() From 451b5e87f82b55f508c8bf95a0d7e62f5c0870ae Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:56:14 +0200 Subject: [PATCH 0990/1872] Trac #17716: PEP8 compliance --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 4f7f6640943..689e1396215 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -402,7 +402,7 @@ def _simplify_(self): sage: G = agg.GrowthGroup('x^ZZ') sage: OT = atm.TermMonoid('O', G); ET = atm.TermMonoid('exact', G, ZZ) sage: R = AsymptoticRing(G, ZZ) - sage: lst = [ET(x,1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] + sage: lst = [ET(x, 1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] sage: expr = R(lst, simplify=False); expr # indirect doctest 4*x^4 + O(x^3) + 2*x^2 + x sage: expr._simplify_(); expr From 7381430a7181eb0e755080a410c63810f242a3a2 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:56:42 +0200 Subject: [PATCH 0991/1872] Trac #17716: "not implemented" instead of "not tested" --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 689e1396215..75c1156f949 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -102,11 +102,11 @@ :: - sage: B. = AsymptoticRing(growth_group='x^QQ * \log(x)^ZZ * QQ^y * y^QQ', coefficient_ring=QQ); B # not tested + sage: B. = AsymptoticRing(growth_group='x^QQ * \log(x)^ZZ * QQ^y * y^QQ', coefficient_ring=QQ); B # not implemented Again, we can look at a typical element:: - sage: B.an_element() # not tested + sage: B.an_element() # not implemented Arithmetical Operations ----------------------- From 9bf196aa9827429847ac2a000d79924d8e365320 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:57:05 +0200 Subject: [PATCH 0992/1872] Trac #17716: fix errors --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 75c1156f949..24473f984d3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -49,7 +49,7 @@ .. MATH:: - \lim_{z\to\infty} \frac{g_2}{g_1} \leq 1. + \lim_{z\to\infty} \frac{g_1}{g_2} \leq 1. .. WARNING:: @@ -92,9 +92,9 @@ -z^(3/2) + O(z^(1/2)) This element consists of two summands: the exact term with coefficient -`-1` and growth `x^{3/2}` and the `O`-term `O(x^{1/2})`. Note that the -growth of `x^{3/2}` is larger than the growth of `x^{1/2}` as -`x\to\infty`, thus this expression cannot be simplified (which would +`-1` and growth `z^{3/2}` and the `O`-term `O(z^{1/2})`. Note that the +growth of `z^{3/2}` is larger than the growth of `z^{1/2}` as +`z\to\infty`, thus this expression cannot be simplified (which would be done automatically, see below). Next, we construct a more sophisticated asymptotic ring in the From a1881013338c835d4bfd808c01d780c94ab4a010 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:57:24 +0200 Subject: [PATCH 0993/1872] Trac #17716: fix TeX errors in docstrings --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 24473f984d3..7cf94d6ee06 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -33,13 +33,13 @@ - elements of the form `z^q` for some integer or rational `q` (growth groups ``z^ZZ`` or ``z^QQ``), -- elements of the form `log(z)^q` for some integer or rational `q` (growth +- elements of the form `\log(z)^q` for some integer or rational `q` (growth groups ``log(z)^ZZ`` or ``log(z)^QQ``), - elements of the form `a^z` for some rational `a` (growth group ``QQ^z``), or -- more sophisticated constructions like products `x^r log(x)^s \cdot +- more sophisticated constructions like products `x^r \log(x)^s \cdot a^y \cdot y^q` (this corresponds to an element of the growth group ``x^QQ * \log(x)^ZZ * QQ^y * y^QQ``). From 4bb745f5d9f796c8485d23536cd456dde8a2201e Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 23 Sep 2015 20:57:40 +0200 Subject: [PATCH 0994/1872] Trac #17716: Heading "Classes and Methods" --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 7cf94d6ee06..43daaee93f7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -174,6 +174,9 @@ - Benjamin Hackl (2015-06): initial version - Benjamin Hackl (2015-07): improvement user interface (short notation) - Daniel Krenn (2015-08): various improvents, review; documentation + +Classes and Methods +=================== """ # ***************************************************************************** From dfa11ac492437cedd686081681fec297404ecf59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Thu, 24 Sep 2015 13:28:48 +1200 Subject: [PATCH 0995/1872] Removing work around for older version of networkx. It gets in the way in newer install. --- build/pkgs/networkx/spkg-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/networkx/spkg-install b/build/pkgs/networkx/spkg-install index 6769f79adac..5cd75ee5791 100755 --- a/build/pkgs/networkx/spkg-install +++ b/build/pkgs/networkx/spkg-install @@ -15,4 +15,4 @@ rm -rf "$SAGE_LOCAL"/spkg/network* cd src -python setup.py install --home="$SAGE_LOCAL" --force +python setup.py install From 2d9dfcdf97ce3b741d181b6f0c6f1f1cc68b880c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Thu, 24 Sep 2015 14:03:36 +1200 Subject: [PATCH 0996/1872] Networkx has a runtime dependency on decorator and may try to install it if not present --- build/pkgs/networkx/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/networkx/dependencies b/build/pkgs/networkx/dependencies index edf27112135..d4db0ff5eae 100644 --- a/build/pkgs/networkx/dependencies +++ b/build/pkgs/networkx/dependencies @@ -1,4 +1,4 @@ -$(INST)/$(PYTHON) +$(INST)/$(PYTHON) $(INST)/$(DECORATOR) ---------- All lines of this file are ignored except the first. From 4f8a84b8f65b917883e46e28b8942ae52dd09b3d Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 24 Sep 2015 13:17:06 +0200 Subject: [PATCH 0997/1872] trac #19279: IncidenceStructure.is_generalized_quadrangle --- .../combinat/designs/incidence_structures.py | 89 +++++++++++++++++++ src/sage/graphs/hypergraph_generators.py | 19 ++++ 2 files changed, 108 insertions(+) diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index b34aae434a3..35ed5b0f068 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1640,6 +1640,95 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): ll = b return (True, (tt,v,k,ll)) if return_parameters else True + def is_generalized_quadrangle(self, verbose=False): + r""" + Test if the incidence structure is a generalized quadrangle. + + An incidence structure is a generalized quadrangle iif: + + - it is `s+1`-:meth:`uniform ` for some positive integer `s`. + + - it is `t+1`-:meth:`regular ` for some positive integer `t`. + + - two blocks intersect on at most one point. + + - For every point `p` not in a block `B`, there is a unique block `B'` + intersecting both `\{p\}` and `B` + + For more information, see the :wikipedia:`Generalized_quadrangle`. + + INPUT: + + - ``verbose`` (boolean) -- whether to print an explanation when the + instance is not a generalized quadrangle. + + EXAMPLE:: + + sage: h = designs.CremonaRichmondConfiguration() + sage: h.is_generalized_quadrangle() + True + + TESTS:: + + sage: H = IncidenceStructure([[1,2],[3,4,5]]) + sage: H.is_generalized_quadrangle(verbose=True) + The incidence structure is not (s+1)-uniform for some s>0. + False + + sage: H = IncidenceStructure([[1,2,3],[3,4,5]]) + sage: H.is_generalized_quadrangle(verbose=True) + The incidence structure is not (t+1)-regular for some t>0. + False + + sage: H = IncidenceStructure((2*graphs.CompleteGraph(3)).edges(labels=False)) + sage: H.is_generalized_quadrangle(verbose=True) + Some point is at distance >3 from some block. + False + + sage: G = graphs.CycleGraph(5) + sage: B = list(G.subgraph_search_iterator(graphs.PathGraph(3))) + sage: H = IncidenceStructure(B) + sage: H.is_generalized_quadrangle(verbose=True) + Two blocks intersect on >1 points. + False + + sage: hypergraphs.CompleteUniform(4,2).is_generalized_quadrangle(verbose=1) + Some point has two projections on some line. + False + """ + s = self.is_uniform()-1 + if not s or s <= 0: + if verbose: + print "The incidence structure is not (s+1)-uniform for some s>0." + return False + + t = self.is_regular()-1 + if not t or t <= 0: + if verbose: + print "The incidence structure is not (t+1)-regular for some t>0." + return False + + # The distance between a point and a line in the incidence graph is odd + # and must be <= 3. Thus, the diameter is at most 4 + g = self.incidence_graph() + if g.diameter() > 4: + if verbose: + print "Some point is at distance >3 from some block." + return False + + # There is a unique projection of a point on a line. Thus, the girth of + # g is at least 7 + girth = g.girth() + if girth == 4: + if verbose: + print "Two blocks intersect on >1 points." + return False + elif girth == 6: + if verbose: + print "Some point has two projections on some line." + return False + return True + def dual(self, algorithm=None): """ Return the dual of the incidence structure. diff --git a/src/sage/graphs/hypergraph_generators.py b/src/sage/graphs/hypergraph_generators.py index 0deb4cbafdd..7dfb9473d99 100644 --- a/src/sage/graphs/hypergraph_generators.py +++ b/src/sage/graphs/hypergraph_generators.py @@ -159,4 +159,23 @@ def nauty(self, number_of_sets, number_of_vertices, yield tuple( tuple( x for x in G.neighbors(v)) for v in range(number_of_vertices, total)) + def CompleteUniform(self, n, k): + r""" + Return the complete `k`-uniform hypergraph on `n` points. + + INPUT: + + - ``k,n`` -- nonnegative integers with `k\leq n` + + EXAMPLE:: + + sage: h = hypergraphs.CompleteUniform(5,2); h + Incidence structure with 5 points and 10 blocks + sage: len(h.packing()) + 2 + """ + from sage.combinat.designs.incidence_structures import IncidenceStructure + from itertools import combinations + return IncidenceStructure(list(combinations(range(n),k))) + hypergraphs = HypergraphGenerators() From 7ab4a0bfb0f42bab0aad673daa9077aadb2ae364 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:00:27 +0200 Subject: [PATCH 0998/1872] Trac #17693, comment 36, 6: rewrite doc of method key --- src/sage/data_structures/mutable_poset.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index a114273951a..c9e3d6601ce 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -243,7 +243,9 @@ def key(self): r""" The key of the element contained in this shell. - The element is converted by the poset to the key. + The key of an element is determined by the mutable poset (the + parent) via the ``key``-function (see construction of a + :class:`MutablePoset`). TESTS:: From 5f7a691c78f34fa815fd904adadbde09041dc6c6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:02:06 +0200 Subject: [PATCH 0999/1872] Trac #17693, comment 36, 7: cache keys --- src/sage/data_structures/mutable_poset.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index c9e3d6601ce..399039d0fab 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -259,8 +259,24 @@ def key(self): sage: f = MutablePosetShell(Q, (1, 2)) sage: f.key 1 + + Test the caching of the key:: + + sage: def k(k): + ....: print 'key %s' % (k,) + ....: return k + sage: R = MP(key=k) + sage: h = MutablePosetShell(R, (1, 2)) + sage: h.key; h.key + key (1, 2) + (1, 2) + (1, 2) """ - return self.poset.get_key(self._element_) + # workaround for #19281 + # (Use @property @cached_method once #19281 is fixed.) + if not hasattr(self, '_cached_key_'): + self._cached_key_ = self.poset.get_key(self._element_) + return self._cached_key_ def predecessors(self, reverse=False): From 60699e1f0906057fdd99b2575f91fbfd0403aef8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:02:34 +0200 Subject: [PATCH 1000/1872] Trac #17693, comment 36, 8: Add a note on special elements in class description --- src/sage/data_structures/mutable_poset.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 399039d0fab..3e18d497fbe 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -174,6 +174,17 @@ class MutablePosetShell(SageObject): A shell for the given element. + .. NOTE:: + + If the :meth:`element` of a shell is ``None``, then this + element is considered as "special" (see :meth:`is_special`). + There are two special elements, namely + + - a ``'null'`` (an element smaller than each other element; + it has no predecessors) and + - a ``'oo'`` (an element larger than each other element; + it has no successors). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 402290906f87257b996d8e4e57a0df72af9cf1ff Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:03:47 +0200 Subject: [PATCH 1001/1872] use _repr_ instead of __repr__ (since we have a SageObject now) --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3e18d497fbe..3fca74ae3a1 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -413,7 +413,7 @@ def is_oo(self): return self.element is None and not self.successors() - def __repr__(self): + def _repr_(self): r""" Return the representation of this shell. @@ -1799,7 +1799,7 @@ def repr_full(self, reverse=False): return '\n'.join(strings) - __repr__ = repr + _repr_ = repr def contains(self, key): From fd292c295f5d6e63737ad0c3657ce3adc4024e4e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:08:43 +0200 Subject: [PATCH 1002/1872] Trac #17693, comment 36, 9: rewrite repr to use is_null and is_oo --- src/sage/data_structures/mutable_poset.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3fca74ae3a1..377d7dabef9 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -445,12 +445,12 @@ def _repr_(self): sage: repr(P.oo) # indirect doctest 'oo' """ - if self.element is None: - if not self.predecessors(): - return 'null' - if not self.successors(): - return 'oo' - return repr(self.element) + if self.is_null(): + return 'null' + elif self.is_oo(): + return 'oo' + else: + return repr(self.element) def __hash__(self): From bf7dfa682c5110912caac4abf6252525b74c1e96 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:10:31 +0200 Subject: [PATCH 1003/1872] Trac #17693, comment 36, 10: simplify note-box --- src/sage/data_structures/mutable_poset.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 377d7dabef9..750a3465da6 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -498,10 +498,7 @@ def le(self, other, reverse=False): The comparison of the shells is based on the comparison of the keys of the elements contained in the shells, - except for the shells containing ``None``. These special - shells are interpreted as smaller or larger than all - other elements, depending on whether they have no - predecessors or no successors, respectively. + except for special shells (see :class:`MutablePosetShell`). TESTS:: From 665692abdab38ce82b2b7786d2d4a96e0ab229e1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:13:14 +0200 Subject: [PATCH 1004/1872] Trac #17693, comment 36, 11: rewrite description of ``reverse`` in le --- src/sage/data_structures/mutable_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 750a3465da6..21278dc252e 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -488,7 +488,7 @@ def le(self, other, reverse=False): - ``other`` -- a shell. - ``reverse`` -- (default: ``False``) if set, then return - ``right <= left`` instead. + whether this shell is greater than or equal to ``other``. OUTPUT: From 104300bbecc327e8cb2ba86c2e7735330c86e975 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:17:43 +0200 Subject: [PATCH 1005/1872] Trac #17693, comment 36, 12: simplify code of le --- src/sage/data_structures/mutable_poset.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 21278dc252e..43137c6ffc8 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -563,18 +563,10 @@ def le(self, other, reverse=False): else: # not null, not oo on the right return False - if other.element is None: - if not other.successors(): - # oo on the right - return True - else: - # null on the right - if self.element is None: - # null or oo on the left - return not self.predecessors() - else: - # not null, not oo on the right - return False + elif other.element is None: + # null/oo on the right + return not other.successors() + return self.key <= other.key From f1b4dffec7099b4e555bd7ec4527e496d8bb26cb Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 24 Sep 2015 19:18:42 +0200 Subject: [PATCH 1006/1872] Trac #19280: add test to mpir's test suite --- build/pkgs/mpir/patches/test-19280.patch | 160 +++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 build/pkgs/mpir/patches/test-19280.patch diff --git a/build/pkgs/mpir/patches/test-19280.patch b/build/pkgs/mpir/patches/test-19280.patch new file mode 100644 index 00000000000..4caf6abdb2d --- /dev/null +++ b/build/pkgs/mpir/patches/test-19280.patch @@ -0,0 +1,160 @@ +diff -ruN mpir-2.7.0/tests/mpz/Makefile.am mpir-2.7.0-patched/tests/mpz/Makefile.am +--- mpir-2.7.0/tests/mpz/Makefile.am 2015-06-09 19:18:27.000000000 +0200 ++++ mpir-2.7.0-patched/tests/mpz/Makefile.am 2015-09-24 18:39:33.093974089 +0200 +@@ -26,7 +26,7 @@ + AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests + LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libmpir.la + +-check_PROGRAMS = bit convert dive dive_ui io logic reuse t-addsub t-aorsmul t-bin t-cdiv_ui t-cmp t-cmp_d t-cmp_si t-cong t-cong_2exp t-div_2exp t-divis t-divis_2exp t-export t-fac_ui t-fdiv t-fdiv_ui t-fib_ui t-fits t-gcd t-gcd_ui t-get_d t-get_d_2exp t-get_si t-get_sx t-get_ux t-hamdist t-import t-inp_str t-io_raw t-jac t-lcm t-likely_prime_p t-lucnum_ui t-mfac_uiui t-mul t-mul_i t-next_prime_candidate t-oddeven t-perfpow t-perfsqr t-popcount t-pow t-powm t-powm_ui t-pprime_p t-primorial_ui t-root t-scan t-set_d t-set_f t-set_si t-set_str t-set_sx t-set_ux t-sizeinbase t-sqrtrem t-tdiv t-tdiv_ui t-trial_division ++check_PROGRAMS = bit convert dive dive_ui io logic reuse t-addsub t-aorsmul t-bin t-cdiv_ui t-cmp t-cmp_d t-cmp_si t-cong t-cong_2exp t-div_2exp t-divis t-divis_2exp t-export t-fac_ui t-fdiv t-fdiv_ui t-fib_ui t-fits t-gcd t-gcd_ui t-get_d t-get_d_2exp t-get_si t-get_sx t-get_ux t-hamdist t-import t-inp_str t-io_raw t-jac t-lcm t-likely_prime_p t-lucnum_ui t-mfac_uiui t-mul t-mul_i t-next_prime_candidate t-oddeven t-perfpow t-perfsqr t-popcount t-pow t-powm t-powm_ui t-pprime_p t-primorial_ui t-root t-scan t-set_d t-set_f t-set_si t-set_str t-set_sx t-set_ux t-sizeinbase t-sqrtrem t-tdiv t-tdiv_ui t-trial_division t-19280 + + if ENABLE_STATIC + if ENABLE_SHARED +diff -ruN mpir-2.7.0/tests/mpz/Makefile.in mpir-2.7.0-patched/tests/mpz/Makefile.in +--- mpir-2.7.0/tests/mpz/Makefile.in 2015-06-16 12:40:00.000000000 +0200 ++++ mpir-2.7.0-patched/tests/mpz/Makefile.in 2015-09-24 18:42:37.485967609 +0200 +@@ -121,7 +121,7 @@ + t-set_si$(EXEEXT) t-set_str$(EXEEXT) t-set_sx$(EXEEXT) \ + t-set_ux$(EXEEXT) t-sizeinbase$(EXEEXT) t-sqrtrem$(EXEEXT) \ + t-tdiv$(EXEEXT) t-tdiv_ui$(EXEEXT) t-trial_division$(EXEEXT) \ +- $(am__EXEEXT_1) ++ t-19280$(EXEEXT) $(am__EXEEXT_1) + @ENABLE_SHARED_TRUE@@ENABLE_STATIC_TRUE@am__append_1 = st_hamdist st_popcount + subdir = tests/mpz + DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ +@@ -197,6 +197,11 @@ + st_popcount_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(st_popcount_LDFLAGS) $(LDFLAGS) -o $@ ++t_19280_SOURCES = t-19280.c ++t_19280_OBJECTS = t-19280.$(OBJEXT) ++t_19280_LDADD = $(LDADD) ++t_19280_DEPENDENCIES = $(top_builddir)/tests/libtests.la \ ++ $(top_builddir)/libmpir.la + t_addsub_SOURCES = t-addsub.c + t_addsub_OBJECTS = t-addsub.$(OBJEXT) + t_addsub_LDADD = $(LDADD) +@@ -526,21 +531,7 @@ + am__v_CCLD_0 = @echo " CCLD " $@; + am__v_CCLD_1 = + SOURCES = bit.c convert.c dive.c dive_ui.c io.c logic.c reuse.c \ +- $(st_hamdist_SOURCES) $(st_popcount_SOURCES) t-addsub.c \ +- t-aorsmul.c t-bin.c t-cdiv_ui.c t-cmp.c t-cmp_d.c t-cmp_si.c \ +- t-cong.c t-cong_2exp.c t-div_2exp.c t-divis.c t-divis_2exp.c \ +- t-export.c t-fac_ui.c t-fdiv.c t-fdiv_ui.c t-fib_ui.c t-fits.c \ +- t-gcd.c t-gcd_ui.c t-get_d.c t-get_d_2exp.c t-get_si.c \ +- t-get_sx.c t-get_ux.c t-hamdist.c t-import.c t-inp_str.c \ +- t-io_raw.c t-jac.c t-lcm.c t-likely_prime_p.c t-lucnum_ui.c \ +- t-mfac_uiui.c t-mul.c t-mul_i.c t-next_prime_candidate.c \ +- t-oddeven.c t-perfpow.c t-perfsqr.c t-popcount.c t-pow.c \ +- t-powm.c t-powm_ui.c t-pprime_p.c t-primorial_ui.c t-root.c \ +- t-scan.c t-set_d.c t-set_f.c t-set_si.c t-set_str.c t-set_sx.c \ +- t-set_ux.c t-sizeinbase.c t-sqrtrem.c t-tdiv.c t-tdiv_ui.c \ +- t-trial_division.c +-DIST_SOURCES = bit.c convert.c dive.c dive_ui.c io.c logic.c reuse.c \ +- $(am__st_hamdist_SOURCES_DIST) $(am__st_popcount_SOURCES_DIST) \ ++ $(st_hamdist_SOURCES) $(st_popcount_SOURCES) t-19280.c \ + t-addsub.c t-aorsmul.c t-bin.c t-cdiv_ui.c t-cmp.c t-cmp_d.c \ + t-cmp_si.c t-cong.c t-cong_2exp.c t-div_2exp.c t-divis.c \ + t-divis_2exp.c t-export.c t-fac_ui.c t-fdiv.c t-fdiv_ui.c \ +@@ -554,6 +545,21 @@ + t-set_f.c t-set_si.c t-set_str.c t-set_sx.c t-set_ux.c \ + t-sizeinbase.c t-sqrtrem.c t-tdiv.c t-tdiv_ui.c \ + t-trial_division.c ++DIST_SOURCES = bit.c convert.c dive.c dive_ui.c io.c logic.c reuse.c \ ++ $(am__st_hamdist_SOURCES_DIST) $(am__st_popcount_SOURCES_DIST) \ ++ t-19280.c t-addsub.c t-aorsmul.c t-bin.c t-cdiv_ui.c t-cmp.c \ ++ t-cmp_d.c t-cmp_si.c t-cong.c t-cong_2exp.c t-div_2exp.c \ ++ t-divis.c t-divis_2exp.c t-export.c t-fac_ui.c t-fdiv.c \ ++ t-fdiv_ui.c t-fib_ui.c t-fits.c t-gcd.c t-gcd_ui.c t-get_d.c \ ++ t-get_d_2exp.c t-get_si.c t-get_sx.c t-get_ux.c t-hamdist.c \ ++ t-import.c t-inp_str.c t-io_raw.c t-jac.c t-lcm.c \ ++ t-likely_prime_p.c t-lucnum_ui.c t-mfac_uiui.c t-mul.c \ ++ t-mul_i.c t-next_prime_candidate.c t-oddeven.c t-perfpow.c \ ++ t-perfsqr.c t-popcount.c t-pow.c t-powm.c t-powm_ui.c \ ++ t-pprime_p.c t-primorial_ui.c t-root.c t-scan.c t-set_d.c \ ++ t-set_f.c t-set_si.c t-set_str.c t-set_sx.c t-set_ux.c \ ++ t-sizeinbase.c t-sqrtrem.c t-tdiv.c t-tdiv_ui.c \ ++ t-trial_division.c + am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ +@@ -1020,6 +1026,10 @@ + @rm -f st_popcount$(EXEEXT) + $(AM_V_CCLD)$(st_popcount_LINK) $(st_popcount_OBJECTS) $(st_popcount_LDADD) $(LIBS) + ++t-19280$(EXEEXT): $(t_19280_OBJECTS) $(t_19280_DEPENDENCIES) $(EXTRA_t_19280_DEPENDENCIES) ++ @rm -f t-19280$(EXEEXT) ++ $(AM_V_CCLD)$(LINK) $(t_19280_OBJECTS) $(t_19280_LDADD) $(LIBS) ++ + t-addsub$(EXEEXT): $(t_addsub_OBJECTS) $(t_addsub_DEPENDENCIES) $(EXTRA_t_addsub_DEPENDENCIES) + @rm -f t-addsub$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_addsub_OBJECTS) $(t_addsub_LDADD) $(LIBS) +@@ -1931,6 +1941,13 @@ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ ++ "$$tst" $(AM_TESTS_FD_REDIRECT) ++t-19280.log: t-19280$(EXEEXT) ++ @p='t-19280$(EXEEXT)'; \ ++ b='t-19280'; \ ++ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ ++ --log-file $$b.log --trs-file $$b.trs \ ++ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) + st_hamdist.log: st_hamdist$(EXEEXT) + @p='st_hamdist$(EXEEXT)'; \ +diff -ruN mpir-2.7.0/tests/mpz/t-19280.c mpir-2.7.0-patched/tests/mpz/t-19280.c +--- mpir-2.7.0/tests/mpz/t-19280.c 1970-01-01 01:00:00.000000000 +0100 ++++ mpir-2.7.0-patched/tests/mpz/t-19280.c 2015-09-24 18:57:03.005937190 +0200 +@@ -0,0 +1,50 @@ ++/* Test t-19280. ++ ++*/ ++ ++#include ++#include ++ ++#include "mpir.h" ++#include "gmp-impl.h" ++#include "tests.h" ++ ++#define printf gmp_printf ++ ++/* Check mpz_tdif_q gives a correct answer on 32-bit, ++ see http://trac.sagemath.org/ticket/19280. ++ This was wrong in sage 6.9.beta7. */ ++static void ++check_19280 (void) ++{ ++ ++ mpz_t one, x, w, correct; ++ mpz_init(one); ++ mpz_init(x); ++ mpz_init(w); ++ mpz_init(correct); ++ mpz_set_str(one, "62165404551223330269422781018352605012557018849668464680057997111644937126566671941632", 10); ++ mpz_set_str(x, "39623752663112484341451587580", 10); ++ mpz_set_str(correct, "1568892403497558507879962225846103176600476845510570267609", 10); ++ ++ mpz_tdiv_q(w, one, x); ++ if (mpz_cmp(w, correct)!=0) { ++ printf("mpz_tdiv_q returned %Zd instead of %Zd.\n", w, correct); ++ abort(); ++ } ++ mpz_clear(one); ++ mpz_clear(x); ++ mpz_clear(w); ++ mpz_clear(correct); ++} ++ ++int ++main (void) ++{ ++ tests_start (); ++ ++ check_19280 (); ++ ++ tests_end (); ++ exit (0); ++} From bb088bd8b8dc07d7141c33134025f7cbf4a2e295 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:19:02 +0200 Subject: [PATCH 1007/1872] Trac #17693, comment 36, 13: use _predecessors_, _successors_ in le for performance --- src/sage/data_structures/mutable_poset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 43137c6ffc8..342bee822c8 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -552,20 +552,20 @@ def le(self, other, reverse=False): return other.le(self, reverse=False) if self.element is None: - if not self.predecessors(): + if not self._predecessors_: # null on the left return True else: # oo on the left if other.element is None: # null or oo on the right - return not other.successors() + return not other._successors_ else: # not null, not oo on the right return False elif other.element is None: # null/oo on the right - return not other.successors() + return not other._successors_ return self.key <= other.key From 0369feef049e67d04149f354158e7b99b5319b89 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:21:51 +0200 Subject: [PATCH 1008/1872] Trac #17693, comment 36, 14+15: simplify/rewrite note-box in eq --- src/sage/data_structures/mutable_poset.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 342bee822c8..8d43f3521d7 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -588,9 +588,8 @@ def eq(self, other): .. NOTE:: This method compares the keys of the elements contained - in the shells, if the elements are not both ``None``. - Otherwise, this method checks whether both shells describe the - same special element. + in the (non-special) shells. In particlar, + elements/shells with the same key are considered as equal. TESTS:: From b5049f672d39e857cded703259322be0bb99817f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 24 Sep 2015 19:34:20 +0200 Subject: [PATCH 1009/1872] Trac #19280: add fix to all x86 gmp-mparam --- build/pkgs/mpir/patches/fix-19280.patch | 189 ++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 build/pkgs/mpir/patches/fix-19280.patch diff --git a/build/pkgs/mpir/patches/fix-19280.patch b/build/pkgs/mpir/patches/fix-19280.patch new file mode 100644 index 00000000000..885c0fde917 --- /dev/null +++ b/build/pkgs/mpir/patches/fix-19280.patch @@ -0,0 +1,189 @@ +diff -ru mpir-2.7.0/mpn/x86/applenopic/core2/gmp-mparam.h mpir-2.7.0-new/mpn/x86/applenopic/core2/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/applenopic/core2/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/applenopic/core2/gmp-mparam.h 2015-09-24 19:31:45.060547384 +0200 +@@ -1,3 +1,7 @@ ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + /* Generated by tuneup.c, 2009-10-08, gcc 4.2 */ + + #define MUL_KARATSUBA_THRESHOLD 22 +Nur in mpir-2.7.0-new/mpn/x86/applenopic/core2: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/core2/gmp-mparam.h mpir-2.7.0-new/mpn/x86/core2/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/core2/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/core2/gmp-mparam.h 2015-09-24 19:31:32.730385817 +0200 +@@ -1,3 +1,7 @@ ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + /* Generated by tuneup.c, 2010-03-24, gcc 4.4 */ + + #define MUL_KARATSUBA_THRESHOLD 22 +Nur in mpir-2.7.0-new/mpn/x86/core2: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/fat/gmp-mparam.h mpir-2.7.0-new/mpn/x86/fat/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/fat/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/fat/gmp-mparam.h 2015-09-24 19:31:51.575803154 +0200 +@@ -20,6 +20,10 @@ + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + #define BITS_PER_MP_LIMB 32 + #define BYTES_PER_MP_LIMB 4 + +Nur in mpir-2.7.0-new/mpn/x86/fat: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/gmp-mparam.h mpir-2.7.0-new/mpn/x86/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/gmp-mparam.h 2015-09-24 19:32:16.420218287 +0200 +@@ -20,6 +20,10 @@ + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + #define BITS_PER_MP_LIMB 32 + #define BYTES_PER_MP_LIMB 4 + +Nur in mpir-2.7.0-new/mpn/x86: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/i486/gmp-mparam.h mpir-2.7.0-new/mpn/x86/i486/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/i486/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/i486/gmp-mparam.h 2015-09-24 19:31:16.962506371 +0200 +@@ -19,6 +19,11 @@ + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ ++ + #define BITS_PER_MP_LIMB 32 + #define BYTES_PER_MP_LIMB 4 + +Nur in mpir-2.7.0-new/mpn/x86/i486: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/k6/gmp-mparam.h mpir-2.7.0-new/mpn/x86/k6/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/k6/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/k6/gmp-mparam.h 2015-09-24 19:31:40.646341539 +0200 +@@ -20,6 +20,10 @@ + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + #define BITS_PER_MP_LIMB 32 + #define BYTES_PER_MP_LIMB 4 + +Nur in mpir-2.7.0-new/mpn/x86/k6: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/k7/gmp-mparam.h mpir-2.7.0-new/mpn/x86/k7/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/k7/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/k7/gmp-mparam.h 2015-09-24 19:32:23.167590050 +0200 +@@ -1,3 +1,7 @@ ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + /* Generated by tuneup.c, 2010-03-24, gcc 4.3 */ + + #define MUL_KARATSUBA_THRESHOLD 26 +Nur in mpir-2.7.0-new/mpn/x86/k7: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/k7/mmx/k8/gmp-mparam.h mpir-2.7.0-new/mpn/x86/k7/mmx/k8/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/k7/mmx/k8/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/k7/mmx/k8/gmp-mparam.h 2015-09-24 19:32:19.753884166 +0200 +@@ -1,3 +1,7 @@ ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + /* Generated by tuneup.c, 2010-03-24, gcc 4.4 */ + + #define MUL_KARATSUBA_THRESHOLD 28 +Nur in mpir-2.7.0-new/mpn/x86/k7/mmx/k8: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/nehalem/gmp-mparam.h mpir-2.7.0-new/mpn/x86/nehalem/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/nehalem/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/nehalem/gmp-mparam.h 2015-09-24 19:32:09.640830522 +0200 +@@ -1,3 +1,7 @@ ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + /* Generated by tuneup.c, 2009-10-07, gcc 4.3 */ + + #define MUL_KARATSUBA_THRESHOLD 18 +Nur in mpir-2.7.0-new/mpn/x86/nehalem: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/p6/gmp-mparam.h mpir-2.7.0-new/mpn/x86/p6/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/p6/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/p6/gmp-mparam.h 2015-09-24 19:32:32.796401709 +0200 +@@ -20,6 +20,9 @@ + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 + + #define BITS_PER_MP_LIMB 32 + #define BYTES_PER_MP_LIMB 4 +Nur in mpir-2.7.0-new/mpn/x86/p6: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/p6/mmx/gmp-mparam.h mpir-2.7.0-new/mpn/x86/p6/mmx/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/p6/mmx/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/p6/mmx/gmp-mparam.h 2015-09-24 19:32:27.597803891 +0200 +@@ -20,6 +20,9 @@ + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 + + #define BITS_PER_MP_LIMB 32 + #define BYTES_PER_MP_LIMB 4 +Nur in mpir-2.7.0-new/mpn/x86/p6/mmx: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/pentium/gmp-mparam.h mpir-2.7.0-new/mpn/x86/pentium/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/pentium/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/pentium/gmp-mparam.h 2015-09-24 19:32:04.174098713 +0200 +@@ -20,6 +20,9 @@ + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 + + #define BITS_PER_MP_LIMB 32 + #define BYTES_PER_MP_LIMB 4 +Nur in mpir-2.7.0-new/mpn/x86/pentium: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/pentium/mmx/gmp-mparam.h mpir-2.7.0-new/mpn/x86/pentium/mmx/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/pentium/mmx/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/pentium/mmx/gmp-mparam.h 2015-09-24 19:31:57.902964934 +0200 +@@ -20,6 +20,9 @@ + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 + + #define BITS_PER_MP_LIMB 32 + #define BYTES_PER_MP_LIMB 4 +Nur in mpir-2.7.0-new/mpn/x86/pentium/mmx: gmp-mparam.h~. +diff -ru mpir-2.7.0/mpn/x86/pentium4/sse2/gmp-mparam.h mpir-2.7.0-new/mpn/x86/pentium4/sse2/gmp-mparam.h +--- mpir-2.7.0/mpn/x86/pentium4/sse2/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 ++++ mpir-2.7.0-new/mpn/x86/pentium4/sse2/gmp-mparam.h 2015-09-24 19:32:36.226115587 +0200 +@@ -1,3 +1,7 @@ ++/* see http://trac.sagemath.org/ticket/19280 */ ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 ++ + /* Generated by tuneup.c, 2014-03-24, gcc 4.7 */ + + #define MUL_KARATSUBA_THRESHOLD 22 +Nur in mpir-2.7.0-new/mpn/x86/pentium4/sse2: gmp-mparam.h~. From 899324763f34bf04901a8ff8065add230d1d8238 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:35:04 +0200 Subject: [PATCH 1010/1872] Trac #17693, comment 36, 17: explain role of poset better in _copy_all_linked_ --- src/sage/data_structures/mutable_poset.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8d43f3521d7..6c2446bd5b3 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -635,7 +635,10 @@ def _copy_all_linked_(self, memo, poset, mapping): - ``memo`` -- a dictionary which assigns to the id of the calling shell to a copy of it. - - ``poset`` -- the poset to which the newly created shells belongs. + - ``poset`` -- the poset to which the newly created shells + belongs. Note that the elements are not inserted into + ``poset``; this is done in the calling method + :meth:`_copy_shells_`. - ``mapping`` -- a function which is applied on each of the elements. From b8a0a6a400a6a9421e2ccf48ad40bebe32e327db Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 19:37:29 +0200 Subject: [PATCH 1011/1872] Trac #17693, comment 36, 16: rewrite short-descr of _copy_all_linked_ --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 6c2446bd5b3..205cef34c1b 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -625,8 +625,8 @@ def eq(self, other): def _copy_all_linked_(self, memo, poset, mapping): r""" - Return a copy of all shells linked to this shell - (including a copy of this shell). + Return a copy of this shell. All shells linked to this shell + are copied as well. This is a helper function for :meth:`MutablePoset.copy`. From 311c752e4555cd38ca8c8a6cc1c6c8b95167da86 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 20:18:29 +0200 Subject: [PATCH 1012/1872] Trac #17693, comment 36, 32: Delete not needed line in doctest of iter_topological --- src/sage/data_structures/mutable_poset.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 205cef34c1b..9d2b8146fca 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1025,8 +1025,6 @@ def iter_topological(self, reverse=False, key=None, condition=None): :: - sage: def C(shell): - ....: return shell.element[0] == 1 sage: list(P.null.iter_topological( ....: reverse=True, condition=lambda s: s.element[0] == 1)) [(1, 3), (1, 2), (1, 1), null] From d0af5fa4e3b44d21f1a0cd4b5459d5d217c14bc5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 20:24:48 +0200 Subject: [PATCH 1013/1872] Trac #17693, comment 36, 36: document merge-function None in merge --- src/sage/data_structures/mutable_poset.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 9d2b8146fca..26585da387d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1053,6 +1053,15 @@ def merge(self, element, check=True, delete=True): Nothing. + .. NOTE:: + + This method uses the parameters ``merge`` and + ``can_merge`` of the :class:`MutablePoset` which contains + this shell. + + If the ``merge`` function returns ``None``, then this shell + is removed from the poset. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 9433564213a8a699814106c375b4cc0a5ef22f71 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 24 Sep 2015 20:24:52 +0200 Subject: [PATCH 1014/1872] trac #19224: Additional doctests --- src/sage/graphs/strongly_regular_db.pyx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 77b8983ab66..49ae296e540 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -995,8 +995,12 @@ def is_switch_OA_srg(int v, int k, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_switch_OA_srg sage: t = is_switch_OA_srg(5,5,5,5); t - sage: is_switch_OA_srg(290, 136, 63, 64) - (.switch_OA_srg at ..., 8, 17) + sage: t = is_switch_OA_srg(170, 78, 35, 36); + sage: t[0](*t[1:]).is_strongly_regular(parameters=True) + (170, 78, 35, 36) + sage: t = is_switch_OA_srg(290, 136, 63, 64); + sage: t[0](*t[1:]).is_strongly_regular(parameters=True) + (290, 136, 63, 64) sage: is_switch_OA_srg(626, 300, 143, 144) (.switch_OA_srg at ..., 12, 25) sage: is_switch_OA_srg(842, 406, 195, 196) From 0855f60975543f2243bd8b0aff73dd6fbe2b9f40 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 20:27:29 +0200 Subject: [PATCH 1015/1872] Trac #17693, comment 36, 39: document that null and oo are not counted in __len__ --- src/sage/data_structures/mutable_poset.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 26585da387d..8b16a749a2f 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1288,6 +1288,10 @@ def __len__(self): An integer. + .. NOTE:: + + The special elements ``'null'`` and ``'oo'`` are not counted. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From a959efd2bfcea9c3a76f02b44120153258212788 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 20:30:13 +0200 Subject: [PATCH 1016/1872] Trac #17693, comment 36, 40: rewrite key-parameter description in shells_topological --- src/sage/data_structures/mutable_poset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8b16a749a2f..6b58831fa14 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1556,9 +1556,9 @@ def shells_topological(self, include_special=False, ``True`` gives largest first. - ``key`` -- (default: ``None``) a function used for sorting - the direct successors of a shell (used in case of a - tie). If this is ``None``, no sorting according to the - representation string occurs. + the direct successors of a shell (used in case of a tie). If + this is ``None``, then the successors are sorted according + to their representation strings. OUTPUT: From e1784af0405e43a8c9a3cb776a4536a024335e81 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 20:32:48 +0200 Subject: [PATCH 1017/1872] Trac #17693, comment 36, 41: remove some poset elements in doctest since not needed --- src/sage/data_structures/mutable_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 6b58831fa14..452af533600 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1716,7 +1716,7 @@ def keys_topological(self, **kwargs): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP([(1, 1), (1, 3), (2, 1), (4, 4), (1, 2), (2, 2)], + sage: P = MP([(1, 1), (2, 1), (4, 4)], ....: key=lambda c: c[0]) sage: [(v, type(v)) for v in P.keys_topological()] [(1, ), From ccb337830ac6004d551e660f582466ffd8afb823 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 24 Sep 2015 20:36:19 +0200 Subject: [PATCH 1018/1872] Trac #17693, comment 36, 42+43: complete INPUT blocks of repr* --- src/sage/data_structures/mutable_poset.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 452af533600..727ebf2c532 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1741,7 +1741,12 @@ def repr(self, include_special=False, reverse=False): INPUT: - Nothing. + - ``include_special`` -- (default: ``False``) a boolean + indicating whether to include the special elements + ``'null'`` and ``'oo'`` or not. + + - ``reverse`` -- (default: ``False``) a boolean. If set, then + largest elements are displayed first. OUTPUT: @@ -1766,7 +1771,8 @@ def repr_full(self, reverse=False): INPUT: - Nothing. + - ``reverse`` -- (default: ``False``) a boolean. If set, then + largest elements are displayed first. OUTPUT: From c26038e543830f388cdceafb139d33e5f28359cd Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 24 Sep 2015 20:39:03 +0200 Subject: [PATCH 1019/1872] trac #19279: Different definition --- .../combinat/designs/incidence_structures.py | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 35ed5b0f068..3373ddb06b9 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1640,21 +1640,23 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): ll = b return (True, (tt,v,k,ll)) if return_parameters else True - def is_generalized_quadrangle(self, verbose=False): + def is_generalized_quadrangle(self, verbose=False, parameters=False): r""" Test if the incidence structure is a generalized quadrangle. An incidence structure is a generalized quadrangle iif: - - it is `s+1`-:meth:`uniform ` for some positive integer `s`. - - - it is `t+1`-:meth:`regular ` for some positive integer `t`. - - two blocks intersect on at most one point. - For every point `p` not in a block `B`, there is a unique block `B'` intersecting both `\{p\}` and `B` + It is a *regular* generalized quadrangle if furthermore: + + - it is `s+1`-:meth:`uniform ` for some positive integer `s`. + + - it is `t+1`-:meth:`regular ` for some positive integer `t`. + For more information, see the :wikipedia:`Generalized_quadrangle`. INPUT: @@ -1662,23 +1664,23 @@ def is_generalized_quadrangle(self, verbose=False): - ``verbose`` (boolean) -- whether to print an explanation when the instance is not a generalized quadrangle. + - ``parameters`` (boolean; ``False``) -- if set to ``True``, the + function returns a pair ``(s,t)`` instead of ``True`` answers. In this + case, `s` and `t` are the integers defined above if they exist (each + can be set to ``False`` otherwise). + EXAMPLE:: sage: h = designs.CremonaRichmondConfiguration() sage: h.is_generalized_quadrangle() True - TESTS:: + This is actually a *regular* generalized quadrangle:: - sage: H = IncidenceStructure([[1,2],[3,4,5]]) - sage: H.is_generalized_quadrangle(verbose=True) - The incidence structure is not (s+1)-uniform for some s>0. - False + sage: h.is_generalized_quadrangle(parameters=True) + (2, 2) - sage: H = IncidenceStructure([[1,2,3],[3,4,5]]) - sage: H.is_generalized_quadrangle(verbose=True) - The incidence structure is not (t+1)-regular for some t>0. - False + TESTS:: sage: H = IncidenceStructure((2*graphs.CompleteGraph(3)).edges(labels=False)) sage: H.is_generalized_quadrangle(verbose=True) @@ -1696,18 +1698,6 @@ def is_generalized_quadrangle(self, verbose=False): Some point has two projections on some line. False """ - s = self.is_uniform()-1 - if not s or s <= 0: - if verbose: - print "The incidence structure is not (s+1)-uniform for some s>0." - return False - - t = self.is_regular()-1 - if not t or t <= 0: - if verbose: - print "The incidence structure is not (t+1)-regular for some t>0." - return False - # The distance between a point and a line in the incidence graph is odd # and must be <= 3. Thus, the diameter is at most 4 g = self.incidence_graph() @@ -1727,7 +1717,17 @@ def is_generalized_quadrangle(self, verbose=False): if verbose: print "Some point has two projections on some line." return False - return True + + if parameters: + s = self.is_uniform() + t = self.is_regular() + s = s-1 if (s is not False and s>=2) else False + t = t-1 if (t is not False and t>=2) else False + return (s,t) + else: + return True + + def dual(self, algorithm=None): """ From 58cd46270c1ac5dc4413a9e6efe3c7aabe83f5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Thu, 24 Sep 2015 21:59:33 +0300 Subject: [PATCH 1020/1872] Added function linear_extensions_graph. --- src/sage/combinat/posets/posets.py | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 58245aa7aca..fa799e57250 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -4456,6 +4456,50 @@ def incomparability_graph(self): G.rename('Incomparability graph on %s vertices' % self.cardinality()) return G + def linear_extensions_graph(self): + r""" + Return the linear extensions graph of the poset. + + Vertices of the graph are linear extensions of the poset. + Two vertices are connected by an edge if the linear extensions + differ by only one adjacent transposition. + + EXAMPLES:: + + sage: P = Poset({1:[3,4],2:[4]}) + sage: G = P.linear_extensions_graph(); G + Graph on 5 vertices + sage: G.degree_sequence() + [3, 2, 2, 2, 1] + + sage: chevron = Poset({1:[2,6], 2:[3], 4:[3,5], 6:[5]}) + sage: G = chevron.linear_extensions_graph(); G + Graph on 22 vertices + sage: G.size() + 36 + + TESTS:: + + sage: Poset().linear_extensions_graph() + Graph on 1 vertex + + sage: A4 = Posets.AntichainPoset(4) + sage: G = A4.linear_extensions_graph() + sage: G.is_regular() + True + """ + from sage.graphs.graph import Graph + # Direct implementation, no optimizations + L = self.linear_extensions() + G = Graph() + G.add_vertices(L) + for i in range(len(L)): + for j in range(i): + tmp = map(lambda x,y: x != y, L[i], L[j]) + if tmp.count(True) == 2 and tmp[tmp.index(True)+1]: + G.add_edge(L[i], L[j]) + return G + def maximal_antichains(self): """ Return all maximal antichains of the poset. From 93346eaa75889e5bb189a5b29ccbc727474ae708 Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Thu, 24 Sep 2015 14:03:45 -0500 Subject: [PATCH 1021/1872] better test case --- src/sage/matroids/matroid.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 2a6d7f3d92f..8405b7fe937 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6731,8 +6731,7 @@ cdef class Matroid(SageObject): True sage: sum(map(len,P))==len(M.groundset()) True - sage: from sage.matroids.advanced import * - sage: BasisMatroid().partition() + sage: Matroid(matrix([])).partition() [] ALGORITHM: From c3e75dc8c995b8a1454a1f109b081f8c45df0eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 24 Sep 2015 22:22:07 +0200 Subject: [PATCH 1022/1872] octave vector parser --- src/sage/interfaces/octave.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index df08d363fe9..fc9bd0741d3 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -524,15 +524,30 @@ def _matrix_(self, R): [3.00000000000000 4.50000000000000] """ from sage.matrix.all import MatrixSpace - s = str(self).strip() - v = s.split('\n ') - nrows = len(v) - if nrows == 0: - return MatrixSpace(R,0,0)(0) - ncols = len(v[0].split()) - M = MatrixSpace(R, nrows, ncols) - v = sum([[x for x in w.split()] for w in v], []) - return M(v) + s = str(self).strip('\n ') + w = [u.strip().split(' ') for u in s.split('\n')] + nrows = len(w) + ncols = len(w[0]) + return MatrixSpace(R, nrows, ncols)(w) + + def _vector_(self, R): + r""" + Return Sage vector from this octave element. + + EXAMPLES:: + + sage: A = octave('[1,2,3,4]') # optional - octave + sage: vector(ZZ, A) # optional - octave + [1 2 3 4] + sage: A = octave('[1,2.3,4.5]') # optional - octave + sage: vector(RR, A) # optional - octave + [1.00000000000000 2.30000000000000 4.50000000000000] + """ + from sage.modules.free_module import FreeModule + s = str(self).strip('\n ') + w = s.strip().split(' ') + nrows = len(w) + return FreeModule(R, nrows)(w) # An instance From 2cd19ba5eee863d7224c28fceb7db998548b904a Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Thu, 24 Sep 2015 17:05:17 -0700 Subject: [PATCH 1023/1872] added a test, revised comments --- .../root_system/integrable_representations.py | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 38a0fcc6023..2942f936480 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -5,7 +5,7 @@ #***************************************************************************** # Copyright (C) 2014, 2105 Daniel Bump # Travis Scrimshaw -# Twisted Affine case: Valentin Buciumas +# Valentin Buciumas # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ @@ -152,8 +152,11 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): 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 - Two examples for twisted affine types:: + Examples for twisted affine types:: + sage: Lambda = RootSystem(["A",2,2]).weight_lattice(extended=True).fundamental_weights() + sage: IntegrableRepresentation(Lambda[0]).strings() + {Lambda[0]: [1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56]} sage: Lambda = RootSystem(['G',2,1]).dual.weight_lattice(extended=true).fundamental_weights() sage: V = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[2]) sage: V.print_strings() # long time @@ -495,8 +498,7 @@ def _from_weight_helper(self, mu, check=False): """ mu = self._P(mu) zero = ZZ.zero() - n0 = mu.monomial_coefficients().get('delta', zero) - mu0 = mu - n0 * self._P.simple_root(self._cartan_type.special_node()) + 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() for ii, i in enumerate(self._index_set_classical): @@ -618,7 +620,7 @@ def _freudenthal_roots_real(self, nu): Return the set of real positive roots `\alpha \in \Delta^+` in ``self`` such that `\nu - \alpha \in Q^+`. - See [Kac] Proposition 6.3 for the way to compute the set of real roots for twisted affine case. + See [Kac]_ Proposition 6.3 for the way to compute the set of real roots for twisted affine case. INPUT: @@ -641,9 +643,6 @@ def _freudenthal_roots_real(self, nu): for al in self._classical_positive_roots: if all(x >= 0 for x in self._from_weight_helper(nu-al)): ret.append(al) - """ - changed the way you compute the set of real roots for twisted affine case, see [Kac] page 83 - """ from sage.combinat.root_system.cartan_type import CartanType if self._cartan_type == CartanType(['B',self._classical_rank,1]).dual() or self._cartan_type == CartanType(['C',self._classical_rank,1]).dual() or self._cartan_type == CartanType(['F',4,1]).dual(): #case A^2_{2l-1} or case D^2_{l+1} or case E^2_6: for al in self._classical_roots: @@ -670,7 +669,7 @@ def _freudenthal_roots_real(self, nu): if sum([val*alpha[i] for i,val in enumerate(n)]) not in ret: ret.append(sum([val*alpha[i] for i,val in enumerate(n)])) - elif self._cartan_type == CartanType(['D',4,3]) or self._cartan_type == CartanType(['G',2,1]).dual(): # case D^3_4 in the Kac/Stembridge notation + elif self._cartan_type == CartanType(['D',4,3]) or self._cartan_type == CartanType(['G',2,1]).dual(): # case D^3_4 in the Kac notation for al in self._classical_roots: if self._inner_qq(al,al) == 2: #if al is a short root: for ir in self._freudenthal_roots_imaginary(nu-al): @@ -723,8 +722,8 @@ def _m_freudenthal(self, n): Compute the weight multiplicity using the Freudenthal multiplicity formula in ``self``. The multiplicities of the imaginary roots for the twisted - affine case are different than those for the untwisted case, - see [Carter]_ Corollary 18.10 for general type and Corollary + affine case are different than those for the untwisted case. + See [Carter]_ Corollary 18.10 for general type and Corollary 18.15 for `A^2_{2l}` EXAMPLES:: @@ -756,7 +755,6 @@ def _m_freudenthal(self, n): for k in dict: # k is a positive number, dict[k] is k*delta num += (self._classical_rank-k%2) * self._freudenthal_accum(mu, dict[k]) - elif self._cartan_type == CartanType(['BC',self._classical_rank,2]): for al in self._freudenthal_roots_imaginary(self._Lam - mu): num += self._classical_rank * self._freudenthal_accum(mu, al) @@ -786,7 +784,6 @@ def _m_freudenthal(self, n): for al in self._freudenthal_roots_imaginary(self._Lam - mu): num += self._classical_rank * self._freudenthal_accum(mu, al) - try: return ZZ(num / den) except TypeError: From 513ea7bfa133b5677d75396fcd41c6a5efd133a1 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Thu, 24 Sep 2015 17:18:21 -0700 Subject: [PATCH 1024/1872] undid accidental reversion of #18246 --- src/sage/combinat/root_system/integrable_representations.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 2942f936480..48e7cc24d0a 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.combinat.root_system.weyl_characters import WeylCharacterRing # TODO: Make this a proper parent and implement actions -class IntegrableRepresentation(CategoryObject, UniqueRepresentation): +class IntegrableRepresentation(UniqueRepresentation, CategoryObject): r""" An irreducible integrable highest weight representation of an affine Lie algebra. @@ -498,7 +498,8 @@ def _from_weight_helper(self, mu, check=False): """ mu = self._P(mu) zero = ZZ.zero() - n0 = mu.monomial_coefficients().get('delta', zero) mu0 = mu - n0 * self._P.simple_root(self._cartan_type.special_node()) + 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() for ii, i in enumerate(self._index_set_classical): From 02a7a7653653a8c4c44ec936aa962c514b5ecce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 25 Sep 2015 12:27:15 +1200 Subject: [PATCH 1025/1872] More robust test for networkx --- src/sage/graphs/generic_graph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 4c6305adc27..98e6597a6cf 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -14559,10 +14559,10 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, [4, 17, 16, 12, 13, 9] sage: D.shortest_path(4, 9, algorithm='BFS') [4, 3, 2, 1, 8, 9] - sage: D.shortest_path(4, 9, algorithm='Dijkstra_NetworkX') - [4, 17, 16, 12, 13, 9] - sage: D.shortest_path(4, 9, algorithm='Dijkstra_Bid_NetworkX') - [4, 17, 16, 12, 13, 9] + sage: D.shortest_path(4, 8, algorithm='Dijkstra_NetworkX') + [4, 3, 2, 1, 8] + sage: D.shortest_path(4, 8, algorithm='Dijkstra_Bid_NetworkX') + [4, 3, 2, 1, 8] sage: D.shortest_path(4, 9, algorithm='Dijkstra_Bid') [4, 3, 19, 0, 10, 9] sage: D.shortest_path(5, 5) From be0067543666fc8ad72c847b0a3ed0cf587218c9 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 25 Sep 2015 09:19:33 +0200 Subject: [PATCH 1026/1872] Trac #19280: increase patch level --- build/pkgs/mpir/package-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/mpir/package-version.txt b/build/pkgs/mpir/package-version.txt index 24ba9a38de6..9c8d6791e82 100644 --- a/build/pkgs/mpir/package-version.txt +++ b/build/pkgs/mpir/package-version.txt @@ -1 +1 @@ -2.7.0 +2.7.0.p1 From 0d48fb57205cb16d58380c9b022c39eb354c3a58 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 25 Sep 2015 09:21:40 +0200 Subject: [PATCH 1027/1872] Trac #19280: Add header to patch files --- build/pkgs/mpir/patches/fix-19280.patch | 2 ++ build/pkgs/mpir/patches/test-19280.patch | 1 + 2 files changed, 3 insertions(+) diff --git a/build/pkgs/mpir/patches/fix-19280.patch b/build/pkgs/mpir/patches/fix-19280.patch index 885c0fde917..6b2f224dff4 100644 --- a/build/pkgs/mpir/patches/fix-19280.patch +++ b/build/pkgs/mpir/patches/fix-19280.patch @@ -1,3 +1,5 @@ +Apply the fix proposed in http://trac.sagemath.org/ticket/18546#comment:23 +to the bug reported in http://trac.sagemath.org/ticket/19280 . diff -ru mpir-2.7.0/mpn/x86/applenopic/core2/gmp-mparam.h mpir-2.7.0-new/mpn/x86/applenopic/core2/gmp-mparam.h --- mpir-2.7.0/mpn/x86/applenopic/core2/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 +++ mpir-2.7.0-new/mpn/x86/applenopic/core2/gmp-mparam.h 2015-09-24 19:31:45.060547384 +0200 diff --git a/build/pkgs/mpir/patches/test-19280.patch b/build/pkgs/mpir/patches/test-19280.patch index 4caf6abdb2d..cef193c8bbf 100644 --- a/build/pkgs/mpir/patches/test-19280.patch +++ b/build/pkgs/mpir/patches/test-19280.patch @@ -1,3 +1,4 @@ +Include a test for the bug reported in http://trac.sagemath.org/ticket/19280 . diff -ruN mpir-2.7.0/tests/mpz/Makefile.am mpir-2.7.0-patched/tests/mpz/Makefile.am --- mpir-2.7.0/tests/mpz/Makefile.am 2015-06-09 19:18:27.000000000 +0200 +++ mpir-2.7.0-patched/tests/mpz/Makefile.am 2015-09-24 18:39:33.093974089 +0200 From 6a86e239c68f0d66cc182a98e74f72b34df4f961 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 25 Sep 2015 11:58:15 +0200 Subject: [PATCH 1028/1872] trac #19291: Graph.spanning_trees does not like loops --- src/sage/graphs/graph.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 5d11da8a6a1..6f5ca77eaa3 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1868,6 +1868,19 @@ def spanning_trees(self): - :meth:`~sage.graphs.graph.Graph.random_spanning_tree` -- returns a random spanning tree. + TESTS: + + Works with looped graphs:: + + sage: g = Graph({i:[i,(i+1)%6] for i in range(6)}) + sage: g.spanning_trees() + [Graph on 6 vertices, + Graph on 6 vertices, + Graph on 6 vertices, + Graph on 6 vertices, + Graph on 6 vertices, + Graph on 6 vertices] + REFERENCES: .. [RT75] Read, R. C. and Tarjan, R. E. @@ -1886,7 +1899,7 @@ def _recursive_spanning_trees(G,forest): return [forest.copy()] else: # Pick an edge e from G-forest - for e in G.edges(): + for e in G.edge_iterator(labels=False): if not forest.has_edge(e): break @@ -1919,7 +1932,7 @@ def _recursive_spanning_trees(G,forest): forest = Graph([]) forest.add_vertices(self.vertices()) forest.add_edges(self.bridges()) - return _recursive_spanning_trees(self, forest) + return _recursive_spanning_trees(Graph(self,immutable=False,loops=False), forest) else: return [] From b597ceb52fed43f6e62a246b977a1f0322b09892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 25 Sep 2015 13:28:14 +0200 Subject: [PATCH 1029/1872] trac #19284 adding equality symbol to octave interface, plus doc details --- src/sage/interfaces/octave.py | 50 ++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index fc9bd0741d3..b26c4fe617b 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -94,9 +94,8 @@ sage: a = octave.eval(t + ';') # optional - octave, < 1/100th of a second sage: a = octave(t) # optional - octave -Note that actually reading a back out takes forever. This *must* -be fixed ASAP - see -http://trac.sagemath.org/sage_trac/ticket/940/. +Note that actually reading ``a`` back out takes forever. This *must* +be fixed as soon as possible, see :trac:`940`. Tutorial -------- @@ -286,7 +285,7 @@ def quit(self, verbose=False): # to signals. if not self._expect is None: if verbose: - print "Exiting spawned %s process."%self + print "Exiting spawned %s process." % self return def _start(self): @@ -308,9 +307,38 @@ def _start(self): # set random seed self.set_seed(self._seed) + def _equality_symbol(self): + """ + EXAMPLES:: + + sage: octave('0 == 1') + 0 + sage: octave('1 == 1') + 1 + """ + return '==' + + def _true_symbol(self): + """ + EXAMPLES:: + + sage: octave('1 == 1') + 1 + """ + return '1' + + def _false_symbol(self): + """ + EXAMPLES:: + + sage: octave('0 == 1') + 0 + """ + return '0' + def set(self, var, value): """ - Set the variable var to the given value. + Set the variable ``var`` to the given ``value``. EXAMPLES:: @@ -325,7 +353,7 @@ def set(self, var, value): def get(self, var): """ - Get the value of the variable var. + Get the value of the variable ``var``. EXAMPLES:: @@ -387,18 +415,16 @@ def version(self): return octave_version() def solve_linear_system(self, A, b): - """ + r""" Use octave to compute a solution x to A\*x = b, as a list. INPUT: + - ``A`` -- mxn matrix A with entries in `\QQ` or `\RR` - - ``A`` - mxn matrix A with entries in QQ or RR - - - ``b`` - m-vector b entries in QQ or RR (resp) - + - ``b`` -- m-vector b entries in `\QQ` or `\RR` (resp) - OUTPUT: An list x (if it exists) which solves M\*x = b + OUTPUT: A list x (if it exists) which solves M\*x = b EXAMPLES:: From 47e33dac54248ac02ff018b210f0a0df9f9534db Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 25 Sep 2015 15:36:02 +0200 Subject: [PATCH 1030/1872] Do not source sage-env in configure --- configure.ac | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 5e320f74a41..3e814ebb8da 100644 --- a/configure.ac +++ b/configure.ac @@ -80,7 +80,7 @@ SAGE_SHARE="$SAGE_LOCAL/share" SAGE_EXTCODE="$SAGE_SHARE/sage/ext" SAGE_SPKG_INST="$SAGE_LOCAL/var/lib/sage/installed" -export PATH="$SAGE_ROOT/build/bin:$SAGE_SRC/bin:$SAGE_LOCAL/bin:$PATH" +export PATH="$SAGE_LOCAL/bin:$PATH" ############################################################################### # Determine whether to use MPIR (default standard pkg) or GMP (optional pkg). @@ -626,8 +626,6 @@ AC_ARG_ENABLE([compiler-checks], [Check versions and presence of C, C++ and Fort ] ) -# Import environment variables. -source src/bin/sage-env || AC_MSG_ERROR([failed to source sage-env]) #--------------------------------------------------------- # Check some programs needed actually exist. From 1c0e2f9964dcaee22f67f282dfbd4b26a57bf27e Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 25 Sep 2015 15:45:22 +0200 Subject: [PATCH 1031/1872] Move generation of build/make/Makefile down in configure.ac --- configure.ac | 478 +++++++++++++++++++++++++-------------------------- 1 file changed, 239 insertions(+), 239 deletions(-) diff --git a/configure.ac b/configure.ac index 3e814ebb8da..ccd22331308 100644 --- a/configure.ac +++ b/configure.ac @@ -270,245 +270,6 @@ if [ $need_to_install_gcc != yes ]; then fi fi fi - - -############################################################################### -# Create $SAGE_ROOT/build/make/Makefile starting from build/make/deps -############################################################################### - -# Use file descriptor 7 since make uses 3 and 4 and configure uses 5 and 6 -exec 7>build/make/Makefile - -cat >&7 <&7 "SHELL = `command -v bash`" -echo >&7 -] - -AC_MSG_CHECKING([package versions]) -AC_MSG_RESULT([]) - -# Usage: newest_version $pkg -# Print version number of latest standard package $pkg -newest_version() { - PKG=$1 - if test -f "$SAGE_ROOT/build/pkgs/$PKG/package-version.txt" ; then - AS_ECHO_N(["$PKG-"]) - cat "$SAGE_ROOT/build/pkgs/$PKG/package-version.txt" - else - echo "$PKG" - fi -} - -# Outputs the list of packages, filtered by 'type', e.g.: -# -# filtered_packages_list base -# filtered_packages_list standard -# filtered_packages_list optional -# filtered_packages_list experimental -# -# Or, if you want all packages: -# -# filtered_packages_list all -# -# The output consists of triples -# PKG_NAME PKG_VERSION PKG_VAR -# - -[ -filtered_packages_list() { - # for each package in pkgs/ - for DIR in $SAGE_ROOT/build/pkgs/*; do - test -d "$DIR" || continue - - PKG_TYPE_FILE="$DIR/type" - if [ -f "$PKG_TYPE_FILE" ]; then - PKG_TYPE=`cat $PKG_TYPE_FILE` - else - echo >&2 "\"$PKG_TYPE_FILE\" is missing. Create it, and set its content" - echo >&2 "to 'base', 'standard', 'optional' or 'experimental'." - return 1 - fi - - # Check consistency of 'DIR/type' file - if [ "$PKG_TYPE" != "base" ] && \ - [ "$PKG_TYPE" != "standard" ] && \ - [ "$PKG_TYPE" != "optional" ] && \ - [ "$PKG_TYPE" != "experimental" ] && \ - [ "$PKG_TYPE" != "pip" ]; then - echo >&2 "The content of \"$PKG_TYPE_FILE\" must be 'base', 'standard', 'optional', 'experimental' or 'pip'" - return 1 - fi - - # Filter - if [ "$1" = "$PKG_TYPE" -o "$1" = all ]; then - PKG_NAME=$(basename $DIR) - PKG_VAR="$(echo $PKG_NAME | sed 's/^4/FOUR/' | tr '[:lower:]' '[:upper:]')" - PKG_VERSION=$(newest_version $PKG_NAME) - echo "$PKG_NAME $PKG_VERSION $PKG_VAR" - fi - done -} - -# Check that all packages define a (valid) 'type' file, or exit -filtered_packages_list none || exit $? - -echo >&7 "# All Sage packages" - -filtered_packages_list all | while read PKG_NAME PKG_VERSION PKG_VAR; do - if test "$PKG_NAME" != "$PKG_VERSION"; then - echo >&7 "$PKG_VAR = $PKG_VERSION" - ]AC_MSG_RESULT([ $PKG_VAR=$PKG_VERSION])[ - fi -done - -cat >&7 <&7 'PYTHON = $(PYTHON3)' -else - echo >&7 'PYTHON = $(PYTHON2)' -fi -] - -# Sage MP library -echo >&7 "SAGE_MP_LIBRARY = \$($SAGE_MP_LIBRARY)" - -# $(TOOLCHAIN) variable containing prerequisites for the build -AS_ECHO_N(>&7 ['TOOLCHAIN =']) -if test "$SAGE_INSTALL_CCACHE" = yes ; then - AS_ECHO_N(>&7 [' $(INST)/$(CCACHE)']) -fi -if test "$need_to_install_gcc" = yes ; then - AS_ECHO_N(>&7 [' $(INST)/$(GCC)']) -fi -echo >&7 -echo >&7 - -[ -echo >&7 '# All standard packages' -echo >&7 'STANDARD_PACKAGES = \' -filtered_packages_list standard | while read PKG_NAME PKG_VERSION PKG_VAR; do - echo >&7 " \$(INST)/\$($PKG_VAR) \\" -done -echo >&7 -echo >&7 - -echo >&7 '# All optional installed packages (triggers the auto-update)' -echo >&7 'OPTIONAL_INSTALLED_PACKAGES = \' -filtered_packages_list optional | while read PKG_NAME PKG_VERSION PKG_VAR; do - if [ "$PKG_NAME" = "gcc" ]; then - continue - fi - if [ -f $SAGE_SPKG_INST/$PKG_NAME-* ]; then - echo >&7 " \$(INST)/\$($PKG_VAR) \\" - fi; -done -echo >&7 -echo >&7 - -echo >&7 'SCRIPT_SOURCES = \' -for file in "$SAGE_SRC/bin/"*; do - echo >&7 " \$(SAGE_SRC)${file#$SAGE_SRC} \\" -done -echo >&7 -echo >&7 'SCRIPTS = \' -for file in "$SAGE_SRC/bin/"*; do - echo >&7 " \$(SAGE_LOCAL)${file#$SAGE_SRC} \\" -done -echo >&7 -echo >&7 'EXTCODE_SOURCES = \' -for file in `find "$SAGE_SRC"/ext -type f`; do - echo >&7 " \$(SAGE_SRC)${file#$SAGE_SRC} \\" -done -echo >&7 -echo >&7 'EXTCODE = \' -for file in `find "$SAGE_SRC"/ext -type f`; do - echo >&7 " \$(SAGE_EXTCODE)${file#$SAGE_SRC/ext} \\" -done -echo >&7 - -# Copy build/make/deps -cat >&7 <&7 -# Copy build/make/deps - -cat >&7 </dependencies files -#============================================================================== - -EOF - -# Add a Makefile target corresponding to a given package -filtered_packages_list all | while read PKG_NAME PKG_VERSION PKG_VAR; do - DEP_FILE="$SAGE_ROOT/build/pkgs/$PKG_NAME/dependencies" - TYPE=`cat "$SAGE_ROOT/build/pkgs/$PKG_NAME/type"` - if [ -f "$DEP_FILE" ]; then - DEPS=" $(head -n 1 $DEP_FILE)" - elif [ "$TYPE" = optional ]; then - DEPS=' | $(STANDARD_PACKAGES)' # default for optional packages - elif [ "$TYPE" = pip ]; then - DEPS=' | $(INST)/$(PIP)' - else - DEPS="" - fi - - if [ "$TYPE" = pip ]; then - # Special rules using PIP - echo >&7 "$PKG_NAME:$DEPS" - echo >&7 " sage-logger 'sage --pip install $PKG_NAME' \$(SAGE_LOGS)/$PKG_NAME.log" - echo >&7 - - # Add a target to remove the "installed" file for "sage -f" - echo >&7 "$PKG_NAME-clean:" - echo >&7 " -sage --pip uninstall -y $PKG_NAME" - echo >&7 - else - # Normal Sage packages - echo >&7 "\$(INST)/$PKG_VERSION:$DEPS" - echo >&7 " +sage-logger '\$(SAGE_SPKG) \$($PKG_VAR)' '\$(SAGE_LOGS)/\$($PKG_VAR).log'" - echo >&7 - - # Add a target with just the bare package name for "sage -i" - echo >&7 "$PKG_NAME: \$(INST)/\$($PKG_VAR)" - echo >&7 - - # Add a target to remove the "installed" file for "sage -f" - echo >&7 "$PKG_NAME-clean:" - echo >&7 " rm -f \$(INST)/\$($PKG_VAR)" - echo >&7 - fi -done - -# Close the Makefile -exec 7>&- ] #--------------------------------------------------------- @@ -1077,6 +838,245 @@ AC_MSG_ERROR([["found Fink in $FINK_PATH. Either: fi +############################################################################### +# Create $SAGE_ROOT/build/make/Makefile starting from build/make/deps +############################################################################### + +# Use file descriptor 7 since make uses 3 and 4 and configure uses 5 and 6 +exec 7>build/make/Makefile + +cat >&7 <&7 "SHELL = `command -v bash`" +echo >&7 + +AC_MSG_CHECKING([package versions]) +AC_MSG_RESULT([]) + +# Usage: newest_version $pkg +# Print version number of latest standard package $pkg +newest_version() { + PKG=$1 + if test -f "$SAGE_ROOT/build/pkgs/$PKG/package-version.txt" ; then + AS_ECHO_N(["$PKG-"]) + cat "$SAGE_ROOT/build/pkgs/$PKG/package-version.txt" + else + echo "$PKG" + fi +} + +# Outputs the list of packages, filtered by 'type', e.g.: +# +# filtered_packages_list base +# filtered_packages_list standard +# filtered_packages_list optional +# filtered_packages_list experimental +# +# Or, if you want all packages: +# +# filtered_packages_list all +# +# The output consists of triples +# PKG_NAME PKG_VERSION PKG_VAR +# + +[ +filtered_packages_list() { + # for each package in pkgs/ + for DIR in $SAGE_ROOT/build/pkgs/*; do + test -d "$DIR" || continue + + PKG_TYPE_FILE="$DIR/type" + if [ -f "$PKG_TYPE_FILE" ]; then + PKG_TYPE=`cat $PKG_TYPE_FILE` + else + echo >&2 "\"$PKG_TYPE_FILE\" is missing. Create it, and set its content" + echo >&2 "to 'base', 'standard', 'optional' or 'experimental'." + return 1 + fi + + # Check consistency of 'DIR/type' file + if [ "$PKG_TYPE" != "base" ] && \ + [ "$PKG_TYPE" != "standard" ] && \ + [ "$PKG_TYPE" != "optional" ] && \ + [ "$PKG_TYPE" != "experimental" ] && \ + [ "$PKG_TYPE" != "pip" ]; then + echo >&2 "The content of \"$PKG_TYPE_FILE\" must be 'base', 'standard', 'optional', 'experimental' or 'pip'" + return 1 + fi + + # Filter + if [ "$1" = "$PKG_TYPE" -o "$1" = all ]; then + PKG_NAME=$(basename $DIR) + PKG_VAR="$(echo $PKG_NAME | sed 's/^4/FOUR/' | tr '[:lower:]' '[:upper:]')" + PKG_VERSION=$(newest_version $PKG_NAME) + echo "$PKG_NAME $PKG_VERSION $PKG_VAR" + fi + done +} + +# Check that all packages define a (valid) 'type' file, or exit +filtered_packages_list none || exit $? + +echo >&7 "# All Sage packages" + +filtered_packages_list all | while read PKG_NAME PKG_VERSION PKG_VAR; do + if test "$PKG_NAME" != "$PKG_VERSION"; then + echo >&7 "$PKG_VAR = $PKG_VERSION" + ]AC_MSG_RESULT([ $PKG_VAR=$PKG_VERSION])[ + fi +done + +cat >&7 <&7 'PYTHON = $(PYTHON3)' +else + echo >&7 'PYTHON = $(PYTHON2)' +fi +] + +# Sage MP library +echo >&7 "SAGE_MP_LIBRARY = \$($SAGE_MP_LIBRARY)" + +# $(TOOLCHAIN) variable containing prerequisites for the build +AS_ECHO_N(>&7 ['TOOLCHAIN =']) +if test "$SAGE_INSTALL_CCACHE" = yes ; then + AS_ECHO_N(>&7 [' $(INST)/$(CCACHE)']) +fi +if test "$need_to_install_gcc" = yes ; then + AS_ECHO_N(>&7 [' $(INST)/$(GCC)']) +fi +echo >&7 +echo >&7 + +[ +echo >&7 '# All standard packages' +echo >&7 'STANDARD_PACKAGES = \' +filtered_packages_list standard | while read PKG_NAME PKG_VERSION PKG_VAR; do + echo >&7 " \$(INST)/\$($PKG_VAR) \\" +done +echo >&7 +echo >&7 + +echo >&7 '# All optional installed packages (triggers the auto-update)' +echo >&7 'OPTIONAL_INSTALLED_PACKAGES = \' +filtered_packages_list optional | while read PKG_NAME PKG_VERSION PKG_VAR; do + if [ "$PKG_NAME" = "gcc" ]; then + continue + fi + if [ -f $SAGE_SPKG_INST/$PKG_NAME-* ]; then + echo >&7 " \$(INST)/\$($PKG_VAR) \\" + fi; +done +echo >&7 +echo >&7 + +echo >&7 'SCRIPT_SOURCES = \' +for file in "$SAGE_SRC/bin/"*; do + echo >&7 " \$(SAGE_SRC)${file#$SAGE_SRC} \\" +done +echo >&7 +echo >&7 'SCRIPTS = \' +for file in "$SAGE_SRC/bin/"*; do + echo >&7 " \$(SAGE_LOCAL)${file#$SAGE_SRC} \\" +done +echo >&7 +echo >&7 'EXTCODE_SOURCES = \' +for file in `find "$SAGE_SRC"/ext -type f`; do + echo >&7 " \$(SAGE_SRC)${file#$SAGE_SRC} \\" +done +echo >&7 +echo >&7 'EXTCODE = \' +for file in `find "$SAGE_SRC"/ext -type f`; do + echo >&7 " \$(SAGE_EXTCODE)${file#$SAGE_SRC/ext} \\" +done +echo >&7 + +# Copy build/make/deps +cat >&7 <&7 +# Copy build/make/deps + +cat >&7 </dependencies files +#============================================================================== + +EOF + +# Add a Makefile target corresponding to a given package +filtered_packages_list all | while read PKG_NAME PKG_VERSION PKG_VAR; do + DEP_FILE="$SAGE_ROOT/build/pkgs/$PKG_NAME/dependencies" + TYPE=`cat "$SAGE_ROOT/build/pkgs/$PKG_NAME/type"` + if [ -f "$DEP_FILE" ]; then + DEPS=" $(head -n 1 $DEP_FILE)" + elif [ "$TYPE" = optional ]; then + DEPS=' | $(STANDARD_PACKAGES)' # default for optional packages + elif [ "$TYPE" = pip ]; then + DEPS=' | $(INST)/$(PIP)' + else + DEPS="" + fi + + if [ "$TYPE" = pip ]; then + # Special rules using PIP + echo >&7 "$PKG_NAME:$DEPS" + echo >&7 " sage-logger 'sage --pip install $PKG_NAME' \$(SAGE_LOGS)/$PKG_NAME.log" + echo >&7 + + # Add a target to remove the "installed" file for "sage -f" + echo >&7 "$PKG_NAME-clean:" + echo >&7 " -sage --pip uninstall -y $PKG_NAME" + echo >&7 + else + # Normal Sage packages + echo >&7 "\$(INST)/$PKG_VERSION:$DEPS" + echo >&7 " +sage-logger '\$(SAGE_SPKG) \$($PKG_VAR)' '\$(SAGE_LOGS)/\$($PKG_VAR).log'" + echo >&7 + + # Add a target with just the bare package name for "sage -i" + echo >&7 "$PKG_NAME: \$(INST)/\$($PKG_VAR)" + echo >&7 + + # Add a target to remove the "installed" file for "sage -f" + echo >&7 "$PKG_NAME-clean:" + echo >&7 " rm -f \$(INST)/\$($PKG_VAR)" + echo >&7 + fi +done + +# Close the Makefile +exec 7>&- +] + + dnl AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([build/make/Makefile-auto]) AC_CONFIG_MACRO_DIR([m4]) From fe6f95c764bbc69663ac6a68cc92723426ec40d2 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Fri, 25 Sep 2015 15:55:49 +0200 Subject: [PATCH 1032/1872] #17190: Authorize empty dictionary in initialization of polynomial over RR --- .../polynomial/polynomial_real_mpfr_dense.pyx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index 9e10335ee2c..a0986cbedb5 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -68,7 +68,7 @@ cdef class PolynomialRealDense(Polynomial): TESTS: - Check that errors and interrupts are handled properly (see #10100):: + Check that errors and interrupts are handled properly (see :trac:`10100`):: sage: a = var('a') sage: PolynomialRealDense(RR['x'], [1,a]) @@ -83,7 +83,7 @@ cdef class PolynomialRealDense(Polynomial): sage: sig_on_count() 0 - Test that we don't clean up uninitialized coefficients (#9826):: + Test that we don't clean up uninitialized coefficients (:trac:`9826`):: sage: k. = GF(7^3) sage: P. = PolynomialRing(k) @@ -91,6 +91,10 @@ cdef class PolynomialRealDense(Polynomial): Traceback (most recent call last): ... TypeError: Unable to convert x (='a') to real number. + + Check that :trac:`17190` is fixed:: + sage: RR['x']({}) + 0 """ Polynomial.__init__(self, parent, is_gen=is_gen) self._base_ring = parent._base @@ -108,11 +112,7 @@ cdef class PolynomialRealDense(Polynomial): elif isinstance(x, (int, float, Integer, Rational, RealNumber)): x = [x] elif isinstance(x, dict): - degree = max(x.keys()) - c = [0] * (degree+1) - for i, a in x.items(): - c[i] = a - x = c + x = self._dict_to_list(x,self._base_ring.zero()) elif isinstance(x, pari_gen): x = [self._base_ring(w) for w in x.list()] elif not isinstance(x, list): @@ -665,9 +665,9 @@ cdef class PolynomialRealDense(Polynomial): sage: f = PolynomialRealDense(RR['x']) sage: f(12) 0.000000000000000 - + TESTS:: - + sage: R. = RR[] # :trac:`17311` sage: (x^2+1)(x=5) 26.0000000000000 @@ -676,13 +676,13 @@ cdef class PolynomialRealDense(Polynomial): xx = args[0] else: return Polynomial.__call__(self, *args, **kwds) - + if not isinstance(xx, RealNumber): if self._base_ring.has_coerce_map_from(parent(xx)): xx = self._base_ring(xx) else: return Polynomial.__call__(self, xx) - + cdef Py_ssize_t i cdef mp_rnd_t rnd = self._base_ring.rnd cdef RealNumber x = xx @@ -713,7 +713,7 @@ cdef class PolynomialRealDense(Polynomial): mpfr_mul(res.value, res.value, x.value, rnd) mpfr_add(res.value, res.value, self._coeffs[i], rnd) return res - + def change_ring(self, R): """ EXAMPLES:: From 6315d74ebf51bc82c26d6dafd389f52d895c8d78 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Fri, 25 Sep 2015 16:29:53 +0200 Subject: [PATCH 1033/1872] #17190: Add missing blank line --- src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index a0986cbedb5..46c8e1dcbfc 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -93,6 +93,7 @@ cdef class PolynomialRealDense(Polynomial): TypeError: Unable to convert x (='a') to real number. Check that :trac:`17190` is fixed:: + sage: RR['x']({}) 0 """ From ca0f846ca4ab829c3356271233d3bce3e9a31e76 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 25 Sep 2015 11:22:31 -0500 Subject: [PATCH 1034/1872] Fixing doctest failures. --- src/sage/misc/c3_controlled.pyx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index cb1c4fe2e18..35253502a88 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -326,9 +326,9 @@ For a typical category, few bases, if any, need to be added to force sage: x.mro == x.mro_standard False sage: x.all_bases_len() - 82 + 84 sage: x.all_bases_controlled_len() - 89 + 91 The following can be used to search through the Sage named categories for any that requires the addition of some bases:: @@ -343,8 +343,7 @@ for any that requires the addition of some bases:: Category of finite dimensional algebras with basis over Rational Field, Category of finite dimensional hopf algebras with basis over Rational Field, Category of finite permutation groups, - Category of graded hopf algebras with basis over Rational Field, - Category of hopf algebras with basis over Rational Field] + Category of graded hopf algebras with basis over Rational Field] AUTHOR: From 0780530a7a7457e13f0cdd1f6ff006782466f0cf Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 25 Sep 2015 11:59:25 -0700 Subject: [PATCH 1035/1872] TL;DR: abbrvs now dead --- .../graphs/generators/classical_geometries.py | 20 +++++++++---------- src/sage/graphs/graph_generators.py | 8 ++++---- src/sage/graphs/strongly_regular_db.pyx | 20 +++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index f7e92ae13d5..3081a3eadc3 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -936,7 +936,7 @@ def TaylorTwographSRG(q): G.name("Taylor two-graph SRG") return G -def AhrensSzekeresGQGraph(q, dual=False): +def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): r""" Return the collinearity graph of the generalized quadrangle `AS(q)`, or of its dual @@ -959,11 +959,11 @@ def AhrensSzekeresGQGraph(q, dual=False): EXAMPLES:: - sage: g=graphs.AhrensSzekeresGQGraph(5); g + sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g AS(5); GQ(4, 6): Graph on 125 vertices sage: g.is_strongly_regular(parameters=True) (125, 28, 3, 7) - sage: g=graphs.AhrensSzekeresGQGraph(5,dual=True); g + sage: g=graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5,dual=True); g AS(5)*; GQ(6, 4): Graph on 175 vertices sage: g.is_strongly_regular(parameters=True) (175, 30, 5, 5) @@ -998,11 +998,11 @@ def AhrensSzekeresGQGraph(q, dual=False): G.name('AS('+str(q)+'); GQ'+str((q-1,q+1))) return G -def T2starGQGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): +def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): r""" Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual - Let `q=2^k` and `\Theta=PG(3,q)`. `T_2^*(q)` is a generalised quadrangle [GQwiki]_ + Let `q=2^k` and `\Theta=PG(3,q)`. `T_2^*(q)` is a generalized quadrangle [GQwiki]_ of order `(q-1,q+1)`, see 3.1.3 in [PT09]_. Fix a plane `\Pi \subset \Theta` and a `hyperoval `__ `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of `\Theta` @@ -1035,11 +1035,11 @@ def T2starGQGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=Tru using the built-in construction:: - sage: g=graphs.T2starGQGraph(4); g + sage: g=graphs.T2starGeneralizedQuadrangleGraph(4); g T2*(O,4); GQ(3, 5): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) - sage: g=graphs.T2starGQGraph(4,dual=True); g + sage: g=graphs.T2starGeneralizedQuadrangleGraph(4,dual=True); g T2*(O,4)*; GQ(5, 3): Graph on 96 vertices sage: g.is_strongly_regular(parameters=True) (96, 20, 4, 4) @@ -1048,7 +1048,7 @@ def T2starGQGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=Tru sage: F=GF(4,'b') sage: O=[vector(F,(0,0,0,1)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) - sage: g=graphs.T2starGQGraph(4, hyperoval=O, field=F); g + sage: g=graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g T2*(O,4); GQ(3, 5): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) @@ -1057,12 +1057,12 @@ def T2starGQGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=Tru sage: F=GF(4,'b') # repeating a point... sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) - sage: graphs.T2starGQGraph(4, hyperoval=O, field=F) + sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+map(lambda x: vector(F, (0,1,x^2,x)),F) - sage: graphs.T2starGQGraph(4, hyperoval=O, field=F) + sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 25c012b0bd2..3db5bb3f4da 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -235,7 +235,7 @@ def __append_to_doc(methods): __append_to_doc( ["AffineOrthogonalPolarGraph", - "AhrensSzekeresGQGraph", + "AhrensSzekeresGeneralizedQuadrangleGraph", "NonisotropicOrthogonalPolarGraph", "NonisotropicUnitaryPolarGraph", "OrthogonalPolarGraph", @@ -243,7 +243,7 @@ def __append_to_doc(methods): "SymplecticPolarGraph", "TaylorTwographDescendantSRG", "TaylorTwographSRG", - "T2starGQGraph", + "T2starGeneralizedQuadrangleGraph", "UnitaryDualPolarGraph", "UnitaryPolarGraph"]) @@ -1999,7 +1999,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None ########################################################################### import sage.graphs.generators.classical_geometries AffineOrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.AffineOrthogonalPolarGraph) - AhrensSzekeresGQGraph = staticmethod(sage.graphs.generators.classical_geometries.AhrensSzekeresGQGraph) + AhrensSzekeresGeneralizedQuadrangleGraph = staticmethod(sage.graphs.generators.classical_geometries.AhrensSzekeresGeneralizedQuadrangleGraph) NonisotropicOrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph) NonisotropicUnitaryPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.NonisotropicUnitaryPolarGraph) OrthogonalPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.OrthogonalPolarGraph) @@ -2009,7 +2009,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None TaylorTwographDescendantSRG = \ staticmethod(sage.graphs.generators.classical_geometries.TaylorTwographDescendantSRG) TaylorTwographSRG = staticmethod(sage.graphs.generators.classical_geometries.TaylorTwographSRG) - T2starGQGraph = staticmethod(sage.graphs.generators.classical_geometries.T2starGQGraph) + T2starGeneralizedQuadrangleGraph = staticmethod(sage.graphs.generators.classical_geometries.T2starGeneralizedQuadrangleGraph) UnitaryDualPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.UnitaryDualPolarGraph) UnitaryPolarGraph = staticmethod(sage.graphs.generators.classical_geometries.UnitaryPolarGraph) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 3006c7f827e..b1019c1d265 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -876,23 +876,23 @@ def is_GQqmqp(int v,int k,int l,int mu): sage: from sage.graphs.strongly_regular_db import is_GQqmqp sage: t = is_GQqmqp(27,10,1,5); t - (, 3, False) + (, 3, False) sage: g = t[0](*t[1:]); g AS(3); GQ(2, 4): Graph on 27 vertices sage: t = is_GQqmqp(45,12,3,3); t - (, 3, True) + (, 3, True) sage: g = t[0](*t[1:]); g AS(3)*; GQ(4, 2): Graph on 45 vertices sage: g.is_strongly_regular(parameters=True) (45, 12, 3, 3) sage: t = is_GQqmqp(16,6,2,2); t - (, 2, True) + (, 2, True) sage: g = t[0](*t[1:]); g T2*(O,2)*; GQ(3, 1): Graph on 16 vertices sage: g.is_strongly_regular(parameters=True) (16, 6, 2, 2) sage: t = is_GQqmqp(64,18,2,6); t - (, 4, False) + (, 4, False) sage: g = t[0](*t[1:]); g T2*(O,4); GQ(3, 5): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) @@ -902,16 +902,16 @@ def is_GQqmqp(int v,int k,int l,int mu): sage: (S,T)=(127,129) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t - (, 128, False) + (, 128, False) sage: (S,T)=(129,127) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t - (, 128, True) + (, 128, True) sage: (S,T)=(124,126) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t - (, 125, False) + (, 125, False) sage: (S,T)=(126,124) sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t - (, 125, True) + (, 125, True) sage: t = is_GQqmqp(5,5,5,5); t """ # do we have GQ(s,t)? we must have mu=t+1, s=l+1, @@ -926,10 +926,10 @@ def is_GQqmqp(int v,int k,int l,int mu): (S+T)/2 == q): if p % 2 == 0: from sage.graphs.generators.classical_geometries\ - import T2starGQGraph as F + import T2starGeneralizedQuadrangleGraph as F else: from sage.graphs.generators.classical_geometries\ - import AhrensSzekeresGQGraph as F + import AhrensSzekeresGeneralizedQuadrangleGraph as F if (S,T) == (q-1, q+1): return (F, q, False) elif (S,T) == (q+1, q-1): From 371febf3f0365ae956325f4e651e81ac6041d85e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 25 Sep 2015 21:05:18 +0200 Subject: [PATCH 1036/1872] trac #19284, check vector and matrix type, also trying to make a basic parser --- src/sage/interfaces/octave.py | 97 +++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index b26c4fe617b..47da9f0ce15 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -311,9 +311,9 @@ def _equality_symbol(self): """ EXAMPLES:: - sage: octave('0 == 1') + sage: octave('0 == 1') # optional - octave 0 - sage: octave('1 == 1') + sage: octave('1 == 1') # optional - octave 1 """ return '==' @@ -322,7 +322,7 @@ def _true_symbol(self): """ EXAMPLES:: - sage: octave('1 == 1') + sage: octave('1 == 1') # optional - octave 1 """ return '1' @@ -331,7 +331,7 @@ def _false_symbol(self): """ EXAMPLES:: - sage: octave('0 == 1') + sage: octave('0 == 1') # optional - octave 0 """ return '0' @@ -550,6 +550,9 @@ def _matrix_(self, R): [3.00000000000000 4.50000000000000] """ from sage.matrix.all import MatrixSpace + oc = self.parent() + if not oc('ismatrix(%s)' % self): + raise TypeError('not an octave matrix') s = str(self).strip('\n ') w = [u.strip().split(' ') for u in s.split('\n')] nrows = len(w) @@ -570,11 +573,97 @@ def _vector_(self, R): [1.00000000000000 2.30000000000000 4.50000000000000] """ from sage.modules.free_module import FreeModule + oc = self.parent() + if not oc('isvector(%s)' % self): + raise TypeError('not an octave vector') s = str(self).strip('\n ') w = s.strip().split(' ') nrows = len(w) return FreeModule(R, nrows)(w) + def _scalar_(self, find_parent=False): + """ + Return Sage scalar from this octave element. + + INPUT: + + - find_parent -- boolean (default ``False``). If ``True`` also return + the ring to which the scalar belongs. + + EXAMPLES:: + + sage: A = octave('2833') # optional - octave + sage: As = A.sage(); As # optional - octave + 2833 + sage: As.parent() # optional - octave + Integer Ring + sage: B = sqrt(A) # optional - octave + sage: Bs = B.sage(); Bs # optional - octave + 53.2259 + sage: Bs.parent() # optional - octave + Real Field with 53 bits of precision + sage: C = sqrt(-A) # optional - octave + sage: Cs = C.sage(); Cs # optional - octave + 53.2259*I + sage: Cs.parent() # optional - octave + Complex Field with 53 bits of precision + """ + from sage.rings.complex_double import CDF + from sage.rings.integer_ring import ZZ + from sage.rings.real_double import RDF + oc = self.parent() + if oc('isinteger(%s)' % self): + if not find_parent: + return ZZ(str(self)) + else: + return ZZ(str(self)), ZZ + elif oc('isreal(%s)' % self): + if not find_parent: + return RDF(str(self)) + else: + return RDF(str(self)), RDF + elif oc('iscomplex(%s)' % self): + real, imag = str(self).strip('() ').split(',') + if not find_parent: + return CDF(RDF(real), RDF(imag)) + else: + return CDF(RDF(real), RDF(imag)), CDF + + def _sage_(self): + """ + Try to parse the octave object and return a sage object. + + EXAMPLES:: + + sage: A = octave('2833') # optional - octave + sage: A.sage() # optional - octave + 2833 + sage: B = sqrt(A) # optional - octave + sage: B.sage() # optional - octave + 53.2259 + sage: C = sqrt(-A) # optional - octave + sage: C.sage() # optional - octave + 53.2259*I + sage: A = octave('[1,2,3,4]') # optional - octave + sage: A.sage() # optional - octave + [1 2 3 4] + sage: A = octave('[1,2.3,4.5]') # optional - octave + sage: A.sage() # optional - octave + [1.00000000000000 2.30000000000000 4.50000000000000] + sage: A = octave('[1,2.3+I,4.5]') # optional - octave + sage: A.sage() # optional - octave + [1.00000000000000 2.30000000000000+1.0*I 4.50000000000000] + """ + oc = self.parent() + if oc('isscalar(%s)' % self): + return self._scalar_() + elif oc('isvector(%s)' % self): + return self._vector_() + elif oc('ismatrix(%s)' % self): + return self._matrix_() + else: + raise NotImplementedError('octave type is not recognized') + # An instance octave = Octave() From 3848dc75d2811fbae85c33b3a1e599f569daf7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 25 Sep 2015 21:13:38 +0200 Subject: [PATCH 1037/1872] trac #18937 version 2.5.0, (grep removed in doc plugin and adapted to sage 6.9 by using ./configure) --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index a5f3f2d4a37..59c2a0e4222 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=f4e1cb57aca1f8225e1c2baca228dccf232c424d -md5=6d67b4ea3c3559135a5edc2c01f776cd -cksum=1760773179 +sha1=80a4c95fd2a476efb6ea3bafa8da0edfeba6f9eb +md5=eab98d58cd9822821f81e69516396f79 +cksum=783383131 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 3f5987a5cb2..437459cd94c 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.4.9 +2.5.0 From f9c2cf07c33553cc7f4e513051b53faf461a4aee Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Sat, 26 Sep 2015 14:24:47 +0900 Subject: [PATCH 1038/1872] Recovering a missing text line on the plotting capability. --- src/doc/ja/a_tour_of_sage/index.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/doc/ja/a_tour_of_sage/index.rst b/src/doc/ja/a_tour_of_sage/index.rst index 46c8f23f845..eeb8e01da5f 100644 --- a/src/doc/ja/a_tour_of_sage/index.rst +++ b/src/doc/ja/a_tour_of_sage/index.rst @@ -58,6 +58,11 @@ Sageでは等号として記号 ``==`` を使う. sage: S[0].rhs() -1/2*sqrt(4*a + 1) - 1/2 + +もちろん,よく使われる種々の関数をプロットすることもできる. + +:: + sage: show(plot(sin(x) + sin(1.6*x), 0, 40)) .. image:: sin_plot.* From 2a5609463a71f7baab5a9f028112bab3de20fd36 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 26 Sep 2015 18:19:32 +0200 Subject: [PATCH 1039/1872] trac #19279: Settling the definition issue --- .../combinat/designs/incidence_structures.py | 19 ++++++++++++++++--- .../graphs/generators/classical_geometries.py | 3 +-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 3373ddb06b9..bab1c8df92c 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1644,7 +1644,8 @@ def is_generalized_quadrangle(self, verbose=False, parameters=False): r""" Test if the incidence structure is a generalized quadrangle. - An incidence structure is a generalized quadrangle iif: + An incidence structure is a generalized quadrangle iff (see [BH12]_, + section 9.6): - two blocks intersect on at most one point. @@ -1659,6 +1660,13 @@ def is_generalized_quadrangle(self, verbose=False, parameters=False): For more information, see the :wikipedia:`Generalized_quadrangle`. + .. NOTE:: + + Observe that some references (e.g. [PT09]_ or Wikipedia) only allow + *regular* generalized quadrangles. To use such a definition, see the + ``parameters`` optional argument described below, or the methods + :meth:`is_regular` and :meth:`is_uniform`. + INPUT: - ``verbose`` (boolean) -- whether to print an explanation when the @@ -1697,6 +1705,13 @@ def is_generalized_quadrangle(self, verbose=False, parameters=False): sage: hypergraphs.CompleteUniform(4,2).is_generalized_quadrangle(verbose=1) Some point has two projections on some line. False + + REFERENCE: + + .. [PT09] S. Payne, J. Thas, + Finite generalized quadrangles, + European Mathematical Society, 2009. + http://cage.ugent.be/~bamberg/FGQ.pdf """ # The distance between a point and a line in the incidence graph is odd # and must be <= 3. Thus, the diameter is at most 4 @@ -1727,8 +1742,6 @@ def is_generalized_quadrangle(self, verbose=False, parameters=False): else: return True - - def dual(self, algorithm=None): """ Return the dual of the incidence structure. diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index cae8a1e9e30..7e86a0352e6 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -637,12 +637,11 @@ def UnitaryPolarGraph(m, q, algorithm="gap"): from sage.schemes.projective.projective_space import ProjectiveSpace from sage.rings.finite_rings.constructor import FiniteField from sage.modules.free_module_element import free_module_element as vector - from __builtin__ import sum as psum Fq = FiniteField(q**2, 'a') PG = map(vector, ProjectiveSpace(m - 1, Fq)) map(lambda x: x.set_immutable(), PG) def P(x,y): - return psum(map(lambda j: x[j]*y[m-1-j]**q, xrange(m)))==0 + return sum(map(lambda j: x[j]*y[m-1-j]**q, xrange(m)))==0 V = filter(lambda x: P(x,x), PG) G = Graph([V,lambda x,y: # bottleneck is here, of course: From 25a60cb27ea91e4a001a8e370e2d08a615a43c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 27 Sep 2015 09:14:54 +0200 Subject: [PATCH 1040/1872] trac #18937 version 2.5.1, back to simple "make" in doc plugins --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index 59c2a0e4222..f67bd8165cd 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=80a4c95fd2a476efb6ea3bafa8da0edfeba6f9eb -md5=eab98d58cd9822821f81e69516396f79 -cksum=783383131 +sha1=cbf2002db03d3bf45be16202005b9c75afa99ed2 +md5=862de73795502ae064c172e7c196c1fc +cksum=973755707 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 437459cd94c..73462a5a134 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.5.0 +2.5.1 From f61803a88c49fb7c5c18a59dae3a4b6f693525ce Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:05:52 +0200 Subject: [PATCH 1041/1872] Trac #17693, comment 36, 46: explain difference remove/discard --- src/sage/data_structures/mutable_poset.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 727ebf2c532..d87ecba4683 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2024,6 +2024,17 @@ def remove(self, key, raise_key_error=True): If the element is not a member and ``raise_key_error`` is set (default), raise a ``KeyError``. + .. NOTE:: + + As with Python's ``set``, the methods :meth:`remove` + and meth:`discard` only differ in their behavior when an + element is not contained in the poset: :meth:`remove` + raises a ``KeyError`` whereas :meth:`discard` does not + raise any exception. + + This default behavior can be overridden with the + ``raise_key_error`` parameter. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2083,6 +2094,11 @@ def remove(self, key, raise_key_error=True): | +-- successors: (1, 1) | +-- no predecessors + .. SEEALSO:: + + :meth:`discard`, + :meth:`pop`. + TESTS:: sage: Q = MP([(1, 1, 42), (1, 3, 42), (2, 1, 7), @@ -2187,6 +2203,17 @@ def discard(self, key, raise_key_error=False): If the element is not a member and ``raise_key_error`` is set (not default), raise a ``KeyError``. + .. NOTE:: + + As with Python's ``set``, the methods :meth:`remove` + and meth:`discard` only differ in their behavior when an + element is not contained in the poset: :meth:`remove` + raises a ``KeyError`` whereas :meth:`discard` does not + raise any exception. + + This default behavior can be overridden with the + ``raise_key_error`` parameter. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2201,6 +2228,11 @@ def discard(self, key, raise_key_error=False): ... KeyError: 'Key (1, 2) is not contained in this poset.' sage: P.discard(T((1, 2))) + + .. SEEALSO:: + + :meth:`remove`, + :meth:`pop`. """ return self.remove(key, raise_key_error) From 2e687daa1b42b20b028371f667cf180dc5545f93 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:08:02 +0200 Subject: [PATCH 1042/1872] Trac #17693, comment 36, 47: remove key from doctest of pop --- src/sage/data_structures/mutable_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d87ecba4683..246013ed0c2 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2252,7 +2252,7 @@ def pop(self, **kwargs): EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP - sage: P = MP(key=lambda c: -c) + sage: P = MP() sage: P.add(3) sage: P poset(3) From cf5aa19d2d9dd9a0dc6c74634937701cd597565b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:09:45 +0200 Subject: [PATCH 1043/1872] Trac #17693, comment 36, 48: add note that special elements cannot be popped --- src/sage/data_structures/mutable_poset.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 246013ed0c2..044efd0e35c 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2249,6 +2249,10 @@ def pop(self, **kwargs): An object. + .. NOTE:: + + The special elements ``'null'`` and ``'oo'`` cannot be popped. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 852b71ae01b0f0961068c03d7c86dc165a5f8af3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:11:54 +0200 Subject: [PATCH 1044/1872] Trac #17693, comment 36, 49: simplify code of pop --- src/sage/data_structures/mutable_poset.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 044efd0e35c..e470887ec53 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2269,10 +2269,6 @@ def pop(self, **kwargs): ... KeyError: 'pop from an empty poset' """ - try: - del kwargs['include_special'] - except KeyError: - pass kwargs['include_special'] = False try: From d718694c9311b46b4c6e34084de672e9010d11e4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:41:07 +0200 Subject: [PATCH 1045/1872] Trac #17693, comment 36, 50: extend description of INPUT-block --- src/sage/data_structures/mutable_poset.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index e470887ec53..40e88c28586 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2287,6 +2287,8 @@ def union(self, *other): - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. + It is possible to specify more than one ``other`` as + variadic arguments (arbitrary argument lists). OUTPUT: @@ -2327,6 +2329,8 @@ def union_update(self, other): - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. + It is possible to specify more than one ``other`` as + variadic arguments (arbitrary argument lists). OUTPUT: From ac7030514567374889feab7abc9a8e370d17dd57 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:42:08 +0200 Subject: [PATCH 1046/1872] Trac #17693, comment 36, 51: note extended/changed --- src/sage/data_structures/mutable_poset.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 40e88c28586..ec0c02f61d8 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2296,9 +2296,11 @@ def union(self, *other): .. NOTE:: - If this poset uses a ``key``-function, then all - comparisons are performed on the keys of the elements (and - not on the elements themselves). + The key of an element is used for comparison. Thus elements with + the same key are considered as equal. + + Due to keys and a ``merge`` function (see :class:`MutablePoset`) + this operation might not be commutative. EXAMPLES:: @@ -2338,9 +2340,11 @@ def union_update(self, other): .. NOTE:: - If this poset uses a ``key``-function, then all - comparisons are performed on the keys of the elements (and - not on the elements themselves). + The key of an element is used for comparison. Thus elements with + the same key are considered as equal. + + Due to keys and a ``merge`` function (see :class:`MutablePoset`) + this operation might not be commutative. .. TODO:: From bbd93167dd19c0d537e030323af59af4524e2687 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:42:31 +0200 Subject: [PATCH 1047/1872] Trac #17693, comment 36, 52: add TODO box --- src/sage/data_structures/mutable_poset.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ec0c02f61d8..12c9b9df164 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2302,6 +2302,12 @@ def union(self, *other): Due to keys and a ``merge`` function (see :class:`MutablePoset`) this operation might not be commutative. + .. TODO:: + + Use the already existing information in the other poset to speed + up this function. (At the moment each element of the other poset + is inserted one by one and without using this information.) + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From aa00e5604327ee3f7ee33b69d99f73d02b514869 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:43:15 +0200 Subject: [PATCH 1048/1872] Trac #17693, comment 36, 53: rewrite code to unify union/union_update --- src/sage/data_structures/mutable_poset.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 12c9b9df164..d7e0aa70b25 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2324,12 +2324,11 @@ def union(self, *other): poset(3, 4, 7, 8, 42) """ new = self.copy() - for o in other: - new.update(o) + new.update(*other) return new - def union_update(self, other): + def union_update(self, *other): r""" Update this poset with the union of itself and another poset. @@ -2375,12 +2374,13 @@ def union_update(self, other): sage: Q poset(3, 4, 7, 8, 42) """ - try: - it = other.elements() - except AttributeError: - it = iter(other) - for element in it: - self.add(element) + for o in other: + try: + it = o.elements() + except AttributeError: + it = iter(o) + for element in it: + self.add(element) update = union_update # as in a Python set From f2df1bb599f96726b5247cd454f3d800dd99d480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Mon, 28 Sep 2015 10:47:51 +0300 Subject: [PATCH 1049/1872] Added a check for bfs parameters. --- src/sage/graphs/generic_graph.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 84938f5c7eb..324f91dda61 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -15941,6 +15941,10 @@ def breadth_first_search(self, start, ignore_direction=False, sage: list(D.breadth_first_search(0, ignore_direction=True)) [0, 1, 2] """ + from sage.rings.semirings.non_negative_integer_semiring import NN + if (distance is not None and distance not in NN): + raise ValueError("distance must be non-negative integer, not {0}".format(distance)) + # Preferably use the Cython implementation if neighbors is None and not isinstance(start, list) and distance is None and hasattr(self._backend,"breadth_first_search") and not report_distance: for v in self._backend.breadth_first_search(start, ignore_direction=ignore_direction): @@ -15957,6 +15961,12 @@ def breadth_first_search(self, start, ignore_direction=False, else: queue = [(start, 0)] + # Non-existing start vertex is detected later if distance > 0. + if distance == 0: + for v in queue: + if not v[0] in self: + raise LookupError("start vertex ({0}) is not a vertex of the graph".format(v[0])) + for v, d in queue: if report_distance: yield v, d @@ -15983,7 +15993,6 @@ def depth_first_search(self, start, ignore_direction=False, INPUT: - - ``start`` - vertex or list of vertices from which to start the traversal From 141ef15293c10b2516fce41c485e4a39e8326bd0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:48:57 +0200 Subject: [PATCH 1050/1872] Trac #17693, comment 36, 54: changes to difference --- src/sage/data_structures/mutable_poset.py | 38 ++++++++++++++--------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d7e0aa70b25..8e619182821 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2398,6 +2398,8 @@ def difference(self, *other): - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. + It is possible to specify more than one ``other`` as + variadic arguments (arbitrary argument lists). OUTPUT: @@ -2405,9 +2407,11 @@ def difference(self, *other): .. NOTE:: - If this poset uses a ``key``-function, then all - comparisons are performed on the keys of the elements (and - not on the elements themselves). + The key of an element is used for comparison. Thus elements with + the same key are considered as equal. + + Due to keys and a ``merge`` function (see :class:`MutablePoset`) + this operation might not be commutative. EXAMPLES:: @@ -2429,12 +2433,11 @@ def difference(self, *other): poset() """ new = self.copy() - for o in other: - new.difference_update(o) + new.difference_update(*other) return new - def difference_update(self, other): + def difference_update(self, *other): r""" Remove all elements of another poset from this poset. @@ -2442,6 +2445,8 @@ def difference_update(self, other): - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. + It is possible to specify more than one ``other`` as + variadic arguments (arbitrary argument lists). OUTPUT: @@ -2449,9 +2454,11 @@ def difference_update(self, other): .. NOTE:: - If this poset uses a ``key``-function, then all - comparisons are performed on the keys of the elements (and - not on the elements themselves). + The key of an element is used for comparison. Thus elements with + the same key are considered as equal. + + Due to keys and a ``merge`` function (see :class:`MutablePoset`) + this operation might not be commutative. EXAMPLES:: @@ -2464,12 +2471,13 @@ def difference_update(self, other): sage: P poset(3, 7) """ - try: - it = other.keys() - except AttributeError: - it = iter(other) - for key in it: - self.discard(key) + for o in other: + try: + it = o.keys() + except AttributeError: + it = iter(o) + for key in it: + self.discard(key) def intersection(self, *other): From 673a1a0c02070e0efd4c00b87e37a74771c85d85 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:55:03 +0200 Subject: [PATCH 1051/1872] Trac #17693, comment 36, 54+55: changes to intersection --- src/sage/data_structures/mutable_poset.py | 32 +++++++++++++---------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8e619182821..de892ad8a78 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2488,6 +2488,8 @@ def intersection(self, *other): - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. + It is possible to specify more than one ``other`` as + variadic arguments (arbitrary argument lists). OUTPUT: @@ -2495,9 +2497,11 @@ def intersection(self, *other): .. NOTE:: - If this poset uses a ``key``-function, then all - comparisons are performed on the keys of the elements (and - not on the elements themselves). + The key of an element is used for comparison. Thus elements with + the same key are considered as equal. + + Due to keys and a ``merge`` function (see :class:`MutablePoset`) + this operation might not be commutative. EXAMPLES:: @@ -2515,12 +2519,11 @@ def intersection(self, *other): poset(42) """ new = self.copy() - for o in other: - new.intersection_update(o) + new.intersection_update(*other) return new - def intersection_update(self, other): + def intersection_update(self, *other): r""" Update this poset with the intersection of itself and another poset. @@ -2528,6 +2531,8 @@ def intersection_update(self, other): - ``other`` -- a poset or an iterable. In the latter case the iterated objects are seen as elements of a poset. + It is possible to specify more than one ``other`` as + variadic arguments (arbitrary argument lists). OUTPUT: @@ -2535,9 +2540,11 @@ def intersection_update(self, other): .. NOTE:: - If this poset uses a ``key``-function, then all - comparisons are performed on the keys of the elements (and - not on the elements themselves). + The key of an element is used for comparison. Thus elements with + the same key are considered as equal. + + Due to keys and a ``merge`` function (see :class:`MutablePoset`) + this operation might not be commutative. EXAMPLES:: @@ -2550,12 +2557,9 @@ def intersection_update(self, other): sage: P poset(42) """ - try: - keys = tuple(self.keys()) - except AttributeError: - keys = tuple(iter(self)) + keys = tuple(self.keys()) for key in keys: - if key not in other: + if any(key not in o for o in other): self.discard(key) From d27425671e3b8fc3b562758cd4c7b04622b42979 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 09:58:39 +0200 Subject: [PATCH 1052/1872] Trac #17693, comment 36, 57: document parameter reverse better in merge --- src/sage/data_structures/mutable_poset.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index de892ad8a78..cf1d66e4689 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2776,7 +2776,10 @@ def merge(self, key=None, reverse=False): element in this poset. - ``reverse`` -- (default: ``False``) specifies which - direction to go first. When ``key=None``, then this also + direction to go first: + ``False`` searches towards ``'oo'`` and + ``True`` searches towards ``'null'``. + When ``key=None``, then this also specifies which elements are merged first. OUTPUT: From 77b93ed753912f259313ee033168222e7460e183 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 10:00:42 +0200 Subject: [PATCH 1053/1872] Trac #17693, comment 36, 58: add doctest for non-reflexive can_merge --- src/sage/data_structures/mutable_poset.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index cf1d66e4689..caf8d756e11 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2865,6 +2865,16 @@ def merge(self, key=None, reverse=False): sage: R = P.mapped(lambda x: x+1) sage: R.merge(reverse=True); R poset(4) + + :: + + sage: P = MP(srange(4), + ....: merge=lambda l, r: r, can_merge=lambda l, r: l < r) + sage: P.merge() + Traceback (most recent call last): + ... + RuntimeError: Stopping merge before started; + the can_merge-function is not reflexive. """ if key is None: for shell in tuple(self.shells_topological(reverse=reverse)): From 55803ca3f24bb33ae00fab0119f7286e156b44f3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 10:04:23 +0200 Subject: [PATCH 1054/1872] Trac #17693, comment 36, 59: add note on can_merge --- src/sage/data_structures/mutable_poset.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index caf8d756e11..f28f3aaa6d3 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2794,6 +2794,12 @@ def merge(self, key=None, reverse=False): ``merge``-function and the corresponding successor/predecessor is removed from the poset. + .. NOTE:: + + ``can_merge` is applied in the sense of the condition of + depth first iteration, i.e., once ``can_merge`` fails, + the successors/predecessors are no longer tested. + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From ac76b87ec4e4b190b327a865b62b5c7b52c34b97 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 10:11:02 +0200 Subject: [PATCH 1055/1872] Trac #17693, comment 36, 61: change example in map --- src/sage/data_structures/mutable_poset.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index f28f3aaa6d3..783f81d2ebf 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2991,10 +2991,11 @@ def map(self, function, topological=False, reverse=False): ....: def __le__(left, right): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP([T((1, 3)), T((2, 1)), - ....: T((4, 4)), T((1, 2)), T((2, 2))]) - sage: P.map(lambda e: str(e)) + ....: T((4, 4)), T((1, 2)), T((2, 2))], + ....: key=lambda e: e[:2]) + sage: P.map(lambda e: e + (sum(e),)) sage: P - poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') + poset((1, 2, 3), (1, 3, 4), (2, 1, 3), (2, 2, 4), (4, 4, 8)) """ shells = self.shells_topological(reverse=reverse) \ if topological else self.shells() From 0353cb659e21c64078828944dcd5bdd4acbeb726 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 10:16:51 +0200 Subject: [PATCH 1056/1872] Trac #17693, comment 36, 62: add note on key-order preservation in mapped --- src/sage/data_structures/mutable_poset.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 783f81d2ebf..038f1cb1c16 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -3022,6 +3022,12 @@ def mapped(self, function): A :class:`MutablePoset`. + .. NOTE:: + + ``function`` is not allowed to change the order of the keys, + but changing the keys themselves is allowed (in contrast + to :meth:`map`). + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 328e8ac6261c223e5013bbd875ce2a42b2308df9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 10:24:36 +0200 Subject: [PATCH 1057/1872] Trac #17693, comment 36, 2: remove empty "Introduction" --- src/sage/data_structures/mutable_poset.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 038f1cb1c16..bceb80e3548 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -10,12 +10,6 @@ :mod:`Posets ` in the reference manual. -.. _mutable_poset_intro: - -Introduction -============ - - .. _mutable_poset_examples: Examples From f90f5158b4ea9357da42e3d0e96448650178bc6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Mon, 28 Sep 2015 12:01:07 +0300 Subject: [PATCH 1058/1872] Typo. Added 'a'. --- 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 324f91dda61..225f182b27b 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -15943,7 +15943,7 @@ def breadth_first_search(self, start, ignore_direction=False, """ from sage.rings.semirings.non_negative_integer_semiring import NN if (distance is not None and distance not in NN): - raise ValueError("distance must be non-negative integer, not {0}".format(distance)) + raise ValueError("distance must be a non-negative integer, not {0}".format(distance)) # Preferably use the Cython implementation if neighbors is None and not isinstance(start, list) and distance is None and hasattr(self._backend,"breadth_first_search") and not report_distance: From 59430d8ff60a44ec5442ae4144d9754b0c98b19c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 28 Sep 2015 11:04:09 +0200 Subject: [PATCH 1059/1872] Trac #18587: remove redundant doctest --- src/sage/rings/asymptotic/growth_group.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 68f193c8f7a..7876beb2dd4 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -221,8 +221,6 @@ class Variable(sage.structure.unique_representation.CachedRepresentation, ('x', ('x',)) sage: v = Variable('x '); repr(v), v.variable_names() ('x', ('x',)) - sage: v = Variable('x '); repr(v), v.variable_names() - ('x', ('x',)) sage: v = Variable(''); repr(v), v.variable_names() ('', ()) From f11377d6c4d8c64c75932ebdde7d7a7fa5ae58a9 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 28 Sep 2015 11:05:27 +0200 Subject: [PATCH 1060/1872] Trac #18587: minor language issues --- src/sage/rings/asymptotic/growth_group.py | 6 +++--- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 7876beb2dd4..093e45cc416 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -300,7 +300,7 @@ def __hash__(self): def __eq__(self, other): r""" - Compares if this variable equals ``other``. + Compare whether this variable equals ``other``. INPUT: @@ -355,7 +355,7 @@ def variable_names(self): def is_monomial(self): r""" - Returns if this is a monomial variable. + Return whether this is a monomial variable. OUTPUT: @@ -375,7 +375,7 @@ def is_monomial(self): @staticmethod def extract_variable_names(s): r""" - Finds the name of the variable for the given string. + Determine the name of the variable for the given string. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 97268d92699..17c0c8beb79 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -45,7 +45,7 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): r""" - Creates various types of cartesian products depending on its input. + Create various types of cartesian products depending on its input. INPUT: From 9da9c95bd16f03149bcc64b24ebea37036bab6a7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 11:05:22 +0200 Subject: [PATCH 1061/1872] Trac #17693, comment 36, 1: add a lot of SEEALSO-blocks --- src/sage/data_structures/mutable_poset.py | 372 ++++++++++++++++++++++ 1 file changed, 372 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index bceb80e3548..8372b989d0c 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -189,6 +189,10 @@ class MutablePosetShell(SageObject): sage: s = P.shell(66) sage: type(s) + + .. SEEALSO:: + + :class:`MutablePoset` """ def __init__(self, poset, element): r""" @@ -214,6 +218,10 @@ def poset(self): r""" The poset to which this shell belongs. + .. SEEALSO:: + + :class:`MutablePoset` + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -231,6 +239,11 @@ def element(self): r""" The element contained in this shell. + .. SEEALSO:: + + :meth:`key`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -252,6 +265,11 @@ def key(self): parent) via the ``key``-function (see construction of a :class:`MutablePoset`). + .. SEEALSO:: + + :meth:`element`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -297,6 +315,11 @@ def predecessors(self, reverse=False): A set. + .. SEEALSO:: + + :meth:`successors`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -324,6 +347,11 @@ def successors(self, reverse=False): A set. + .. SEEALSO:: + + :meth:`predecessors`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -353,6 +381,12 @@ def is_special(self): ``True`` or ``False``. + .. SEEALSO:: + + :meth:`is_null`, + :meth:`is_oo`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -374,6 +408,13 @@ def is_null(self): ``True`` or ``False``. + .. SEEALSO:: + + :meth:`is_special`, + :meth:`is_oo`, + :meth:`MutablePoset.null`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -395,6 +436,13 @@ def is_oo(self): ``True`` or ``False``. + .. SEEALSO:: + + :meth:`is_null`, + :meth:`is_special`, + :meth:`MutablePoset.oo`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -494,6 +542,11 @@ def le(self, other, reverse=False): of the keys of the elements contained in the shells, except for special shells (see :class:`MutablePosetShell`). + .. SEEALSO:: + + :meth:`eq`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -585,6 +638,11 @@ def eq(self, other): in the (non-special) shells. In particlar, elements/shells with the same key are considered as equal. + .. SEEALSO:: + + :meth:`le`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -640,6 +698,11 @@ def _copy_all_linked_(self, memo, poset, mapping): A new shell. + .. SEEALSO:: + + :meth:`MutablePoset.copy`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -691,6 +754,11 @@ def _search_covers_(self, covers, shell, reverse=False): Note that ``False`` is returned if we do not have ``self <= shell``. + .. SEEALSO:: + + :meth:`covers`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -757,6 +825,10 @@ def covers(self, shell, reverse=False): sage: sorted(P.oo.covers(e, reverse=True), ....: key=lambda c: repr(c.element)) [(4, 4)] + + .. SEEALSO:: + + :class:`MutablePoset` """ covers = set() self._search_covers_(covers, shell, reverse) @@ -793,6 +865,12 @@ def _iter_depth_first_visit_(self, marked, An iterator. + .. SEEALSO:: + + :meth:`iter_depth_first`, + :meth:`iter_topological`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -862,6 +940,11 @@ def iter_depth_first(self, reverse=False, key=None, condition=None): sage: list(P.null.iter_depth_first( ....: condition=lambda s: s.element[0] == 1)) [null, (1, 1), (1, 2), (1, 3)] + + .. SEEALSO:: + + :meth:`iter_topological`, + :class:`MutablePoset`. """ marked = set() return self._iter_depth_first_visit_(marked, reverse, key, condition) @@ -897,6 +980,12 @@ def _iter_topological_visit_(self, marked, An iterator. + .. SEEALSO:: + + :meth:`iter_depth_first`, + :meth:`iter_topological`, + :class:`MutablePoset`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1022,6 +1111,14 @@ def iter_topological(self, reverse=False, key=None, condition=None): sage: list(P.null.iter_topological( ....: reverse=True, condition=lambda s: s.element[0] == 1)) [(1, 3), (1, 2), (1, 1), null] + + .. SEEALSO:: + + :meth:`iter_depth_first`, + :meth:`MutablePoset.shells_topological`, + :meth:`MutablePoset.elements_topological`, + :meth:`MutablePoset.keys_topological`, + :class:`MutablePoset`. """ marked = set() return self._iter_topological_visit_(marked, reverse, key, condition) @@ -1070,6 +1167,11 @@ def merge(self, element, check=True, delete=True): sage: P.shell(2).merge((3, 'b')) sage: P poset((1, 'a'), (2, 'bc'), (4, 'd')) + + .. SEEALSO:: + + :meth:`MutablePoset.merge`, + :class:`MutablePoset`. """ poset = self.poset if poset._merge_ is None: @@ -1094,6 +1196,10 @@ def is_MutablePoset(P): r""" Test whether ``P`` inherits from :class:`MutablePoset`. + .. SEEALSO:: + + :class:`MutablePoset` + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1179,6 +1285,10 @@ class MutablePoset(SageObject): sage: C = MP([5, 3, 11]); C poset(3, 5, 11) + + .. SEEALSO:: + + :class:`MutablePosetShell`. """ def __init__(self, data=None, key=None, merge=None, can_merge=None): r""" @@ -1247,6 +1357,12 @@ def clear(self): Nothing. + .. SEEALSO:: + + :meth:`discard`, + :meth:`pop`, + :meth:`remove`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1317,6 +1433,12 @@ def null(self): null sage: z.is_null() True + + .. SEEALSO:: + + :meth:`oo`, + :meth:`MutablePosetShell.is_null`, + :meth:`MutablePosetShell.is_special`. """ return self._null_ @@ -1335,6 +1457,12 @@ def oo(self): oo sage: oo.is_oo() True + + .. SEEALSO:: + + :meth:`null`, + :meth:`MutablePosetShell.is_oo`, + :meth:`MutablePosetShell.is_special`. """ return self._oo_ @@ -1365,6 +1493,11 @@ def shell(self, key): 42 sage: type(e) + + .. SEEALSO:: + + :meth:`element`, + :meth:`get_key`. """ return self._shells_[key] @@ -1390,6 +1523,11 @@ def element(self, key): 42 sage: type(e) + + .. SEEALSO:: + + :meth:`shell`, + :meth:`get_key`. """ return self.shell(key).element @@ -1406,6 +1544,11 @@ def get_key(self, element): An object (the key of ``element``). + .. SEEALSO:: + + :meth:`element`, + :meth:`shell`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1438,6 +1581,10 @@ def _copy_shells_(self, other, mapping): Nothing. + .. SEEALSO:: + + :meth:`copy` + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1476,6 +1623,11 @@ def copy(self, mapping=None): A poset with the same content as ``self``. + .. SEEALSO:: + + :meth:`map`, + :meth:`mapped`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1525,6 +1677,16 @@ def shells(self, include_special=False): () sage: tuple(P.shells(include_special=True)) (null, oo) + + .. SEEALSO:: + + :meth:`shells_topological`, + :meth:`elements`, + :meth:`elements_topological`, + :meth:`keys`, + :meth:`keys_topological`, + :meth:`MutablePosetShell.iter_depth_first`, + :meth:`MutablePosetShell.iter_topological`. """ if include_special: yield self.null @@ -1580,6 +1742,16 @@ def shells_topological(self, include_special=False, sage: list(P.shells_topological( ....: include_special=True, reverse=True)) [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), null] + + .. SEEALSO:: + + :meth:`shells`, + :meth:`elements`, + :meth:`elements_topological`, + :meth:`keys`, + :meth:`keys_topological`, + :meth:`MutablePosetShell.iter_depth_first`, + :meth:`MutablePosetShell.iter_topological`. """ if key is None: key = repr @@ -1618,6 +1790,16 @@ def elements(self, **kwargs): [3, 7, 42] returns all elements as well. + + .. SEEALSO:: + + :meth:`shells`, + :meth:`shells_topological`, + :meth:`elements_topological`, + :meth:`keys`, + :meth:`keys_topological`, + :meth:`MutablePosetShell.iter_depth_first`, + :meth:`MutablePosetShell.iter_topological`. """ for shell in self.shells(**kwargs): yield shell.element @@ -1653,6 +1835,16 @@ def elements_topological(self, **kwargs): ((2, 1), ), ((2, 2), ), ((4, 4), )] + + .. SEEALSO:: + + :meth:`shells`, + :meth:`shells_topological`, + :meth:`elements`, + :meth:`keys`, + :meth:`keys_topological`, + :meth:`MutablePosetShell.iter_depth_first`, + :meth:`MutablePosetShell.iter_topological`. """ for shell in self.shells_topological(**kwargs): yield shell.element @@ -1689,6 +1881,16 @@ def keys(self, **kwargs): [(3, ), (7, ), (42, )] + + .. SEEALSO:: + + :meth:`shells`, + :meth:`shells_topological`, + :meth:`elements`, + :meth:`elements_topological`, + :meth:`keys_topological`, + :meth:`MutablePosetShell.iter_depth_first`, + :meth:`MutablePosetShell.iter_topological`. """ for shell in self.shells(**kwargs): yield shell.key @@ -1724,6 +1926,16 @@ def keys_topological(self, **kwargs): [((1, 1), ), ((2, 1), ), ((4, 4), )] + + .. SEEALSO:: + + :meth:`shells`, + :meth:`shells_topological`, + :meth:`elements`, + :meth:`elements_topological`, + :meth:`keys`, + :meth:`MutablePosetShell.iter_depth_first`, + :meth:`MutablePosetShell.iter_topological`. """ for shell in self.shells_topological(**kwargs): yield shell.key @@ -1746,6 +1958,10 @@ def repr(self, include_special=False, reverse=False): A string. + .. SEEALSO:: + + :meth:`repr_full` + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1772,6 +1988,10 @@ def repr_full(self, reverse=False): A string. + .. SEEALSO:: + + :meth:`repr` + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1816,6 +2036,12 @@ def contains(self, key): ``True`` or ``False``. + .. SEEALSO:: + + :meth:`shells`, + :meth:`elements`, + :meth:`keys`. + TESTS:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -1944,6 +2170,12 @@ def add(self, element): sage: B poset() + .. SEEALSO:: + + :meth:`discard`, + :meth:`pop`, + :meth:`remove`. + TESTS:: sage: R = MP([(1, 1, 42), (1, 3, 42), (2, 1, 7), @@ -2090,6 +2322,8 @@ def remove(self, key, raise_key_error=True): .. SEEALSO:: + :meth:`add`, + :meth:`clear`, :meth:`discard`, :meth:`pop`. @@ -2225,6 +2459,8 @@ def discard(self, key, raise_key_error=False): .. SEEALSO:: + :meth:`add`, + :meth:`clear`, :meth:`remove`, :meth:`pop`. """ @@ -2262,6 +2498,13 @@ def pop(self, **kwargs): Traceback (most recent call last): ... KeyError: 'pop from an empty poset' + + .. SEEALSO:: + + :meth:`add`, + :meth:`clear`, + :meth:`discard`, + :meth:`remove`. """ kwargs['include_special'] = False @@ -2312,6 +2555,16 @@ def union(self, *other): sage: P.union(Q) poset(3, 4, 7, 8, 42) + .. SEEALSO:: + + :meth:`union_update`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`, + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`is_superset`. + TESTS:: sage: P.union(P, Q, Q, P) @@ -2362,6 +2615,16 @@ def union_update(self, *other): sage: P poset(3, 4, 7, 8, 42) + .. SEEALSO:: + + :meth:`union`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`, + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`is_superset`. + TESTS:: sage: Q.update(P) @@ -2417,6 +2680,16 @@ def difference(self, *other): sage: P.difference(Q) poset(3, 7) + .. SEEALSO:: + + :meth:`union`, :meth:`union_update`, + :meth:`difference_update`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`, + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`is_superset`. + TESTS:: sage: P.difference(Q, Q) @@ -2464,6 +2737,16 @@ def difference_update(self, *other): sage: P.difference_update(Q) sage: P poset(3, 7) + + .. SEEALSO:: + + :meth:`union`, :meth:`union_update`, + :meth:`difference`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`, + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`is_superset`. """ for o in other: try: @@ -2507,6 +2790,16 @@ def intersection(self, *other): sage: P.intersection(Q) poset(42) + .. SEEALSO:: + + :meth:`union`, :meth:`union_update`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection_update`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`, + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`is_superset`. + TESTS:: sage: P.intersection(P, Q, Q, P) @@ -2550,6 +2843,16 @@ def intersection_update(self, *other): sage: P.intersection_update(Q) sage: P poset(42) + + .. SEEALSO:: + + :meth:`union`, :meth:`union_update`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`, + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`is_superset`. """ keys = tuple(self.keys()) for key in keys: @@ -2584,6 +2887,16 @@ def symmetric_difference(self, other): poset(4, 8, 42) sage: P.symmetric_difference(Q) poset(3, 4, 7, 8) + + .. SEEALSO:: + + :meth:`union`, :meth:`union_update`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference_update`, + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`is_superset`. """ new = self.copy() new.symmetric_difference_update(other) @@ -2619,6 +2932,16 @@ def symmetric_difference_update(self, other): sage: P.symmetric_difference_update(Q) sage: P poset(3, 4, 7, 8) + + .. SEEALSO:: + + :meth:`union`, :meth:`union_update`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference`, + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`is_superset`. """ T = other.difference(self) self.difference_update(other) @@ -2655,6 +2978,15 @@ def is_disjoint(self, other): False sage: P.is_disjoint(Q.difference(P)) True + + .. SEEALSO:: + + :meth:`is_subset`, + :meth:`is_superset`, + :meth:`union`, :meth:`union_update`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`. """ return all(key not in other for key in self.keys()) @@ -2700,6 +3032,15 @@ def is_subset(self, other): True sage: P.is_subset(P.union(Q)) True + + .. SEEALSO:: + + :meth:`is_disjoint`, + :meth:`is_superset`, + :meth:`union`, :meth:`union_update`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`. """ return all(key in other for key in self.keys()) @@ -2745,6 +3086,15 @@ def is_superset(self, other): True sage: P.union(Q).is_superset(P) True + + .. SEEALSO:: + + :meth:`is_disjoint`, + :meth:`is_subset`, + :meth:`union`, :meth:`union_update`, + :meth:`difference`, :meth:`difference_update`, + :meth:`intersection`, :meth:`intersection_update`, + :meth:`symmetric_difference`, :meth:`symmetric_difference_update`. """ try: it = other.keys() @@ -2849,6 +3199,10 @@ def merge(self, key=None, reverse=False): sage: Q.merge(); Q poset((4, 4, 'abcdef')) + .. SEEALSO:: + + :meth:`MutablePosetShell.merge` + TESTS:: sage: copy(P).merge(reverse=False) == copy(P).merge(reverse=True) @@ -2921,6 +3275,10 @@ def maximal_elements(self): ....: T((1, 2)), T((2, 2))]) sage: list(P.maximal_elements()) [(1, 3), (2, 2)] + + .. SEEALSO:: + + :meth:`minimal_elements` """ return iter(shell.element for shell in self.oo.predecessors() @@ -2949,6 +3307,10 @@ def minimal_elements(self): ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: list(P.minimal_elements()) [(1, 2), (2, 1)] + + .. SEEALSO:: + + :meth:`maximal_elements` """ return iter(shell.element for shell in self.null.successors() @@ -2990,6 +3352,11 @@ def map(self, function, topological=False, reverse=False): sage: P.map(lambda e: e + (sum(e),)) sage: P poset((1, 2, 3), (1, 3, 4), (2, 1, 3), (2, 2, 4), (4, 4, 8)) + + .. SEEALSO:: + + :meth:`copy`, + :meth:`mapped`. """ shells = self.shells_topological(reverse=reverse) \ if topological else self.shells() @@ -3032,6 +3399,11 @@ def mapped(self, function): ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: P.mapped(lambda e: str(e)) poset('(1, 2)', '(1, 3)', '(2, 1)', '(2, 2)', '(4, 4)') + + .. SEEALSO:: + + :meth:`copy`, + :meth:`map`. """ return self.copy(mapping=function) From 10aedb7e47ce3466bd80ca6ed7724df263e706ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 28 Sep 2015 11:31:03 +0200 Subject: [PATCH 1062/1872] trac #18937, bot version 2.5.2, respecting $MAKE if it exists --- build/pkgs/patchbot/checksums.ini | 6 +++--- build/pkgs/patchbot/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/patchbot/checksums.ini b/build/pkgs/patchbot/checksums.ini index f67bd8165cd..4a35077fa89 100644 --- a/build/pkgs/patchbot/checksums.ini +++ b/build/pkgs/patchbot/checksums.ini @@ -1,4 +1,4 @@ tarball=patchbot-VERSION.tar.bz2 -sha1=cbf2002db03d3bf45be16202005b9c75afa99ed2 -md5=862de73795502ae064c172e7c196c1fc -cksum=973755707 +sha1=1850ce7004fe49b669be0b53102d32e9095cc307 +md5=a84f244c2f6e6c715676a09028750b36 +cksum=1356602931 diff --git a/build/pkgs/patchbot/package-version.txt b/build/pkgs/patchbot/package-version.txt index 73462a5a134..f225a78adf0 100644 --- a/build/pkgs/patchbot/package-version.txt +++ b/build/pkgs/patchbot/package-version.txt @@ -1 +1 @@ -2.5.1 +2.5.2 From f904968af9b3dd51313876e95820f9dd9bb2f6ce Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 12:26:13 +0200 Subject: [PATCH 1063/1872] Trac #17693, comment 36, 24-26: rewrite docstring of covers --- src/sage/data_structures/mutable_poset.py | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 8372b989d0c..f2b26f35d84 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -785,29 +785,36 @@ def _search_covers_(self, covers, shell, reverse=False): def covers(self, shell, reverse=False): r""" - Return the covers of the given shell (considering only - shells which originate from this shell). + Return the lower or upper covers of the specified ``shell``; + the search is started at this (``self``) shell. + + A lower cover of `x` is an element `y` of the poset + such that `y < x` and there is no element `z` of the poset + so that `x < z < y`. Likewise, + an upper cover of `x` is an element `y` such that `x < y` and + there is no element `z` so that `x < z < y`. INPUT: - ``shell`` -- the shell for which to find the covering shells. + There is no restrition of ``shell`` being contained in the poset. - ``reverse`` -- (default: ``False``) if not set, then find the lower covers, otherwise find the upper covers. OUTPUT: - A set of the covers. + A set of :class:`shells `. + + .. NOTE:: - Suppose ``reverse`` is ``False``. This method returns all the - lower covers of the given ``shell``, i.e., shells in the - poset, which are at most the given shell and maximal with - this property. Only shells which are (not necessarily - direct) successors of the calling shell are considered. + Suppose ``reverse`` is ``False``. This method starts at + the calling shell (``self``) and searches towards ``'oo'``. + Thus, only shells which are (not necessarily + direct) successors of this shell are considered. - If ``reverse`` is ``True``, then the reverse direction is - taken, i.e., in the text above replace lower covers by upper - covers, maximal by minimal, and successors by predecessors. + If ``reverse`` is ``True``, then the reverse direction is + taken. EXAMPLES:: From c546102768f5ace3dd178d55ac4ca25140356a61 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 12:44:34 +0200 Subject: [PATCH 1064/1872] minor simplification of covers code --- src/sage/data_structures/mutable_poset.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index ce35de4a0c5..fb7e0263f9b 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -791,10 +791,7 @@ def covers(self, shell, reverse=False): covers = set().union(*(e.covers(shell, reverse) for e in self.successors(reverse) if e.le(shell, reverse))) - if covers: - return covers - else: - return set([self]) + return covers or set([self]) def _iter_depth_first_visit_(self, marked, From 34e34dca5609d9b5ff4bb90247fa412d014dbd49 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 12:45:41 +0200 Subject: [PATCH 1065/1872] Trac #17693, comment 36, 19--23: improve docstring of covers (former _search_covers_) --- src/sage/data_structures/mutable_poset.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index fb7e0263f9b..95222430d73 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -747,6 +747,8 @@ def covers(self, shell, reverse=False): - ``shell`` -- the shell for which to find the covering shells. There is no restrition of ``shell`` being contained in the poset. + If ``shell`` is contained in the poset, then use the more efficient + methods :meth:`predecessors` and :meth:`successors`. - ``reverse`` -- (default: ``False``) if not set, then find the lower covers, otherwise find the upper covers. @@ -778,13 +780,30 @@ def covers(self, shell, reverse=False): sage: sorted(P.null.covers(e), ....: key=lambda c: repr(c.element)) [(1, 2), (2, 1)] + sage: set(_) == e.predecessors() + True sage: sorted(P.oo.covers(e, reverse=True), ....: key=lambda c: repr(c.element)) [(4, 4)] + sage: set(_) == e.successors() + True + + :: + + sage: Q = MP([T((3, 2))]) + sage: f = next(Q.shells()) + sage: sorted(P.null.covers(f), + ....: key=lambda c: repr(c.element)) + [(2, 2)] + sage: sorted(P.oo.covers(f, reverse=True), + ....: key=lambda c: repr(c.element)) + [(4, 4)] .. SEEALSO:: - :class:`MutablePoset` + :meth:`predecessors`, + :meth:`successors`, + :class:`MutablePoset`. """ if self == shell: return set() From 490c2236b3ba38a125986c0cd5c4669f92911917 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 12:51:17 +0200 Subject: [PATCH 1066/1872] Trac #17693, comment 36, 28--31: document role of self --- src/sage/data_structures/mutable_poset.py | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 95222430d73..2e01c395343 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -843,6 +843,12 @@ def _iter_depth_first_visit_(self, marked, An iterator. + .. NOTE:: + + The depth first search starts at this (``self``) shell. Thus + only this shell and shells greater than (in case of + ``reverse=False``) this shell are visited. + .. SEEALSO:: :meth:`iter_depth_first`, @@ -899,6 +905,12 @@ def iter_depth_first(self, reverse=False, key=None, condition=None): An iterator. + .. NOTE:: + + The depth first search starts at this (``self``) shell. Thus + only this shell and shells greater than (in case of + ``reverse=False``) this shell are visited. + ALGORITHM: See :wikipedia:`Depth-first_search`. @@ -958,6 +970,13 @@ def _iter_topological_visit_(self, marked, An iterator. + .. NOTE:: + + The topological search will only find shells smaller than + (in case of ``reverse=False``) + or equal to this (``self``) shell. This is in contrast to + :meth:`iter_depth_first`. + .. SEEALSO:: :meth:`iter_depth_first`, @@ -1014,6 +1033,13 @@ def iter_topological(self, reverse=False, key=None, condition=None): An iterator. + .. NOTE:: + + The topological search will only find shells smaller than + (in case of ``reverse=False``) + or equal to this (``self``) shell. This is in contrast to + :meth:`iter_depth_first`. + ALGORITHM: Here a simplified version of the algorithm found in [T1976]_ From 3de0a1d250a07c902295ff6199b9995e3fd19849 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 13:10:31 +0200 Subject: [PATCH 1067/1872] Trac #17693, comment 36, 33: explicitly mention merge and can_merge at top of docstring --- src/sage/data_structures/mutable_poset.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 2e01c395343..b61ce1cd53d 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1133,6 +1133,7 @@ def merge(self, element, check=True, delete=True): Merge the given element with the element contained in this shell. + INPUT: - ``element`` -- an element (of the poset). @@ -1150,9 +1151,12 @@ def merge(self, element, check=True, delete=True): .. NOTE:: - This method uses the parameters ``merge`` and - ``can_merge`` of the :class:`MutablePoset` which contains - this shell. + This operation depends on the parameters ``merge`` and + ``can_merge`` of the :class:`MutablePoset` this shell is + contained in. These parameters are defined when the poset + is constructed. + + .. NOTE:: If the ``merge`` function returns ``None``, then this shell is removed from the poset. From 894e3a83ceb1b2f0cb4f508f57ca5bce8c84c62a Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 28 Sep 2015 13:41:45 +0200 Subject: [PATCH 1068/1872] Trac #18587: Fix ReSt errors --- src/sage/rings/asymptotic/growth_group_cartesian.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 17c0c8beb79..212b8c8bbe3 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -193,7 +193,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): sage: C.an_element() x^(1/2) * log(x) * y^(1/2) - .. SEEALSO: + .. SEEALSO:: :class:`~sage.sets.cartesian_product.CartesianProduct`, :class:`~sage.sets.cartesian_product.CartesianProductPosets`. @@ -362,7 +362,7 @@ def _convert_to_factor_(self, data): def _coerce_map_from_(self, S): r""" - Return ``True if there is a coercion from ``S`` + Return ``True`` if there is a coercion from ``S``. EXAMPLES:: @@ -385,7 +385,7 @@ def gens_monomial(self): A tuple containing elements of this growth group. - .. NOTE: + .. NOTE:: This method calls the ``gens_monomial()`` method on the individual factors of this cartesian product and From 61085d0aa73893bb9439f10c53466fc3fe872658 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 28 Sep 2015 13:42:01 +0200 Subject: [PATCH 1069/1872] Trac #18587: add heading "Classes and Methods" --- src/sage/rings/asymptotic/growth_group.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 093e45cc416..bb9d12c5287 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -95,6 +95,9 @@ False (Note that it is mathematically nonsense to make ``log(x)`` larger than ``x``.) + +Classes and Methods +=================== """ #***************************************************************************** From 6fefead5a7fd8cfe4e84d73641b4459c4671ceb4 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 28 Sep 2015 13:42:29 +0200 Subject: [PATCH 1070/1872] Trac #18587: Fix minor errors --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index bb9d12c5287..553d4db3d2b 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -205,7 +205,7 @@ class Variable(sage.structure.unique_representation.CachedRepresentation, - ``var`` -- an object whose representation string is used as the variable. It has to be a valid Python identifier. ``var`` can - also be a tuple (or other iterable of such objects). + also be a tuple (or other iterable) of such objects. - ``repr`` -- (default: ``None``) if specified, then this string will be displayed instead of ``var``. Use this to get @@ -290,7 +290,7 @@ def __init__(self, var, repr=None): def __hash__(self): r""" - Return the hash if this variable. + Return the hash of this variable. TESTS:: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 212b8c8bbe3..adf241ba28e 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -375,7 +375,7 @@ def _coerce_map_from_(self, S): def gens_monomial(self): r""" - Return a tuple containing generators of this growth group. + Return a tuple containing monomial generators of this growth group. INPUT: From 485b46f4f2203885ee22469c3b237e67a605bc21 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 13:38:22 +0200 Subject: [PATCH 1071/1872] Trac #17693, comment 36, 34: raise exceptions when merge is not possible --- src/sage/data_structures/mutable_poset.py | 26 +++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index b61ce1cd53d..233a5638f0b 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1133,14 +1133,14 @@ def merge(self, element, check=True, delete=True): Merge the given element with the element contained in this shell. - INPUT: - ``element`` -- an element (of the poset). - ``check`` -- (default: ``True``) if set, then the ``can_merge``-function of :class:`MutablePoset` determines - whether the merge is possible. + whether the merge is possible. ``can_merge`` is ``None`` means + that this check is always passed. - ``delete`` -- (default: ``True``) if set, then ``element`` is removed from the poset after the merge. @@ -1180,14 +1180,25 @@ def merge(self, element, check=True, delete=True): :meth:`MutablePoset.merge`, :class:`MutablePoset`. + + TESTS:: + + sage: MP([2], merge=operator.add, + ....: can_merge=lambda _, __: False).shell(2).merge(1) + Traceback (most recent call last): + ... + RuntimeError: Cannot merge 2 with 1. """ poset = self.poset if poset._merge_ is None: + # poset._merge_ is None means no merge (poset._merge_ simply + # returns its first input argument). return self_element = self.element - if check and poset._can_merge_ is not None and \ - not poset._can_merge_(self_element, element): - return + if check: + if not poset._can_merge_(self_element, element): + raise RuntimeError('Cannot merge %s with %s.' % + (self_element, element)) new = poset._merge_(self_element, element) if new is None: poset.discard(poset.get_key(self.element)) @@ -1341,7 +1352,10 @@ def __init__(self, data=None, key=None, merge=None, can_merge=None): self._key_ = key self._merge_ = merge - self._can_merge_ = can_merge + if can_merge is None: + self._can_merge_ = lambda _, __: True + else: + self._can_merge_ = can_merge if data is not None: try: From d5d6bec7548d7c2ab961a31d70e96211cb572d2e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 13:38:54 +0200 Subject: [PATCH 1072/1872] check=False in MutablePoset.merge since checked already before --- src/sage/data_structures/mutable_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 233a5638f0b..dcf3deaf784 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -3272,7 +3272,7 @@ def can_merge(other): for m in tuple(to_merge): if m.is_special(): continue - shell.merge(m.element, delete=True) + shell.merge(m.element, check=False, delete=True) def maximal_elements(self): From 6da3db12035b5b4904dd7ba25082140c17023fa6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 13:52:28 +0200 Subject: [PATCH 1073/1872] Trac #17693, comment 36, 37: extend doc to mention more explicitly that merge is not allowed to change keys --- src/sage/data_structures/mutable_poset.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index dcf3deaf784..67f4600d1f9 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1262,7 +1262,8 @@ class MutablePoset(SageObject): ``merge`` is ``None`` (default) is equivalent to ``merge`` returning its first argument. Note that it is not allowed that the key of the returning element differs from the key of the first - input parameter. + input parameter. This means ``merge`` must not change the + position of the element in the poset. - ``can_merge`` -- a function which checks whether its second argument can be merged to its first. From f1e9f9e8224c4e78944c57f3ca9c4b73a2f96d83 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 13:57:55 +0200 Subject: [PATCH 1074/1872] Trac #17693, comment 36, 38: clarify parameter key --- src/sage/data_structures/mutable_poset.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 67f4600d1f9..b99414785f6 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1250,6 +1250,12 @@ class MutablePoset(SageObject): (default), this is the identity, i.e., keys are equal to their elements. + Two elements with the same keys are considered as equal; so only + one of these two elements can be in the poset. + + This ``key`` is not used for sorting (in contrast to + sorting-functions, e.g. ``sorted``). + - ``merge`` -- a function which merges its second argument (an element) to its first (again an element) and returns the result (as an element). If the return value is ``None``, the element is From ae0cad989dd4e5dddc9bf2218280fab131db2c85 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 28 Sep 2015 14:03:14 +0200 Subject: [PATCH 1075/1872] Trac #17693, comment 36, 60: mention motivation asymptoic expansions in merge method --- src/sage/data_structures/mutable_poset.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index b99414785f6..117d8138fc0 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -3173,6 +3173,13 @@ def merge(self, key=None, reverse=False): depth first iteration, i.e., once ``can_merge`` fails, the successors/predecessors are no longer tested. + .. NOTE:: + + The motivation for such a merge behavior comes from + asymptotic expansions: `O(n^3)` is merges with, for + example, `3n^2` or `O(n)` to `O(n^3)` (as `n` tends to + `\infty`; see :wikipedia:`Big_O_notation`) + EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 617df137291c1fd10fcc7de21435867d316870ff Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 28 Sep 2015 10:22:17 -0300 Subject: [PATCH 1076/1872] Trac 19299: implement cartesian_factors --- src/sage/sets/cartesian_product.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index a208f257250..bf44ea3ba50 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -276,3 +276,18 @@ def __iter__(self): 1 """ return iter(self.value) + + def cartesian_factors(self): + r""" + Return the tuple of elements that compose this element. + + EXAMPLES:: + + sage: A = cartesian_product([ZZ, RR]) + sage: A((1, 1.23)).cartesian_factors() + sage: A((1, 1.23)).cartesian_factors() + (1, 1.23000000000000) + sage: type(_) + + """ + return self.value From 1b271285ac389d31d9603e227e40da6fe3f45d3e Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 28 Sep 2015 10:34:22 -0300 Subject: [PATCH 1077/1872] Trac 19299: improve speed of OperationTable --- src/sage/matrix/operation_table.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index eca698fd93d..4f1aff5de81 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -388,6 +388,12 @@ def __init__(self, S, operation, names='letters', elements=None): except Exception: raise TypeError('unable to coerce %s into %s' % (e, S)) self._elts = elems + try: + self._index_elts = {e: i for i,e in enumerate(self._elts)} + except TypeError: + # the elements might not be hashable. But if they are it is much + # faster to lookup in a hash table rather than in a list! + pass self._n = len(self._elts) self._name_dict = {} @@ -419,16 +425,24 @@ def __init__(self, S, operation, names='letters', elements=None): # If not, we'll discover that next in actual use. self._table = [] + if hasattr(self, '_index_elts'): + get_row = lambda x: self._index_elts[x] + else: + get_row = lambda x: self._elts.index(x) for g in self._elts: row = [] for h in self._elts: try: result = self._operation(g, h) - row.append(self._elts.index(result)) - except ValueError: # list/index condition - raise ValueError('%s%s%s=%s, and so the set is not closed' % (g, self._ascii_symbol, h, result)) except Exception: raise TypeError('elements %s and %s of %s are incompatible with operation: %s' % (g,h,S,self._operation)) + + try: + r = get_row(result) + except (KeyError,ValueError): + raise ValueError('%s%s%s=%s, and so the set is not closed' % (g, self._ascii_symbol, h, result)) + + row.append(r) self._table.append(row) def _name_maker(self, names): @@ -559,8 +573,8 @@ def __getitem__(self, pair): TESTS:: sage: from sage.matrix.operation_table import OperationTable - sage: G=DiCyclicGroup(3) - sage: T=OperationTable(G, operator.mul) + sage: G = DiCyclicGroup(3) + sage: T = OperationTable(G, operator.mul) sage: T[G('(1,2)(3,4)(5,6,7)')] Traceback (most recent call last): ... From a0b8757523c91c8d8c7cea296930743a3b263585 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 28 Sep 2015 16:17:36 +0200 Subject: [PATCH 1078/1872] trac #19299: Code rephrase --- src/sage/matrix/operation_table.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index 4f1aff5de81..e76a66c0ab8 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -388,12 +388,6 @@ def __init__(self, S, operation, names='letters', elements=None): except Exception: raise TypeError('unable to coerce %s into %s' % (e, S)) self._elts = elems - try: - self._index_elts = {e: i for i,e in enumerate(self._elts)} - except TypeError: - # the elements might not be hashable. But if they are it is much - # faster to lookup in a hash table rather than in a list! - pass self._n = len(self._elts) self._name_dict = {} @@ -425,10 +419,14 @@ def __init__(self, S, operation, names='letters', elements=None): # If not, we'll discover that next in actual use. self._table = [] - if hasattr(self, '_index_elts'): - get_row = lambda x: self._index_elts[x] - else: - get_row = lambda x: self._elts.index(x) + + # the elements might not be hashable. But if they are it is much + # faster to lookup in a hash table rather than in a list! + try: + get_row = {e: i for i,e in enumerate(self._elts)}.__getitem__ + except TypeError: + get_row = self._elts.index + for g in self._elts: row = [] for h in self._elts: From 6ca3e5fd32c7fc5398ece1876ce5981f27663a60 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 16:28:41 +0200 Subject: [PATCH 1079/1872] fixed doctests --- src/sage/categories/sets_cat.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 0a7a95737ef..db3c5332b69 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1452,17 +1452,11 @@ def cartesian_product(*parents, **kwargs): Category of sets sage: cartesian_product([ZZ, ZZ]).category() Join of - Category of rings and - Category of Cartesian products of distributive magmas and additive magmas and - Category of Cartesian products of monoids and - Category of Cartesian products of commutative additive groups and + Category of Cartesian products of commutative rings and Category of Cartesian products of enumerated sets sage: cartesian_product([ZZ, ZZ], extra_category=Posets()).category() Join of - Category of rings and - Category of Cartesian products of distributive magmas and additive magmas and - Category of Cartesian products of monoids and - Category of Cartesian products of commutative additive groups and + Category of Cartesian products of commutative rings and Category of posets and Category of Cartesian products of enumerated sets """ From b3b9821d5f8566848b0ba107c3ef0bd28e761f78 Mon Sep 17 00:00:00 2001 From: Stefan Kraemer Date: Mon, 28 Sep 2015 16:47:11 +0200 Subject: [PATCH 1080/1872] Bugfix hyperbolic_arc and hyperbolic_polygon --- src/sage/plot/hyperbolic_arc.py | 10 +++++++--- src/sage/plot/hyperbolic_polygon.py | 14 ++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/sage/plot/hyperbolic_arc.py b/src/sage/plot/hyperbolic_arc.py index 1e658fc84d5..e4e7c6bbfff 100644 --- a/src/sage/plot/hyperbolic_arc.py +++ b/src/sage/plot/hyperbolic_arc.py @@ -7,6 +7,7 @@ """ #***************************************************************************** # Copyright (C) 2011 Hartmut Monien , +# 2015 Stefan Kraemer # # Distributed under the terms of the GNU General Public License (GPL) # @@ -70,13 +71,16 @@ def _hyperbolic_arc(self, z0, z3, first=False): the hyperbolic arc between the complex numbers z0 and z3 in the hyperbolic plane. """ - if (z0-z3).real() == 0: + z0, z3 = (CC(z0), CC(z3)) + p = (abs(z0)*abs(z0)-abs(z3)*abs(z3))/(z0-z3).real()/2 + r = abs(z0-p) + + if abs(z3-z0)/r < 0.1: self.path.append([(z0.real(),z0.imag()), (z3.real(),z3.imag())]) return - z0, z3 = (CC(z0), CC(z3)) + if z0.imag() == 0 and z3.imag() == 0: p = (z0.real()+z3.real())/2 - r = abs(z0-p) zm = CC(p, r) self._hyperbolic_arc(z0, zm, first) self._hyperbolic_arc(zm, z3) diff --git a/src/sage/plot/hyperbolic_polygon.py b/src/sage/plot/hyperbolic_polygon.py index e6465183e04..3bfbdcb3404 100644 --- a/src/sage/plot/hyperbolic_polygon.py +++ b/src/sage/plot/hyperbolic_polygon.py @@ -8,7 +8,8 @@ """ #***************************************************************************** # Copyright (C) 2011 Hartmut Monien , -# 2014 Vincent Delecroix <20100.delecroix@gmail.com> +# 2014 Vincent Delecroix <20100.delecroix@gmail.com>, +# 2015 Stefan Kraemer # # Distributed under the terms of the GNU General Public License (GPL) # @@ -85,20 +86,21 @@ def _hyperbolic_arc(self, z0, z3, first=False): the hyperbolic arc between the complex numbers z0 and z3 in the hyperbolic plane. """ - if (z0-z3).real() == 0: + z0, z3 = (CC(z0), CC(z3)) + p = (abs(z0)*abs(z0)-abs(z3)*abs(z3))/(z0-z3).real()/2 + r = abs(z0-p) + + if abs(z3-z0)/r < 0.1: self.path.append([(z0.real(), z0.imag()), (z3.real(), z3.imag())]) return - z0, z3 = (CC(z0), CC(z3)) + if z0.imag() == 0 and z3.imag() == 0: p = (z0.real()+z3.real())/2 - r = abs(z0-p) zm = CC(p, r) self._hyperbolic_arc(z0, zm, first) self._hyperbolic_arc(zm, z3) return else: - p = (abs(z0)*abs(z0)-abs(z3)*abs(z3))/(z0-z3).real()/2 - r = abs(z0-p) zm = ((z0+z3)/2-p)/abs((z0+z3)/2-p)*r+p t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real() z1 = z0 + t*CC(z0.imag(), (p-z0.real())) From db042e0ecc3b30a1e41f39bca38e4ac59bb9e4fc Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 28 Sep 2015 18:00:49 +0200 Subject: [PATCH 1081/1872] Trac #17693: fix ReSt and hyperlink issues --- src/sage/data_structures/mutable_poset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 63a18d44611..be5e2607f35 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -690,7 +690,7 @@ def _copy_all_linked_(self, memo, poset, mapping): - ``poset`` -- the poset to which the newly created shells belongs. Note that the elements are not inserted into ``poset``; this is done in the calling method - :meth:`_copy_shells_`. + :meth:`MutablePoset._copy_shells_`. - ``mapping`` -- a function which is applied on each of the elements. @@ -2278,7 +2278,7 @@ def remove(self, key, raise_key_error=True): .. NOTE:: As with Python's ``set``, the methods :meth:`remove` - and meth:`discard` only differ in their behavior when an + and :meth:`discard` only differ in their behavior when an element is not contained in the poset: :meth:`remove` raises a ``KeyError`` whereas :meth:`discard` does not raise any exception. @@ -2459,7 +2459,7 @@ def discard(self, key, raise_key_error=False): .. NOTE:: As with Python's ``set``, the methods :meth:`remove` - and meth:`discard` only differ in their behavior when an + and :meth:`discard` only differ in their behavior when an element is not contained in the poset: :meth:`remove` raises a ``KeyError`` whereas :meth:`discard` does not raise any exception. @@ -3165,7 +3165,7 @@ def merge(self, key=None, reverse=False): .. NOTE:: - ``can_merge` is applied in the sense of the condition of + ``can_merge`` is applied in the sense of the condition of depth first iteration, i.e., once ``can_merge`` fails, the successors/predecessors are no longer tested. From bbe02ef463cdd3536bd907892c68e73792790525 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 28 Sep 2015 18:01:14 +0200 Subject: [PATCH 1082/1872] Trac #17693: minor language issues and typos --- src/sage/data_structures/mutable_poset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index be5e2607f35..363699c4cc1 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -176,7 +176,7 @@ class MutablePosetShell(SageObject): - a ``'null'`` (an element smaller than each other element; it has no predecessors) and - - a ``'oo'`` (an element larger than each other element; + - an ``'oo'`` (an element larger than each other element; it has no successors). EXAMPLES:: @@ -635,7 +635,7 @@ def eq(self, other): .. NOTE:: This method compares the keys of the elements contained - in the (non-special) shells. In particlar, + in the (non-special) shells. In particular, elements/shells with the same key are considered as equal. .. SEEALSO:: @@ -3172,9 +3172,9 @@ def merge(self, key=None, reverse=False): .. NOTE:: The motivation for such a merge behavior comes from - asymptotic expansions: `O(n^3)` is merges with, for + asymptotic expansions: `O(n^3)` merges with, for example, `3n^2` or `O(n)` to `O(n^3)` (as `n` tends to - `\infty`; see :wikipedia:`Big_O_notation`) + `\infty`; see :wikipedia:`Big_O_notation`). EXAMPLES:: From 4deddbd1a09e0e60273797cb89becdc651325b9c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 28 Sep 2015 18:02:23 +0200 Subject: [PATCH 1083/1872] Trac #17693: remove comment on non-commutativity for difference and update_difference --- src/sage/data_structures/mutable_poset.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 363699c4cc1..878459e6f3a 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2692,9 +2692,6 @@ def difference(self, *other): The key of an element is used for comparison. Thus elements with the same key are considered as equal. - Due to keys and a ``merge`` function (see :class:`MutablePoset`) - this operation might not be commutative. - EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2749,9 +2746,6 @@ def difference_update(self, *other): The key of an element is used for comparison. Thus elements with the same key are considered as equal. - Due to keys and a ``merge`` function (see :class:`MutablePoset`) - this operation might not be commutative. - EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 62cb899564ef038d3ca230de0bf00e19a7fe8b47 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 25 Sep 2015 22:48:16 +0200 Subject: [PATCH 1084/1872] Revert autotools dependencies --- build/pkgs/autotools/dependencies | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 build/pkgs/autotools/dependencies diff --git a/build/pkgs/autotools/dependencies b/build/pkgs/autotools/dependencies deleted file mode 100644 index 3546cda4614..00000000000 --- a/build/pkgs/autotools/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -# no dependencies - ----------- -All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. From 954c0d03b85680cb45534ddb7a920aa4ab451357 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 28 Sep 2015 15:13:47 -0300 Subject: [PATCH 1085/1872] Trac 19299: remove a duplicated line --- src/sage/sets/cartesian_product.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index bf44ea3ba50..0ecfd6917e4 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -285,7 +285,6 @@ def cartesian_factors(self): sage: A = cartesian_product([ZZ, RR]) sage: A((1, 1.23)).cartesian_factors() - sage: A((1, 1.23)).cartesian_factors() (1, 1.23000000000000) sage: type(_) From f6b88ed88f106904bd548e1d2cafbaca75b75d1e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 28 Sep 2015 18:19:14 +0200 Subject: [PATCH 1086/1872] trac #19301: Cleanup in dense_graph.pyx --- src/sage/graphs/base/dense_graph.pyx | 111 +++++++++++---------------- 1 file changed, 44 insertions(+), 67 deletions(-) diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx index f1abc3d4128..e9da1a2a239 100644 --- a/src/sage/graphs/base/dense_graph.pyx +++ b/src/sage/graphs/base/dense_graph.pyx @@ -102,18 +102,16 @@ from ``CGraph`` (for explanation, refer to the documentation there):: It also contains the following variables:: - cdef int radix_div_shift - cdef int radix_mod_mask cdef int num_longs cdef unsigned long *edges The array ``edges`` is a series of bits which are turned on or off, and due to this, dense graphs only support graphs without edge labels and with no multiple -edges. The ints ``radix_div_shift`` and ``radix_mod_mask`` are simply for doing -efficient division by powers of two, and ``num_longs`` stores the length of the -``edges`` array. Recall that this length reflects the number of available -vertices, not the number of "actual" vertices. For more details about this, -refer to the documentation for ``CGraph``. +edges. ``num_longs`` stores the length of the ``edges`` array. Recall that this +length reflects the number of available vertices, not the number of "actual" +vertices. For more details about this, refer to the documentation for +``CGraph``. + """ #******************************************************************************* @@ -125,6 +123,11 @@ refer to the documentation for ``CGraph``. include 'sage/data_structures/bitset.pxi' +from libc.string cimport memcpy + +cdef int radix = sizeof(unsigned long) * 8 # number of bits per 'unsigned long' +cdef int radix_mod_mask = radix - 1 # (assumes that radis is a power of 2) + cdef class DenseGraph(CGraph): """ Compiled dense graphs. @@ -151,7 +154,6 @@ cdef class DenseGraph(CGraph): for use in pickling. """ - def __cinit__(self, int nverts, int extra_vertices = 10, verts = None, arcs = None): """ Allocation and initialization happen in one place. @@ -167,35 +169,24 @@ cdef class DenseGraph(CGraph): """ if nverts == 0 and extra_vertices == 0: raise RuntimeError('Dense graphs must allocate space for vertices!') - cdef int radix = sizeof(unsigned long) << 3 - self.radix_mod_mask = radix - 1 - cdef int i = 0 - while ((1)<> self.radix_div_shift - if total_verts & self.radix_mod_mask: - i += 1 - self.num_longs = i + # self.num_longs = "ceil(total_verts/radix)" + self.num_longs = total_verts / radix + (0 != (total_verts & radix_mod_mask)) - self.edges = sage_malloc(total_verts * self.num_longs * sizeof(unsigned long)) - self.in_degrees = sage_malloc(total_verts * sizeof(int)) - self.out_degrees = sage_malloc(total_verts * sizeof(int)) + self.edges = sage_calloc(total_verts * self.num_longs, sizeof(unsigned long)) + self.in_degrees = sage_calloc(total_verts, sizeof(int)) + self.out_degrees = sage_calloc(total_verts, sizeof(int)) if not self.edges or not self.in_degrees or not self.out_degrees: - if self.edges: sage_free(self.edges) - if self.in_degrees: sage_free(self.in_degrees) - if self.out_degrees: sage_free(self.out_degrees) + sage_free(self.edges) + sage_free(self.in_degrees) + sage_free(self.out_degrees) raise MemoryError - for i from 0 <= i < self.num_longs * total_verts: - self.edges[i] = 0 - for i from 0 <= i < total_verts: - self.in_degrees[i] = 0 - self.out_degrees[i] = 0 + bitset_init(self.active_vertices, total_verts) bitset_set_first_n(self.active_vertices, self.num_verts) @@ -261,6 +252,7 @@ cdef class DenseGraph(CGraph): cdef int i, j if total_verts == 0: raise RuntimeError('Dense graphs must allocate space for vertices!') + cdef bitset_t bits cdef int min_verts, min_longs, old_longs = self.num_longs if total_verts < self.active_vertices.size: @@ -276,42 +268,27 @@ cdef class DenseGraph(CGraph): min_verts = self.active_vertices.size min_longs = self.num_longs - i = total_verts >> self.radix_div_shift - if total_verts & self.radix_mod_mask: - i += 1 - self.num_longs = i - if min_longs == -1: min_longs = self.num_longs + # self.num_longs = "ceil(total_verts/radix)" + self.num_longs = total_verts / radix + (0 != (total_verts & radix_mod_mask)) - cdef unsigned long *new_edges = sage_malloc(total_verts * self.num_longs * sizeof(unsigned long)) + if min_longs == -1: + min_longs = self.num_longs + # Resize of self.edges + cdef unsigned long *new_edges = sage_calloc(total_verts * self.num_longs, sizeof(unsigned long)) for i from 0 <= i < min_verts: - for j from 0 <= j < min_longs: - new_edges[i*self.num_longs + j] = self.edges[i*old_longs + j] - for j from min_longs <= j < self.num_longs: - new_edges[i*self.num_longs + j] = 0 - for i from min_verts <= i < total_verts: - for j from 0 <= j < self.num_longs: - new_edges[i*self.num_longs + j] = 0 + memcpy(new_edges+i*self.num_longs, self.edges+i*old_longs, min_longs*sizeof(unsigned long)) + sage_free(self.edges) self.edges = new_edges - self.in_degrees = sage_realloc(self.in_degrees, total_verts * sizeof(int)) + self.in_degrees = sage_realloc(self.in_degrees , total_verts * sizeof(int)) self.out_degrees = sage_realloc(self.out_degrees, total_verts * sizeof(int)) - cdef int first_limb - cdef unsigned long zero_gate - if total_verts > self.active_vertices.size: - first_limb = (self.active_vertices.size >> self.radix_div_shift) - zero_gate = (1) << (self.active_vertices.size & self.radix_mod_mask) - zero_gate -= 1 - for i from 0 <= i < total_verts: - self.edges[first_limb] &= zero_gate - for j from first_limb < j < self.num_longs: - self.edges[j] = 0 - - for i from self.active_vertices.size <= i < total_verts: - self.in_degrees[i] = 0 - self.out_degrees[i] = 0 + for i in range(self.active_vertices.size, total_verts): + self.in_degrees[i] = 0 + self.out_degrees[i] = 0 + bitset_realloc(self.active_vertices, total_verts) ################################### @@ -326,8 +303,8 @@ cdef class DenseGraph(CGraph): u, v -- non-negative integers """ - cdef int place = (u * self.num_longs) + (v >> self.radix_div_shift) - cdef unsigned long word = (1) << (v & self.radix_mod_mask) + cdef int place = (u * self.num_longs) + (v / radix) + cdef unsigned long word = (1) << (v & radix_mod_mask) if not self.edges[place] & word: self.in_degrees[v] += 1 self.out_degrees[u] += 1 @@ -373,9 +350,9 @@ cdef class DenseGraph(CGraph): 1 -- True """ - cdef int place = (u * self.num_longs) + (v >> self.radix_div_shift) - cdef unsigned long word = (1) << (v & self.radix_mod_mask) - return (self.edges[place] & word) >> (v & self.radix_mod_mask) + cdef int place = (u * self.num_longs) + (v / radix) + cdef unsigned long word = (1) << (v & radix_mod_mask) + return (self.edges[place] & word) >> (v & radix_mod_mask) cpdef bint has_arc(self, int u, int v) except -1: """ @@ -409,8 +386,8 @@ cdef class DenseGraph(CGraph): u, v -- non-negative integers, must be in self """ - cdef int place = (u * self.num_longs) + (v >> self.radix_div_shift) - cdef unsigned long word = (1) << (v & self.radix_mod_mask) + cdef int place = (u * self.num_longs) + (v / radix) + cdef unsigned long word = (1) << (v & radix_mod_mask) if self.edges[place] & word: self.in_degrees[v] -= 1 self.out_degrees[u] -= 1 @@ -527,8 +504,8 @@ cdef class DenseGraph(CGraph): there were more """ - cdef int place = v >> self.radix_div_shift - cdef unsigned long word = (1) << (v & self.radix_mod_mask) + cdef int place = v / radix + cdef unsigned long word = (1) << (v & radix_mod_mask) cdef int i, num_nbrs = 0 for i from 0 <= i < self.active_vertices.size: if self.edges[place + i*self.num_longs] & word: From 548b8f012647c1fae0ab8d080f2f27a382c39d51 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 28 Sep 2015 20:24:58 +0200 Subject: [PATCH 1087/1872] trac #19301: complement() --- src/sage/graphs/base/dense_graph.pyx | 37 ++++++++++++++++++++++++++++ src/sage/graphs/generic_graph.py | 13 ++++------ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx index e9da1a2a239..29bf399164d 100644 --- a/src/sage/graphs/base/dense_graph.pyx +++ b/src/sage/graphs/base/dense_graph.pyx @@ -421,6 +421,43 @@ cdef class DenseGraph(CGraph): self.check_vertex(v) self.del_arc_unsafe(u,v) + def complement(self): + r""" + Replaces the graph with its complement + + .. NOTE:: + + Assumes that the graph has no loop. + + EXAMPLE:: + + sage: from sage.graphs.base.dense_graph import DenseGraph + sage: G = DenseGraph(5) + sage: G.add_arc(0,1) + sage: G.has_arc(0,1) + True + sage: G.complement() + sage: G.has_arc(0,1) + False + """ + cdef int num_arcs_old = self.num_arcs + + # The following cast assumes that mp_limb_t is an unsigned long. + # (this assumption is already made in bitset.pxi) + cdef unsigned long * active_vertices_bitset + active_vertices_bitset = self.active_vertices.bits + + cdef int i,j + for i in range(self.active_vertices.size): + if bitset_in(self.active_vertices,i): + self.add_arc_unsafe(i,i) + for j in range(self.num_longs): # the actual job + self.edges[i*self.num_longs+j] ^= active_vertices_bitset[j] + self.in_degrees[i] = self.num_verts-self.in_degrees[i] + self.out_degrees[i] = self.num_verts-self.out_degrees[i] + + self.num_arcs = self.num_verts*(self.num_verts-1) - num_arcs_old + ################################### # Neighbor functions ################################### diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 84938f5c7eb..fb80ead83ea 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16338,17 +16338,14 @@ def complement(self): Graph on 10 vertices """ - if self.has_multiple_edges(): - raise TypeError('complement not well defined for (di)graphs with multiple edges') self._scream_if_not_simple() - G = copy(self) - G.delete_edges(G.edges()) + + G = self.copy(data_structure='dense') + G._backend.c_graph()[0].complement() + if self.name(): G.name("complement({})".format(self.name())) - for u in self: - for v in self: - if not self.has_edge(u,v): - G.add_edge(u,v) + if getattr(self, '_immutable', False): return G.copy(immutable=True) return G From 9fcf7716def342b2e550c563c459dd0eea9531d5 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:42:03 +0200 Subject: [PATCH 1088/1872] extended introduction (comment 1) --- src/sage/rings/asymptotic/growth_group.py | 31 +++++++++++++---------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 553d4db3d2b..a84b9984352 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -47,21 +47,22 @@ Growth Group x^ZZ -.. NOTE:: +Creation of Growth Groups +========================= - By using the following short notation for growth groups, their - creation is very simple: *Monomial growth groups* (i.e. the - group for powers of a fixed symbol; - :class:`~sage.rings.asymptotic.growth_group.MonomialGrowthGroup`) - are denoted as ``variable^base``, e.g. ``x^ZZ`` and ``y^QQ`` for - the group of integer powers of `x`, and the group of rational - powers of `y`, respectively. +By using the following short notation for growth groups, their +creation is very simple: *Monomial growth groups* (i.e. the +group for powers of a fixed symbol; +:class:`~sage.rings.asymptotic.growth_group.MonomialGrowthGroup`) +are denoted as ``variable^base``, e.g. ``x^ZZ`` and ``y^QQ`` for +the group of integer powers of `x`, and the group of rational +powers of `y`, respectively. - This also enables us to construct *logarithmic growth groups*, - e.g. ``log(x)^ZZ``. +This also enables us to construct *logarithmic growth groups*, +e.g. ``log(x)^ZZ``. - This notation will also be extended to *Exponential growth - groups*. +This notation will also be extended to *Exponential growth +groups*. EXAMPLES:: @@ -94,7 +95,11 @@ sage: agg.GrowthGroup('x^ZZ * log(x)^ZZ') is agg.GrowthGroup('log(x)^ZZ * x^ZZ') False -(Note that it is mathematically nonsense to make ``log(x)`` larger than ``x``.) +In this case the components are ordered lexicographically, which +means that in the second growth group, ``log(x)`` is assumed to +grow faster than ``x`` (which is nonsense, mathematically). See +:class:`sage.rings.asymptotic.growth_group_cartesian.CartesianProductFactory` +for more details. Classes and Methods =================== From 125c0c4ecf982b9f0bf2cce1ea4039c68dae1f23 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:45:12 +0200 Subject: [PATCH 1089/1872] fix imports and take care of changes in #18223 --- src/sage/rings/asymptotic/growth_group_cartesian.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index adf241ba28e..8a5d7ccaafb 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -70,11 +70,11 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): Growth Group y^ZZ sage: E = cartesian_product([A, D]); E Growth Group x^ZZ * y^ZZ - sage: E._le_ == E.le_components + sage: E._le_ == E.le_product True sage: F = cartesian_product([C, D]); F Growth Group x^ZZ * log(x)^ZZ * y^ZZ - sage: F._le_ == F.le_components + sage: F._le_ == F.le_product True sage: cartesian_product([A, E]); G Traceback (most recent call last): @@ -166,7 +166,7 @@ def create_object(self, version, args, **kwds): CartesianProductGrowthGroups = CartesianProductFactory('CartesianProductGrowthGroups') -from sage.sets.cartesian_product import CartesianProductPosets +from sage.combinat.posets.cartesian_product import CartesianProductPosets from sage.rings.asymptotic.growth_group import GenericGrowthGroup class GenericProduct(CartesianProductPosets, GenericGrowthGroup): r""" @@ -188,7 +188,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): sage: Lx = agg.MonomialGrowthGroup(ZZ, 'log(x)') sage: Cx = cartesian_product([Px, Lx], order='lex') sage: Py = agg.MonomialGrowthGroup(QQ, 'y') - sage: C = cartesian_product([Cx, Py], order='components'); C + sage: C = cartesian_product([Cx, Py], order='product'); C # indirect doctest Growth Group x^QQ * log(x)^ZZ * y^QQ sage: C.an_element() x^(1/2) * log(x) * y^(1/2) @@ -196,7 +196,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): .. SEEALSO:: :class:`~sage.sets.cartesian_product.CartesianProduct`, - :class:`~sage.sets.cartesian_product.CartesianProductPosets`. + :class:`~sage.combinat.posets.cartesian_product.CartesianProductPosets`. """ def _element_constructor_(self, data): @@ -484,7 +484,7 @@ def __init__(self, sets, category, **kwargs): """ super(MultivariateProduct, self).__init__( - sets, category, order='components', **kwargs) + sets, category, order='product', **kwargs) CartesianProduct = CartesianProductGrowthGroups From dc2504d156664801482c8182a5c2cc39a9559563 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:46:40 +0200 Subject: [PATCH 1090/1872] cartesian_product doctests: indirect (comments 9/10) --- .../rings/asymptotic/growth_group_cartesian.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 8a5d7ccaafb..d4d4bf6fa0e 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -62,26 +62,26 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): Growth Group x^ZZ sage: B = GrowthGroup('log(x)^ZZ'); B Growth Group log(x)^ZZ - sage: C = cartesian_product([A, B]); C + sage: C = cartesian_product([A, B]); C # indirect doctest Growth Group x^ZZ * log(x)^ZZ sage: C._le_ == C.le_lex True sage: D = GrowthGroup('y^ZZ'); D Growth Group y^ZZ - sage: E = cartesian_product([A, D]); E + sage: E = cartesian_product([A, D]); E # indirect doctest Growth Group x^ZZ * y^ZZ sage: E._le_ == E.le_product True - sage: F = cartesian_product([C, D]); F + sage: F = cartesian_product([C, D]); F # indirect doctest Growth Group x^ZZ * log(x)^ZZ * y^ZZ sage: F._le_ == F.le_product True - sage: cartesian_product([A, E]); G + sage: cartesian_product([A, E]); G # indirect doctest Traceback (most recent call last): ... ValueError: Growth groups (Growth Group x^ZZ, Growth Group x^ZZ * y^ZZ) do not have pairwise disjoint variables. - sage: cartesian_product([A, B, D]) + sage: cartesian_product([A, B, D]) # indirect doctest Growth Group x^ZZ * log(x)^ZZ * y^ZZ TESTS:: @@ -177,7 +177,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.MonomialGrowthGroup(QQ, 'x') sage: L = agg.MonomialGrowthGroup(ZZ, 'log(x)') - sage: C = cartesian_product([P, L], order='lex'); C + sage: C = cartesian_product([P, L], order='lex'); C # indirect doctest Growth Group x^QQ * log(x)^ZZ sage: C.an_element() x^(1/2) * log(x) @@ -186,7 +186,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): sage: Px = agg.MonomialGrowthGroup(QQ, 'x') sage: Lx = agg.MonomialGrowthGroup(ZZ, 'log(x)') - sage: Cx = cartesian_product([Px, Lx], order='lex') + sage: Cx = cartesian_product([Px, Lx], order='lex') # indirect doctest sage: Py = agg.MonomialGrowthGroup(QQ, 'y') sage: C = cartesian_product([Cx, Py], order='product'); C # indirect doctest Growth Group x^QQ * log(x)^ZZ * y^QQ From 665f2ba1ce69e30506970427b6935f1d715fecac Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:48:15 +0200 Subject: [PATCH 1091/1872] improve documentation (CartesianProductFactory, UnivariateProduct, MultivariateProduct) (comment 13) --- .../asymptotic/growth_group_cartesian.py | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index d4d4bf6fa0e..e00f0b5d00d 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -55,6 +55,26 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): is taken for comparing two cartesian product elements. If ``order`` is ``None`` this is determined automatically. + .. NOTE:: + + The cartesian product of growth groups is again a growth + group. In particular, the resulting structure is partially + ordered. + + The order on the product is determined as follows: + + - Cartesian factors with respect to the same variable are + ordered lexicographically. This causes + ``GrowthGroup('x^ZZ * log(x)^ZZ')`` and + ``GrowthGroup('log(x)^ZZ * x^ZZ')`` to produce two + different growth groups. + + - Factors over different variables are equipped with the + product order (i.e. the comparison is component-wise). + + Also, note that the sets of variables of the cartesian + factors have to be either equal or disjoint. + EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup @@ -455,9 +475,26 @@ def _repr_(self): class UnivariateProduct(GenericProduct): + r""" + A cartesian product of growth groups with the same variables. + + .. NOTE:: + + A univariate product of growth groups is ordered + lexicographically. This is motivated by the assumption + that univariate growth groups can be ordered in a chain + with respect to the growth they model (e.g. + ``x^ZZ * log(x)^ZZ``: polynomial growth dominates + logarithmic growth). + + .. SEEALSO:: + + :class:`MultivariateProduct`, + :class:`GenericProduct`. + """ def __init__(self, sets, category, **kwargs): r""" - A cartesian product of growth groups with the same variables. + See :class:`UnivariateProduct` for details. TEST:: @@ -473,9 +510,24 @@ def __init__(self, sets, category, **kwargs): class MultivariateProduct(GenericProduct): + r""" + A cartesian product of growth groups with pairwise disjoint + (or equal) variable sets. + + .. NOTE:: + + A multivariate product of growth groups is ordered by + means of the product order, i.e. component-wise. This is + motivated by the assumption that different variables are + considered to be independent (e.g. ``x^ZZ * y^ZZ``). + + .. SEEALSO:: + + :class:`UnivariateProduct`, + :class:`GenericProduct`. + """ def __init__(self, sets, category, **kwargs): r""" - A cartesian product of growth groups with the pairwise different variables. TEST:: From 26eb89c3df4df5d4b246b5b25529d1b157b37dd9 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:49:57 +0200 Subject: [PATCH 1092/1872] remove unreachable ValueError (comment 2) --- src/sage/rings/asymptotic/growth_group.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index a84b9984352..6c3392412ba 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -280,9 +280,6 @@ def __init__(self, var, repr=None): for v in var), tuple()) var_repr = ', '.join(var) else: - for v in var: - if not isidentifier(v): - raise ValueError("'%s' is not a valid name for a variable." % (v,)) var_bases = var var_repr = str(repr).strip() From 0887284c5f683d3fe3f7ad6f7c987e6706c4efcb Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:50:48 +0200 Subject: [PATCH 1093/1872] extract_variable_names: let SR parse (comment 3) --- src/sage/rings/asymptotic/growth_group.py | 82 +++++++---------------- 1 file changed, 23 insertions(+), 59 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6c3392412ba..c3f8d3be543 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -266,6 +266,13 @@ def __init__(self, var, repr=None): blub sage: Variable('blub') is Variable('blub') True + + :: + + sage: Variable('(:-)') + Traceback (most recent call last): + ... + TypeError: Malformed expression: (: !!! -) """ from sage.symbolic.ring import isidentifier @@ -405,21 +412,19 @@ def extract_variable_names(s): :: sage: Variable.extract_variable_names('log(77w)') - Traceback (most recent call last): - .... - ValueError: '77w' is not a valid name for a variable. + ('w',) sage: Variable.extract_variable_names('log(x') Traceback (most recent call last): .... - ValueError: Unbalanced parentheses in 'log(x'. + TypeError: Bad function call: log(x !!! sage: Variable.extract_variable_names('x)') Traceback (most recent call last): .... - ValueError: Unbalanced parentheses in 'x)'. + TypeError: Malformed expression: x) !!! sage: Variable.extract_variable_names('log)x(') Traceback (most recent call last): .... - ValueError: Unbalanced parentheses in 'log)x('. + TypeError: Malformed expression: log) !!! x( sage: Variable.extract_variable_names('log(x)+y') ('x', 'y') @@ -434,7 +439,9 @@ def extract_variable_names(s): sage: Variable.extract_variable_names('+a') ('a',) sage: Variable.extract_variable_names('a+') - ('a',) + Traceback (most recent call last): + ... + TypeError: Malformed expression: a+ !!! sage: Variable.extract_variable_names('b!') ('b',) sage: Variable.extract_variable_names('-a') @@ -445,59 +452,16 @@ def extract_variable_names(s): ('q',) sage: Variable.extract_variable_names('77') () - """ - from sage.symbolic.ring import isidentifier - import re - numbers = re.compile(r"\d+$") - vars = [] - - def find_next_outer_parentheses(s): - op = s.find('(') - level = 1 - for i, c in enumerate(s[op+1:]): - if c == ')': - level -= 1 - if c == '(': - level += 1 - if level == 0: - return op, op+i+1 - return op, -1 - def strip(s): - s = s.strip() - if not s: - return - - # parentheses (...) - # functions f(...) - op, cl = find_next_outer_parentheses(s) - if (op == -1) != (cl == -1) or op > cl: - raise ValueError("Unbalanced parentheses in '%s'." % (s,)) - if cl != -1: - strip(s[op+1:cl]) - strip(s[cl+1:]) - return - - # unary +a, a+, ... - # binary a+b, a*b, ... - for operator in ('**', '+', '-', '*', '/', '^', '!'): - a, o, b = s.partition(operator) - if o: - strip(a) - strip(b) - return - - # a number - if numbers.match(s) is not None: - return - - # else: a variable - if not isidentifier(s): - raise ValueError("'%s' is not a valid name for a variable." % (s,)) - vars.append(s) - - strip(s) - return tuple(vars) + :: + + sage: Variable.extract_variable_names('a + (b + c) + d') + ('a', 'b', 'c', 'd') + """ + from sage.symbolic.ring import SR + if s == '': + return () + return tuple(str(s) for s in SR(s).variables()) class GenericGrowthElement(sage.structure.element.MultiplicativeGroupElement): From d35c406fbb3c88ea0044dfb3e72f432d743cb14d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:51:31 +0200 Subject: [PATCH 1094/1872] fix doctest --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c3f8d3be543..a729da75b22 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1570,7 +1570,7 @@ def __init__(self, base, var, category): sage: agg.MonomialGrowthGroup('x', ZZ) Traceback (most recent call last): ... - ValueError: 'Integer Ring' is not a valid name for a variable. + TypeError: x is not a valid base sage: agg.MonomialGrowthGroup('x', 'y') Traceback (most recent call last): ... From 9528dfe67106f3a97b154c7c3a895772d1bb4af6 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:51:39 +0200 Subject: [PATCH 1095/1872] language (comment 4) --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index a729da75b22..dea8c273bed 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1217,7 +1217,7 @@ def gens_monomial(self): while ``log(x)^ZZ`` or ``icecream(x)^ZZ`` do not have monomial generators. - This method is only implemented for concrete growth + This method must be implemented for concrete growth group implementations. TESTS:: From f88d3ead2feadd76bf3fccbd6488f7d0c36c501d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 28 Sep 2015 21:52:09 +0200 Subject: [PATCH 1096/1872] MonomialGrowthGroup._convert_: let SR parse string + take care of '1' (comment 6) --- src/sage/rings/asymptotic/growth_group.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index dea8c273bed..df8da46165d 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1716,8 +1716,13 @@ def _convert_(self, data): x^(-2) sage: P('x^-2') x^(-2) + + :: + + sage: P('1') + 1 """ - if data == 1: + if data == 1 or data == '1': return self.base().zero() var = repr(self._var_) if str(data) == var: @@ -1728,15 +1733,8 @@ def _convert_(self, data): except AttributeError: if var not in str(data): return # this has to end here - - elif str(data) == '1/' + var: - return self.base()(-1) - elif str(data).startswith(var + '^'): - return self.base()(str(data).replace(var + '^', '') - .replace('(', '').replace(')', '')) - else: - return # end of parsing - + from sage.symbolic.ring import SR + return self._convert_(SR(data)) from sage.symbolic.ring import SR from sage.rings.polynomial.polynomial_ring import PolynomialRing_general From 173cc9beb820fdcb97b5323297df28ec1acc89f6 Mon Sep 17 00:00:00 2001 From: Andrew Gainer-Dewar Date: Mon, 28 Sep 2015 15:53:12 -0400 Subject: [PATCH 1097/1872] Fix bogus doc ref to polyhedron.interior_point() --- src/sage/geometry/polyhedron/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 0d3fe99bad4..4892e002b6b 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1909,7 +1909,7 @@ def center(self): """ Return the average of the vertices. - See also :meth:`interior_point`. + See also :meth:`representative_point`. OUTPUT: From 0d806488874034fc5d47ffd6603880256b4e79f2 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 28 Sep 2015 22:18:56 +0200 Subject: [PATCH 1098/1872] trac #19301: Doctest --- src/sage/graphs/generic_graph.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index fb80ead83ea..e4feaeb6694 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16291,8 +16291,7 @@ def add_path(self, vertices): vert1 = v def complement(self): - """ - Returns the complement of the (di)graph. + """Returns the complement of the (di)graph. The complement of a graph has the same vertices, but exactly those edges that are not in the original graph. This is not well defined @@ -16320,7 +16319,10 @@ def complement(self): sage: G.complement() Traceback (most recent call last): ... - TypeError: complement not well defined for (di)graphs with multiple edges + ValueError: This method is not known to work on graphs with + multiedges. Perhaps this method can be updated to handle them, but + in the meantime if you want to use it please disallow multiedges + using allow_multiple_edges(). TESTS: From c590ad18c93f7b0376145142c4da1448cda05b8f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 29 Sep 2015 05:48:25 +0200 Subject: [PATCH 1099/1872] trac #19279: Remove duplicate references --- src/sage/combinat/designs/incidence_structures.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index bab1c8df92c..4597204b8a8 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1662,8 +1662,8 @@ def is_generalized_quadrangle(self, verbose=False, parameters=False): .. NOTE:: - Observe that some references (e.g. [PT09]_ or Wikipedia) only allow - *regular* generalized quadrangles. To use such a definition, see the + Some references (e.g. [PT09]_ or [GQwiki]_) only allow *regular* + generalized quadrangles. To use such a definition, see the ``parameters`` optional argument described below, or the methods :meth:`is_regular` and :meth:`is_uniform`. @@ -1705,13 +1705,6 @@ def is_generalized_quadrangle(self, verbose=False, parameters=False): sage: hypergraphs.CompleteUniform(4,2).is_generalized_quadrangle(verbose=1) Some point has two projections on some line. False - - REFERENCE: - - .. [PT09] S. Payne, J. Thas, - Finite generalized quadrangles, - European Mathematical Society, 2009. - http://cage.ugent.be/~bamberg/FGQ.pdf """ # The distance between a point and a line in the incidence graph is odd # and must be <= 3. Thus, the diameter is at most 4 From f7bd83a0f256e186fe5f8ecc9c4501d0643f7811 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 29 Sep 2015 08:50:11 +0200 Subject: [PATCH 1100/1872] Trac #17693, comment 43, 7: do caching of key in __init__ --- src/sage/data_structures/mutable_poset.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 878459e6f3a..41e5cd3a32c 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -208,6 +208,7 @@ def __init__(self, poset, element): """ self._poset_ = poset self._element_ = element + self._key_ = self.poset.get_key(element) self._predecessors_ = set() self._successors_ = set() super(MutablePosetShell, self).__init__() @@ -290,16 +291,12 @@ def key(self): ....: return k sage: R = MP(key=k) sage: h = MutablePosetShell(R, (1, 2)) - sage: h.key; h.key key (1, 2) + sage: h.key; h.key (1, 2) (1, 2) """ - # workaround for #19281 - # (Use @property @cached_method once #19281 is fixed.) - if not hasattr(self, '_cached_key_'): - self._cached_key_ = self.poset.get_key(self._element_) - return self._cached_key_ + return self._key_ def predecessors(self, reverse=False): From a554d697526397fca280239fa11b210cbec94c80 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 29 Sep 2015 08:56:40 +0200 Subject: [PATCH 1101/1872] rac #17693, comment 43, 18: use .is_oo to test for oo in doctest --- src/sage/data_structures/mutable_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 41e5cd3a32c..6465689ac7a 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -710,7 +710,7 @@ def _copy_all_linked_(self, memo, poset, mapping): sage: z.poset is Q True sage: oo = z.successors().pop() - sage: oo == P.oo + sage: oo.is_oo() True """ try: From 3ac7ed1b8f318620cbeee52f570d6e8ef7bb23f9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 29 Sep 2015 08:57:05 +0200 Subject: [PATCH 1102/1872] rac #17693, comment 43, 18: add a doctest "oo is Q.oo" --- src/sage/data_structures/mutable_poset.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 6465689ac7a..3905ac1510f 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -712,6 +712,14 @@ def _copy_all_linked_(self, memo, poset, mapping): sage: oo = z.successors().pop() sage: oo.is_oo() True + + Note that :meth:`_copy_all_linked_` does not change the mutable + poset `Q` (this is done in the calling method + :meth:`MutablePoset._copy_shells_`). Thus we have + :: + + sage: oo is Q.oo + False """ try: return memo[id(self)] From 2f675b3a6fff5e50770e85aedc23f38afbe275f0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 29 Sep 2015 09:03:06 +0200 Subject: [PATCH 1103/1872] Trac #17693, comment 43, 18: add a doctest in eq (comparing elements in different posets) --- src/sage/data_structures/mutable_poset.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 3905ac1510f..6498e069796 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -663,6 +663,16 @@ def eq(self, other): False sage: oo == z False + + Comparing elements in different mutable posets is possible; their + shells are equal if their elements are:: + + sage: S = MP([42]); s = S.shell(42) + sage: T = MP([42]); t = T.shell(42) + sage: s == t + True + sage: S.oo == T.oo + True """ if self.element is None and other.element is None: return self.is_null() == other.is_null() From dea3c966b0fe1437e1dd5de4c058b2c79b259b59 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Tue, 29 Sep 2015 09:08:22 +0200 Subject: [PATCH 1104/1872] Trac #18587: additional doctest --- src/sage/rings/asymptotic/growth_group.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index df8da46165d..dc3926a88de 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -427,6 +427,8 @@ def extract_variable_names(s): TypeError: Malformed expression: log) !!! x( sage: Variable.extract_variable_names('log(x)+y') ('x', 'y') + sage: Variable.extract_variable_names('icecream(summer)') + ('summer',) :: From 6d3e4f4ce27b8b0cb252f05a352458f7075e0b1a Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Tue, 29 Sep 2015 09:08:43 +0200 Subject: [PATCH 1105/1872] Trac #18587: nicer output of one link target --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index dc3926a88de..0cfb6bc1710 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -98,7 +98,7 @@ In this case the components are ordered lexicographically, which means that in the second growth group, ``log(x)`` is assumed to grow faster than ``x`` (which is nonsense, mathematically). See -:class:`sage.rings.asymptotic.growth_group_cartesian.CartesianProductFactory` +:class:`CartesianProduct ` for more details. Classes and Methods From f064a3b6434551b97a0bbb36d918b8b2d1ffe3d6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 29 Sep 2015 09:14:02 +0200 Subject: [PATCH 1106/1872] Trac #17693, comment 43, 22: covers --> lower_covers, upper_covers --- src/sage/data_structures/mutable_poset.py | 103 +++++++++++++++++++--- 1 file changed, 89 insertions(+), 14 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 6498e069796..e7412ab6357 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -747,16 +747,14 @@ def _copy_all_linked_(self, memo, poset, mapping): return new - def covers(self, shell, reverse=False): + def lower_covers(self, shell, reverse=False): r""" - Return the lower or upper covers of the specified ``shell``; + Return the lower covers of the specified ``shell``; the search is started at this (``self``) shell. A lower cover of `x` is an element `y` of the poset such that `y < x` and there is no element `z` of the poset - so that `x < z < y`. Likewise, - an upper cover of `x` is an element `y` such that `x < y` and - there is no element `z` so that `x < z < y`. + so that `y < z < x`. INPUT: @@ -765,8 +763,9 @@ def covers(self, shell, reverse=False): If ``shell`` is contained in the poset, then use the more efficient methods :meth:`predecessors` and :meth:`successors`. - - ``reverse`` -- (default: ``False``) if not set, then find - the lower covers, otherwise find the upper covers. + - ``reverse`` -- (default: ``False``) if set, then find + the upper covers (see also :meth:`upper_covers`) + instead of the lower covers. OUTPUT: @@ -792,12 +791,12 @@ def covers(self, shell, reverse=False): ....: T((4, 4)), T((1, 2)), T((2, 2))]) sage: e = P.shell(T((2, 2))); e (2, 2) - sage: sorted(P.null.covers(e), + sage: sorted(P.null.lower_covers(e), ....: key=lambda c: repr(c.element)) [(1, 2), (2, 1)] sage: set(_) == e.predecessors() True - sage: sorted(P.oo.covers(e, reverse=True), + sage: sorted(P.oo.upper_covers(e), ....: key=lambda c: repr(c.element)) [(4, 4)] sage: set(_) == e.successors() @@ -807,27 +806,103 @@ def covers(self, shell, reverse=False): sage: Q = MP([T((3, 2))]) sage: f = next(Q.shells()) - sage: sorted(P.null.covers(f), + sage: sorted(P.null.lower_covers(f), ....: key=lambda c: repr(c.element)) [(2, 2)] - sage: sorted(P.oo.covers(f, reverse=True), + sage: sorted(P.oo.upper_covers(f), ....: key=lambda c: repr(c.element)) [(4, 4)] .. SEEALSO:: + :meth:`upper_covers`, :meth:`predecessors`, :meth:`successors`, :class:`MutablePoset`. """ if self == shell: return set() - covers = set().union(*(e.covers(shell, reverse) + covers = set().union(*(e.lower_covers(shell, reverse) for e in self.successors(reverse) if e.le(shell, reverse))) return covers or set([self]) + def upper_covers(self, shell, reverse=False): + r""" + Return the upper covers of the specified ``shell``; + the search is started at this (``self``) shell. + + An upper cover of `x` is an element `y` of the poset + such that `x < y` and there is no element `z` of the poset + so that `x < z < y`. + + INPUT: + + - ``shell`` -- the shell for which to find the covering shells. + There is no restrition of ``shell`` being contained in the poset. + If ``shell`` is contained in the poset, then use the more efficient + methods :meth:`predecessors` and :meth:`successors`. + + - ``reverse`` -- (default: ``False``) if set, then find + the lower covers (see also :meth:`lower_covers`) + instead of the upper covers. + + OUTPUT: + + A set of :class:`shells `. + + .. NOTE:: + + Suppose ``reverse`` is ``False``. This method starts at + the calling shell (``self``) and searches towards ``'null'``. + Thus, only shells which are (not necessarily + direct) predecessors of this shell are considered. + + If ``reverse`` is ``True``, then the reverse direction is + taken. + + EXAMPLES:: + + sage: from sage.data_structures.mutable_poset import MutablePoset as MP + sage: class T(tuple): + ....: def __le__(left, right): + ....: return all(l <= r for l, r in zip(left, right)) + sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), + ....: T((4, 4)), T((1, 2)), T((2, 2))]) + sage: e = P.shell(T((2, 2))); e + (2, 2) + sage: sorted(P.null.lower_covers(e), + ....: key=lambda c: repr(c.element)) + [(1, 2), (2, 1)] + sage: set(_) == e.predecessors() + True + sage: sorted(P.oo.upper_covers(e), + ....: key=lambda c: repr(c.element)) + [(4, 4)] + sage: set(_) == e.successors() + True + + :: + + sage: Q = MP([T((3, 2))]) + sage: f = next(Q.shells()) + sage: sorted(P.null.lower_covers(f), + ....: key=lambda c: repr(c.element)) + [(2, 2)] + sage: sorted(P.oo.upper_covers(f), + ....: key=lambda c: repr(c.element)) + [(4, 4)] + + .. SEEALSO:: + + :meth:`predecessors`, + :meth:`successors`, + :class:`MutablePoset`. + """ + return self.lower_covers(shell, not reverse) + + def _iter_depth_first_visit_(self, marked, reverse=False, key=None, condition=None): @@ -2258,8 +2333,8 @@ def add(self, element): return new = MutablePosetShell(self, element) - new._predecessors_ = self.null.covers(new, reverse=False) - new._successors_ = self.oo.covers(new, reverse=True) + new._predecessors_ = self.null.lower_covers(new) + new._successors_ = self.oo.upper_covers(new) for s in new.predecessors(): for l in s.successors().intersection(new.successors()): From bea925cec11160275c4b3357c25b0f3d157d482e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 29 Sep 2015 09:16:06 +0200 Subject: [PATCH 1107/1872] Trac #17693, comment 43, 55: remove comment on non-commutativity --- src/sage/data_structures/mutable_poset.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index e7412ab6357..c7d36b4279f 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2886,9 +2886,6 @@ def intersection(self, *other): The key of an element is used for comparison. Thus elements with the same key are considered as equal. - Due to keys and a ``merge`` function (see :class:`MutablePoset`) - this operation might not be commutative. - EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP @@ -2939,9 +2936,6 @@ def intersection_update(self, *other): The key of an element is used for comparison. Thus elements with the same key are considered as equal. - Due to keys and a ``merge`` function (see :class:`MutablePoset`) - this operation might not be commutative. - EXAMPLES:: sage: from sage.data_structures.mutable_poset import MutablePoset as MP From 66759bb07e885f55decc3d09319f68f6d646f634 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 09:22:05 +0200 Subject: [PATCH 1108/1872] Revert "remove unreachable ValueError (comment 2)" This reverts commit 26eb89c3df4df5d4b246b5b25529d1b157b37dd9. --- src/sage/rings/asymptotic/growth_group.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 0cfb6bc1710..6f5b9a195b3 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -287,6 +287,9 @@ def __init__(self, var, repr=None): for v in var), tuple()) var_repr = ', '.join(var) else: + for v in var: + if not isidentifier(v): + raise ValueError("'%s' is not a valid name for a variable." % (v,)) var_bases = var var_repr = str(repr).strip() From 4e73b4576e1e949b7257d858fbeb958152df9f66 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 29 Sep 2015 09:22:06 +0200 Subject: [PATCH 1109/1872] Trac #17693, comment 43, 63: extend/rewrite non-commutativity note --- src/sage/data_structures/mutable_poset.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index c7d36b4279f..d46d930d814 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2708,10 +2708,9 @@ def union_update(self, *other): .. NOTE:: The key of an element is used for comparison. Thus elements with - the same key are considered as equal. - - Due to keys and a ``merge`` function (see :class:`MutablePoset`) - this operation might not be commutative. + the same key are considered as equal; + ``A.union_update(B)`` and ``B.union_update(A)`` might + result in different posets. .. TODO:: @@ -2934,7 +2933,9 @@ def intersection_update(self, *other): .. NOTE:: The key of an element is used for comparison. Thus elements with - the same key are considered as equal. + the same key are considered as equal; + ``A.union_update(B)`` and ``B.union_update(A)`` might + result in different posets. EXAMPLES:: @@ -2977,9 +2978,8 @@ def symmetric_difference(self, other): .. NOTE:: - If this poset uses a ``key``-function, then all - comparisons are performed on the keys of the elements (and - not on the elements themselves). + The key of an element is used for comparison. Thus elements with + the same key are considered as equal. EXAMPLES:: @@ -3021,9 +3021,10 @@ def symmetric_difference_update(self, other): .. NOTE:: - If this poset uses a ``key``-function, then all - comparisons are performed on the keys of the elements (and - not on the elements themselves). + The key of an element is used for comparison. Thus elements with + the same key are considered as equal; + ``A.union_update(B)`` and ``B.union_update(A)`` might + result in different posets. EXAMPLES:: From e8d8d2c4b4975054c2470d2ee88e937ae1044167 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Tue, 29 Sep 2015 10:05:07 +0200 Subject: [PATCH 1110/1872] Trac #17693: typos --- src/sage/data_structures/mutable_poset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d46d930d814..d95798f363b 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -759,7 +759,7 @@ def lower_covers(self, shell, reverse=False): INPUT: - ``shell`` -- the shell for which to find the covering shells. - There is no restrition of ``shell`` being contained in the poset. + There is no restriction of ``shell`` being contained in the poset. If ``shell`` is contained in the poset, then use the more efficient methods :meth:`predecessors` and :meth:`successors`. @@ -840,7 +840,7 @@ def upper_covers(self, shell, reverse=False): INPUT: - ``shell`` -- the shell for which to find the covering shells. - There is no restrition of ``shell`` being contained in the poset. + There is no restriction of ``shell`` being contained in the poset. If ``shell`` is contained in the poset, then use the more efficient methods :meth:`predecessors` and :meth:`successors`. From 4b7f929e34a497e1180cb51efc74af4fdf7f79df Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Tue, 29 Sep 2015 10:05:25 +0200 Subject: [PATCH 1111/1872] Trac #17693: fix two copy&paste errors --- src/sage/data_structures/mutable_poset.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index d95798f363b..882a1135648 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -2934,7 +2934,7 @@ def intersection_update(self, *other): The key of an element is used for comparison. Thus elements with the same key are considered as equal; - ``A.union_update(B)`` and ``B.union_update(A)`` might + ``A.intersection_update(B)`` and ``B.intersection_update(A)`` might result in different posets. EXAMPLES:: @@ -3023,7 +3023,8 @@ def symmetric_difference_update(self, other): The key of an element is used for comparison. Thus elements with the same key are considered as equal; - ``A.union_update(B)`` and ``B.union_update(A)`` might + ``A.symmetric_difference_update(B)`` and + ``B.symmetric_difference_update(A)`` might result in different posets. EXAMPLES:: From a0b3d7bce3325e271e53b0a83047a6f80ac28a22 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Tue, 29 Sep 2015 10:05:47 +0200 Subject: [PATCH 1112/1872] Trac #17693: ReSt improvement --- src/sage/data_structures/mutable_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 882a1135648..3275be203ff 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -724,7 +724,7 @@ def _copy_all_linked_(self, memo, poset, mapping): True Note that :meth:`_copy_all_linked_` does not change the mutable - poset `Q` (this is done in the calling method + poset ``Q`` (this is done in the calling method :meth:`MutablePoset._copy_shells_`). Thus we have :: From 064256413e24934e44328446dd093d8d56a786c3 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 10:06:06 +0200 Subject: [PATCH 1113/1872] doctest added --- src/sage/rings/asymptotic/growth_group.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6f5b9a195b3..efc3e739ba2 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -273,6 +273,10 @@ def __init__(self, var, repr=None): Traceback (most recent call last): ... TypeError: Malformed expression: (: !!! -) + sage: Variable('(:-)', repr='icecream') + Traceback (most recent call last): + ... + ValueError: '(:-)' is not a valid name for a variable. """ from sage.symbolic.ring import isidentifier From 7f209ea7928606090e597d0633685649739932b8 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 10:14:15 +0200 Subject: [PATCH 1114/1872] improved error message (equal or disjoint var.) --- src/sage/rings/asymptotic/growth_group_cartesian.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index e00f0b5d00d..89cdcbe2dea 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -99,8 +99,8 @@ class CartesianProductFactory(sage.structure.factory.UniqueFactory): sage: cartesian_product([A, E]); G # indirect doctest Traceback (most recent call last): ... - ValueError: Growth groups (Growth Group x^ZZ, Growth Group x^ZZ * y^ZZ) - do not have pairwise disjoint variables. + ValueError: The growth groups (Growth Group x^ZZ, Growth Group x^ZZ * y^ZZ) + need to have pairwise disjoint or equal variables. sage: cartesian_product([A, B, D]) # indirect doctest Growth Group x^ZZ * log(x)^ZZ * y^ZZ @@ -164,8 +164,8 @@ def create_object(self, version, args, **kwds): # check if variables are pairwise disjoint for u, w in product(iter(v for v, _ in vgs), repeat=2): if u != w and set(u).intersection(set(w)): - raise ValueError('Growth groups %s do not have pairwise disjoint ' - 'variables.' % (growth_groups,)) + raise ValueError('The growth groups %s need to have pairwise ' + 'disjoint or equal variables.' % (growth_groups,)) # build cartesian products u_groups = list() From 29fbc41159aec20da5bc1e0a5a08ddc8058a9fc7 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 29 Sep 2015 10:10:31 +0200 Subject: [PATCH 1115/1872] Better hash for rationals --- src/sage/libs/gmp/pylong.pyx | 7 ++-- src/sage/rings/finite_rings/integer_mod.pyx | 11 ++--- .../number_field_element_quadratic.pyx | 42 +++++++------------ src/sage/rings/rational.pyx | 31 +++++++------- src/sage/rings/real_interval_absolute.pyx | 3 +- src/sage/rings/real_lazy.pyx | 3 +- 6 files changed, 44 insertions(+), 53 deletions(-) diff --git a/src/sage/libs/gmp/pylong.pyx b/src/sage/libs/gmp/pylong.pyx index fa4e13a3afd..2575c0a214c 100644 --- a/src/sage/libs/gmp/pylong.pyx +++ b/src/sage/libs/gmp/pylong.pyx @@ -82,7 +82,8 @@ cdef int mpz_set_pylong(mpz_ptr z, L) except -1: cdef Py_hash_t mpz_pythonhash(mpz_srcptr z): """ Hash an ``mpz``, where the hash value is the same as the hash value - of the corresponding Python ``long``. + of the corresponding Python ``long``, except that we do not replace + -1 by -2 (the Cython wrapper for ``__hash__`` does that). """ # Add all limbs, adding 1 for every carry cdef mp_limb_t h1 = 0 @@ -97,7 +98,5 @@ cdef Py_hash_t mpz_pythonhash(mpz_srcptr z): cdef Py_hash_t h = h1 if mpz_sgn(z) < 0: - h = -h - if h == -1: - return -2 + return -h return h diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index efc5d11d33b..496816f39da 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -57,12 +57,14 @@ TESTS:: """ -################################################################################# +#***************************************************************************** # Copyright (C) 2006 Robert Bradshaw # 2006 William Stein # -# Distributed under the terms of the GNU General Public License (GPL) -# +# 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/ #***************************************************************************** @@ -2111,8 +2113,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): sage: hash(a) 8943 """ -# return mpz_pythonhash(self.value) - return hash(self.lift()) + return mpz_pythonhash(self.value) @coerce_binop def gcd(self, IntegerMod_gmp other): 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 223ed701c1b..0af8481f076 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -17,18 +17,14 @@ AUTHORS: The ``_new()`` method should be overridden in this class to copy the ``D`` and ``standard_embedding`` attributes """ + #***************************************************************************** -# Copyright (C) 2007 Robert Bradshaw -# -# 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: +# Copyright (C) 2007 Robert Bradshaw # +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** @@ -1313,32 +1309,22 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: L. = QuadraticField(-7) sage: hash(a) 42082631 - sage: hash(L(1)) 1 sage: hash(L(-3)) -3 - - sage: hash(L(-32/118)) - -53 - sage: hash(-32/118) - -53 + sage: hash(L(-32/118)) == hash(-32/118) + True """ # 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 + cdef Py_hash_t n = mpz_pythonhash(self.a) + cdef Py_hash_t d = mpz_pythonhash(self.denom) + cdef Py_hash_t h = n + (d - 1) * (7461864723258187525) + # 2. mix the hash together with b + h += 42082631 * mpz_pythonhash(self.b) + return h def __nonzero__(self): """ diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 63fa7fa0225..90b00709559 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -2019,20 +2019,23 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: - sage: (-4/17).__hash__() - -19 - sage: (-5/1).__hash__() - -5 - """ - cdef long n, d - n = mpz_pythonhash(mpq_numref(self.value)) - d = mpz_pythonhash(mpq_denref(self.value)) - if d == 1: - return n - n = n ^ d - if n == -1: - return -2 - return n + sage: QQ(42).__hash__() + 42 + sage: QQ(1/42).__hash__() + -7658195599476688946 + sage: n = ZZ.random_element(10^100) + sage: hash(n) == hash(QQ(n)) or n + True + sage: hash(-n) == hash(-QQ(n)) or n + True + sage: hash(-4/17) + -47583156 # 32-bit + 8709371129873690700 # 64-bit + """ + cdef Py_hash_t n = mpz_pythonhash(mpq_numref(self.value)) + cdef Py_hash_t d = mpz_pythonhash(mpq_denref(self.value)) + # The constant below is (1 + sqrt(5)) << 61 + return n + (d - 1) * (7461864723258187525) def __getitem__(self, int n): """ diff --git a/src/sage/rings/real_interval_absolute.pyx b/src/sage/rings/real_interval_absolute.pyx index 1fdcaf2ce0d..e1cfa086c46 100644 --- a/src/sage/rings/real_interval_absolute.pyx +++ b/src/sage/rings/real_interval_absolute.pyx @@ -465,7 +465,8 @@ cdef class RealIntervalAbsoluteElement(FieldElement): sage: hash(R(1/4)) == hash(1/4) True sage: hash(R(pi)) - 4385 + 891658780 # 32-bit + 532995478001132060 # 64-bit """ return hash(self.midpoint()) diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index bfe6fe659f0..84da4693055 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -1197,7 +1197,8 @@ cdef class LazyBinop(LazyFieldElement): sage: from sage.rings.real_lazy import LazyBinop sage: a = LazyBinop(RLF, 5, 1/2, operator.sub) sage: hash(a) - 2 + -1607638785 # 32-bit + -7461864723258187521 # 64-bit """ return hash(self._op(hash(self._left), hash(self._right))) From f5f7dcf8bb0c20bd3fc6212015b82e9cfd8691e1 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 10:39:17 +0200 Subject: [PATCH 1116/1872] fixed imports --- src/sage/rings/asymptotic/asymptotic_ring.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 43daaee93f7..0704892d23a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -189,9 +189,13 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** -import sage +from sage.structure.element import RingElement +from sage.rings.ring import Ring +from sage.structure.unique_representation import UniqueRepresentation +from sage.misc.superseded import experimental -class AsymptoticExpression(sage.rings.ring_element.RingElement): + +class AsymptoticExpression(RingElement): r""" Class for asymptotic expressions, i.e., the elements of an :class:`AsymptoticRing`. @@ -674,9 +678,7 @@ def O(self): for element in self.summands.maximal_elements()) - -class AsymptoticRing(sage.rings.ring.Ring, - sage.structure.unique_representation.UniqueRepresentation): +class AsymptoticRing(Ring, UniqueRepresentation): r""" A ring consisting of :class:`asymptotic expressions `. @@ -805,7 +807,7 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, category) - @sage.misc.superseded.experimental(trac_number=17601) + @experimental(trac_number=17601) def __init__(self, growth_group, coefficient_ring, category=None): r""" See :class:`AsymptoticRing` for more information. From ed50a2c763c6e89059a87600e76fc82e7a378f07 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 29 Sep 2015 10:54:36 +0200 Subject: [PATCH 1117/1872] Remove comparison boilerplate - part 4 --- src/sage/rings/complex_ball_acb.pyx | 143 ++++---- src/sage/rings/complex_double.pyx | 20 +- src/sage/rings/complex_interval.pyx | 28 +- src/sage/rings/complex_number.pyx | 8 +- .../rings/finite_rings/element_givaro.pyx | 13 - .../rings/finite_rings/element_ntl_gf2e.pyx | 22 +- .../rings/finite_rings/element_pari_ffelt.pyx | 56 ++- .../rings/finite_rings/hom_finite_field.pyx | 11 - src/sage/rings/finite_rings/integer_mod.pyx | 12 - .../rings/laurent_series_ring_element.pyx | 3 - src/sage/rings/morphism.pyx | 51 +-- .../number_field/number_field_element.pyx | 5 +- .../number_field_element_quadratic.pyx | 21 +- src/sage/rings/power_series_poly.pyx | 18 - src/sage/rings/power_series_ring_element.pyx | 28 +- src/sage/rings/rational.pyx | 7 +- src/sage/rings/real_arb.pyx | 341 +++++++++--------- src/sage/rings/real_lazy.pyx | 91 +---- src/sage/rings/real_mpfi.pyx | 22 +- 19 files changed, 340 insertions(+), 560 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 6823960c101..0c5b9e6ec29 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -583,7 +583,7 @@ cdef class ComplexBall(Element): """ return acb_is_exact(self.value) - def __richcmp__(left, right, int op): + cpdef _richcmp_(left, Element right, int op): """ Compare ``left`` and ``right``. @@ -607,19 +607,6 @@ cdef class ComplexBall(Element): False sage: a == b # optional - arb False - """ - return (left)._richcmp(right, op) - - cpdef _richcmp_(left, Element right, int op): - """ - Compare ``left`` and ``right``. - - For more information, see :mod:`sage.rings.complex_ball_acb`. - - EXAMPLES:: - - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb sage: a = CBF(1, 2) # optional - arb sage: b = CBF(1, 2) # optional - arb sage: a is b # optional - arb @@ -629,70 +616,70 @@ cdef class ComplexBall(Element): TESTS: - Balls whose intersection consists of one point:: - - sage: a = CBF(RIF(1, 2), RIF(1, 2)) # optional - arb - sage: b = CBF(RIF(2, 4), RIF(2, 4)) # optional - arb - sage: a < b # optional - arb - Traceback (most recent call last): - ... - TypeError: No order is defined for ComplexBalls. - sage: a > b # optional - arb - Traceback (most recent call last): - ... - TypeError: No order is defined for ComplexBalls. - sage: a <= b # optional - arb - Traceback (most recent call last): - ... - TypeError: No order is defined for ComplexBalls. - sage: a >= b # optional - arb - Traceback (most recent call last): - ... - TypeError: No order is defined for ComplexBalls. - sage: a == b # optional - arb - False - sage: a != b # optional - arb - False - - Balls with non-trivial intersection:: - - sage: a = CBF(RIF(1, 4), RIF(1, 4)) # optional - arb - sage: a = CBF(RIF(2, 5), RIF(2, 5)) # optional - arb - sage: a == b # optional - arb - False - sage: a != b # optional - arb - False - - One ball contained in another:: - - sage: a = CBF(RIF(1, 4), RIF(1, 4)) # optional - arb - sage: b = CBF(RIF(2, 3), RIF(2, 3)) # optional - arb - sage: a == b # optional - arb - False - sage: a != b # optional - arb - False - - Disjoint balls:: - - sage: a = CBF(1/3, 1/3) # optional - arb - sage: b = CBF(1/5, 1/5) # optional - arb - sage: a == b # optional - arb - False - sage: a != b # optional - arb - True - - Exact elements:: - - sage: a = CBF(2, 2) # optional - arb - sage: b = CBF(2, 2) # optional - arb - sage: a.is_exact() # optional - arb - True - sage: b.is_exact() # optional - arb - True - sage: a == b # optional - arb - True - sage: a != b # optional - arb - False + Balls whose intersection consists of one point:: + + sage: a = CBF(RIF(1, 2), RIF(1, 2)) # optional - arb + sage: b = CBF(RIF(2, 4), RIF(2, 4)) # optional - arb + sage: a < b # optional - arb + Traceback (most recent call last): + ... + TypeError: No order is defined for ComplexBalls. + sage: a > b # optional - arb + Traceback (most recent call last): + ... + TypeError: No order is defined for ComplexBalls. + sage: a <= b # optional - arb + Traceback (most recent call last): + ... + TypeError: No order is defined for ComplexBalls. + sage: a >= b # optional - arb + Traceback (most recent call last): + ... + TypeError: No order is defined for ComplexBalls. + sage: a == b # optional - arb + False + sage: a != b # optional - arb + False + + Balls with non-trivial intersection:: + + sage: a = CBF(RIF(1, 4), RIF(1, 4)) # optional - arb + sage: a = CBF(RIF(2, 5), RIF(2, 5)) # optional - arb + sage: a == b # optional - arb + False + sage: a != b # optional - arb + False + + One ball contained in another:: + + sage: a = CBF(RIF(1, 4), RIF(1, 4)) # optional - arb + sage: b = CBF(RIF(2, 3), RIF(2, 3)) # optional - arb + sage: a == b # optional - arb + False + sage: a != b # optional - arb + False + + Disjoint balls:: + + sage: a = CBF(1/3, 1/3) # optional - arb + sage: b = CBF(1/5, 1/5) # optional - arb + sage: a == b # optional - arb + False + sage: a != b # optional - arb + True + + Exact elements:: + + sage: a = CBF(2, 2) # optional - arb + sage: b = CBF(2, 2) # optional - arb + sage: a.is_exact() # optional - arb + True + sage: b.is_exact() # optional - arb + True + sage: a == b # optional - arb + True + sage: a != b # optional - arb + False """ cdef ComplexBall lt, rt cdef acb_t difference diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 2dbd9b83612..e181c7d8237 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -795,9 +795,13 @@ cdef class ComplexDoubleElement(FieldElement): """ return hash(complex(self)) - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, Element right) except -2: """ - Rich comparison between ``left`` and ``right``. + We order the complex numbers in dictionary order by real parts then + imaginary parts. + + This order, of course, does not respect the field structure, though + it agrees with the usual order on the real numbers. EXAMPLES:: @@ -807,18 +811,8 @@ cdef class ComplexDoubleElement(FieldElement): -1 sage: cmp(CDF(1 + i), CDF(-1 - i)) 1 - """ - return (left)._richcmp(right, op) - - cpdef int _cmp_(left, Element right) except -2: - """ - We order the complex numbers in dictionary order by real parts then - imaginary parts. - This order, of course, does not respect the field structure, though - it agrees with the usual order on the real numbers. - - EXAMPLES:: + :: sage: CDF(2,3) < CDF(3,1) True diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 2fc79377f4a..eb358f81872 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -1000,7 +1000,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): """ return self.real().__nonzero__() or self.imag().__nonzero__() - def __richcmp__(left, right, int op): + cpdef _richcmp_(left, Element right, int op): r""" As with the real interval fields this never returns false positives. Thus, `a == b` is ``True`` iff both `a` and `b` represent the same @@ -1037,9 +1037,6 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): sage: CDF(1) >= CDF(1) >= CDF.gen() >= CDF.gen() >= 0 >= -CDF.gen() >= CDF(-1) True """ - return (left)._richcmp(right, op) - - cpdef _richcmp_(left, Element right, int op): cdef ComplexIntervalFieldElement lt, rt lt = left rt = right @@ -1072,7 +1069,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): elif op == 5: #>= return real_diff > 0 or (real_diff == 0 and imag_diff >= 0) - def __cmp__(left, right): + 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(), @@ -1093,27 +1090,18 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): 0 sage: cmp(b, a) 1 - """ - return (left)._cmp(right) - - - 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(), - x.imag().lower(), x.imag().upper())`` TESTS:: sage: tests = [] sage: for rl in (0, 1): - ... for ru in (rl, rl + 1): - ... for il in (0, 1): - ... for iu in (il, il + 1): - ... tests.append((CIF(RIF(rl, ru), RIF(il, iu)), (rl, ru, il, iu))) + ....: for ru in (rl, rl + 1): + ....: for il in (0, 1): + ....: for iu in (il, il + 1): + ....: tests.append((CIF(RIF(rl, ru), RIF(il, iu)), (rl, ru, il, iu))) sage: for (i1, t1) in tests: - ... for (i2, t2) in tests: - ... assert(cmp(i1, i2) == cmp(t1, t2)) + ....: for (i2, t2) in tests: + ....: assert(cmp(i1, i2) == cmp(t1, t2)) """ cdef int a, b a = mpfi_nan_p(left.__re) diff --git a/src/sage/rings/complex_number.pyx b/src/sage/rings/complex_number.pyx index 34e941fe73a..8e4de8876a7 100644 --- a/src/sage/rings/complex_number.pyx +++ b/src/sage/rings/complex_number.pyx @@ -1123,11 +1123,10 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): """ return complex(mpfr_get_d(self.__re, rnd), mpfr_get_d(self.__im, rnd)) - # return complex(float(self.__re), float(self.__im)) - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, sage.structure.element.Element right) except -2: """ - Rich comparision between ``left`` and ``right``. + Compare ``left`` and ``right``. EXAMPLES:: @@ -1136,9 +1135,6 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): sage: cmp(CC(2, 1), CC(2, 1)) 0 """ - return (left)._richcmp(right, op) - - 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 c94ee5a675f..403b99c8fd0 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -1297,19 +1297,6 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): return make_FiniteField_givaroElement(cache, cache.objectptr.one) return make_FiniteField_givaroElement(cache, r) - def __richcmp__(left, right, int op): - """ - EXAMPLES:: - - sage: k. = GF(9); k - Finite Field in a of size 3^2 - sage: a == k('a') # indirect doctest - True - sage: a == a + 1 - False - """ - return (left)._richcmp(right, op) - cpdef int _cmp_(left, Element right) except -2: """ Comparison of finite field elements is correct or equality diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index ba7b6991436..7c890f3ac2f 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -803,10 +803,16 @@ cdef class FiniteField_ntl_gf2eElement(FinitePolyExtElement): from sage.groups.generic import power return power(self,exp) - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, Element right) except -2: """ Comparison of finite field elements. + .. NOTE:: + + Finite fields are unordered. However, we adopt the convention that + an element ``e`` is bigger than element ``f`` if its polynomial + representation is bigger. + EXAMPLES:: sage: k. = GF(2^20) @@ -819,13 +825,7 @@ cdef class FiniteField_ntl_gf2eElement(FinitePolyExtElement): sage: e != (e + 1) True - .. NOTE:: - - Finite fields are unordered. However, we adopt the convention that - an element ``e`` is bigger than element ``f`` if its polynomial - representation is bigger. - - EXAMPLES:: + :: sage: K. = GF(2^100) sage: a < a^2 @@ -843,12 +843,6 @@ cdef class FiniteField_ntl_gf2eElement(FinitePolyExtElement): sage: a == a True """ - return (left)._richcmp(right, op) - - cpdef int _cmp_(left, Element right) except -2: - """ - Comparison of finite field elements. - """ (left._parent._cache).F.restore() c = GF2E_equal((left).x, (right).x) if c == 1: diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index 2ab45e245c5..2401a21b95a 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -388,31 +388,13 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): """ Comparison of finite field elements. - TESTS:: - - sage: k. = FiniteField(3^3, impl='pari_ffelt') - sage: a == 1 - False - sage: a^0 == 1 - True - sage: a == a - True - sage: a < a^2 - True - sage: a > a^2 - False - """ - cdef int r - pari_catch_sig_on() - r = cmp_universal(self.val, (other).val) - pari_catch_sig_off() - return r + .. NOTE:: - def __richcmp__(FiniteFieldElement_pari_ffelt left, object right, int op): - """ - Rich comparison of finite field elements. + Finite fields are unordered. However, for the purpose of + this function, we adopt the lexicographic ordering on the + representing polynomials. - EXAMPLE:: + EXAMPLES:: sage: k. = GF(2^20, impl='pari_ffelt') sage: e = k.random_element() @@ -424,13 +406,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): sage: e != (e + 1) True - .. NOTE:: - - Finite fields are unordered. However, for the purpose of - this function, we adopt the lexicographic ordering on the - representing polynomials. - - EXAMPLE:: + :: sage: K. = GF(2^100, impl='pari_ffelt') sage: a < a^2 @@ -447,8 +423,26 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): False sage: a == a True + + TESTS:: + + sage: k. = FiniteField(3^3, impl='pari_ffelt') + sage: a == 1 + False + sage: a^0 == 1 + True + sage: a == a + True + sage: a < a^2 + True + sage: a > a^2 + False """ - return (left)._richcmp(right, op) + cdef int r + pari_catch_sig_on() + r = cmp_universal(self.val, (other).val) + pari_catch_sig_off() + return r cpdef ModuleElement _add_(FiniteFieldElement_pari_ffelt self, ModuleElement right): """ diff --git a/src/sage/rings/finite_rings/hom_finite_field.pyx b/src/sage/rings/finite_rings/hom_finite_field.pyx index 04a45c10142..1ca9fd576c1 100644 --- a/src/sage/rings/finite_rings/hom_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field.pyx @@ -341,16 +341,10 @@ cdef class FiniteFieldHomomorphism_generic(RingHomomorphism_im_gens): """ return self._section_class(self) - - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - - def __hash__(self): return Morphism.__hash__(self) - cdef class FrobeniusEndomorphism_finite_field(FrobeniusEndomorphism_generic): """ A class implementing Frobenius endomorphisms on finite fields. @@ -670,11 +664,6 @@ cdef class FrobeniusEndomorphism_finite_field(FrobeniusEndomorphism_generic): """ return self.power() == 0 - - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - - def __hash__(self): return Morphism.__hash__(self) diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index efc5d11d33b..4b041bba56b 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -1838,10 +1838,6 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): else: return 1 - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - - cpdef bint is_one(IntegerMod_gmp self): """ Returns ``True`` if this is `1`, otherwise @@ -2252,10 +2248,6 @@ cdef class IntegerMod_int(IntegerMod_abstract): else: return 1 - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - - cpdef bint is_one(IntegerMod_int self): """ Returns ``True`` if this is `1`, otherwise @@ -3080,10 +3072,6 @@ cdef class IntegerMod_int64(IntegerMod_abstract): elif self.ivalue < (right).ivalue: return -1 else: return 1 - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - - cpdef bint is_one(IntegerMod_int64 self): """ Returns ``True`` if this is `1`, otherwise diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 391991b4329..f54ada8f8d5 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -869,9 +869,6 @@ cdef class LaurentSeries(AlgebraElement): return self.prec() return min(self.prec(), f.prec()) - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - 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 502c1ceb976..594cf9ff34e 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -1137,20 +1137,6 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): _slots['__im_gens'] = self.__im_gens return RingHomomorphism._extra_slots(self, _slots) - def __richcmp__(left, right, int op): - """ - Used internally by the cmp method. - - TESTS:: - - sage: R. = QQ[]; f = R.hom([x,x+y]); g = R.hom([y,x]) - sage: cmp(f,g) # indirect doctest - 1 - sage: cmp(g,f) - -1 - """ - return (left)._richcmp(right, op) - cpdef int _cmp_(self, Element other) except -2: r""" EXAMPLES: @@ -1175,6 +1161,14 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): sage: loads(dumps(f2)) == f2 True + :: + + sage: R. = QQ[]; f = R.hom([x,x+y]); g = R.hom([y,x]) + sage: cmp(f,g) # indirect doctest + 1 + sage: cmp(g,f) + -1 + EXAMPLES: A multivariate quotient over a finite field:: @@ -1441,22 +1435,6 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): _slots['__underlying'] = self.__underlying return RingHomomorphism._extra_slots(self, _slots) - def __richcmp__(left, right, int op): - """ - Used internally by the cmp method. - - TESTS:: - - sage: R. = QQ[]; f = R.hom([x,x+y]); g = R.hom([y,x]) - sage: S. = R[] - sage: fS = S.hom(f,S); gS = S.hom(g,S) - sage: cmp(fS,gS) # indirect doctest - 1 - sage: cmp(gS,fS) # indirect doctest - -1 - """ - return (left)._richcmp(right, op) - cpdef int _cmp_(self, Element other) except -2: r""" EXAMPLES: @@ -1480,6 +1458,16 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): sage: f1P == loads(dumps(f1P)) True + TESTS:: + + sage: R. = QQ[]; f = R.hom([x,x+y]); g = R.hom([y,x]) + sage: S. = R[] + sage: fS = S.hom(f,S); gS = S.hom(g,S) + sage: cmp(fS,gS) # indirect doctest + 1 + sage: cmp(gS,fS) # indirect doctest + -1 + EXAMPLES: A matrix ring over a multivariate quotient over a finite field:: @@ -2109,9 +2097,6 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): codomain = self.codomain() return hash((domain, codomain, ('Frob', self._power))) - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - cpdef int _cmp_(left, Element right) except -2: if left is right: return 0 domain = left.domain() diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 1e3d3306f14..030c8d4dda5 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -709,7 +709,7 @@ cdef class NumberFieldElement(FieldElement): raise IndexError, "index must be between 0 and degree minus 1." return self.polynomial()[n] - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, sage.structure.element.Element right) except -2: r""" EXAMPLE:: @@ -719,9 +719,6 @@ cdef class NumberFieldElement(FieldElement): sage: a + 1 < a # indirect doctest False """ - return (left)._richcmp(right, op) - - 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 223ed701c1b..1d8ebcf6c2e 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -658,22 +658,15 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): return test return -test - def __richcmp__(left, right, int op): + cpdef _richcmp_(left, Element _right, int op): r""" - Note: we may implement a more direct way of comparison for integer, - float and quadratic numbers input (ie avoiding coercion). + Rich comparison of elements. TESTS:: sage: K. = QuadraticField(-1) sage: sorted([5*i+1, 2, 3*i+1, 2-i]) [3*i + 1, 5*i + 1, -i + 2, 2] - """ - return (left)._richcmp(right, op) - - cpdef _richcmp_(left, Element _right, int op): - r""" - C implementation of comparison. TESTS: @@ -796,8 +789,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpz_clear(j) return rich_to_bool_sgn(op, test) - def __cmp__(left, right): - r""" + cpdef int _cmp_(left, Element _right) except -2: + """ Comparisons of elements. When there is a real embedding defined, the comparisons uses comparison @@ -869,12 +862,6 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: map(CDF, l) == sorted(map(CDF, l)) True """ - return (left)._cmp(right) - - cpdef int _cmp_(left, Element _right) except -2: - """ - C implementation of comparison. - """ cdef NumberFieldElement_quadratic right = _right cdef int test diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index e2b3c29cd68..9881351ef45 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -89,24 +89,6 @@ cdef class PowerSeries_poly(PowerSeries): """ return self.__class__, (self._parent, self.__f, self._prec, self.__is_gen) - def __richcmp__(left, right, int op): - """ - Used for comparing power series. - - EXAMPLES:: - - sage: R. = ZZ[[]] - sage: f = 1 + t + t^7 - 5*t^10 - sage: g = 1 + t + t^7 - 5*t^10 + O(t^15) - sage: f == f - True - sage: f < g - False - sage: f == g - True - """ - return (left)._richcmp(right, op) - def polynomial(self): """ Return the underlying polynomial of self. diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index ab3f67a20cf..ae25cd36fea 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -315,18 +315,6 @@ cdef class PowerSeries(AlgebraElement): S = self._parent.change_ring(R) return S(self) - def __cmp__(left, right): - """ - Called by comparison operations. - - EXAMPLES:: - - sage: R. = PowerSeriesRing(ZZ) - sage: 1+x^2 < 2-x - True - """ - return (left)._cmp(right) - cpdef int _cmp_(self, Element right) except -2: r""" Comparison of self and ``right``. @@ -358,9 +346,23 @@ cdef class PowerSeries(AlgebraElement): sage: 1 - 2*q + q^2 +O(q^3) == 1 - 2*q^2 + q^2 + O(q^4) False + :: + + sage: R. = ZZ[[]] + sage: 1 + t^2 < 2 - t + True + sage: f = 1 + t + t^7 - 5*t^10 + sage: g = 1 + t + t^7 - 5*t^10 + O(t^15) + sage: f == f + True + sage: f < g + False + sage: f == g + True + TESTS: - Ticket :trac:`9457` is fixed:: + :trac:`9457` is fixed:: sage: A. = PowerSeriesRing(ZZ) sage: g = t + t^3 + t^5 + O(t^6); g diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 63fa7fa0225..d1680334abe 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -709,9 +709,9 @@ cdef class Rational(sage.structure.element.FieldElement): l = self.continued_fraction_list() return ContinuedFraction_periodic(l) - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, sage.structure.element.Element right) except -2: """ - Rich comparison between two rational numbers. + Compare two rational numbers. INPUT: @@ -730,9 +730,6 @@ cdef class Rational(sage.structure.element.FieldElement): sage: 4/5 < 0.8 False """ - return (left)._richcmp(right, op) - - 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 f7ad8c92f67..7c7722dae9e 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1392,7 +1392,7 @@ cdef class RealBall(RingElement): """ return arb_is_exact(self.value) - def __richcmp__(left, right, int op): + cpdef _richcmp_(left, Element right, int op): """ Compare ``left`` and ``right``. @@ -1400,191 +1400,172 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: a = RBF(1) # optional - arb - sage: b = RBF(1) # optional - arb - sage: a is b # optional - arb - False - sage: a == b # optional - arb - True - sage: a = RBF(1/3) # optional - arb - sage: a.is_exact() # optional - arb - False - sage: b = RBF(1/3) # optional - arb - sage: b.is_exact() # optional - arb - False - sage: a == b # optional - arb - False - """ - return (left)._richcmp(right, op) + sage: from sage.rings.real_arb import RealBallField # optional - arb + sage: RBF = RealBallField() # optional - arb + sage: a = RBF(1) # optional - arb + sage: b = RBF(1) # optional - arb + sage: a is b # optional - arb + False + sage: a == b # optional - arb + True + sage: a = RBF(1/3) # optional - arb + sage: a.is_exact() # optional - arb + False + sage: b = RBF(1/3) # optional - arb + sage: b.is_exact() # optional - arb + False + sage: a == b # optional - arb + False - cpdef _richcmp_(left, Element right, int op): - """ - Compare ``left`` and ``right``. + TESTS: - For more information, see :mod:`sage.rings.real_arb`. + Balls whose intersection consists of one point:: - EXAMPLES:: + sage: a = RBF(RIF(1, 2)) # optional - arb + sage: b = RBF(RIF(2, 4)) # optional - arb + sage: a < b # optional - arb + False + sage: a > b # optional - arb + False + sage: a <= b # optional - arb + False + sage: a >= b # optional - arb + False + sage: a == b # optional - arb + False + sage: a != b # optional - arb + False - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: a = RBF(1) # optional - arb - sage: b = RBF(1) # optional - arb - sage: a is b # optional - arb - False - sage: a == b # optional - arb - True + Balls with non-trivial intersection:: - TESTS: + sage: a = RBF(RIF(1, 4)) # optional - arb + sage: a = RBF(RIF(2, 5)) # optional - arb + sage: a < b # optional - arb + False + sage: a <= b # optional - arb + False + sage: a > b # optional - arb + False + sage: a >= b # optional - arb + False + sage: a == b # optional - arb + False + sage: a != b # optional - arb + False - Balls whose intersection consists of one point:: - - sage: a = RBF(RIF(1, 2)) # optional - arb - sage: b = RBF(RIF(2, 4)) # optional - arb - sage: a < b # optional - arb - False - sage: a > b # optional - arb - False - sage: a <= b # optional - arb - False - sage: a >= b # optional - arb - False - sage: a == b # optional - arb - False - sage: a != b # optional - arb - False - - Balls with non-trivial intersection:: - - sage: a = RBF(RIF(1, 4)) # optional - arb - sage: a = RBF(RIF(2, 5)) # optional - arb - sage: a < b # optional - arb - False - sage: a <= b # optional - arb - False - sage: a > b # optional - arb - False - sage: a >= b # optional - arb - False - sage: a == b # optional - arb - False - sage: a != b # optional - arb - False - - One ball contained in another:: - - sage: a = RBF(RIF(1, 4)) # optional - arb - sage: b = RBF(RIF(2, 3)) # optional - arb - sage: a < b # optional - arb - False - sage: a <= b # optional - arb - False - sage: a > b # optional - arb - False - sage: a >= b # optional - arb - False - sage: a == b # optional - arb - False - sage: a != b # optional - arb - False - - Disjoint balls:: - - sage: a = RBF(1/3) # optional - arb - sage: b = RBF(1/2) # optional - arb - sage: a < b # optional - arb - True - sage: a <= b # optional - arb - True - sage: a > b # optional - arb - False - sage: a >= b # optional - arb - False - sage: a == b # optional - arb - False - sage: a != b # optional - arb - True - - Exact elements:: - - sage: a = RBF(2) # optional - arb - sage: b = RBF(2) # optional - arb - sage: a.is_exact() # optional - arb - True - sage: b.is_exact() # optional - arb - True - sage: a < b # optional - arb - False - sage: a <= b # optional - arb - True - sage: a > b # optional - arb - False - sage: a >= b # optional - arb - True - sage: a == b # optional - arb - True - sage: a != b # optional - arb - False - - Special values:: - - sage: inf = RBF(+infinity) # optional - arb - sage: other_inf = RBF(+infinity, 42.r) # optional - arb - sage: neg_inf = RBF(-infinity) # optional - arb - sage: extended_line = 1/RBF(0) # optional - arb - sage: exact_nan = inf - inf # optional - arb - sage: exact_nan.mid(), exact_nan.rad() # optional - arb - (NaN, 0.00000000) - sage: other_exact_nan = inf - inf # optional - arb - - :: - - sage: exact_nan == exact_nan, exact_nan <= exact_nan, exact_nan >= exact_nan # optional - arb - (False, False, False) - sage: exact_nan != exact_nan, exact_nan < exact_nan, exact_nan > exact_nan # optional - arb - (False, False, False) - sage: from operator import eq, ne, le, lt, ge, gt # optional - arb - sage: ops = [eq, ne, le, lt, ge, gt] # optional - arb - sage: any(op(exact_nan, other_exact_nan) for op in ops) # optional - arb - False - sage: any(op(exact_nan, b) for op in ops for b in [RBF(1), extended_line, inf, neg_inf]) # optional - arb - False - - :: - - sage: neg_inf < a < inf and inf > a > neg_inf # optional - arb - True - sage: neg_inf <= b <= inf and inf >= b >= neg_inf # optional - arb - True - sage: neg_inf <= extended_line <= inf and inf >= extended_line >= neg_inf # optional - arb - True - sage: neg_inf < extended_line or extended_line < inf # optional - arb - False - sage: inf > extended_line or extended_line > neg_inf # optional - arb - False - - :: - - sage: all(b <= b == b >= b and not (b < b or b != b or b > b) # optional - arb - ....: for b in [inf, neg_inf, other_inf]) - True - sage: any(b1 == b2 for b1 in [inf, neg_inf, a, extended_line] # optional - arb - ....: for b2 in [inf, neg_inf, a, extended_line] - ....: if not b1 is b2) - False - sage: all(b1 != b2 and not b1 == b2 # optional - arb - ....: for b1 in [inf, neg_inf, a] - ....: for b2 in [inf, neg_inf, a] - ....: if not b1 is b2) - True - sage: neg_inf <= -other_inf == neg_inf == -other_inf < other_inf == inf <= other_inf # optional - arb - True - sage: any(inf < b or b > inf # optional - arb - ....: for b in [inf, other_inf, a, extended_line]) - False - sage: any(inf <= b or b >= inf for b in [a, extended_line]) # optional - arb - False + One ball contained in another:: + + sage: a = RBF(RIF(1, 4)) # optional - arb + sage: b = RBF(RIF(2, 3)) # optional - arb + sage: a < b # optional - arb + False + sage: a <= b # optional - arb + False + sage: a > b # optional - arb + False + sage: a >= b # optional - arb + False + sage: a == b # optional - arb + False + sage: a != b # optional - arb + False + + Disjoint balls:: + + sage: a = RBF(1/3) # optional - arb + sage: b = RBF(1/2) # optional - arb + sage: a < b # optional - arb + True + sage: a <= b # optional - arb + True + sage: a > b # optional - arb + False + sage: a >= b # optional - arb + False + sage: a == b # optional - arb + False + sage: a != b # optional - arb + True + + Exact elements:: + + sage: a = RBF(2) # optional - arb + sage: b = RBF(2) # optional - arb + sage: a.is_exact() # optional - arb + True + sage: b.is_exact() # optional - arb + True + sage: a < b # optional - arb + False + sage: a <= b # optional - arb + True + sage: a > b # optional - arb + False + sage: a >= b # optional - arb + True + sage: a == b # optional - arb + True + sage: a != b # optional - arb + False + + Special values:: + + sage: inf = RBF(+infinity) # optional - arb + sage: other_inf = RBF(+infinity, 42.r) # optional - arb + sage: neg_inf = RBF(-infinity) # optional - arb + sage: extended_line = 1/RBF(0) # optional - arb + sage: exact_nan = inf - inf # optional - arb + sage: exact_nan.mid(), exact_nan.rad() # optional - arb + (NaN, 0.00000000) + sage: other_exact_nan = inf - inf # optional - arb + + :: + + sage: exact_nan == exact_nan, exact_nan <= exact_nan, exact_nan >= exact_nan # optional - arb + (False, False, False) + sage: exact_nan != exact_nan, exact_nan < exact_nan, exact_nan > exact_nan # optional - arb + (False, False, False) + sage: from operator import eq, ne, le, lt, ge, gt # optional - arb + sage: ops = [eq, ne, le, lt, ge, gt] # optional - arb + sage: any(op(exact_nan, other_exact_nan) for op in ops) # optional - arb + False + sage: any(op(exact_nan, b) for op in ops for b in [RBF(1), extended_line, inf, neg_inf]) # optional - arb + False + + :: + + sage: neg_inf < a < inf and inf > a > neg_inf # optional - arb + True + sage: neg_inf <= b <= inf and inf >= b >= neg_inf # optional - arb + True + sage: neg_inf <= extended_line <= inf and inf >= extended_line >= neg_inf # optional - arb + True + sage: neg_inf < extended_line or extended_line < inf # optional - arb + False + sage: inf > extended_line or extended_line > neg_inf # optional - arb + False + + :: + + sage: all(b <= b == b >= b and not (b < b or b != b or b > b) # optional - arb + ....: for b in [inf, neg_inf, other_inf]) + True + sage: any(b1 == b2 for b1 in [inf, neg_inf, a, extended_line] # optional - arb + ....: for b2 in [inf, neg_inf, a, extended_line] + ....: if not b1 is b2) + False + sage: all(b1 != b2 and not b1 == b2 # optional - arb + ....: for b1 in [inf, neg_inf, a] + ....: for b2 in [inf, neg_inf, a] + ....: if not b1 is b2) + True + sage: neg_inf <= -other_inf == neg_inf == -other_inf < other_inf == inf <= other_inf # optional - arb + True + sage: any(inf < b or b > inf # optional - arb + ....: for b in [inf, other_inf, a, extended_line]) + False + sage: any(inf <= b or b >= inf for b in [a, extended_line]) # optional - arb + False """ cdef RealBall lt, rt cdef arb_t difference diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index bfe6fe659f0..fce4acfed0d 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -668,6 +668,26 @@ cdef class LazyFieldElement(FieldElement): True sage: RLF(3) == RLF(4) False + sage: RLF(3) < RLF(5/3) + False + + TESTS:: + + sage: from sage.rings.real_lazy import LazyBinop + sage: RLF(3) < LazyBinop(RLF, 5, 3, operator.div) + False + sage: from sage.rings.real_lazy import LazyWrapper + sage: LazyWrapper(RLF, 3) < LazyWrapper(RLF, 5/3) + False + sage: from sage.rings.real_lazy import LazyUnop + sage: RLF(3) < LazyUnop(RLF, 2, sqrt) + False + sage: from sage.rings.real_lazy import LazyNamedUnop + sage: RLF(3) < LazyNamedUnop(RLF, 0, 'sin') + False + sage: from sage.rings.real_lazy import LazyConstant + sage: RLF(3) < LazyConstant(RLF, 'e') + False """ left = self try: @@ -679,17 +699,6 @@ cdef class LazyFieldElement(FieldElement): left, right = self.approx(), other.approx() return cmp(left, right) - def __richcmp__(left, right, int op): - """ - Perform a rich comparison between ``left`` and ``right``. - - EXAMPLES:: - - sage: RLF(3) < RLF(5/3) - False - """ - return (left)._richcmp(right, op) - def __hash__(self): """ Return the hash value of ``self``. @@ -993,18 +1002,6 @@ cdef class LazyWrapper(LazyFieldElement): """ return not not self._value - def __richcmp__(left, right, int op): - """ - Perform a rich comparison between ``left`` and ``right``. - - EXAMPLES:: - - sage: from sage.rings.real_lazy import LazyWrapper - sage: LazyWrapper(RLF, 3) < LazyWrapper(RLF, 5/3) - False - """ - return (left)._richcmp(right, op) - def __hash__(self): """ Return the hash value of ``self``. @@ -1176,18 +1173,6 @@ cdef class LazyBinop(LazyFieldElement): # We only do a call here because it is a python call. return self._op(left, right) - def __richcmp__(left, right, int op): - """ - Perform a rich comparison between ``left`` and ``right``. - - EXAMPLES:: - - sage: from sage.rings.real_lazy import LazyBinop - sage: RLF(3) < LazyBinop(RLF, 5, 3, operator.div) - False - """ - return (left)._richcmp(right, op) - def __hash__(self): """ Return the hash value of ``self``. @@ -1280,18 +1265,6 @@ cdef class LazyUnop(LazyFieldElement): return ~arg return self._op(self._arg.eval(R)) - def __richcmp__(left, right, int op): - """ - Perform a rich comparison between ``left`` and ``right``. - - EXAMPLES:: - - sage: from sage.rings.real_lazy import LazyUnop - sage: RLF(3) < LazyUnop(RLF, 2, sqrt) - False - """ - return (left)._richcmp(right, op) - def __hash__(self): """ Return the hash value of ``self``. @@ -1411,18 +1384,6 @@ cdef class LazyNamedUnop(LazyUnop): interval_field = self._parent.interval_field() return self.eval(interval_field._middle_field()) - def __richcmp__(left, right, int op): - """ - Perform a rich comparison between ``left`` and ``right``. - - EXAMPLES:: - - sage: from sage.rings.real_lazy import LazyNamedUnop - sage: RLF(3) < LazyNamedUnop(RLF, 0, 'sin') - False - """ - return (left)._richcmp(right, op) - def __hash__(self): """ Return the hash value of ``self``. @@ -1549,18 +1510,6 @@ cdef class LazyConstant(LazyFieldElement): self._extra_args = args return self - def __richcmp__(left, right, int op): - """ - Perform a rich comparison between ``left`` and ``right``. - - EXAMPLES:: - - sage: from sage.rings.real_lazy import LazyConstant - sage: RLF(3) < LazyConstant(RLF, 'e') - False - """ - return (left)._richcmp(right, op) - def __hash__(self): """ Return the hash value of ``self``. diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 85d3b750787..4da87d4c4bd 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -3445,11 +3445,10 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): """ return mpfi_nan_p(self.value) - def __richcmp__(left, right, int op): + cpdef _richcmp_(left, Element right, int op): """ - Rich comparison between ``left`` and ``right``. - - For more information, see :mod:`sage.rings.real_mpfi`. + Implements comparisons between intervals. (See the file header + comment for more information on interval comparison.) EXAMPLES:: @@ -3469,13 +3468,6 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): False sage: RIF(0, 2) > RIF(2, 3) False - """ - return (left)._richcmp(right, op) - - cpdef _richcmp_(left, Element right, int op): - """ - Implements comparisons between intervals. (See the file header - comment for more information on interval comparison.) EXAMPLES:: @@ -3666,7 +3658,7 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): """ return not (mpfr_zero_p(&self.value.left) and mpfr_zero_p(&self.value.right)) - def __cmp__(left, right): + cpdef int _cmp_(left, Element right) except -2: """ Compare two intervals lexicographically. @@ -3694,12 +3686,6 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): sage: cmp(RIF(0, 1), RIF(0, 1/2)) 1 """ - return (left)._cmp(right) - - cpdef int _cmp_(left, Element right) except -2: - """ - Implements the lexicographic total order on intervals. - """ cdef RealIntervalFieldElement lt, rt lt = left From d8c1302e2720ad02ca6f6d10b08c378c08532293 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 29 Sep 2015 11:33:55 +0200 Subject: [PATCH 1118/1872] Doctest fixes --- src/sage/combinat/crystals/alcove_path.py | 31 ++-- src/sage/graphs/generic_graph.py | 169 +++++++++--------- src/sage/matrix/matrix_cyclo_dense.pyx | 8 +- src/sage/matroids/linear_matroid.pyx | 2 +- .../hecke_triangle_group_element.py | 4 +- .../hecke_triangle_groups.py | 25 +-- src/sage/symbolic/expression.pyx | 6 +- 7 files changed, 122 insertions(+), 123 deletions(-) diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index b8cacdf58c2..444c251a16d 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -9,21 +9,17 @@ Special thanks to: Nicolas Borie, Anne Schilling, Travis Scrimshaw, and Nicolas Thiery. """ + #***************************************************************************** -# Copyright (C) 2008 Brant Jones -# Copyright (C) 2013 Arthur Lubovsky -# -# 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: +# Copyright (C) 2008 Brant Jones +# Copyright (C) 2013 Arthur Lubovsky # +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. # http://www.gnu.org/licenses/ -#**************************************************************************** +#***************************************************************************** from sage.structure.parent import Parent from sage.structure.element import Element @@ -674,9 +670,9 @@ def phi(self, i): sage: C = crystals.AlcovePaths(['A',2],[1,1]) sage: [c.phi(1) for c in C] - [1, 0, 2, 0, 1, 1, 0, 0] + [1, 0, 2, 1, 0, 1, 0, 0] sage: [c.phi(2) for c in C] - [1, 2, 0, 1, 0, 0, 1, 0] + [1, 2, 0, 0, 1, 0, 1, 0] """ highest_weight_crystal = self.parent()._highest_weight_crystal positions, gi = self._gi(i) @@ -698,9 +694,9 @@ def epsilon(self, i): sage: C = crystals.AlcovePaths(['A',2],[1,1]) sage: [c.epsilon(1) for c in C] - [0, 1, 0, 0, 1, 0, 2, 1] + [0, 1, 0, 1, 0, 0, 2, 1] sage: [c.epsilon(2) for c in C] - [0, 0, 1, 1, 0, 2, 0, 1] + [0, 0, 1, 0, 1, 2, 0, 1] """ #crude but functional j = 0 @@ -722,11 +718,10 @@ def weight(self): sage: for i in C: i.weight() 2*Lambda[1] Lambda[2] - Lambda[1] - Lambda[2] -2*Lambda[1] + 2*Lambda[2] + Lambda[1] - Lambda[2] -Lambda[1] -2*Lambda[2] - sage: B = crystals.AlcovePaths(['A',2,1],[1,0,0]) sage: p = B.module_generators[0].f_string([0,1,2]) sage: p.weight() diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 84938f5c7eb..5616179feef 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -14007,7 +14007,7 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, in the graph [OLJ14]_. In formulas, .. MATH:: - + c(v)=\frac{r(v)-1}{\sum_{w \in R(v)} d(v,w)}\frac{r(v)-1}{n-1} where `R(v)` is the set of vertices reachable from `v`, and @@ -14104,10 +14104,10 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, sage: D.show(figsize=[2,2]) sage: D.centrality_closeness() {0: 1.0, 1: 1.0, 2: 0.75, 3: 0.75} - + In a (strongly) connected (di)graph, the closeness centrality of `v` is inverse of the average distance between `v` and all other vertices:: - + sage: g = graphs.PathGraph(5) sage: g.centrality_closeness(0) 0.4 @@ -14120,9 +14120,9 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, sage: dist = d.shortest_path_lengths(0).values() sage: float(len(dist)-1) / sum(dist) 0.4 - + If a vertex has (out)degree 0, its closeness centrality is not defined:: - + sage: g = Graph(5) sage: g.centrality_closeness() {} @@ -18612,76 +18612,79 @@ def graphviz_string(self, **options): sage: print G.graphviz_string(labels="latex",edge_labels=True) digraph { node [shape="plaintext"]; - node_7 [label=" ", texlbl="$\frac{2}{3}$"]; - node_5 [label=" ", texlbl="$\frac{1}{3}$"]; + node_10 [label=" ", texlbl="$1$"]; + node_11 [label=" ", texlbl="$2$"]; + node_3 [label=" ", texlbl="$-\frac{1}{2}$"]; node_6 [label=" ", texlbl="$\frac{1}{2}$"]; - node_9 [label=" ", texlbl="$1$"]; + node_7 [label=" ", texlbl="$\frac{1}{2}$"]; + node_5 [label=" ", texlbl="$\frac{1}{3}$"]; + node_8 [label=" ", texlbl="$\frac{2}{3}$"]; node_4 [label=" ", texlbl="$\frac{1}{4}$"]; - node_8 [label=" ", texlbl="$\frac{4}{5}$"]; - node_0 [label=" ", texlbl="$-4$"]; - node_10 [label=" ", texlbl="$2$"]; node_1 [label=" ", texlbl="$-2$"]; - node_3 [label=" ", texlbl="$-\frac{1}{2}$"]; + node_9 [label=" ", texlbl="$\frac{4}{5}$"]; + node_0 [label=" ", texlbl="$-4$"]; node_2 [label=" ", texlbl="$-1$"]; - node_6 -> node_1 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"]; - node_6 -> node_7 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; - node_9 -> node_2 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"]; - node_9 -> node_6 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; + node_10 -> node_2 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"]; + node_10 -> node_6 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; + node_11 -> node_3 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"]; + node_11 -> node_5 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; + node_7 -> node_1 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"]; + node_7 -> node_8 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; node_4 -> node_0 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"]; - node_4 -> node_8 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; - node_10 -> node_3 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$"]; - node_10 -> node_5 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; + node_4 -> node_9 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; } sage: print G.graphviz_string(labels="latex",color_by_label=True) digraph { node [shape="plaintext"]; - node_7 [label=" ", texlbl="$\frac{2}{3}$"]; - node_5 [label=" ", texlbl="$\frac{1}{3}$"]; + node_10 [label=" ", texlbl="$1$"]; + node_11 [label=" ", texlbl="$2$"]; + node_3 [label=" ", texlbl="$-\frac{1}{2}$"]; node_6 [label=" ", texlbl="$\frac{1}{2}$"]; - node_9 [label=" ", texlbl="$1$"]; + node_7 [label=" ", texlbl="$\frac{1}{2}$"]; + node_5 [label=" ", texlbl="$\frac{1}{3}$"]; + node_8 [label=" ", texlbl="$\frac{2}{3}$"]; node_4 [label=" ", texlbl="$\frac{1}{4}$"]; - node_8 [label=" ", texlbl="$\frac{4}{5}$"]; - node_0 [label=" ", texlbl="$-4$"]; - node_10 [label=" ", texlbl="$2$"]; node_1 [label=" ", texlbl="$-2$"]; - node_3 [label=" ", texlbl="$-\frac{1}{2}$"]; + node_9 [label=" ", texlbl="$\frac{4}{5}$"]; + node_0 [label=" ", texlbl="$-4$"]; node_2 [label=" ", texlbl="$-1$"]; - node_6 -> node_1 [color = "#ff0000"]; - node_6 -> node_7 [color = "#00ffff"]; - node_9 -> node_2 [color = "#ff0000"]; - node_9 -> node_6 [color = "#00ffff"]; + node_10 -> node_2 [color = "#ff0000"]; + node_10 -> node_6 [color = "#00ffff"]; + node_11 -> node_3 [color = "#ff0000"]; + node_11 -> node_5 [color = "#00ffff"]; + node_7 -> node_1 [color = "#ff0000"]; + node_7 -> node_8 [color = "#00ffff"]; node_4 -> node_0 [color = "#ff0000"]; - node_4 -> node_8 [color = "#00ffff"]; - node_10 -> node_3 [color = "#ff0000"]; - node_10 -> node_5 [color = "#00ffff"]; + node_4 -> node_9 [color = "#00ffff"]; } sage: print G.graphviz_string(labels="latex",color_by_label={ f: "red", g: "blue" }) digraph { node [shape="plaintext"]; - node_7 [label=" ", texlbl="$\frac{2}{3}$"]; - node_5 [label=" ", texlbl="$\frac{1}{3}$"]; + node_10 [label=" ", texlbl="$1$"]; + node_11 [label=" ", texlbl="$2$"]; + node_3 [label=" ", texlbl="$-\frac{1}{2}$"]; node_6 [label=" ", texlbl="$\frac{1}{2}$"]; - node_9 [label=" ", texlbl="$1$"]; + node_7 [label=" ", texlbl="$\frac{1}{2}$"]; + node_5 [label=" ", texlbl="$\frac{1}{3}$"]; + node_8 [label=" ", texlbl="$\frac{2}{3}$"]; node_4 [label=" ", texlbl="$\frac{1}{4}$"]; - node_8 [label=" ", texlbl="$\frac{4}{5}$"]; - node_0 [label=" ", texlbl="$-4$"]; - node_10 [label=" ", texlbl="$2$"]; node_1 [label=" ", texlbl="$-2$"]; - node_3 [label=" ", texlbl="$-\frac{1}{2}$"]; + node_9 [label=" ", texlbl="$\frac{4}{5}$"]; + node_0 [label=" ", texlbl="$-4$"]; node_2 [label=" ", texlbl="$-1$"]; - node_6 -> node_1 [color = "red"]; - node_6 -> node_7 [color = "blue"]; - node_9 -> node_2 [color = "red"]; - node_9 -> node_6 [color = "blue"]; + node_10 -> node_2 [color = "red"]; + node_10 -> node_6 [color = "blue"]; + node_11 -> node_3 [color = "red"]; + node_11 -> node_5 [color = "blue"]; + node_7 -> node_1 [color = "red"]; + node_7 -> node_8 [color = "blue"]; node_4 -> node_0 [color = "red"]; - node_4 -> node_8 [color = "blue"]; - node_10 -> node_3 [color = "red"]; - node_10 -> node_5 [color = "blue"]; + node_4 -> node_9 [color = "blue"]; } By default ``graphviz`` renders digraphs using a hierarchical @@ -18734,60 +18737,62 @@ def graphviz_string(self, **options): ... return { "backward": u == 1 } sage: print G.graphviz_string(edge_options = edge_options) digraph { - node_7 [label="2/3"]; - node_5 [label="1/3"]; + node_10 [label="1"]; + node_11 [label="2"]; + node_3 [label="-1/2"]; node_6 [label="1/2"]; - node_9 [label="1"]; + node_7 [label="1/2"]; + node_5 [label="1/3"]; + node_8 [label="2/3"]; node_4 [label="1/4"]; - node_8 [label="4/5"]; - node_0 [label="-4"]; - node_10 [label="2"]; node_1 [label="-2"]; - node_3 [label="-1/2"]; + node_9 [label="4/5"]; + node_0 [label="-4"]; node_2 [label="-1"]; - node_6 -> node_1; - node_6 -> node_7; - node_2 -> node_9 [dir=back]; - node_6 -> node_9 [dir=back]; + node_2 -> node_10 [dir=back]; + node_6 -> node_10 [dir=back]; + node_11 -> node_3; + node_11 -> node_5; + node_7 -> node_1; + node_7 -> node_8; node_4 -> node_0; - node_4 -> node_8; - node_10 -> node_3; - node_10 -> node_5; + node_4 -> node_9; } We now test all options:: sage: def edge_options((u,v,label)): - ... options = { "color": { f: "red", g: "blue" }[label] } - ... if (u,v) == (1/2, -2): options["label"] = "coucou"; options["label_style"] = "string" - ... if (u,v) == (1/2,2/3): options["dot"] = "x=1,y=2" - ... if (u,v) == (1, -1): options["label_style"] = "latex" - ... if (u,v) == (1, 1/2): options["edge_string"] = "<-" - ... if (u,v) == (1/2, 1): options["backward"] = True - ... return options + ....: options = { "color": { f: "red", g: "blue" }[label] } + ....: if (u,v) == (1/2, -2): options["label"] = "coucou"; options["label_style"] = "string" + ....: if (u,v) == (1/2,2/3): options["dot"] = "x=1,y=2" + ....: if (u,v) == (1, -1): options["label_style"] = "latex" + ....: if (u,v) == (1, 1/2): options["edge_string"] = "<-" + ....: if (u,v) == (1/2, 1): options["backward"] = True + ....: return options sage: print G.graphviz_string(edge_options = edge_options) digraph { - node_7 [label="2/3"]; - node_5 [label="1/3"]; + node_10 [label="1"]; + node_11 [label="2"]; + node_3 [label="-1/2"]; node_6 [label="1/2"]; - node_9 [label="1"]; + node_7 [label="1/2"]; + node_5 [label="1/3"]; + node_8 [label="2/3"]; node_4 [label="1/4"]; - node_8 [label="4/5"]; - node_0 [label="-4"]; - node_10 [label="2"]; node_1 [label="-2"]; - node_3 [label="-1/2"]; + node_9 [label="4/5"]; + node_0 [label="-4"]; node_2 [label="-1"]; - node_6 -> node_1 [label="coucou", color = "red"]; - node_6 -> node_7 [x=1,y=2, color = "blue"]; - node_9 -> node_2 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$", color = "red"]; - node_9 <- node_6 [color = "blue"]; + node_10 -> node_2 [label=" ", texlbl="$x \ {\mapsto}\ -\frac{1}{x}$", color = "red"]; + node_10 <- node_6 [color = "blue"]; + node_11 -> node_3 [color = "red"]; + node_11 -> node_5 [color = "blue"]; + node_7 -> node_1 [label="coucou", color = "red"]; + node_7 -> node_8 [x=1,y=2, color = "blue"]; node_4 -> node_0 [color = "red"]; - node_4 -> node_8 [color = "blue"]; - node_10 -> node_3 [color = "red"]; - node_10 -> node_5 [color = "blue"]; + node_4 -> node_9 [color = "blue"]; } TESTS: diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index b92fc8eca7c..8f339fd272b 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -683,8 +683,8 @@ cdef class Matrix_cyclo_dense(matrix_dense.Matrix_dense): Yes, this works:: - sage: hash(A) - -25 + sage: hash(A) # random + 3107179158321342168 """ return self._matrix._hash() @@ -702,8 +702,8 @@ cdef class Matrix_cyclo_dense(matrix_dense.Matrix_dense): ... TypeError: mutable matrices are unhashable sage: A.set_immutable() - sage: A.__hash__() - -18 + sage: A.__hash__() # random + 2347601038649299176 """ if self._is_immutable: return self._hash() diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 70be4f2c5b2..fea578452b3 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -2422,7 +2422,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): ....: reduced_matrix=[[-1, -1, 0], [1, 0, -1], [0, 1, 1]]) sage: N.linear_coextension_cochains(F=[0, 1], cosimple=True, ....: fundamentals=set([1, -1, 1/2, 2])) - [{0: 2, 1: 1}, {0: 1/2, 1: 1}, {0: -1, 1: 1}] + [{0: 2, 1: 1}, {0: -1, 1: 1}, {0: 1/2, 1: 1}] """ return self.dual().linear_extension_chains(F=F, simple=cosimple, fundamentals=fundamentals) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index 135ad6032ed..4ecd5b9c911 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -2018,7 +2018,7 @@ def simple_fixed_point_set(self, extended=True): sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6) sage: el.simple_fixed_point_set() - {(-lam + 3/2)*e + 1/2*lam - 1, 1/2*e + 1/2*lam, 1/2*e - 1/2*lam, (-lam + 3/2)*e - 1/2*lam + 1} + {(-lam + 3/2)*e - 1/2*lam + 1, 1/2*e + 1/2*lam, (-lam + 3/2)*e + 1/2*lam - 1, 1/2*e - 1/2*lam} sage: el.simple_fixed_point_set(extended=False) {1/2*e + 1/2*lam, 1/2*e - 1/2*lam} """ @@ -2517,7 +2517,7 @@ def is_hecke_symmetric(self): sage: el.is_hecke_symmetric() True sage: el.simple_fixed_point_set() - {(lam - 3/2)*e + 1/2*lam - 1, (lam - 3/2)*e - 1/2*lam + 1, (-lam + 3/2)*e - 1/2*lam + 1, (-lam + 3/2)*e + 1/2*lam - 1} + {(lam - 3/2)*e + 1/2*lam - 1, (-lam + 3/2)*e + 1/2*lam - 1, (lam - 3/2)*e - 1/2*lam + 1, (-lam + 3/2)*e - 1/2*lam + 1} sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set() True """ diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index 0a2b54c0a6d..64c3e1520c1 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -933,25 +933,26 @@ def _conjugacy_representatives(self, max_block_length=ZZ(0), D=None): sage: list(G._conj_block[2]) [((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, 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)]] + sage: [key for key in sorted(G._conj_prim)] + [-4, lam - 3, 0, 4*lam, 7*lam + 6, 9*lam + 5, 15*lam + 6, 33*lam + 21] + sage: for key in sorted(G._conj_prim): + ....: print G._conj_prim[key] + [[S], [S]] [[U], [U]] - [[V(1)*V(3)], [V(2)*V(4)]] - [[V(1)*V(4)]] + [[V(4)]] [[V(3)], [V(2)]] + [[V(1)*V(4)]] [[V(3)*V(4)], [V(1)*V(2)]] + [[V(1)*V(3)], [V(2)*V(4)]] [[V(2)*V(3)]] - [[S], [S]] - sage: [key for key in G._conj_nonprim] - [lam - 3, 32*lam + 16, -lam - 2] + sage: [key for key in sorted(G._conj_nonprim)] + [-lam - 2, lam - 3, 32*lam + 16] - sage: for key in G._conj_nonprim: print G._conj_nonprim[key] + sage: for key in sorted(G._conj_nonprim): + ....: print G._conj_nonprim[key] + [[U^(-2)], [U^2], [U^(-2)], [U^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") """ diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 3809dc83610..fd90f429bb9 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1441,10 +1441,8 @@ cdef class Expression(CommutativeRingElement): sage: hash(SR(3/1)) 3 - sage: hash(SR(19/23)) - 4 - sage: hash(19/23) - 4 + sage: hash(SR(19/23)) == hash(19/23) # known bug #19310 + True The hash for symbolic expressions are unfortunately random. Here we only test that the hash() function returns without error, and that From 8607575987fcf949da47d2d6aff5297db3bb1c30 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 29 Sep 2015 12:16:41 +0200 Subject: [PATCH 1119/1872] trac #19309: Polhill strongly regular graphs --- src/sage/graphs/strongly_regular_db.pyx | 167 +++++++++++++++++++++++- 1 file changed, 164 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index cfefb513375..583facb022b 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -471,7 +471,7 @@ def is_NO_F2(int v,int k,int l,int mu): For more information, see :func:`sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph` - and + and INPUT: @@ -522,7 +522,7 @@ def is_NO_F3(int v,int k,int l,int mu): For more information, see :func:`sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph` - and + and INPUT: @@ -637,6 +637,166 @@ def is_NU(int v,int k,int l,int mu): from sage.graphs.generators.classical_geometries import NonisotropicUnitaryPolarGraph return (NonisotropicUnitaryPolarGraph, n, q) +@cached_function +def is_polhill(int v,int k,int l,int mu): + r""" + Test whether some graph from [Polhill09]_ is `(1024,k,\lambda,\mu)`-strongly regular. + + .. NOTE:: + + This function does not actually explore *all* strongly regular graphs + produced in [Polhill09]_, but only those on 1024 vertices. + + INPUT: + + - ``v,k,l,mu`` (integers) + + OUTPUT: + + A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if the + parameters match, and ``None`` otherwise. + + EXAMPLES:: + + sage: from sage.graphs.strongly_regular_db import is_polhill + sage: t = is_polhill(1024, 231, 38, 56); t + [. at ...>] + sage: g = t[0](*t[1:]); g # not tested (too long) + [. at ...>] + sage: g.is_strongly_regular(parameters=True) # not tested (too long) + (28, 15, 6, 10) + sage: t = is_polhill(1024, 264, 56, 72); t + [. at ...>] + sage: t = is_polhill(1024, 297, 76, 90); t + [. at ...>] + sage: t = is_polhill(1024, 330, 98, 110); t + [. at ...>] + sage: t = is_polhill(1024, 462, 206, 210); t + [. at ...>] + + REFERENCE: + + .. [Polhill09] J. Polhill, + Negative Latin square type partial difference sets and + amorphic association schemes with Galois rings, + Journal of Combinatorial Designs 17, no. 3 (2009): 266-282. + http://onlinelibrary.wiley.com/doi/10.1002/jcd.20206/abstract + """ + if (v,k,l,mu) not in [(1024, 231, 38, 56), + (1024, 264, 56, 72), + (1024, 297, 76, 90), + (1024, 330, 98, 110), + (1024, 462, 206, 210)]: + return + + from itertools import product + from sage.categories.cartesian_product import cartesian_product + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing + from copy import copy + + def additive_cayley(vertices): + g = Graph() + g.add_vertices(vertices[0].parent()) + edges = [(x,x+vv) + for vv in set(vertices) + for x in g] + g.add_edges(edges) + g.relabel() + return g + + # D is a Partial Difference Set of (Z4)^2, see section 2. + G = cartesian_product([IntegerModRing(4),IntegerModRing(4)]) + D = [ + [(2,0),(0,1),(0,3),(1,1),(3,3)], + [(1,0),(3,0),(0,2),(1,3),(3,1)], + [(1,2),(3,2),(2,1),(2,3),(2,2)] + ] + D = [map(G,x) for x in D] + + # The K_i are hyperplanes partitionning the nonzero elements of + # GF(2^s)^2. See section 6. + s = 3 + G1 = GF(2**s,'x') + Gp = cartesian_product([G1,G1]) + K = [Gp((x,1)) for x in G1]+[Gp((1,0))] + K = [[x for x in Gp if x[0]*uu+x[1]*vv == 0] for (uu,vv) in K] + + # We now define the P_{i,j}. see section 6. + + P = {} + P[0,1] = range((-1) + 1 , 2**(s-2)+1) + P[1,1] = range((-1) + 2**(s-2)+2 , 2**(s-1)+1) + P[2,1] = range((-1) + 2**(s-1)+2 , 2**(s-1)+2**(s-2)+1) + P[3,1] = range((-1) + 2**(s-1)+2**(s-2)+2, 2**(s)+1) + + P[0,2] = range((-1) + 2**(s-2)+2 , 2**(s-1)+2) + P[1,2] = range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+2) + P[2,2] = range((-1) + 2**(s-1)+2**(s-2)+3, 2**(s)+1) + [0] + P[3,2] = range((-1) + 2 , 2**(s-2)+1) + + P[0,3] = range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+3) + P[1,3] = range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1) + [0,1] + P[2,3] = range((-1) + 3 , 2**(s-2)+2) + P[3,3] = range((-1) + 2**(s-2)+3 , 2**(s-1)+2) + + P[0,4] = range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1) + P[1,4] = range((-1) + 3 , 2**(s-2)+1) + [2**(s-1)+1,2**(s-1)+2**(s-2)+2] + P[2,4] = range((-1) + 2**(s-2)+3 , 2**(s-1)+1) + [2**(s-1)+2**(s-2)+1,1] + P[3,4] = range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+1) + [2**(s-2)+1,0] + + R = {x:copy(P[x]) for x in P} + + for x in P: + P[x] = [K[i] for i in P[x]] + P[x] = set(sum(P[x],[])).difference([Gp((0,0))]) + + P[1,4].add(Gp((0,0))) + P[2,4].add(Gp((0,0))) + P[3,4].add(Gp((0,0))) + + # We now define the R_{i,j}. see *end* of section 6. + + R[0,3] = range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+2) + R[1,3] = range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1) + [0,1,2**(s-1)+2**(s-2)+2] + R[0,4] = range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1) + [2**(s-1)+2**(s-2)+2] + R[1,4] = range((-1) + 3 , 2**(s-2)+1) + [2**(s-1)+1] + + for x in R: + R[x] = [K[i] for i in R[x]] + R[x] = set(sum(R[x],[])).difference([Gp((0,0))]) + + R[1,3].add(Gp((0,0))) + R[2,4].add(Gp((0,0))) + R[3,4].add(Gp((0,0))) + + # Dabcd = Da, Db, Dc, Dd (cf. p273) + # D1234 = D1, D2, D3, D4 (cf. p276) + Dabcd = [] + D1234 = [] + + Gprod = cartesian_product([G,Gp]) + for DD,PQ in [(Dabcd,P), (D1234,R)]: + for i in range(1,5): + Dtmp = [product([G.zero()],PQ[0,i]), + product(D[0],PQ[1,i]), + product(D[1],PQ[2,i]), + product(D[2],PQ[3,i])] + Dtmp = map(set,Dtmp) + Dtmp = map(Gprod,sum(map(list,Dtmp),[])) + DD.append(Dtmp) + + # Now that we have the data, we can return the graphs. + if k == 231: + return [lambda :additive_cayley(Dabcd[0])] + if k == 264: + return [lambda :additive_cayley(D1234[2])] + if k == 297: + return [lambda :additive_cayley(D1234[0]+D1234[1]+D1234[2]).complement()] + if k == 330: + return [lambda :additive_cayley(Dabcd[0]+Dabcd[1]+Dabcd[2]).complement()] + if k == 462: + return [lambda :additive_cayley(Dabcd[0]+Dabcd[1])] + def is_RSHCD(int v,int k,int l,int mu): r""" Test whether some RSHCD graph is `(v,k,\lambda,\mu)`-strongly regular. @@ -2300,7 +2460,8 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint is_unitary_dual_polar, is_RSHCD, is_twograph_descendant_of_srg, - is_taylor_twograph_srg] + is_taylor_twograph_srg, + is_polhill] # Going through all test functions, for the set of parameters and its # complement. From bd93e375088c447f0f709dbc888b23ac99c5b805 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 12:26:49 +0200 Subject: [PATCH 1120/1872] fix doctests --- src/sage/rings/asymptotic/growth_group.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 83e92741c90..5f665d920f6 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -111,7 +111,7 @@ sage: G.an_element() (1/2)^x * x * log(x)^(1/2) * y^(1/2) sage: x, y = var('x y') - sage: sage: G(2^x * log(x) * y^(1/2)) * G(x^(-5) * 5^x * y^(1/3)) + sage: G(2^x * log(x) * y^(1/2)) * G(x^(-5) * 5^x * y^(1/3)) 10^x * x^(-5) * log(x) * y^(5/6) Classes and Methods @@ -979,7 +979,7 @@ def __init__(self, base, var, category=None): sage: agg.MonomialGrowthGroup('x', ZZ) Traceback (most recent call last): ... - ValueError: 'Integer Ring' is not a valid name for a variable. + TypeError: x is not a valid base sage: agg.MonomialGrowthGroup('x', 'y') Traceback (most recent call last): ... @@ -990,7 +990,7 @@ def __init__(self, base, var, category=None): sage: agg.ExponentialGrowthGroup('x', ZZ) Traceback (most recent call last): ... - ValueError: 'Integer Ring' is not a valid name for a variable. + TypeError: x is not a valid base sage: agg.ExponentialGrowthGroup('x', 'y') Traceback (most recent call last): ... From 7ec7e7d6c4c1272303e157d6721ace98580cc38f Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 13:15:18 +0200 Subject: [PATCH 1121/1872] fix indentation of one block --- src/sage/rings/asymptotic/growth_group.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 5f665d920f6..00761010e32 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -61,11 +61,11 @@ This also enables us to construct *logarithmic growth groups*, e.g. ``log(x)^ZZ``. - Exponential growth groups, i.e. growth groups representing - elements of the form `\operatorname{base}^\operatorname{variable}` - are denoted as ``base^variable``. For example, ``QQ^x`` denotes - the multiplicative group of exponential expressions `q^x`, where - `q \in \mathbb{Q}^{\times}`. +Exponential growth groups, i.e. growth groups representing +elements of the form `\operatorname{base}^{\operatorname{variable}}` +are denoted as ``base^variable``. For example, ``QQ^x`` denotes +the multiplicative group of exponential expressions `q^x`, where +`q \in \mathbb{Q}^{\times}`. EXAMPLES:: From e56459a5a4027406d40e56428a6fb16b520e7f6b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 13:15:27 +0200 Subject: [PATCH 1122/1872] : --> :: --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 00761010e32..3679f5ad586 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2018,7 +2018,7 @@ def base(self): r""" The base of this exponential growth element. - EXAMPLES: + EXAMPLES:: sage: import sage.rings.asymptotic.growth_group as agg sage: P = agg.GrowthGroup('ZZ^x') From 538e1e46de7713b869072fa7f998ee8a6d9ebc09 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 15:46:42 +0200 Subject: [PATCH 1123/1872] doctest for simplify-keyword --- src/sage/rings/asymptotic/asymptotic_ring.py | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0704892d23a..d0e8e886157 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -325,6 +325,53 @@ def __init__(self, parent, summands, simplify=True): sage: ex2 = x + O(R_x(1)) sage: ex1 * ex2 5*x^6 + O(x^5) + + :: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: OT = TermMonoid('O', G); ET = TermMonoid('exact', G, ZZ) + sage: R = AsymptoticRing(G, ZZ) + sage: lst = [ET(x, 1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] + sage: expr = R(lst, simplify=False); expr # indirect doctest + 4*x^4 + O(x^3) + 2*x^2 + x + sage: print expr.summands.repr_full() + poset(x, 2*x^2, O(x^3), 4*x^4) + +-- null + | +-- no predecessors + | +-- successors: x + +-- x + | +-- predecessors: null + | +-- successors: 2*x^2 + +-- 2*x^2 + | +-- predecessors: x + | +-- successors: O(x^3) + +-- O(x^3) + | +-- predecessors: 2*x^2 + | +-- successors: 4*x^4 + +-- 4*x^4 + | +-- predecessors: O(x^3) + | +-- successors: oo + +-- oo + | +-- predecessors: 4*x^4 + | +-- no successors + sage: expr._simplify_(); expr + 4*x^4 + O(x^3) + sage: print expr.summands.repr_full() + poset(O(x^3), 4*x^4) + +-- null + | +-- no predecessors + | +-- successors: O(x^3) + +-- O(x^3) + | +-- predecessors: null + | +-- successors: 4*x^4 + +-- 4*x^4 + | +-- predecessors: O(x^3) + | +-- successors: oo + +-- oo + | +-- predecessors: 4*x^4 + | +-- no successors """ super(AsymptoticExpression, self).__init__(parent=parent) From e98964b777730f729b50aefd0ec2beca8cc67f22 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 15:46:56 +0200 Subject: [PATCH 1124/1872] remove superfluous doctest --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d0e8e886157..bc3f2359e25 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -799,13 +799,6 @@ class AsymptoticRing(Ring, UniqueRepresentation): sage: R1_x.has_coerce_map_from(QQ) True - - TESTS:: - - sage: R3_x = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R3_x - Asymptotic Ring over Rational Field - sage: R1_x is R2_x is R3_x - True """ # enable the category framework for elements Element = AsymptoticExpression From 5cf2a31a3bd9784cfc101313ac71feb11b48f5e1 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 15:47:23 +0200 Subject: [PATCH 1125/1872] doctests for AsymptoticRing.__init__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index bc3f2359e25..33f0fa19174 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -867,6 +867,28 @@ def __init__(self, growth_group, coefficient_ring, category=None): Traceback (most recent call last): ... TypeError: __classcall__() takes at least 3 arguments (2 given) + + :: + + sage: AsymptoticRing(growth_group=None, coefficient_ring=ZZ) + Traceback (most recent call last): + ... + ValueError: Growth group not specified. Cannot continue. + sage: AsymptoticRing(growth_group='x^ZZ', coefficient_ring=None) + Traceback (most recent call last): + ... + ValueError: Coefficient ring not specified. Cannot continue. + sage: AsymptoticRing(growth_group='x^ZZ', coefficient_ring='icecream') + Traceback (most recent call last): + ... + ValueError: icecream is not a ring. Cannot continue. + + :: + + sage: AsymptoticRing('x^ZZ', QQ, category=Posets()) + Traceback (most recent call last): + ... + ValueError: (Category of posets,) is not a subcategory of Category of rings """ from sage.categories.rings import Rings From dc00f9545788d7ccfd36b5c0df915dcd9e27360b Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 15:47:41 +0200 Subject: [PATCH 1126/1872] improve documentation of _element_constructor_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 33f0fa19174..6c841146136 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -993,6 +993,12 @@ def _element_constructor_(self, data, summands=None, simplify=True): An element of this asymptotic ring. + .. NOTE:: + + Either ``data`` or ``summands`` has to be given. If + ``summands`` is specified, then no positional argument + may be passed (except for `int(0)`). + TESTS:: sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) From abb08ff241086ac0faee88969a4d6f190244de7f Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 15:48:02 +0200 Subject: [PATCH 1127/1872] improve _element_constructor_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 6c841146136..64c4ee9c96e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1014,10 +1014,17 @@ def _element_constructor_(self, data, summands=None, simplify=True): Traceback (most recent call last): ... TypeError: Cannot convert y to an asymptotic expression. + + :: + + sage: AR(1234, summands=6789) + Traceback (most recent call last): + ... + ValueError: Input is ambiguous: 1234 as well as summands=6789 are specified. """ if summands is not None: if type(data) != int or data != 0: - raise ValueError('Input is ambigous: ' + raise ValueError('Input is ambiguous: ' '%s as well as summands=%s ' 'are specified.' % (data, summands)) return self.element_class(self, summands, simplify=simplify) From c3d64c2bde1bf8a5c64c9d433e1d94004b8250ef Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 29 Sep 2015 16:45:27 +0200 Subject: [PATCH 1128/1872] Doctest fixes for 32 bits --- src/sage/functions/other.py | 5 +++-- src/sage/graphs/generic_graph.py | 12 ++++++------ src/sage/rings/rational.pyx | 3 ++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 1dbe2c36b01..5cf096613c6 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1709,8 +1709,9 @@ def __init__(self): Note that the order of arguments does not matter:: - sage: beta(1/2,3*x) - beta(1/2, 3*x) + sage: beta(1/2, 3*x) + beta(3*x, 1/2) # 32-bit + beta(1/2, 3*x) # 64-bit The result is symbolic if exact input is given:: diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 5616179feef..0d4e8026454 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -18609,7 +18609,7 @@ def graphviz_string(self, **options): sage: G = DiGraph() sage: G.add_edges([(i,f(i),f) for i in (1,2,1/2,1/4)]) sage: G.add_edges([(i,g(i),g) for i in (1,2,1/2,1/4)]) - sage: print G.graphviz_string(labels="latex",edge_labels=True) + sage: print G.graphviz_string(labels="latex",edge_labels=True) # random digraph { node [shape="plaintext"]; node_10 [label=" ", texlbl="$1$"]; @@ -18635,7 +18635,7 @@ def graphviz_string(self, **options): node_4 -> node_9 [label=" ", texlbl="$x \ {\mapsto}\ \frac{1}{x + 1}$"]; } - sage: print G.graphviz_string(labels="latex",color_by_label=True) + sage: print G.graphviz_string(labels="latex",color_by_label=True) # random digraph { node [shape="plaintext"]; node_10 [label=" ", texlbl="$1$"]; @@ -18661,7 +18661,7 @@ def graphviz_string(self, **options): node_4 -> node_9 [color = "#00ffff"]; } - sage: print G.graphviz_string(labels="latex",color_by_label={ f: "red", g: "blue" }) + sage: print G.graphviz_string(labels="latex",color_by_label={ f: "red", g: "blue" }) # random digraph { node [shape="plaintext"]; node_10 [label=" ", texlbl="$1$"]; @@ -18734,8 +18734,8 @@ def graphviz_string(self, **options): going backward (e.g. going up instead of down):: sage: def edge_options((u,v,label)): - ... return { "backward": u == 1 } - sage: print G.graphviz_string(edge_options = edge_options) + ....: return { "backward": u == 1 } + sage: print G.graphviz_string(edge_options = edge_options) # random digraph { node_10 [label="1"]; node_11 [label="2"]; @@ -18770,7 +18770,7 @@ def graphviz_string(self, **options): ....: if (u,v) == (1, 1/2): options["edge_string"] = "<-" ....: if (u,v) == (1/2, 1): options["backward"] = True ....: return options - sage: print G.graphviz_string(edge_options = edge_options) + sage: print G.graphviz_string(edge_options = edge_options) # random digraph { node_10 [label="1"]; node_11 [label="2"]; diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 90b00709559..5378f5870e8 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -2022,7 +2022,8 @@ cdef class Rational(sage.structure.element.FieldElement): sage: QQ(42).__hash__() 42 sage: QQ(1/42).__hash__() - -7658195599476688946 + 1488680910 # 32-bit + -7658195599476688946 # 64-bit sage: n = ZZ.random_element(10^100) sage: hash(n) == hash(QQ(n)) or n True From 78b9e96eefc3c64573d4adc6271bdbd730b14d10 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Tue, 29 Sep 2015 16:47:16 +0200 Subject: [PATCH 1129/1872] Trac #17716: additional doctest --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 64c4ee9c96e..dc6b94ae5e4 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -372,6 +372,8 @@ def __init__(self, parent, summands, simplify=True): +-- oo | +-- predecessors: 4*x^4 | +-- no successors + sage: R(lst, simplify=True) # indirect doctest + 4*x^4 + O(x^3) """ super(AsymptoticExpression, self).__init__(parent=parent) From 055e35bf7632c403be96371ce4f56f128534a307 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Tue, 29 Sep 2015 16:47:34 +0200 Subject: [PATCH 1130/1872] Trac #17716: Fix ReSt error --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index dc6b94ae5e4..a770c31ccfb 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -999,7 +999,7 @@ def _element_constructor_(self, data, summands=None, simplify=True): Either ``data`` or ``summands`` has to be given. If ``summands`` is specified, then no positional argument - may be passed (except for `int(0)`). + may be passed (except for ``int(0)``). TESTS:: From 83d60c416226061858eb17f1792345639078ff87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 29 Sep 2015 17:04:07 +0200 Subject: [PATCH 1131/1872] trac #17946 fixing two typoes --- src/sage/geometry/hyperplane_arrangement/arrangement.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 9b658fb1d46..0b0f2ed3f47 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -1934,11 +1934,11 @@ def varchenko_matrix(self, names='h'): @cached_method def matroid(self): r""" - Return the matroid assoicated to ``self``. + Return the matroid associated to ``self``. Let `A` denote a central hyperplane arrangement and `n_H` the normal vector of some hyperplane `H \in A`. We define a matroid - `M_A` as the linear matoid spanned by `\{ n_H | H \in A \}`. + `M_A` as the linear matroid spanned by `\{ n_H | H \in A \}`. The matroid `M_A` is such that the lattice of flats of `M` is isomorphic to the intersection lattice of `A` (Proposition 3.6 in [RS]_). From 7c54c8a9a3e8a04f1bd2e6531550adb995ac4442 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 29 Sep 2015 11:14:59 -0500 Subject: [PATCH 1132/1872] Added axiom for Complete and made manifolds a category over a base ring. --- src/sage/categories/category_with_axiom.py | 1 + src/sage/categories/manifolds.py | 128 ++++++++++++--------- src/sage/categories/metric_spaces.py | 26 +++++ src/sage/categories/sets_cat.py | 5 +- 4 files changed, 106 insertions(+), 54 deletions(-) diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 98869bcd5e3..5ad5572945d 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1677,6 +1677,7 @@ class ``Sets.Finite``), or in a separate file (typically in a class "Differentiable", "Smooth", "Analytic", "AlmostComplex", "Real", "FinitelyGeneratedAsMagma", "Facade", "Finite", "Infinite", + "Complete", "FiniteDimensional", "Connected", "WithBasis", "Irreducible", "Commutative", "Associative", "Inverse", "Unital", "Division", "NoZeroDivisors", diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index 83e7a4ec363..884e9cb8ef6 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -12,13 +12,12 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import LazyImport -from sage.categories.category import Category -from sage.categories.category_singleton import Category_singleton -from sage.categories.category_with_axiom import CategoryWithAxiom +from sage.categories.category_types import Category_over_base_ring +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.sets_cat import Sets from sage.categories.fields import Fields -class Manifolds(Category_singleton): +class Manifolds(Category_over_base_ring): r""" The category of manifolds over any field. @@ -29,8 +28,8 @@ class Manifolds(Category_singleton): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds(); C - Category of manifolds + sage: C = Manifolds(RR); C + Category of manifolds over Real Field with 53 bits of precision sage: C.super_categories() [Category of topological spaces] @@ -38,13 +37,27 @@ class Manifolds(Category_singleton): sage: TestSuite(C).run() """ + def __init__(self, base, name=None): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds(RR) + sage: TestSuite(C).run() + """ + if base not in Fields().Topological(): + raise ValueError("base must be a topological field") + Category_over_base_ring.__init__(self, base, name) + @cached_method def super_categories(self): """ EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().super_categories() + sage: Manifolds(RR).super_categories() [Category of topological spaces] """ return [Sets().Topological()] @@ -62,7 +75,7 @@ def additional_structure(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().additional_structure() + sage: Manifolds(RR).additional_structure() """ return None @@ -75,7 +88,7 @@ def dimension(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: M = Manifolds().example() + sage: M = Manifolds(RR).example() sage: M.dimension() 3 """ @@ -89,13 +102,14 @@ def Connected(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Connected() + sage: Manifolds(RR).Connected() Category of connected manifolds + over Real Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds().Connected()).run() - sage: Manifolds().Connected.__module__ + sage: TestSuite(Manifolds(RR).Connected()).run() + sage: Manifolds(RR).Connected.__module__ 'sage.categories.manifolds' """ return self._with_axiom('Connected') @@ -109,15 +123,16 @@ def FiniteDimensional(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds().Connected().FiniteDimensional(); C + sage: C = Manifolds(RR).Connected().FiniteDimensional(); C Category of finite dimensional connected manifolds + over Real Field with 53 bits of precision TESTS:: sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds().Connected().FiniteDimensional() + sage: C = Manifolds(RR).Connected().FiniteDimensional() sage: TestSuite(C).run() - sage: Manifolds().Connected().FiniteDimensional.__module__ + sage: Manifolds(RR).Connected().FiniteDimensional.__module__ 'sage.categories.manifolds' """ return self._with_axiom('FiniteDimensional') @@ -130,13 +145,14 @@ def Real(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real() + sage: Manifolds(RR).Real() Category of real manifolds + over Real Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds().Real()).run() - sage: Manifolds().Real.__module__ + sage: TestSuite(Manifolds(RR).Real()).run() + sage: Manifolds(RR).Real.__module__ 'sage.categories.manifolds' """ return self._with_axiom('Real') @@ -149,28 +165,29 @@ def Complex(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Complex() + sage: Manifolds(RR).Complex() Category of complex manifolds + over Real Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds().Complex()).run() - sage: Manifolds().Complex.__module__ + sage: TestSuite(Manifolds(RR).Complex()).run() + sage: Manifolds(RR).Complex.__module__ 'sage.categories.manifolds' """ return self._with_axiom('Complex') - class FiniteDimensional(CategoryWithAxiom): + class FiniteDimensional(CategoryWithAxiom_over_base_ring): """ Category of finite dimensional manifolds. """ - class Connected(CategoryWithAxiom): + class Connected(CategoryWithAxiom_over_base_ring): """ The category of connected manifolds. """ - class Real(CategoryWithAxiom): + class Real(CategoryWithAxiom_over_base_ring): """ The category of manifolds over `\RR`. """ @@ -184,7 +201,7 @@ def Complex(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real().Complex() + sage: Manifolds(RR).Real().Complex() Traceback (most recent call last): ... TypeError: a real manifold is not a complex manifold @@ -200,13 +217,14 @@ def Differentiable(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real().Differentiable() + sage: Manifolds(RR).Real().Differentiable() Category of differentiable real manifolds + over Real Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds().Real().Differentiable()).run() - sage: Manifolds().Real().Differentiable.__module__ + sage: TestSuite(Manifolds(RR).Real().Differentiable()).run() + sage: Manifolds(RR).Real().Differentiable.__module__ 'sage.categories.manifolds' """ return self._with_axiom('Differentiable') @@ -219,13 +237,14 @@ def Smooth(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real().Smooth() + sage: Manifolds(RR).Real().Smooth() Category of smooth real manifolds + over Real Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds().Real().Smooth()).run() - sage: Manifolds().Real().Smooth.__module__ + sage: TestSuite(Manifolds(RR).Real().Smooth()).run() + sage: Manifolds(RR).Real().Smooth.__module__ 'sage.categories.manifolds' """ return self._with_axiom('Smooth') @@ -238,13 +257,14 @@ def Analytic(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real().Analytic() + sage: Manifolds(RR).Real().Analytic() Category of analytic real manifolds + over Real Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds().Real().Analytic()).run() - sage: Manifolds().Real().Analytic.__module__ + sage: TestSuite(Manifolds(RR).Real().Analytic()).run() + sage: Manifolds(RR).Real().Analytic.__module__ 'sage.categories.manifolds' """ return self._with_axiom('Analytic') @@ -258,18 +278,19 @@ def AlmostComplex(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real().AlmostComplex() + sage: Manifolds(RR).Real().AlmostComplex() Category of almost complex real manifolds + over Real Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds().Real().AlmostComplex()).run() - sage: Manifolds().Real().AlmostComplex.__module__ + sage: TestSuite(Manifolds(RR).Real().AlmostComplex()).run() + sage: Manifolds(RR).Real().AlmostComplex.__module__ 'sage.categories.manifolds' """ return self._with_axiom('AlmostComplex') - class Differentiable(CategoryWithAxiom): + class Differentiable(CategoryWithAxiom_over_base_ring): """ The category of differentiable manifolds over `\RR`. @@ -277,7 +298,7 @@ class Differentiable(CategoryWithAxiom): underlying vector space is `\RR^d` and differentiable atlas. """ - class Smooth(CategoryWithAxiom): + class Smooth(CategoryWithAxiom_over_base_ring): """ The category of smooth manifolds over `\RR`. @@ -293,12 +314,13 @@ def extra_super_categories(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real().Smooth().super_categories() # indirect doctest - [Category of differentiable real manifolds] + sage: Manifolds(RR).Real().Smooth().super_categories() # indirect doctest + [Category of differentiable real manifolds + over Real Field with 53 bits of precision] """ - return [Manifolds().Real().Differentiable()] + return [Manifolds(self.base()).Real().Differentiable()] - class Analytic(CategoryWithAxiom): + class Analytic(CategoryWithAxiom_over_base_ring): r""" The category of complex manifolds. @@ -314,12 +336,13 @@ def extra_super_categories(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real().Analytic().super_categories() # indirect doctest - [Category of smooth real manifolds] + sage: Manifolds(RR).Real().Analytic().super_categories() # indirect doctest + [Category of smooth real manifolds + over Real Field with 53 bits of precision] """ - return [Manifolds().Real().Smooth()] + return [Manifolds(self.base()).Real().Smooth()] - class AlmostComplex(CategoryWithAxiom): + class AlmostComplex(CategoryWithAxiom_over_base_ring): r""" The category of almost complex manifolds. @@ -338,12 +361,13 @@ def extra_super_categories(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Real().Analytic().super_categories() # indirect doctest - [Category of smooth real manifolds] + sage: Manifolds(RR).Real().Analytic().super_categories() # indirect doctest + [Category of smooth real manifolds + over Real Field with 53 bits of precision] """ - return [Manifolds().Real().Smooth()] + return [Manifolds(self.base()).Real().Smooth()] - class Complex(CategoryWithAxiom): + class Complex(CategoryWithAxiom_over_base_ring): r""" The category of complex manifolds. @@ -360,7 +384,7 @@ def Real(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().Complex().Real() + sage: Manifolds(RR).Complex().Real() Traceback (most recent call last): ... TypeError: a complex manifold is not a real manifold diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index ed041469f6f..ef2460ba3c6 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -9,7 +9,9 @@ #****************************************************************************** from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method from sage.categories.category import Category +from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory from sage.categories.with_realizations import WithRealizationsCategory @@ -184,3 +186,27 @@ def dist(self, a, b): R = self.a_realization() return R.dist(R(a), R(b)) + class SubcategoryMethods: + @cached_method + def Complete(self): + """ + Return the full subcategory of the complete objects of ``self``. + + EXAMPLES:: + + sage: Sets().Metric().Complete() + Category of complete metric spaces + + TESTS:: + + sage: TestSuite(Sets().Metric().Complete()).run() + sage: Sets().Metric().Complete.__module__ + 'sage.categories.metric_spaces' + """ + return self._with_axiom('Complete') + + class Complete(CategoryWithAxiom): + """ + The category of complete metric spaces. + """ + diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 590200be2f3..62cd556c476 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1680,8 +1680,9 @@ def __invert__(self): Facade = LazyImport('sage.categories.facade_sets', 'FacadeSets') Finite = LazyImport('sage.categories.finite_sets', 'FiniteSets', at_startup=True) Topological = LazyImport('sage.categories.topological_spaces', - 'TopologicalSpaces', 'Topological') - Metric = LazyImport('sage.categories.metric_spaces', 'MetricSpaces', 'Mertic') + 'TopologicalSpaces', 'Topological', at_startup=True) + Metric = LazyImport('sage.categories.metric_spaces', 'MetricSpaces', + 'Mertic', at_startup=True) class Infinite(CategoryWithAxiom): From 36473057a7c5250f67a53813102e549e1b7f3ed5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 29 Sep 2015 11:16:14 -0500 Subject: [PATCH 1133/1872] Some cleanup and adding more category information to particular sets. --- src/sage/homology/simplicial_complex.py | 6 +- .../homology/simplicial_complex_homset.py | 84 +++++++++---------- src/sage/rings/complex_field.py | 16 +++- src/sage/rings/integer_ring.pyx | 19 ++++- src/sage/rings/rational_field.py | 15 +++- src/sage/rings/real_mpfr.pyx | 15 +++- 6 files changed, 100 insertions(+), 55 deletions(-) diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index d50f8bc7aa6..52b6c980b52 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -165,11 +165,12 @@ from sage.rings.integer_ring import ZZ from sage.structure.parent_gens import normalize_names from sage.misc.latex import latex +from sage.misc.misc import union from sage.matrix.constructor import matrix from sage.homology.chain_complex import ChainComplex from sage.graphs.graph import Graph from functools import reduce -from sage.categories.simplicial_complexes import SimplicialComplexes +lazy_import('sage.categories.simplicial_complexes', 'SimplicialComplexes') def lattice_paths(t1, t2, length=None): """ @@ -834,7 +835,6 @@ def __init__(self, from_characteristic_function is not None): raise ValueError("maximal_faces and from_characteristic_function cannot be both defined") CategoryObject.__init__(self, category=SimplicialComplexes().Finite()) - from sage.misc.misc import union C = None vertex_set = [] @@ -2081,8 +2081,6 @@ def add_face(self, face): self._facets = Facets # Update the vertex set - from sage.misc.misc import union - if self._sorted: self._vertex_set = Simplex(sorted(reduce(union, [self._vertex_set, new_face]))) else: diff --git a/src/sage/homology/simplicial_complex_homset.py b/src/sage/homology/simplicial_complex_homset.py index db00d572733..5b0083c4c75 100644 --- a/src/sage/homology/simplicial_complex_homset.py +++ b/src/sage/homology/simplicial_complex_homset.py @@ -6,9 +6,7 @@ - Travis Scrimshaw (2012-08-18): Made all simplicial complexes immutable to work with the homset cache. -EXAMPLES: - -:: +EXAMPLES:: sage: S = simplicial_complexes.Sphere(1) sage: T = simplicial_complexes.Sphere(2) @@ -16,7 +14,9 @@ sage: f = {0:0,1:1,2:3} sage: x = H(f) sage: x - Simplicial complex morphism {0: 0, 1: 1, 2: 3} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Simplicial complex morphism {0: 0, 1: 1, 2: 3} + from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} sage: x.is_injective() True sage: x.is_surjective() @@ -33,7 +33,7 @@ sage: S = simplicial_complexes.Sphere(1) sage: T = simplicial_complexes.Sphere(2) sage: H = Hom(S,T) - sage: loads(dumps(H))==H + sage: loads(dumps(H)) == H True """ @@ -82,7 +82,7 @@ def __call__(self, f): INPUT: - ``f`` -- a dictionary with keys exactly the vertices of the domain - and values vertices of the codomain + and values vertices of the codomain EXAMPLES:: @@ -92,13 +92,15 @@ def __call__(self, f): sage: H = Hom(S,T) sage: x = H(f) sage: x - Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 2, 4: 2} from Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 2, 4: 2} + from Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets + to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} """ return simplicial_complex_morphism.SimplicialComplexMorphism(f,self.domain(),self.codomain()) def diagonal_morphism(self,rename_vertices=True): r""" - Returns the diagonal morphism in `Hom(S, S \times S)`. + Return the diagonal morphism in `Hom(S, S \times S)`. EXAMPLES:: @@ -106,36 +108,32 @@ def diagonal_morphism(self,rename_vertices=True): sage: H = Hom(S,S.product(S, is_mutable=False)) sage: d = H.diagonal_morphism() sage: d - Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2', 3: 'L3R3'} from - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} - to Simplicial complex with 16 vertices and 96 facets + Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2', 3: 'L3R3'} + from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + to Simplicial complex with 16 vertices and 96 facets sage: T = SimplicialComplex([[0], [1]], is_mutable=False) sage: U = T.product(T,rename_vertices = False, is_mutable=False) sage: G = Hom(T,U) sage: e = G.diagonal_morphism(rename_vertices = False) sage: e - Simplicial complex morphism {0: (0, 0), 1: (1, 1)} from - Simplicial complex with vertex set (0, 1) and facets {(0,), (1,)} - to Simplicial complex with 4 vertices and facets {((1, 1),), ((1, 0),), ((0, 0),), ((0, 1),)} + Simplicial complex morphism {0: (0, 0), 1: (1, 1)} + from Simplicial complex with vertex set (0, 1) and facets {(0,), (1,)} + to Simplicial complex with 4 vertices and facets {((1, 1),), ((1, 0),), ((0, 0),), ((0, 1),)} """ - - if self._codomain == self._domain.product(self._domain,rename_vertices=rename_vertices): - X = self._domain.product(self._domain,rename_vertices=rename_vertices) - f = dict() - if rename_vertices: - for i in self._domain.vertices().set(): - f[i] = "L"+str(i)+"R"+str(i) - else: - for i in self._domain.vertices().set(): - f[i] = (i,i) - return simplicial_complex_morphism.SimplicialComplexMorphism(f, self._domain,X) + X = self._domain.product(self._domain,rename_vertices=rename_vertices) + if self._codomain != X: + raise TypeError("diagonal morphism is only defined for Hom(X,XxX)") + f = {} + if rename_vertices: + f = {i: "L{0}R{0}".format(i) for i in self._domain.vertices().set()} else: - raise TypeError("Diagonal morphism is only defined for Hom(X,XxX).") + f = {i: (i,i) for i in self._domain.vertices().set()} + return simplicial_complex_morphism.SimplicialComplexMorphism(f, self._domain, X) def identity(self): """ - Returns the identity morphism of `Hom(S,S)`. + Return the identity morphism of `Hom(S,S)`. EXAMPLES:: @@ -148,21 +146,18 @@ def identity(self): sage: T = SimplicialComplex([[0,1]], is_mutable=False) sage: G = Hom(T,T) sage: G.identity() - Simplicial complex morphism {0: 0, 1: 1} from - Simplicial complex with vertex set (0, 1) and facets {(0, 1)} to - Simplicial complex with vertex set (0, 1) and facets {(0, 1)} + Simplicial complex morphism {0: 0, 1: 1} + from Simplicial complex with vertex set (0, 1) and facets {(0, 1)} + to Simplicial complex with vertex set (0, 1) and facets {(0, 1)} """ - if self.is_endomorphism_set(): - f = dict() - for i in self._domain.vertices().set(): - f[i]=i - return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,self._codomain) - else: - raise TypeError("Identity map is only defined for endomorphism sets.") + if not self.is_endomorphism_set(): + raise TypeError("identity map is only defined for endomorphism sets") + f = {i:i for i in self._domain.vertices().set()} + return simplicial_complex_morphism.SimplicialComplexMorphism(f, self._domain, self._codomain) def an_element(self): """ - Returns a (non-random) element of ``self``. + Return a (non-random) element of ``self``. EXAMPLES:: @@ -177,11 +172,10 @@ def an_element(self): try: i = next(self._codomain.vertices().set().__iter__()) except StopIteration: - if len(X_vertices) == 0: - return dict() + if not X_vertices: + return {} else: - raise TypeError("There are no morphisms from a non-empty simplicial complex to an empty simplicial comples.") - f = dict() - for x in X_vertices: - f[x]=i - return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,self._codomain) + raise TypeError("there are no morphisms from a non-empty simplicial complex to an empty simplicial complex") + f = {x:i for x in X_vertices} + return simplicial_complex_morphism.SimplicialComplexMorphism(f, self._domain, self._codomain) + diff --git a/src/sage/rings/complex_field.py b/src/sage/rings/complex_field.py index 5ac959ccce6..0f786b5571f 100644 --- a/src/sage/rings/complex_field.py +++ b/src/sage/rings/complex_field.py @@ -203,7 +203,7 @@ def __init__(self, prec=53): """ self._prec = int(prec) from sage.categories.fields import Fields - ParentWithGens.__init__(self, self._real_field(), ('I',), False, category = Fields()) + ParentWithGens.__init__(self, self._real_field(), ('I',), False, category=Fields().Metric().Complete()) # self._populate_coercion_lists_() self._populate_coercion_lists_(coerce_list=[complex_number.RRtoCC(self._real_field(), self)]) @@ -744,3 +744,17 @@ def _factor_univariate_polynomial(self, f): from sage.structure.factorization import Factorization return Factorization([(R(g).monic(),e) for g,e in zip(*F)], f.leading_coefficient()) + + def dist(self, a, b): + """ + Return the distance between ``a`` and ``b``. + + EXAMPLES:: + + sage: CC.dist(3, 2) + 1.00000000000000 + sage: CC.dist(-1, I) + 1.41421356237310 + """ + return self(a - b).abs() + diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index f43931947ba..bbafd60a2a4 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -303,7 +303,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): True """ ParentWithGens.__init__(self, self, ('x',), normalize=False, - category=(EuclideanDomains(), InfiniteEnumeratedSets())) + category=(EuclideanDomains(), InfiniteEnumeratedSets().Metric())) self._populate_coercion_lists_(element_constructor=integer.Integer, init_no_parent=True, convert_method_name='_integer_') @@ -1245,9 +1245,22 @@ cdef class IntegerRing_class(PrincipalIdealDomain): elif n == 2: return sage.rings.integer.Integer(-1) elif n < 1: - raise ValueError, "n must be positive in zeta()" + raise ValueError("n must be positive in zeta()") else: - raise ValueError, "no nth root of unity in integer ring" + raise ValueError("no nth root of unity in integer ring") + + def dist(self, a, b): + """ + Return the distance between ``a`` and ``b``. + + EXAMPLES:: + + sage: ZZ.dist(3, 2) + 1 + sage: ZZ.dist(-1, 1) + 2 + """ + return self(a - b).abs() def parameter(self): r""" diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 59a757424eb..8b5794f9e92 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -215,7 +215,7 @@ def __init__(self): ('x',) """ from sage.categories.basic import QuotientFields - ParentWithGens.__init__(self, self, category = QuotientFields()) + ParentWithGens.__init__(self, self, category=QuotientFields().Metric()) self._assign_names(('x',),normalize=False) # ??? self._populate_coercion_lists_(element_constructor=rational.Rational, init_no_parent=True) @@ -934,6 +934,19 @@ def algebraic_closure(self): from sage.rings.all import QQbar return QQbar + def dist(self, a, b): + """ + Return the distance between ``a`` and ``b``. + + EXAMPLES:: + + sage: QQ.dist(3, 2) + 1 + sage: QQ.dist(-1, 1/2) + 3/2 + """ + return self(a - b).abs() + def order(self): r""" Return the order of `\QQ` which is `\infty`. diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index ac9e423689f..415e9be2e44 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -451,7 +451,7 @@ cdef class RealField_class(sage.rings.ring.Field): self.rnd = n self.rnd_str = rnd from sage.categories.fields import Fields - ParentWithGens.__init__(self, self, tuple([]), False, category = Fields()) + ParentWithGens.__init__(self, self, tuple([]), False, category=Fields().Metric().Complete()) # hack, we cannot call the constructor here rn = RealNumber.__new__(RealNumber) @@ -801,6 +801,19 @@ cdef class RealField_class(sage.rings.ring.Field): """ return self.complex_field() + def dist(self, a, b): + """ + Return the distance between ``a`` and ``b``. + + EXAMPLES:: + + sage: RR.dist(3, 2) + 1.00000000000000 + sage: RR.dist(-1, pi) + 4.14159265358979 + """ + return self(a - b).abs() + def ngens(self): """ Return the number of generators. From e8e2501fd4b08280cbca5aca749191a743c0ff01 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 14 Sep 2015 21:20:13 +0200 Subject: [PATCH 1134/1872] make entry in reference/index --- src/doc/en/reference/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/index.rst b/src/doc/en/reference/index.rst index 5972217c39d..85c52019900 100644 --- a/src/doc/en/reference/index.rst +++ b/src/doc/en/reference/index.rst @@ -78,6 +78,7 @@ Calculus * :doc:`Symbolic Calculus ` * :doc:`Mathematical Constants ` * :doc:`Elementary and Special Functions ` +* :doc:`Asymptotic Expansions ` (experimental) Geometry and Topology --------------------- From 36e16a307cb5f4e5751d7f3c529539f4b5daa096 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 29 Sep 2015 19:55:01 +0200 Subject: [PATCH 1135/1872] fix doctests after merge --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++++++---- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 1e62227af32..f17fbc3bbc8 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -906,7 +906,8 @@ def __init__(self, growth_group, coefficient_ring, category=None): raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) if category is None: - category = Rings() & sage.categories.posets.Posets() + from sage.categories.posets import Posets + category = Rings() & Posets() else: if not isinstance(category, tuple): category = (category,) @@ -1368,9 +1369,11 @@ def __init__(self, growth_group): AsymptoticRing """ self.growth_group = growth_group + + from sage.categories.rings import Rings + from sage.categories.posets import Posets super(ConstructionFunctor, self).__init__( - sage.categories.rings.Rings(), - sage.categories.rings.Rings() & sage.categories.posets.Posets()) + Rings(), Rings() & Posets()) def _repr_(self): @@ -1439,7 +1442,8 @@ def merge(self, other): return self if isinstance(other, AsymptoticRingFunctor): - cm = sage.structure.element.get_coercion_model() + from sage.structure.element import get_coercion_model + cm = get_coercion_model() try: G = cm.common_parent(self.growth_group, other.growth_group) except TypeError: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 7a4447a8cb7..beda5e25a63 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -350,7 +350,7 @@ def __init__(self, parent, growth): sage: atm.GenericTerm(T, agg.GrowthGroup('y^ZZ').gen()) Traceback (most recent call last): ... - ValueError: y is not in the parent's specified growth group + ValueError: y is not in Growth Group x^ZZ """ from sage.rings.asymptotic.growth_group import GenericGrowthElement @@ -359,7 +359,7 @@ def __init__(self, parent, growth): try: self.growth = parent.growth_group(growth) except ValueError, TypeError: - raise ValueError("%s is not in %s" % (growth, self.growth_group)) + raise ValueError("%s is not in %s" % (growth, parent.growth_group)) super(GenericTerm, self).__init__(parent=parent) From b37740fa38e4502b265990b97982d3c2abf3c523 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 20:29:40 +0200 Subject: [PATCH 1136/1872] remove code duplicate --- src/sage/rings/asymptotic/asymptotic_ring.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index abff9ef1d82..bf5897a8f3e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -907,11 +907,6 @@ def __pow__(self, power): 'implemented.' % (self, power)) return super(AsymptoticExpression, self).__pow__(power) - if len(self.summands) > 1: - raise NotImplementedError('Taking the sum %s to the ' - 'non-integer power %s not ' - 'implemented.' % (self, power)) - P = self.parent() if power not in P.growth_group.base(): raise ValueError('%s disallows taking %s ' From bfc460abdfbe3783f0df8b7f66c9b333f6d0ecda Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 20:29:48 +0200 Subject: [PATCH 1137/1872] fix removed keyword 'default_prec' --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index bf5897a8f3e..894950daf81 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1102,7 +1102,8 @@ def __classcall__(cls, growth_group, coefficient_ring, names=None, @experimental(trac_number=17601) - def __init__(self, growth_group, coefficient_ring, category=None): + def __init__(self, growth_group, coefficient_ring, category=None, + default_prec=None): r""" See :class:`AsymptoticRing` for more information. From fc9bcf22eac7b1f33ddde08bb06d894e00fcf770 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 20:30:15 +0200 Subject: [PATCH 1138/1872] add result to doctest --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 894950daf81..30061d685ac 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -890,7 +890,8 @@ def __pow__(self, power): ... NotImplementedError: Taking the sum y^2 + O(y) to the non-integer power 1/2 is not implemented. - sage: (y^2+O(y))^(-2) + sage: (y^2 + O(y))^(-2) + y^(-4) + O(y^(-5)) :: From 4edaa39b778366e3edd7e7ca9585338525289b78 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 20:30:32 +0200 Subject: [PATCH 1139/1872] slightly improve __pow__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 30061d685ac..2aa9a038a5a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -925,8 +925,7 @@ def __pow__(self, power): new_growth = expr.growth**power return P(expr.parent()(new_growth)) else: - raise NotImplementedError('Negative powers are not implemented' - ' for the term %s.' % (self, )) + return (~self)**(-power) From c7023dd4f301e0712e69b827ccfa10c7cd2f3b73 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 29 Sep 2015 20:34:22 +0200 Subject: [PATCH 1140/1872] todo-block with remark w.r.t. L-terms added --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 2aa9a038a5a..85dad0abbb6 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -776,6 +776,12 @@ def __invert__(self): returned by this method might not fulfill ``el * el._invert_() == 1``. + .. TODO:: + + As soon as `L`-terms are implemented, this + implementation has to be adapted as well in order to + yield correct results. + EXAMPLES:: sage: R. = AsymptoticRing('x^ZZ', QQ, default_prec=4) From 5f8ee7921401ca77960ac7afc7cf9af62e8b8a6c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 29 Sep 2015 21:09:52 -0500 Subject: [PATCH 1141/1872] Added reference and minor tweaks. --- src/sage/geometry/hyperplane_arrangement/arrangement.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 0b0f2ed3f47..a1306b07250 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -2008,7 +2008,7 @@ def minimal_generated_number(self): continue d = list(d) dep = V.linear_dependence([norms[j] for j in d]) - w = copy(W.zero()) + w = W.zero().list() for j,k in enumerate(d): w[k] = dep[0][j] sol.append(w) @@ -2021,8 +2021,8 @@ def is_formal(self): """ Return if ``self`` is formal. - A hyperplane arrangement is *formal* if it is 3-generated as - defined in :meth:`minimal_generated_number`. + A hyperplane arrangement is *formal* if it is 3-generated [Vuz93]_, + where `k`-generated is defined in :meth:`minimal_generated_number`. EXAMPLES:: From 19830bc7e970affaa9c1768d15dc7a82d01a4d86 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 08:32:46 +0200 Subject: [PATCH 1142/1872] post-merge: rewrite imports sage.* --- src/sage/rings/asymptotic/asymptotic_ring.py | 25 +++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b4b7042dbd2..84bf02844c1 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1763,6 +1763,8 @@ def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, ValueError: (Category of posets,) is not a subcategory of Category of rings """ from sage.categories.sets_cat import Sets + from sage.categories.rings import Rings + Sets_parent_class = Sets().parent_class while issubclass(cls, Sets_parent_class): cls = cls.__base__ @@ -1776,7 +1778,7 @@ def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, if coefficient_ring is None: raise ValueError('Coefficient ring not specified. Cannot continue.') - if coefficient_ring not in sage.categories.rings.Rings(): + if coefficient_ring not in Rings(): raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) strgens = tuple(str(g) for g in growth_group.gens_monomial()) @@ -2108,7 +2110,12 @@ def _element_constructor_(self, data, simplify=True, convert=True): return self._create_exact_summand_(data) from misc import combine_exceptions - if P is sage.symbolic.ring.SR: + from sage.symbolic.ring import SR + from sage.rings.polynomial.polynomial_ring import is_PolynomialRing + from sage.rings.polynomial.multi_polynomial_ring_generic import is_MPolynomialRing + from sage.rings.power_series_ring import is_PowerSeriesRing + + if P is SR: from sage.symbolic.operators import add_vararg if data.operator() == add_vararg: summands = [] @@ -2122,7 +2129,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): (data, self)), e) return sum(summands) - elif sage.rings.polynomial.polynomial_ring.is_PolynomialRing(P): + elif is_PolynomialRing(P): p = P.gen() try: return sum(self.create_summand('exact', growth=p**i, @@ -2132,7 +2139,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): raise combine_exceptions( ValueError('Polynomial %s is not in %s' % (data, self)), e) - elif sage.rings.polynomial.multi_polynomial_ring_generic.is_MPolynomialRing(P): + elif is_MPolynomialRing(P): try: return sum(self.create_summand('exact', growth=g, coefficient=c) for c, g in iter(data)) @@ -2140,7 +2147,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): raise combine_exceptions( ValueError('Polynomial %s is not in %s' % (data, self)), e) - elif sage.rings.power_series_ring.is_PowerSeriesRing(P): + elif is_PowerSeriesRing(P): raise NotImplementedError( 'Cannot convert %s from the %s to an asymptotic expression ' 'in %s, since growths at other points than +oo are not yet ' @@ -2589,10 +2596,11 @@ def __init__(self, growth_group): sage: AsymptoticRingFunctor(GrowthGroup('x^ZZ')) AsymptoticRing """ + from sage.categories.rings import Rings + from sage.categories.posets import Posets self.growth_group = growth_group super(ConstructionFunctor, self).__init__( - sage.categories.rings.Rings(), - sage.categories.rings.Rings() & sage.categories.posets.Posets()) + Rings(), Rings() & Posets()) def _repr_(self): @@ -2661,7 +2669,8 @@ def merge(self, other): return self if isinstance(other, AsymptoticRingFunctor): - cm = sage.structure.element.get_coercion_model() + from sage.structure.element import get_coercion_model + cm = get_coercion_model() try: G = cm.common_parent(self.growth_group, other.growth_group) except TypeError: From 5ab1a001215ef669cc9fb13d50322bbf2b073e42 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 08:45:45 +0200 Subject: [PATCH 1143/1872] post-merge: fix doctests --- src/sage/rings/asymptotic/asymptotic_ring.py | 9 +-------- src/sage/rings/asymptotic/term_monoid.py | 17 +++++++++-------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 84bf02844c1..388f20e4e43 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -495,7 +495,7 @@ def __init__(self, parent, summands, simplify=True, convert=True): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: G = GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = TermMonoid('O', G); ET = TermMonoid('exact', G, ZZ) + sage: OT = TermMonoid('O', G, ZZ); ET = TermMonoid('exact', G, ZZ) sage: R = AsymptoticRing(G, ZZ) sage: lst = [ET(x, 1), ET(x^2, 2), OT(x^3), ET(x^4, 4)] sage: expr = R(lst, simplify=False); expr # indirect doctest @@ -1754,13 +1754,6 @@ def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, Traceback (most recent call last): ... ValueError: icecream is not a ring. Cannot continue. - - :: - - sage: AsymptoticRing('x^ZZ', QQ, category=Posets()) - Traceback (most recent call last): - ... - ValueError: (Category of posets,) is not a subcategory of Category of rings """ from sage.categories.sets_cat import Sets from sage.categories.rings import Rings diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 63ac3fd1ec2..a46c26fcea2 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -91,8 +91,8 @@ sage: import sage.rings.asymptotic.term_monoid as atm sage: import sage.rings.asymptotic.growth_group as agg sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(growth_group=G) - sage: ET = atm.ExactTermMonoid(growth_group=G, base_ring=QQ) + sage: OT = atm.OTermMonoid(growth_group=G, coefficient_ring=QQ) + sage: ET = atm.ExactTermMonoid(growth_group=G, coefficient_ring=QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: et1 = ET(x^2, 2) @@ -372,7 +372,7 @@ def __init__(self, parent, growth): sage: atm.GenericTerm(T, agg.GrowthGroup('y^ZZ').gen()) Traceback (most recent call last): ... - ValueError: y is not in the parent's specified growth group + ValueError: y is not in Growth Group x^ZZ """ if parent is None: raise ValueError('The parent must be provided') @@ -572,7 +572,7 @@ def _calculate_pow_test_zero_(self, exponent): Traceback (most recent call last): ... ZeroDivisionError: Cannot take Generic Term with growth z to exponent -2. - > *previous* ZeroDivisionError: Rational division by zero + > *previous* ZeroDivisionError: rational division by zero """ zero = self.parent().coefficient_ring.zero() try: @@ -658,7 +658,7 @@ def can_absorb(self, other): sage: import sage.rings.asymptotic.growth_group as agg sage: import sage.rings.asymptotic.term_monoid as atm sage: G = agg.GenericGrowthGroup(ZZ) - sage: T = atm.GenericTermMonoid(G) + sage: T = atm.GenericTermMonoid(G, ZZ) sage: g1 = G(raw_element=21); g2 = G(raw_element=42) sage: t1 = T(g1); t2 = T(g2) sage: t1.can_absorb(t2) # indirect doctest @@ -1508,9 +1508,9 @@ def _element_constructor_(self, data, coefficient=None): a common parent has to be found:: sage: term1.parent() - Generic Term Monoid x^ZZ + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field sage: term2.parent() - Generic Term Monoid x^QQ + Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field sage: term1 <= term2 True @@ -3376,7 +3376,8 @@ def create_key_and_extra_args(self, term, sage: atm.TermMonoid.create_key_and_extra_args('icecream', G) Traceback (most recent call last): ... - ValueError: icecream has to be either 'exact' or 'O' + ValueError: Term specification 'icecream' has to be either + 'exact' or 'O' or an instance of an existing term. sage: atm.TermMonoid.create_key_and_extra_args('O', ZZ) Traceback (most recent call last): ... From 596515000c225cb924b553d20cec33e77c978e78 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 28 Sep 2015 14:53:30 +0200 Subject: [PATCH 1144/1872] Moved line related to dictionary of encoders --- src/sage/coding/__init__.py | 1 - src/sage/coding/all.py | 4 +--- src/sage/coding/linear_code.py | 5 ++--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sage/coding/__init__.py b/src/sage/coding/__init__.py index b2cee969e25..c9fecacd721 100644 --- a/src/sage/coding/__init__.py +++ b/src/sage/coding/__init__.py @@ -1,2 +1 @@ import all -linear_code.AbstractLinearCode._registered_encoders["GeneratorMatrix"] = linear_code.LinearCodeGeneratorMatrixEncoder diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index e753a13d621..5895ac96efc 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -1,7 +1,6 @@ from sage.misc.lazy_import import lazy_import -from code_constructions import (permutation_action, - walsh_matrix,cyclotomic_cosets) +from code_constructions import (permutation_action, walsh_matrix,cyclotomic_cosets) from sage.misc.superseded import deprecated_callable_import deprecated_callable_import(15445, @@ -70,7 +69,6 @@ "self_orthogonal_binary_codes"]) from sd_codes import self_dual_codes_binary - lazy_import("sage.coding.delsarte_bounds", ["Krawtchouk", "delsarte_bound_hamming_space", "delsarte_bound_additive_hamming_space"]) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 39e25a56853..92c3f486fd6 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -238,7 +238,7 @@ from sage.misc.decorators import rename_keyword from sage.misc.cachefunc import cached_method from sage.misc.superseded import deprecated_function_alias - +from encoder import Encoder ZZ = IntegerRing() VectorSpace = fm.VectorSpace @@ -3672,8 +3672,6 @@ def generator_matrix(self, encoder_name=None, **kwargs): ####################### encoders ############################### -from encoder import Encoder - class LinearCodeGeneratorMatrixEncoder(Encoder): r""" Encoder based on generator_matrix for Linear codes. @@ -3743,3 +3741,4 @@ def generator_matrix(self): [1 1 0 1 0 0 1] """ return self.code().generator_matrix() +AbstractLinearCode._registered_encoders["GeneratorMatrix"] = LinearCodeGeneratorMatrixEncoder From 4fe08b71014cfa6ada12ed1c0c5735ba09f8e0df Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 09:26:34 +0200 Subject: [PATCH 1145/1872] rewrite a doctest to make it work (and mark original test as 'not tested') --- src/sage/rings/asymptotic/asymptotic_ring.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 388f20e4e43..0b66ef57ffa 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1187,14 +1187,17 @@ def __pow__(self, exponent, precision=None): Asymptotic Ring over Rational Field sage: (x^(1/2) + O(x^0))^15 x^(15/2) + O(x^7) - sage: (y^2+O(y))^(1/2) - Traceback (most recent call last): - ... - NotImplementedError: Taking the sum y^2 + O(y) to the - non-integer power 1/2 is not implemented. + sage: (y^2 + O(y))^(1/2) # not tested + y + O(1) sage: (y^2 + O(y))^(-2) y^(-4) + O(y^(-5)) + :: + + sage: B. = AsymptoticRing(growth_group='z^QQ * log(z)^QQ', coefficient_ring=QQ) + sage: (z^2 + O(z))^(1/2) + z + O(1) + :: sage: A. = AsymptoticRing('QQ^x * x^SR * log(x)^ZZ', QQ) From 45d0c031918b89cb4e92a26735de7f798636a7a5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 11:02:06 +0200 Subject: [PATCH 1146/1872] post-merge: fix imports --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- src/sage/rings/asymptotic/term_monoid.py | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 1cbbafc59b2..090f85720cd 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2532,8 +2532,8 @@ class MonomialGrowthGroup(GenericGrowthGroup): TESTS:: - sage: L1 = agg.MonomialGrowthGroup(QQ, log(x)) - sage: L2 = agg.MonomialGrowthGroup(QQ, 'log(x)') + sage: L1 = MonomialGrowthGroup(QQ, log(x)) + sage: L2 = MonomialGrowthGroup(QQ, 'log(x)') sage: L1 is L2 True """ diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index ef3c0bf40e6..94630e7871f 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -90,11 +90,11 @@ by which other terms. We start by defining the necessary term monoids and some terms:: - sage: import sage.rings.asymptotic.term_monoid as atm - sage: import sage.rings.asymptotic.growth_group as agg - sage: G = agg.GrowthGroup('x^ZZ'); x = G.gen() - sage: OT = atm.OTermMonoid(growth_group=G, coefficient_ring=QQ) - sage: ET = atm.ExactTermMonoid(growth_group=G, coefficient_ring=QQ) + sage: from sage.rings.asymptotic.term_monoid import OTermMonoid, ExactTermMonoid + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: OT = OTermMonoid(growth_group=G, coefficient_ring=QQ) + sage: ET = ExactTermMonoid(growth_group=G, coefficient_ring=QQ) sage: ot1 = OT(x); ot2 = OT(x^2) sage: et1 = ET(x^2, 2) @@ -268,8 +268,8 @@ def absorption(left, right): :: - sage: T = atm.TermMonoid('exact', G, ZZ) - sage: atm.absorption(T(x^2), T(x^3)) + sage: T = TermMonoid('exact', GrowthGroup('x^ZZ'), ZZ) + sage: absorption(T(x^2), T(x^3)) Traceback (most recent call last): ... ArithmeticError: Absorption between x^2 and x^3 is not possible. @@ -365,11 +365,12 @@ def __init__(self, parent, growth): :: - sage: atm.GenericTerm(parent=None, growth=x) + sage: from sage.rings.asymptotic.term_monoid import GenericTerm + sage: GenericTerm(parent=None, growth=x) Traceback (most recent call last): ... ValueError: The parent must be provided - sage: atm.GenericTerm(T, agg.GrowthGroup('y^ZZ').gen()) + sage: GenericTerm(T, GrowthGroup('y^ZZ').gen()) Traceback (most recent call last): ... ValueError: y is not in Growth Group x^ZZ @@ -3379,12 +3380,12 @@ def create_key_and_extra_args(self, term, TESTS:: - sage: atm.TermMonoid.create_key_and_extra_args('icecream', G) + sage: TermMonoid.create_key_and_extra_args('icecream', G) Traceback (most recent call last): ... ValueError: Term specification 'icecream' has to be either 'exact' or 'O' or an instance of an existing term. - sage: atm.TermMonoid.create_key_and_extra_args('O', ZZ) + sage: TermMonoid.create_key_and_extra_args('O', ZZ) Traceback (most recent call last): ... ValueError: Integer Ring has to be an asymptotic growth group From f62f7cf167e99cd3e94898b7560ee95df7ade1f5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 11:02:22 +0200 Subject: [PATCH 1147/1872] post-merge: fix doctests --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 090f85720cd..22ac92d8f17 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -302,11 +302,11 @@ def __init__(self, var, repr=None, ignore=None): sage: Variable('(:-)') Traceback (most recent call last): ... - TypeError: Malformed expression: (: !!! -) + TypeError: Malformed expression: : !!! - sage: Variable('(:-)', repr='icecream') Traceback (most recent call last): ... - ValueError: '(:-)' is not a valid name for a variable. + ValueError: ':-' is not a valid name for a variable. """ from sage.symbolic.ring import isidentifier diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index bf4e780d50c..597283d2d75 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -266,7 +266,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): sage: Lx = GrowthGroup('log(x)^ZZ') sage: Cx = cartesian_product([Px, Lx], order='lex') # indirect doctest sage: Py = GrowthGroup('y^QQ') - sage: C = cartesian_product([Cx, Py], order='components'); C # indirect doctest + sage: C = cartesian_product([Cx, Py], order='product'); C # indirect doctest Growth Group x^QQ * log(x)^ZZ * y^QQ sage: C.an_element() x^(1/2)*log(x)*y^(1/2) From 3ca2e9179d3bf8ad5a72df9b9b7a69cf25a0adb0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 11:13:51 +0200 Subject: [PATCH 1148/1872] fix broken links --- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 94630e7871f..f3202834fc7 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -235,7 +235,7 @@ def absorption(left, right): Let one of the two passed terms absorb the other. Helper function used by - :class:`~sage.rings.asymptotic_ring.AsymptoticExpression`. + :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpression`. .. NOTE:: @@ -289,7 +289,7 @@ def can_absorb(left, right): other. Helper function used by - :class:`~sage.rings.asymptotic_ring.AsymptoticExpression`. + :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpression`. INPUT: From 03f3621a3023a84d33aeb314b941d457ecc589b8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 11:19:57 +0200 Subject: [PATCH 1149/1872] fix duplicated docstring-parts --- src/sage/rings/asymptotic/term_monoid.py | 29 +++++++----------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index f3202834fc7..328a478762c 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -31,27 +31,6 @@ `x^5`). Essentially, absorption can be interpreted as the addition of "compatible" terms (partial addition). -.. TODO:: - - - Implementation of more term types (e.g. `L` terms, - `\Omega` terms, `o` terms, `\Theta` terms). - -AUTHORS: - -- Benjamin Hackl (2015-01-01): initial version -- Benjamin Hackl, Daniel Krenn (2015-05-15): conception of the asymptotic ring -- Benjamin Hackl (2015-06-00): refactoring caused by refactoring growth groups -- Daniel Krenn (2015-07-00): extensive review and patches -- Benjamin Hackl (2015-07-00): cross-review; short notation -- Daniel Krenn (2015-08-31): various improvements, review; documentation - -ACKNOWLEDGEMENT: - -- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the - Austrian Science Fund (FWF): P 24644-N26. - -- Benjamin Hackl is supported by the Google Summer of Code 2015. - .. WARNING:: As this code is experimental, a warning is thrown when a term @@ -196,6 +175,7 @@ Long story short: we consider terms with different coefficients that have equal growth to be incomparable. + Various ======= @@ -211,6 +191,13 @@ - Benjamin Hackl (2015-06): refactoring caused by refactoring growth groups - Daniel Krenn (2015-07): extensive review and patches - Benjamin Hackl (2015-07): cross-review; short notation +ACKNOWLEDGEMENT: + +- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the + Austrian Science Fund (FWF): P 24644-N26. + +- Benjamin Hackl is supported by the Google Summer of Code 2015. + Classes and Methods =================== From 7f4272375d6de89bbe7fe5457c11d9165d4622ff Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 11:20:59 +0200 Subject: [PATCH 1150/1872] update AUTHORS (new style) --- src/sage/data_structures/mutable_poset.py | 3 +-- src/sage/rings/asymptotic/asymptotic_ring.py | 5 ++--- src/sage/rings/asymptotic/growth_group.py | 8 ++------ src/sage/rings/asymptotic/growth_group_cartesian.py | 5 ++--- src/sage/rings/asymptotic/misc.py | 3 +-- src/sage/rings/asymptotic/term_monoid.py | 8 +++----- 6 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index daf731cd188..e3ce1f1a0ec 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -136,8 +136,7 @@ AUTHORS: -- Daniel Krenn (2015-01-21): initial version -- Daniel Krenn (2015-08-28): mapping methods, bug fixes, cleanup +- Daniel Krenn (2015) ACKNOWLEDGEMENT: diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 815b8489db8..072d8bb27ab 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -369,9 +369,8 @@ AUTHORS: -- Benjamin Hackl (2015-06-00): initial version -- Benjamin Hackl (2015-07-00): improvement user interface (short notation) -- Daniel Krenn (2015-08-31): various improvements, review; documentation +- Benjamin Hackl (2015) +- Daniel Krenn (2015) ACKNOWLEDGEMENT: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 22ac92d8f17..0a12f524d22 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -182,12 +182,8 @@ AUTHORS: -- Benjamin Hackl (2015-01-01): initial version -- Daniel Krenn (2015-05-29): initial version and review -- Daniel Krenn (2015-06-02): cartesian products -- Benjamin Hackl (2015-07-00): growth group factory -- Benjamin Hackl (2015-08-00): exponential growth group, initial version -- Daniel Krenn (2015-08-31): various improvements, review; documentation +- Benjamin Hackl (2015) +- Daniel Krenn (2015) ACKNOWLEDGEMENT: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 597283d2d75..3f6a9b2c6dc 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -5,9 +5,8 @@ AUTHORS: -- Daniel Krenn (2015-06-02): cartesian products -- Benjamin Hackl (2015-07-00) -- Daniel Krenn (2015-08-31): various improvements, review; documentation +- Benjamin Hackl (2015) +- Daniel Krenn (2015) ACKNOWLEDGEMENT: diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 4416e26d423..5d7c65b3a8c 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -3,8 +3,7 @@ AUTHORS: -- Daniel Krenn (2015-08-25): move functions from other files to this file -- Daniel Krenn (2015-08-31): various improvements, review; documentation +- Daniel Krenn (2015) ACKNOWLEDGEMENT: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 328a478762c..15c693f42fb 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -186,11 +186,9 @@ AUTHORS: -- Benjamin Hackl (2015-01): initial version -- Benjamin Hackl, Daniel Krenn (2015-05): conception of the asymptotic ring -- Benjamin Hackl (2015-06): refactoring caused by refactoring growth groups -- Daniel Krenn (2015-07): extensive review and patches -- Benjamin Hackl (2015-07): cross-review; short notation +- Benjamin Hackl (2015) +- Daniel Krenn (2015) + ACKNOWLEDGEMENT: - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the From 79377fe809b272ebd8a6391152f13d513e28210d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 11:19:57 +0200 Subject: [PATCH 1151/1872] fix duplicated docstring-parts --- src/sage/rings/asymptotic/term_monoid.py | 27 +++++++----------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index a46c26fcea2..eab43d82a5a 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -31,25 +31,6 @@ `x^5`). Essentially, absorption can be interpreted as the addition of "compatible" terms (partial addition). -.. TODO:: - - - Implementation of more term types (e.g. `L` terms, - `\Omega` terms, `o` terms, `\Theta` terms). - -AUTHORS: - -- Benjamin Hackl (2015-01-01): initial version -- Benjamin Hackl, Daniel Krenn (2015-05-15): conception of the asymptotic ring -- Benjamin Hackl (2015-06-00): refactoring caused by refactoring growth groups -- Daniel Krenn (2015-07-00): extensive review and patches -- Benjamin Hackl (2015-07-00): cross-review; short notation -- Daniel Krenn (2015-08-31): various improvements, review; documentation - -ACKNOWLEDGEMENT: - -- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the - Austrian Science Fund (FWF): P 24644-N26. - .. WARNING:: As this code is experimental, a warning is thrown when a term @@ -194,6 +175,7 @@ Long story short: we consider terms with different coefficients that have equal growth to be incomparable. + Various ======= @@ -209,6 +191,13 @@ - Benjamin Hackl (2015-06): refactoring caused by refactoring growth groups - Daniel Krenn (2015-07): extensive review and patches - Benjamin Hackl (2015-07): cross-review; short notation +ACKNOWLEDGEMENT: + +- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the + Austrian Science Fund (FWF): P 24644-N26. + +- Benjamin Hackl is supported by the Google Summer of Code 2015. + Classes and Methods =================== From dd82094ee12535fe218a6a1d0d96a8c60b6b3f2d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 11:19:57 +0200 Subject: [PATCH 1152/1872] fix duplicated docstring-parts # Conflicts: # src/sage/rings/asymptotic/term_monoid.py --- src/sage/rings/asymptotic/term_monoid.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index beda5e25a63..1ec2fb485e1 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -172,6 +172,7 @@ Long story short: we consider terms with different coefficients that have equal growth to be incomparable. + Various ======= @@ -188,6 +189,14 @@ - Daniel Krenn (2015-07): extensive review and patches - Benjamin Hackl (2015-07): cross-review; short notation +ACKNOWLEDGEMENT: + +- Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the + Austrian Science Fund (FWF): P 24644-N26. + +- Benjamin Hackl is supported by the Google Summer of Code 2015. + + Classes and Methods =================== """ From 2cd79106de53372604add19be8ac74b1679903bc Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 11:48:26 +0200 Subject: [PATCH 1153/1872] trac #19309: Note for later --- src/sage/graphs/strongly_regular_db.pyx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 583facb022b..dd0462cc0a1 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -647,6 +647,10 @@ def is_polhill(int v,int k,int l,int mu): This function does not actually explore *all* strongly regular graphs produced in [Polhill09]_, but only those on 1024 vertices. + John Polhill offered his help if we attempt to write a code to guess, + given `(v,k,\lambda,\mu)`, which of his construction must be applied to + find the graph. + INPUT: - ``v,k,l,mu`` (integers) From f6272d39e0de839ef4e28e28d3d8fd207fe6cbae Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 12:10:35 +0200 Subject: [PATCH 1154/1872] trac #19317: A (1288,792,476,504)-strongly regular graph --- src/sage/graphs/strongly_regular_db.pyx | 51 +++++++++++++++++++------ 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index cfefb513375..2c1ac3ae0de 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -2033,6 +2033,45 @@ def SRG_81_50_31_30(): M = Matrix(GF(3),[list(l) for l in x]) return strongly_regular_from_two_weight_code(LinearCode(M)) +def SRG_1288_792_476_504(): + r""" + Return a `(1288, 792, 476, 504)`-strongly regular graph. + + This graph is built on the words of weight 12 in the + :func:`~sage.coding.code_constructions.BinaryGolayCode`. Two of them are + then made adjacent if their symmetric difference has weight 12 (cf + [BvE92]_). + + .. SEEALSO:: + + :func:`strongly_regular_from_two_weight_code` -- build a strongly regular graph from + a two-weight code. + + EXAMPLE:: + + sage: from sage.graphs.strongly_regular_db import SRG_1288_792_476_504 + sage: G = SRG_1288_792_476_504() # long time + sage: G.is_strongly_regular(parameters=True) # long time + (1288, 792, 476, 504) + + REFERENCE: + + .. [BvE92] A. Brouwer and C. Van Eijl, + On the p-Rank of the Adjacency Matrices of Strongly Regular Graphs + Journal of Algebraic Combinatorics (1992), vol.1, n.4, pp329-346, + http://dx.doi.org/10.1023/A%3A1022438616684 + """ + from sage.coding.code_constructions import BinaryGolayCode + C = BinaryGolayCode() + C = [[i for i,v in enumerate(c) if v] + for c in C] + C = [s for s in C if len(s) == 12] + G = Graph([map(frozenset,C), + lambda x,y:len(x.symmetric_difference(y))==12]) + G.relabel() + return G + + cdef bint seems_feasible(int v, int k, int l, int mu): r""" Tests is the set of parameters seems feasible @@ -2182,17 +2221,6 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (324,95,22,30)-strongly regular graph is known to exist. Comments: - A realizable set of parameters that Sage cannot realize (help us!):: - - sage: graphs.strongly_regular_graph(1288, 495, 206, existence=True) - True - sage: graphs.strongly_regular_graph(1288, 495, 206) - Traceback (most recent call last): - ... - RuntimeError: Andries Brouwer's database claims that such a (1288,495,206,180)-strongly - regular graph exists, but Sage does not know how to build it. - ... - A large unknown set of parameters (not in Andries Brouwer's database):: sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True) @@ -2281,6 +2309,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (729, 476, 313,306): [SRG_729_476_313_306], (729, 532, 391,380): [SRG_729_532_391_380], (1024,825, 668,650): [SRG_1024_825_668_650], + (1288,792, 476,504): [SRG_1288_792_476_504], (1782,416, 100, 96): [SuzukiGraph], } From 70aa9c4fa3c8711fb7dc4aea446d4624d2a27803 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 12:28:20 +0200 Subject: [PATCH 1155/1872] rename CartesianProductPosets to CartesianProductPoset --- src/sage/categories/posets.py | 6 +++--- src/sage/combinat/posets/cartesian_product.py | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index 257a8ebc917..a20888d765e 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -683,9 +683,9 @@ def is_antichain_of_poset(self, o): """ return all(not self.lt(x,y) for x in o for y in o) - CartesianProductPosets = LazyImport( - 'sage.combinat.posets.cartesian_product', 'CartesianProductPosets') - CartesianProduct = CartesianProductPosets + CartesianProductPoset = LazyImport( + 'sage.combinat.posets.cartesian_product', 'CartesianProductPoset') + CartesianProduct = CartesianProductPoset class ElementMethods: pass diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 4a68fe27db7..8b97dc88f85 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -18,7 +18,7 @@ from sage.sets.cartesian_product import CartesianProduct -class CartesianProductPosets(CartesianProduct): +class CartesianProductPoset(CartesianProduct): r""" A class implementing cartesian products of posets (and elements thereof). Compared to :class:`CartesianProduct` you are able to @@ -83,7 +83,7 @@ class CartesianProductPosets(CartesianProduct): def __init__(self, sets, category, order=None, **kwargs): r""" - See :class:`CartesianProductPosets` for details. + See :class:`CartesianProductPoset` for details. TESTS:: @@ -111,7 +111,7 @@ def __init__(self, sets, category, order=None, **kwargs): if not isinstance(category, tuple): category = (category,) category = Category.join(category + (Posets(),)) - super(CartesianProductPosets, self).__init__( + super(CartesianProductPoset, self).__init__( sets, category, **kwargs) @@ -132,7 +132,7 @@ def le(self, left, right): .. NOTE:: This method uses the order defined on creation of this - cartesian product. See :class:`CartesianProductPosets`. + cartesian product. See :class:`CartesianProductPoset`. EXAMPLES:: @@ -315,7 +315,7 @@ def _le_(self, other): .. NOTE:: - This method calls :meth:`CartesianProductPosets.le`. Override + This method calls :meth:`CartesianProductPoset.le`. Override it in inherited class to change this. It can be assumed that this element and ``other`` have @@ -323,7 +323,7 @@ def _le_(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPoset # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -358,7 +358,7 @@ def __le__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPoset # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -402,7 +402,7 @@ def __ge__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPoset # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -437,7 +437,7 @@ def __lt__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPoset # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -472,7 +472,7 @@ def __gt__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPosets # needed until #19269 is fixed + sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPoset # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) From f21990d0b55e665aed89b8aef0f862eef59d6368 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 12:30:21 +0200 Subject: [PATCH 1156/1872] code-simplify CartesianProduct assignment --- src/sage/categories/posets.py | 3 +-- src/sage/sets/cartesian_product.py | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index a20888d765e..52baeec2e41 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -683,9 +683,8 @@ def is_antichain_of_poset(self, o): """ return all(not self.lt(x,y) for x in o for y in o) - CartesianProductPoset = LazyImport( + CartesianProduct = LazyImport( 'sage.combinat.posets.cartesian_product', 'CartesianProductPoset') - CartesianProduct = CartesianProductPoset class ElementMethods: pass diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index b91844303f1..a4ff5cc257e 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -4,8 +4,6 @@ AUTHORS: - Nicolas Thiery (2010-03): initial version -- Daniel Krenn (2015-06): cartesian products for posets with different orders - """ #***************************************************************************** # Copyright (C) 2008 Nicolas Thiery , From f7b20da3550e0ab6ef32414179b47589252676af Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 30 Sep 2015 12:02:01 +0200 Subject: [PATCH 1157/1872] Reorganize compiler checks in proper autoconf style --- configure.ac | 521 ++++++++++++++++++--------------------------------- 1 file changed, 187 insertions(+), 334 deletions(-) diff --git a/configure.ac b/configure.ac index ccd22331308..05da588ae59 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,14 @@ -dnl Very loosely based on configure.ac in prereq-0.3 written by William Stein. -dnl Version 0.7 written by David Kirkby, released under the GPL version 2. -dnl in January 2010 +#***************************************************************************** +# Copyright (C) 2005-2007 William Stein +# Copyright (C) 2009-2011 David Kirkby +# Copyright (C) 2012-2015 Jeroen Demeyer +# +# 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/ +#***************************************************************************** dnl If you are going to update this, please stick the recommended layout dnl in the autoconf manual - i.e. @@ -14,9 +22,8 @@ dnl Next check compiler characteristics dnl Next check for library functions dnl Next check for system services -dnl Older versions give "undefined macro: _m4_divert_diversion", see -dnl http://trac.sagemath.org/ticket/15606#comment:19 -AC_PREREQ([2.64]) +dnl Older versions do not support $GFC +AC_PREREQ([2.69]) AC_DEFUN([SAGE_VERSION], m4_esyscmd_s([. src/bin/sage-version.sh && echo $SAGE_VERSION])) AC_INIT([Sage], SAGE_VERSION, [sage-devel@googlegroups.com]) @@ -115,163 +122,9 @@ else ;; esac fi - -############################################################################### -# Determine whether to install GCC (gcc, g++, gfortran). -############################################################################### - -# Determine various compilers. These variables should not be exported, -# they are only used in this build/make/install script to determine whether to -# install GCC. The "real" $CC, $CXX,... variables for building Sage are -# set in sage-env. - -if [ -z "$CXX" ]; then - CXX=g++ -fi - -if [ -z "$CC" ]; then - if command -v gcc >/dev/null 2>/dev/null; then - CC=gcc - fi -fi - -if [ -z "$FC" ]; then - if command -v gfortran >/dev/null 2>/dev/null; then - FC=gfortran - elif command -v g95 >/dev/null 2>/dev/null; then - FC=g95 - elif command -v g77 >/dev/null 2>/dev/null; then - FC=g77 - fi -fi - -if [ -f "$SAGE_LOCAL/bin/gcc" ]; then - # Ignore SAGE_INSTALL_GCC if GCC is already installed - SAGE_INSTALL_GCC="" -fi - -if [ -n "$SAGE_INSTALL_GCC" ]; then - # Check the value of the environment variable SAGE_INSTALL_GCC - case "$SAGE_INSTALL_GCC" in - yes) - echo >&2 "Installing GCC because SAGE_INSTALL_GCC is set to 'yes'." - need_to_install_gcc=yes;; - no) - need_to_install_gcc=no;; - *) - echo >&2 "Error: SAGE_INSTALL_GCC should be set to 'yes' or 'no'." - echo >&2 "You can also leave it unset to install GCC when needed." - exit 2;; - esac -else - # SAGE_INSTALL_GCC is not set, install GCC when needed. - need_to_install_gcc=no - - # Check whether $CXX is some version of GCC. If it's a different - # compiler, install GCC. - CXXtype=`source sage-env; testcxx.sh $CXX` - if [ "$CXXtype" != GCC ]; then - echo >&2 "Installing GCC because your '$CXX' isn't GCC (GNU C++)." - need_to_install_gcc=yes - else - # $CXX points to some version of GCC, find out which version. - GCCVERSION=`$CXX -dumpversion` - # Add the .0 because Debian/Ubuntu gives version numbers like - # 4.6 instead of 4.6.4 (Trac #18885) - case "$GCCVERSION.0" in - [0-3].*|4.[0-3].*) - # Install our own GCC if the system-provided one is older than gcc-4.4. - # * gcc-4.2.4 compiles a slow IML: - # https://groups.google.com/forum/?fromgroups#!topic/sage-devel/Ux3t0dW2FSI - # * gcc-4.3 might have trouble building ATLAS: - # https://groups.google.com/forum/?fromgroups#!topic/sage-devel/KCeFqQ_w2FE - echo >&2 "Installing GCC because you have $CXX version $GCCVERSION, which is quite old." - need_to_install_gcc=yes;; - 4.4.*|4.5.*) - # GCC 4.4.x and GCC 4.5.x fail to compile PARI/GP on ia64: - # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46044 - if [ x`uname -m` = xia64 ]; then - echo >&2 "Installing GCC because you have $CXX version $GCCVERSION on ia64." - echo >&2 "gcc <= 4.5 fails to compile PARI/GP on ia64." - need_to_install_gcc=yes - fi;; - 4.6.*) - # Also install GCC if we have version 4.6.* which is - # known to give trouble within Sage: - # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48702 - # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48774 - # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52061 - # * https://groups.google.com/d/msg/sage-release/xgmJ3nAcUOY/jH8OZjftYRsJ - echo >&2 "Installing GCC because you have $CXX version $GCCVERSION." - echo >&2 "gcc-4.6.* has known bugs affecting Sage." - need_to_install_gcc=yes;; - 4.7.0) - # GCC 4.7.0 is very broken on ia64, see - # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48496 - # This is fixed in GCC 4.7.1. - if [ x`uname -m` = xia64 ]; then - echo >&2 "Installing GCC because you have $CXX version $GCCVERSION on ia64." - echo >&2 "gcc-4.7.0 has a serious bug on ia64." - need_to_install_gcc=yes - fi;; - esac - fi - - # Check C, C++ and Fortran compilers. - if [ -z "$CC" ]; then - echo >&2 "Installing GCC because a C compiler is missing." - need_to_install_gcc=yes - fi - - if [ -z "$FC" ]; then - echo >&2 "Installing GCC because a Fortran compiler is missing." - need_to_install_gcc=yes - fi -fi - -# If we are not installing GCC: check that the assembler and linker -# used by $CXX match $AS and $LD. -# See http://trac.sagemath.org/sage_trac/ticket/14296 -if [ $need_to_install_gcc != yes ]; then - if [ "$AS" != "" ]; then - CXX_as=`$CXX -print-file-name=as 2>/dev/null` - CXX_as=`command -v $CXX_as 2>/dev/null` - cmd_AS=`command -v $AS` - - if [ "$CXX_as" != "" -a "$CXX_as" != "$cmd_AS" ]; then - echo >&2 "Error: Mismatch of assemblers between" - echo >&2 " * $CXX using $CXX_as" - echo >&2 " * \$AS equal to $AS" - if [ "$SAGE_PORT" = "" ]; then - echo >&2 "Aborting, either change or unset AS or set SAGE_PORT=yes or set" - echo >&2 "SAGE_INSTALL_GCC=yes (this GCC would use assembler $AS)" - exit 1 - else - echo >&2 "Continuing since SAGE_PORT is set." - fi - fi - fi - if [ "$LD" != "" ]; then - CXX_ld=`$CXX -print-file-name=ld 2>/dev/null` - CXX_ld=`command -v $CXX_ld 2>/dev/null` - cmd_LD=`command -v $LD` - - if [ "$CXX_ld" != "" -a "$CXX_ld" != "$cmd_LD" ]; then - echo >&2 "Error: Mismatch of linkers between" - echo >&2 " * $CXX using $CXX_ld" - echo >&2 " * \$LD equal to $LD" - if [ "$SAGE_PORT" = "" ]; then - echo >&2 "Aborting, either change or unset LD or set SAGE_PORT=yes or set" - echo >&2 "SAGE_INSTALL_GCC=yes (this GCC would use linker $LD)" - exit 1 - else - echo >&2 "Continuing since SAGE_PORT is set." - fi - fi - fi -fi ] + #--------------------------------------------------------- AX_CHECK_ROOT([AC_MSG_ERROR([You cannot build Sage as root, switch to an unpriviledged user])], []) @@ -366,30 +219,10 @@ The Sage community would also appreciate any patches you submit]]);; esac -dnl Check compiler versions -buggy_gcc_version1="4.0.0" -minimum_gcc_version_for_no_hassle="4.0.1" -minimum_gcc_version_for_debugging_purposes="3.4.0" - -#--------------------------------------------------------- -# Process options and environment variables - -# Check --enable-compiler-checks (default depends on whether we are -# installing GCC) -AC_ARG_ENABLE([compiler-checks], [Check versions and presence of C, C++ and Fortran compilers (default: yes unless installing GCC)], - [enable_compiler_checks=$enableval], - [# Default - if test "$need_to_install_gcc" = yes; then - enable_compiler_checks=no; - else - enable_compiler_checks=yes; - fi - ] - ) - +############################################################################### +# Check general programs +############################################################################### -#--------------------------------------------------------- -# Check some programs needed actually exist. AC_CHECK_PROG(found_ar, ar, yes, no) if test x$found_ar != xyes then @@ -508,10 +341,62 @@ then AC_MSG_ERROR([Exiting, since AC_PACKAGE_NAME requires dpkg-architecture on Debian]) fi -#--------------------------------------------------------- -# C/C++/Fortran compilers -# First check for programs we need. +############################################################################### +# Check C/C++/Fortran compilers +############################################################################### + +dnl Usage: SAGE_SHOULD_INSTALL_GCC(reason) +dnl +dnl Use this macro to indicate that we SHOULD install GCC. +dnl In this case, GCC will be installed unless SAGE_INSTALL_GCC=no. +dnl In the latter case, a warning is given. +AC_DEFUN([SAGE_SHOULD_INSTALL_GCC], [ + if test x$SAGE_INSTALL_GCC = xexists; then + true # Do nothing if already installed + elif test x$SAGE_INSTALL_GCC = xno; then + AC_MSG_WARN($1) + else + AC_MSG_NOTICE([Installing GCC because] $1) + need_to_install_gcc=yes + fi +]) + +dnl Usage: SAGE_MUST_INSTALL_GCC(reason) +dnl +dnl Use this macro to indicate that we MUST install GCC. +dnl In this case, it is an error if SAGE_INSTALL_GCC=no. +AC_DEFUN([SAGE_MUST_INSTALL_GCC], [ + if test x$SAGE_INSTALL_GCC = xexists; then + true # Do nothing if already installed + elif test x$SAGE_INSTALL_GCC = xno; then + AC_MSG_ERROR([SAGE_INSTALL_GCC is set to 'no', but] $1) + else + AC_MSG_NOTICE([Installing GCC because] $1) + need_to_install_gcc=yes + fi +]) + + +# By default, do not install GCC +need_to_install_gcc=no + +if test -f "$SAGE_LOCAL/bin/gcc"; then + # Special value for SAGE_INSTALL_GCC if GCC is already installed + SAGE_INSTALL_GCC=exists +elif test -n "$SAGE_INSTALL_GCC"; then + # Check the value of the environment variable SAGE_INSTALL_GCC + case "$SAGE_INSTALL_GCC" in + yes) + SAGE_MUST_INSTALL_GCC([SAGE_INSTALL_GCC is set to 'yes']);; + no) + true;; + *) + AC_MSG_ERROR([SAGE_INSTALL_GCC should be set to 'yes' or 'no'. You can also leave it unset to install GCC when needed]);; + esac +fi + + AC_LANG(C) AC_PROG_CC() AC_PROG_CPP() @@ -524,44 +409,41 @@ AC_PROG_FC() if test "x$CXX" = x then - AC_MSG_ERROR([Exiting, since a C++ compiler was not found.]) + AC_MSG_ERROR([a C++ compiler is missing]) fi -if test $enable_compiler_checks = yes -then - if test "x$CC" = x - then - AC_MSG_ERROR([Exiting, since a C compiler was not found.]) - fi - if test "x$FC" = x - then - AC_MSG_ERROR([Exiting, since a Fortran compiler was not found.]) - fi -fi -# Next one should check for header files. +############################################################################### +# Check header files +############################################################################### + # complex.h is one that might not exist on older systems. AC_LANG(C++) AC_CHECK_HEADER([complex.h],[],[ AC_MSG_ERROR([Exiting, since you do not have the 'complex.h' header file.]) ]) -# Next one should check for types. -# None needed -# Next one should check for structures. +############################################################################### +# Check types/structures +############################################################################### + # None needed -# Next one should check for compiler characterists. -# Check that we can compile C99 code +############################################################################### +# Check compiler characterists +############################################################################### + AC_LANG(C) -AC_PROG_CC_C99() -if test $enable_compiler_checks = yes -then +if test -z "$CC"; then + SAGE_MUST_INSTALL_GCC([a C compiler is missing]) +else + # Check that we can compile C99 code + AC_PROG_CC_C99() if test "x$ac_cv_prog_cc_c99" = xno then - AC_MSG_ERROR([Exiting, as your C compiler cannot compile C99 code]) + SAGE_MUST_INSTALL_GCC([your C compiler cannot compile C99 code]) fi fi @@ -571,62 +453,82 @@ fi # sets FC to /usr/bin/ls, we will at least know it's # not a working Fortran compiler. AC_LANG(Fortran) -if test $enable_compiler_checks = yes -then +if test -z "$FC"; then + SAGE_MUST_INSTALL_GCC([a Fortran compiler is missing]) +else # see http://www.gnu.org/software/hello/manual/autoconf/Fortran-Compiler.html AC_FC_FREEFORM([], [ AC_MSG_NOTICE([Your Fortran compiler does not accept free-format source code]) AC_MSG_NOTICE([which means the compiler is either seriously broken, or]) AC_MSG_NOTICE([is too old to build Sage.]) - AC_MSG_ERROR([Exiting, as the Fortran compiler is not suitable]) + SAGE_MUST_INSTALL_GCC([the Fortran compiler is not suitable]) ]) fi -if test $enable_compiler_checks = yes -then - # Check that all compilers (C, C++, Fortan) are either all GNU - # compiler or all non-GNU compilers. If not, there is a problem, as - # mixing GNU and non-GNU compilers is likely to cause problems. - if test x$GCC = xyes && test x$GXX != xyes - then - AC_MSG_NOTICE([You are trying to use gcc but not g++]) - AC_MSG_ERROR([The mixing of GNU and non-GNU compilers is not permitted]) - fi - if test x$GXX = xyes && test x$ac_cv_fc_compiler_gnu != xyes - then - AC_MSG_NOTICE([You are trying to use g++ but not gfortran]) - AC_MSG_ERROR([The mixing of GNU and non-GNU compilers is not permitted]) - fi - if test x$ac_cv_fc_compiler_gnu = xyes && test x$GCC != xyes - then - AC_MSG_NOTICE([You are trying to use gfortran but not gcc]) - AC_MSG_ERROR([The mixing of GNU and non-GNU compilers is not permitted]) - fi -fi -# The following tests check the version of the compilers (if GNU) -# are all the same. If non-GNU compilers are used, then no such -# checks are performed. -if test $enable_compiler_checks = yes -then -if test x$GCC = xyes -then - # Thank you to Andrew W. Nosenko andrew.w.nosenko@gmail.com - # who answered my query about testing of gcc versions on - # the autoconf@gnu.org mailing list. - # AS_VERSION_COMPARE(ver-1, ver-2, [action-if-less], [action-if-eq], [action-if-greater]) - AX_GCC_VERSION - AX_GXX_VERSION - AS_VERSION_COMPARE([$GCC_VERSION], [$GXX_VERSION], - [ - AC_MSG_NOTICE([gcc ($GCC_VERSION) and g++ ($GXX_VERSION) are not the same version]) - AC_MSG_NOTICE([which they must be. Check your setting of CC and CXX]) - AC_MSG_ERROR([Exiting, since the C and C++ compilers have different versions]) - ],[],[ - AC_MSG_NOTICE([gcc ($GCC_VERSION) and g++ ($GXX_VERSION) are not the same version]) - AC_MSG_NOTICE([which they must be. Check your setting of CC and CXX]) - AC_MSG_ERROR([Exiting, since the C and C++ compilers have different versions])]) +# Check compiler versions + +if test x$GXX != xyes; then + SAGE_SHOULD_INSTALL_GCC([your C++ compiler isn't GCC (GNU C++)]) +elif test $need_to_install_gcc = yes; then + # If we're installing GCC anyway, skip the rest of these version + # checks. + true +elif test x$GCC != xyes; then + SAGE_SHOULD_INSTALL_GCC([your C compiler isn't GCC (GNU C)]) +elif test x$GFC != xyes; then + SAGE_SHOULD_INSTALL_GCC([your Fortran compiler isn't GCC (GNU Fortran)]) +else + # Since need_to_install_gcc is "no", we know that + # at least C, C++ and Fortran compilers are available. + # We also know that all compilers are GCC. + + # Find out the compiler versions: + AX_GCC_VERSION() + AX_GXX_VERSION() + + # Add the .0 because Debian/Ubuntu gives version numbers like + # 4.6 instead of 4.6.4 (Trac #18885) + case "$GXX_VERSION.0" in + [0-3].*|4.[0-3].*) + # Install our own GCC if the system-provided one is older than gcc-4.4. + # * gcc-4.2.4 compiles a slow IML: + # https://groups.google.com/forum/?fromgroups#!topic/sage-devel/Ux3t0dW2FSI + # * gcc-4.3 might have trouble building ATLAS: + # https://groups.google.com/forum/?fromgroups#!topic/sage-devel/KCeFqQ_w2FE + SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION, which is quite old]);; + 4.4.*|4.5.*) + # GCC 4.4.x and GCC 4.5.x fail to compile PARI/GP on ia64: + # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46044 + if test x`uname -m` = xia64; then + SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION on ia64]) + AC_MSG_NOTICE([gcc <= 4.5 fails to compile PARI/GP on ia64]) + fi;; + 4.6.*) + # Also install GCC if we have version 4.6.* which is + # known to give trouble within Sage: + # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48702 + # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48774 + # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52061 + # * https://groups.google.com/d/msg/sage-release/xgmJ3nAcUOY/jH8OZjftYRsJ + SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION]) + AC_MSG_NOTICE([g++-4.6.* has known bugs affecting Sage]);; + 4.7.0) + # GCC 4.7.0 is very broken on ia64, see + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48496 + # This is fixed in GCC 4.7.1. + if test x`uname -m` = xia64; then + SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION on ia64]) + AC_MSG_NOTICE([g++-4.7.0 has a serious bug on ia64]) + fi;; + esac + + # The following tests check that the version of the compilers + # are all the same. + if test "$GCC_VERSION" != "$GXX_VERSION"; then + SAGE_SHOULD_INSTALL_GCC([$CC ($GCC_VERSION) and $CXX ($GXX_VERSION) are not the same version]) + fi # In the paragraph below, 'gfortran' is used to indicate the GNU Fortran # compiler, though it might be called something else. @@ -663,90 +565,41 @@ then if test "x$fortran_version_string" = x then - AC_MSG_NOTICE([Although gcc and g++ are both version $GCC_VERSION]) - AC_MSG_NOTICE([the Fortran compiler $FC is some other version.]) - AC_MSG_NOTICE([The output from $FC --version is below.]) - echo "" - $FC --version 2>&1 - echo "" - AC_MSG_ERROR([Exiting, since the Fortran compiler is not the same version as the C and C++ compilers]) - else - AC_MSG_NOTICE([Excellent, the C, C++ and Fortran compilers are all GCC $GCC_VERSION]) + SAGE_SHOULD_INSTALL_GCC([the Fortran compiler is not the same version as the C compiler]) fi +fi - # Exit if the version of GCC is known to be too old, and so old - # we have no intension whatsoever of trying to make Sage work with it. - AS_VERSION_COMPARE([$GCC_VERSION], [$minimum_gcc_version_for_debugging_purposes],[ - AC_MSG_NOTICE([GCC $GCC_VERSION is too old and can not build AC_PACKAGE_NAME. ]) - AC_MSG_NOTICE([Please use a GCC of at least $minimum_gcc_version_for_no_hassle ]) - AC_MSG_NOTICE([There are no plans whatsoever to support GCC $GCC_VERSION]) - AC_MSG_ERROR([Exiting, due to the use of a version of GCC that is too old]) - ], [],[]) - - # Exit if Sage is *precisely* version $buggy_gcc_version1, as that is very buggy. - # If any later versions of GCC are found to be buggy (which would never surprise me) - # We can easily add a buggy_gcc_version2 and repeat the next 5 lines. - # At the time of writing (28th September 2009) that is version 4.0.0, - # but rather than hard-code that, it is set as a variable. - AS_VERSION_COMPARE([$GCC_VERSION], [$buggy_gcc_version1],[],[ - AC_MSG_NOTICE([GCC $buggy_gcc_version1 is very buggy and can not build AC_PACKAGE_NAME.]) - AC_MSG_NOTICE([Please use a gcc of at least $minimum_gcc_version_for_no_hassle.]) - AC_MSG_ERROR([Exiting, due to the use of a version of GCC that is too buggy]) - ],[]) - - # Issue a warning if gcc is too old to work with all packages, but - # someone wants to try getting one or more packages work with - # an earlier gcc. At the time of writing, (28th Sept 2009), ratpoints - # has such an issue, requiring version 4.0.1, but we would like to - # get it to work with version 3.4.x - AS_VERSION_COMPARE([$GCC_VERSION], [$minimum_gcc_version_for_no_hassle],[ - AC_MSG_NOTICE([******************************************************]) - AC_MSG_NOTICE([******************************************************]) - AC_MSG_NOTICE([******************************************************]) - AC_MSG_NOTICE([GCC $GCC_VERSION is too old and can not build AC_PACKAGE_NAME.]) - AC_MSG_NOTICE([Please use a gcc of at least $minimum_gcc_version_for_no_hassle]) - AC_MSG_NOTICE([if you just want AC_PACKAGE_NAME to build without problems.]) - AC_MSG_NOTICE([]) - if test "${SAGE_USE_OLD_GCC+set}" = set; then - AC_MSG_NOTICE([Since the variable SAGE_USE_OLD_GCC was set, the]) - AC_MSG_NOTICE([build will continue, but it will fail without changes]) - AC_MSG_NOTICE([to the Sage source code. You can be 100% sure of that.]) - else - AC_MSG_NOTICE([If you want to try building Sage with a GCC 3.4.x ]) - AC_MSG_NOTICE([with a view to debugging the problems which stop it ]) - AC_MSG_NOTICE([working on a gcc 3.4 series compiler, set the ]) - AC_MSG_NOTICE([environment variable SAGE_USE_OLD_GCC to something non]) - AC_MSG_NOTICE([empty. But if you just want Sage to work, upgrade GCC ]) - AC_MSG_NOTICE([******************************************************]) - AC_MSG_NOTICE([******************************************************]) - AC_MSG_ERROR([Exiting, due to the use of a version of GCC that is too old]) - fi - ], -[ -AC_MSG_NOTICE([Good, gcc and g++ are are just new enough as GCC $minimum_gcc_version_for_no_hassle]) -AC_MSG_NOTICE([is the minimum version needed needed to build AC_PACKAGE_NAME]) -] -, -[ -AC_MSG_NOTICE([Excellent, GCC $GCC_VERSION is later than the minimum]) -AC_MSG_NOTICE([needed to build AC_PACKAGE_NAME, which is GCC version $minimum_gcc_version_for_no_hassle]) -]) - # AS_VERSION_COMPARE(ver-1, ver-2, [action-if-less], [action-if-eq], [action-if-greater]) -else - AC_MSG_WARN([You have a non-GNU compiler, but AC_PACKAGE_NAME has never been built]) - AC_MSG_WARN([successfully with any compiler other than GCC, despite]) - AC_MSG_WARN([some attempts made on Solaris to use Sun's compiler, which]) - AC_MSG_WARN([produces faster code than GCC. However, the AC_PACKAGE_NAME developers]) - AC_MSG_WARN([want AC_PACKAGE_NAME to work with other compilers, so please try.]) - AC_MSG_WARN([The AC_PACKAGE_NAME developers would welcome any feedback you can give.]) - AC_MSG_WARN([Please visit http://groups.google.com/group/sage-devel]) - AC_MSG_WARN([If you just want to use AC_PACKAGE_NAME, we suggest the use of]) - AC_MSG_WARN([GCC of at least version $minimum_gcc_version_for_no_hassle]) +# Check that the assembler and linker used by $CXX match $AS and $LD. +# See http://trac.sagemath.org/sage_trac/ticket/14296 +if test -n "$AS"; then + CXX_as=`$CXX -print-file-name=as 2>/dev/null` + CXX_as=`command -v $CXX_as 2>/dev/null` + cmd_AS=`command -v $AS` + + if test "$CXX_as" != "" -a "$CXX_as" != "$cmd_AS"; then + SAGE_SHOULD_INSTALL_GCC([there is a mismatch of assemblers]) + AC_MSG_NOTICE([ $CXX uses $CXX_as]) + AC_MSG_NOTICE([ \$AS equal to $AS]) + fi +fi +if test -n "$LD"; then + CXX_ld=`$CXX -print-file-name=ld 2>/dev/null` + CXX_ld=`command -v $CXX_ld 2>/dev/null` + cmd_LD=`command -v $LD` + + if test "$CXX_ld" != "" -a "$CXX_ld" != "$cmd_LD"; then + SAGE_SHOULD_INSTALL_GCC([there is a mismatch of linkers]) + AC_MSG_NOTICE([ $CXX uses $CXX_ld]) + AC_MSG_NOTICE([ \$LD equal to $LD]) + fi fi -fi # test $enable_compiler_checks = yes -# Testing for library functions + +############################################################################### +# Check libraries +############################################################################### + # First check for something that should be in any maths library (sqrt). AC_LANG(C++) AC_CHECK_LIB(m,sqrt,[],[ From dc390fc22a0c22b75ebd26ef0161bf0770142c48 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 30 Sep 2015 12:42:32 +0200 Subject: [PATCH 1158/1872] forgot an else --- src/sage/databases/findstat.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index c831644c4ca..61dfb90dab1 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -458,6 +458,15 @@ def __call__(self, query, function=None, depth=2, max_values=FINDSTAT_MAX_VALUES Traceback (most recent call last): ... ValueError: The given arguments, Permutations and 1, cannot be used for a FindStat search. + + sage: from sage.databases.findstat import FindStatCollection + sage: findstat(FindStatCollection("Permutations"), lambda pi: pi.length()) # optional -- internet,random + 0: (St000018: The [[/Permutations/Inversions|number of inversions]] of a permutation., [], 200) + 1: (St000004: The [[/Permutations/Descents-Major|major index]] of a permutation., [Mp00062: inversion-number to major-index bijection], 200) + 2: (St000067: The inversion number of the alternating sign matrix., [Mp00063: to alternating sign matrix], 152) + 3: (St000246: The [[/Permutations/Inversions|number of non-inversions]] of a permutation., [Mp00064: reverse], 200) + 4: (St000008: The major index of the composition., [Mp00062: inversion-number to major-index bijection, Mp00071: descent composition], 200) + """ try: depth = int(depth) @@ -526,7 +535,9 @@ def __call__(self, query, function=None, depth=2, max_values=FINDSTAT_MAX_VALUES else: if callable(function): - if not isinstance(query, FindStatCollection): + if isinstance(query, FindStatCollection): + collection = query + else: collection = FindStatCollection(query) first_terms = collection.first_terms(function, max_values=max_values) data = [([key], [value]) for (key, value) in first_terms] From 8f9a61942e14254ec028924bccf918774fb57cf6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 13:20:53 +0200 Subject: [PATCH 1159/1872] add a doctest dealing with coercion while comparing --- src/sage/combinat/posets/cartesian_product.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 8b97dc88f85..10bb66d5fe6 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -358,7 +358,8 @@ def __le__(self, other): TESTS:: - sage: QQ.CartesianProduct = sage.combinat.posets.cartesian_product.CartesianProductPoset # needed until #19269 is fixed + sage: from sage.combinat.posets.cartesian_product import CartesianProductPoset + sage: QQ.CartesianProduct = CartesianProductPoset # needed until #19269 is fixed sage: def le_sum(left, right): ....: return (sum(left) < sum(right) or ....: sum(left) == sum(right) and left[0] <= right[0]) @@ -367,6 +368,25 @@ def __le__(self, other): True sage: C((1/3, 2)) <= C((2, 2)) True + + The following example tests that the coercion gets involved in + comparisons; it can be simplified once #18182 is in merged. + :: + + sage: class MyCP(CartesianProductPoset): + ....: def _coerce_map_from_(self, S): + ....: if isinstance(S, self.__class__): + ....: S_factors = S.cartesian_factors() + ....: R_factors = self.cartesian_factors() + ....: if len(S_factors) == len(R_factors): + ....: if all(r.has_coerce_map_from(s) + ....: for r,s in zip(R_factors, S_factors)): + ....: return True + sage: QQ.CartesianProduct = MyCP + sage: A = cartesian_product((QQ, ZZ), order=le_sum) + sage: B = cartesian_product((QQ, QQ), order=le_sum) + sage: A((1/2, 4)) <= B((1/2, 5)) + True """ from sage.structure.element import have_same_parent if have_same_parent(self, other): From 9d21de90392c4850c09ec05d70f4b0d07ed21445 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 30 Sep 2015 13:43:23 +0200 Subject: [PATCH 1160/1872] Double-quote character ranges --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 05da588ae59..7924fb4f80f 100644 --- a/configure.ac +++ b/configure.ac @@ -491,7 +491,7 @@ else # Add the .0 because Debian/Ubuntu gives version numbers like # 4.6 instead of 4.6.4 (Trac #18885) case "$GXX_VERSION.0" in - [0-3].*|4.[0-3].*) + [[0-3]].*|4.[[0-3]].*) # Install our own GCC if the system-provided one is older than gcc-4.4. # * gcc-4.2.4 compiles a slow IML: # https://groups.google.com/forum/?fromgroups#!topic/sage-devel/Ux3t0dW2FSI From 619cd8c8e41f9728f9a7616860786163144b3ecc Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 13:45:15 +0200 Subject: [PATCH 1161/1872] copy code from #19048 --- src/sage/misc/mrange.py | 116 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index eb03223dbf6..c54529787fe 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -608,3 +608,119 @@ def cartesian_product_iterator(X): [()] """ return xmrange_iter(X, tuple) + + +def product_diagonal(A, B): + r""" + Return an iterator over the product of `A` and `B` which iterates + along the diagonal. + + INPUT: + + - ``A`` and ``B`` -- iterables (over a finite number of elements) + + OUTPUT: + + An iterator over `(a,b)` for `a \in A` and `b \in B`. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.misc import product_diagonal + sage: tuple(product_diagonal(srange(2), srange(2))) + ((0, 0), (0, 1), (1, 0), (1, 1)) + sage: tuple(product_diagonal(srange(4), srange(2))) + ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) + sage: tuple(product_diagonal(srange(2), srange(3))) + ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) + sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) + ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') + + TESTS: + + Check that all pairs are returned:: + + sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n + ....: for m in srange(5) for n in srange(5)) + True + + Check that everthing is loaded in the correct order:: + + sage: def it(s, n): + ....: for i in srange(n): + ....: print '%s loads item number %s' % (s, i) + ....: yield i + sage: for p in product_diagonal(it('A', 2), it('B', 2)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + (1, 1) + sage: for p in product_diagonal(it('A', 3), it('B', 2)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + (1, 1) + A loads item number 2 + (2, 0) + (2, 1) + sage: for p in product_diagonal(it('A', 2), it('B', 4)): + ....: print p + A loads item number 0 + B loads item number 0 + (0, 0) + B loads item number 1 + (0, 1) + A loads item number 1 + (1, 0) + B loads item number 2 + (0, 2) + (1, 1) + B loads item number 3 + (0, 3) + (1, 2) + (1, 3) + """ + # when writing this code I thought the solution would be shorter... + + class iter_as_list(list): + def __init__(self, iterable): + self.it = iter(iterable) + self.newdata = True + def __getitem__(self, i): + self.newdata = False + try: + while len(self) <= i: + self.append(next(self.it)) + self.newdata = True + except StopIteration: + raise + return list.__getitem__(self, i) + + from itertools import count + A = iter_as_list(A) + B = iter_as_list(B) + for s in count(): + for i in range(s+1): + stopped = False + try: + a = A[i] + except StopIteration: + stopped = True + try: + b = B[s-i] + except StopIteration: + stopped = True + if stopped: + continue + yield a, b + if not A.newdata and not B.newdata and s >= len(A) + len(B): + return From c4d28791ecb941e50fa1397c205e259a8ecc56a3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 13:45:52 +0200 Subject: [PATCH 1162/1872] rename to product_cantor_pairing --- src/sage/misc/mrange.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index c54529787fe..895efa0587e 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -610,7 +610,7 @@ def cartesian_product_iterator(X): return xmrange_iter(X, tuple) -def product_diagonal(A, B): +def product_cantor_pairing(A, B): r""" Return an iterator over the product of `A` and `B` which iterates along the diagonal. @@ -625,21 +625,21 @@ def product_diagonal(A, B): EXAMPLES:: - sage: from sage.rings.asymptotic.misc import product_diagonal - sage: tuple(product_diagonal(srange(2), srange(2))) + sage: from sage.rings.asymptotic.misc import product_cantor_pairing + sage: tuple(product_cantor_pairing(srange(2), srange(2))) ((0, 0), (0, 1), (1, 0), (1, 1)) - sage: tuple(product_diagonal(srange(4), srange(2))) + sage: tuple(product_cantor_pairing(srange(4), srange(2))) ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) - sage: tuple(product_diagonal(srange(2), srange(3))) + sage: tuple(product_cantor_pairing(srange(2), srange(3))) ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) - sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) + sage: tuple(''.join(p) for p in product_cantor_pairing('abc', 'xyz')) ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') TESTS: Check that all pairs are returned:: - sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n + sage: all(len(tuple(product_cantor_pairing(srange(m), srange(n)))) == m*n ....: for m in srange(5) for n in srange(5)) True @@ -649,7 +649,7 @@ def product_diagonal(A, B): ....: for i in srange(n): ....: print '%s loads item number %s' % (s, i) ....: yield i - sage: for p in product_diagonal(it('A', 2), it('B', 2)): + sage: for p in product_cantor_pairing(it('A', 2), it('B', 2)): ....: print p A loads item number 0 B loads item number 0 @@ -659,7 +659,7 @@ def product_diagonal(A, B): A loads item number 1 (1, 0) (1, 1) - sage: for p in product_diagonal(it('A', 3), it('B', 2)): + sage: for p in product_cantor_pairing(it('A', 3), it('B', 2)): ....: print p A loads item number 0 B loads item number 0 @@ -672,7 +672,7 @@ def product_diagonal(A, B): A loads item number 2 (2, 0) (2, 1) - sage: for p in product_diagonal(it('A', 2), it('B', 4)): + sage: for p in product_cantor_pairing(it('A', 2), it('B', 4)): ....: print p A loads item number 0 B loads item number 0 From a4697d3585a2396c8d338da06fdc887caf20e6bb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 13:48:50 +0200 Subject: [PATCH 1163/1872] fix import in doctest --- src/sage/misc/mrange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 895efa0587e..01eee13c016 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -625,7 +625,7 @@ def product_cantor_pairing(A, B): EXAMPLES:: - sage: from sage.rings.asymptotic.misc import product_cantor_pairing + sage: from sage.misc.mrange import product_cantor_pairing sage: tuple(product_cantor_pairing(srange(2), srange(2))) ((0, 0), (0, 1), (1, 0), (1, 1)) sage: tuple(product_cantor_pairing(srange(4), srange(2))) From e8460b9599cdcee722dbd6aea7d4382bb83d55a4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 13:50:30 +0200 Subject: [PATCH 1164/1872] improve docstring --- src/sage/misc/mrange.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 01eee13c016..c53d19c01cc 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -613,11 +613,12 @@ def cartesian_product_iterator(X): def product_cantor_pairing(A, B): r""" Return an iterator over the product of `A` and `B` which iterates - along the diagonal. + along the diagonals a la + :wikipedia:`Cantor pairing `. INPUT: - - ``A`` and ``B`` -- iterables (over a finite number of elements) + - ``A`` and ``B`` -- iterables. OUTPUT: From bf6f9118956a7aac842f675e5a019d198a0fb2e0 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 30 Sep 2015 13:54:19 +0200 Subject: [PATCH 1165/1872] Quote $1 --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 7924fb4f80f..3962c484f18 100644 --- a/configure.ac +++ b/configure.ac @@ -355,9 +355,9 @@ AC_DEFUN([SAGE_SHOULD_INSTALL_GCC], [ if test x$SAGE_INSTALL_GCC = xexists; then true # Do nothing if already installed elif test x$SAGE_INSTALL_GCC = xno; then - AC_MSG_WARN($1) + AC_MSG_WARN([$1]) else - AC_MSG_NOTICE([Installing GCC because] $1) + AC_MSG_NOTICE([Installing GCC because $1]) need_to_install_gcc=yes fi ]) @@ -370,9 +370,9 @@ AC_DEFUN([SAGE_MUST_INSTALL_GCC], [ if test x$SAGE_INSTALL_GCC = xexists; then true # Do nothing if already installed elif test x$SAGE_INSTALL_GCC = xno; then - AC_MSG_ERROR([SAGE_INSTALL_GCC is set to 'no', but] $1) + AC_MSG_ERROR([SAGE_INSTALL_GCC is set to 'no', but $1]) else - AC_MSG_NOTICE([Installing GCC because] $1) + AC_MSG_NOTICE([Installing GCC because $1]) need_to_install_gcc=yes fi ]) From 9e41be5b7ffd3ffa34991c3f686c0a618fef42ca Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 14:01:25 +0200 Subject: [PATCH 1166/1872] doctest with infinite iterator inputs --- src/sage/misc/mrange.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index c53d19c01cc..beda5d77430 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -636,6 +636,13 @@ def product_cantor_pairing(A, B): sage: tuple(''.join(p) for p in product_cantor_pairing('abc', 'xyz')) ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') + Infinite iterators are a valid as an input as well:: + + sage: from itertools import islice + sage: list(islice(product_cantor_pairing(ZZ, QQ), 14)) + [(0, 0), (0, 1), (1, 0), (0, -1), (1, 1), (-1, 0), (0, 1/2), + (1, -1), (-1, 1), (2, 0), (0, -1/2), (1, 1/2), (-1, -1), (2, 1)] + TESTS: Check that all pairs are returned:: From 97cb59c8ef71cd3a9e8df6086a2ff377baf3392f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 14:01:42 +0200 Subject: [PATCH 1167/1872] add seealso blocks --- src/sage/misc/mrange.py | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index beda5d77430..7c528f88de4 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -198,6 +198,14 @@ def mrange_iter(iter_list, typ=list): sage: mrange_iter([]) [[]] + .. SEEALSO:: + + :class:`xmrange_iter`, + :func:`mrange`, + :class:`xmrange`, + :func:`cartesian_product_iterator`, + :func:`product_cantor_pairing`. + AUTHORS: - Joel B. Mohler @@ -302,6 +310,14 @@ class xmrange_iter: (389, 'orange') (389, 'horse') + .. SEEALSO:: + + :func:`mrange_iter`, + :func:`mrange`, + :class:`xmrange`, + :func:`cartesian_product_iterator`, + :func:`product_cantor_pairing`. + AUTHORS: - Joel B. Mohler @@ -457,6 +473,13 @@ def mrange(sizes, typ=list): sage: mrange([]) [[]] + .. SEEALSO:: + + :func:`mrange_iter`, + :class:`xmrange_iter`, + :class:`xmrange`, + :func:`cartesian_product_iterator`, + :func:`product_cantor_pairing`. AUTHORS: @@ -559,6 +582,14 @@ class xmrange: (389, 'orange') (389, 'horse') + .. SEEALSO:: + + :func:`mrange_iter`, + :class:`xmrange_iter`, + :func:`mrange`, + :func:`cartesian_product_iterator`, + :func:`product_cantor_pairing`. + AUTHORS: - Jon Hanke @@ -606,6 +637,14 @@ def cartesian_product_iterator(X): [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')] sage: list(cartesian_product_iterator([])) [()] + + .. SEEALSO:: + + :func:`mrange_iter`, + :class:`xmrange_iter`, + :func:`mrange`, + :class:`xmrange`, + :func:`product_cantor_pairing`. """ return xmrange_iter(X, tuple) @@ -643,6 +682,14 @@ def product_cantor_pairing(A, B): [(0, 0), (0, 1), (1, 0), (0, -1), (1, 1), (-1, 0), (0, 1/2), (1, -1), (-1, 1), (2, 0), (0, -1/2), (1, 1/2), (-1, -1), (2, 1)] + .. SEEALSO:: + + :func:`mrange_iter`, + :class:`xmrange_iter`, + :func:`mrange`, + :class:`xmrange`, + :func:`cartesian_product_iterator`. + TESTS: Check that all pairs are returned:: From 17229c620b4aff47161b725de2ebb4f890cfc2af Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 14:02:34 +0200 Subject: [PATCH 1168/1872] extend AUTHROS --- src/sage/misc/mrange.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 7c528f88de4..5601c330094 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -8,6 +8,8 @@ - William Stein (2006-07-19) - Jon Hanke + +- Daniel Krenn """ #***************************************************************************** From ba99790d116341acfd9a691ac0a2f26f705aa988 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 14:27:53 +0200 Subject: [PATCH 1169/1872] use new product_cantor_pairing and delete old product_diagonal --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 +- src/sage/rings/asymptotic/term_monoid.py | 120 +------------------ 2 files changed, 4 insertions(+), 120 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 9e1c15edb83..81156397afd 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1112,12 +1112,12 @@ def some_elements(self): O(z^(-1/2)), -8*z^(3/2) + O(z^(1/2))) """ - from sage.rings.asymptotic.term_monoid import product_diagonal + from sage.misc.mrange import product_cantor_pairing from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) return iter(-self(e)**3 + self(o) - for e, o in product_diagonal( + for e, o in product_cantor_pairing( E.some_elements(), O.some_elements())) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index f13b8253f4f..3a35dedacf9 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -205,123 +205,6 @@ import sage - -def product_diagonal(A, B): - r""" - Return an iterator over the product of `A` and `B` which iterates - along the diagonal. - - INPUT: - - - ``A`` and ``B`` -- iterables (over a finite number of elements) - - OUTPUT: - - An iterator over `(a,b)` for `a \in A` and `b \in B`. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.term_monoid import product_diagonal - sage: tuple(product_diagonal(srange(2), srange(2))) - ((0, 0), (0, 1), (1, 0), (1, 1)) - sage: tuple(product_diagonal(srange(4), srange(2))) - ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) - sage: tuple(product_diagonal(srange(2), srange(3))) - ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) - sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) - ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') - - TESTS: - - Check that all pairs are returned:: - - sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n - ....: for m in srange(5) for n in srange(5)) - True - - Check that everthing is loaded in the correct order:: - - sage: def it(s, n): - ....: for i in srange(n): - ....: print '%s loads item number %s' % (s, i) - ....: yield i - sage: for p in product_diagonal(it('A', 2), it('B', 2)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - (1, 1) - sage: for p in product_diagonal(it('A', 3), it('B', 2)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - (1, 1) - A loads item number 2 - (2, 0) - (2, 1) - sage: for p in product_diagonal(it('A', 2), it('B', 4)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - B loads item number 2 - (0, 2) - (1, 1) - B loads item number 3 - (0, 3) - (1, 2) - (1, 3) - """ - # when writing this code I thought the solution would be shorter... - - class iter_as_list(list): - def __init__(self, iterable): - self.it = iter(iterable) - self.newdata = True - def __getitem__(self, i): - self.newdata = False - try: - while len(self) <= i: - self.append(next(self.it)) - self.newdata = True - except StopIteration: - raise - return list.__getitem__(self, i) - - from itertools import count - A = iter_as_list(A) - B = iter_as_list(B) - for s in count(): - for i in range(s+1): - stopped = False - try: - a = A[i] - except StopIteration: - stopped = True - try: - b = B[s-i] - except StopIteration: - stopped = True - if stopped: - continue - yield a, b - if not A.newdata and not B.newdata and s >= len(A) + len(B): - return - - def absorption(left, right): r""" Let one of the two passed terms absorb the other. @@ -2073,7 +1956,8 @@ def some_elements(self): z^2, -2*z^(1/2), 2*z^(-1/2), -z^2, z^(-2)) """ - return iter(self(g, c) for g, c in product_diagonal( + from sage.misc.mrange import product_cantor_pairing + return iter(self(g, c) for g, c in product_cantor_pairing( self.growth_group.some_elements(), iter(c for c in self.base_ring().some_elements() if c != 0))) From 298ea502e737df767ee4341761d9eff149a88cb4 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 30 Sep 2015 14:30:50 +0200 Subject: [PATCH 1170/1872] Add check for C++11 --- Makefile | 3 +- configure.ac | 37 ++----- m4/ax_cxx_compile_stdcxx_11.m4 | 172 +++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 32 deletions(-) create mode 100644 m4/ax_cxx_compile_stdcxx_11.m4 diff --git a/Makefile b/Makefile index a7df7e96cb9..0ec44481c04 100644 --- a/Makefile +++ b/Makefile @@ -119,8 +119,7 @@ ptestoptional: ptestall # just an alias ptestoptionallong: ptestalllong # just an alias -configure: configure.ac src/bin/sage-version.sh \ - m4/ax_c_check_flag.m4 m4/ax_gcc_option.m4 m4/ax_gcc_version.m4 m4/ax_gxx_option.m4 m4/ax_gxx_version.m4 m4/ax_prog_perl_version.m4 +configure: configure.ac src/bin/sage-version.sh m4/*.m4 ./bootstrap -d install: diff --git a/configure.ac b/configure.ac index 3962c484f18..17b9379ff15 100644 --- a/configure.ac +++ b/configure.ac @@ -435,6 +435,11 @@ AC_CHECK_HEADER([complex.h],[],[ # Check compiler characterists ############################################################################### +AX_CXX_COMPILE_STDCXX_11([], optional) +if test $HAVE_CXX11 != 1; then + SAGE_MUST_INSTALL_GCC([your C++ compiler does not support C++11]) +fi + AC_LANG(C) if test -z "$CC"; then SAGE_MUST_INSTALL_GCC([a C compiler is missing]) @@ -491,37 +496,9 @@ else # Add the .0 because Debian/Ubuntu gives version numbers like # 4.6 instead of 4.6.4 (Trac #18885) case "$GXX_VERSION.0" in - [[0-3]].*|4.[[0-3]].*) - # Install our own GCC if the system-provided one is older than gcc-4.4. - # * gcc-4.2.4 compiles a slow IML: - # https://groups.google.com/forum/?fromgroups#!topic/sage-devel/Ux3t0dW2FSI - # * gcc-4.3 might have trouble building ATLAS: - # https://groups.google.com/forum/?fromgroups#!topic/sage-devel/KCeFqQ_w2FE + [[0-3]].*|4.[[0-7]].*) + # Install our own GCC if the system-provided one is older than gcc-4.8. SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION, which is quite old]);; - 4.4.*|4.5.*) - # GCC 4.4.x and GCC 4.5.x fail to compile PARI/GP on ia64: - # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46044 - if test x`uname -m` = xia64; then - SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION on ia64]) - AC_MSG_NOTICE([gcc <= 4.5 fails to compile PARI/GP on ia64]) - fi;; - 4.6.*) - # Also install GCC if we have version 4.6.* which is - # known to give trouble within Sage: - # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48702 - # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48774 - # * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52061 - # * https://groups.google.com/d/msg/sage-release/xgmJ3nAcUOY/jH8OZjftYRsJ - SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION]) - AC_MSG_NOTICE([g++-4.6.* has known bugs affecting Sage]);; - 4.7.0) - # GCC 4.7.0 is very broken on ia64, see - # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48496 - # This is fixed in GCC 4.7.1. - if test x`uname -m` = xia64; then - SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION on ia64]) - AC_MSG_NOTICE([g++-4.7.0 has a serious bug on ia64]) - fi;; esac # The following tests check that the version of the compilers diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 00000000000..516da37e822 --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,172 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++11 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX11 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + struct Base { + virtual void f() {} + }; + struct Child : public Base { + virtual void f() override {} + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; + auto l = [](){}; + // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] + struct use_l { use_l() { l(); } }; + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this + namespace test_template_alias_sfinae { + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { + func(0); + } + } + + // Check for C++11 attribute support + void noret [[noreturn]] () { throw 0; } +]]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl + m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], + [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], + [$2], [optional], [ax_cxx_compile_cxx11_required=false], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 features by default, + ax_cv_cxx_compile_cxx11, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [ax_cv_cxx_compile_cxx11=yes], + [ax_cv_cxx_compile_cxx11=no])]) + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++11 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for switch in -std=c++11 -std=c++0x +std=c++11 "-h std=c++11"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + AC_MSG_NOTICE([No compiler with C++11 support was found]) + else + HAVE_CXX11=1 + AC_DEFINE(HAVE_CXX11,1, + [define if the compiler supports basic C++11 syntax]) + fi + + AC_SUBST(HAVE_CXX11) + fi +]) From 8204cfa2718fe9568f24b3e44ed0b091b8d70069 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 14:31:26 +0200 Subject: [PATCH 1171/1872] remove old product_diagonal (superseded by #19319) --- src/sage/rings/asymptotic/misc.py | 116 ------------------------------ 1 file changed, 116 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index fa30f1537cc..dcc5097be84 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -367,119 +367,3 @@ def find_mergedoverlapping_index(A, B): return B[:i] + A + B[i+len(A):], B raise ValueError('Input does not have an overlap.') - - -def product_diagonal(A, B): - r""" - Return an iterator over the product of `A` and `B` which iterates - along the diagonal. - - INPUT: - - - ``A`` and ``B`` -- iterables (over a finite number of elements) - - OUTPUT: - - An iterator over `(a,b)` for `a \in A` and `b \in B`. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.misc import product_diagonal - sage: tuple(product_diagonal(srange(2), srange(2))) - ((0, 0), (0, 1), (1, 0), (1, 1)) - sage: tuple(product_diagonal(srange(4), srange(2))) - ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) - sage: tuple(product_diagonal(srange(2), srange(3))) - ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) - sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) - ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') - - TESTS: - - Check that all pairs are returned:: - - sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n - ....: for m in srange(5) for n in srange(5)) - True - - Check that everthing is loaded in the correct order:: - - sage: def it(s, n): - ....: for i in srange(n): - ....: print '%s loads item number %s' % (s, i) - ....: yield i - sage: for p in product_diagonal(it('A', 2), it('B', 2)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - (1, 1) - sage: for p in product_diagonal(it('A', 3), it('B', 2)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - (1, 1) - A loads item number 2 - (2, 0) - (2, 1) - sage: for p in product_diagonal(it('A', 2), it('B', 4)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - B loads item number 2 - (0, 2) - (1, 1) - B loads item number 3 - (0, 3) - (1, 2) - (1, 3) - """ - # when writing this code I thought the solution would be shorter... - - class iter_as_list(list): - def __init__(self, iterable): - self.it = iter(iterable) - self.newdata = True - def __getitem__(self, i): - self.newdata = False - try: - while len(self) <= i: - self.append(next(self.it)) - self.newdata = True - except StopIteration: - raise - return list.__getitem__(self, i) - - from itertools import count - A = iter_as_list(A) - B = iter_as_list(B) - for s in count(): - for i in range(s+1): - stopped = False - try: - a = A[i] - except StopIteration: - stopped = True - try: - b = B[s-i] - except StopIteration: - stopped = True - if stopped: - continue - yield a, b - if not A.newdata and not B.newdata and s >= len(A) + len(B): - return From d9ba9b2a3b3fc59d4b98e85f87cc4575036f139f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 15:25:28 +0200 Subject: [PATCH 1172/1872] trac #19042: Faster package check --- src/sage/sat/solvers/satsolver.pyx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index 801c9c76b2a..c3baf8cf5d4 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -14,6 +14,7 @@ AUTHORS: - Martin Albrecht (2012): first version """ +from sage.misc.package import PackageNotFoundError cdef class SatSolver: def __cinit__(self, *args, **kwds): @@ -314,13 +315,19 @@ def SAT(solver=None): #vars: 0, #lits: 0, #clauses: 0, #learnt: 0, #assigns: 0 """ - from sage.misc.package import is_package_installed + if solver is None: + try: + from sage.sat.solvers.cryptominisat.cryptominisat import CryptoMiniSat + cryptominisat_available = True + except ImportError: + cryptominisat_available = False + if (solver == 'cryptominisat' or - (solver is None and is_package_installed('cryptominisat'))): + (solver is None and cryptominisat_available)): try: from sage.sat.solvers.cryptominisat.cryptominisat import CryptoMiniSat except ImportError: - raise ImportError("To enable this feature, run 'sage -i cryptominisat'.") + raise PackageNotFoundError("To enable this feature, run 'sage -i cryptominisat'.") return CryptoMiniSat() elif (solver == "LP" or solver is None): from sat_lp import SatLP From d35f98f88314101d141e185f7ed0f385aa32860a Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 15:26:00 +0200 Subject: [PATCH 1173/1872] trac #19042: Remove KeyboardInterrupt check --- src/sage/sat/solvers/sat_lp.pyx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/sat/solvers/sat_lp.pyx b/src/sage/sat/solvers/sat_lp.pyx index 024ddad5a2e..bffe684a047 100644 --- a/src/sage/sat/solvers/sat_lp.pyx +++ b/src/sage/sat/solvers/sat_lp.pyx @@ -108,9 +108,6 @@ class SatLP(SatSolver): - If this instance is UNSAT: ``False`` - - If the solver was interrupted before deciding satisfiability - ``None``. - EXAMPLE:: sage: def is_bipartite_SAT(G): @@ -133,8 +130,6 @@ class SatLP(SatSolver): self._LP.solve() except MIPSolverException: return False - except KeyboardInterrupt: - return None b = self._LP.get_values(self._vars) n = max(b) From 470500f86e188164d23cb5c417ebecbab10f43cc Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 15:27:38 +0200 Subject: [PATCH 1174/1872] trac #19042: pyx->py --- src/module_list.py | 3 --- src/sage/sat/solvers/{sat_lp.pyx => sat_lp.py} | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) rename src/sage/sat/solvers/{sat_lp.pyx => sat_lp.py} (99%) diff --git a/src/module_list.py b/src/module_list.py index feca321996a..7108872b586 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1605,9 +1605,6 @@ def uname_specific(name, value, alternative): Extension('sage.sat.solvers.satsolver', sources = ['sage/sat/solvers/satsolver.pyx']), - Extension('sage.sat.solvers.sat_lp', - sources = ['sage/sat/solvers/sat_lp.pyx']), - ################################ ## ## sage.schemes diff --git a/src/sage/sat/solvers/sat_lp.pyx b/src/sage/sat/solvers/sat_lp.py similarity index 99% rename from src/sage/sat/solvers/sat_lp.pyx rename to src/sage/sat/solvers/sat_lp.py index bffe684a047..7c8b2fe2e8d 100644 --- a/src/sage/sat/solvers/sat_lp.pyx +++ b/src/sage/sat/solvers/sat_lp.py @@ -6,7 +6,7 @@ can be expected to be slower than when using :class:`~sage.sat.solvers.cryptominisat.cryptominisat.CryptoMiniSat`. """ -from satsolver cimport SatSolver +from satsolver import SatSolver from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException class SatLP(SatSolver): From e9309e7c826982f251825f1c8f959723daf0ab35 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 15:32:17 +0200 Subject: [PATCH 1175/1872] trac #19042: Wrong text --- src/sage/sat/solvers/satsolver.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index c3baf8cf5d4..9666c7cae22 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -327,7 +327,7 @@ def SAT(solver=None): try: from sage.sat.solvers.cryptominisat.cryptominisat import CryptoMiniSat except ImportError: - raise PackageNotFoundError("To enable this feature, run 'sage -i cryptominisat'.") + raise PackageNotFoundError("cryptominisat") return CryptoMiniSat() elif (solver == "LP" or solver is None): from sat_lp import SatLP From 9a773111ae58047835319f8ced3668000633604b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 15:38:16 +0200 Subject: [PATCH 1176/1872] deal with product(empty, infinite) --- src/sage/misc/mrange.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 5601c330094..55605fbea74 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -745,6 +745,14 @@ def product_cantor_pairing(A, B): (0, 3) (1, 2) (1, 3) + + :: + + sage: from itertools import count + sage: list(product_cantor_pairing([], count())) + [] + sage: list(product_cantor_pairing(count(), [])) + [] """ # when writing this code I thought the solution would be shorter... @@ -765,7 +773,11 @@ def __getitem__(self, i): from itertools import count A = iter_as_list(A) B = iter_as_list(B) - for s in count(): + try: + yield A[0], B[0] + except StopIteration: + return + for s in count(1): for i in range(s+1): stopped = False try: From 70185c3a13f573cf1eacbec2eb2122082e6c375f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 15:39:18 +0200 Subject: [PATCH 1177/1872] remove unneccesary try/except block --- src/sage/misc/mrange.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 55605fbea74..7f5e4948573 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -762,12 +762,9 @@ def __init__(self, iterable): self.newdata = True def __getitem__(self, i): self.newdata = False - try: - while len(self) <= i: - self.append(next(self.it)) - self.newdata = True - except StopIteration: - raise + while len(self) <= i: + self.append(next(self.it)) + self.newdata = True return list.__getitem__(self, i) from itertools import count From 74547e6aac076261a6f7da6577d771eb9a830e60 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 15:49:56 +0200 Subject: [PATCH 1178/1872] fix code after changes by previous merge --- src/sage/rings/asymptotic/growth_group_cartesian.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 89cdcbe2dea..8c91ae6bd05 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -186,9 +186,9 @@ def create_object(self, version, args, **kwds): CartesianProductGrowthGroups = CartesianProductFactory('CartesianProductGrowthGroups') -from sage.combinat.posets.cartesian_product import CartesianProductPosets +from sage.combinat.posets.cartesian_product import CartesianProductPoset from sage.rings.asymptotic.growth_group import GenericGrowthGroup -class GenericProduct(CartesianProductPosets, GenericGrowthGroup): +class GenericProduct(CartesianProductPoset, GenericGrowthGroup): r""" A cartesian product of growth groups. @@ -216,7 +216,7 @@ class GenericProduct(CartesianProductPosets, GenericGrowthGroup): .. SEEALSO:: :class:`~sage.sets.cartesian_product.CartesianProduct`, - :class:`~sage.combinat.posets.cartesian_product.CartesianProductPosets`. + :class:`~sage.combinat.posets.cartesian_product.CartesianProductPoset`. """ def _element_constructor_(self, data): @@ -444,7 +444,7 @@ def variable_names(self): return tuple(v for v, _ in groupby(vars)) - class Element(CartesianProductPosets.Element): + class Element(CartesianProductPoset.Element): def _repr_(self): r""" A representation string for this cartesian product element. From d4dec2be9048e1b8fc9de246fe5c698d3676a13a Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 30 Sep 2015 15:51:43 +0200 Subject: [PATCH 1179/1872] Trac #19319: alternative implementation --- src/sage/misc/mrange.py | 53 +++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 7f5e4948573..4a60ab31aeb 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -711,9 +711,9 @@ def product_cantor_pairing(A, B): A loads item number 0 B loads item number 0 (0, 0) + A loads item number 1 B loads item number 1 (0, 1) - A loads item number 1 (1, 0) (1, 1) sage: for p in product_cantor_pairing(it('A', 3), it('B', 2)): @@ -721,12 +721,12 @@ def product_cantor_pairing(A, B): A loads item number 0 B loads item number 0 (0, 0) + A loads item number 1 B loads item number 1 (0, 1) - A loads item number 1 (1, 0) - (1, 1) A loads item number 2 + (1, 1) (2, 0) (2, 1) sage: for p in product_cantor_pairing(it('A', 2), it('B', 4)): @@ -734,9 +734,9 @@ def product_cantor_pairing(A, B): A loads item number 0 B loads item number 0 (0, 0) + A loads item number 1 B loads item number 1 (0, 1) - A loads item number 1 (1, 0) B loads item number 2 (0, 2) @@ -756,37 +756,28 @@ def product_cantor_pairing(A, B): """ # when writing this code I thought the solution would be shorter... - class iter_as_list(list): - def __init__(self, iterable): - self.it = iter(iterable) - self.newdata = True - def __getitem__(self, i): - self.newdata = False - while len(self) <= i: - self.append(next(self.it)) - self.newdata = True - return list.__getitem__(self, i) from itertools import count - A = iter_as_list(A) - B = iter_as_list(B) - try: - yield A[0], B[0] - except StopIteration: - return - for s in count(1): - for i in range(s+1): - stopped = False + from sage.rings.infinity import infinity + A = iter(A) + B = iter(B) + max_A = infinity + max_B = infinity + cache_A = [] + cache_B = [] + for s in count(): + if s <= max_A: try: - a = A[i] + cache_A.append(next(A)) except StopIteration: - stopped = True + max_A = s-1 + if s <= max_B: try: - b = B[s-i] + cache_B.append(next(B)) except StopIteration: - stopped = True - if stopped: - continue - yield a, b - if not A.newdata and not B.newdata and s >= len(A) + len(B): + max_B = s-1 + if s > max_A + max_B or max_A < 0 or max_B < 0: return + + for i in range(max(0, s-max_B), min(s, max_A)+1): + yield cache_A[i], cache_B[s-i] From 09221f0e4cffd3802ec574f84a846a399560badf Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 16:01:37 +0200 Subject: [PATCH 1180/1872] fixup due to changes in #18587 (coming from #18223) --- src/sage/rings/asymptotic/growth_group_cartesian.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index dea803bff66..9d6710a0ee7 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -231,7 +231,7 @@ def __classcall__(cls, *args, **kwds): sage: GrowthGroup('x^ZZ * y^ZZ') # indirect doctest Growth Group x^ZZ * y^ZZ """ - return CartesianProductPosets.__classcall__(cls, *args, **kwds) + return CartesianProductPoset.__classcall__(cls, *args, **kwds) def __init__(self, sets, category, **kwds): @@ -245,7 +245,7 @@ def __init__(self, sets, category, **kwds): Growth Group x^ZZ * y^ZZ """ order = kwds.pop('order') - CartesianProductPosets.__init__(self, sets, category, order, **kwds) + CartesianProductPoset.__init__(self, sets, category, order, **kwds) vars = sum(iter(factor.variable_names() for factor in self.cartesian_factors()), @@ -271,7 +271,7 @@ def __hash__(self): sage: hash(GrowthGroup('x^ZZ * y^ZZ')) # indirect doctest, random -1 """ - return CartesianProductPosets.__hash__(self) + return CartesianProductPoset.__hash__(self) def _element_constructor_(self, data): From fde8e6d09f41645ec4faf9d071cf60c7b35ef9e3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 30 Sep 2015 16:40:03 +0200 Subject: [PATCH 1181/1872] minor changes to code: spacings, PEP8, remove comment --- src/sage/misc/mrange.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 4a60ab31aeb..ecb0c9b4329 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -754,11 +754,9 @@ def product_cantor_pairing(A, B): sage: list(product_cantor_pairing(count(), [])) [] """ - # when writing this code I thought the solution would be shorter... - - from itertools import count from sage.rings.infinity import infinity + A = iter(A) B = iter(B) max_A = infinity @@ -770,14 +768,14 @@ def product_cantor_pairing(A, B): try: cache_A.append(next(A)) except StopIteration: - max_A = s-1 + max_A = s - 1 if s <= max_B: try: cache_B.append(next(B)) except StopIteration: - max_B = s-1 + max_B = s - 1 if s > max_A + max_B or max_A < 0 or max_B < 0: return - for i in range(max(0, s-max_B), min(s, max_A)+1): + for i in range(max(0, s-max_B), min(s, max_A) + 1): yield cache_A[i], cache_B[s-i] From b52a8bce2a3cabc089ae6a4b91e38a38af94e9d8 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 16:47:11 +0200 Subject: [PATCH 1182/1872] trac #19061: utf8 for graph.py --- src/sage/graphs/graph.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 77bf03c1e42..ef59285c82d 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Undirected graphs From edb16b0ed12c36dcc5e8d0e262ad38c3ca3f7ad8 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 30 Sep 2015 16:55:03 +0200 Subject: [PATCH 1183/1872] Typo --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 3962c484f18..ad01e0392f9 100644 --- a/configure.ac +++ b/configure.ac @@ -432,7 +432,7 @@ AC_CHECK_HEADER([complex.h],[],[ ############################################################################### -# Check compiler characterists +# Check compiler characteristics ############################################################################### AC_LANG(C) From 8fa7a280222ee3bccdc91ecce9f58ed88cd1c6f1 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 17:18:13 +0200 Subject: [PATCH 1184/1872] trac #19061: Workaround Cython injection --- src/sage/misc/rest_index_of_methods.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/rest_index_of_methods.py b/src/sage/misc/rest_index_of_methods.py index 9e120a1b2ce..c928f036c62 100644 --- a/src/sage/misc/rest_index_of_methods.py +++ b/src/sage/misc/rest_index_of_methods.py @@ -7,6 +7,8 @@ {INDEX_OF_FUNCTIONS} """ +from sage.misc.sageinspect import _extract_embedded_position + def gen_rest_table_index(list_of_entries, names=None, sort=True, only_local_functions=True): r""" Return a ReST table describing a list of functions. @@ -170,9 +172,15 @@ def gen_rest_table_index(list_of_entries, names=None, sort=True, only_local_func else: continue + # Extract lines injected by cython + doc = e.__doc__ + doc_tmp = _extract_embedded_position(doc) + if doc_tmp: + doc = doc_tmp[0] + # Descriptions of the method/function - if e.__doc__: - desc = e.__doc__.split('\n\n')[0] # first paragraph + if doc: + desc = doc.split('\n\n')[0] # first paragraph desc = " ".join([x.strip() for x in desc.splitlines()]) # concatenate lines desc = desc.strip() # remove leading spaces else: From a4ac4458b8f5aa633047299f9db2269fdf4e74ca Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 22:20:22 +0200 Subject: [PATCH 1185/1872] trac #19042: Review --- src/doc/en/reference/sat/index.rst | 2 +- src/sage/sat/all.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/en/reference/sat/index.rst b/src/doc/en/reference/sat/index.rst index d4cf6adfbe0..7f6314ac5d8 100644 --- a/src/doc/en/reference/sat/index.rst +++ b/src/doc/en/reference/sat/index.rst @@ -36,7 +36,7 @@ We now show how to solve a simple SAT problem. :: In Sage's notation:: - sage: solver = SAT() # random + sage: solver = SAT() sage: solver.add_clause( ( 1, 2, 3) ) sage: solver.add_clause( ( 1, 2, -3) ) sage: solver() # random diff --git a/src/sage/sat/all.py b/src/sage/sat/all.py index 63993752958..d4beeb2a9a1 100644 --- a/src/sage/sat/all.py +++ b/src/sage/sat/all.py @@ -1 +1,2 @@ -from solvers.satsolver import SAT +from sage.misc.lazy_import import lazy_import +lazy_import('sage.sat.solvers.satsolver', 'SAT') From d330146452be5ce3cdc491868f1320f05c882445 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 23 Sep 2015 15:11:41 +0200 Subject: [PATCH 1186/1872] Upgrade PARI/GP to latest master --- build/pkgs/pari/checksums.ini | 6 +- build/pkgs/pari/package-version.txt | 2 +- build/pkgs/pari/patches/KERNELCFLAGS.patch | 16 -- build/pkgs/pari/patches/README.txt | 10 -- build/pkgs/pari/patches/det_garbage.patch | 55 ------ build/pkgs/pari/patches/perl_regex.patch | 200 --------------------- build/pkgs/pari/spkg-install | 9 +- src/sage/libs/pari/paridecl.pxd | 101 ++++++++++- src/sage_setup/autogen/pari/parser.py | 2 +- 9 files changed, 111 insertions(+), 290 deletions(-) delete mode 100644 build/pkgs/pari/patches/KERNELCFLAGS.patch delete mode 100644 build/pkgs/pari/patches/det_garbage.patch delete mode 100644 build/pkgs/pari/patches/perl_regex.patch diff --git a/build/pkgs/pari/checksums.ini b/build/pkgs/pari/checksums.ini index 8870cbb86ee..c62c530a888 100644 --- a/build/pkgs/pari/checksums.ini +++ b/build/pkgs/pari/checksums.ini @@ -1,4 +1,4 @@ tarball=pari-VERSION.tar.gz -sha1=307409c3917f6df71d2e10640c119e7d31c1f2e6 -md5=41936ce2dce6bd00a662bf43a772685f -cksum=855809013 +sha1=fa23e0c8b6e38a356048d19224dc9b9658d77724 +md5=c753faaa4780de5ad8d461f0ffd70ecf +cksum=1220765312 diff --git a/build/pkgs/pari/package-version.txt b/build/pkgs/pari/package-version.txt index 8db184f072c..2b25bd18c62 100644 --- a/build/pkgs/pari/package-version.txt +++ b/build/pkgs/pari/package-version.txt @@ -1 +1 @@ -2.8-1637-g489005a.p1 +2.8-1813-g6157df4.p0 diff --git a/build/pkgs/pari/patches/KERNELCFLAGS.patch b/build/pkgs/pari/patches/KERNELCFLAGS.patch deleted file mode 100644 index 537dbb52d1e..00000000000 --- a/build/pkgs/pari/patches/KERNELCFLAGS.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff -ru src/config/get_cc b/config/get_cc ---- src/config/get_cc 2014-02-01 21:41:54.534348273 +0100 -+++ b/config/get_cc 2014-02-01 21:42:50.850930971 +0100 -@@ -94,7 +94,11 @@ - OPTFLAGS="$OPTFLAGS -fno-strict-aliasing" - fi - rm -f $exe $exe$exe_suff -- KERNELCFLAGS=-funroll-loops -+ if [ "$SAGE_DEBUG" = yes ]; then -+ KERNELCFLAGS=-O1 -+ else -+ KERNELCFLAGS=-funroll-loops -+ fi - - DBGFLAGS=${DBGFLAGS:-"-g $warn"} - # Specific optimisations for some architectures diff --git a/build/pkgs/pari/patches/README.txt b/build/pkgs/pari/patches/README.txt index 93ac577bd55..d9aef73659a 100644 --- a/build/pkgs/pari/patches/README.txt +++ b/build/pkgs/pari/patches/README.txt @@ -11,17 +11,7 @@ Patches to configuration files: Darwin. Submitted upstream, but upstream only applied it for PowerPC. Since this doesn't break anything and only improves performance, add the flag unconditionally. -* KERNELCFLAGS.patch (Jeroen Demeyer): when SAGE_DEBUG=yes, compile - kernel files with -O1 instead of -funroll-loops; -O0 gives a - segmentation fault on some OS X systems when doing - factor(10356613*10694706299664611221) - See #13921, also reported upstream: - - http://pari.math.u-bordeaux.fr/archives/pari-dev-1301/msg00000.html C files: -* det_garbage.patch (Jeroen Demeyer, #15654): When computing a - determinant(), only collect garbage once per outer loop iteration. - Better increase PARI stack size instead of collecting garbage too - often. * public_memory_functions.patch (Jeroen Demeyer, #16997): Make some of PARI's private memory functions public to improve interface with Sage. diff --git a/build/pkgs/pari/patches/det_garbage.patch b/build/pkgs/pari/patches/det_garbage.patch deleted file mode 100644 index ab7af6643af..00000000000 --- a/build/pkgs/pari/patches/det_garbage.patch +++ /dev/null @@ -1,55 +0,0 @@ -diff --git a/src/basemath/alglin1.c b/src/basemath/alglin1.c -index cada9eb..515eba9 100644 ---- a/src/basemath/alglin1.c -+++ b/src/basemath/alglin1.c -@@ -248,6 +248,7 @@ gen_det(GEN a, void *E, const struct bb_field *ff) - a = RgM_shallowcopy(a); - for (i=1; ired(E,gcoeff(a,k,i)); -@@ -272,7 +273,7 @@ gen_det(GEN a, void *E, const struct bb_field *ff) - for (j=i+1; j<=nbco; j++) - { - gcoeff(a,j,k) = ff->add(E, gcoeff(a,j,k), ff->mul(E,m,gcoeff(a,j,i))); -- if (gc_needed(av,1)) -+ if (gc_needed(av,1) && (garbage++ == 0)) - { - if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i); - gerepileall(av,4, &a,&x,&q,&m); -@@ -3722,6 +3723,7 @@ det_simple_gauss(GEN a, GEN data, pivot_fun pivot) - a = RgM_shallowcopy(a); - for (i=1; i nbco) return gerepilecopy(av, gcoeff(a,i,i)); - if (k != i) -@@ -3741,7 +3743,7 @@ det_simple_gauss(GEN a, GEN data, pivot_fun pivot) - for (j=i+1; j<=nbco; j++) - { - gcoeff(a,j,k) = gsub(gcoeff(a,j,k), gmul(m,gcoeff(a,j,i))); -- if (gc_needed(av,3)) -+ if (gc_needed(av,3) && (garbage++ == 0)) - { - if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i); - gerepileall(av,2, &a,&x); -@@ -3792,6 +3794,7 @@ det_bareiss(GEN a) - { - GEN ci, ck, m; - int diveuc = (gequal1(pprec)==0); -+ int garbage = 0; /* Only gerepile() once per loop iteration */ - - p = gcoeff(a,i,i); - if (gequal0(p)) -@@ -3828,7 +3831,7 @@ det_bareiss(GEN a) - GEN p1 = gsub(gmul(p,gel(ck,j)), gmul(m,gel(ci,j))); - if (diveuc) p1 = mydiv(p1,pprec); - gel(ck,j) = gerepileupto(av2, p1); -- if (gc_needed(av,2)) -+ if (gc_needed(av,2) && (garbage++ == 0)) - { - if(DEBUGMEM>1) pari_warn(warnmem,"det. col = %ld",i); - gerepileall(av,2, &a,&pprec); diff --git a/build/pkgs/pari/patches/perl_regex.patch b/build/pkgs/pari/patches/perl_regex.patch deleted file mode 100644 index 038f4d604e8..00000000000 --- a/build/pkgs/pari/patches/perl_regex.patch +++ /dev/null @@ -1,200 +0,0 @@ -commit 257750686ae1fe928a2b4b489844c1b57a108bd3 -Author: Karim Belabas -Date: Tue Jul 14 15:23:42 2015 +0200 - - doc_make: escape all {} in regexps [ perl-5.22 warns on these => fatal - -diff --git a/src/desc/doc_make b/src/desc/doc_make -index bb41bc9..8521a9d 100755 ---- a/src/desc/doc_make -+++ b/src/desc/doc_make -@@ -38,13 +38,13 @@ while () - $v =~ s/\[\]/[\\,]/g; - $v =~ s/(\w\w+)/\\var{$1}/g; - $v =~ s/\^([a-z])/\\hbox{\\kbd{\\pow}}$1/g; -- $v =~ s/\\var{flag}/\\fl/g; -- $v =~ s/\\var{(\d+)}/{$1}/g; -+ $v =~ s/\\var\{flag\}/\\fl/g; -+ $v =~ s/\\var\{(\d+)\}/{$1}/g; - $v =~ s/_/\\_/g; # don't merge with first subst: \var{} rule kills it - - $v = "\$($v)\$"; - } -- if ($doc !~ /\\syn\w*{/ && $sec !~ /programming\/control/) { -+ if ($doc !~ /\\syn\w*\{/ && $sec !~ /programming\/control/) { - $doc .= library_syntax($fun, $args); - } - s/_def_//; -commit 742c70e505a7e75128720f619d63e882c03e9346 -Author: Karim Belabas -Date: Tue Jul 14 13:20:07 2015 +0200 - - gphelp: escape all {} in regexps [ perl-5.22 warns on these => fatal ] - -diff --git a/doc/gphelp.in b/doc/gphelp.in -index 00ff6bd..89f2768 100755 ---- a/doc/gphelp.in -+++ b/doc/gphelp.in -@@ -298,7 +298,7 @@ sub treat { - if ($pat =~ /[a-zA-Z0-9]$/) { $pat .= '\b'; } else { $pat .= '}'; } - while () - { -- if (/\\(subsubsec[a-z]*|subsec[a-z]*|section|chapter|label){$pat/) -+ if (/\\(subsubsec[a-z]*|subsec[a-z]*|section|chapter|label)\{$pat/) - { $first = $_; last; } - } - if (eof(DOC)) -@@ -380,7 +380,7 @@ sub apropos_check { - return if ($line !~ /$help/i); - - local($_) = $current; -- s/\\b{(.)}/\\$1/; -+ s/\\b\{(.)\}/\\$1/; - s/\{\}//g; - s/\\pow/^/; - s/\\%/%/; -@@ -400,7 +400,7 @@ sub apropos { - @sentence_list = @list = ""; - while () - { -- if (/^\\(subsubsec[a-z]*|subsec[a-z]*|section|chapter){/) -+ if (/^\\(subsubsec[a-z]*|subsec[a-z]*|section|chapter)\{/) - { - $new = &get_match($_,'{','}'); - &apropos_check($line, $current); -@@ -748,7 +748,7 @@ sub basic_subst { - s/\\fun\s*\{([^{}]*)\}\s*\{((?:[^{}]|\{[^{}]*\})*)\}\s*\{((?:[^{}]|\{[^{}]*\})*)\}/\\kbd{$1 \\key{$2}($3)}\\sidx{$2}/g; - - s/\\\\(?=[a-zA-Z])/\\bs /g; -- s/\\b{}\\b{}/\\bs\\bs /g; -+ s/\\b\{\}\\b\{\}/\\bs\\bs /g; - s/\\\\/\\bs/g; - s/(\'\'|\`\`)/"/g unless $to_pod; # (english) double quotes - # asymptotic or isomorphic (~) [beware of ties] -@@ -760,16 +760,16 @@ sub basic_subst { - s/\\(~|tilde)/~/g; - - s/\\(equiv)(?![a-zA-Z])/ = /g; -- s/\\`a/$tr{agrave}/; s/\\`{a}/$tr{agrave}/; -- s/\\"o/$tr{ouml}/; s/\\"{o}/$tr{ouml}/; -- s/\\"u/$tr{uuml}/; s/\\"{u}/$tr{uuml}/; -- s/\\'e/$tr{eacute}/; s/\\'{e}/$tr{eacute}/; -+ s/\\`a/$tr{agrave}/; s/\\`\{a\}/$tr{agrave}/; -+ s/\\"o/$tr{ouml}/; s/\\"\{o\}/$tr{ouml}/; -+ s/\\"u/$tr{uuml}/; s/\\"\{u\}/$tr{uuml}/; -+ s/\\'e/$tr{eacute}/; s/\\'\{e\}/$tr{eacute}/; - - s/(^|[^\\])%.*/$1/g; # comments - s/\\vadjust\s*\{\s*\\penalty\s*\d+\s*\}//g; - - # We do not strip %\n, thus: -- s/\\kbd{\n\s*/\\kbd{/g; -+ s/\\kbd\{\n\s*/\\kbd{/g; - s/\$\\bf(\b|(?=[\d_]))\s*([^\$]+)\$/\$$tr{startbcode}$1$tr{endbcode}\$/g; - s/\$/$tr{dollar}/g; # math mode - s/\t/ /g; s/\\,//g; s/\\[ ;]/ /g; # various spaces -@@ -779,7 +779,7 @@ sub basic_subst { - s/\\TeX\{\}/TeX/g; - s/\\TeX(\W)/TeX$1/g; - s/ *\\circ\b */ o /g; -- s/\\d?frac{\s*((?:[^{}]|\{[^{}]*\})*)}{\s*((?:[^{}]|\{[^{}]*\})*)}/($1)\/($2)/g; -+ s/\\d?frac\{\s*((?:[^{}]|\{[^{}]*\})*)\}\{\s*((?:[^{}]|\{[^{}]*\})*)\}/($1)\/($2)/g; - s(\\d?frac\s*(\d)\s*(\d))(($1/$2))g; - s[{\s*(\w)\s*\\over(?![a-zA-Z])\s*(\w)\s*}]{($1/$2)}g; - s[{\s*((?:[^{}]|\{[^{}]*\})*)\\over(?![a-zA-Z])\s*((?:[^{}]|\{[^{}]*\})*)}][($1)/($2)]g; -@@ -796,7 +796,7 @@ sub basic_subst { - - s/(\\string)?\\_/_/g; - s/\\([#\$&%|])/$1/g; -- s/\\(hat(?![a-zA-Z])|\^)({\\?\s*})?/^/g; -+ s/\\(hat(?![a-zA-Z])|\^)(\{\\?\s*\})?/^/g; - s/^(\@\[podleader\]head\d *)\\pow(?![a-zA-z])( *)/$1^$2/gm; - s/ *\\pow(?![a-zA-z]) */^/g; - -@@ -896,21 +896,21 @@ sub basic_subst { - s/\\(floor|ceil|round|binom)\{/$1\{/g; - s/\\(var|emph)\{([^\}]*)\}/$tr{startit}$2$tr{endit}/g; - s/\\fl(?![a-zA-Z])/$tr{startit}flag$tr{endit}/g; -- s/\\b{([^}]*)}/$tr{startcode}\\$1$tr{endcode}/g; -+ s/\\b\{([^}]*)\}/$tr{startcode}\\$1$tr{endcode}/g; - s/\\kbdsidx/\\sidx/g; - s/\\sidx\{[^\}]*\}//g unless $to_pod; - s/\\[a-zA-Z]*idx\{([^\}]*)\}/$1/g unless $to_pod; -- s/{\\text{(st|nd|th)}}/\\text{$1}/g; -- s/\^\\text{th}/-th/g; -- s/1\^\\text{st}/1st/g; -- s/2\^\\text{nd}/2nd/g; -+ s/\{\\text\{(st|nd|th)\}\}/\\text{$1}/g; -+ s/\^\\text\{th\}/-th/g; -+ s/1\^\\text\{st\}/1st/g; -+ s/2\^\\text\{nd\}/2nd/g; - - s/\\(text|hbox|Big)//g; - s/^([ \t]+)\{ *\\(it|sl|bf|tt)\b/S<$1>{\\$2/gm; - s/\{ *\\(it|sl) *(([^{}]+(?=[{}])|\{[^{}]*\})*)\}/$tr{startit}$2$tr{endit}/g; - s/\{ *\\bf *(([^{}]+(?=[{}])|\{[^{}]*\})*)\}/$tr{startbold}$1$tr{endbold}/g; - s/\{ *\\tt *(([^{}]+(?=[{}])|\{[^{}]*\})*)\}/$tr{startpodcode}$1$tr{endpodcode}/g; -- $seek=1 if (s/\\emph{ */$tr{startit}/g); -+ $seek=1 if (s/\\emph\{ */$tr{startit}/g); - if ($seek) { $seek=0 if (s/\}/$tr{endit}/) } - s/\\(backslash|bs)\{(\w)\}/\\$2/g; - s/\\(backslash|bs)(?![a-zA-Z]) */\\/g; -@@ -1028,21 +1028,21 @@ sub TeXprint_topod { - # Try to guard \label/\sidx (removing possible '.') - # This somehow breaks index... - # s/(\\(?:section|subsec(?:ref|idx|op)?(unix)?)\s*{(?:(?:[^{}]+(?=[{}])|{[^{}]+})+)})\.?\s*\\(label|sidx)/$1\n\\$2/; -- s/(\\(?:section|subsec(?:ref|idx|op)?)\s*{(?:(?:[^{}]+(?=[{}])|{[^{}]+})+)})\.?\s*\\(label|sidx)/$1\n\\$2/; -+ s/(\\(?:section|subsec(?:ref|idx|op)?)\s*\{(?:(?:[^{}]+(?=[{}])|{[^{}]+})+)\})\.?\s*\\(label|sidx)/$1\n\\$2/; - - # last if /\\subsec[\\{}ref]*[\\\${]$help[}\\\$]/o; -- s/\\chapter\s*{((?:[^{}]|\{[^{}]*\})*)}\s*/\n\n$tr{podleader}head1 NAME\n\nlibPARI - $1\n\n/; -- s/\\appendix\s*{((?:[^{}]|\{[^{}]*\})*)}\s*/\n\n$tr{podleader}head1 NAME\n\nAppendix - $1\n\n/; -- s/\\section\s*{((?:[^{}]|\{[^{}]*\})*)}\s*/"\n\n$tr{podleader}head1 " . indexify($1) . "\n\n"/e; -+ s/\\chapter\s*\{((?:[^{}]|\{[^{}]*\})*)\}\s*/\n\n$tr{podleader}head1 NAME\n\nlibPARI - $1\n\n/; -+ s/\\appendix\s*\{((?:[^{}]|\{[^{}]*\})*)\}\s*/\n\n$tr{podleader}head1 NAME\n\nAppendix - $1\n\n/; -+ s/\\section\s*\{((?:[^{}]|\{[^{}]*\})*)\}\s*/"\n\n$tr{podleader}head1 " . indexify($1) . "\n\n"/e; - - # Try to delimit by : -- s/\\subsec(?:ref)?(?:unix)?\s*{(([^{}]+(?=[{}])|{[^{}]+})+)}([^\n]*):[\n ]/"\n\n$tr{podleader}head2 " . indexify("$1$3") . "\n\n"/e; -- s/\\subsubsec(?:ref)?(?:unix)?\s*{(([^{}]+(?=[{}])|{[^{}]+})+)}([^:]*):\s*/"\n\n$tr{podleader}head3 " . indexify("$1$3") . "\n\n"/e; -+ s/\\subsec(?:ref)?(?:unix)?\s*\{(([^{}]+(?=[{}])|{[^{}]+})+)\}([^\n]*):[\n ]/"\n\n$tr{podleader}head2 " . indexify("$1$3") . "\n\n"/e; -+ s/\\subsubsec(?:ref)?(?:unix)?\s*\{(([^{}]+(?=[{}])|{[^{}]+})+)\}([^:]*):\s*/"\n\n$tr{podleader}head3 " . indexify("$1$3") . "\n\n"/e; - s/\\subsubsec\s*{(([^{}]+(?=[{}])|{[^{}]+})+)}(.*)$/"\n\n$tr{podleader}head3 " . indexify("$1") . "$3\n\n"/me; - s/\\subseckbd\s*{(([^{}]+(?=[{}])|{[^{}]+})+)}([^:]*):\s*/"\n\n$tr{podleader}head2 " . indexify("$1$3") . "\n\n"/e; - # Try to delimit by ' ' -- s/\\subsec(?:ref)?(?:unix)?\s*{(([^{}]+(?=[{}])|{[^{}]+})+)}(\S*)\s+/"\n\n$tr{podleader}head2 " . indexify("$1$3") . "\n\n"/e; -- s/\\subsec(?:title)?(?:unix)?\s*{(([^{}]+(?=[{}])|{[^{}]*})+)}:?\s*/"\n\n$tr{podleader}head2 " . indexify("$1") . "\n\n"/e; -+ s/\\subsec(?:ref)?(?:unix)?\s*\{(([^{}]+(?=[{}])|{[^{}]+})+)\}(\S*)\s+/"\n\n$tr{podleader}head2 " . indexify("$1$3") . "\n\n"/e; -+ s/\\subsec(?:title)?(?:unix)?\s*\{(([^{}]+(?=[{}])|{[^{}]*})+)\}:?\s*/"\n\n$tr{podleader}head2 " . indexify("$1") . "\n\n"/e; - - # This is to skip preface in refcard: - /\Q$tr{podleader}\Ehead1|\\title(?![a-zA-Z])\s*\{/o and $seen_start = 1 -@@ -1097,18 +1097,18 @@ sub TeXprint_topod { - s/\$\$(.*?)\$\$\s*/\n\nS< >$tr{startcode}$1$tr{endcode}\n\n/gs; - s/\$([^\$]+)\$/$tr{startcode}$1$tr{endcode}/g; - -- s/\\s(?:ref|idx){\s*([^{}]*)}/"X<" . for_index($1) . ">"/ge; # -- s/\\(?:ref|idx){\s*([^{}]*)}/"X<" . for_index($1) . ">$1"/ge; -+ s/\\s(?:ref|idx)\{\s*([^{}]*)\}/"X<" . for_index($1) . ">"/ge; # -+ s/\\(?:ref|idx)\{\s*([^{}]*)\}/"X<" . for_index($1) . ">$1"/ge; - - # Conflict between different versions of PARI and refcard: --# s/\\(?:key|li)\s*{(.*)}\s*{(.+)}[ \t]*\n/\n\n=item C<$2>\n\n$1\n\n/msg; --# s/\\(?:key|li)\s*{(.*)}\s*{}[ \t]*\n/\n\n=back\n\n$1\n\n=over\n\n/mgs; --# s/\\(key|var)(?![a-zA-Z])\s*{(\w+)}/C<$2>/mg; -- s/\\var\s*{X<(\w+)>(\w+)}/X<$1>$tr{startcode}$2$tr{endcode}/mg; -- s/\\var\s*{f{}lag}/$tr{startcode}flag$tr{endcode}/mg; -- -- s/\\metax(?![a-zA-Z])\s*{(.*)}\s*{\s*(\w+)(?=C\<)(.*)}[ \t]*\n/\n\n=item C$3>\n\n$1\n\n/mg; -- s/\\metax(?![a-zA-Z])\s*{(.*)}\s*{(.*)}[ \t]*\n/\n\n=item C<$2>\n\n$1\n\n/mg; -+# s/\\(?:key|li)\s*\{(.*)\}\s*\{(.+)\}[ \t]*\n/\n\n=item C<$2>\n\n$1\n\n/msg; -+# s/\\(?:key|li)\s*\{(.*)\}\s*\{\}[ \t]*\n/\n\n=back\n\n$1\n\n=over\n\n/mgs; -+# s/\\(key|var)(?![a-zA-Z])\s*\{(\w+)\}/C<$2>/mg; -+ s/\\var\s*\{X<(\w+)>(\w+)\}/X<$1>$tr{startcode}$2$tr{endcode}/mg; -+ s/\\var\s*\{f\{\}lag\}/$tr{startcode}flag$tr{endcode}/mg; -+ -+ s/\\metax(?![a-zA-Z])\s*\{(.*)\}\s*\{\s*(\w+)(?=C\<)(.*)\}[ \t]*\n/\n\n=item C$3>\n\n$1\n\n/mg; -+ s/\\metax(?![a-zA-Z])\s*\{(.*)\}\s*\{(.*)\}[ \t]*\n/\n\n=item C<$2>\n\n$1\n\n/mg; - s/C\<\{\}=/C\<=/g; - s/\\fl(?![a-zA-Z])/I/g; - s/\\file(?![a-zA-Z])/F/g; diff --git a/build/pkgs/pari/spkg-install b/build/pkgs/pari/spkg-install index 6a7b1ebc9d3..55a64aec9a8 100755 --- a/build/pkgs/pari/spkg-install +++ b/build/pkgs/pari/spkg-install @@ -206,7 +206,14 @@ set_environment # Set CFLAGS if [ "$SAGE_DEBUG" = yes ]; then # Disable optimisation, add debug symbols. - CFLAGS="$CFLAGS -O0 -g" + CFLAGS="-O0 -g $CFLAGS" + + # Compile kernel files with -O1 instead of -funroll-loops; -O0 gives + # a segmentation fault on some OS X systems when doing + # factor(10356613*10694706299664611221) + # See #13921, also reported upstream: + # - http://pari.math.u-bordeaux.fr/archives/pari-dev-1301/msg00000.html + PARI_MAKEFLAGS="KERNELCFLAGS=-O1 $PARI_MAKEFLAGS" else # Use PARI's default CFLAGS (with -g added). # PARI's Configure adds -O3 to the CFLAGS, so we don't need to add diff --git a/src/sage/libs/pari/paridecl.pxd b/src/sage/libs/pari/paridecl.pxd index fac8f363ccd..8e039a6084a 100644 --- a/src/sage/libs/pari/paridecl.pxd +++ b/src/sage/libs/pari/paridecl.pxd @@ -1435,6 +1435,7 @@ cdef extern from "sage/libs/pari/parisage.h": long fetch_var_higher() GEN fetch_var_value(long vx, GEN t) GEN gp_read_str(char *t) + GEN gp_read_str_multiline(char *t) entree* install(void *f, char *name, char *code) entree* is_entry(char *s) void kill0(char *e) @@ -2203,7 +2204,7 @@ cdef extern from "sage/libs/pari/parisage.h": # classpoly.c - GEN polclass(GEN D, long xvar) + GEN polclass(GEN D, long inv, long xvar) # compile.c @@ -2216,8 +2217,8 @@ cdef extern from "sage/libs/pari/parisage.h": # concat.c - GEN concat(GEN x, GEN y) - GEN concat1(GEN x) + GEN gconcat(GEN x, GEN y) + GEN gconcat1(GEN x) GEN matconcat(GEN v) GEN shallowconcat(GEN x, GEN y) GEN shallowconcat1(GEN x) @@ -3181,7 +3182,101 @@ cdef extern from "sage/libs/pari/parisage.h": GEN rnfkummer(GEN bnr, GEN subgroup, long all, long prec) + # lfun.c + + long is_linit(GEN data) + GEN ldata_get_an(GEN ldata) + long ldata_get_selfdual(GEN ldata) + long ldata_isreal(GEN ldata) + GEN ldata_get_gammavec(GEN ldata) + long ldata_get_degree(GEN ldata) + long ldata_get_k(GEN ldata) + GEN ldata_get_conductor(GEN ldata) + GEN ldata_get_rootno(GEN ldata) + GEN ldata_get_residue(GEN ldata) + GEN ldata_vecan(GEN ldata, long L, long prec) + long ldata_get_type(GEN ldata) + long linit_get_type(GEN linit) + GEN linit_get_ldata(GEN linit) + GEN linit_get_tech(GEN linit) + GEN lfun_get_domain(GEN tech) + GEN lfun_get_dom(GEN tech) + long lfun_get_bitprec(GEN tech) + GEN lfun_get_factgammavec(GEN tech) + GEN lfun_get_step(GEN tech) + GEN lfun_get_pol(GEN tech) + GEN lfun_get_Residue(GEN tech) + GEN lfun_get_k2(GEN tech) + GEN lfun_get_w2(GEN tech) + GEN lfun_get_expot(GEN tech) + long lfun_get_der(GEN tech) + long lfun_get_bitprec(GEN tech) + GEN lfun(GEN ldata, GEN s, long prec) + GEN lfun_bitprec(GEN ldata, GEN s, long bitprec) + GEN lfun0_bitprec(GEN ldata, GEN s, long der, long bitprec) + GEN lfun0(GEN ldata, GEN s, long der, long prec) + long lfuncheckfeq(GEN data, GEN t0, long prec) + long lfuncheckfeq_bitprec(GEN data, GEN t0, long bitprec) + GEN lfunconductor(GEN data, GEN maxcond, long flag, long prec) + GEN lfuncreate(GEN obj) + GEN lfunan(GEN ldata, long L, long prec) + GEN lfunhardy(GEN ldata, GEN t, long prec) + GEN lfunhardy_bitprec(GEN ldata, GEN t, long bitprec) + GEN lfuninit(GEN ldata, GEN dom, long der, long prec) + GEN lfuninit_bitprec(GEN ldata, GEN dom, long der, long bitprec) + GEN lfuninit_make(long t, GEN ldata, GEN molin, GEN domain) + long lfunisvgaell(GEN Vga, long flag) + GEN lfunlambda(GEN ldata, GEN s, long prec) + GEN lfunlambda_bitprec(GEN ldata, GEN s, long bitprec) + GEN lfunlambda0(GEN ldata, GEN s, long der, long prec) + GEN lfunlambda0_bitprec(GEN ldata, GEN s, long der, long bitprec) + GEN lfunmisc_to_ldata(GEN ldata) + GEN lfunmisc_to_ldata_shallow(GEN ldata) + long lfunorderzero(GEN ldata, long prec) + long lfunorderzero_bitprec(GEN ldata, long bitprec) + GEN lfunprod_get_fact(GEN tech) + GEN lfunrootno(GEN data, long prec) + GEN lfunrootno_bitprec(GEN data, long bitprec) + GEN lfunrootres(GEN data, long prec) + GEN lfunrootres_bitprec(GEN data, long bitprec) + GEN lfunrtopoles(GEN r) + GEN lfuntheta(GEN data, GEN t, long m, long prec) + GEN lfuntheta_bitprec(GEN data, GEN t, long m, long bitprec) + GEN lfunthetainit(GEN ldata, GEN tinf, long m, long prec) + GEN lfunthetainit_bitprec(GEN ldata, GEN tdom, long m, long bitprec) + GEN lfunthetacheckinit(GEN data, GEN tinf, long m, long *ptbitprec, long fl) + GEN lfunzeros(GEN ldata, GEN lim, long divz, long prec) + GEN lfunzeros_bitprec(GEN ldata, GEN lim, long divz, long bitprec) + int sdomain_isincl(GEN dom, GEN dom0) + GEN theta_get_an(GEN tdata) + GEN theta_get_K(GEN tdata) + GEN theta_get_R(GEN tdata) + long theta_get_bitprec(GEN tdata) + long theta_get_m(GEN tdata) + GEN theta_get_tdom(GEN tdata) + GEN theta_get_sqrtN(GEN tdata) + + # lfunutils.c + + GEN dirzetak(GEN nf, GEN b) + GEN ellmoddegree(GEN e, long prec) + GEN lfunabelianrelinit(GEN bnfabs, GEN bnf, GEN polrel, GEN dom, long der, long prec) + GEN lfunabelianrelinit_bitprec(GEN bnfabs, GEN bnf, GEN polrel, GEN dom, long der, long bitprec) + GEN lfunconvol(GEN a1, GEN a2) + GEN lfundiv(GEN ldata1, GEN ldata2, long prec) + GEN lfunzetakinit(GEN pol, GEN dom, long der, long flag, long prec) + GEN lfunzetakinit_bitprec(GEN pol, GEN dom, long der, long flag, long bitprec) + GEN lfunetaquo(GEN ldata) + GEN lfunmfspec(GEN ldata, long prec) + GEN lfunmfpeters(GEN ldata, long prec) + GEN lfunmfpeters_bitprec(GEN ldata, long bitprec) + GEN lfunmul(GEN ldata1, GEN ldata2, long prec) + GEN lfunqf(GEN ldata) + GEN lfunsymsq(GEN ldata, GEN known, long prec) + GEN lfunsymsqspec(GEN ldata, long prec) + # lll.c + GEN ZM_lll_norms(GEN x, double D, long flag, GEN *B) GEN kerint(GEN x) GEN lll(GEN x) diff --git a/src/sage_setup/autogen/pari/parser.py b/src/sage_setup/autogen/pari/parser.py index f4d8a04d823..639673bd024 100644 --- a/src/sage_setup/autogen/pari/parser.py +++ b/src/sage_setup/autogen/pari/parser.py @@ -47,7 +47,7 @@ def pari_share(): return os.path.join(SAGE_LOCAL, "share", "pari") paren_re = re.compile(r"[(](.*)[)]") -argname_re = re.compile(r"[ {]*([A-Za-z0-9_]+)") +argname_re = re.compile(r"[ {]*([A-Za-z_][A-Za-z0-9_]*)") def read_pari_desc(): """ From 5bf22dd5904ad797f492c0215e2040f8854b21a9 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Tue, 18 Aug 2015 01:47:26 -0700 Subject: [PATCH 1187/1872] Trac 19321: hash for LaurentPolynomial_mpair --- src/sage/rings/polynomial/laurent_polynomial.pyx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 091fc1a2fb0..2dd216c3ffa 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1335,6 +1335,21 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): """ return self._parent, (self._poly,) + def __hash__(self): + r""" + TESTS:: + + sage: L. = LaurentPolynomialRing(QQ) + sage: f = L({(-1,-1):1}) + sage: hash(f) + 1 + sage: f = L({(1,1):1}) + sage: hash(f) + -2021162459040316190 # 64-bit + -1148451614 # 32-bit + """ + return hash(self._poly) + cdef _new_c(self): """ Returns a new Laurent polynomial From b6a04d66866d79f79c3c3dae511beda92e5a9e62 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 16 Aug 2015 21:18:27 +0200 Subject: [PATCH 1188/1872] Trac 19321: hash values for CFiniteSequence --- src/sage/rings/cfinite_sequence.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index a33e1c75d01..972392426db 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -429,6 +429,18 @@ def _repr_(self): else: return 'C-finite sequence, generated by ' + str(self.ogf()) + def __hash__(self): + r""" + Hash value for C finite sequence. + + EXAMPLES:: + + sage: C. = CFiniteSequences(QQ) + sage: hash(C((2-x)/(1-x-x^2))) # random + 42 + """ + return hash(self.parent()) ^ hash(self._ogf) + def _add_(self, other): """ Addition of C-finite sequences. From d671b88ab629a6a2a94a09d92c5a8d3b792845a6 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 16 Aug 2015 21:57:35 +0200 Subject: [PATCH 1189/1872] Trac 19321: hash for abelian group elements --- src/sage/groups/abelian_gps/abelian_group_element.py | 1 - src/sage/groups/abelian_gps/element_base.py | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/abelian_gps/abelian_group_element.py b/src/sage/groups/abelian_gps/abelian_group_element.py index c49325d699b..d1d61c93cc0 100644 --- a/src/sage/groups/abelian_gps/abelian_group_element.py +++ b/src/sage/groups/abelian_gps/abelian_group_element.py @@ -93,7 +93,6 @@ class AbelianGroupElement(AbelianGroupElementBase): sage: a*b in F True """ - def as_permutation(self): r""" Return the element of the permutation group G (isomorphic to the diff --git a/src/sage/groups/abelian_gps/element_base.py b/src/sage/groups/abelian_gps/element_base.py index ab2cff59587..1cf9c4a5a62 100644 --- a/src/sage/groups/abelian_gps/element_base.py +++ b/src/sage/groups/abelian_gps/element_base.py @@ -73,6 +73,16 @@ def __init__(self, parent, exponents): if len(self._exponents) != n: raise IndexError('argument length (= %s) must be %s.'%(len(exponents), n)) + def __hash__(self): + r""" + TESTS:: + + sage: F = AbelianGroup(3,[7,8,9]) + sage: hash(F.an_element()) # random + 1024 + """ + return hash(self.parent()) ^ hash(self._exponents) + def exponents(self): """ The exponents of the generators defining the group element. From 503679090e7ed809761abe6f211fe3cb5f8d73fd Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 18 Aug 2015 12:43:35 +0200 Subject: [PATCH 1190/1872] Trac 19321: hash for matrix group element --- src/sage/groups/matrix_gps/group_element.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/matrix_gps/group_element.py b/src/sage/groups/matrix_gps/group_element.py index 5c0ae88326b..434c7ce8027 100644 --- a/src/sage/groups/matrix_gps/group_element.py +++ b/src/sage/groups/matrix_gps/group_element.py @@ -117,12 +117,23 @@ class MatrixGroupElement_base(MultiplicativeGroupElement): EXAMPLES:: sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] sage: G = MatrixGroup(gens) sage: g = G.random_element() sage: type(g) """ + def __hash__(self): + r""" + TESTS:: + + sage: MS = MatrixSpace(GF(3), 2) + sage: G = MatrixGroup([MS([1,1,0,1]), MS([1,0,1,1])]) + sage: g = G.an_element() + sage: hash(g) + 0 + """ + return hash(self.matrix()) def _repr_(self): """ From 9a3c11d18979217cbd3bff32037c17a9769df3cf Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 18 Aug 2015 12:43:50 +0200 Subject: [PATCH 1191/1872] Trac 19321: hash for indexed free monoid --- src/sage/monoids/indexed_free_monoid.py | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index 734d24087bd..e4772f34910 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -371,6 +371,19 @@ def __init__(self, F, x): """ IndexedMonoidElement.__init__(self, F, tuple(map(tuple, x))) + def __hash__(self): + r""" + TESTS:: + + sage: F = FreeMonoid(index_set=tuple('abcde')) + sage: hash(F ([(1,2),(0,1)]) ) + 2401565693828035651 # 64-bit + 1164080195 # 32-bit + sage: hash(F ([(0,2),(1,1)]) ) + -3359280905493236379 # 64-bit + -1890405019 # 32-bit + """ + return hash(self._monomial) def _sorted_items(self): """ @@ -486,6 +499,20 @@ def _sorted_items(self): pass return v + def __hash__(self): + r""" + TESTS:: + + sage: F = FreeAbelianMonoid(index_set=ZZ) + sage: hash( F([(0,1), (2,2)]) ) + 8087055352805725849 # 64-bit + 250091161 # 32-bit + sage: hash( F([(2,1)]) ) + 5118585357534560720 # 64-bit + 1683816912 # 32-bit + """ + return hash(frozenset(self._monomial.items())) + def _mul_(self, other): """ Multiply ``self`` by ``other``. From 90f5186b64f7fceadbd6d053230b4cc0194da0d3 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 18 Aug 2015 12:44:04 +0200 Subject: [PATCH 1192/1872] Trac 19321: hash for free groups --- src/sage/groups/free_group.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/groups/free_group.py b/src/sage/groups/free_group.py index 0bdef462d65..f328c0efbdc 100644 --- a/src/sage/groups/free_group.py +++ b/src/sage/groups/free_group.py @@ -227,6 +227,9 @@ def __init__(self, parent, x): x = AbstractWordTietzeWord(l, parent._gap_gens()) ElementLibGAP.__init__(self, parent, x) + def __hash__(self): + return hash(self.Tietze()) + def _latex_(self): """ Return a LaTeX representation From 48b50028ed63682f45b3f0db6d891d35303f7119 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 18 Aug 2015 13:32:37 +0200 Subject: [PATCH 1193/1872] Trac 19321: hash for poset elements --- src/sage/combinat/posets/elements.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/combinat/posets/elements.py b/src/sage/combinat/posets/elements.py index b27afd59980..0cf391ef992 100644 --- a/src/sage/combinat/posets/elements.py +++ b/src/sage/combinat/posets/elements.py @@ -51,6 +51,17 @@ def __init__(self, poset, element, vertex): self.element = element self.vertex = vertex + def __hash__(self): + r""" + TESTS:: + + sage: P = Poset([[1,2],[4],[3],[4],[]], facade = False) + sage: e = P(0) + sage: hash(e) + 0 + """ + return hash(self.element) + def _repr_(self): """ TESTS:: From 07e740d630e9123c462922e9efa572ab8aff75c0 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Tue, 18 Aug 2015 22:21:52 -0700 Subject: [PATCH 1194/1872] Trac 19321: some more hashes --- src/sage/groups/free_group.py | 8 +++++++ .../modform_hecketriangle/abstract_ring.py | 4 ++-- .../modular/overconvergent/weightspace.py | 14 ++++++++++++ src/sage/monoids/free_monoid_element.py | 17 ++++++++++++++ src/sage/structure/element.pyx | 22 +++++++++++++++++-- 5 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/sage/groups/free_group.py b/src/sage/groups/free_group.py index f328c0efbdc..45ef7a1c10c 100644 --- a/src/sage/groups/free_group.py +++ b/src/sage/groups/free_group.py @@ -228,6 +228,14 @@ def __init__(self, parent, x): ElementLibGAP.__init__(self, parent, x) def __hash__(self): + r""" + TESTS:: + + sage: G. = FreeGroup() + sage: hash(a*b*b*~a) + -485698212495963022 # 64-bit + -1876767630 # 32-bit + """ return hash(self.Tietze()) def _latex_(self): diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index 6577462c05f..9f80cd3de45 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -747,11 +747,11 @@ def diff_alg(self): sage: from sage.modular.modform_hecketriangle.graded_ring import ModularFormsRing sage: ModularFormsRing().diff_alg() - Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dY*Y: Y*dY + 1, dZ*Z: Z*dZ + 1, dX*X: X*dX + 1} + Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dZ*Z: Z*dZ + 1, dY*Y: Y*dY + 1, dX*X: X*dX + 1} sage: from sage.modular.modform_hecketriangle.space import CuspForms sage: CuspForms(k=12, base_ring=AA).diff_alg() - Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dY*Y: Y*dY + 1, dZ*Z: Z*dZ + 1, dX*X: X*dX + 1} + Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dZ*Z: Z*dZ + 1, dY*Y: Y*dY + 1, dX*X: X*dX + 1} """ # We only use two operators for now which do not involve 'd', so for performance diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index 3e6e55445f4..a1f65f55d25 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -566,6 +566,20 @@ def chi(self): """ return self._chi + def __hash__(self): + r""" + TESTS:: + + sage: w = pAdicWeightSpace(23)(12, DirichletGroup(23, QQ).0) + sage: hash(w) + -2363716619315244394 # 64-bit + 470225558 # 32-bit + """ + if self._chi.is_trivial(): + return hash(self._k) + else: + return hash( (self._k,self._chi.modulus(),self._chi) ) + def _repr_(self): r""" String representation of self. diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index 7fef15de61c..9872b16c232 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -80,6 +80,23 @@ def __init__(self, F, x, check=True): # TODO: should have some other checks here... raise TypeError("Argument x (= %s) is of the wrong type."%x) + def __hash__(self): + r""" + TESTS:: + + sage: R. = FreeMonoid(2) + sage: hash(x) + 1914282862589934403 # 64-bit + 139098947 # 32-bit + sage: hash(y) + 2996819001369607946 # 64-bit + 13025034 # 32-bit + sage: hash(x*y) + 7114093379175463612 # 64-bit + 2092317372 # 32-bit + """ + return hash(tuple(self._element_list)) + def __iter__(self): """ Returns an iterator which yields tuples of variable and exponent. diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 5b71a088b05..b0d93cb1035 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -128,6 +128,8 @@ underscores). # by any element. Derived class must call __init__ ################################################################## +from libc.limits cimport LONG_MAX, LONG_MIN + include "sage/ext/python.pxi" from sage.ext.stdsage cimport * @@ -3279,10 +3281,26 @@ cdef class InfinityElement(RingElement): return ZZ(0) cdef class PlusInfinityElement(InfinityElement): - pass + def __hash__(self): + r""" + TESTS:: + + sage: hash(+infinity) + 9223372036854775807 # 64-bit + 2147483647 # 32-bit + """ + return LONG_MAX cdef class MinusInfinityElement(InfinityElement): - pass + def __hash__(self): + r""" + TESTS:: + + sage: hash(-infinity) + -9223372036854775808 # 64-bit + -2147483648 # 32-bit + """ + return LONG_MIN ################################################################################# From 3e920d0379ae690dd3f16dc9eafdf8498ef5f3ef Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 19 Aug 2015 12:22:42 +0200 Subject: [PATCH 1195/1872] Trac 19321: hash for linear expression --- src/sage/geometry/linear_expression.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index 93e7d05cf4f..ca4773e0449 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -351,6 +351,18 @@ def change_ring(self, base_ring): return self return P.change_ring(base_ring)(self) + def __hash__(self): + r""" + TESTS:: + + sage: from sage.geometry.linear_expression import LinearExpressionModule + sage: L. = LinearExpressionModule(QQ) + sage: hash(L([0,1])) + 3430019387558 # 64-bit + -1659481946 # 32-bit + """ + return hash(self._coeffs) ^ hash(self._const) + def __cmp__(self, other): """ Compare two linear expressions. @@ -379,10 +391,7 @@ def __cmp__(self, other): False """ assert type(self) is type(other) and self.parent() is other.parent() # guaranteed by framework - c = cmp(self._coeffs, other._coeffs) - if c != 0: return c - c = cmp(self._const, other._const) - return c + return cmp(self._coeffs, other._coeffs) or cmp(self._const, other._const) def evaluate(self, point): """ From 3436b380cb4cfdfeaf4277893fbe76e281551c81 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 19 Aug 2015 12:37:34 +0200 Subject: [PATCH 1196/1872] Trac 19321: hash for alternating sign matrices --- src/sage/combinat/alternating_sign_matrix.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 930a703e6af..8558936ef7a 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -104,6 +104,17 @@ def __init__(self, parent, asm): self._matrix = asm Element.__init__(self, parent) + def __hash__(self): + r""" + TESTS:: + + sage: A = AlternatingSignMatrices(3) + sage: elt = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]) + sage: hash(elt) + 12 + """ + return hash(self._matrix) + def _repr_(self): """ Return a string representation of ``self``. @@ -1101,7 +1112,9 @@ def _element_constructor_(self, asm): raise ValueError("Cannot convert between alternating sign matrices of different sizes") if asm in MonotoneTriangles(self._n): return self.from_monotone_triangle(asm) - return self.element_class(self, self._matrix_space(asm)) + m = self._matrix_space(asm) + m.set_immutable() + return self.element_class(self, m) Element = AlternatingSignMatrix @@ -1147,7 +1160,9 @@ def from_monotone_triangle(self, triangle): asm.append(row) prev = v - return self.element_class(self, self._matrix_space(asm)) + m = self._matrix_space(asm) + m.set_immutable() + return self.element_class(self, m) def from_corner_sum(self, corner): r""" From c777f223fdad903062b16b7094821fe45216756a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 19 Aug 2015 20:10:00 +0200 Subject: [PATCH 1197/1872] Trac 19321: fix infinite polynomial elements --- src/sage/rings/polynomial/infinite_polynomial_element.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index 59e873fe00d..081b6d4f340 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -255,16 +255,15 @@ def _repr_(self): """ return repr(self._p) - def _hash_(self): + def __hash__(self): """ TESTS:: sage: X. = InfinitePolynomialRing(QQ) sage: a = x[0] + x[1] sage: hash(a) # indirect doctest - -6172640511012239345 # 64-bit - -957478897 # 32-bit - + 971115012877883067 # 64-bit + -2103273797 # 32-bit """ return hash(self._p) From 6716eb6e156a2e04298e0ac60e8251e636ac26fc Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 20 Aug 2015 00:58:07 +0200 Subject: [PATCH 1198/1872] Trac 19321: fix similarity classes --- src/sage/combinat/similarity_class_type.py | 43 ++++++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/similarity_class_type.py b/src/sage/combinat/similarity_class_type.py index 9cbfc8b1774..36f5bc22194 100644 --- a/src/sage/combinat/similarity_class_type.py +++ b/src/sage/combinat/similarity_class_type.py @@ -181,7 +181,7 @@ class type, it is also possible to compute the number of classes of that type from sage.functions.all import factorial from sage.rings.arith import moebius from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.structure.element import Element +from sage.structure.element import Element, parent from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -400,6 +400,25 @@ def __repr__(self): """ return "%s"%([self._deg, self._par]) + def __hash__(self): + r""" + TESTS:: + + sage: PT1 = PrimarySimilarityClassType(2, [3, 2, 1]) + sage: PT2 = PrimarySimilarityClassType(3, [3, 2, 1]) + sage: PT3 = PrimarySimilarityClassType(2, [4, 2, 1]) + sage: hash(PT1) + 5050909583595644741 # 64-bit + 1658169157 # 32-bit + sage: hash(PT2) + 5050909583595644740 # 64-bit + 1658169156 # 32-bit + sage: hash(PT3) + 6312110366011971308 # 64-bit + 1429493484 # 32-bit + """ + return hash(self._deg) ^ hash(tuple(self._par)) + def __eq__(self, other): """ Check equality. @@ -420,9 +439,25 @@ def __eq__(self, other): sage: PT1 == PT5 False """ - if isinstance(other, PrimarySimilarityClassType): - return self.degree() == other.degree() and self.partition() == other.partition() - return False + return isinstance(other, PrimarySimilarityClassType) and \ + self.degree() == other.degree() and \ + self.partition() == other.partition() + + def __ne__(self, other): + r""" + TESTS:: + + sage: PT1 = PrimarySimilarityClassType(2, [3, 2, 1]) + sage: PT2 = PrimarySimilarityClassType(2, Partition([3, 2, 1])) + sage: PT1 != PT2 + False + sage: PT3 = PrimarySimilarityClassType(3, [3, 2, 1]) + sage: PT1 != PT3 + True + """ + return not isinstance(other, PrimarySimilarityClassType) or \ + self.degree() != other.degree() or \ + self.partition() != other.partition() def size(self): """ From ff2b1c517186e3195dd6f89b25a7e2dac901d8b1 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 20 Aug 2015 01:07:04 +0200 Subject: [PATCH 1199/1872] Trac 19321: fix Kleber tree hash value --- .../rigged_configurations/kleber_tree.py | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/rigged_configurations/kleber_tree.py b/src/sage/combinat/rigged_configurations/kleber_tree.py index 1a059859c79..18cecea1f23 100644 --- a/src/sage/combinat/rigged_configurations/kleber_tree.py +++ b/src/sage/combinat/rigged_configurations/kleber_tree.py @@ -24,30 +24,30 @@ sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree sage: KT = KleberTree(['A', 3, 1], [[3,2], [2,1], [1,1], [1,1]]) - sage: for x in set(KT.list()): x - Kleber tree node with weight [1, 0, 3] and upwards edge root [1, 1, 0] - Kleber tree node with weight [0, 2, 2] and upwards edge root [1, 0, 0] - Kleber tree node with weight [2, 1, 2] and upwards edge root [0, 0, 0] - Kleber tree node with weight [2, 0, 0] and upwards edge root [0, 1, 1] - Kleber tree node with weight [0, 0, 2] and upwards edge root [1, 1, 0] - Kleber tree node with weight [0, 1, 0] and upwards edge root [0, 0, 1] - Kleber tree node with weight [3, 0, 1] and upwards edge root [0, 1, 1] - Kleber tree node with weight [0, 1, 0] and upwards edge root [1, 1, 1] - Kleber tree node with weight [1, 1, 1] and upwards edge root [1, 1, 1] - Kleber tree node with weight [0, 0, 2] and upwards edge root [2, 2, 1] + sage: sorted((x.weight.to_vector(), x.up_root.to_vector()) for x in KT.list()) + [((0, 0, 2), (1, 1, 0)), + ((0, 0, 2), (2, 2, 1)), + ((0, 1, 0), (0, 0, 1)), + ((0, 1, 0), (1, 1, 1)), + ((0, 2, 2), (1, 0, 0)), + ((1, 0, 3), (1, 1, 0)), + ((1, 1, 1), (1, 1, 1)), + ((2, 0, 0), (0, 1, 1)), + ((2, 1, 2), (0, 0, 0)), + ((3, 0, 1), (0, 1, 1))] sage: KT = KleberTree(['A', 7, 1], [[3,2], [2,1], [1,1]]) sage: KT Kleber tree of Cartan type ['A', 7, 1] and B = ((3, 2), (2, 1), (1, 1)) - sage: for x in set(KT.list()): x - Kleber tree node with weight [1, 0, 1, 0, 1, 0, 0] and upwards edge root [1, 2, 2, 1, 0, 0, 0] - Kleber tree node with weight [0, 0, 1, 0, 0, 1, 0] and upwards edge root [2, 3, 3, 2, 1, 0, 0] - Kleber tree node with weight [1, 1, 2, 0, 0, 0, 0] and upwards edge root [0, 0, 0, 0, 0, 0, 0] - Kleber tree node with weight [2, 0, 1, 1, 0, 0, 0] and upwards edge root [0, 1, 1, 0, 0, 0, 0] - Kleber tree node with weight [1, 0, 0, 2, 0, 0, 0] and upwards edge root [0, 1, 1, 0, 0, 0, 0] - Kleber tree node with weight [0, 0, 3, 0, 0, 0, 0] and upwards edge root [1, 1, 0, 0, 0, 0, 0] - Kleber tree node with weight [0, 0, 0, 1, 1, 0, 0] and upwards edge root [1, 1, 1, 0, 0, 0, 0] - Kleber tree node with weight [0, 1, 1, 1, 0, 0, 0] and upwards edge root [1, 1, 1, 0, 0, 0, 0] + sage: sorted((x.weight.to_vector(), x.up_root.to_vector()) for x in KT.list()) + [((0, 0, 0, 1, 1, 0, 0), (1, 1, 1, 0, 0, 0, 0)), + ((0, 0, 1, 0, 0, 1, 0), (2, 3, 3, 2, 1, 0, 0)), + ((0, 0, 3, 0, 0, 0, 0), (1, 1, 0, 0, 0, 0, 0)), + ((0, 1, 1, 1, 0, 0, 0), (1, 1, 1, 0, 0, 0, 0)), + ((1, 0, 0, 2, 0, 0, 0), (0, 1, 1, 0, 0, 0, 0)), + ((1, 0, 1, 0, 1, 0, 0), (1, 2, 2, 1, 0, 0, 0)), + ((1, 1, 2, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0)), + ((2, 0, 1, 1, 0, 0, 0), (0, 1, 1, 0, 0, 0, 0))] """ #***************************************************************************** @@ -347,6 +347,22 @@ def multiplicity(self): return mult + def __hash__(self): + r""" + TESTS:: + + sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree + sage: RS = RootSystem(['A', 2]) + sage: WS = RS.weight_space() + sage: R = RS.root_space() + sage: KT = KleberTree(['A', 2, 1], [[1,1]]) + sage: n = KT(WS.sum_of_terms([(1,5), (2,2)]), R.zero()) + sage: hash(n) + -603608031356818252 # 64-bit + -1956156236 # 32-bit + """ + return hash(self.depth) ^ hash(self.weight) + def __cmp__(self, rhs): r""" Check whether two nodes are equal. From b8b389a530cde4d7dd2c6764cbb4f1b837569995 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 20 Aug 2015 01:18:05 +0200 Subject: [PATCH 1200/1872] Trac 19321: fix hash for Additive abelian group elements --- .../additive_abelian_group.py | 4 ++-- src/sage/modules/fg_pid/fgp_element.py | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/additive_abelian/additive_abelian_group.py b/src/sage/groups/additive_abelian/additive_abelian_group.py index 51fa899443a..3bf8aef61e6 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_group.py +++ b/src/sage/groups/additive_abelian/additive_abelian_group.py @@ -401,7 +401,7 @@ def __init__(self, cover, rels, gens): Additive abelian group isomorphic to Z/3 """ AdditiveAbelianGroup_class.__init__(self, cover, rels) - self._orig_gens = [self(x) for x in gens] + self._orig_gens = tuple(self(x) for x in gens) def gens(self): r""" @@ -416,7 +416,7 @@ def gens(self): sage: G.smith_form_gens() ((1, 2),) """ - return tuple(self._orig_gens) + return self._orig_gens def identity(self): r""" diff --git a/src/sage/modules/fg_pid/fgp_element.py b/src/sage/modules/fg_pid/fgp_element.py index 2b4f43bb14f..3e47a40fbde 100644 --- a/src/sage/modules/fg_pid/fgp_element.py +++ b/src/sage/modules/fg_pid/fgp_element.py @@ -343,8 +343,28 @@ def vector(self): try: return self.__vector except AttributeError: self.__vector = self.parent().coordinate_vector(self, reduce=True) + self.__vector.set_immutable() return self.__vector + def __hash__(self): + r""" + TESTS:: + + sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ) + sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: Q = V/W + sage: x = Q.0 + 3*Q.1 + sage: hash(x) + 3713081631933328131 # 64-bit + 1298787075 # 32-bit + + sage: A = AdditiveAbelianGroup([3]) + sage: hash(A.an_element()) + 3430019387558 # 64-bit + -1659481946 # 32-bit + """ + return hash(self.vector()) + def _vector_(self, base_ring=None): """ Support for conversion to vectors. From 03f05ddbc1e1acf7001e09efc30db79199872e31 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 23 Aug 2015 07:53:35 -0300 Subject: [PATCH 1201/1872] Trac 19321: fix fgp vector conversion --- src/sage/modules/fg_pid/fgp_element.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/fg_pid/fgp_element.py b/src/sage/modules/fg_pid/fgp_element.py index 3e47a40fbde..749f67a3991 100644 --- a/src/sage/modules/fg_pid/fgp_element.py +++ b/src/sage/modules/fg_pid/fgp_element.py @@ -387,10 +387,21 @@ def _vector_(self, base_ring=None): (1, 3) sage: vector(CDF, x) (1.0, 3.0) + + TESTS:: + + sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ) + sage: W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) + sage: Q = V/W + sage: x = Q.0 + 3*Q.1 + sage: vector(x).is_mutable() + True + sage: vector(CDF,x).is_mutable() + True """ v = self.vector() if base_ring is None or v.base_ring() is base_ring: - return v + return v.__copy__() else: return v.change_ring(base_ring) From 42c9d8555a49906123cdf6aaad2aa5c4a0126d7a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 19 Aug 2015 16:17:11 +0200 Subject: [PATCH 1202/1872] Trac 19321: hash for polyhedra --- src/sage/geometry/polyhedron/base.py | 26 +++++++++++++++++++ .../polyhedron/ppl_lattice_polytope.py | 17 ++++++------ .../geometry/polyhedron/representation.py | 4 +-- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 0d3fe99bad4..f3a43681522 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -120,6 +120,32 @@ def __init__(self, parent, Vrep, Hrep, **kwds): else: self._init_empty_polyhedron() + def __hash__(self): + r""" + TESTS:: + + sage: K. = QuadraticField(2) + sage: p = Polyhedron(vertices=[(0,1,a),(3,a,5)], + ....: rays=[(a,2,3), (0,0,1)], + ....: base_ring=K) + sage: q = Polyhedron(vertices=[(3,a,5),(0,1,a)], + ....: rays=[(0,0,1), (a,2,3)], + ....: base_ring=K) + sage: hash(p) == hash(q) + True + """ + # TODO: find something better *but* fast + return hash((self.dim(), + self.ambient_dim(), + self.n_Hrepresentation(), + self.n_Vrepresentation(), + self.n_equations(), + self.n_facets(), + self.n_inequalities(), + self.n_lines(), + self.n_rays(), + self.n_vertices())) + def _sage_input_(self, sib, coerced): """ Return Sage command to reconstruct ``self``. diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py index 8ffaddec672..6b43c095f42 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py @@ -900,18 +900,19 @@ def base_rays(self, fiber, points): ((1),) """ quo = self.base_projection(fiber) - vertices = [] + vertices = set() for p in points: - v = vector(ZZ,quo(p)) + v = quo(p).vector() if v.is_zero(): continue - d = GCD_list(v.list()) - if d>1: - for i in range(0,v.degree()): + d = GCD_list(v.list()) + if d > 1: + v = v.__copy__() + for i in range(v.degree()): v[i] /= d - v.set_immutable() - vertices.append(v) - return tuple(uniq(vertices)) + v.set_immutable() + vertices.add(v) + return tuple(sorted(vertices)) @cached_method def has_IP_property(self): diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index b61b0caa2d5..3249ceb5184 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -135,9 +135,7 @@ def __cmp__(self, other): """ if not isinstance(other, PolyhedronRepresentation): return -1 - type_cmp = cmp(type(self), type(other)) - if (type_cmp != 0): return type_cmp - return cmp(self._vector, other._vector) + return cmp(type(self), type(other)) or cmp(self._vector, other._vector) def vector(self, base_ring=None): """ From bb5c34159dc5f9813d6019f4ffecb25fe462ac58 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 26 Sep 2015 00:16:56 -0300 Subject: [PATCH 1203/1872] Trac 19321: change output order in documentation --- src/sage/categories/regular_crystals.py | 2 +- src/sage/combinat/posets/posets.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index 9fa8085633b..8f46bd74ad9 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -560,7 +560,7 @@ def demazure_operator_simple(self, i, ring = None): sage: K = crystals.KirillovReshetikhin(['A',2,1],2,1) sage: t = K(rows=[[3],[2]]) sage: t.demazure_operator_simple(0) - B[[[2, 3]]] + B[[[1, 2]]] + B[[[1, 2]]] + B[[[2, 3]]] TESTS:: diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 58245aa7aca..b665046afcd 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1236,9 +1236,9 @@ def hasse_diagram(self, wrapped = True): sage: P = Poset((divisors(15), attrcall("divides")), facade = False) sage: H = P.hasse_diagram() sage: H.vertices() - [1, 5, 3, 15] + [1, 3, 5, 15] sage: H.edges() - [(1, 3, None), (1, 5, None), (5, 15, None), (3, 15, None)] + [(1, 3, None), (1, 5, None), (3, 15, None), (5, 15, None)] sage: H.set_latex_options(format="dot2tex") # optional - dot2tex sage: view(H, tight_page=True) # optional - dot2tex, not tested (opens external window) """ From a64ff78d0d1a6d232e3fb6eafad43f66c6ad952b Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Fri, 25 Sep 2015 18:20:53 -0700 Subject: [PATCH 1204/1872] trac 19321: fix some non-deterministic doctests (and add some deterministic checks) --- .../polynomial/multi_polynomial_ideal.py | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index c0e7bce2c1e..da64b370cdb 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2692,10 +2692,14 @@ def __init__(self, ring, gens, coerce=True, side = "left"): sage: H.inject_variables() Defining x, y, z sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) # indirect doctest - sage: I + sage: I #random Left Ideal (y^2, x^2, z^2 - 1) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: H.ideal([y^2, x^2, z^2-H.one()], side="twosided") + sage: sorted(I.gens(),key=str) + [x^2, y^2, z^2 - 1] + sage: H.ideal([y^2, x^2, z^2-H.one()], side="twosided") #random Twosided Ideal (y^2, x^2, z^2 - 1) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(H.ideal([y^2, x^2, z^2-H.one()], side="twosided").gens(),key=str) + [x^2, y^2, z^2 - 1] sage: H.ideal([y^2, x^2, z^2-H.one()], side="right") Traceback (most recent call last): ... @@ -2726,8 +2730,10 @@ def __call_singular(self, cmd, arg = None): sage: H.inject_variables() Defining x, y, z sage: id = H.ideal(x + y, y + z) - sage: id.std() # indirect doctest + sage: id.std() # indirect doctest # random Left Ideal (z, y, x) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(id.std().gens(),key=str) + [x, y, z] """ from sage.libs.singular.function import singular_function fun = singular_function(cmd) @@ -2748,23 +2754,34 @@ def std(self): sage: H.inject_variables() Defining x, y, z sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) - sage: I.std() + sage: I.std() #random Left Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(I.std().gens(),key=str) + [2*x*y - z - 1, x*z + x, x^2, y*z - y, y^2, z^2 - 1] + If the ideal is a left ideal, then std returns a left Groebner basis. But if it is a two-sided ideal, then the output of std and :meth:`twostd` coincide:: sage: JL = H.ideal([x^3, y^3, z^3 - 4*z]) - sage: JL + sage: JL #random Left Ideal (x^3, y^3, z^3 - 4*z) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: JL.std() + sage: sorted(JL.gens(),key=str) + [x^3, y^3, z^3 - 4*z] + sage: JL.std() #random Left Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, 2*x*y*z - z^2 - 2*z, y^3, x^3) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(JL.std().gens(),key=str) + [2*x*y*z - z^2 - 2*z, x*z^2 + 2*x*z, x^3, y*z^2 - 2*y*z, y^3, z^3 - 4*z] sage: JT = H.ideal([x^3, y^3, z^3 - 4*z], side='twosided') - sage: JT + sage: JT #random Twosided Ideal (x^3, y^3, z^3 - 4*z) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} - sage: JT.std() + sage: sorted(JT.gens(),key=str) + [x^3, y^3, z^3 - 4*z] + sage: JT.std() #random Twosided Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, y^2*z - 2*y^2, 2*x*y*z - z^2 - 2*z, x^2*z + 2*x^2, y^3, x*y^2 - y*z, x^2*y - x*z - 2*x, x^3) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(JT.std().gens(),key=str) + [2*x*y*z - z^2 - 2*z, x*y^2 - y*z, x*z^2 + 2*x*z, x^2*y - x*z - 2*x, x^2*z + 2*x^2, x^3, y*z^2 - 2*y*z, y^2*z - 2*y^2, y^3, z^3 - 4*z] sage: JT.std() == JL.twostd() True @@ -2787,8 +2804,10 @@ def twostd(self): sage: H.inject_variables() Defining x, y, z sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) - sage: I.twostd() + sage: I.twostd() #random Twosided Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field... + sage: sorted(I.twostd().gens(),key=str) + [2*x*y - z - 1, x*z + x, x^2, y*z - y, y^2, z^2 - 1] ALGORITHM: Uses Singular's twostd command """ @@ -2809,7 +2828,7 @@ def _groebner_strategy(self): sage: A. = FreeAlgebra(QQ, 3) sage: H. = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) - sage: I._groebner_strategy() + sage: I._groebner_strategy() #random Groebner Strategy for ideal generated by 6 elements over Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} @@ -2837,7 +2856,7 @@ def reduce(self,p): sage: A. = FreeAlgebra(QQ, 3) sage: H. = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False, side='twosided') - sage: Q = H.quotient(I); Q + sage: Q = H.quotient(I); Q #random Quotient of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} by the ideal (y^2, x^2, z^2 - 1) @@ -2847,10 +2866,8 @@ def reduce(self,p): Here, we see that the relation that we just found in the quotient is actually a consequence of the given relations:: - sage: I.std() - Twosided Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) - of Noncommutative Multivariate Polynomial Ring in x, y, z over - Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: H.2^2-H.one() in I.std().gens() + True Here is the corresponding direct test:: @@ -2869,10 +2886,10 @@ def _contains_(self,p): sage: A. = FreeAlgebra(QQ, 3) sage: H. = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) sage: JL = H.ideal([x^3, y^3, z^3 - 4*z]) - sage: JL.std() + sage: JL.std() #random Left Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, 2*x*y*z - z^2 - 2*z, y^3, x^3) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} sage: JT = H.ideal([x^3, y^3, z^3 - 4*z], side='twosided') - sage: JT.std() + sage: JT.std() #random Twosided Ideal (z^3 - 4*z, y*z^2 - 2*y*z, x*z^2 + 2*x*z, y^2*z - 2*y^2, 2*x*y*z - z^2 - 2*z, x^2*z + 2*x^2, y^3, x*y^2 - y*z, x^2*y - x*z - 2*x, x^3) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} Apparently, ``x*y^2-y*z`` should be in the two-sided, but not From 93b537d6d02ba40bb5253faeae2aa293756b055a Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Fri, 25 Sep 2015 17:57:07 -0700 Subject: [PATCH 1205/1872] trac 19321: doctest fixes and making some code deterministic --- src/sage/groups/conjugacy_classes.py | 2 +- src/sage/groups/finitely_presented_named.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/groups/conjugacy_classes.py b/src/sage/groups/conjugacy_classes.py index 3553af8e8a0..d528090a295 100644 --- a/src/sage/groups/conjugacy_classes.py +++ b/src/sage/groups/conjugacy_classes.py @@ -180,7 +180,7 @@ def __iter__(self): sage: a = G(a) sage: C = ConjugacyClass(G, a) sage: it = iter(C) - sage: [next(it) for _ in range(5)] + sage: [next(it) for _ in range(5)] # random (nothing guarantees enumeration order) [ [1 1] [ 2 1] [ 0 1] [ 3 1] [ 3 4] [0 1], [-1 0], [-1 2], [-4 -1], [-1 -1] diff --git a/src/sage/groups/finitely_presented_named.py b/src/sage/groups/finitely_presented_named.py index 31214fc9751..88fd6df7420 100644 --- a/src/sage/groups/finitely_presented_named.py +++ b/src/sage/groups/finitely_presented_named.py @@ -130,14 +130,14 @@ def FinitelyGeneratedAbelianPresentation(int_list): sage: groups.presentation.FGAbelian([0,0]) Finitely presented group < a, b | a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([0,0,0]) - Finitely presented group < a, b, c | a^-1*c^-1*a*c, a^-1*b^-1*a*b, c^-1*b^-1*c*b > + Finitely presented group < a, b, c | a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c > And various infinite abelian groups:: sage: groups.presentation.FGAbelian([0,2]) Finitely presented group < a, b | a^2, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([0,2,2]) - Finitely presented group < a, b, c | a^2, b^2, a^-1*c^-1*a*c, a^-1*b^-1*a*b, c^-1*b^-1*c*b > + Finitely presented group < a, b, c | a^2, b^2, a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c > Outputs are reduced to minimal generators and relations:: @@ -193,7 +193,7 @@ def FinitelyGeneratedAbelianPresentation(int_list): ret_rls = [F([i+1])**invariants[i] for i in range(len(invariants)) if invariants[i]!=0] # Build commutator relations - gen_pairs = list(Set(F.gens()).subsets(2)) + gen_pairs = [[F.gen(i),F.gen(j)] for i in range(F.ngens()-1) for j in range(i+1,F.ngens())] ret_rls = ret_rls + [x[0]**(-1)*x[1]**(-1)*x[0]*x[1] for x in gen_pairs] return FinitelyPresentedGroup(F, tuple(ret_rls)) From 23b2b461a1821aba592c09e85ae9c19846bad1bc Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Fri, 25 Sep 2015 18:34:28 -0700 Subject: [PATCH 1206/1872] trac 19321: fix some doctests in polynomial/plural.pyx ncalgebras print a set and hence their representation is non-deterministic --- src/sage/libs/singular/groebner_strategy.pyx | 4 ++-- src/sage/rings/polynomial/plural.pyx | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sage/libs/singular/groebner_strategy.pyx b/src/sage/libs/singular/groebner_strategy.pyx index 231cce0ed21..b4c2be95922 100644 --- a/src/sage/libs/singular/groebner_strategy.pyx +++ b/src/sage/libs/singular/groebner_strategy.pyx @@ -312,7 +312,7 @@ cdef class NCGroebnerStrategy(SageObject): sage: A. = FreeAlgebra(QQ, 3) sage: H. = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) sage: I = H.ideal([y^2, x^2, z^2-H.one()]) - sage: NCGroebnerStrategy(I) + sage: NCGroebnerStrategy(I) #random Groebner Strategy for ideal generated by 3 elements over Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} TESTS:: @@ -412,7 +412,7 @@ cdef class NCGroebnerStrategy(SageObject): sage: H. = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) sage: I = H.ideal([y^2, x^2, z^2-H.one()]) sage: strat = NCGroebnerStrategy(I) - sage: strat # indirect doctest + sage: strat # indirect doctest #random Groebner Strategy for ideal generated by 3 elements over Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} """ return "Groebner Strategy for ideal generated by %d elements over %s"%(self._ideal.ngens(),self._parent) diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 6dc97afb04e..56a572dc4fb 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -161,9 +161,9 @@ class G_AlgFactory(UniqueFactory): TEST:: sage: A. = FreeAlgebra(QQ, 3) - sage: A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) # indirect doctest - Noncommutative Multivariate Polynomial Ring in x, y, z over Rational - Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: H=A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: sorted(H.relations().iteritems(),key=str) + [(y*x, x*y - z), (z*x, x*z + 2*x), (z*y, y*z - 2*y)] """ # key = (base_ring,names, c,d, order, category) @@ -1711,10 +1711,13 @@ cdef class NCPolynomial_plural(RingElement): The Groebner basis shows that the result is correct:: - sage: I.std() + sage: I.std() #random Left Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: x*z + 2*x, z*y: y*z - 2*y, y*x: x*y - z} + sage: sorted(I.std().gens(),key=str) + [2*x*y - z - 1, x*z + x, x^2, y*z - y, y^2, z^2 - 1] + """ cdef ideal *_I @@ -2954,8 +2957,12 @@ def ExteriorAlgebra(base_ring, names,order='degrevlex'): EXAMPLES:: sage: from sage.rings.polynomial.plural import ExteriorAlgebra - sage: E = ExteriorAlgebra(QQ, ['x', 'y', 'z']) ; E + sage: E = ExteriorAlgebra(QQ, ['x', 'y', 'z']) ; E #random Quotient of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {z*x: -x*z, z*y: -y*z, y*x: -x*y} by the ideal (z^2, y^2, x^2) + sage: sorted(E.cover().domain().relations().iteritems(),key=str) + [(y*x, -x*y), (z*x, -x*z), (z*y, -y*z)] + sage: sorted(E.cover().kernel().gens(),key=str) + [x^2, y^2, z^2] sage: E.inject_variables() Defining xbar, ybar, zbar sage: x,y,z = (xbar,ybar,zbar) From bebb8af5eaa7ff834a03e9c887da69b118a257af Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 30 Sep 2015 18:17:27 -0300 Subject: [PATCH 1207/1872] Trac 19321: fix a doctest --- src/sage/categories/regular_crystals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index 8f46bd74ad9..9fa8085633b 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -560,7 +560,7 @@ def demazure_operator_simple(self, i, ring = None): sage: K = crystals.KirillovReshetikhin(['A',2,1],2,1) sage: t = K(rows=[[3],[2]]) sage: t.demazure_operator_simple(0) - B[[[1, 2]]] + B[[[2, 3]]] + B[[[2, 3]]] + B[[[1, 2]]] TESTS:: From fe306f971ac9edde2cec32997c3cff7b4db1ce1b Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 29 Sep 2015 21:30:44 -0300 Subject: [PATCH 1208/1872] Trac 19322: faster longest_common_prefix --- src/sage/combinat/words/word_char.pyx | 153 +++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/words/word_char.pyx b/src/sage/combinat/words/word_char.pyx index bef4c943c05..3940c5a41eb 100644 --- a/src/sage/combinat/words/word_char.pyx +++ b/src/sage/combinat/words/word_char.pyx @@ -550,7 +550,6 @@ cdef class WordDatatype_char(WordDatatype): return w._new_c(data, new_length, None) - @cython.boundscheck(False) def has_prefix(self, other): r""" Test whether ``other`` is a prefix of ``self``. @@ -573,6 +572,22 @@ cdef class WordDatatype_char(WordDatatype): True sage: w.has_prefix(w[1:]) False + + TESTS: + + :trac:`19322`:: + + sage: W = Words([0,1,2]) + sage: w = W([0,1,0,2]) + sage: w.has_prefix(words.FibonacciWord()) + False + + sage: w.has_prefix([0,1,0,2,0]) + False + sage: w.has_prefix([0,1,0,2]) + True + sage: w.has_prefix([0,1,0]) + True """ cdef size_t i cdef WordDatatype_char w @@ -582,15 +597,16 @@ cdef class WordDatatype_char(WordDatatype): w = other if w._length > self._length: return False - return memcmp(self._data, w._data, w._length) == 0 + return memcmp(self._data, w._data, w._length * sizeof(unsigned char)) == 0 elif PySequence_Check(other): # python level - if len(other) > self._length: + from sage.combinat.words.infinite_word import InfiniteWord_class + if isinstance(other, InfiniteWord_class) or len(other) > len(self): return False for i in range(len(other)): - if other[i] != self._data[i]: + if other[i] != self[i]: return False return True @@ -638,3 +654,132 @@ cdef class WordDatatype_char(WordDatatype): return memcmp(self._data, self._data + l, l * sizeof(unsigned char)) == 0 + + def longest_common_prefix(self, other): + r""" + Return the longest common prefix of this word and ``other``. + + EXAMPLES:: + + sage: W = Words([0,1,2]) + sage: W([0,1,0,2]).longest_common_prefix([0,1]) + word: 01 + sage: u = W([0,1,0,0,1]) + sage: v = W([0,1,0,2]) + sage: u.longest_common_prefix(v) + word: 010 + sage: v.longest_common_prefix(u) + word: 010 + + Using infinite words is also possible (and the return type is also a + of the same type as ``self``):: + + sage: W([0,1,0,0]).longest_common_prefix(words.FibonacciWord()) + word: 0100 + sage: type(_) + + + An example of an intensive usage:: + + sage: W = Words([0,1]) + sage: w = words.FibonacciWord() + sage: w = W(list(w[:5000])) + sage: L = [[len(w[n:].longest_common_prefix(w[n+fibonacci(i):])) + ....: for i in range(5,15)] for n in range(1,1000)] + sage: for n,l in enumerate(L): + ....: if l.count(0) > 4: print n+1,l + 375 [0, 13, 0, 34, 0, 89, 0, 233, 0, 233] + 376 [0, 12, 0, 33, 0, 88, 0, 232, 0, 232] + 608 [8, 0, 21, 0, 55, 0, 144, 0, 377, 0] + 609 [7, 0, 20, 0, 54, 0, 143, 0, 376, 0] + 985 [0, 13, 0, 34, 0, 89, 0, 233, 0, 610] + 986 [0, 12, 0, 33, 0, 88, 0, 232, 0, 609] + """ + cdef WordDatatype_char w + cdef size_t i + cdef size_t m + + if isinstance(other, WordDatatype_char): + # C level + # (this can be much faster if we allow to compare larger memory + # zones) + w = other + m = self._length if self._length <= w._length else w._length + for i in range(m): + if self._data[i] != w._data[i]: + break + else: + if self._length <= w._length: + return self + else: + return other + + return self._new_c(self._data, i, self) + + elif PySequence_Check(other): + # Python level + # we avoid to call len(other) since it might be an infinite word + from itertools import islice + for i,a in enumerate(islice(other, self._length)): + if self._data[i] != a: + break + else: + i += 1 + + return self._new_c(self._data, i, self) + + raise TypeError("not able to initialize a word from {}".format(other)) + + def longest_common_suffix(self, other): + r""" + Return the longest common suffix between this word and ``other``. + + EXAMPLES:: + + sage: W = Words([0,1,2]) + sage: W([0,1,0,2]).longest_common_suffix([2,0,2]) + word: 02 + sage: u = W([0,1,0,0,1]) + sage: v = W([1,2,0,0,1]) + sage: u.longest_common_suffix(v) + word: 001 + sage: v.longest_common_suffix(u) + word: 001 + """ + cdef WordDatatype_char w + cdef size_t i + cdef size_t m + + if isinstance(other, WordDatatype_char): + # C level + # (this can be much faster if we could compare larger memory + # zones) + w = other + m = self._length if self._length <= w._length else w._length + for i in range(m): + if self._data[self._length-i-1] != w._data[w._length-i-1]: + break + else: + if self._length <= w._length: + return self + else: + return other + + return self._new_c(self._data+self._length-i, i, self) + + elif PySequence_Check(other): + # Python level + m = self._length if self._length <= len(other) else len(other) + for i in range(m): + if self._data[self._length-i-1] != other[len(other)-i-1]: + break + else: + if self._length == m: + return self + else: + i += 1 + + return self._new_c(self._data+self._length-i, i, self) + + raise TypeError("not able to initialize a word from {}".format(other)) + From 94166b67c1a2e0a06770b7e7fb6acffd71d480f6 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 1 Oct 2015 11:23:26 +0200 Subject: [PATCH 1209/1872] trac #19042: Review --- src/sage/sat/converters/polybori.py | 2 +- src/sage/sat/solvers/sat_lp.py | 6 +++--- src/sage/sat/solvers/satsolver.pyx | 9 ++++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sage/sat/converters/polybori.py b/src/sage/sat/converters/polybori.py index bbc3b64ab8c..11b5d295b14 100644 --- a/src/sage/sat/converters/polybori.py +++ b/src/sage/sat/converters/polybori.py @@ -154,7 +154,7 @@ def var(self, m=None, decision=None): INPUT: - ``m`` - something the new variables maps to, usually a monomial - - ``decision`` - is this variable a deicison variable? + - ``decision`` - is this variable a decision variable? EXAMPLE:: diff --git a/src/sage/sat/solvers/sat_lp.py b/src/sage/sat/solvers/sat_lp.py index 7c8b2fe2e8d..1a74206f162 100644 --- a/src/sage/sat/solvers/sat_lp.py +++ b/src/sage/sat/solvers/sat_lp.py @@ -2,7 +2,7 @@ Solve SAT problems Integer Linear Programming The class defined here is a :class:`~sage.sat.solvers.satsolver.SatSolver` that -solves its instance using :class:`MixedIntegerLinearProgram`. Its performances +solves its instance using :class:`MixedIntegerLinearProgram`. Its performance can be expected to be slower than when using :class:`~sage.sat.solvers.cryptominisat.cryptominisat.CryptoMiniSat`. """ @@ -119,7 +119,7 @@ def __call__(self): ....: return S sage: S = is_bipartite_SAT(graphs.CycleGraph(6)) sage: S() # random - [None, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0] + [None, True, False, True, False, True, False] sage: True in S() True sage: S = is_bipartite_SAT(graphs.CycleGraph(7)) @@ -133,7 +133,7 @@ def __call__(self): b = self._LP.get_values(self._vars) n = max(b) - return [None]+[b.get(i,False) for i in range(1,n+1)] + return [None]+[bool(b.get(i,0)) for i in range(1,n+1)] def __repr__(self): """ diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index 9666c7cae22..734393d4800 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -318,18 +318,17 @@ def SAT(solver=None): if solver is None: try: from sage.sat.solvers.cryptominisat.cryptominisat import CryptoMiniSat - cryptominisat_available = True + solver = "cryptominisat" except ImportError: - cryptominisat_available = False + solver = "LP" - if (solver == 'cryptominisat' or - (solver is None and cryptominisat_available)): + if solver == 'cryptominisat': try: from sage.sat.solvers.cryptominisat.cryptominisat import CryptoMiniSat except ImportError: raise PackageNotFoundError("cryptominisat") return CryptoMiniSat() - elif (solver == "LP" or solver is None): + elif solver == "LP": from sat_lp import SatLP return SatLP() else: From d152338c0f963518f550fa2f6e71f4e4ef58cc4b Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 1 Oct 2015 11:20:47 -0400 Subject: [PATCH 1210/1872] add character.py, character basis to sf, element methods to sfa --- src/sage/combinat/sf/character.py | 234 ++++++++++++++++++++++++++++++ src/sage/combinat/sf/sf.py | 99 +++++++++++++ src/sage/combinat/sf/sfa.py | 93 ++++++++++++ 3 files changed, 426 insertions(+) create mode 100644 src/sage/combinat/sf/character.py diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py new file mode 100644 index 00000000000..df8592ed162 --- /dev/null +++ b/src/sage/combinat/sf/character.py @@ -0,0 +1,234 @@ +""" +character bases of the symmetric functions +""" +#***************************************************************************** +# Copyright (C) 2015 Mike Zabrocki `. + + In terms of methods that are implemented in Sage, if ``n`` is + a sufficiently large integer, then + ``ht(lam).character_to_frobenius_image(n)`` is equal the complete + function indexed by ``[n-sum(lam)]+lam``. + + This basis is introduced in [OZ2015]_. + + .. SEEALSO:: + + :meth:`~sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.character_to_frobenius_image`, + :meth:`~sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.eval_at_permutation_roots` + + EXAMPLES:: + + sage: SymmetricFunctions(QQ).induced_trivial_character() + Symmetric Functions over Rational Field in the induced trivial character basis + sage: ht = SymmetricFunctions(QQ).ht() + sage: h = SymmetricFunctions(QQ).h() + sage: h(ht([3,2]).character_to_frobenius_image(9)) + h[4, 3, 2] + sage: h(ht([3,2]).character_to_frobenius_image(7)) + h[3, 2, 2] + sage: h(ht([3,2]).character_to_frobenius_image(5)) + h[3, 2] + sage: h(ht([3,2]).character_to_frobenius_image(4)) + 0 + sage: p = SymmetricFunctions(QQ).p() + sage: [h([4,1]).scalar(p(rho)) for rho in Partitions(5)] + [0, 1, 0, 2, 1, 3, 5] + sage: [ht([1]).eval_at_permutation_roots(rho) for rho in Partitions(5)] + [0, 1, 0, 2, 1, 3, 5] + """ + from character import character_basis + return character_basis(self, self.h(), "induced trivial character", 'ht') + ht = induced_trivial_character + def forgotten(self): r""" The forgotten basis of the Symmetric Functions (or the basis dual to diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 5d17372220a..2bf4933123f 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5175,6 +5175,99 @@ def hl_creation_operator(self, nu, t = None): for mu in Partitions(d+1, max_length=len(nu)) ) ) + def eval_at_permutation_roots(self, rho): + r""" + Evaluate at eigenvalues of a permutation matrix. + + Evaluate a symmetric function at the eigenvalues of a permutation + matrix whose cycle structure is ``rho``. This computation is + computed by coercing to the power sum basis where the value may + be computed on the generators. + + This function evaluates an element at the roots of unity + + .. MATH:: + + \Xi_{\rho_1},\Xi_{\rho_2},\ldots,\Xi_{\rho_\ell} + + where + + .. MATH:: + + \Xi_{m} = 1,\zeta_m,\zeta_m^2,\ldots,\zeta_m^{m-1} + + and `\zeta_m` is an `m` root of unity. + These roots of unity represent the eigenvalues of permutation + matrix with cycle structure `\rho`. + + INPUT: + + - ``rho`` -- a partition or a list of non-negative integers + + OUTPUT: + + - an element of the base ring + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).s() + sage: s([3,3]).eval_at_permutation_roots([6]) + 0 + sage: s([3,3]).eval_at_permutation_roots([3]) + 1 + sage: s([3,3]).eval_at_permutation_roots([1]) + 0 + sage: s([3,3]).eval_at_permutation_roots([3,3]) + 4 + sage: s([3,3]).eval_at_permutation_roots([1,1,1,1,1]) + 175 + sage: (s[1]+s[2]+s[3]).eval_at_permutation_roots([3,2]) + 2 + """ + p = self.parent().symmetric_function_ring().p() + return p(self).eval_at_permutation_roots(rho) + + def character_to_frobenius_image(self, n): + r""" + Interpret ``self`` as a `Gl_n` character and then take the Frobenius + image of this character of the permutation matrices `S_n` which + naturally sit inside of `Gl_n`. + + To know the value of this character at a permutation of cycle structure + `\rho` the symmetric function ``self`` is evaluated at the + eigenvalues of of a permutation of cycle structure `\rho`. The + Frobenius image is then defined as + `\sum_{\rho \vdash n} f[ \Xi_\rho ] p_\rho/z_\rho`. + + .. SEEALSO:: + :meth:`eval_at_permutation_roots` + + INPUT: + + - ``n`` -- a non-negative integer to interpret ``self`` as + a character of `Gl_n` + + OUTPUT: + + - a symmetric function of degree ``n`` + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).s() + sage: s([1,1]).character_to_frobenius_image(5) + s[3, 1, 1] + s[4, 1] + sage: s([2,1]).character_to_frobenius_image(5) + s[2, 2, 1] + 2*s[3, 1, 1] + 2*s[3, 2] + 3*s[4, 1] + s[5] + sage: s([2,2,2]).character_to_frobenius_image(3) + s[3] + sage: s([2,2,2]).character_to_frobenius_image(4) + s[2, 2] + 2*s[3, 1] + 2*s[4] + sage: s([2,2,2]).character_to_frobenius_image(5) + 2*s[2, 2, 1] + s[3, 1, 1] + 4*s[3, 2] + 3*s[4, 1] + 2*s[5] + """ + p = self.parent().symmetric_function_ring().p() + return self.parent()(p.sum(self.eval_at_permutation_roots(rho) \ + *p(rho)/rho.centralizer_size() for rho in Partitions(n))) SymmetricFunctionAlgebra_generic.Element = SymmetricFunctionAlgebra_generic_Element From 612248ab39ee8d3d67e10a833e6c3059482daf4c Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 1 Oct 2015 12:45:18 -0400 Subject: [PATCH 1211/1872] changes to powersum.py, sf/__init__.py and module_list.rst --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/sf/__init__.py | 1 + src/sage/combinat/sf/character.py | 2 - src/sage/combinat/sf/powersum.py | 103 ++++++++++++++++++ 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index f7fb0ba2d8c..b0e3bd6da98 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -251,6 +251,7 @@ Comprehensive Module list sage/combinat/set_partition_ordered sage/combinat/sf/__init__ sage/combinat/sf/all + sage/combinat/sf/character sage/combinat/sf/classical sage/combinat/sf/dual sage/combinat/sf/elementary diff --git a/src/sage/combinat/sf/__init__.py b/src/sage/combinat/sf/__init__.py index 3fd89a5bbe1..81da64b61b1 100644 --- a/src/sage/combinat/sf/__init__.py +++ b/src/sage/combinat/sf/__init__.py @@ -13,6 +13,7 @@ - :ref:`sage.combinat.sf.elementary` - :ref:`sage.combinat.sf.homogeneous` - :ref:`sage.combinat.sf.powersum` +- :ref:`sage.combinat.sf.character` - :ref:`sage.combinat.sf.dual` - :ref:`sage.combinat.sf.orthotriang` - :ref:`sage.combinat.sf.kfpoly` diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index df8592ed162..3e97234935b 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -19,8 +19,6 @@ from sage.misc.cachefunc import cached_method from sage.categories.homset import Hom from sage.combinat.partition import Partition -from sage.rings.arith import divisors, moebius -from sage.functions.other import binomial class generic_character(SFA_generic): def _my_key(self, la): diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index c61ca4dbaab..b97176ab8cc 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -19,6 +19,7 @@ #***************************************************************************** import sfa, multiplicative, classical from sage.combinat.partition import Partition +from sage.rings.arith import divisors class SymmetricFunctionAlgebra_power(multiplicative.SymmetricFunctionAlgebra_multiplicative): def __init__(self, Sym): @@ -164,6 +165,55 @@ def bottom_schur_function(self, partition, degree=None): in s_partition if len(p) == degree], distinct=True) + def eval_at_permutation_roots_on_generators(self, k, rho): + r""" + Evaluate `p_k` at eigenvalues of permutation matrix. + + This function evaluates a symmetric function ``p([k])`` + at the eigenvalues of a permutation matrix with cycle + structure ``\rho``. + + This function evaluates a `p_k` at the roots of unity + + .. MATH:: + + \Xi_{\rho_1},\Xi_{\rho_2},\ldots,\Xi_{\rho_\ell} + + where + + .. MATH:: + + \Xi_{m} = 1,\zeta_m,\zeta_m^2,\ldots,\zeta_m^{m-1} + + and `\zeta_m` is an `m` root of unity. + This is characterized by `p_k[ A , B ] = p_k[A] + p_k[B]` and + `p_k[ \Xi_m ] = 0` unless `m` divides `k` and `p_{rm}[\Xi_m]=m`. + + INPUT: + + - ``k`` -- a non-negative integer + - ``rho`` -- a partition or a list of non-negative integers + + OUTPUT: + + - an element of the base ring + + EXAMPLES:: + + sage: p = SymmetricFunctions(QQ).p() + sage: p.eval_at_permutation_roots_on_generators(3, [6]) + 0 + sage: p.eval_at_permutation_roots_on_generators(3, [3]) + 3 + sage: p.eval_at_permutation_roots_on_generators(3, [1]) + 1 + sage: p.eval_at_permutation_roots_on_generators(3, [3,3]) + 6 + sage: p.eval_at_permutation_roots_on_generators(3, [1,1,1,1,1]) + 5 + """ + return self.base_ring().sum(d*list(rho).count(d) for d in divisors(k)) + class Element(classical.SymmetricFunctionAlgebra_classical.Element): def omega(self): r""" @@ -600,6 +650,59 @@ def expand(self, n, alphabet='x'): condition = lambda part: False return self._expand(condition, n, alphabet) + def eval_at_permutation_roots(self, rho): + r""" + Evaluate at eigenvalues of a permutation matrix. + + Evaluate an element of the power sum basis at the eigenvalues + of a permutation matrix with cycle structure `\rho`. + + This function evaluates an element at the roots of unity + + .. MATH:: + + \Xi_{\rho_1},\Xi_{\rho_2},\ldots,\Xi_{\rho_\ell} + + where + + .. MATH:: + + \Xi_{m} = 1,\zeta_m,\zeta_m^2,\ldots,\zeta_m^{m-1} + + and `\zeta_m` is an `m` root of unity. + These roots of unity represent the eigenvalues of permutation + matrix with cycle structure `\rho`. + + INPUT: + + - ``rho`` -- a partition or a list of non-negative integers + + OUTPUT: + + - an element of the base ring + + EXAMPLES:: + + sage: p = SymmetricFunctions(QQ).p() + sage: p([3,3]).eval_at_permutation_roots([6]) + 0 + sage: p([3,3]).eval_at_permutation_roots([3]) + 9 + sage: p([3,3]).eval_at_permutation_roots([1]) + 1 + sage: p([3,3]).eval_at_permutation_roots([3,3]) + 36 + sage: p([3,3]).eval_at_permutation_roots([1,1,1,1,1]) + 25 + sage: (p[1]+p[2]+p[3]).eval_at_permutation_roots([3,2]) + 5 + """ + p = self.parent() + R = self.base_ring() + on_basis = lambda lam: R.prod( + p.eval_at_permutation_roots_on_generators(k, rho) for k in lam) + return p._apply_module_morphism(self, on_basis, R) + # Backward compatibility for unpickling from sage.structure.sage_object import register_unpickle_override register_unpickle_override('sage.combinat.sf.powersum', 'SymmetricFunctionAlgebraElement_power', SymmetricFunctionAlgebra_power.Element) From 048b036934efaefb3a4c38b8a5d0b90ff25dc995 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 1 Oct 2015 22:53:04 +0200 Subject: [PATCH 1212/1872] Implement conversion of interval fields to real/complex fields --- src/sage/rings/complex_interval.pyx | 22 +++++- src/sage/rings/complex_interval_field.py | 9 ++- src/sage/rings/qqbar.py | 4 +- src/sage/rings/real_mpfi.pxd | 6 +- src/sage/rings/real_mpfi.pyx | 93 ++++++++++++++---------- 5 files changed, 83 insertions(+), 51 deletions(-) diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 2fc79377f4a..655600142e2 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -51,10 +51,9 @@ from complex_number cimport ComplexNumber import complex_interval_field from complex_field import ComplexField import sage.misc.misc -import integer +cimport integer import infinity -import real_mpfi -import real_mpfr +cimport real_mpfi cimport real_mpfr @@ -927,6 +926,23 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): return x + def _complex_mpfr_field_(self, field): + """ + Convert to a complex field. + + EXAMPLES:: + + sage: re = RIF("1.2") + sage: im = RIF(2, 3) + sage: a = ComplexIntervalField(30)(re, im) + sage: CC(a) + 1.20000000018626 + 2.50000000000000*I + """ + cdef ComplexNumber x = field(0) + mpfi_mid(x.__re, self.__re) + mpfi_mid(x.__im, self.__im) + return x + def __int__(self): """ Convert ``self`` to an ``int``. diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index a400f29f278..e147a410be5 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -377,10 +377,15 @@ def __call__(self, x, im=None): 2 + 3*I sage: CIF(pi, e) 3.141592653589794? + 2.718281828459046?*I + sage: ComplexIntervalField(100)(CIF(RIF(2,3))) + 3.? """ if im is None: - if isinstance(x, complex_interval.ComplexIntervalFieldElement) and x.parent() is self: - return x + if isinstance(x, complex_interval.ComplexIntervalFieldElement): + if x.parent() is self: + return x + else: + return complex_interval.ComplexIntervalFieldElement(self, x) elif isinstance(x, complex_double.ComplexDoubleElement): return complex_interval.ComplexIntervalFieldElement(self, x.real(), x.imag()) elif isinstance(x, str): diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 87143860d09..b12789b9194 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -362,8 +362,8 @@ AA(2) Just for fun, let's try ``sage_input`` on a very complicated expression. The -output of this example changed with the rewritting of polynomial multiplication -algorithms in #10255:: +output of this example changed with the rewriting of polynomial multiplication +algorithms in :trac:`10255`:: sage: rt2 = sqrt(AA(2)) sage: rt3 = sqrt(QQbar(3)) diff --git a/src/sage/rings/real_mpfi.pxd b/src/sage/rings/real_mpfi.pxd index 5996b03d2f5..d90d471627e 100644 --- a/src/sage/rings/real_mpfi.pxd +++ b/src/sage/rings/real_mpfi.pxd @@ -2,15 +2,13 @@ from sage.libs.mpfi cimport * cimport sage.rings.ring -cimport sage.structure.element from sage.structure.element cimport RingElement -from rational import Rational from rational cimport Rational cimport real_mpfr -cdef class RealIntervalFieldElement(sage.structure.element.RingElement) # forward decl +cdef class RealIntervalFieldElement(RingElement) # forward decl cdef class RealIntervalField_class(sage.rings.ring.Field): cdef int __prec @@ -35,7 +33,7 @@ cdef class RealIntervalField_class(sage.rings.ring.Field): cdef RealIntervalFieldElement _new(self) -cdef class RealIntervalFieldElement(sage.structure.element.RingElement): +cdef class RealIntervalFieldElement(RingElement): cdef mpfi_t value cdef char init cdef RealIntervalFieldElement _new(self) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 85d3b750787..b3ba9c88ebb 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -239,6 +239,7 @@ Comparisons with numpy types are right (see :trac:`17758` and :trac:`18076`):: import math # for log import sys +import operator include 'sage/ext/interrupt.pxi' include "sage/ext/cdefs.pxi" @@ -246,32 +247,21 @@ from cpython.mem cimport * from cpython.string cimport * cimport sage.rings.ring -import sage.rings.ring - cimport sage.structure.element from sage.structure.element cimport RingElement, Element, ModuleElement -import sage.structure.element cimport real_mpfr -from real_mpfr cimport RealField_class, RealNumber -from real_mpfr import RealField -import real_mpfr - -import operator +from real_mpfr cimport RealField_class, RealNumber, RealField +from sage.libs.mpfr cimport MPFR_RNDN, MPFR_RNDZ, MPFR_RNDU, MPFR_RNDD, MPFR_RNDA -from integer import Integer from integer cimport Integer - -from real_double import RealDoubleElement from real_double cimport RealDoubleElement import sage.rings.complex_field - import sage.rings.infinity from sage.structure.parent_gens cimport ParentWithGens -cdef class RealIntervalFieldElement(sage.structure.element.RingElement) #***************************************************************************** # @@ -1115,16 +1105,13 @@ cdef class RealIntervalField_class(sage.rings.ring.Field): return self(-1) raise ValueError, "No %sth root of unity in self"%n -R = RealIntervalField() #***************************************************************************** # # RealIntervalFieldElement -- element of Real Field # -# -# #***************************************************************************** -cdef class RealIntervalFieldElement(sage.structure.element.RingElement): +cdef class RealIntervalFieldElement(RingElement): """ A real number interval. """ @@ -3073,33 +3060,59 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): # Conversions ########################################### -# def __float__(self): -# return mpfr_get_d(self.value, (self._parent).rnd) - -# def __int__(self): -# """ -# Returns integer truncation of this real number. -# """ -# s = self.str(32) -# i = s.find('.') -# return int(s[:i], 32) + def _mpfr_(self, RealField_class field): + """ + Convert to a real field, honoring the rounding mode of the + real field. -# def __long__(self): -# """ -# Returns long integer truncation of this real number. -# """ -# s = self.str(32) -# i = s.find('.') -# return long(s[:i], 32) + EXAMPLES:: -# def __complex__(self): -# return complex(float(self)) + sage: a = RealIntervalField(30)("1.2") + sage: RR(a) + 1.20000000018626 + sage: b = RIF(-1, 3) + sage: RR(b) + 1.00000000000000 -# def _complex_number_(self): -# return sage.rings.complex_field.ComplexField(self.prec())(self) + With different rounding modes:: -# def _pari_(self): -# return sage.libs.pari.all.pari.new_with_bits_prec(str(self), (self._parent).__prec) + sage: RealField(53, rnd="RNDU")(a) + 1.20000000111759 + sage: RealField(53, rnd="RNDD")(a) + 1.19999999925494 + sage: RealField(53, rnd="RNDZ")(a) + 1.19999999925494 + sage: RealField(53, rnd="RNDU")(b) + 3.00000000000000 + sage: RealField(53, rnd="RNDD")(b) + -1.00000000000000 + sage: RealField(53, rnd="RNDZ")(b) + 0.000000000000000 + """ + cdef RealNumber x = field._new() + if field.rnd == MPFR_RNDN: + mpfi_mid(x.value, self.value) + elif field.rnd == MPFR_RNDD: + mpfi_get_left(x.value, self.value) + elif field.rnd == MPFR_RNDU: + mpfi_get_right(x.value, self.value) + elif field.rnd == MPFR_RNDZ: + if mpfi_is_strictly_pos_default(self.value): # interval is > 0 + mpfi_get_left(x.value, self.value) + elif mpfi_is_strictly_neg_default(self.value): # interval is < 0 + mpfi_get_right(x.value, self.value) + else: + mpfr_set_zero(x.value, 1) # interval contains 0 + elif field.rnd == MPFR_RNDA: + # return the endpoint which is furthest from 0 + lo, hi = self.endpoints() + if hi.abs() >= lo.abs(): + mpfi_get_right(x.value, self.value) + else: + mpfi_get_left(x.value, self.value) + else: + raise AssertionError("%s has unknown rounding mode"%field) + return x def unique_sign(self): r""" From 752c401b852050c48186439a727040e3d81d90be Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 1 Oct 2015 23:22:36 +0200 Subject: [PATCH 1213/1872] Use the new conversions in qqbar --- src/sage/rings/qqbar.py | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index b12789b9194..8fc07afb441 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -4553,13 +4553,13 @@ def complex_number(self, field): EXAMPLES:: sage: a = QQbar.zeta(5) - sage: a.complex_number(CIF) + sage: a.complex_number(CC) 0.309016994374947 + 0.951056516295154*I - sage: (a + a.conjugate()).complex_number(CIF) + sage: (a + a.conjugate()).complex_number(CC) 0.618033988749895 - 5.42101086242752e-20*I """ v = self.interval(ComplexIntervalField(field.prec())) - return v.center() + return field(v) def complex_exact(self, field): r""" @@ -5204,21 +5204,7 @@ def real_number(self, field): 1.41421356237309 """ v = self.interval(RealIntervalField(field.prec())) - - mode = field.rounding_mode() - if mode == 'RNDN': - return v.center() - if mode == 'RNDD': - return v.lower() - if mode == 'RNDU': - return v.upper() - if mode == 'RNDZ': - if v > 0: - return field(v.lower()) - elif v < 0: - return field(v.upper()) - else: - return field(0) + return field(v) _mpfr_ = real_number From 88b74bba339c1ff53063ebe43819b222fd478f1b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 1 Oct 2015 21:53:50 -0400 Subject: [PATCH 1214/1872] Trac #19332: Add discrete_complementarity_set() method for cones. Any sort of "linear property" on a cone can usually be verified on a generating set of the cone instead of the whole thing. This involves a finite number of steps for a polyhedral cone. The discrete complementarity set is a finite subset, consisting of generators, of the usual complementarity set that appears in complementarity and mathematical programming problems. Having it available lets us check complementarity properties on the cone. This commit adds the method, examples, and tests. --- src/sage/geometry/cone.py | 94 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 936b8c434ee..e425afad19f 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -4348,6 +4348,100 @@ def lineality(self): """ return self.linear_subspace().dimension() + def discrete_complementarity_set(self): + r""" + Compute a discrete complementarity set of this cone. + + A discrete complementarity set of a cone is the set of all + orthogonal pairs `(x,s)` where `x` is in some fixed generating + set of the cone, and `s` is in some fixed generating set of its + dual. The generators chosen for this cone and its dual are + simply their :meth:`~IntegralRayCollection.rays`. + + OUTPUT: + + A list of pairs `(x,s)` such that, + + * `x` and `s` are orthogonal vectors. + * `x` is one of this cone's :meth:`~IntegralRayCollection.rays`. + * `s` is one of the :meth:`~IntegralRayCollection.rays` of this + cone's :meth:`dual`. + + REFERENCES: + + .. [Orlitzky] M. Orlitzky. The Lyapunov rank of an improper cone. + http://www.optimization-online.org/DB_HTML/2015/10/5135.html + + EXAMPLES: + + The discrete complementarity set of the nonnegative orthant + consists of pairs of standard basis vectors:: + + sage: K = Cone([(1,0),(0,1)]) + sage: K.discrete_complementarity_set() + [((1, 0), (0, 1)), ((0, 1), (1, 0))] + + If the cone consists of a single ray, the second components of + the discrete complementarity set should generate the orthogonal + complement of that ray:: + + sage: K = Cone([(1,0)]) + sage: K.discrete_complementarity_set() + [((1, 0), (0, 1)), ((1, 0), (0, -1))] + sage: K = Cone([(1,0,0)]) + sage: K.discrete_complementarity_set() + [((1, 0, 0), (0, 1, 0)), + ((1, 0, 0), (0, -1, 0)), + ((1, 0, 0), (0, 0, 1)), + ((1, 0, 0), (0, 0, -1))] + + When the cone is the entire space, its dual is the trivial cone, + so the discrete complementarity set is empty:: + + sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) + sage: K.discrete_complementarity_set() + [] + + Likewise when this cone is trivial (its dual is the entire space):: + + sage: L = ToricLattice(0) + sage: K = Cone([], ToricLattice(0)) + sage: K.discrete_complementarity_set() + [] + + TESTS: + + The complementarity set of the dual can be obtained by switching + components in the complementarity set of the original cone:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=6) + sage: dcs_dual = K.dual().discrete_complementarity_set() + sage: expected = [ (x,s) for (s,x) in dcs_dual ] + sage: actual = K.discrete_complementarity_set() + sage: sorted(actual) == sorted(expected) + True + + The pairs in the discrete complementarity set are in fact + complementary:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=6) + sage: dcs = K.discrete_complementarity_set() + sage: sum([ x.inner_product(s).abs() for (x,s) in dcs ]) + 0 + + """ + V = self.lattice().vector_space() + + # Convert rays to vectors so that we can compute inner products. + G1 = [ V(x) for x in self.rays() ] + + # We also convert the generators of the dual cone so that we + # return pairs of vectors and not (vector, ray) pairs. + G2 = [ V(s) for s in self.dual().rays() ] + + return [ (x,s) for x in G1 for s in G2 if x.inner_product(s) == 0 ] def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, From c281a6c684ba517944bd4ad173d028f3bde6cd93 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 1 Oct 2015 23:33:15 -0400 Subject: [PATCH 1215/1872] implementation of irreducible character basis by power sum expansion --- src/sage/combinat/sf/character.py | 209 ++++++++++++++++++++++++++++++ src/sage/combinat/sf/sf.py | 5 +- 2 files changed, 211 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 3e97234935b..7e637611b3d 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -230,3 +230,212 @@ def _self_to_other_on_basis(self, lam): sim = self._other(self._other(lam).character_to_frobenius_image(n)) return self._other(lam)-sum(c*self._self_to_other_on_basis( \ Partition(mu[1:])) for (mu,c) in sim if mu[1:]!=lam) + +class irreducible_character_basis(generic_character): + r""" + The irreducible symmetric group character basis of the symmetric functions + """ + def __init__(self, Sym, pfix): + r""" + Initialize the basis and register coercions + + The coercions are set up between the ``other_basis`` + + INPUT: + + - ``Sym`` -- an instance of the symmetric function algebra + - ``pfix`` -- a prefix to use for the basis + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ) + sage: ht = SymmetricFunctions(QQ).ht(); ht + Symmetric Functions over Rational Field in the induced trivial character basis + sage: st = SymmetricFunctions(QQ).st(); st + Symmetric Functions over Rational Field in the irreducible symmetric group character basis + """ + SFA_generic.__init__(self, Sym, \ + basis_name="irreducible symmetric group character", prefix=pfix) + self._other = Sym.Schur() + self._p = Sym.powersum() + from sage.categories.graded_hopf_algebras_with_basis \ + import GradedHopfAlgebrasWithBasis + categ = GradedHopfAlgebrasWithBasis(self.base_ring()) + self.module_morphism(self._self_to_power_on_basis, + codomain=Sym.powersum(), category=categ).register_as_coercion() + from sage.categories.morphism import SetMorphism + self.register_coercion( + SetMorphism(Hom(self._other, self, categ), self._other_to_self)) + + def _b_power_k(self, k): + r""" + An expression involving moebius inversion in the powersum generators. + + For a positive value of ``k``, this expression is + + .. MATH:: + + \frac{1}{k} \sum_{d|k} \mu(d/k) p_d + + INPUT: + + - ``k`` -- a positive integer + + OUTPUT: + + - an expression in the powersum basis of the symmetric functions + + EXAMPLES:: + + sage: st = SymmetricFunctions(QQ).st() + sage: st._b_power_k(1) + p[1] + sage: st._b_power_k(2) + -1/2*p[1] + 1/2*p[2] + sage: st._b_power_k(6) + 1/6*p[1] - 1/6*p[2] - 1/6*p[3] + 1/6*p[6] + + """ + if k==1: + return self._p([1]) + if k>0: + return 1/k*self._p.sum(moebius(k/d)*self._p([d]) for d in \ + divisors(k)) + + def _b_power_k_r(self, k, r): + r""" + An expression involving moebius inversion in the powersum generators. + + For a positive value of ``k``, this expression is + + .. MATH:: + + \sum_{j=0}^r (-1)^{r-j}k^j\binom{r,j} \left( + \frac{1}{k} \sum_{d|k} \mu(d/k) p_d \right)_k + + INPUT: + + - ``k``, ``r`` -- positive integers + + OUTPUT: + + - an expression in the powersum basis of the symmetric functions + + EXAMPLES:: + + sage: st = SymmetricFunctions(QQ).st() + sage: st._b_power_k_r(1,1) + -p[] + p[1] + sage: st._b_power_k_r(2,2) + p[] + 4*p[1] + p[1, 1] - 4*p[2] - 2*p[2, 1] + p[2, 2] + sage: st._b_power_k_r(3,2) + p[] + 5*p[1] + p[1, 1] - 5*p[3] - 2*p[3, 1] + p[3, 3] + + """ + p = self._p + return p.sum((-1)**(r-j)*k**j*binomial(r,j)*p.prod( \ + self._b_power_k(k)-i*p.one() for i in range(j)) for j in range(r+1)) + + def _b_power_gamma(self, gamma): + r""" + An expression involving moebius inversion in the powersum generators. + + For a partition `\gamma = (1^{m_1}, 2^{m_2}, \ldots r^{m_r})`, + this expression is + + .. MATH:: + + {\mathbf p}_{\ga} = \sum_{k \geq 1} {\mathbf p}_{k^{m_k}} + + where + + .. MATH:: + + {\mathbf p}_{k^r} = \sum_{j=0}^r (-1)^{r-j}k^j\binom{r,j} + \left( \frac{1}{k} \sum_{d|k} \mu(d/k) p_d \right)_k~. + + INPUT: + + - ``gamma`` -- a partition + + OUTPUT: + + - an expression in the powersum basis of the symmetric functions + + EXAMPLES:: + + sage: st = SymmetricFunctions(QQ).st() + sage: st._b_power_k_r(1,1) + -p[] + p[1] + sage: st._b_power_k_r(2,2) + p[] + 4*p[1] + p[1, 1] - 4*p[2] - 2*p[2, 1] + p[2, 2] + sage: st._b_power_k_r(3,2) + p[] + 5*p[1] + p[1, 1] - 5*p[3] - 2*p[3, 1] + p[3, 3] + + """ + return self._p.prod( self._b_power_k_r(Integer(k),Integer(r)) \ + for (k,r) in gamma.to_exp_dict().iteritems()) + + def _self_to_power_on_basis(self, lam): + r""" + An expansion of the irreducible character in the powersum basis. + + The formula for the irreducible character basis indexed by the + partition ``lam`` is given by the formula + + .. MATH:: + + \sum_{\gamma} \chi^{\lambda}(\gamma) + \frac{{\mathbf p}_\gamma}{z_\gamma} + + where `\chi^{\lambda}(\gamma)` is the irreducible character + indexed by the partition `\lambda` and evaluated at an element + of cycle structure `\gamma` and `{\mathbf p}_\gamma` is the + power sum expression calculated in the method + ``_b_power_gamma``. + + INPUT: + + - ``lam`` -- a partition + + OUTPUT: + + - an expression in the power sum basis + + EXAMPLES:: + + sage: st = SymmetricFunctions(QQ).st() + sage: st._self_to_power_on_basis([2,1]) + 3*p[1] - 2*p[1, 1] + 1/3*p[1, 1, 1] - 1/3*p[3] + sage: st._self_to_power_on_basis([1,1]) + p[] - p[1] + 1/2*p[1, 1] - 1/2*p[2] + + """ + return self._p.sum(c*self._b_power_gamma(ga) for (ga, c) in \ + self._p(self._other(lam))) + @cached_method + def _self_to_other_on_basis(self, lam): + r""" + An expansion of the irreducible character basis in the Schur basis. + + Compute the Schur expansion by first computing it in the + powersum basis and the coercing to the Schur basis. + + INPUT: + + - ``lam`` -- a partition + + OUTPUT: + + - an expression in the Schur basis + + EXAMPLES:: + + sage: st = SymmetricFunctions(QQ).st() + sage: st._self_to_other_on_basis(Partition([1,1])) + s[] - s[1] + s[1, 1] + sage: st._self_to_other_on_basis(Partition([2,1])) + 3*s[1] - 2*s[1, 1] - 2*s[2] + s[2, 1] + + """ + return self._other(self._self_to_power_on_basis(lam)) diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 798d6594f67..b93c8b90cf5 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -975,9 +975,8 @@ def irreducible_symmetric_group_character(self): ....: for rho in Partitions(5)])) [4, 2, 0, 1, -1, 0, -1] """ - from character import character_basis - return character_basis(self, self.s(), \ - "irreducible symmetric group character",'st') + from character import irreducible_character_basis + return irreducible_character_basis(self, 'st') st = irreducible_symmetric_group_character def induced_trivial_character(self): From 0f4e373b88a1c18492d2489485829131ec476c65 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 2 Oct 2015 15:10:16 +0200 Subject: [PATCH 1216/1872] Revert "Trac #19280: add fix to all x86 gmp-mparam" This reverts commit b5049f672d39e857cded703259322be0bb99817f. --- build/pkgs/mpir/patches/fix-19280.patch | 189 ------------------------ 1 file changed, 189 deletions(-) diff --git a/build/pkgs/mpir/patches/fix-19280.patch b/build/pkgs/mpir/patches/fix-19280.patch index 6b2f224dff4..0afe281b2b0 100644 --- a/build/pkgs/mpir/patches/fix-19280.patch +++ b/build/pkgs/mpir/patches/fix-19280.patch @@ -1,191 +1,2 @@ Apply the fix proposed in http://trac.sagemath.org/ticket/18546#comment:23 to the bug reported in http://trac.sagemath.org/ticket/19280 . -diff -ru mpir-2.7.0/mpn/x86/applenopic/core2/gmp-mparam.h mpir-2.7.0-new/mpn/x86/applenopic/core2/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/applenopic/core2/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/applenopic/core2/gmp-mparam.h 2015-09-24 19:31:45.060547384 +0200 -@@ -1,3 +1,7 @@ -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - /* Generated by tuneup.c, 2009-10-08, gcc 4.2 */ - - #define MUL_KARATSUBA_THRESHOLD 22 -Nur in mpir-2.7.0-new/mpn/x86/applenopic/core2: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/core2/gmp-mparam.h mpir-2.7.0-new/mpn/x86/core2/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/core2/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/core2/gmp-mparam.h 2015-09-24 19:31:32.730385817 +0200 -@@ -1,3 +1,7 @@ -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - /* Generated by tuneup.c, 2010-03-24, gcc 4.4 */ - - #define MUL_KARATSUBA_THRESHOLD 22 -Nur in mpir-2.7.0-new/mpn/x86/core2: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/fat/gmp-mparam.h mpir-2.7.0-new/mpn/x86/fat/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/fat/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/fat/gmp-mparam.h 2015-09-24 19:31:51.575803154 +0200 -@@ -20,6 +20,10 @@ - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - #define BITS_PER_MP_LIMB 32 - #define BYTES_PER_MP_LIMB 4 - -Nur in mpir-2.7.0-new/mpn/x86/fat: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/gmp-mparam.h mpir-2.7.0-new/mpn/x86/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/gmp-mparam.h 2015-09-24 19:32:16.420218287 +0200 -@@ -20,6 +20,10 @@ - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - #define BITS_PER_MP_LIMB 32 - #define BYTES_PER_MP_LIMB 4 - -Nur in mpir-2.7.0-new/mpn/x86: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/i486/gmp-mparam.h mpir-2.7.0-new/mpn/x86/i486/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/i486/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/i486/gmp-mparam.h 2015-09-24 19:31:16.962506371 +0200 -@@ -19,6 +19,11 @@ - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ -+ - #define BITS_PER_MP_LIMB 32 - #define BYTES_PER_MP_LIMB 4 - -Nur in mpir-2.7.0-new/mpn/x86/i486: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/k6/gmp-mparam.h mpir-2.7.0-new/mpn/x86/k6/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/k6/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/k6/gmp-mparam.h 2015-09-24 19:31:40.646341539 +0200 -@@ -20,6 +20,10 @@ - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - #define BITS_PER_MP_LIMB 32 - #define BYTES_PER_MP_LIMB 4 - -Nur in mpir-2.7.0-new/mpn/x86/k6: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/k7/gmp-mparam.h mpir-2.7.0-new/mpn/x86/k7/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/k7/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/k7/gmp-mparam.h 2015-09-24 19:32:23.167590050 +0200 -@@ -1,3 +1,7 @@ -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - /* Generated by tuneup.c, 2010-03-24, gcc 4.3 */ - - #define MUL_KARATSUBA_THRESHOLD 26 -Nur in mpir-2.7.0-new/mpn/x86/k7: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/k7/mmx/k8/gmp-mparam.h mpir-2.7.0-new/mpn/x86/k7/mmx/k8/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/k7/mmx/k8/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/k7/mmx/k8/gmp-mparam.h 2015-09-24 19:32:19.753884166 +0200 -@@ -1,3 +1,7 @@ -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - /* Generated by tuneup.c, 2010-03-24, gcc 4.4 */ - - #define MUL_KARATSUBA_THRESHOLD 28 -Nur in mpir-2.7.0-new/mpn/x86/k7/mmx/k8: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/nehalem/gmp-mparam.h mpir-2.7.0-new/mpn/x86/nehalem/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/nehalem/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/nehalem/gmp-mparam.h 2015-09-24 19:32:09.640830522 +0200 -@@ -1,3 +1,7 @@ -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - /* Generated by tuneup.c, 2009-10-07, gcc 4.3 */ - - #define MUL_KARATSUBA_THRESHOLD 18 -Nur in mpir-2.7.0-new/mpn/x86/nehalem: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/p6/gmp-mparam.h mpir-2.7.0-new/mpn/x86/p6/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/p6/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/p6/gmp-mparam.h 2015-09-24 19:32:32.796401709 +0200 -@@ -20,6 +20,9 @@ - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 - - #define BITS_PER_MP_LIMB 32 - #define BYTES_PER_MP_LIMB 4 -Nur in mpir-2.7.0-new/mpn/x86/p6: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/p6/mmx/gmp-mparam.h mpir-2.7.0-new/mpn/x86/p6/mmx/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/p6/mmx/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/p6/mmx/gmp-mparam.h 2015-09-24 19:32:27.597803891 +0200 -@@ -20,6 +20,9 @@ - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 - - #define BITS_PER_MP_LIMB 32 - #define BYTES_PER_MP_LIMB 4 -Nur in mpir-2.7.0-new/mpn/x86/p6/mmx: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/pentium/gmp-mparam.h mpir-2.7.0-new/mpn/x86/pentium/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/pentium/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/pentium/gmp-mparam.h 2015-09-24 19:32:04.174098713 +0200 -@@ -20,6 +20,9 @@ - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 - - #define BITS_PER_MP_LIMB 32 - #define BYTES_PER_MP_LIMB 4 -Nur in mpir-2.7.0-new/mpn/x86/pentium: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/pentium/mmx/gmp-mparam.h mpir-2.7.0-new/mpn/x86/pentium/mmx/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/pentium/mmx/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/pentium/mmx/gmp-mparam.h 2015-09-24 19:31:57.902964934 +0200 -@@ -20,6 +20,9 @@ - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 - - #define BITS_PER_MP_LIMB 32 - #define BYTES_PER_MP_LIMB 4 -Nur in mpir-2.7.0-new/mpn/x86/pentium/mmx: gmp-mparam.h~. -diff -ru mpir-2.7.0/mpn/x86/pentium4/sse2/gmp-mparam.h mpir-2.7.0-new/mpn/x86/pentium4/sse2/gmp-mparam.h ---- mpir-2.7.0/mpn/x86/pentium4/sse2/gmp-mparam.h 2015-05-30 05:15:49.000000000 +0200 -+++ mpir-2.7.0-new/mpn/x86/pentium4/sse2/gmp-mparam.h 2015-09-24 19:32:36.226115587 +0200 -@@ -1,3 +1,7 @@ -+/* see http://trac.sagemath.org/ticket/19280 */ -+#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 -+#define SB_DIV_QR_SMALL_THRESHOLD 0 -+ - /* Generated by tuneup.c, 2014-03-24, gcc 4.7 */ - - #define MUL_KARATSUBA_THRESHOLD 22 -Nur in mpir-2.7.0-new/mpn/x86/pentium4/sse2: gmp-mparam.h~. From f780291ccb0363c69411dfe723de795f2c75093b Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 2 Oct 2015 15:13:01 +0200 Subject: [PATCH 1217/1872] Trac #19280: Use patch proposed in http://trac.sagemath.org/ticket/19280#comment:5 --- build/pkgs/mpir/patches/fix-19280.patch | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/build/pkgs/mpir/patches/fix-19280.patch b/build/pkgs/mpir/patches/fix-19280.patch index 0afe281b2b0..ced078c66ee 100644 --- a/build/pkgs/mpir/patches/fix-19280.patch +++ b/build/pkgs/mpir/patches/fix-19280.patch @@ -1,2 +1,22 @@ Apply the fix proposed in http://trac.sagemath.org/ticket/18546#comment:23 to the bug reported in http://trac.sagemath.org/ticket/19280 . + +diff -ru mpir-2.7.0/gmp-impl.h mpir-2.7.0-fixed/gmp-impl.h +Index: gmp-impl.h +=================================================================== +--- mpir-2.7.0/gmp-impl.h 2015-06-10 23:02:35.000000000 +0200 ++++ mpir-2.7.0-fixed/gmp-impl.h 2015-09-29 17:04:17.746919331 +0200 +@@ -2040,11 +2040,11 @@ + #endif + + #ifndef SB_DIVAPPR_Q_SMALL_THRESHOLD +-#define SB_DIVAPPR_Q_SMALL_THRESHOLD 11 ++#define SB_DIVAPPR_Q_SMALL_THRESHOLD 0 + #endif + + #ifndef SB_DIV_QR_SMALL_THRESHOLD +-#define SB_DIV_QR_SMALL_THRESHOLD 11 ++#define SB_DIV_QR_SMALL_THRESHOLD 0 + #endif + + #ifndef DC_DIVAPPR_Q_THRESHOLD From c655f9ffb0ad9f0bfdaf712a4becb2e9eb9c1a70 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 2 Oct 2015 11:19:07 -0300 Subject: [PATCH 1218/1872] Trac 19319: Cantor iteration of cartesian products --- src/sage/misc/mrange.py | 69 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index eb03223dbf6..457111a8ef1 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -608,3 +608,72 @@ def cartesian_product_iterator(X): [()] """ return xmrange_iter(X, tuple) + +def cantor_product(*args): + r""" + Return an iterator over the product of `A` and `B` which iterates + along the diagonals a la + :wikipedia:`Cantor pairing `. + + INPUT: + + - a certain number of iteratable + + EXAMPLES:: + + sage: from sage.misc.mrange import cantor_product + sage: list(cantor_product([0,1], [0,1], [0,1])) + [[0, 0, 0], + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [1, 1, 0], + [1, 0, 1], + [0, 1, 1], + [1, 1, 1]] + sage: list(cantor_product([0,1], [0,1,2,3]) + [[0, 0], [1, 0], [0, 1], [1, 1], [0, 2], [1, 2], [0, 3], [1, 3]] + + Infinite iterators are valid input as well:: + + sage: from itertools import islice + sage: list(islice(product_cantor_pairing(ZZ, QQ), 14)) + [[0, 0], [0, 1], [1, 0], [0, -1], [1, 1], [-1, 0], [0, 1/2], + [1, -1], [-1, 1], [2, 0], [0, -1/2], [1, 1/2], [-1, -1], [2, 1]] + + TESTS:: + + sage: C = cantor_product([0,1], [0,1,2,3], [0,1,2]) + sage: sum(1 for _ in C) == 2*4*3 + True + + sage: list(cantor_product([], count())) + [] + """ + from itertools import count + from sage.combinat.integer_list import IntegerListsLex + + m = len(args) # numer of factors + lengths = [None] * m # None or length of factors + data = [[] for _ in range(m)] # the initial slice of each factor + iterators = [iter(a) for a in args] # the iterators + + for n in count(0): + # try to add one more term to each bin + for i,a in enumerate(iterators): + if lengths[i] is None: + try: + data[i].append(a.next()) + except StopIteration: + assert len(data[i]) == n + if n == 0: + return + lengths[i] = n + + # iterate through what we have + ceiling = [n if lengths[i] is None else lengths[i]-1 for i in range(m)] + for v in IntegerListsLex(n, length=m, ceiling=ceiling): + yield [data[i][v[i]] for i in range(m)] + + if all(l is not None for l in lengths) and sum(l-1 for l in lengths) == n: + return From 4a52a845469078b5418937e8927d473e8b3d2ec6 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 2 Oct 2015 11:25:01 -0300 Subject: [PATCH 1219/1872] Trac 19319: fix doctests --- src/sage/misc/mrange.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 457111a8ef1..26883625af2 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -611,8 +611,7 @@ def cartesian_product_iterator(X): def cantor_product(*args): r""" - Return an iterator over the product of `A` and `B` which iterates - along the diagonals a la + Return an iterator over the product of the inputs along the diagonals a la :wikipedia:`Cantor pairing `. INPUT: @@ -631,15 +630,27 @@ def cantor_product(*args): [1, 0, 1], [0, 1, 1], [1, 1, 1]] - sage: list(cantor_product([0,1], [0,1,2,3]) + sage: list(cantor_product([0,1], [0,1,2,3])) [[0, 0], [1, 0], [0, 1], [1, 1], [0, 2], [1, 2], [0, 3], [1, 3]] Infinite iterators are valid input as well:: sage: from itertools import islice - sage: list(islice(product_cantor_pairing(ZZ, QQ), 14)) - [[0, 0], [0, 1], [1, 0], [0, -1], [1, 1], [-1, 0], [0, 1/2], - [1, -1], [-1, 1], [2, 0], [0, -1/2], [1, 1/2], [-1, -1], [2, 1]] + sage: list(islice(cantor_product(ZZ, QQ), 14)) + [[0, 0], + [1, 0], + [0, 1], + [-1, 0], + [1, 1], + [0, -1], + [2, 0], + [-1, 1], + [1, -1], + [0, 1/2], + [-2, 0], + [2, 1], + [-1, -1], + [1, 1/2]] TESTS:: @@ -647,8 +658,11 @@ def cantor_product(*args): sage: sum(1 for _ in C) == 2*4*3 True + sage: from itertools import count sage: list(cantor_product([], count())) [] + sage: list(cantor_product(count(), [], count())) + [] """ from itertools import count from sage.combinat.integer_list import IntegerListsLex From 3c5af3b58343d7ec4438a8c308ff886f5f211573 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 2 Oct 2015 19:26:24 +0200 Subject: [PATCH 1220/1872] Trac #19319: fix typo --- src/sage/misc/mrange.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 26883625af2..62dcad83717 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -616,12 +616,12 @@ def cantor_product(*args): INPUT: - - a certain number of iteratable + - a certain number of iterables EXAMPLES:: sage: from sage.misc.mrange import cantor_product - sage: list(cantor_product([0,1], [0,1], [0,1])) + sage: list(cantor_product([0, 1], [0, 1], [0, 1])) [[0, 0, 0], [1, 0, 0], [0, 1, 0], From c20bfe5346cb2bee144057dda9d106d8b2df3106 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 2 Oct 2015 19:26:57 +0200 Subject: [PATCH 1221/1872] Trac #19319: a.next() -> next(a) (Python3 compliance) --- src/sage/misc/mrange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 62dcad83717..a445d9b3af7 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -677,7 +677,7 @@ def cantor_product(*args): for i,a in enumerate(iterators): if lengths[i] is None: try: - data[i].append(a.next()) + data[i].append(next(a)) except StopIteration: assert len(data[i]) == n if n == 0: From 1fee7226728e5ec09ffdeb1acdb59c2aad1dc7d5 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 2 Oct 2015 19:27:16 +0200 Subject: [PATCH 1222/1872] Trac #19319: added a few blanks --- src/sage/misc/mrange.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index a445d9b3af7..6db6c544765 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -630,7 +630,7 @@ def cantor_product(*args): [1, 0, 1], [0, 1, 1], [1, 1, 1]] - sage: list(cantor_product([0,1], [0,1,2,3])) + sage: list(cantor_product([0, 1], [0, 1, 2, 3])) [[0, 0], [1, 0], [0, 1], [1, 1], [0, 2], [1, 2], [0, 3], [1, 3]] Infinite iterators are valid input as well:: @@ -654,7 +654,7 @@ def cantor_product(*args): TESTS:: - sage: C = cantor_product([0,1], [0,1,2,3], [0,1,2]) + sage: C = cantor_product([0, 1], [0, 1, 2, 3], [0, 1, 2]) sage: sum(1 for _ in C) == 2*4*3 True @@ -674,7 +674,7 @@ def cantor_product(*args): for n in count(0): # try to add one more term to each bin - for i,a in enumerate(iterators): + for i, a in enumerate(iterators): if lengths[i] is None: try: data[i].append(next(a)) From 96c03668100f8fc42e60ae3f7d7a715d257f41cb Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 2 Oct 2015 15:48:53 -0300 Subject: [PATCH 1223/1872] Trac 19319: return tuples + repeat argument --- src/sage/misc/mrange.py | 82 ++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 6db6c544765..8bff4902c60 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -609,7 +609,7 @@ def cartesian_product_iterator(X): """ return xmrange_iter(X, tuple) -def cantor_product(*args): +def cantor_product(*args, **kwds): r""" Return an iterator over the product of the inputs along the diagonals a la :wikipedia:`Cantor pairing `. @@ -618,39 +618,42 @@ def cantor_product(*args): - a certain number of iterables + - ``repeat`` -- an optional integer. If it is provided, the input is + repeated ``repeat`` times. + EXAMPLES:: sage: from sage.misc.mrange import cantor_product - sage: list(cantor_product([0, 1], [0, 1], [0, 1])) - [[0, 0, 0], - [1, 0, 0], - [0, 1, 0], - [0, 0, 1], - [1, 1, 0], - [1, 0, 1], - [0, 1, 1], - [1, 1, 1]] + sage: list(cantor_product([0, 1], repeat=3)) + [(0, 0, 0), + (1, 0, 0), + (0, 1, 0), + (0, 0, 1), + (1, 1, 0), + (1, 0, 1), + (0, 1, 1), + (1, 1, 1)] sage: list(cantor_product([0, 1], [0, 1, 2, 3])) - [[0, 0], [1, 0], [0, 1], [1, 1], [0, 2], [1, 2], [0, 3], [1, 3]] + [(0, 0), (1, 0), (0, 1), (1, 1), (0, 2), (1, 2), (0, 3), (1, 3)] Infinite iterators are valid input as well:: sage: from itertools import islice sage: list(islice(cantor_product(ZZ, QQ), 14)) - [[0, 0], - [1, 0], - [0, 1], - [-1, 0], - [1, 1], - [0, -1], - [2, 0], - [-1, 1], - [1, -1], - [0, 1/2], - [-2, 0], - [2, 1], - [-1, -1], - [1, 1/2]] + [(0, 0), + (1, 0), + (0, 1), + (-1, 0), + (1, 1), + (0, -1), + (2, 0), + (-1, 1), + (1, -1), + (0, 1/2), + (-2, 0), + (2, 1), + (-1, -1), + (1, 1/2)] TESTS:: @@ -663,6 +666,18 @@ def cantor_product(*args): [] sage: list(cantor_product(count(), [], count())) [] + + sage: list(cantor_product(count(), repeat=0)) + [()] + + sage: next(cantor_product(count(), repeat=-1)) + Traceback (most recent call last): + ... + ValueError: repeat argument cannot be negative + sage: next(cantor_product(count(), toto='hey')) + Traceback (most recent call last): + ... + TypeError: 'toto' is an invalid keyword argument for this function """ from itertools import count from sage.combinat.integer_list import IntegerListsLex @@ -671,6 +686,15 @@ def cantor_product(*args): lengths = [None] * m # None or length of factors data = [[] for _ in range(m)] # the initial slice of each factor iterators = [iter(a) for a in args] # the iterators + repeat = int(kwds.pop('repeat', 1)) + if repeat == 0: + yield () + return + elif repeat < 0: + raise ValueError("repeat argument cannot be negative") + if kwds: + raise TypeError("'{}' is an invalid keyword argument for this function".format(next(kwds.iterkeys()))) + mm = m * repeat for n in count(0): # try to add one more term to each bin @@ -685,9 +709,9 @@ def cantor_product(*args): lengths[i] = n # iterate through what we have - ceiling = [n if lengths[i] is None else lengths[i]-1 for i in range(m)] - for v in IntegerListsLex(n, length=m, ceiling=ceiling): - yield [data[i][v[i]] for i in range(m)] + ceiling = [n if lengths[i] is None else lengths[i]-1 for i in range(m)] * repeat + for v in IntegerListsLex(n, length=mm, ceiling=ceiling): + yield tuple(data[i%m][v[i]] for i in range(mm)) - if all(l is not None for l in lengths) and sum(l-1 for l in lengths) == n: + if all(l is not None for l in lengths) and repeat*sum(l-1 for l in lengths) == n: return From 75922c99d315a0b775da7cd41405518018d37b67 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 1 Oct 2015 10:23:07 +0200 Subject: [PATCH 1224/1872] trac #19325: cython() does not know how to compile c++ --- src/sage/misc/cython.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 01ee022b37d..8bacfe1ebc7 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -454,7 +454,6 @@ def cython(filename, verbose=False, compile_message=False, include_dirs = %s) """%(extra_args, name, name, extension, additional_source_files, libs, language, includes) open('%s/setup.py'%build_dir,'w').write(setup) - cython_include = ' '.join(["-I '%s'"%x for x in includes if len(x.strip()) > 0 ]) options = ['-p'] @@ -463,7 +462,12 @@ def cython(filename, verbose=False, compile_message=False, if sage_namespace: options.append('--pre-import sage.all') - cmd = "cd '%s' && cython %s %s '%s.pyx' 1>log 2>err " % (build_dir, ' '.join(options), cython_include, name) + cmd = "cd '{DIR}' && cython {OPT} {INC} {LANG} '{NAME}.pyx' 1>log 2>err ".format( + DIR=build_dir, + OPT=' '.join(options), + INC=cython_include, + LANG='--cplus' if language=='c++' else '', + NAME=name) if create_local_c_file: target_c = '%s/_%s.c'%(os.path.abspath(os.curdir), base) @@ -481,9 +485,6 @@ def cython(filename, verbose=False, compile_message=False, err = subtract_from_line_numbers(open('%s/err'%build_dir).read(), offset) raise RuntimeError("Error converting {} to C:\n{}\n{}".format(filename, log, err)) - if language=='c++': - os.system("cd '%s' && mv '%s.c' '%s.cpp'"%(build_dir,name,name)) - cmd = 'cd %s && python setup.py build 1>log 2>err'%build_dir if verbose: print(cmd) From d2a8cf6349e188f75891ceb9c5d4abc9f4f0aed6 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 1 Oct 2015 10:43:12 +0200 Subject: [PATCH 1225/1872] trac #19325: Doctest --- src/sage/misc/cython.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 8bacfe1ebc7..8fd9e67f6ff 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -283,7 +283,7 @@ def pyx_preparse(s): def cython(filename, verbose=False, compile_message=False, use_cache=False, create_local_c_file=False, annotate=True, sage_namespace=True, create_local_so_file=False): - """ + r""" Compile a Cython file. This converts a Cython file to a C (or C++ file), and then compiles that. The .c file and the .so file are created in a temporary directory. @@ -341,6 +341,11 @@ def cython(filename, verbose=False, compile_message=False, sage: x x^2 + Check that compiling c++ code works:: + + sage: cython("#clang C++\n"+ + ....: "from libcpp.vector cimport vector\n" + ....: "cdef vector[int] * v = new vector[int](4)\n") """ if not filename.endswith('pyx'): print("Warning: file (={}) should have extension .pyx".format(filename), file=sys.stderr) From a15ae13c5a9ff74d345525c8b028f4ebdfac0d56 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Fri, 2 Oct 2015 21:11:18 +0200 Subject: [PATCH 1226/1872] Update to Cython 0.23.3 --- build/pkgs/cython/checksums.ini | 6 +++--- build/pkgs/cython/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cython/checksums.ini b/build/pkgs/cython/checksums.ini index 95899805812..f3ac4410434 100644 --- a/build/pkgs/cython/checksums.ini +++ b/build/pkgs/cython/checksums.ini @@ -1,4 +1,4 @@ tarball=Cython-VERSION.tar.gz -sha1=2ff0f863d3b996d2265d0bf06e567e5dd23d004d -md5=db3c5b365e1c3f71c7cd90e96473a3ab -cksum=1672168057 +sha1=d5592dc3d529c55a5ef95346caccf11c556993bd +md5=813df20f7ce5f00e60568e0371fbd07c +cksum=365027876 diff --git a/build/pkgs/cython/package-version.txt b/build/pkgs/cython/package-version.txt index e13359b8fa3..9e40e75c5d2 100644 --- a/build/pkgs/cython/package-version.txt +++ b/build/pkgs/cython/package-version.txt @@ -1 +1 @@ -0.23.1.p0 +0.23.3 From 395a1d5bcde52aee79af22a561e9052a0e80b82c Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 2 Oct 2015 21:23:09 +0200 Subject: [PATCH 1227/1872] trac #19335: A (512, 315, 202, 180)-strongly regular graph --- src/sage/graphs/strongly_regular_db.pyx | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index cfefb513375..988adaa225f 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1871,6 +1871,44 @@ def SRG_512_219_106_84(): M = Matrix(GF(2),[list(l) for l in x]) return strongly_regular_from_two_weight_code(LinearCode(M)) +def SRG_512_315_202_180(): + r""" + Return a `(512, 315, 202, 180)`-strongly regular graph. + + This graph is built from a projective binary code with weights `32, 40`, + found by Axel Kohnert [Kohnert07]_ and shared by Alfred Wassermann. + + .. SEEALSO:: + + :func:`strongly_regular_from_two_weight_code` -- build a strongly + regular graph from a two-weight code. + + EXAMPLE:: + + sage: from sage.graphs.strongly_regular_db import SRG_512_315_202_180 + sage: G = SRG_512_315_202_180() # long time + sage: G.is_strongly_regular(parameters=True) # long time + (512, 315, 202, 180) + + REFERENCE: + + .. [Kohnert07] A. Kohnert, + Constructing two-weight codes with prescribed groups of automorphisms, + Discrete applied mathematics 155, no. 11 (2007): 1451-1457. + http://linearcodes.uni-bayreuth.de/twoweight/ + """ + x=("0100011110111000001011010110110111100010001000001000001001010110101101", + "1000111101110000000110101111101111000100010000010000000010101111001011", + "0001111011100000011101011101011110011000100000100000000101011100010111", + "0011110101000000111010111010111100110001000011000000001010111000101101", + "0111101000000001110101110111111001100010000100000000010101110011001011", + "1111010000000011101011101101110011010100001000000000101011100100010111", + "1110100010000111000111011011100110111000010000000001000111001010101101", + "1101000110001110001110110101001101110000100010000010001110010101001011", + "1010001110011100001101101010011011110001000100000100001100101010010111") + M = Matrix(GF(2),[list(l) for l in x]) + return strongly_regular_from_two_weight_code(LinearCode(M)) + def SRG_256_153_92_90(): r""" Return a `(256, 153, 92, 90)`-strongly regular graph. @@ -2272,6 +2310,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (416, 100, 36, 20): [SRG_416_100_36_20], (512, 219, 106, 84): [SRG_512_219_106_84], (512, 73, 12, 10): [SRG_512_73_12_10], + (512, 315, 202,180): [SRG_512_315_202_180], (560, 208, 72, 80): [SRG_560_208_72_80], (625, 416, 279,272): [SRG_625_416_279_272], (625, 364, 213,210): [SRG_625_364_213_210], From acba28ba98c6a82c63ed69f21a27a14c80d09010 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 2 Oct 2015 23:25:20 +0200 Subject: [PATCH 1228/1872] trac #19309: Broken doctest --- src/sage/graphs/strongly_regular_db.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index dd0462cc0a1..ae3adcf94c9 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -666,9 +666,9 @@ def is_polhill(int v,int k,int l,int mu): sage: t = is_polhill(1024, 231, 38, 56); t [. at ...>] sage: g = t[0](*t[1:]); g # not tested (too long) - [. at ...>] + Graph on 1024 vertices sage: g.is_strongly_regular(parameters=True) # not tested (too long) - (28, 15, 6, 10) + (1024, 231, 38, 56) sage: t = is_polhill(1024, 264, 56, 72); t [. at ...>] sage: t = is_polhill(1024, 297, 76, 90); t From c5a38ddcab7cfe777d3242511bb0203cad3d71d7 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Fri, 2 Oct 2015 18:56:05 -0400 Subject: [PATCH 1229/1872] add missing import statements --- src/sage/combinat/sf/character.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 7e637611b3d..dbdeccef703 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -19,6 +19,9 @@ from sage.misc.cachefunc import cached_method from sage.categories.homset import Hom from sage.combinat.partition import Partition +from sage.rings.arith import divisors, moebius +from sage.functions.other import binomial +from sage.rings.integer import Integer class generic_character(SFA_generic): def _my_key(self, la): From f33cddb82d04a87c7afb9758e1351b8f5961bf94 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Fri, 2 Oct 2015 19:26:23 -0400 Subject: [PATCH 1230/1872] additional documentation --- src/sage/combinat/sf/character.py | 46 +++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index dbdeccef703..760d3cd848e 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -1,5 +1,10 @@ """ character bases of the symmetric functions + +REFERENCES: + +.. [OZ2015] R. Orellana, M. Zabrocki, *Symmetric group characters + as symmetric functions*, :arxiv:`1000.0000v1`. """ #***************************************************************************** # Copyright (C) 2015 Mike Zabrocki Date: Fri, 2 Oct 2015 22:13:50 -0500 Subject: [PATCH 1231/1872] additional documentation in the header of the file character.py --- src/sage/combinat/sf/character.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 760d3cd848e..9e909ebad9e 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -1,5 +1,10 @@ """ -character bases of the symmetric functions +Characters of the symmetric group as bases of the symmetric functions + +Just as the Schur functions are the irreducible characters of `Gl_n` +and form a basis of the symmetric functions, the irreducible +symmetric group character basis are the irreducible characters of +of `S_n` when the group is realized as the permutation matrices. REFERENCES: From b0d1fcdf8a4ca42753a26a23df6720d0f8cc96cb Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 08:52:41 +0200 Subject: [PATCH 1232/1872] Revert "Merge branch 'u/dkrenn/product_cantor_pairing' of trac.sagemath.org:sage into t/19048/asy/an_element" This reverts commit f0b1172fe8bb87a1a36ff61415cf7442ba319a30, reversing changes made to e81d77de08b9be4e93e12d9f89b39f8b424077fe. --- src/sage/misc/mrange.py | 62 +++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index ecb0c9b4329..5601c330094 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -711,9 +711,9 @@ def product_cantor_pairing(A, B): A loads item number 0 B loads item number 0 (0, 0) - A loads item number 1 B loads item number 1 (0, 1) + A loads item number 1 (1, 0) (1, 1) sage: for p in product_cantor_pairing(it('A', 3), it('B', 2)): @@ -721,12 +721,12 @@ def product_cantor_pairing(A, B): A loads item number 0 B loads item number 0 (0, 0) - A loads item number 1 B loads item number 1 (0, 1) + A loads item number 1 (1, 0) - A loads item number 2 (1, 1) + A loads item number 2 (2, 0) (2, 1) sage: for p in product_cantor_pairing(it('A', 2), it('B', 4)): @@ -734,9 +734,9 @@ def product_cantor_pairing(A, B): A loads item number 0 B loads item number 0 (0, 0) - A loads item number 1 B loads item number 1 (0, 1) + A loads item number 1 (1, 0) B loads item number 2 (0, 2) @@ -745,37 +745,39 @@ def product_cantor_pairing(A, B): (0, 3) (1, 2) (1, 3) - - :: - - sage: from itertools import count - sage: list(product_cantor_pairing([], count())) - [] - sage: list(product_cantor_pairing(count(), [])) - [] """ - from itertools import count - from sage.rings.infinity import infinity + # when writing this code I thought the solution would be shorter... + + class iter_as_list(list): + def __init__(self, iterable): + self.it = iter(iterable) + self.newdata = True + def __getitem__(self, i): + self.newdata = False + try: + while len(self) <= i: + self.append(next(self.it)) + self.newdata = True + except StopIteration: + raise + return list.__getitem__(self, i) - A = iter(A) - B = iter(B) - max_A = infinity - max_B = infinity - cache_A = [] - cache_B = [] + from itertools import count + A = iter_as_list(A) + B = iter_as_list(B) for s in count(): - if s <= max_A: + for i in range(s+1): + stopped = False try: - cache_A.append(next(A)) + a = A[i] except StopIteration: - max_A = s - 1 - if s <= max_B: + stopped = True try: - cache_B.append(next(B)) + b = B[s-i] except StopIteration: - max_B = s - 1 - if s > max_A + max_B or max_A < 0 or max_B < 0: + stopped = True + if stopped: + continue + yield a, b + if not A.newdata and not B.newdata and s >= len(A) + len(B): return - - for i in range(max(0, s-max_B), min(s, max_A) + 1): - yield cache_A[i], cache_B[s-i] From ba223fdc563b33db191aa08d055b7d7de5cb8ffb Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 08:53:52 +0200 Subject: [PATCH 1233/1872] Revert "extend AUTHROS" This reverts commit 17229c620b4aff47161b725de2ebb4f890cfc2af. --- src/sage/misc/mrange.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 5601c330094..7c528f88de4 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -8,8 +8,6 @@ - William Stein (2006-07-19) - Jon Hanke - -- Daniel Krenn """ #***************************************************************************** From ce7d224235646968fc6ef1b8c5d6c39b6b7a7526 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 08:53:55 +0200 Subject: [PATCH 1234/1872] Revert "add seealso blocks" This reverts commit 97cb59c8ef71cd3a9e8df6086a2ff377baf3392f. --- src/sage/misc/mrange.py | 47 ----------------------------------------- 1 file changed, 47 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 7c528f88de4..beda5d77430 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -198,14 +198,6 @@ def mrange_iter(iter_list, typ=list): sage: mrange_iter([]) [[]] - .. SEEALSO:: - - :class:`xmrange_iter`, - :func:`mrange`, - :class:`xmrange`, - :func:`cartesian_product_iterator`, - :func:`product_cantor_pairing`. - AUTHORS: - Joel B. Mohler @@ -310,14 +302,6 @@ class xmrange_iter: (389, 'orange') (389, 'horse') - .. SEEALSO:: - - :func:`mrange_iter`, - :func:`mrange`, - :class:`xmrange`, - :func:`cartesian_product_iterator`, - :func:`product_cantor_pairing`. - AUTHORS: - Joel B. Mohler @@ -473,13 +457,6 @@ def mrange(sizes, typ=list): sage: mrange([]) [[]] - .. SEEALSO:: - - :func:`mrange_iter`, - :class:`xmrange_iter`, - :class:`xmrange`, - :func:`cartesian_product_iterator`, - :func:`product_cantor_pairing`. AUTHORS: @@ -582,14 +559,6 @@ class xmrange: (389, 'orange') (389, 'horse') - .. SEEALSO:: - - :func:`mrange_iter`, - :class:`xmrange_iter`, - :func:`mrange`, - :func:`cartesian_product_iterator`, - :func:`product_cantor_pairing`. - AUTHORS: - Jon Hanke @@ -637,14 +606,6 @@ def cartesian_product_iterator(X): [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')] sage: list(cartesian_product_iterator([])) [()] - - .. SEEALSO:: - - :func:`mrange_iter`, - :class:`xmrange_iter`, - :func:`mrange`, - :class:`xmrange`, - :func:`product_cantor_pairing`. """ return xmrange_iter(X, tuple) @@ -682,14 +643,6 @@ def product_cantor_pairing(A, B): [(0, 0), (0, 1), (1, 0), (0, -1), (1, 1), (-1, 0), (0, 1/2), (1, -1), (-1, 1), (2, 0), (0, -1/2), (1, 1/2), (-1, -1), (2, 1)] - .. SEEALSO:: - - :func:`mrange_iter`, - :class:`xmrange_iter`, - :func:`mrange`, - :class:`xmrange`, - :func:`cartesian_product_iterator`. - TESTS: Check that all pairs are returned:: From 17e72f9e3cc184af992cfc2559c5fea64dea2018 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 08:53:57 +0200 Subject: [PATCH 1235/1872] Revert "doctest with infinite iterator inputs" This reverts commit 9e41be5b7ffd3ffa34991c3f686c0a618fef42ca. --- src/sage/misc/mrange.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index beda5d77430..c53d19c01cc 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -636,13 +636,6 @@ def product_cantor_pairing(A, B): sage: tuple(''.join(p) for p in product_cantor_pairing('abc', 'xyz')) ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') - Infinite iterators are a valid as an input as well:: - - sage: from itertools import islice - sage: list(islice(product_cantor_pairing(ZZ, QQ), 14)) - [(0, 0), (0, 1), (1, 0), (0, -1), (1, 1), (-1, 0), (0, 1/2), - (1, -1), (-1, 1), (2, 0), (0, -1/2), (1, 1/2), (-1, -1), (2, 1)] - TESTS: Check that all pairs are returned:: From 39709525c9d3c7d66ea60d48b3417d64acb846ba Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 08:53:58 +0200 Subject: [PATCH 1236/1872] Revert "improve docstring" This reverts commit e8460b9599cdcee722dbd6aea7d4382bb83d55a4. --- src/sage/misc/mrange.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index c53d19c01cc..01eee13c016 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -613,12 +613,11 @@ def cartesian_product_iterator(X): def product_cantor_pairing(A, B): r""" Return an iterator over the product of `A` and `B` which iterates - along the diagonals a la - :wikipedia:`Cantor pairing `. + along the diagonal. INPUT: - - ``A`` and ``B`` -- iterables. + - ``A`` and ``B`` -- iterables (over a finite number of elements) OUTPUT: From ec19552d3dda0b5b1aedf11406acc772cd9539ac Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 08:53:59 +0200 Subject: [PATCH 1237/1872] Revert "fix import in doctest" This reverts commit a4697d3585a2396c8d338da06fdc887caf20e6bb. --- src/sage/misc/mrange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 01eee13c016..895efa0587e 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -625,7 +625,7 @@ def product_cantor_pairing(A, B): EXAMPLES:: - sage: from sage.misc.mrange import product_cantor_pairing + sage: from sage.rings.asymptotic.misc import product_cantor_pairing sage: tuple(product_cantor_pairing(srange(2), srange(2))) ((0, 0), (0, 1), (1, 0), (1, 1)) sage: tuple(product_cantor_pairing(srange(4), srange(2))) From 5b653f3c052c488d925ee38f39be64d9764f3f6f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 08:54:00 +0200 Subject: [PATCH 1238/1872] Revert "rename to product_cantor_pairing" This reverts commit c4d28791ecb941e50fa1397c205e259a8ecc56a3. --- src/sage/misc/mrange.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 895efa0587e..c54529787fe 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -610,7 +610,7 @@ def cartesian_product_iterator(X): return xmrange_iter(X, tuple) -def product_cantor_pairing(A, B): +def product_diagonal(A, B): r""" Return an iterator over the product of `A` and `B` which iterates along the diagonal. @@ -625,21 +625,21 @@ def product_cantor_pairing(A, B): EXAMPLES:: - sage: from sage.rings.asymptotic.misc import product_cantor_pairing - sage: tuple(product_cantor_pairing(srange(2), srange(2))) + sage: from sage.rings.asymptotic.misc import product_diagonal + sage: tuple(product_diagonal(srange(2), srange(2))) ((0, 0), (0, 1), (1, 0), (1, 1)) - sage: tuple(product_cantor_pairing(srange(4), srange(2))) + sage: tuple(product_diagonal(srange(4), srange(2))) ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) - sage: tuple(product_cantor_pairing(srange(2), srange(3))) + sage: tuple(product_diagonal(srange(2), srange(3))) ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) - sage: tuple(''.join(p) for p in product_cantor_pairing('abc', 'xyz')) + sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') TESTS: Check that all pairs are returned:: - sage: all(len(tuple(product_cantor_pairing(srange(m), srange(n)))) == m*n + sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n ....: for m in srange(5) for n in srange(5)) True @@ -649,7 +649,7 @@ def product_cantor_pairing(A, B): ....: for i in srange(n): ....: print '%s loads item number %s' % (s, i) ....: yield i - sage: for p in product_cantor_pairing(it('A', 2), it('B', 2)): + sage: for p in product_diagonal(it('A', 2), it('B', 2)): ....: print p A loads item number 0 B loads item number 0 @@ -659,7 +659,7 @@ def product_cantor_pairing(A, B): A loads item number 1 (1, 0) (1, 1) - sage: for p in product_cantor_pairing(it('A', 3), it('B', 2)): + sage: for p in product_diagonal(it('A', 3), it('B', 2)): ....: print p A loads item number 0 B loads item number 0 @@ -672,7 +672,7 @@ def product_cantor_pairing(A, B): A loads item number 2 (2, 0) (2, 1) - sage: for p in product_cantor_pairing(it('A', 2), it('B', 4)): + sage: for p in product_diagonal(it('A', 2), it('B', 4)): ....: print p A loads item number 0 B loads item number 0 From c41435fb4cc26469203323cb3dd02f351713676c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 08:54:36 +0200 Subject: [PATCH 1239/1872] Revert "copy code from #19048" This reverts commit 619cd8c8e41f9728f9a7616860786163144b3ecc. --- src/sage/misc/mrange.py | 116 ---------------------------------------- 1 file changed, 116 deletions(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index c54529787fe..eb03223dbf6 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -608,119 +608,3 @@ def cartesian_product_iterator(X): [()] """ return xmrange_iter(X, tuple) - - -def product_diagonal(A, B): - r""" - Return an iterator over the product of `A` and `B` which iterates - along the diagonal. - - INPUT: - - - ``A`` and ``B`` -- iterables (over a finite number of elements) - - OUTPUT: - - An iterator over `(a,b)` for `a \in A` and `b \in B`. - - EXAMPLES:: - - sage: from sage.rings.asymptotic.misc import product_diagonal - sage: tuple(product_diagonal(srange(2), srange(2))) - ((0, 0), (0, 1), (1, 0), (1, 1)) - sage: tuple(product_diagonal(srange(4), srange(2))) - ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) - sage: tuple(product_diagonal(srange(2), srange(3))) - ((0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (1, 2)) - sage: tuple(''.join(p) for p in product_diagonal('abc', 'xyz')) - ('ax', 'ay', 'bx', 'az', 'by', 'cx', 'bz', 'cy', 'cz') - - TESTS: - - Check that all pairs are returned:: - - sage: all(len(tuple(product_diagonal(srange(m), srange(n)))) == m*n - ....: for m in srange(5) for n in srange(5)) - True - - Check that everthing is loaded in the correct order:: - - sage: def it(s, n): - ....: for i in srange(n): - ....: print '%s loads item number %s' % (s, i) - ....: yield i - sage: for p in product_diagonal(it('A', 2), it('B', 2)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - (1, 1) - sage: for p in product_diagonal(it('A', 3), it('B', 2)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - (1, 1) - A loads item number 2 - (2, 0) - (2, 1) - sage: for p in product_diagonal(it('A', 2), it('B', 4)): - ....: print p - A loads item number 0 - B loads item number 0 - (0, 0) - B loads item number 1 - (0, 1) - A loads item number 1 - (1, 0) - B loads item number 2 - (0, 2) - (1, 1) - B loads item number 3 - (0, 3) - (1, 2) - (1, 3) - """ - # when writing this code I thought the solution would be shorter... - - class iter_as_list(list): - def __init__(self, iterable): - self.it = iter(iterable) - self.newdata = True - def __getitem__(self, i): - self.newdata = False - try: - while len(self) <= i: - self.append(next(self.it)) - self.newdata = True - except StopIteration: - raise - return list.__getitem__(self, i) - - from itertools import count - A = iter_as_list(A) - B = iter_as_list(B) - for s in count(): - for i in range(s+1): - stopped = False - try: - a = A[i] - except StopIteration: - stopped = True - try: - b = B[s-i] - except StopIteration: - stopped = True - if stopped: - continue - yield a, b - if not A.newdata and not B.newdata and s >= len(A) + len(B): - return From 3fd53d64c55fcbd51c743e2cbbbe0f637fb7a917 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 09:07:28 +0200 Subject: [PATCH 1240/1872] Trac #19048: rename product_cantor_pairing to cantor_product (see #19319) --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 41a7c678320..268583b121b 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1487,12 +1487,12 @@ def some_elements(self): O(z^(-1/2)), -8*z^(3/2) + O(z^(1/2))) """ - from sage.misc.mrange import product_cantor_pairing + from sage.misc.mrange import cantor_product from sage.rings.asymptotic.term_monoid import TermMonoid E = TermMonoid('exact', self.growth_group, self.coefficient_ring) O = TermMonoid('O', self.growth_group, self.coefficient_ring) return iter(-self(e)**3 + self(o) - for e, o in product_cantor_pairing( + for e, o in cantor_product( E.some_elements(), O.some_elements())) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index c98f08f4e4d..344051bad79 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2077,8 +2077,8 @@ def some_elements(self): z^2, -2*z^(1/2), 2*z^(-1/2), -z^2, z^(-2)) """ - from sage.misc.mrange import product_cantor_pairing - return iter(self(g, c) for g, c in product_cantor_pairing( + from sage.misc.mrange import cantor_product + return iter(self(g, c) for g, c in cantor_product( self.growth_group.some_elements(), iter(c for c in self.base_ring().some_elements() if c != 0))) From 617c5933907d132785ee1052473dfa808350ec04 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 3 Oct 2015 09:18:32 +0200 Subject: [PATCH 1241/1872] Trac #19048: Fix doctests (order in cantor_product changed) --- src/sage/rings/asymptotic/asymptotic_ring.py | 8 ++++---- src/sage/rings/asymptotic/term_monoid.py | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 268583b121b..0fff2cb67f9 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1477,15 +1477,15 @@ def some_elements(self): sage: A = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ) sage: tuple(islice(A.some_elements(), 10)) (-z^(3/2) + O(z^(1/2)), + O(z^(1/2)), -z^(3/2) + O(z^(-1/2)), z^(3/2) + O(z^(1/2)), + O(z^(-1/2)), O(z^2), + -z^6 + O(z^(1/2)), z^(3/2) + O(z^(-1/2)), - O(z^(1/2)), - -z^(3/2) + O(z^(-2)), O(z^2), - O(z^(-1/2)), - -8*z^(3/2) + O(z^(1/2))) + -z^(3/2) + O(z^(-2))) """ from sage.misc.mrange import cantor_product from sage.rings.asymptotic.term_monoid import TermMonoid diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 344051bad79..7d9a9bbd475 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2073,9 +2073,8 @@ def some_elements(self): sage: G = agg.GrowthGroup('z^QQ') sage: T = atm.ExactTermMonoid(G, ZZ) sage: tuple(islice(T.some_elements(), 10)) - (z^(1/2), -z^(1/2), z^(-1/2), 2*z^(1/2), -z^(-1/2), - z^2, -2*z^(1/2), 2*z^(-1/2), -z^2, z^(-2)) - + (z^(1/2), z^(-1/2), -z^(1/2), z^2, -z^(-1/2), 2*z^(1/2), + z^(-2), -z^2, 2*z^(-1/2), -2*z^(1/2)) """ from sage.misc.mrange import cantor_product return iter(self(g, c) for g, c in cantor_product( From d99ab5f27d400709e8108c41e3eb62623ac4f83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Sat, 3 Oct 2015 11:01:27 +0300 Subject: [PATCH 1242/1872] Polishing to documentation of boolean-valued poset functions. --- src/sage/combinat/posets/hasse_diagram.py | 2 + src/sage/combinat/posets/posets.py | 325 +++++++++++++--------- 2 files changed, 198 insertions(+), 129 deletions(-) diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index ecd358c4abb..b6baeb31ccc 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -376,6 +376,8 @@ def is_chain(self): sage: p.is_chain() False """ + if self.cardinality() == 0: + return True return (self.num_edges()+1 == self.num_verts() and # Hasse Diagram is a tree all(d<=1 for d in self.out_degree()) and # max outdegree is <= 1 all(d<=1 for d in self.in_degree())) # max indegree is <= 1 diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 58245aa7aca..51bd45052d4 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -12,7 +12,7 @@ :class:`FinitePoset` | A class for finite posets :class:`FinitePosets_n` | A class for finite posets up to isomorphism (i.e. unlabeled posets) :meth:`Poset` | Construct a finite poset from various forms of input data. - :meth:`is_poset` | Tests whether a directed graph is acyclic and transitively reduced. + :meth:`is_poset` | Return ``True`` if a directed graph is acyclic and transitively reduced. List of Poset methods --------------------- @@ -65,16 +65,16 @@ :meth:`~FinitePoset.dimension` | Return the dimension of the poset. :meth:`~FinitePoset.has_bottom` | Return ``True`` if the poset has a unique minimal element. :meth:`~FinitePoset.has_top` | Return ``True`` if the poset has a unique maximal element. - :meth:`~FinitePoset.is_bounded` | Return ``True`` if the poset contains a unique maximal element and a unique minimal element, and False otherwise. - :meth:`~FinitePoset.is_chain` | Return ``True`` if the poset is totally ordered, and False otherwise. - :meth:`~FinitePoset.is_connected` | Return ``True`` if the poset is connected, and ``False`` otherwise. - :meth:`~FinitePoset.is_graded` | Return whether this poset is graded. - :meth:`~FinitePoset.is_ranked` | Return whether this poset is ranked. - :meth:`~FinitePoset.is_ranked` | Return ``True`` if the poset is rank symmetric. - :meth:`~FinitePoset.is_incomparable_chain_free` | Return whether the poset is `(m+n)`-free. - :meth:`~FinitePoset.is_slender` | Return whether the poset ``self`` is slender or not. - :meth:`~FinitePoset.is_join_semilattice` | Return ``True`` is the poset has a join operation, and False otherwise. - :meth:`~FinitePoset.is_meet_semilattice` | Return ``True`` if self has a meet operation, and False otherwise. + :meth:`~FinitePoset.is_bounded` | Return ``True`` if the poset has both unique minimal and unique maximal element. + :meth:`~FinitePoset.is_chain` | Return ``True`` if the poset is totally ordered. + :meth:`~FinitePoset.is_connected` | Return ``True`` if the poset is connected. + :meth:`~FinitePoset.is_graded` | Return ``True`` if all maximal chains of the poset has same length. + :meth:`~FinitePoset.is_ranked` | Return ``True`` if the poset has a rank function. + :meth:`~FinitePoset.is_rank_symmetric` | Return ``True`` if the poset is rank symmetric. + :meth:`~FinitePoset.is_incomparable_chain_free` | Return ``True`` if the poset is `(m+n)`-free. + :meth:`~FinitePoset.is_slender` | Return ``True`` if the poset is slender. + :meth:`~FinitePoset.is_join_semilattice` | Return ``True`` is the poset has a join operation. + :meth:`~FinitePoset.is_meet_semilattice` | Return ``True`` if the poset has a meet operation. **Minimal and maximal elements** @@ -1947,53 +1947,60 @@ def relations_number(self): intervals_number = relations_number intervals_iterator = relations_iterator - def is_incomparable_chain_free(self, m, n = None): + def is_incomparable_chain_free(self, m, n=None): r""" - Return ``True`` if the poset is `(m+n)`-free (that is, there is no pair - of incomparable chains of lengths `m` and `n`), and ``False`` if not. + Return ``True`` if the poset is `(m+n)`-free, and ``False`` otherwise. - If ``m`` is a tuple of pairs of chain lengths, returns ``True`` if the poset - does not contain a pair of incomparable chains whose lengths comprise - one of the chain pairs, and ``False`` if not. - A poset is `(m+n)`-free if it contains no induced subposet that is - isomorphic to the poset consisting of two disjoint chains of lengths - `m` and `n`. See, for example, Exercise 15 in Chapter 3 of - [EnumComb1]_. + A poset is `(m+n)`-free if there is no incomparable chains of + lengths `m` and `n`. Three cases have special name: + + - ''interval order'' is `(2+2)`-free + - ''semiorder'' (or ''unit interval order'') is `(1+3)`-free and + `(2+2)`-free + - ''weak order'' is `1+2`-free. INPUT: - - ``m`` - tuple of pairs of nonnegative integers - - ``m``, ``n`` - nonnegative integers + - ``m``, ``n`` - positive integers, OR + - ``m`` - list of pairs of positive integers (``n`` must be ``None``) EXAMPLES:: - sage: P = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) - sage: P.is_incomparable_chain_free(1, 1) - False - sage: P.is_incomparable_chain_free(2, 1) + sage: B3 = Posets.BooleanLattice(3) + sage: B3.is_incomparable_chain_free(1, 3) True + sage: B3.is_incomparable_chain_free(2, 2) + False - :: - - sage: P = Poset(((0, 1, 2, 3, 4), ((0, 1), (1, 2), (0, 3), (4, 2)))) - sage: P.is_incomparable_chain_free(((3, 1), (2, 2))) + sage: IP6 = Posets.IntegerPartitions(6) + sage: IP6.is_incomparable_chain_free(1, 3) + False + sage: IP6.is_incomparable_chain_free(2, 2) True - :: + A list of pairs as an argument:: - sage: P = Poset((("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), (("d", "a"), ("e", "a"), ("f", "a"), ("g", "a"), ("h", "b"), ("f", "b"), ("h", "c"), ("g", "c"), ("h", "d"), ("i", "d"), ("h", "e"), ("i", "e"), ("j", "f"), ("i", "f"), ("j", "g"), ("i", "g"), ("j", "h")))) - sage: P.is_incomparable_chain_free(3, 1) - True - sage: P.is_incomparable_chain_free(2, 2) + sage: B3.is_incomparable_chain_free([[1, 3], [2, 2]]) False - :: + We show how to get an incomparable chain pair:: - sage: [len([p for p in Posets(n) if p.is_incomparable_chain_free(((3, 1), (2, 2)))]) for n in range(6)] # long time - [1, 1, 2, 5, 14, 42] + sage: P = Posets.PentagonPoset() + sage: c1 = Posets.ChainPoset(1) + sage: c2 = Posets.ChainPoset(2) + sage: c1_2 = c1.disjoint_union(c2) + sage: incomps = P.isomorphic_subposets(c1_2)[0] + sage: sorted(incomps.list()), incomps.cover_relations() + ([1, 2, 3], [[2, 3]]) TESTS:: + sage: Poset().is_incomparable_chain_free(1,1) # Test empty poset + True + + sage: [len([p for p in Posets(n) if p.is_incomparable_chain_free(((3, 1), (2, 2)))]) for n in range(6)] # long time + [1, 1, 2, 5, 14, 42] + sage: Q = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) sage: Q.is_incomparable_chain_free(2, 20/10) True @@ -2004,7 +2011,7 @@ def is_incomparable_chain_free(self, m, n = None): sage: Q.is_incomparable_chain_free(2, -1) Traceback (most recent call last): ... - ValueError: 2 and -1 must be nonnegative integers. + ValueError: 2 and -1 must be positive integers. sage: P = Poset(((0, 1, 2, 3, 4), ((0, 1), (1, 2), (0, 3), (4, 2)))) sage: P.is_incomparable_chain_free((3, 1)) Traceback (most recent call last): @@ -2051,8 +2058,8 @@ def is_incomparable_chain_free(self, m, n = None): m, n = Integer(m), Integer(n) except TypeError: raise TypeError('%s and %s must be integers.' % (m, n)) - if m < 0 or n < 0: - raise ValueError("%s and %s must be nonnegative integers." % (m, n)) + if m < 1 or n < 1: + raise ValueError("%s and %s must be positive integers." % (m, n)) twochains = digraphs.TransitiveTournament(m) + digraphs.TransitiveTournament(n) return self._hasse_diagram.transitive_closure().subgraph_search(twochains, induced = True) is None @@ -2241,7 +2248,7 @@ def bottom(self): sage: Q.bottom() 0 - .. SEEALSO:: :meth:`has_bottom`, :meth:`top`. + .. SEEALSO:: :meth:`has_bottom`, :meth:`top` """ hasse_bot = self._hasse_diagram.bottom() if hasse_bot is None: @@ -2256,14 +2263,19 @@ def has_bottom(self): EXAMPLES:: - sage: P = Poset({0:[3],1:[3],2:[3],3:[4],4:[]}) + sage: P = Poset({0:[3], 1:[3], 2:[3], 3:[4], 4:[]}) sage: P.has_bottom() False - sage: Q = Poset({0:[1],1:[]}) + sage: Q = Poset({0:[1], 1:[]}) sage: Q.has_bottom() True - .. SEEALSO:: :meth:`bottom`, :meth:`has_top`. + .. SEEALSO:: :meth:`bottom`, :meth:`has_top`, :meth:`is_bounded` + + TESTS:: + + sage: Poset().has_top() # Test empty poset + False """ return self._hasse_diagram.has_bottom() @@ -2280,7 +2292,7 @@ def top(self): sage: Q.top() 1 - .. SEEALSO:: :meth:`has_top`, :meth:`bottom`. + .. SEEALSO:: :meth:`has_top`, :meth:`bottom` TESTS:: @@ -2303,14 +2315,19 @@ def has_top(self): EXAMPLES:: - sage: P = Poset({0:[3],1:[3],2:[3],3:[4,5],4:[],5:[]}) + sage: P = Poset({0:[3], 1:[3], 2:[3], 3:[4, 5], 4:[], 5:[]}) sage: P.has_top() False - sage: Q = Poset({0:[1],1:[]}) + sage: Q = Poset({0:[3], 1:[3], 2:[3], 3:[4], 4:[]}) sage: Q.has_top() True - .. SEEALSO:: :meth:`top`, :meth:`has_bottom`. + .. SEEALSO:: :meth:`top`, :meth:`has_bottom`, :meth:`is_bounded` + + TESTS:: + + sage: Poset().has_top() # Test empty poset + False """ return self._hasse_diagram.has_top() @@ -2368,35 +2385,57 @@ def has_isomorphic_subposet(self, other): def is_bounded(self): """ - Return ``True`` if the poset ``self`` is bounded, and ``False`` - otherwise. + Return ``True`` if the poset is bounded, and ``False`` otherwise. - We call a poset bounded if it contains a unique maximal element + A poset is bounded if it contains both a unique maximal element and a unique minimal element. EXAMPLES:: - sage: P = Poset({0:[3],1:[3],2:[3],3:[4,5],4:[],5:[]}) + sage: P = Poset({0:[3], 1:[3], 2:[3], 3:[4, 5], 4:[], 5:[]}) sage: P.is_bounded() False - sage: Q = Poset({0:[1],1:[]}) + sage: Q = Posets.DiamondPoset(5) sage: Q.is_bounded() True + + .. SEEALSO:: :meth:`has_bottom`, :meth:`has_top` + + TESTS:: + + sage: Poset().is_bounded() # Test empty poset + False + sage: Poset({1:[]}).is_bounded() # Here top == bottom + True + sage: ( len([P for P in Posets(5) if P.is_bounded()]) == + ....: Posets(3).cardinality() ) + True """ return self._hasse_diagram.is_bounded() def is_chain(self): """ - Returns True if the poset is totally ordered, and False otherwise. + Return ``True`` if the poset is totally ordered, and ``False`` + otherwise. EXAMPLES:: - sage: L = Poset({0:[1],1:[2],2:[3],3:[4]}) - sage: L.is_chain() + sage: I = Poset({0:[1], 1:[2], 2:[3], 3:[4]}) + sage: I.is_chain() True - sage: V = Poset({0:[1,2]}) + + sage: II = Poset({0:[1], 2:[3]}) + sage: II.is_chain() + False + + sage: V = Poset({0:[1, 2]}) sage: V.is_chain() False + + TESTS:: + + sage: [len([P for P in Posets(n) if P.is_chain()]) for n in range(5)] + [1, 1, 1, 1, 1] """ return self._hasse_diagram.is_chain() @@ -2477,18 +2516,26 @@ def is_connected(self): """ Return ``True`` if the poset is connected, and ``False`` otherwise. - Poset is not connected if it can be divided to disjoint parts + A poset is not connected if it can be divided to parts `S_1` and `S_2` so that every element of `S_1` is incomparable to every element of `S_2`. EXAMPLES:: - sage: P=Poset({1:[2,3], 3:[4,5]}) + sage: P = Poset({1:[2, 3], 3:[4, 5]}) sage: P.is_connected() True - sage: P=Poset({1:[2,3], 3:[4,5], 6:[7,8]}) + + sage: P = Poset({1:[2, 3], 3:[4, 5], 6:[7, 8]}) sage: P.is_connected() False + + .. SEEALSO:: :meth:`connected_components` + + TESTS:: + + sage: Poset().is_connected() # Test empty poset + True """ return self._hasse_diagram.is_connected() @@ -2821,80 +2868,76 @@ def rank(self, element=None): def is_ranked(self): r""" - Returns whether this poset is ranked. + Return ``True`` if the poset is ranked, and ``False`` otherwise. - A poset is *ranked* if it admits a rank function. For more information - about the rank function, see :meth:`~sage.combinat.posets.hasse_diagram.HasseDiagram.rank_function`. + Informally a ranked poset can be "levelized": every element is + on a "level", and no cover relation jumps over a level. - .. SEEALSO:: :meth:`is_graded`. + Formally defined, a ranked poset can have function `r` from + poset elements to integers so that `r(x)=r(y)+1` if `x` covers `y`. EXAMPLES:: - sage: P = Poset([[1],[2],[3],[4],[]]) + sage: P = Poset( ([1, 2, 3, 4], [[1, 2], [2, 4], [3, 4]] )) sage: P.is_ranked() True - sage: Q = Poset([[1,5],[2,6],[3],[4],[],[6,3],[4]]) - sage: Q.is_ranked() - False - sage: P = Poset( ([1,2,3,4],[[1,2],[2,4],[3,4]] )) + + sage: P = Poset([[1, 5], [2, 6], [3], [4],[], [6, 3], [4]]) sage: P.is_ranked() + False + + .. SEEALSO:: :meth:`rank_function`, :meth:`rank`, :meth:`is_graded` + + TESTS:: + + sage: Poset().is_ranked() # Test empty poset True """ return bool(self.rank_function()) def is_graded(self): r""" - Returns whether this poset is graded. + Return ``True`` if the poset is graded, and ``False`` otherwise. - A poset is *graded* if all its maximal chains have the same length. - There are various competing definitions for graded posets (see - :wikipedia:`Graded_poset`). This definition is from section 3.1 of - Richard Stanley's *Enumerative Combinatorics, Vol. 1* [EnumComb1]_. + Informally a graded poset can be "levelized" with every maximal chain + going throught all levels: every element is on a "level", no cover + relation jumps over a level, and no chain ends in the middle of + levels. - Note that every graded poset is ranked, but the converse is not - true. + Formally defined a poset is graded if all its maximal chains have + the same length. There are various competing definitions for graded + posets (see :wikipedia:`Graded_poset`). This definition is from + section 3.1 of Richard Stanley's *Enumerative Combinatorics, + Vol. 1* [EnumComb1]_. - .. SEEALSO:: :meth:`is_ranked` + Note that every graded poset is ranked. The converse is true + for bounded posets, including lattices. EXAMPLES:: - sage: P = Poset([[1],[2],[3],[4],[]]) + sage: P = Posets.PentagonPoset() # Not even ranked sage: P.is_graded() - True - sage: Q = Poset([[1,5],[2,6],[3],[4],[],[6,3],[4]]) - sage: Q.is_graded() False - sage: P = Poset( ([1,2,3,4],[[1,2],[2,4],[3,4]] )) + + sage: P = Poset({1:[2, 3], 3:[4]}) # Ranked, but not graded sage: P.is_graded() False - sage: P = Poset({1: [2, 3], 4: [5]}) + + sage: P = Poset({1:[3, 4], 2:[3, 4], 5:[6]}) sage: P.is_graded() True - sage: P = Poset({1: [2, 3], 3: [4]}) - sage: P.is_graded() - False - sage: P = Poset({1: [2, 3], 4: []}) + + sage: P = Poset([[1], [2], [], [4], []]) sage: P.is_graded() False - sage: P = Posets.BooleanLattice(4) - sage: P.is_graded() - True - sage: P = RootSystem(['D',4]).root_poset() - sage: P.is_graded() - True - sage: P = Poset({}) - sage: P.is_graded() - True - TESTS: + .. SEEALSO:: :meth:`is_ranked`, :meth:`level_sets` - Here we test that the empty poset is graded:: + TESTS:: - sage: Poset([[],[]]).is_graded() + sage: Poset().is_graded() # Test empty poset True """ - # The code below is not really optimized, but beats looking at - # every maximal chain... if len(self) <= 2: return True # Let's work with the Hasse diagram in order to avoid some @@ -3163,21 +3206,29 @@ def meet_matrix(self): def is_meet_semilattice(self): r""" - Returns True if self has a meet operation, and False otherwise. + Return ``True`` if the poset has a meet operation, and + ``False`` otherwise. - EXAMPLES:: + A meet is the greatest lower bound for given elements, if it exists. - sage: P = Poset([[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]], facade = False) - sage: P.is_meet_semilattice() - True + EXAMPLES:: - sage: P = Poset([[1,2],[3],[3],[]]) + sage: P = Poset({1:[2, 3, 4], 2:[5, 6], 3:[6], 4:[6, 7]}) sage: P.is_meet_semilattice() True - sage: P = Poset({0:[2,3],1:[2,3]}) - sage: P.is_meet_semilattice() + sage: Q = P.dual() + sage: Q.is_meet_semilattice() False + + .. SEEALSO:: :meth:`is_join_semilattice`, :meth:`~sage.categories.finite_posets.FinitePosets.ParentMethods.is_lattice` + + TESTS:: + + sage: Poset().is_meet_semilattice() # Test empty lattice + True + sage: len([P for P in Posets(4) if P.is_meet_semilattice()]) + 5 """ return self._hasse_diagram.is_meet_semilattice() @@ -3194,22 +3245,32 @@ def join_matrix(self): def is_join_semilattice(self): """ - Returns True if the poset has a join operation, and False + Return ``True`` if the poset has a join operation, and ``False`` otherwise. + A join is the least upper bound for given elements, if it exists. + EXAMPLES:: - sage: P = Poset([[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]]) + sage: P = Poset([[1,3,2], [4], [4,5,6], [6], [7], [7], [7], []]) sage: P.is_join_semilattice() True - sage: P = Poset([[1,2],[3],[3],[]]) - sage: P.is_join_semilattice() - True + Elements 3 and 4 have no common upper bound at all; elements + 1 and 2 have upper bounds 3 and 4, but no least upper bound:: - sage: P = Poset({0:[2,3],1:[2,3]}) + sage: P = Poset({1:[3, 4], 2:[3, 4]}) sage: P.is_join_semilattice() False + + .. SEEALSO:: :meth:`is_meet_semilattice`, :meth:`~sage.categories.finite_posets.FinitePosets.ParentMethods.is_lattice` + + TESTS:: + + sage: Poset().is_join_semilattice() # Test empty lattice + True + sage: len([P for P in Posets(4) if P.is_join_semilattice()]) + 5 """ return self._hasse_diagram.is_join_semilattice() @@ -5245,7 +5306,8 @@ def evacuation(self): def is_rank_symmetric(self): """ - Return ``True`` if the poset is rank symmetric, and ``False`` otherwise. + Return ``True`` if the poset is rank symmetric, and ``False`` + otherwise. The poset is expected to be graded and connected. @@ -5255,12 +5317,12 @@ def is_rank_symmetric(self): EXAMPLES:: - sage: P = Poset({1:[2], 2:[3,4], 3:[5], 4:[5]}) - sage: P.is_rank_symmetric() - False - sage: P = Poset({1:[3,4,5], 2:[3,4,5], 3:[6], 4:[7], 5:[7]}) + sage: P = Poset({1:[3, 4, 5], 2:[3, 4, 5], 3:[6], 4:[7], 5:[7]}) sage: P.is_rank_symmetric() True + sage: P = Poset({1:[2], 2:[3, 4], 3:[5], 4:[5]}) + sage: P.is_rank_symmetric() + False TESTS:: @@ -5297,21 +5359,26 @@ def is_slender(self): EXAMPLES:: - sage: P = Poset(([1,2,3,4],[[1,2],[1,3],[2,4],[3,4]]), facade = True) + sage: P = Poset(([1, 2, 3, 4], [[1, 2], [1, 3], [2, 4], [3, 4]])) sage: P.is_slender() True - sage: P = Poset(([1,2,3,4,5],[[1,2],[1,3],[1,4],[2,5],[3,5],[4,5]]), facade = True) + sage: P = Poset(([1,2,3,4,5],[[1,2],[1,3],[1,4],[2,5],[3,5],[4,5]])) sage: P.is_slender() False - sage: W = WeylGroup(['A',2]) + sage: W = WeylGroup(['A', 2]) sage: G = W.bruhat_poset() sage: G.is_slender() True - sage: W = WeylGroup(['A',3]) + sage: W = WeylGroup(['A', 3]) sage: G = W.bruhat_poset() sage: G.is_slender() True + + TESTS:: + + sage: Poset().is_slender() # Test empty poset + True """ for x in self: d = {} @@ -5771,13 +5838,13 @@ def cardinality(self, from_iterator=False): def is_poset(dig): r""" - Tests whether a directed graph is acyclic and transitively - reduced. + Return ``True`` if a directed graph is acyclic and transitively + reduced, and ``False`` otherwise. EXAMPLES:: sage: from sage.combinat.posets.posets import is_poset - sage: dig = DiGraph({0:[2,3], 1:[3,4,5], 2:[5], 3:[5], 4:[5]}) + sage: dig = DiGraph({0:[2, 3], 1:[3, 4, 5], 2:[5], 3:[5], 4:[5]}) sage: is_poset(dig) False sage: is_poset(dig.transitive_reduction()) From f1f93b9620dbb15e9615ebebe33c3601c2c88c29 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sat, 3 Oct 2015 12:56:27 +0200 Subject: [PATCH 1243/1872] Disambiguate integer type rank --- src/sage/graphs/asteroidal_triples.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/asteroidal_triples.pyx b/src/sage/graphs/asteroidal_triples.pyx index 56bfe7d2ce6..fbe72d233ca 100644 --- a/src/sage/graphs/asteroidal_triples.pyx +++ b/src/sage/graphs/asteroidal_triples.pyx @@ -240,7 +240,7 @@ cdef list is_asteroidal_triple_free_C(int n, # We now search for an unseen vertex v = bitset_first_in_complement(seen) - while v!=-1: + while v != -1: # and add it to the queue waiting_list[0] = v waiting_beginning = 0 From f465c96099ab3681ba1162eaf739c7768d8218ab Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 3 Oct 2015 18:09:10 +0200 Subject: [PATCH 1244/1872] trac #19340: Better interface for hadamard_matrix --- src/sage/combinat/matrices/hadamard_matrix.py | 142 ++++++++++++++++-- src/sage/matrix/constructor.py | 3 - 2 files changed, 130 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index a46d40ab2ee..1edcd8b9c2d 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -50,11 +50,11 @@ from sage.rings.integer import Integer from sage.matrix.constructor import matrix, block_matrix, block_diagonal_matrix, diagonal_matrix from urllib import urlopen -from sage.misc.functional import is_even from sage.rings.arith import is_prime, is_square, is_prime_power, divisors from math import sqrt from sage.matrix.constructor import identity_matrix as I from sage.matrix.constructor import ones_matrix as J +from sage.misc.unknown import Unknown def H1(i, j, p): """ @@ -193,11 +193,99 @@ def hadamard_matrix_paleyII(n): # normalising H so that first row and column have only +1 entries. return normalise_hadamard(H) -def hadamard_matrix(n): +def is_hadamard_matrix(M, normalized=False, verbose=False): + r""" + Test if `M` is a hadamard matrix. + + INPUT: + + - ``M`` -- a matrix + + - ``normalized`` (boolean) -- whether to test if ``M`` is a normalized + Hadamard matrix, i.e. has its first row/column filles with +1. + + - ``verbose`` (boolean) -- whether to be verbose when the matrix is not + Hadamard. + + EXAMPLE:: + + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: is_hadamard_matrix(matrix.hadamard(12)) + True + sage: h = matrix.hadamard(12) + sage: h[0,0] = 2 + sage: is_hadamard_matrix(h,verbose=True) + The matrix does not only contain +1 and -1 entries, e.g. 2 + False + sage: h = matrix.hadamard(12) + sage: for i in range(12): + ....: h[i,2] = -h[i,2] + sage: is_hadamard_matrix(h,verbose=True,normalized=True) + The matrix is not normalized + False + + """ + n = M.ncols() + if n != M.nrows(): + if verbose: + print "The matrix is not square ({}x{})".format(M.nrows(),n) + return False + + if n == 0: + return True + + for r in M: + for v in r: + if v*v != 1: + if verbose: + print "The matrix does not only contain +1 and -1 entries, e.g. "+str(v) + return False + + prod = (M*M.transpose()).dict() + if (len(prod) != n or + set(prod.itervalues()) != {n} or + any( (i,i) not in prod for i in range(n) )): + if verbose: + print "The product M*M.transpose() is not equal to nI" + return False + + if normalized: + if (set(M.row(0) ) != {1} or + set(M.column(0)) != {1}): + if verbose: + print "The matrix is not normalized" + return False + + return True + +from sage.matrix.constructor import matrix_method +@matrix_method +def hadamard_matrix(n,existence=False, check=True): + r""" Tries to construct a Hadamard matrix using a combination of Paley and Sylvester constructions. + INPUT: + + - ``n`` (integer) -- dimension of the matrix + + - ``existence`` (boolean) -- whether to build the matrix or merely query if + a construction is available in Sage. When set to ``True``, the function + returns: + + - ``True`` -- meaning that Sage knows how to build the matrix + + - ``Unknown`` -- meaning that Sage does not know how to build the + matrix, but that the design may exist (see :mod:`sage.misc.unknown`). + + - ``False`` -- meaning that the matrix does not exist. + + - ``check`` (boolean) -- whether to check that output is correct before + returning it. As this is expected to be useless (but we are cautious + guys), you may want to disable it whenever you want speed. Set to ``True`` + by default. + EXAMPLES:: sage: hadamard_matrix(12).det() @@ -238,30 +326,60 @@ def hadamard_matrix(n): [ 1 -1 1 -1 1 -1| 1 1 -1 -1 -1 1] [ 1 -1 -1 1 -1 1| 1 1 1 -1 -1 -1] [ 1 1 -1 -1 1 -1| 1 -1 1 1 -1 -1] + + TESTS:: + + sage: matrix.hadamard(10,existence=True) + False + sage: matrix.hadamard(12,existence=True) + True + sage: matrix.hadamard(20,existence=True) + Unknown + sage: matrix.hadamard(10) + Traceback (most recent call last): + ... + ValueError: The Hadamard matrix of order 10 does not exist """ if not(n % 4 == 0) and (n > 2): + if existence: + return False raise ValueError("The Hadamard matrix of order %s does not exist" % n) if n == 2: - return matrix([[1, 1], [1, -1]]) - if is_even(n): - N = Integer(n / 2) + if existence: + return True + M = matrix([[1, 1], [1, -1]]) elif n == 1: - return matrix([1]) - if is_prime(N - 1) and (N - 1) % 4 == 1: - return hadamard_matrix_paleyII(n) + if existence: + return True + M = matrix([1]) + elif is_prime(n//2 - 1) and (n//2 - 1) % 4 == 1: + if existence: + return True + M = hadamard_matrix_paleyII(n) elif n == 4 or n % 8 == 0: - had = hadamard_matrix(Integer(n / 2)) + if existence: + return hadamard_matrix(n//2,existence=True) + had = hadamard_matrix(n//2,check=False) chad1 = matrix([list(r) + list(r) for r in had.rows()]) mhad = (-1) * had R = len(had.rows()) chad2 = matrix([list(had.rows()[i]) + list(mhad.rows()[i]) for i in range(R)]) - return chad1.stack(chad2) - elif is_prime(N - 1) and (N - 1) % 4 == 3: - return hadamard_matrix_paleyI(n) + M = chad1.stack(chad2) + elif is_prime(n//2 - 1) and (n//2 - 1) % 4 == 3: + if existence: + return True + M = hadamard_matrix_paleyI(n) else: + if existence: + return Unknown raise ValueError("The Hadamard matrix of order %s is not yet implemented." % n) + if check: + assert is_hadamard_matrix(M, normalized=True) + + return M + def hadamard_matrix_www(url_file, comments=False): """ Pulls file from Sloane's database and returns the corresponding Hadamard diff --git a/src/sage/matrix/constructor.py b/src/sage/matrix/constructor.py index 97348ba1468..3f108e1beed 100644 --- a/src/sage/matrix/constructor.py +++ b/src/sage/matrix/constructor.py @@ -4159,6 +4159,3 @@ def ith_to_zero_rotation_matrix(v, i, ring=None): entries[(k, k)] = 1 entries.update({(j,j):aa, (j,i):bb, (i,j):-bb, (i,i):aa}) return matrix(entries, nrows=dim, ring=ring) - - - From a5a4bbff80f2aed2a5b549d6b64f215967bc5ec7 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 3 Oct 2015 18:28:00 +0200 Subject: [PATCH 1245/1872] trac #19340: Pre-existing bug that hid several paley constructions --- src/sage/combinat/matrices/hadamard_matrix.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 1edcd8b9c2d..84e29988a05 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -333,7 +333,7 @@ def hadamard_matrix(n,existence=False, check=True): False sage: matrix.hadamard(12,existence=True) True - sage: matrix.hadamard(20,existence=True) + sage: matrix.hadamard(92,existence=True) Unknown sage: matrix.hadamard(10) Traceback (most recent call last): @@ -366,7 +366,7 @@ def hadamard_matrix(n,existence=False, check=True): chad2 = matrix([list(had.rows()[i]) + list(mhad.rows()[i]) for i in range(R)]) M = chad1.stack(chad2) - elif is_prime(n//2 - 1) and (n//2 - 1) % 4 == 3: + elif is_prime(n - 1) and (n - 1) % 4 == 3: if existence: return True M = hadamard_matrix_paleyI(n) From 83bbce2b3d5e8940971f4fe3196e088d58fc018a Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 3 Oct 2015 23:50:24 +0200 Subject: [PATCH 1246/1872] trac #19341: Cleaning/Fix in combinat/matrices/hadamard_matrix --- src/sage/combinat/matrices/hadamard_matrix.py | 194 +++++++++--------- 1 file changed, 95 insertions(+), 99 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 84e29988a05..1145d3ea96f 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -56,56 +56,6 @@ from sage.matrix.constructor import ones_matrix as J from sage.misc.unknown import Unknown -def H1(i, j, p): - """ - Returns the i,j-th entry of the Paley matrix, type I case. - The Paley type I case corresponds to the case `p \cong 3 \mod{4}` - for a prime `p`. - - .. TODO:: - - This construction holds more generally for prime powers `q` - congruent to `3 \mod{4}`. We should implement these but we - first need to implement Quadratic character for `GF(q)`. - - EXAMPLES:: - - sage: sage.combinat.matrices.hadamard_matrix.H1(1,2,3) - 1 - """ - if i == 0 or j == 0: - return 1 - # what follows will not be executed for (i, j) = (0, 0). - if i == j: - return -1 - return -kronecker_symbol(i - j, p) - -def H2(i, j, p): - """ - Returns the i,j-th entry of the Paley matrix, type II case. - - The Paley type II case corresponds to the case `p \cong 1 \mod{4}` - for a prime `p` (see [Hora]_). - - .. TODO:: - - This construction holds more generally for prime powers `q` - congruent to `1 \mod{4}`. We should implement these but we - first need to implement Quadratic character for `GF(q)`. - - EXAMPLES:: - - sage: sage.combinat.matrices.hadamard_matrix.H2(1,2,5) - 1 - """ - if i == 0 and j == 0: - return 0 - if i == 0 or j == 0: - return 1 - if i == j: - return 0 - return kronecker_symbol(i - j, p) - def normalise_hadamard(H): """ Return the normalised Hadamard matrix corresponding to ``H``. @@ -119,14 +69,12 @@ def normalise_hadamard(H): sage: H == hadamard_matrix(4) True """ - Hc1 = H.column(0) - Hr1 = H.row(0) for i in range(H.ncols()): - if Hc1[i] < 0: - H.rescale_row(i, -1) - for i in range(H.nrows()): - if Hr1[i] < 0: + if H[0,i] < 0: H.rescale_col(i, -1) + for i in range(H.nrows()): + if H[i,0] < 0: + H.rescale_row(i, -1) return H def hadamard_matrix_paleyI(n): @@ -140,18 +88,36 @@ def hadamard_matrix_paleyI(n): We note that this method returns a normalised Hadamard matrix :: - sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(4) + sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(4) # random [ 1 1 1 1] + [ 1 -1 1 -1] [ 1 -1 -1 1] [ 1 1 -1 -1] - [ 1 -1 1 -1] + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: test_cases = [x+1 for x in range(100) if is_prime_power(x) and x%4==3] + sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True) + ....: for n in test_cases) + True """ p = n - 1 - if not(is_prime(p) and (p % 4 == 3)): + if not(is_prime_power(p) and (p % 4 == 3)): raise ValueError("The order %s is not covered by the Paley type I construction." % n) - H = matrix(ZZ, [[H1(i, j, p) for i in range(n)] for j in range(n)]) - # normalising H so that first row and column have only +1 entries. - return normalise_hadamard(H) + + from sage.rings.finite_rings.constructor import FiniteField + K = FiniteField(p,'x') + K_list = list(K) + K_list.insert(0,K.zero()) + H = matrix(ZZ, [[2*((x-y).is_square()-.5) for x in K_list] for y in K_list]) + for i in range(n): + H[0,i] = 1 + H[i,i] = -1 + H[i,0] = -1 + H = normalise_hadamard(H) + return H def hadamard_matrix_paleyII(n): """ @@ -169,28 +135,54 @@ def hadamard_matrix_paleyII(n): We note that the method returns a normalised Hadamard matrix :: - sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12) - [ 1 1 1 1 1 1| 1 1 1 1 1 1] - [ 1 1 1 -1 -1 1|-1 -1 1 -1 -1 1] - [ 1 1 1 1 -1 -1|-1 1 -1 1 -1 -1] - [ 1 -1 1 1 1 -1|-1 -1 1 -1 1 -1] - [ 1 -1 -1 1 1 1|-1 -1 -1 1 -1 1] - [ 1 1 -1 -1 1 1|-1 1 -1 -1 1 -1] - [-----------------+-----------------] - [ 1 -1 -1 -1 -1 -1|-1 1 1 1 1 1] - [ 1 -1 1 -1 -1 1| 1 -1 -1 1 1 -1] - [ 1 1 -1 1 -1 -1| 1 -1 -1 -1 1 1] - [ 1 -1 1 -1 1 -1| 1 1 -1 -1 -1 1] - [ 1 -1 -1 1 -1 1| 1 1 1 -1 -1 -1] - [ 1 1 -1 -1 1 -1| 1 -1 1 1 -1 -1] + sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12) # random + [ 1 1| 1 1| 1 1| 1 1| 1 1| 1 1] + [ 1 -1|-1 1|-1 1|-1 1|-1 1|-1 1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1| 1 -1| 1 1|-1 -1|-1 -1| 1 1] + [ 1 1|-1 -1| 1 -1|-1 1|-1 1| 1 -1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1| 1 1| 1 -1| 1 1|-1 -1|-1 -1] + [ 1 1| 1 -1|-1 -1| 1 -1|-1 1|-1 1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1|-1 -1| 1 1| 1 -1| 1 1|-1 -1] + [ 1 1|-1 1| 1 -1|-1 -1| 1 -1|-1 1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1|-1 -1|-1 -1| 1 1| 1 -1| 1 1] + [ 1 1|-1 1|-1 1| 1 -1|-1 -1| 1 -1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1| 1 1|-1 -1|-1 -1| 1 1| 1 -1] + [ 1 1| 1 -1|-1 1|-1 1| 1 -1|-1 -1] + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyII + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1] + sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True) + ....: for n in test_cases) + True """ - N = Integer(n/2) - p = N - 1 - if not(is_prime(p) and (p % 4 == 1)): + q = n//2 - 1 + if not(n%2==0 and is_prime_power(q) and (q % 4 == 1)): raise ValueError("The order %s is not covered by the Paley type II construction." % n) - S = matrix(ZZ, [[H2(i, j, p) for i in range(N)] for j in range(N)]) - H = block_matrix([[S + 1, S - 1], [1 - S, S + 1]]) - # normalising H so that first row and column have only +1 entries. + + from sage.rings.finite_rings.constructor import FiniteField + K = FiniteField(q,'x') + K_list = list(K) + K_list.insert(0,K.zero()) + H = matrix(ZZ, [[2*((x-y).is_square()-.5) for x in K_list] for y in K_list]) + for i in range(q+1): + H[0,i] = 1 + H[i,0] = 1 + H[i,i] = 0 + + tr = { 0: matrix(2,2,[ 1,-1,-1,-1]), + 1: matrix(2,2,[ 1, 1, 1,-1]), + -1: matrix(2,2,[-1,-1,-1, 1])} + + H = block_matrix(q+1,q+1,[tr[v] for r in H for v in r]) + return normalise_hadamard(H) def is_hadamard_matrix(M, normalized=False, verbose=False): @@ -297,7 +289,7 @@ def hadamard_matrix(n,existence=False, check=True): sage: hadamard_matrix(2) [ 1 1] [ 1 -1] - sage: hadamard_matrix(8) + sage: hadamard_matrix(8) # random [ 1 1 1 1 1 1 1 1] [ 1 -1 1 -1 1 -1 1 -1] [ 1 1 -1 -1 1 1 -1 -1] @@ -312,20 +304,24 @@ def hadamard_matrix(n,existence=False, check=True): We note that the method `hadamard_matrix()` returns a normalised Hadamard matrix (the entries in the first row and column are all +1) :: - sage: hadamard_matrix(12) - [ 1 1 1 1 1 1| 1 1 1 1 1 1] - [ 1 1 1 -1 -1 1|-1 -1 1 -1 -1 1] - [ 1 1 1 1 -1 -1|-1 1 -1 1 -1 -1] - [ 1 -1 1 1 1 -1|-1 -1 1 -1 1 -1] - [ 1 -1 -1 1 1 1|-1 -1 -1 1 -1 1] - [ 1 1 -1 -1 1 1|-1 1 -1 -1 1 -1] - [-----------------+-----------------] - [ 1 -1 -1 -1 -1 -1|-1 1 1 1 1 1] - [ 1 -1 1 -1 -1 1| 1 -1 -1 1 1 -1] - [ 1 1 -1 1 -1 -1| 1 -1 -1 -1 1 1] - [ 1 -1 1 -1 1 -1| 1 1 -1 -1 -1 1] - [ 1 -1 -1 1 -1 1| 1 1 1 -1 -1 -1] - [ 1 1 -1 -1 1 -1| 1 -1 1 1 -1 -1] + sage: hadamard_matrix(12) # random + [ 1 1| 1 1| 1 1| 1 1| 1 1| 1 1] + [ 1 -1|-1 1|-1 1|-1 1|-1 1|-1 1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1| 1 -1| 1 1|-1 -1|-1 -1| 1 1] + [ 1 1|-1 -1| 1 -1|-1 1|-1 1| 1 -1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1| 1 1| 1 -1| 1 1|-1 -1|-1 -1] + [ 1 1| 1 -1|-1 -1| 1 -1|-1 1|-1 1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1|-1 -1| 1 1| 1 -1| 1 1|-1 -1] + [ 1 1|-1 1| 1 -1|-1 -1| 1 -1|-1 1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1|-1 -1|-1 -1| 1 1| 1 -1| 1 1] + [ 1 1|-1 1|-1 1| 1 -1|-1 -1| 1 -1] + [-----+-----+-----+-----+-----+-----] + [ 1 -1| 1 1|-1 -1|-1 -1| 1 1| 1 -1] + [ 1 1| 1 -1|-1 1|-1 1| 1 -1|-1 -1] TESTS:: @@ -352,7 +348,7 @@ def hadamard_matrix(n,existence=False, check=True): if existence: return True M = matrix([1]) - elif is_prime(n//2 - 1) and (n//2 - 1) % 4 == 1: + elif is_prime_power(n//2 - 1) and (n//2 - 1) % 4 == 1: if existence: return True M = hadamard_matrix_paleyII(n) @@ -366,7 +362,7 @@ def hadamard_matrix(n,existence=False, check=True): chad2 = matrix([list(had.rows()[i]) + list(mhad.rows()[i]) for i in range(R)]) M = chad1.stack(chad2) - elif is_prime(n - 1) and (n - 1) % 4 == 3: + elif is_prime_power(n - 1) and (n - 1) % 4 == 3: if existence: return True M = hadamard_matrix_paleyI(n) From 057933782566ba05423d302fe8fae82276238edc Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 3 Oct 2015 17:56:38 -0500 Subject: [PATCH 1247/1872] Some reviewer tweaks and doc additions. --- src/sage/categories/modules.py | 11 +++++++-- src/sage/categories/super_algebras.py | 12 ++++++++++ .../super_hopf_algebras_with_basis.py | 2 +- src/sage/categories/super_modules.py | 23 +++++++++++++++++-- .../categories/super_modules_with_basis.py | 20 ++++++++++++---- 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 56bbe1b0b61..d389b571c2d 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -405,7 +405,10 @@ def Super(self, base_ring=None): .. TODO:: - Same as :meth:`Graded`. + - Explain why this does not commute with :meth:`WithBasis` + - Improve the support for covariant functorial + constructions categories over a base ring so as to + get rid of the ``base_ring`` argument. TESTS:: @@ -476,7 +479,11 @@ def tensor_square(self): sage: A = HopfAlgebrasWithBasis(QQ).example() sage: A.tensor_square() - An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field # An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field + An example of Hopf algebra with basis: + the group algebra of the Dihedral group of order 6 + as a permutation group over Rational Field # An example + of Hopf algebra with basis: the group algebra of the Dihedral + group of order 6 as a permutation group over Rational Field """ return tensor([self, self]) diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py index 4fd9583c206..84c1bc1503b 100644 --- a/src/sage/categories/super_algebras.py +++ b/src/sage/categories/super_algebras.py @@ -17,6 +17,18 @@ class SuperAlgebras(SuperModulesCategory): """ The category of super algebras. + An `R`-*super algebra* is an `R`-super module `A` endowed with an + `R`-algebra structure satisfying + + .. MATH:: + + A_0 A_0 \subseteq A_0, \qquad + A_0 A_1 \subseteq A_1, \qquad + A_1 A_0 \subseteq A_1, \qquad + A_1 A_1 \subseteq A_0 + + and `1 \in A_0`. + EXAMPLES:: sage: Algebras(ZZ).Super() diff --git a/src/sage/categories/super_hopf_algebras_with_basis.py b/src/sage/categories/super_hopf_algebras_with_basis.py index 58e133915b6..28347832bc4 100644 --- a/src/sage/categories/super_hopf_algebras_with_basis.py +++ b/src/sage/categories/super_hopf_algebras_with_basis.py @@ -12,7 +12,7 @@ class SuperHopfAlgebrasWithBasis(SuperModulesCategory): """ - The category of super algebras with a distinguished basis + The category of super Hopf algebras with a distinguished basis. EXAMPLES:: diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py index b93883e4139..16ef317ce16 100644 --- a/src/sage/categories/super_modules.py +++ b/src/sage/categories/super_modules.py @@ -16,6 +16,8 @@ from sage.categories.covariant_functorial_construction import CovariantConstructionCategory from sage.categories.modules import Modules +# Note, a commutative algebra is not a commutative super algebra, +# therefore the following whitelist. axiom_whitelist = frozenset(["Facade", "Finite", "Infinite", "FiniteDimensional", "Connected", "WithBasis", # "Commutative", @@ -88,6 +90,15 @@ class SuperModules(SuperModulesCategory): """ The category of super modules. + An `R`-*super module* (where `R` is a ring) is an `R`-module `M` equipped + with a decomposition `M = M_0 \oplus M_1` into two `R`-submodules + `M_0` and `M_1` (called the *even part* and the *odd part* of `M`, + respectively). + + Thus, an `R`-super module automatically becomes a `\ZZ / 2 \ZZ`-graded + `R`-module, with `M_0` being the degree-`0` component and `M_1` being the + degree-`1` component. + EXAMPLES:: sage: Modules(ZZ).Super() @@ -134,7 +145,7 @@ def extra_super_categories(self): [] This makes sure that ``Modules(QQ).Super()`` returns an - instance of :class:`GradedModules` and not a join category of + instance of :class:`SuperModules` and not a join category of an instance of this class and of ``VectorSpaces(QQ)``:: sage: type(Modules(QQ).Super()) @@ -144,7 +155,7 @@ def extra_super_categories(self): Get rid of this workaround once there is a more systematic approach for the alias ``Modules(QQ)`` -> ``VectorSpaces(QQ)``. - Probably the later should be a category with axiom, and + Probably the latter should be a category with axiom, and covariant constructions should play well with axioms. """ from sage.categories.modules import Modules @@ -164,6 +175,14 @@ def is_even_odd(self): Return ``0`` if ``self`` is an even element or ``1`` if an odd element. + .. NOTE:: + + The default implementation assumes that the even/odd is + determined by the parity of :meth:`degree`. + + Overwrite this method if the even/odd behavior is desired + to be independent. + EXAMPLES:: sage: cat = Algebras(QQ).WithBasis().Super() diff --git a/src/sage/categories/super_modules_with_basis.py b/src/sage/categories/super_modules_with_basis.py index e6930e620e9..c56b097e2d2 100644 --- a/src/sage/categories/super_modules_with_basis.py +++ b/src/sage/categories/super_modules_with_basis.py @@ -14,6 +14,10 @@ class SuperModulesWithBasis(SuperModulesCategory): """ The category of super modules with a distinguished basis. + An `R`-*super module with a distinguished basis* is an + `R`-super module equipped with an `R`-module basis whose elements are + homogeneous. + EXAMPLES:: sage: C = GradedModulesWithBasis(ZZ); C @@ -31,13 +35,21 @@ class SuperModulesWithBasis(SuperModulesCategory): class ParentMethods: def _even_odd_on_basis(self, m): """ - Return if ``m`` is an index of an even or odd basis element. + Return the parity of the basis element indexed by ``m``. OUTPUT: ``0`` if ``m`` is for an even element or ``1`` if ``m`` is for an odd element. + .. NOTE:: + + The default implementation assumes that the even/odd is + determined by the parity of :meth:`degree`. + + Overwrite this method if the even/odd behavior is desired + to be independent. + EXAMPLES:: sage: Q = QuadraticForm(QQ, 2, [1,2,3]) @@ -53,7 +65,7 @@ class ElementMethods: def is_super_homogeneous(self): r""" Return whether this element is homogeneous, in the sense - of a super module. + of a super module (i.e., is even or odd). EXAMPLES:: @@ -70,8 +82,8 @@ def is_super_homogeneous(self): False The exterior algebra has a `\ZZ` grading, which induces the - `\ZZ / 2\ZZ` grading, however the definition of homogeneous - elements differ because of the different gradings:: + `\ZZ / 2\ZZ` grading. However the definition of homogeneous + elements differs because of the different gradings:: sage: E. = ExteriorAlgebra(QQ) sage: a = x*y + 4 From aec22cc54dee46aceaa315a96905059927ad1ea4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 3 Oct 2015 18:14:35 -0500 Subject: [PATCH 1248/1872] Added one more test. --- src/sage/categories/super_modules_with_basis.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/categories/super_modules_with_basis.py b/src/sage/categories/super_modules_with_basis.py index c56b097e2d2..4fa76c34e2d 100644 --- a/src/sage/categories/super_modules_with_basis.py +++ b/src/sage/categories/super_modules_with_basis.py @@ -122,6 +122,10 @@ def is_even_odd(self): Traceback (most recent call last): ... ValueError: element is not homogeneous + + sage: E. = ExteriorAlgebra(QQ) + sage: (x*y).is_even_odd() + 0 """ if not self.support(): raise ValueError("the zero element does not have a well-defined degree") From d77ee902e808082dcc44daf71bb0ea2756c621bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Sat, 3 Oct 2015 21:35:47 -0500 Subject: [PATCH 1249/1872] Improved docstring of PolynomialElement.pseudo_quo_rem() --- src/sage/rings/polynomial/polynomial_element.pyx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index aeb9ba9cd34..ebe25afc471 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4007,13 +4007,14 @@ cdef class Polynomial(CommutativeAlgebraElement): INPUT: - - ``other`` -- A nonzero polynomial, otherwise an exception ValueError is raised + - ``other`` -- a nonzero polynomial OUTPUT: - If ``other`` is nonzero, this algorithm finds Q and R such that - l^(m-n+1) self = Q * other + R where m = deg(self), n = deg(other), - l is the leading coefficient of other, and such that deg(R) < deg(other). + `Q` and `R` such that `l^{m-n+1} \mathrm{self} = Q \cdot\mathrm{other} + R` + where `m` is the degree of this polynomial, `n` is the degree of + ``other``, `l` is the leading coefficient of ``other``. The result is + such that `\deg(R) < \deg(\mathrm{other})`. ALGORITHM: From 78baa464369a7b1bf9c7d29a8b42ced79973fd94 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 4 Oct 2015 08:47:00 +0200 Subject: [PATCH 1250/1872] trac #19342: Goethals-Seidel constructions of strongly regular graphs --- src/sage/graphs/generators/families.py | 62 +++++++++++++++++ src/sage/graphs/graph_generators.py | 2 + src/sage/graphs/strongly_regular_db.pyx | 90 ++++++++++++++++++++++--- 3 files changed, 146 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 05efc1dc10b..2f55630c433 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -689,6 +689,68 @@ def CubeGraph(n): return r +def GoethalsSeidelGraph(k,r): + r""" + Returns the graph `\text{Goethals-Seidel}(k,r)`. + + The graph `\text{Goethals-Seidel}(k,r)` comes from a construction presented + in Theorem 2.4 of [GS70]_. It relies on a :func:`(v,k)-BIBD + ` with `r` + blocks and a + :func:`~sage.combinat.matrices.hadamard_matrix.hadamard_matrix>` of order + `r+1`. The result is a + :func:`sage.graphs.strongly_regular_db.strongly_regular_graph` on `v(r+1)` + vertices with degree `k=(n-r-1)/2`. + + It appears under this name in Andries Brouwer's `database of strongly + regular graphs `__. + + INPUT: + + - ``k,r`` -- integers + + EXAMPLE:: + + sage: graphs.GoethalsSeidelGraph(3,3) + Graph on 28 vertices + sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) + (28, 12, 6, 4) + """ + from sage.combinat.designs.bibd import balanced_incomplete_block_design + from sage.combinat.matrices.hadamard_matrix import hadamard_matrix + from sage.matrix.constructor import Matrix + from sage.matrix.constructor import block_matrix + from sage.matrix.constructor import identity_matrix + + v = (k-1)*r+1 + n = v*(r+1) + + # N is the (v times b) incidence matrix of a bibd + N = balanced_incomplete_block_design(v,k).incidence_matrix() + + # L is a (r+1 times r) matrix, where r is the row sum of N + L = hadamard_matrix(r+1).submatrix(0,1) + L = [Matrix(C).transpose() for C in L.columns()] + zero = Matrix(r+1,1,[0]*(r+1)) + + # For every row of N, we replace the 0s with a column of zeros, and we + # replace the ith 1 with the ith column of L. The result is P. + P = [] + for row in N: + Ltmp = L[:] + P.append([Ltmp.pop(0) if i else zero + for i in row]) + + P = block_matrix(P) + + # The final graph + PP = - P*P.transpose() + for i in range(n): + PP[i,i] = 0 + + G = Graph(PP, format="seidel_adjacency_matrix") + return G + def DorogovtsevGoltsevMendesGraph(n): """ Construct the n-th generation of the Dorogovtsev-Goltsev-Mendes diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index a28d0c3aa75..8585aa121bc 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -202,6 +202,7 @@ def __append_to_doc(methods): "fusenes", "FuzzyBallGraph", "GeneralizedPetersenGraph", + "GoethalsSeidelGraph", "HanoiTowerGraph", "HararyGraph", "HyperStarGraph", @@ -1972,6 +1973,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None FriendshipGraph = staticmethod(sage.graphs.generators.families.FriendshipGraph) FuzzyBallGraph = staticmethod(sage.graphs.generators.families.FuzzyBallGraph) GeneralizedPetersenGraph = staticmethod(sage.graphs.generators.families.GeneralizedPetersenGraph) + GoethalsSeidelGraph = staticmethod(sage.graphs.generators.families.GoethalsSeidelGraph) HanoiTowerGraph = staticmethod(sage.graphs.generators.families.HanoiTowerGraph) HararyGraph = staticmethod(sage.graphs.generators.families.HararyGraph) HyperStarGraph = staticmethod(sage.graphs.generators.families.HyperStarGraph) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index cfefb513375..36358e89262 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -340,13 +340,85 @@ def is_orthogonal_polar(int v,int k,int l,int mu): from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph return (OrthogonalPolarGraph, 2*m, q, "-") +@cached_function +def is_goethals_seidel(int v,int k,int l,int mu): + r""" + Test whether some + :func:`~sage.graphs.graph_generators.GraphGenerators.GoethalsSeidelGraph` graph is + `(v,k,\lambda,\mu)`-strongly regular. + + INPUT: + + - ``v,k,l,mu`` (integers) + + OUTPUT: + + A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one + exists, and ``None`` otherwise. + + EXAMPLES:: + + sage: from sage.graphs.strongly_regular_db import is_goethals_seidel + sage: t = is_goethals_seidel(28, 12, 6, 4); t + [, 3, 3] + sage: g = t[0](*t[1:]); g + Graph on 28 vertices + sage: g.is_strongly_regular(parameters=True) + (28, 12, 6, 4) + + sage: t = is_goethals_seidel(496, 240, 120, 112); t + [, 3, 15] + sage: g = t[0](*t[1:]); g + Graph on 496 vertices + sage: g.is_strongly_regular(parameters=True) + (496, 240, 120, 112) + + sage: t = is_goethals_seidel(5,5,5,5); t + + TESTS:: + + sage: for p in [(28, 12, 6, 4), (120, 56, 28, 24), (496, 240, 120, 112), + ....: (540, 264, 138, 120), (780, 380, 190, 180), (976, 480, 248, 224), + ....: (1216, 600, 312, 280), (1456, 720, 376, 336)]: + ....: print is_goethals_seidel(*p) + [, 3, 3] + [, 3, 7] + [, 3, 15] + [, 5, 11] + [, 3, 19] + [, 5, 15] + [, 6, 15] + [, 7, 15] + + """ + from sage.combinat.designs.bibd import balanced_incomplete_block_design + from sage.combinat.matrices.hadamard_matrix import hadamard_matrix + + # here we guess the parameters v_bibd,k_bibd and r_bibd of the block design + # + # - the number of vertices v is equal to v_bibd*(r_bibd+1) + # - the degree k of the graph is equal to k=(v-r_bibd-1)/2 + + r_bibd = v-2*k-1 + v_bibd = v//(r_bibd+1) + k_bibd = (v_bibd-1)/r_bibd + 1 if r_bibd>0 else -1 + + if (v == v_bibd*(r_bibd+1) and + 2*k == v-r_bibd-1 and + 4*l == 10*k+v_bibd+k_bibd+2*r_bibd-4*v and + hadamard_matrix(r_bibd+1, existence=True) and + balanced_incomplete_block_design(v_bibd, k_bibd, existence = True)): + from sage.graphs.generators.families import GoethalsSeidelGraph + return [GoethalsSeidelGraph, k_bibd, r_bibd] + @cached_function def is_NOodd(int v,int k,int l,int mu): r""" Test whether some NO^e(2n+1,q) graph is `(v,k,\lambda,\mu)`-strongly regular. - Here `q>2`, for in the case `q=2` this graph is complete. For more information, see - :func:`sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph` + Here `q>2`, for in the case `q=2` this graph is complete. For more + information, see + :func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph` and Sect. 7.C of [BvL84]_. INPUT: @@ -415,7 +487,7 @@ def is_NOperp_F5(int v,int k,int l,int mu): Test whether some NO^e,perp(2n+1,5) graph is `(v,k,\lambda,\mu)`-strongly regular. For more information, see - :func:`sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph` + :func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph` and Sect. 7.D of [BvL84]_. INPUT: @@ -470,7 +542,7 @@ def is_NO_F2(int v,int k,int l,int mu): Test whether some NO^e,perp(2n,2) graph is `(v,k,\lambda,\mu)`-strongly regular. For more information, see - :func:`sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph` + :func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph` and INPUT: @@ -521,7 +593,7 @@ def is_NO_F3(int v,int k,int l,int mu): Test whether some NO^e,perp(2n,3) graph is `(v,k,\lambda,\mu)`-strongly regular. For more information, see - :func:`sage.graphs.generators.classical_geometries.NonisotropicOrthogonalPolarGraph` + :func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph` and INPUT: @@ -576,7 +648,7 @@ def is_NU(int v,int k,int l,int mu): Test whether some NU(n,q)-graph, is `(v,k,\lambda,\mu)`-strongly regular. Note that n>2; for n=2 there is no s.r.g. For more information, see - :func:`sage.graphs.generators.classical_geometries.NonisotropicUnitaryPolarGraph` + :func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicUnitaryPolarGraph` and series C14 in [Hu75]_. INPUT: @@ -934,8 +1006,9 @@ def is_taylor_twograph_srg(int v,int k,int l,int mu): OUTPUT: A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph - :func:`TaylorTwographSRG ` - if the parameters match, and ``None`` otherwise. + :func:`TaylorTwographSRG + ` if the + parameters match, and ``None`` otherwise. EXAMPLES:: @@ -2294,6 +2367,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint test_functions = [is_paley, is_johnson, is_orthogonal_array_block_graph, is_steiner, is_affine_polar, + is_goethals_seidel, is_orthogonal_polar, is_NOodd, is_NOperp_F5, is_NO_F2, is_NO_F3, is_NU, is_unitary_polar, From 2e0f69f3803a9b2ff99900fdd10ade0cd4514eb4 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sun, 4 Oct 2015 16:15:58 +0200 Subject: [PATCH 1251/1872] Trac #19073: Fix ReSt errors and links --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- src/sage/rings/asymptotic/growth_group.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index f17fbc3bbc8..1ae58139971 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1327,7 +1327,7 @@ class AsymptoticRingFunctor(ConstructionFunctor): - ``growth_group`` -- a partially ordered group (see :class:`AsymptoticRing` or - mod:`~sage.rings.asymptotic.growth_group` for details). + :mod:`~sage.rings.asymptotic.growth_group` for details). EXAMPLES:: @@ -1398,7 +1398,7 @@ def _apply_functor(self, coefficient_ring): INPUT: - - ``base`` - anything :class:`MonomialGrowthGroup` accepts. + - ``base`` - anything :class:`~sage.rings.asymptotic.growth_group.MonomialGrowthGroup` accepts. OUTPUT: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c8dd78fe178..1800dc27c7c 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1697,7 +1697,7 @@ class AbstractGrowthGroupFunctor(ConstructionFunctor): :mod:`sage.rings.asymptotic.asymptotic_ring`, :class:`ExponentialGrowthGroupFunctor`, :class:`MonomialGrowthGroupFunctor`, - :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, :class:`sage.categories.pushout.ConstructionFunctor`. """ @@ -2316,7 +2316,7 @@ class MonomialGrowthGroupFunctor(AbstractGrowthGroupFunctor): :mod:`sage.rings.asymptotic.asymptotic_ring`, :class:`AbstractGrowthGroupFunctor`, :class:`ExponentialGrowthGroupFunctor`, - :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, :class:`sage.categories.pushout.ConstructionFunctor`. TESTS:: @@ -2800,7 +2800,7 @@ class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): :mod:`sage.rings.asymptotic.asymptotic_ring`, :class:`AbstractGrowthGroupFunctor`, :class:`MonomialGrowthGroupFunctor`, - :class:`sage.rings.asymptotic.asymptotic_ring.AsyptoticRingFunctor`, + :class:`sage.rings.asymptotic.asymptotic_ring.AsymptoticRingFunctor`, :class:`sage.categories.pushout.ConstructionFunctor`. TESTS:: From 22c6bf6d772e40d58d7306976c73ab8359a86d3a Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sun, 4 Oct 2015 16:16:43 +0200 Subject: [PATCH 1252/1872] Trac #19073: Fix minor errors --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/growth_group.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 1ae58139971..0e634663269 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1417,7 +1417,7 @@ def _apply_functor(self, coefficient_ring): def merge(self, other): r""" - Merge this functor with ``other`` of possible. + Merge this functor with ``other`` if possible. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 1800dc27c7c..868983be974 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2782,7 +2782,7 @@ def construction(self): class ExponentialGrowthGroupFunctor(AbstractGrowthGroupFunctor): r""" A :class:`construction functor ` - :class:`exponential growth groups `. + for :class:`exponential growth groups `. INPUT: From 3f67b6b0d0e10c2f4816acc791f6dc2a016eeb8d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 4 Oct 2015 09:17:21 -0500 Subject: [PATCH 1253/1872] Fixing trivial doctest due to changes in category heirarchy. --- src/sage/misc/c3_controlled.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index cb1c4fe2e18..dbf8c5f19ac 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -326,9 +326,9 @@ For a typical category, few bases, if any, need to be added to force sage: x.mro == x.mro_standard False sage: x.all_bases_len() - 82 + 90 sage: x.all_bases_controlled_len() - 89 + 97 The following can be used to search through the Sage named categories for any that requires the addition of some bases:: From 1f672aef481c17e40ccd09b4d0e86b00ed955855 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sun, 4 Oct 2015 16:42:54 +0200 Subject: [PATCH 1254/1872] Trac #19073: language issues --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- src/sage/rings/asymptotic/growth_group.py | 6 +++--- src/sage/rings/asymptotic/growth_group_cartesian.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0e634663269..a34583bceb1 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1454,7 +1454,7 @@ def merge(self, other): def __eq__(self, other): r""" - Return if this functor is equal to ``other``. + Return whether this functor is equal to ``other``. INPUT: @@ -1481,7 +1481,7 @@ def __eq__(self, other): def __ne__(self, other): r""" - Return if this functor is not equal to ``other``. + Return whether this functor is not equal to ``other``. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 868983be974..6c62c9f9f90 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -436,7 +436,7 @@ def __eq__(self, other): def __ne__(self, other): r""" - Compares if this variable does not equal ``other``. + Return whether this variable does not equal ``other``. INPUT: @@ -1769,7 +1769,7 @@ def merge(self, other): def __eq__(self, other): r""" - Return if this functor is equal to ``other``. + Return whether this functor is equal to ``other``. INPUT: @@ -1794,7 +1794,7 @@ def __eq__(self, other): def __ne__(self, other): r""" - Return if this functor is not equal to ``other``. + Return whether this functor is not equal to ``other``. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 2676b1a4131..fba1744e11a 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -306,7 +306,7 @@ def create_object(self, version, args, **kwds): vgs = tuple((v, tuple(gs)) for v, gs in groupby(sorted(vg, key=lambda k: k[0]), key=lambda k: k[0])) - # check if variables are pairwise disjoint + # check whether variables are pairwise disjoint for u, w in product(iter(v for v, _ in vgs), repeat=2): if u != w and not set(u).isdisjoint(set(w)): raise ValueError('The growth groups %s need to have pairwise ' @@ -534,7 +534,7 @@ def _repr_short_(self): def _convert_factors_(self, factors): r""" Helper method. Try to convert some ``factors`` to an - element of one of the cartesian factors and returns the product of + element of one of the cartesian factors and return the product of all these factors. INPUT: @@ -569,7 +569,7 @@ def get_factor(data): def cartesian_injection(self, factor, element): r""" - Injects the given element into this cartesian product at the given factor. + Inject the given element into this cartesian product at the given factor. INPUT: From e2070b1eade3c10b528757d362d63db499d7e5e6 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sun, 4 Oct 2015 16:43:13 +0200 Subject: [PATCH 1255/1872] Trac #19073: mark doctests as indirect --- src/sage/rings/asymptotic/growth_group.py | 2 +- src/sage/rings/asymptotic/growth_group_cartesian.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6c62c9f9f90..b740df6b91e 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1459,7 +1459,7 @@ def _coerce_map_from_(self, S): :: - sage: agg.GrowthGroup('x^QQ').has_coerce_map_from(agg.GrowthGroup('QQ^x')) + sage: agg.GrowthGroup('x^QQ').has_coerce_map_from(agg.GrowthGroup('QQ^x')) # indirect doctest False """ if isinstance(S, type(self)) and self._var_ == S._var_: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index fba1744e11a..b6590f6fbb1 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -609,9 +609,9 @@ def _coerce_map_from_(self, S): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: A = GrowthGroup('QQ^x * x^QQ') sage: B = GrowthGroup('QQ^x * x^ZZ') - sage: A.has_coerce_map_from(B) + sage: A.has_coerce_map_from(B) # indirect doctest True - sage: B.has_coerce_map_from(A) + sage: B.has_coerce_map_from(A) # indirect doctest False """ if CartesianProductPosets.has_coerce_map_from(self, S): From 7146ae68993635d63ed7ecf222af880ec8aec5c8 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 4 Oct 2015 18:03:58 +0200 Subject: [PATCH 1256/1872] trac #19342: The Goethals-Seidel graph, not its complement --- src/sage/graphs/generators/families.py | 4 +-- src/sage/graphs/strongly_regular_db.pyx | 39 ++++++++++++++----------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 2f55630c433..d9a880bffb8 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -700,7 +700,7 @@ def GoethalsSeidelGraph(k,r): :func:`~sage.combinat.matrices.hadamard_matrix.hadamard_matrix>` of order `r+1`. The result is a :func:`sage.graphs.strongly_regular_db.strongly_regular_graph` on `v(r+1)` - vertices with degree `k=(n-r-1)/2`. + vertices with degree `k=(n+r-1)/2`. It appears under this name in Andries Brouwer's `database of strongly regular graphs `__. @@ -744,7 +744,7 @@ def GoethalsSeidelGraph(k,r): P = block_matrix(P) # The final graph - PP = - P*P.transpose() + PP = P*P.transpose() for i in range(n): PP[i,i] = 0 diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 36358e89262..b40e5976755 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -359,37 +359,42 @@ def is_goethals_seidel(int v,int k,int l,int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_goethals_seidel - sage: t = is_goethals_seidel(28, 12, 6, 4); t - [, 3, 3] + sage: t = is_goethals_seidel(28, 15, 6, 10); t + [, 3, 3] sage: g = t[0](*t[1:]); g Graph on 28 vertices sage: g.is_strongly_regular(parameters=True) - (28, 12, 6, 4) + (28, 15, 6, 10) - sage: t = is_goethals_seidel(496, 240, 120, 112); t - [, 3, 15] + sage: t = is_goethals_seidel(256, 135, 70, 72); t + [, 2, 15] sage: g = t[0](*t[1:]); g - Graph on 496 vertices + Graph on 256 vertices sage: g.is_strongly_regular(parameters=True) - (496, 240, 120, 112) + (256, 135, 70, 72) sage: t = is_goethals_seidel(5,5,5,5); t TESTS:: - sage: for p in [(28, 12, 6, 4), (120, 56, 28, 24), (496, 240, 120, 112), - ....: (540, 264, 138, 120), (780, 380, 190, 180), (976, 480, 248, 224), - ....: (1216, 600, 312, 280), (1456, 720, 376, 336)]: + sage: for p in [(16, 9, 4, 6), (28, 15, 6, 10), (64, 35, 18, 20), (120, 63, 30, 36), + ....: (144, 77, 40, 42), (256, 135, 70, 72), (400, 209, 108, 110), + ....: (496, 255, 126, 136), (540, 275, 130, 150), (576, 299, 154, 156), + ....: (780, 399, 198, 210), (784, 405, 208, 210), (976, 495, 238, 264)]: ....: print is_goethals_seidel(*p) + [, 2, 3] [, 3, 3] + [, 2, 7] [, 3, 7] + [, 2, 11] + [, 2, 15] + [, 2, 19] [, 3, 15] [, 5, 11] + [, 2, 23] [, 3, 19] + [, 2, 27] [, 5, 15] - [, 6, 15] - [, 7, 15] - """ from sage.combinat.designs.bibd import balanced_incomplete_block_design from sage.combinat.matrices.hadamard_matrix import hadamard_matrix @@ -397,15 +402,15 @@ def is_goethals_seidel(int v,int k,int l,int mu): # here we guess the parameters v_bibd,k_bibd and r_bibd of the block design # # - the number of vertices v is equal to v_bibd*(r_bibd+1) - # - the degree k of the graph is equal to k=(v-r_bibd-1)/2 + # - the degree k of the graph is equal to k=(v+r_bibd-1)/2 - r_bibd = v-2*k-1 + r_bibd = k - (v-1-k) v_bibd = v//(r_bibd+1) k_bibd = (v_bibd-1)/r_bibd + 1 if r_bibd>0 else -1 if (v == v_bibd*(r_bibd+1) and - 2*k == v-r_bibd-1 and - 4*l == 10*k+v_bibd+k_bibd+2*r_bibd-4*v and + 2*k == v+r_bibd-1 and + 4*l == -2*v + 6*k -v_bibd -k_bibd and hadamard_matrix(r_bibd+1, existence=True) and balanced_incomplete_block_design(v_bibd, k_bibd, existence = True)): from sage.graphs.generators.families import GoethalsSeidelGraph From 9e5437364d8cb518b5d4d49dcddf947680c6e9ca Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 4 Oct 2015 12:33:19 -0500 Subject: [PATCH 1257/1872] Fixing code from change in behavior. --- .../rigged_configurations/rigged_configuration_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py index 43b9e20cba8..bbfe85b94a7 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py +++ b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py @@ -1862,7 +1862,7 @@ def left_column_box(self): for nu in parts[:r-1]: nu._list.append(1) for a, nu in enumerate(parts[:r-1]): - vac_num = RC._calc_vacancy_number(parts, a, -1) + vac_num = RC._calc_vacancy_number(parts, a, 1) i = nu._list.index(1) nu.vacancy_numbers.insert(i, vac_num) nu.rigging.insert(i, vac_num) From fa476ddac910418cb12790af8896154ddca8fd00 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 4 Oct 2015 12:58:51 -0500 Subject: [PATCH 1258/1872] Fixing double-colon in INPUT block. --- src/sage/categories/modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index f38253fb33e..9ac2f77f110 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -352,7 +352,7 @@ def Filtered(self, base_ring=None): r""" Return the subcategory of the filtered objects of ``self``. - INPUT:: + INPUT: - ``base_ring`` -- this is ignored From 6cc8b8460dfe5a05380e73e667dc7294e4369774 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 4 Oct 2015 16:20:51 -0500 Subject: [PATCH 1259/1872] Reviewer changes with Darij. --- src/sage/algebras/associated_graded.py | 18 +++++++------- src/sage/algebras/clifford_algebra.py | 24 ++++++++++--------- src/sage/algebras/weyl_algebra.py | 1 + .../filtered_algebras_with_basis.py | 6 ++--- .../categories/filtered_modules_with_basis.py | 2 +- src/sage/categories/modules_with_basis.py | 4 ++-- src/sage/categories/super_algebras.py | 17 +++++++++++++ .../categories/super_algebras_with_basis.py | 22 +++++++++++++++++ src/sage/categories/super_modules.py | 2 +- 9 files changed, 70 insertions(+), 26 deletions(-) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index a86df92acbf..750cbe33df1 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -178,14 +178,16 @@ def __init__(self, A, category=None): base_ring = A.base_ring() base_one = base_ring.one() - if category is None: - category = A.category().Graded() - opts = copy(A.print_options()) - if not opts['prefix'] and not opts['bracket']: - opts['bracket'] = '(' - opts['prefix'] = opts['prefix'] + 'bar' - - CombinatorialFreeModule.__init__(self, base_ring, A.indices(), + category = A.category().Graded().or_subcategory(category) + try: + opts = copy(A.print_options()) + if not opts['prefix'] and not opts['bracket']: + opts['bracket'] = '(' + opts['prefix'] = opts['prefix'] + 'bar' + except AttributeError: + opts = {'prefix': 'Abar'} + + CombinatorialFreeModule.__init__(self, base_ring, A.basis().keys(), category=category, **opts) # Setup the conversion back diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 7dc85e88289..bb88f5e3bb4 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -426,12 +426,9 @@ class CliffordAlgebra(CombinatorialFreeModule): (where `\ZZ_2 = \ZZ / 2 \ZZ`); this grading is determined by placing all elements of `V` in degree `1`. It is also an `\NN`-filtered algebra, with the filtration too being defined - by placing all elements of `V` in degree `1`. Due to current - limitations of the category framework, Sage can consider - either the grading or the filtration but not both at the same - time (though one can introduce two equal Clifford algebras, - one filtered and the other graded); the ``graded`` parameter - determines which of them is to be used. + by placing all elements of `V` in degree `1`. The :meth:`degree` gives + the `\NN`-*filtration* degree, and to get the super degree use instead + :meth:`~sage.categories.super_modules.SuperModules.ElementMethods.is_even_odd`. The Clifford algebra also can be considered as a covariant functor from the category of vector spaces equipped with quadratic forms @@ -466,8 +463,6 @@ class CliffordAlgebra(CombinatorialFreeModule): - ``Q`` -- a quadratic form - ``names`` -- (default: ``'e'``) the generator names - - ``graded`` -- (default: ``True``) if ``True``, then use the `\ZZ / 2\ZZ` - grading, otherwise use the `\ZZ` filtration EXAMPLES: @@ -528,6 +523,9 @@ def __init__(self, Q, names, category=None): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl = CliffordAlgebra(Q) + sage: Cl.category() + Category of finite dimensional super algebras with basis + over (euclidean domains and infinite enumerated sets) sage: TestSuite(Cl).run() TESTS: @@ -1125,7 +1123,8 @@ def lift_isometry(self, m, names=None): f = lambda x: Cl.prod(Cl._from_dict( {(j,): m[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - return self.module_morphism(on_basis=f, codomain=Cl) + return self.module_morphism(on_basis=f, codomain=Cl, + category=AlgebrasWithBasis(self.base_ring()).Super()) # This is a general method for finite dimensional algebras with bases # and should be moved to the corresponding category once there is @@ -1348,7 +1347,7 @@ class ExteriorAlgebra(CliffordAlgebra): `Q(v) = 0` for all vectors `v \in V`. See :class:`CliffordAlgebra` for the notion of a Clifford algebra. - The exterior algebra of an `R`-module `V` is a super connected + The exterior algebra of an `R`-module `V` is a connected `\ZZ`-graded Hopf superalgebra. It is commutative in the super sense (i.e., the odd elements anticommute and square to `0`). @@ -1422,6 +1421,9 @@ def __init__(self, R, names): EXAMPLES:: sage: E. = ExteriorAlgebra(QQ) + sage: E.category() + Category of finite dimensional super hopf algebras with basis + over Rational Field sage: TestSuite(E).run() """ cat = HopfAlgebrasWithBasis(R).Super() @@ -1569,7 +1571,7 @@ def lift_morphism(self, phi, names=None): f = lambda x: E.prod(E._from_dict( {(j,): phi[j,i] for j in range(n)}, remove_zeros=True ) for i in x) - return self.module_morphism(on_basis=f, codomain=E) + return self.module_morphism(on_basis=f, codomain=E, category=AlgebrasWithBasis(R).Super()) def volume_form(self): """ diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 1ab18ac6715..d94fbd37f9d 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -589,6 +589,7 @@ def __init__(self, R, names=None): raise ValueError("variable names cannot differ by a leading 'd'") # TODO: Make this into a filtered algebra under the natural grading of # x_i and dx_i have degree 1 + # Filtered is not included because it is a supercategory of super if R.is_field(): cat = AlgebrasWithBasis(R).NoZeroDivisors().Super() else: diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index 1179b068b7b..053d119a040 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -461,14 +461,14 @@ def induced_graded_map(self, other, f): sage: Q = QuadraticForm(ZZ, 2, [1,2,3]) sage: B = CliffordAlgebra(Q, names=['u','v']); B The Clifford algebra of the Quadratic form in 2 - variables over Integer Ring with coefficients: + variables over Integer Ring with coefficients: [ 1 2 ] [ * 3 ] sage: m = Matrix(ZZ, [[1, 2], [1, -1]]) sage: f = B.lift_module_morphism(m, names=['x','y']) sage: A = f.domain(); A The Clifford algebra of the Quadratic form in 2 - variables over Integer Ring with coefficients: + variables over Integer Ring with coefficients: [ 6 0 ] [ * 3 ] sage: x, y = A.gens() @@ -521,7 +521,7 @@ def on_basis(m): lifted_img_of_m = f(from_gr(grA.monomial(m))) return other.projection(i)(lifted_img_of_m) return grA.module_morphism(on_basis=on_basis, - codomain=grB, category=cat) + codomain=grB, category=cat) # If we could assume that the projection of the basis # element of ``self`` indexed by an index ``m`` is the # basis element of ``grA`` indexed by ``m``, then this diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index bf7642ae79e..7f2320f7f19 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -562,7 +562,7 @@ def on_basis(m): lifted_img_of_m = f(from_gr(grA.monomial(m))) return other.projection(i)(lifted_img_of_m) return grA.module_morphism(on_basis=on_basis, - codomain=grB, category=cat) + codomain=grB, category=cat) # If we could assume that the projection of the basis # element of ``self`` indexed by an index ``m`` is the # basis element of ``grA`` indexed by ``m``, then this diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 291c55f7f7a..282b6fc7fa9 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -126,8 +126,8 @@ class ModulesWithBasis(CategoryWithAxiom_over_base_ring): .. NOTE:: This category currently requires an implementation of an - element method ``support``. Once :trac:`18066`, an implementation - of an ``items`` method will be required. + element method ``support``. Once :trac:`18066` is merged, an + implementation of an ``items`` method will be required. TESTS:: diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py index 84c1bc1503b..55c7562b255 100644 --- a/src/sage/categories/super_algebras.py +++ b/src/sage/categories/super_algebras.py @@ -48,3 +48,20 @@ def extra_super_categories(self): """ return [self.base_category().Graded()] + class ParentMethods: + def graded_algebra(self): + r""" + Return the associated graded algebra to ``self``. + + .. WARNING:: + + Because a super module `M` is naturally `\ZZ / 2 \ZZ`-graded, and + graded modules have a natural filtration induced by the grading, if + `M` has a different filtration, then the associated graded module + `\operatorname{gr} M \neq M`. This is most apparent with super + algebras, such as the :class:`differential Weyl algebra + `, and the + multiplication may not coincide. + """ + raise NotImplementedError + diff --git a/src/sage/categories/super_algebras_with_basis.py b/src/sage/categories/super_algebras_with_basis.py index 51b2b72afe8..9a4a1bc05a0 100644 --- a/src/sage/categories/super_algebras_with_basis.py +++ b/src/sage/categories/super_algebras_with_basis.py @@ -37,3 +37,25 @@ def extra_super_categories(self): """ return [self.base_category().Graded()] + class ParentMethods: + def graded_algebra(self): + r""" + Return the associated graded module to ``self``. + + See :class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra` + for the definition and the properties of this. + + .. SEEALSO:: + + :meth:`~sage.categories.filtered_modules_with_basis.ParentMethods.graded_algebra` + + EXAMPLES:: + + sage: W. = algebras.DifferentialWeyl(QQ) + sage: W.graded_algebra() + Graded Algebra of Differential Weyl algebra of + polynomials in x, y over Rational Field + """ + from sage.algebras.associated_graded import AssociatedGradedAlgebra + return AssociatedGradedAlgebra(self) + diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py index 16ef317ce16..a0a06dddf3d 100644 --- a/src/sage/categories/super_modules.py +++ b/src/sage/categories/super_modules.py @@ -87,7 +87,7 @@ def _repr_object_names(self): return "super {}".format(self.base_category()._repr_object_names()) class SuperModules(SuperModulesCategory): - """ + r""" The category of super modules. An `R`-*super module* (where `R` is a ring) is an `R`-module `M` equipped From ebbc28d6aa6e890312fa23f87863ec4179bf6f4b Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 4 Oct 2015 19:31:54 -0300 Subject: [PATCH 1260/1872] Trac 19322: reviewer comments - use min/max - avoid recomputing len(other) - move an import at the module level - better error message (+ test) --- src/sage/combinat/words/word_char.pyx | 37 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/words/word_char.pyx b/src/sage/combinat/words/word_char.pyx index 3940c5a41eb..0c55949c019 100644 --- a/src/sage/combinat/words/word_char.pyx +++ b/src/sage/combinat/words/word_char.pyx @@ -25,6 +25,8 @@ from cpython.number cimport PyIndex_Check, PyNumber_Check from cpython.sequence cimport PySequence_Check from cpython.slice cimport PySlice_Check, PySlice_GetIndicesEx +import itertools + # the maximum value of a size_t cdef size_t SIZE_T_MAX = -( 1) @@ -694,6 +696,15 @@ cdef class WordDatatype_char(WordDatatype): 609 [7, 0, 20, 0, 54, 0, 143, 0, 376, 0] 985 [0, 13, 0, 34, 0, 89, 0, 233, 0, 610] 986 [0, 12, 0, 33, 0, 88, 0, 232, 0, 609] + + TESTS:: + + sage: W = Words([0,1,2]) + sage: w = W([0,2,1,0,0,1]) + sage: w.longest_common_prefix(0) + Traceback (most recent call last): + ... + TypeError: unsupported input 0 """ cdef WordDatatype_char w cdef size_t i @@ -704,7 +715,7 @@ cdef class WordDatatype_char(WordDatatype): # (this can be much faster if we allow to compare larger memory # zones) w = other - m = self._length if self._length <= w._length else w._length + m = min(self._length, w._length) for i in range(m): if self._data[i] != w._data[i]: break @@ -719,8 +730,7 @@ cdef class WordDatatype_char(WordDatatype): elif PySequence_Check(other): # Python level # we avoid to call len(other) since it might be an infinite word - from itertools import islice - for i,a in enumerate(islice(other, self._length)): + for i,a in enumerate(itertools.islice(other, self._length)): if self._data[i] != a: break else: @@ -728,7 +738,7 @@ cdef class WordDatatype_char(WordDatatype): return self._new_c(self._data, i, self) - raise TypeError("not able to initialize a word from {}".format(other)) + raise TypeError("unsupported input {}".format(other)) def longest_common_suffix(self, other): r""" @@ -745,17 +755,27 @@ cdef class WordDatatype_char(WordDatatype): word: 001 sage: v.longest_common_suffix(u) word: 001 + + TESTS:: + + sage: W = Words([0,1,2]) + sage: w = W([0,2,1,0,0,1]) + sage: w.longest_common_suffix(0) + Traceback (most recent call last): + ... + TypeError: unsupported input 0 """ cdef WordDatatype_char w cdef size_t i cdef size_t m + cdef size_t lo if isinstance(other, WordDatatype_char): # C level # (this can be much faster if we could compare larger memory # zones) w = other - m = self._length if self._length <= w._length else w._length + m = min(self._length, w._length) for i in range(m): if self._data[self._length-i-1] != w._data[w._length-i-1]: break @@ -769,9 +789,10 @@ cdef class WordDatatype_char(WordDatatype): elif PySequence_Check(other): # Python level - m = self._length if self._length <= len(other) else len(other) + lo = len(other) + m = min(self._length, lo) for i in range(m): - if self._data[self._length-i-1] != other[len(other)-i-1]: + if self._data[self._length-i-1] != other[lo-i-1]: break else: if self._length == m: @@ -781,5 +802,5 @@ cdef class WordDatatype_char(WordDatatype): return self._new_c(self._data+self._length-i, i, self) - raise TypeError("not able to initialize a word from {}".format(other)) + raise TypeError("unsupported input {}".format(other)) From 5c29fd4a50a40d9cc0fcd5d23288639eda3f35f7 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 5 Oct 2015 00:46:13 +0200 Subject: [PATCH 1261/1872] fix typos --- src/sage/categories/pushout.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index cdefa9be244..fd3896ae6b8 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -680,7 +680,7 @@ def common_base(self, other_functor, self_bases, other_bases): .. NOTE:: Overload this function in derived class, see - e.e. :class:`MultivariateConstructionFunctor`. + e.g. :class:`MultivariateConstructionFunctor`. TESTS:: @@ -690,7 +690,7 @@ def common_base(self, other_functor, self_bases, other_bases): ... CoercionException: No common base ("join") found for The cartesian_product functorial construction(Integer Ring) and FractionField(Integer Ring): - (Multivariate) functors are inkompatibel. + (Multivariate) functors are incompatible. sage: pushout(cartesian_product([ZZ]), cartesian_product([ZZ, QQ])) # indirect doctest Traceback (most recent call last): ... @@ -702,7 +702,7 @@ def common_base(self, other_functor, self_bases, other_bases): if self != other_functor: self._raise_common_base_exception_( other_functor, self_bases, other_bases, - '(Multivariate) functors are inkompatibel') + '(Multivariate) functors are incompatible') if len(self_bases) != len(other_bases): self._raise_common_base_exception_( other_functor, self_bases, other_bases, From 6233426582384da8b5935854bbf6beae5976b63f Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 5 Oct 2015 00:47:07 +0200 Subject: [PATCH 1262/1872] improve language --- src/sage/categories/modules.py | 6 +++--- src/sage/categories/pushout.py | 8 ++++---- src/sage/sets/cartesian_product.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 41e7c68bb3c..f603e71f8c0 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -582,8 +582,8 @@ class CartesianProducts(CartesianProductsCategory): """ The category of modules constructed as cartesian products of modules - This construction gives the direct product of modules. See - discussion on: + This construction gives the direct product of modules. The + implementation is based on the following resources: - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16 - http://en.wikipedia.org/wiki/Direct_product @@ -606,7 +606,7 @@ def extra_super_categories(self): class ParentMethods: def base_ring(self): """ - Return the base ring this cartesian product. + Return the base ring of this cartesian product. EXAMPLES:: diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index fd3896ae6b8..b626210f311 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3387,10 +3387,10 @@ def pushout(R, S): Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Real Field with 53 bits of precision Some more tests related to univariate/multivariate - constructions. We construct a parent for a generalization to - polynomials, where we not only specify a coefficient ring `C` but - also an additive monoid `E` for its exponents. Its elements are - then + constructions. We consider a generalization of polynomial rings, + where in addition to the coefficient ring `C` we also specify + an additive monoid `E` for the exponents of the indeterminate. + In particular, the elements of such a parent are given by .. MATH:: diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index e88f8ce9d67..5766bc53276 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -229,7 +229,7 @@ def construction(self): OUTPUT: A pair whose first entry is a cartesian product functor and - its second a list of the cartesian factors. + its second entry is a list of the cartesian factors. EXAMPLES:: From d31667e083586a1c3c47dcf98a96ec6b72d558f8 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 5 Oct 2015 00:47:29 +0200 Subject: [PATCH 1263/1872] fix ReSt-error --- src/sage/categories/modules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index f603e71f8c0..fb721b36e3c 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -585,8 +585,8 @@ class CartesianProducts(CartesianProductsCategory): This construction gives the direct product of modules. The implementation is based on the following resources: - - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16 - - http://en.wikipedia.org/wiki/Direct_product + - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16 + - http://en.wikipedia.org/wiki/Direct_product """ def extra_super_categories(self): """ From c4a5bfd0af27ae8aab42f7b51002273ffa46a875 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 5 Oct 2015 00:48:08 +0200 Subject: [PATCH 1264/1872] remove superfluous import in doctest, superfluous empty line in docstring, and fix spacing in a line (pep 8) --- src/sage/categories/pushout.py | 2 -- src/sage/sets/cartesian_product.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index b626210f311..34c8ae59d20 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -643,7 +643,6 @@ class MultivariateConstructionFunctor(ConstructionFunctor): TESTS:: sage: from sage.categories.pushout import pushout - sage: from sage.sets.cartesian_product import CartesianProduct sage: A = cartesian_product((QQ['z'], QQ)) sage: B = cartesian_product((ZZ['t']['z'], QQ)) sage: pushout(A, B) @@ -3515,7 +3514,6 @@ def pushout(R, S): Univariate Polynomial Ring in y over Rational Field, Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field) - :: sage: from sage.categories.pushout import PolynomialFunctor diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 5766bc53276..27bb6d8c458 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -257,7 +257,7 @@ def _coerce_map_from_(self, S): S_factors = S.cartesian_factors() R_factors = self.cartesian_factors() if len(S_factors) == len(R_factors): - if all(r.has_coerce_map_from(s) for r,s in zip(R_factors, S_factors)): + if all(r.has_coerce_map_from(s) for r, s in zip(R_factors, S_factors)): return True an_element = Sets.CartesianProducts.ParentMethods.an_element From 726b74ada27a58d2a899ca2b2fa66fc15b7e9a05 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 5 Oct 2015 00:50:10 +0200 Subject: [PATCH 1265/1872] CartesianProductPolys: check whether other has a construction --- src/sage/categories/pushout.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 34c8ae59d20..e2e2420fa14 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3538,8 +3538,10 @@ def pushout(R, S): ....: other.cartesian_factors() + ....: tuple(f for f in self.cartesian_factors() ....: if f.variable_name() not in o_vars))) - ....: C = other.construction()[0] - ....: if isinstance(C, PolynomialFunctor): + ....: C = other.construction() + ....: if C is None: + ....: return + ....: elif isinstance(C[0], PolynomialFunctor): ....: return pushout(self, CartesianProductPolys((other,))) :: From d449fabb1adcd514bf988e64736a18de34dd7e25 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 5 Oct 2015 00:56:08 +0200 Subject: [PATCH 1266/1872] add two doctests --- src/sage/categories/pushout.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index e2e2420fa14..0a43371f337 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3513,6 +3513,10 @@ def pushout(R, S): (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Rational Field, Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field) + sage: pushout(ZZ, cartesian_product([ZZ, QQ])) + Traceback (most recent call last): + ... + CoercionException: 'NoneType' object is not iterable :: @@ -3578,6 +3582,15 @@ def pushout(R, S): Univariate Polynomial Ring in y over Multivariate Polynomial Ring in b, c over Rational Field) + :: + + sage: pushout(CartesianProductPolys((ZZ['x'],)), ZZ) + Traceback (most recent call last): + ... + CoercionException: No common base ("join") found for + The cartesian_product functorial construction(...) and None(Integer Ring): + (Multivariate) functors are incompatible. + AUTHORS: - Robert Bradshaw From 5852e1ccc9a362dbb577798961deb3958458cfc5 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 4 Oct 2015 21:49:43 -0400 Subject: [PATCH 1267/1872] Trac #19332: Use reviewer's implementation of discrete_complementarity_set(). The initial implementation of discrete_complementarity_set() converted all rays to vectors before computing inner products and returning orthogonal pairs. Now the inner product is computed directly on the rays of the cone. As a result, toric lattice elements (not vectors) are returned. This simplifies the implementation, and the test output has been adjusted to reflect the ambient lattice of each ray. --- src/sage/geometry/cone.py | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index e425afad19f..ec0c157451c 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -4362,7 +4362,7 @@ def discrete_complementarity_set(self): A list of pairs `(x,s)` such that, - * `x` and `s` are orthogonal vectors. + * `x` and `s` are orthogonal. * `x` is one of this cone's :meth:`~IntegralRayCollection.rays`. * `s` is one of the :meth:`~IntegralRayCollection.rays` of this cone's :meth:`dual`. @@ -4375,11 +4375,11 @@ def discrete_complementarity_set(self): EXAMPLES: The discrete complementarity set of the nonnegative orthant - consists of pairs of standard basis vectors:: + consists of pairs of standard basis elements:: sage: K = Cone([(1,0),(0,1)]) sage: K.discrete_complementarity_set() - [((1, 0), (0, 1)), ((0, 1), (1, 0))] + [(N(1, 0), M(0, 1)), (N(0, 1), M(1, 0))] If the cone consists of a single ray, the second components of the discrete complementarity set should generate the orthogonal @@ -4387,13 +4387,13 @@ def discrete_complementarity_set(self): sage: K = Cone([(1,0)]) sage: K.discrete_complementarity_set() - [((1, 0), (0, 1)), ((1, 0), (0, -1))] + [(N(1, 0), M(0, 1)), (N(1, 0), M(0, -1))] sage: K = Cone([(1,0,0)]) sage: K.discrete_complementarity_set() - [((1, 0, 0), (0, 1, 0)), - ((1, 0, 0), (0, -1, 0)), - ((1, 0, 0), (0, 0, 1)), - ((1, 0, 0), (0, 0, -1))] + [(N(1, 0, 0), M(0, 1, 0)), + (N(1, 0, 0), M(0, -1, 0)), + (N(1, 0, 0), M(0, 0, 1)), + (N(1, 0, 0), M(0, 0, -1))] When the cone is the entire space, its dual is the trivial cone, so the discrete complementarity set is empty:: @@ -4430,18 +4430,10 @@ def discrete_complementarity_set(self): sage: dcs = K.discrete_complementarity_set() sage: sum([ x.inner_product(s).abs() for (x,s) in dcs ]) 0 - """ - V = self.lattice().vector_space() - - # Convert rays to vectors so that we can compute inner products. - G1 = [ V(x) for x in self.rays() ] - - # We also convert the generators of the dual cone so that we - # return pairs of vectors and not (vector, ray) pairs. - G2 = [ V(s) for s in self.dual().rays() ] - - return [ (x,s) for x in G1 for s in G2 if x.inner_product(s) == 0 ] + return [ (x,s) for x in self + for s in self.dual() + if x.inner_product(s) == 0 ] def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, From 872932952e7db998d013637636ca82124ace544e Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 4 Oct 2015 22:14:27 -0400 Subject: [PATCH 1268/1872] Trac #19332: Documentation updates for discrete_complementarity_set(). It's somewhat important to note that the elements of a discrete complementarity set are nonzero, so a statement to that effect has been added to the OUTPUT block. A few places referred to "the" discrete complementarity set; these have been fixed to say "a discrete complementarity set," as they are in general not unique. --- src/sage/geometry/cone.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index ec0c157451c..f9768c96406 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -4362,6 +4362,7 @@ def discrete_complementarity_set(self): A list of pairs `(x,s)` such that, + * `x` and `s` are nonzero. * `x` and `s` are orthogonal. * `x` is one of this cone's :meth:`~IntegralRayCollection.rays`. * `s` is one of the :meth:`~IntegralRayCollection.rays` of this @@ -4374,16 +4375,16 @@ def discrete_complementarity_set(self): EXAMPLES: - The discrete complementarity set of the nonnegative orthant - consists of pairs of standard basis elements:: + Pairs of standard basis elements form a discrete complementarity + set for the nonnegative orthant:: sage: K = Cone([(1,0),(0,1)]) sage: K.discrete_complementarity_set() [(N(1, 0), M(0, 1)), (N(0, 1), M(1, 0))] - If the cone consists of a single ray, the second components of - the discrete complementarity set should generate the orthogonal - complement of that ray:: + If a cone consists of a single ray, then the second components + of a discrete complementarity set for that cone should generate + the orthogonal complement of the ray:: sage: K = Cone([(1,0)]) sage: K.discrete_complementarity_set() @@ -4395,14 +4396,16 @@ def discrete_complementarity_set(self): (N(1, 0, 0), M(0, 0, 1)), (N(1, 0, 0), M(0, 0, -1))] - When the cone is the entire space, its dual is the trivial cone, - so the discrete complementarity set is empty:: + When a cone is the entire space, its dual is the trivial cone, + so the only discrete complementarity set for it is empty:: sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) + sage: K.is_full_space() + True sage: K.discrete_complementarity_set() [] - Likewise when this cone is trivial (its dual is the entire space):: + Likewise for trivial cones, whose duals are the entire space:: sage: L = ToricLattice(0) sage: K = Cone([], ToricLattice(0)) @@ -4411,8 +4414,9 @@ def discrete_complementarity_set(self): TESTS: - The complementarity set of the dual can be obtained by switching - components in the complementarity set of the original cone:: + A discrete complementarity set for the dual can be obtained by + switching components in a discrete complementarity set of the + original cone:: sage: set_random_seed() sage: K = random_cone(max_ambient_dim=6) @@ -4422,7 +4426,7 @@ def discrete_complementarity_set(self): sage: sorted(actual) == sorted(expected) True - The pairs in the discrete complementarity set are in fact + The pairs in a discrete complementarity set are in fact complementary:: sage: set_random_seed() From 0106ab21b4396709346515564b3609ba1c9cee40 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 5 Oct 2015 09:01:58 +0200 Subject: [PATCH 1269/1872] trac #19342: Doctest --- src/sage/graphs/generators/families.py | 3 ++- src/sage/graphs/strongly_regular_db.pyx | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index d9a880bffb8..e0f23d9bc4c 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -714,7 +714,8 @@ def GoethalsSeidelGraph(k,r): sage: graphs.GoethalsSeidelGraph(3,3) Graph on 28 vertices sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) - (28, 12, 6, 4) + (28, 15, 6, 10) + """ from sage.combinat.designs.bibd import balanced_incomplete_block_design from sage.combinat.matrices.hadamard_matrix import hadamard_matrix diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index b40e5976755..47f85f31b35 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -360,14 +360,14 @@ def is_goethals_seidel(int v,int k,int l,int mu): sage: from sage.graphs.strongly_regular_db import is_goethals_seidel sage: t = is_goethals_seidel(28, 15, 6, 10); t - [, 3, 3] + [, 3, 3] sage: g = t[0](*t[1:]); g Graph on 28 vertices sage: g.is_strongly_regular(parameters=True) (28, 15, 6, 10) sage: t = is_goethals_seidel(256, 135, 70, 72); t - [, 2, 15] + [, 2, 15] sage: g = t[0](*t[1:]); g Graph on 256 vertices sage: g.is_strongly_regular(parameters=True) From 5ec1fffc6a467ceb94be2af661cbdbfd0ada68d8 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Mon, 5 Oct 2015 07:32:21 -0400 Subject: [PATCH 1270/1872] update the arxiv reference --- src/sage/combinat/sf/character.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 9e909ebad9e..1b56ec8c18a 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -9,7 +9,7 @@ REFERENCES: .. [OZ2015] R. Orellana, M. Zabrocki, *Symmetric group characters - as symmetric functions*, :arxiv:`1000.0000v1`. + as symmetric functions*, :arxiv:`arXiv:1510.00438`. """ #***************************************************************************** # Copyright (C) 2015 Mike Zabrocki Date: Mon, 5 Oct 2015 07:42:46 -0400 Subject: [PATCH 1271/1872] format incorrect on reference --- src/sage/combinat/sf/character.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 1b56ec8c18a..d8eb03a04b2 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -9,7 +9,7 @@ REFERENCES: .. [OZ2015] R. Orellana, M. Zabrocki, *Symmetric group characters - as symmetric functions*, :arxiv:`arXiv:1510.00438`. + as symmetric functions*, :arxiv:`1510.00438`. """ #***************************************************************************** # Copyright (C) 2015 Mike Zabrocki Date: Mon, 5 Oct 2015 14:32:24 +0200 Subject: [PATCH 1272/1872] trac #19350: A (280, 117, 44, 52)-strongly regular graph --- src/sage/graphs/strongly_regular_db.pyx | 46 ++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index cfefb513375..a41105140d9 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1367,7 +1367,7 @@ def SRG_276_140_58_84(): def SRG_280_135_70_60(): r""" - Return a strongly regular graph with parameters (280, 135, 70, 60). + Return a strongly regular graph with parameters `(280, 135, 70, 60)`. This graph is built from the action of `J_2` on a `3.PGL(2,9)` subgroup it contains. @@ -1393,6 +1393,49 @@ def SRG_280_135_70_60(): g.relabel() return g +def SRG_280_117_44_52(): + r""" + Return a strongly regular graph with parameters `(280, 117, 44, 52)`. + + This graph is built according to a very pretty construction of Mathon and + Rosa [MR85]_: + + The vertices of the graph `G` are all partitions of a set of 9 elements + into `\{\{a,b,c\},\{d,e,f\},\{g,h,i}\}`. The cross-intersection of two + such partitions `P=\{P_1,P_2,P_3\}` and `P'=\{P'_1,P'_2,P'_3\}` being + defined as `\{P_i\cap P_j: 1\leq i,j\leq 3\}`, two vertices of `G` are + set to be adjacent if the cross-intersection of their respective + partitions does not contain exactly 7 nonempty sets. + + EXAMPLE:: + + sage: from sage.graphs.strongly_regular_db import SRG_280_117_44_52 + sage: g=SRG_280_117_44_52() + sage: g.is_strongly_regular(parameters=True) + (280, 117, 44, 52) + + REFERENCE: + + .. [MR85] R. Mathon and A. Rosa, + A new strongly regular graph, + Journal of Combinatorial Theory, Series A 38, no. 1 (1985): 84-86. + http://dx.doi.org/10.1016/0097-3165(85)90025-1 + """ + from sage.graphs.hypergraph_generators import hypergraphs + + # V is the set of partions {{a,b,c},{d,e,f},{g,h,i}} of {0,...,8} + H = hypergraphs.CompleteUniform(9,3) + g = H.intersection_graph() + V = g.complement().cliques_maximal() + V = map(frozenset,V) + + # G is the graph defined on V in which two vertices are adjacent when they + # corresponding partitions cross-intersect on 7 nonempty sets + G = Graph([V, lambda x,y: + sum(any(xxx in yy for xxx in xx) for xx in x for yy in y) != 7], + loops=False) + return G + def strongly_regular_from_two_weight_code(L): r""" Return a strongly regular graph from a two-weight code. @@ -2268,6 +2311,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (256, 153, 92, 90): [SRG_256_153_92_90], (275, 112, 30, 56): [McLaughlinGraph], (276, 140, 58, 84): [SRG_276_140_58_84], + (280, 117, 44, 52): [SRG_280_117_44_52], (280, 135, 70, 60): [SRG_280_135_70_60], (416, 100, 36, 20): [SRG_416_100_36_20], (512, 219, 106, 84): [SRG_512_219_106_84], From 5a0c4b0d9610c2eee9f8d25f929ae3047cb65df8 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 5 Oct 2015 14:39:00 +0200 Subject: [PATCH 1273/1872] Better error handling in sage-download-file --- build/sage_bootstrap/cmdline.py | 41 +++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index c1dfe89c8d8..76c3fc008bf 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -170,8 +170,8 @@ def run(self): destination = None for arg in sys.argv[1:]: if arg.startswith('--print-fastest-mirror'): - print(MirrorList().fastest) - sys.exit(0) + url = "fastest mirror" + continue if arg.startswith('--quiet'): progress = False continue @@ -184,13 +184,30 @@ def run(self): raise ValueError('too many arguments') if url is None: print(dedent(self.__doc__.format(SAGE_DISTFILES=SAGE_DISTFILES))) - sys.exit(1) - if url.startswith('http://') or url.startswith('https://') or url.startswith('ftp://'): - Download(url, destination, progress=progress, ignore_errors=True).run() - else: - # url is a tarball name - tarball = Tarball(url) - tarball.download() - if destination is not None: - tarball.save_as(destination) - + sys.exit(2) + + try: + if url.startswith('http://') or url.startswith('https://') or url.startswith('ftp://'): + Download(url, destination, progress=progress, ignore_errors=True).run() + elif url == "fastest mirror": + print(MirrorList().fastest) + else: + # url is a tarball name + tarball = Tarball(url) + tarball.download() + if destination is not None: + tarball.save_as(destination) + except: + try: + stars = '*' * 72 + '\n' + sys.stderr.write(stars) + try: + import traceback + traceback.print_exc(file=sys.stderr) + sys.stderr.write(stars) + except: + pass + sys.stderr.write("Error downloading %s\n"%(url,)) + sys.stderr.write(stars) + finally: + sys.exit(1) From 92582788c1f3a01479f4414b466275120aa843ec Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 5 Oct 2015 16:44:07 +0200 Subject: [PATCH 1274/1872] Avoid magic string --- build/sage_bootstrap/cmdline.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index 76c3fc008bf..c08d958e4c4 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -167,10 +167,12 @@ class SageDownloadFileApplication(object): def run(self): progress = True url = None + print_fastest_mirror = None destination = None for arg in sys.argv[1:]: if arg.startswith('--print-fastest-mirror'): - url = "fastest mirror" + url = "" + print_fastest_mirror = True continue if arg.startswith('--quiet'): progress = False @@ -189,7 +191,8 @@ def run(self): try: if url.startswith('http://') or url.startswith('https://') or url.startswith('ftp://'): Download(url, destination, progress=progress, ignore_errors=True).run() - elif url == "fastest mirror": + elif print_fastest_mirror: + url = "fastest mirror" # For error message print(MirrorList().fastest) else: # url is a tarball name @@ -197,7 +200,7 @@ def run(self): tarball.download() if destination is not None: tarball.save_as(destination) - except: + except BaseException: try: stars = '*' * 72 + '\n' sys.stderr.write(stars) From 6e2b88bdcd57198ffeb97d4ed4575ee7833e5e0e Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 5 Oct 2015 17:13:48 +0200 Subject: [PATCH 1275/1872] Optimize initialization of RealIntervalFieldElement --- src/sage/rings/qqbar.py | 26 ++++-- src/sage/rings/real_mpfi.pxd | 9 +- src/sage/rings/real_mpfi.pyx | 155 +++++++++++++---------------------- 3 files changed, 82 insertions(+), 108 deletions(-) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 8fc07afb441..cd3a99f14f9 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -449,7 +449,7 @@ ....: def convert_test(v): ....: try: ....: return ty(v) - ....: except ValueError: + ....: except (TypeError, ValueError): ....: return None ....: return [convert_test(_) for _ in all_vals] sage: convert_test_all(float) @@ -3807,7 +3807,8 @@ def degree(self): def interval_fast(self, field): r""" - Given a ``RealIntervalField``, compute the value of this number + Given a :class:`RealIntervalField` or + :class:`ComplexIntervalField`, compute the value of this number using interval arithmetic of at least the precision of the field, and return the value in that field. (More precision may be used in the computation.) The returned interval may be arbitrarily @@ -3827,15 +3828,11 @@ def interval_fast(self, field): sage: x.interval_fast(RIF) Traceback (most recent call last): ... - TypeError: Unable to convert number to real interval. + TypeError: unable to convert 0.7071067811865475244? + 0.7071067811865475244?*I to real interval """ - if field.prec() == self._value.prec(): - return field(self._value) - elif field.prec() > self._value.prec(): + while self._value.prec() < field.prec(): self._more_precision() - return self.interval_fast(field) - else: - return field(self._value) + return field(self._value) def interval_diameter(self, diam): """ @@ -3887,11 +3884,22 @@ def interval(self, field): 0.8412535328311811689? + 0.540640817455597582?*I sage: x.interval(CIF64) 0.8412535328311811689? + 0.5406408174555975822?*I + + The following implicitly use this method:: + + sage: RIF(AA(5).sqrt()) + 2.236067977499790? + sage: AA(-5).sqrt().interval(RIF) + Traceback (most recent call last): + ... + TypeError: unable to convert 2.236067977499789697?*I to real interval """ target = RR(1.0) >> field.prec() val = self.interval_diameter(target) return field(val) + _real_mpfi_ = interval + def radical_expression(self): r""" Attempt to obtain a symbolic expression using radicals. If no diff --git a/src/sage/rings/real_mpfi.pxd b/src/sage/rings/real_mpfi.pxd index d90d471627e..278d533cfd9 100644 --- a/src/sage/rings/real_mpfi.pxd +++ b/src/sage/rings/real_mpfi.pxd @@ -30,14 +30,17 @@ cdef class RealIntervalField_class(sage.rings.ring.Field): cdef real_mpfr.RealField_class __lower_field cdef real_mpfr.RealField_class __middle_field cdef real_mpfr.RealField_class __upper_field - cdef RealIntervalFieldElement _new(self) + cdef inline RealIntervalFieldElement _new(self): + """Return a new real number with parent ``self``.""" + return RealIntervalFieldElement.__new__(RealIntervalFieldElement, self) cdef class RealIntervalFieldElement(RingElement): cdef mpfi_t value - cdef char init - cdef RealIntervalFieldElement _new(self) + cdef inline RealIntervalFieldElement _new(self): + """Return a new real interval with same parent as ``self``.""" + return RealIntervalFieldElement.__new__(RealIntervalFieldElement, self._parent) cdef RealIntervalFieldElement abs(RealIntervalFieldElement self) cdef Rational _simplest_rational_helper(self) cpdef _str_question_style(self, int base, int error_digits, e, bint prefer_sci) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index b3ba9c88ebb..4402d06a71c 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -564,17 +564,6 @@ cdef class RealIntervalField_class(sage.rings.ring.Field): else: return RealField(self.__prec, self.sci_not, "RNDZ") - cdef RealIntervalFieldElement _new(self): - """ - Return a new real number with parent ``self``. - """ - cdef RealIntervalFieldElement x - x = RealIntervalFieldElement.__new__(RealIntervalFieldElement) - x._parent = self - mpfi_init2(x.value, self.__prec) - x.init = 1 - return x - def _repr_(self): """ Return a string representation of ``self``. @@ -667,7 +656,7 @@ cdef class RealIntervalField_class(sage.rings.ring.Field): sage: R('2', base=2) Traceback (most recent call last): ... - TypeError: Unable to convert number to real interval. + TypeError: unable to convert '2' to real interval sage: a = R('1.1001', base=2); a 1.5625000? sage: a.str(2) @@ -1115,21 +1104,33 @@ cdef class RealIntervalFieldElement(RingElement): """ A real number interval. """ - cdef RealIntervalFieldElement _new(self): + def __cinit__(self, parent, x=None, base=None): """ - Return a new real interval with same parent as ``self``. + Initialize the parent of this element and allocate memory + + TESTS:: + + sage: from sage.rings.real_mpfi import RealIntervalFieldElement + sage: RealIntervalFieldElement.__new__(RealIntervalFieldElement, None) + Traceback (most recent call last): + ... + TypeError: Cannot convert NoneType to sage.rings.real_mpfi.RealIntervalField_class + sage: RealIntervalFieldElement.__new__(RealIntervalFieldElement, ZZ) + Traceback (most recent call last): + ... + TypeError: Cannot convert sage.rings.integer_ring.IntegerRing_class to sage.rings.real_mpfi.RealIntervalField_class + sage: RealIntervalFieldElement.__new__(RealIntervalFieldElement, RIF) + [.. NaN ..] """ - cdef RealIntervalFieldElement x - x = RealIntervalFieldElement.__new__(RealIntervalFieldElement) - x._parent = self._parent - mpfi_init2(x.value, (self._parent).__prec) - x.init = 1 - return x + cdef RealIntervalField_class p = parent + mpfi_init2(self.value, p.__prec) + self._parent = p def __init__(self, RealIntervalField_class parent, x=0, int base=10): """ - Create a real interval element. Should be called by first creating - a :class:`RealIntervalField`, as illustrated in the examples. + Initialize a real interval element. Should be called by first + creating a :class:`RealIntervalField`, as illustrated in the + examples. EXAMPLES:: @@ -1157,94 +1158,56 @@ cdef class RealIntervalFieldElement(RingElement): Type: ``RealIntervalField?`` for many more examples. """ - import sage.rings.qqbar - - self.init = 0 - if parent is None: - raise TypeError - self._parent = parent - mpfi_init2(self.value, parent.__prec) - self.init = 1 - if x is None: return - cdef RealIntervalFieldElement _x, n, d - cdef RealNumber rn, rn1 - cdef Rational rat, rat1 - cdef Integer integ, integ1 - cdef RealDoubleElement dx, dx1 - cdef int ix, ix1 + if x is None: + return + + cdef RealNumber ra, rb + cdef RealIntervalFieldElement d + if isinstance(x, RealIntervalFieldElement): - _x = x # so we can get at x.value - mpfi_set(self.value, _x.value) + mpfi_set(self.value, (x).value) elif isinstance(x, RealNumber): - rn = x - mpfi_set_fr(self.value, rn.value) + mpfi_set_fr(self.value, (x).value) elif isinstance(x, Rational): - rat = x - mpfi_set_q(self.value, rat.value) + mpfi_set_q(self.value, (x).value) elif isinstance(x, Integer): - integ = x - mpfi_set_z(self.value, integ.value) + mpfi_set_z(self.value, (x).value) elif isinstance(x, int): - ix = x - mpfi_set_si(self.value, ix) + mpfi_set_si(self.value, x) + elif hasattr(x, '_real_mpfi_'): + d = x._real_mpfi_(self._parent) + mpfi_set(self.value, d.value) elif isinstance(x, tuple): try: a, b = x except ValueError: raise TypeError("tuple defining an interval must have length 2") if isinstance(a, RealNumber) and isinstance(b, RealNumber): - rn = a - rn1 = b - mpfi_interv_fr(self.value, rn.value, rn1.value) + mpfi_interv_fr(self.value, (a).value, (b).value) elif isinstance(a, RealDoubleElement) and isinstance(b, RealDoubleElement): - dx = a - dx1 = b - mpfi_interv_d(self.value, dx._value, dx1._value) + mpfi_interv_d(self.value, (a)._value, (b)._value) elif isinstance(a, Rational) and isinstance(b, Rational): - rat = a - rat1 = b - mpfi_interv_q(self.value, rat.value, rat1.value) + mpfi_interv_q(self.value, (a).value, (b).value) elif isinstance(a, Integer) and isinstance(b, Integer): - integ = a - integ1 = b - mpfi_interv_z(self.value, integ.value, integ1.value) + mpfi_interv_z(self.value, (a).value, (b).value) elif isinstance(a, int) and isinstance(b, int): - ix = a - ix1 = b - mpfi_interv_si(self.value, ix, ix1) + mpfi_interv_si(self.value, a, b) else: # generic fallback - rn = self._parent(a).lower() - rn1 = self._parent(b).upper() - mpfi_interv_fr(self.value, rn.value, rn1.value) - - elif isinstance(x, sage.rings.qqbar.AlgebraicReal): - d = x.interval(self._parent) - mpfi_set(self.value, d.value) - - elif hasattr(x, '_real_mpfi_'): - d = x._real_mpfi_(self._parent) - mpfi_set(self.value, d.value) - + ra = self._parent(a).lower() + rb = self._parent(b).upper() + mpfi_interv_fr(self.value, ra.value, rb.value) + elif isinstance(x, str): + s = str(x).replace('..', ',').replace(' ','').replace('+infinity', '@inf@').replace('-infinity','-@inf@') + if mpfi_set_str(self.value, s, base): + raise TypeError("unable to convert {!r} to real interval".format(x)) else: - from sage.symbolic.expression import Expression - - if isinstance(x, Expression): - d = x._real_mpfi_(self._parent) - mpfi_set(self.value, d.value) - - elif isinstance(x, str): - # string - s = str(x).replace('..', ',').replace(' ','').replace('+infinity', '@inf@').replace('-infinity','-@inf@') - if mpfi_set_str(self.value, s, base): - raise TypeError("Unable to convert number to real interval.") - else: - # try coercing to real - try: - rn = self._parent._lower_field()(x) - rn1 = self._parent._upper_field()(x) - except TypeError: - raise TypeError("Unable to convert number to real interval.") - mpfi_interv_fr(self.value, rn.value, rn1.value) + # try coercing to real + try: + ra = self._parent._lower_field()(x) + rb = self._parent._upper_field()(x) + except TypeError: + raise TypeError("unable to convert {!r} to real interval".format(x)) + mpfi_interv_fr(self.value, ra.value, rb.value) def __reduce__(self): """ @@ -1292,7 +1255,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: R = RealIntervalField() sage: del R # indirect doctest """ - if self.init: + if self._parent is not None: mpfi_clear(self.value) def __repr__(self): @@ -3939,7 +3902,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: a.min('x') Traceback (most recent call last): ... - TypeError: Unable to convert number to real interval. + TypeError: unable to convert 'x' to real interval """ cdef RealIntervalFieldElement constructed cdef RealIntervalFieldElement result @@ -4043,7 +4006,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: a.max('x') Traceback (most recent call last): ... - TypeError: Unable to convert number to real interval. + TypeError: unable to convert 'x' to real interval """ cdef RealIntervalFieldElement constructed cdef RealIntervalFieldElement result From 50c696612c689a1bb2bfbffaf00f2ca211b1f35b Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 5 Oct 2015 18:16:22 +0200 Subject: [PATCH 1276/1872] trac #19350: Typo --- src/sage/graphs/strongly_regular_db.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index a41105140d9..8bb3fe56863 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1403,7 +1403,7 @@ def SRG_280_117_44_52(): The vertices of the graph `G` are all partitions of a set of 9 elements into `\{\{a,b,c\},\{d,e,f\},\{g,h,i}\}`. The cross-intersection of two such partitions `P=\{P_1,P_2,P_3\}` and `P'=\{P'_1,P'_2,P'_3\}` being - defined as `\{P_i\cap P_j: 1\leq i,j\leq 3\}`, two vertices of `G` are + defined as `\{P_i\cap P'_j: 1\leq i,j\leq 3\}`, two vertices of `G` are set to be adjacent if the cross-intersection of their respective partitions does not contain exactly 7 nonempty sets. From 53164a9a0567d6b84111a0eb8eabd1630970fda5 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 5 Oct 2015 09:37:49 -0700 Subject: [PATCH 1277/1872] implementing SRG_210_99_48_45 --- src/sage/graphs/strongly_regular_db.pyx | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index cfefb513375..33f8d65d65f 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1218,6 +1218,59 @@ def SRG_176_105_68_54(): H = IncidenceStructure([x for x in W if 22 not in x]) return H.intersection_graph(3) +def SRG_210_99_48_45(): + r""" + Return a strongly regular graph with parameters `(210, 99, 48, 45)` + + This graph is from Example 4.2 in [KPRWZ10]_. One considers the action of + the symmetric group `S_7` on the 210 digraphs isomorphic to the + disjoint union of `K_1` and the circulant 6-vertex digraph + ``digraphs.Circulant(6,[1,4])``. It has 16 orbitals; the package [COCO]_ + found a megring of them, explicitly described in [KPRWZ10]_, resulting in + this graph. + + EXAMPLE:: + + sage: from sage.graphs.strongly_regular_db import SRG_210_99_48_45 + sage: g=SRG_210_99_48_45() + sage: g.is_strongly_regular(parameters=True) + (210, 99, 48, 45) + + REFERENCES: + + .. [KPRWZ10] M. H. Klin, C. Pech, S. Reichard, A. Woldar, M. Zvi-Av, + Examples of computer experimentation in algebraic combinatorics, + ARS MATHEMATICA CONTEMPORANEA 3 (2010) 237–258 + http://amc-journal.eu/index.php/amc/article/viewFile/119/118 + + .. [COCO] I. A. Faradjev and M. H. Klin, + Computer package for computations with coherent configurations, + Proc. ISSAC-91, ACM Press, Bonn, 1991, pages 219–223; + code, by I.A.Faradjev (with contributions by A.E.Brouwer, D.V.Pasechnik) + https://github.com/dimpase/coco + + """ + from sage.libs.gap.libgap import libgap + from sage.combinat.permutation import Permutation + def ekg(g0): # return arcs of the Cayley digraph of on {g,g^4} + g = Permutation(g0) + return libgap.Set(map(lambda x: (x,g(x)), range(1,8))\ + + map(lambda x: (x,g(g(g(g(x))))), range(1,8))) + + kd=map(ekg, + [(7, 1, 2, 3, 4, 5), (7, 1, 3, 4, 5, 6), + (7, 3, 4, 5, 6, 2), (7, 1, 4, 3, 5, 6), + (7, 3, 1, 4, 5, 6), (7, 2, 4, 3, 5, 6), + (7, 3, 2, 4, 5, 1), (7, 2, 4, 3, 5, 1)]) + s=libgap.SymmetricGroup(7) + O=s.Orbit(kd[0],libgap.OnSetsTuples) + sa=s.Action(O,libgap.OnSetsTuples) + G=Graph() + for g in kd[1:]: + G.add_edges(libgap.Orbit(sa,[libgap.Position(O,kd[0]),\ + libgap.Position(O,g)],libgap.OnSets)) + return G + def SRG_243_110_37_60(): r""" Return a `(243, 110, 37, 60)`-strongly regular graph. @@ -2258,6 +2311,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (176, 49, 12, 14): [SRG_176_49_12_14], (176, 105, 68, 54): [SRG_176_105_68_54], (196, 91, 42, 42): [SRG_196_91_42_42], + (210, 99, 48, 45): [SRG_210_99_48_45], (220, 84, 38, 28): [SRG_220_84_38_28], (231, 30, 9, 3): [CameronGraph], (243, 110, 37, 60): [SRG_243_110_37_60], From d5f10f7e308bf0fdbe9cfd2b7cc39eab6ace8eb4 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 5 Oct 2015 18:47:57 +0200 Subject: [PATCH 1278/1872] trac #19353: A (729, 448, 277, 272)-strongly regular graph --- src/sage/graphs/strongly_regular_db.pyx | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index cfefb513375..2eccbdc5463 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1522,6 +1522,34 @@ def SRG_560_208_72_80(): h.relabel() return h +def SRG_729_448_277_272(): + r""" + Return a `(729, 448, 277, 272)`-strongly regular graph. + + This graph is built from a ternary `[140, 6]` code with weights `90, 99`, + found by Axel Kohnert [Kohnert07]_ and shared by Alfred Wassermann. + + .. SEEALSO:: + + :func:`strongly_regular_from_two_weight_code` -- build a strongly regular graph from + a two-weight code. + + EXAMPLE:: + + sage: from sage.graphs.strongly_regular_db import SRG_729_448_277_272 + sage: G = SRG_729_448_277_272() # long time + sage: G.is_strongly_regular(parameters=True) # long time + (729, 448, 277, 272) + """ + x = ("10111011111111101110101110111100111011111011101111101001001111011011011111100100111101000111101111101100011011001111101110111110101111111001", + "01220121111211011101011101112101220022120121011222010110011010120110112112001101021010101111012211011000020110012221212101011101211122020011", + "22102021112110111120211021122012100012202220112110101200110101202102122120011110020201211110021210110000101200121222122010211022211210110101", + "11010221121101111102210221220221000111011101121102012101101012012022222000211200202012211100111201200001122001211011120102110212212102121001", + "20201121211111111012202022201210001220122121211010121011010020110121220201212002010222011001111012100011010212110021202021102112221012110011", + "02022222111111110112020112011200022102212222110102210110100101102211201211220020002120110011110221100110002121100222120211021112010112220101") + M = Matrix(GF(3),[list(l) for l in x]) + return strongly_regular_from_two_weight_code(LinearCode(M)) + def SRG_729_532_391_380(): r""" Return a `(729, 532, 391, 380)`-strongly regular graph. @@ -2277,6 +2305,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (625, 364, 213,210): [SRG_625_364_213_210], (729, 616, 523,506): [SRG_729_616_523_506], (729, 420, 243,240): [SRG_729_420_243_240], + (729, 448, 277,272): [SRG_729_448_277_272], (729, 560, 433,420): [SRG_729_560_433_420], (729, 476, 313,306): [SRG_729_476_313_306], (729, 532, 391,380): [SRG_729_532_391_380], From 2553467c572dc462c4b514ba8e405fb928017928 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 5 Oct 2015 20:18:12 +0200 Subject: [PATCH 1279/1872] trac #19340: Typo --- src/sage/combinat/matrices/hadamard_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 84e29988a05..5159a16bdf3 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -202,7 +202,7 @@ def is_hadamard_matrix(M, normalized=False, verbose=False): - ``M`` -- a matrix - ``normalized`` (boolean) -- whether to test if ``M`` is a normalized - Hadamard matrix, i.e. has its first row/column filles with +1. + Hadamard matrix, i.e. has its first row/column filled with +1. - ``verbose`` (boolean) -- whether to be verbose when the matrix is not Hadamard. From cdd0b8fd407431f524534cb9c0beb9942ba4bef5 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 5 Oct 2015 20:26:59 +0200 Subject: [PATCH 1280/1872] trac #19350: Dima cannot add a space in a docstring without me. --- src/sage/graphs/strongly_regular_db.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 8bb3fe56863..209dec6e182 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1403,7 +1403,7 @@ def SRG_280_117_44_52(): The vertices of the graph `G` are all partitions of a set of 9 elements into `\{\{a,b,c\},\{d,e,f\},\{g,h,i}\}`. The cross-intersection of two such partitions `P=\{P_1,P_2,P_3\}` and `P'=\{P'_1,P'_2,P'_3\}` being - defined as `\{P_i\cap P'_j: 1\leq i,j\leq 3\}`, two vertices of `G` are + defined as `\{P_i \cap P'_j: 1\leq i,j\leq 3\}`, two vertices of `G` are set to be adjacent if the cross-intersection of their respective partitions does not contain exactly 7 nonempty sets. From 7667bf2e63c14bf2f4f8437a02f786dfbc507970 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 5 Oct 2015 22:08:09 +0200 Subject: [PATCH 1281/1872] trac #19358: Wrong results in Graph.treewidth() --- src/sage/graphs/graph.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 56282c0c86e..51a35e102ad 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -2736,6 +2736,15 @@ def treewidth(self,k=None,certificate=False): ....: g.delete_edges(list(combinations(bag,2))) sage: g.size() 0 + + :trac:`19358`:: + + sage: g = Graph() + sage: for i in range(3): + ....: for j in range(2): + ....: g.add_path([i,(i,j),(i+1)%3]) + sage: g.treewidth() + 2 """ from sage.misc.cachefunc import cached_function from sage.sets.set import Set @@ -2781,9 +2790,8 @@ def rec(cut,cc): if len(cc)+len(cut) <= k+1: return [(cut,cut.union(cc))] if certificate else True - # The list of potential vertices that could be added to the current cut - extensions = {v for u in cut for v in g.neighbors(u) if v in cc} - for v in extensions: + # We explore all possible extensions of the cut + for v in cc: # New cuts and connected components, with v respectively added and # removed From 98e4667d49ce4634c9208e5a8e880fb389aca7d2 Mon Sep 17 00:00:00 2001 From: Michele Borassi Date: Mon, 5 Oct 2015 23:23:18 +0200 Subject: [PATCH 1282/1872] Solved bug with edge labels --- src/sage/graphs/base/boost_graph.pyx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index 0663cb34d25..a68db5dcc73 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -166,6 +166,13 @@ cpdef edge_connectivity(g): sage: edge_connectivity(g) [4, [(0, 1), (0, 2), (0, 3), (0, 4)]] + Vertex-labeled graphs:: + + sage: from sage.graphs.base.boost_graph import edge_connectivity + sage: g = graphs.GridGraph([2,2]) + sage: edge_connectivity(g) + [2, [((0, 0), (0, 1)), ((0, 0), (1, 0))]] + """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph @@ -173,11 +180,12 @@ cpdef edge_connectivity(g): # These variables are automatically deleted when the function terminates. cdef BoostVecGraph g_boost_und cdef BoostVecDiGraph g_boost_dir + cdef dict int_to_vertex = {i:v for i,v in enumerate(g.vertices())} if isinstance(g, Graph): boost_graph_from_sage_graph(&g_boost_und, g) sig_check() - return boost_edge_connectivity(&g_boost_und) + ec, edges = boost_edge_connectivity(&g_boost_und) elif isinstance(g, DiGraph): from sage.misc.stopgap import stopgap @@ -186,11 +194,13 @@ cpdef edge_connectivity(g): boost_graph_from_sage_graph(&g_boost_dir, g) sig_check() - return boost_edge_connectivity(&g_boost_dir) + ec, edges = boost_edge_connectivity(&g_boost_dir) else: raise ValueError("The input must be a Sage graph.") + return [ec, [(int_to_vertex[u], int_to_vertex[v]) for (u,v) in edges]] + cdef boost_clustering_coeff(BoostGenGraph *g, vertices): r""" Computes the clustering coefficient of all vertices in the list provided. From e345dfab6cc04da5451c4fbee1de6a09625f0b41 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 5 Oct 2015 21:30:54 -0300 Subject: [PATCH 1283/1872] Trac 19284: fix doc + make it work --- src/sage/interfaces/octave.py | 222 ++++++++++++++++++++++------------ 1 file changed, 148 insertions(+), 74 deletions(-) diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index 47da9f0ce15..bb1fe260ab4 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -372,9 +372,9 @@ def clear(self, var): EXAMPLES:: sage: octave.set('x', '2') # optional - octave - sage: octave.clear('x') # optional - octave - sage: octave.get('x') # optional - octave - "error: `x' undefined near line ... column 1" + sage: octave.clear('x') # optional - octave + sage: octave.get('x') # optional - octave + "error: 'x' undefined near line ... column 1" """ self.eval('clear %s'%var) @@ -533,33 +533,114 @@ def _object_class(self): return OctaveElement +octave_functions = set() + +def to_complex(octave_string, R): + r""" + Helper function to convert octave complex number + + TESTS:: + + sage: from sage.interfaces.octave import to_complex + sage: to_complex('(0,1)', CDF) + 1.0*I + sage: to_complex('(1.3231,-0.2)', CDF) + 1.3231 - 0.2*I + """ + real, imag = octave_string.strip('() ').split(',') + return R(float(real), float(imag)) + class OctaveElement(ExpectElement): - def _matrix_(self, R): + def _get_sage_ring(self): + r""" + TESTS:: + + sage: octave('1')._get_sage_ring() # optional - octave + Real Double Field + sage: octave('I')._get_sage_ring() # optional - octave + Complex Double Field + sage: octave('[]')._get_sage_ring() # optional - octave + Real Double Field + """ + if self.isinteger(): + import sage.rings.integer_ring + return sage.rings.integer_ring.ZZ + elif self.isreal(): + import sage.rings.real_double + return sage.rings.real_double.RDF + elif self.iscomplex(): + import sage.rings.complex_double + return sage.rings.complex_double.CDF + else: + raise TypeError("no Sage ring associated to this element.") + + def __nonzero__(self): + r""" + Test whether this element is zero. + + EXAMPLES:: + + sage: bool(octave('0')) # optional - octave + False + sage: bool(octave('[]')) # optional - octave + False + sage: bool(octave('[0,0]')) # optional - octave + False + sage: bool(octave('[0,0,0;0,0,0]')) # optional - octave + False + + sage: bool(octave('0.1')) # optional - octave + True + sage: bool(octave('[0,1,0]')) # optional - octave + True + sage: bool(octave('[0,0,-0.1;0,0,0]')) # optional - octave + True + """ + return str(self) != ' [](0x0)' and any(x != '0' for x in str(self).split()) + + def _matrix_(self, R=None): r""" Return Sage matrix from this octave element. EXAMPLES:: + sage: A = octave('[1,2;3,4.5]') # optional - octave + sage: matrix(A) # optional - octave + [1.0 2.0] + [3.0 4.5] + sage: _.base_ring() # optional - octave + Real Double Field + + sage: A = octave('[I,1;-1,0]') # optional - octave + sage: matrix(A) # optional - octave + [1.0*I 1.0] + [ -1.0 0.0] + sage: _.base_ring() # optional - octave + Complex Double Field + sage: A = octave('[1,2;3,4]') # optional - octave sage: matrix(ZZ, A) # optional - octave [1 2] [3 4] - sage: A = octave('[1,2;3,4.5]') # optional - octave - sage: matrix(RR, A) # optional - octave - [1.00000000000000 2.00000000000000] - [3.00000000000000 4.50000000000000] """ - from sage.matrix.all import MatrixSpace oc = self.parent() - if not oc('ismatrix(%s)' % self): + if not self.ismatrix(): raise TypeError('not an octave matrix') + if R is None: + R = self._get_sage_ring() + s = str(self).strip('\n ') w = [u.strip().split(' ') for u in s.split('\n')] nrows = len(w) ncols = len(w[0]) + + if self.iscomplex(): + w = [[to_complex(x,R) for x in row] for row in w] + + from sage.matrix.all import MatrixSpace return MatrixSpace(R, nrows, ncols)(w) - def _vector_(self, R): + def _vector_(self, R=None): r""" Return Sage vector from this octave element. @@ -567,67 +648,62 @@ def _vector_(self, R): sage: A = octave('[1,2,3,4]') # optional - octave sage: vector(ZZ, A) # optional - octave - [1 2 3 4] + (1, 2, 3, 4) sage: A = octave('[1,2.3,4.5]') # optional - octave - sage: vector(RR, A) # optional - octave - [1.00000000000000 2.30000000000000 4.50000000000000] + sage: vector(A) # optional - octave + (1.0, 2.3, 4.5) + sage: A = octave('[1,I]') # optional - octave + sage: vector(A) # optional - octave + (1.0, 1.0*I) """ - from sage.modules.free_module import FreeModule oc = self.parent() - if not oc('isvector(%s)' % self): + if not self.isvector(): raise TypeError('not an octave vector') + if R is None: + R = self._get_sage_ring() + s = str(self).strip('\n ') w = s.strip().split(' ') nrows = len(w) + + if self.iscomplex(): + w = [to_complex(x, R) for x in w] + + from sage.modules.free_module import FreeModule return FreeModule(R, nrows)(w) - def _scalar_(self, find_parent=False): + def _scalar_(self): """ Return Sage scalar from this octave element. - INPUT: - - - find_parent -- boolean (default ``False``). If ``True`` also return - the ring to which the scalar belongs. - EXAMPLES:: sage: A = octave('2833') # optional - octave - sage: As = A.sage(); As # optional - octave - 2833 - sage: As.parent() # optional - octave - Integer Ring + sage: As = A.sage(); As # optional - octave + 2833.0 + sage: As.parent() # optional - octave + Real Double Field + sage: B = sqrt(A) # optional - octave - sage: Bs = B.sage(); Bs # optional - octave + sage: Bs = B.sage(); Bs # optional - octave 53.2259 - sage: Bs.parent() # optional - octave - Real Field with 53 bits of precision + sage: Bs.parent() # optional - octave + Real Double Field + sage: C = sqrt(-A) # optional - octave - sage: Cs = C.sage(); Cs # optional - octave + sage: Cs = C.sage(); Cs # optional - octave 53.2259*I - sage: Cs.parent() # optional - octave - Complex Field with 53 bits of precision + sage: Cs.parent() # optional - octave + Complex Double Field """ - from sage.rings.complex_double import CDF - from sage.rings.integer_ring import ZZ - from sage.rings.real_double import RDF - oc = self.parent() - if oc('isinteger(%s)' % self): - if not find_parent: - return ZZ(str(self)) - else: - return ZZ(str(self)), ZZ - elif oc('isreal(%s)' % self): - if not find_parent: - return RDF(str(self)) - else: - return RDF(str(self)), RDF - elif oc('iscomplex(%s)' % self): - real, imag = str(self).strip('() ').split(',') - if not find_parent: - return CDF(RDF(real), RDF(imag)) - else: - return CDF(RDF(real), RDF(imag)), CDF + if not self.isscalar(): + raise TypeError("not an octave scalar") + + R = self._get_sage_ring() + if self.iscomplex(): + return to_complex(str(self), R) + else: + return R(str(self)) def _sage_(self): """ @@ -635,36 +711,34 @@ def _sage_(self): EXAMPLES:: - sage: A = octave('2833') # optional - octave - sage: A.sage() # optional - octave - 2833 - sage: B = sqrt(A) # optional - octave - sage: B.sage() # optional - octave + sage: A = octave('2833') # optional - octave + sage: A.sage() # optional - octave + 2833.0 + sage: B = sqrt(A) # optional - octave + sage: B.sage() # optional - octave 53.2259 - sage: C = sqrt(-A) # optional - octave - sage: C.sage() # optional - octave + sage: C = sqrt(-A) # optional - octave + sage: C.sage() # optional - octave 53.2259*I - sage: A = octave('[1,2,3,4]') # optional - octave - sage: A.sage() # optional - octave - [1 2 3 4] - sage: A = octave('[1,2.3,4.5]') # optional - octave - sage: A.sage() # optional - octave - [1.00000000000000 2.30000000000000 4.50000000000000] - sage: A = octave('[1,2.3+I,4.5]') # optional - octave - sage: A.sage() # optional - octave - [1.00000000000000 2.30000000000000+1.0*I 4.50000000000000] - """ - oc = self.parent() - if oc('isscalar(%s)' % self): + sage: A = octave('[1,2,3,4]') # optional - octave + sage: A.sage() # optional - octave + (1.0, 2.0, 3.0, 4.0) + sage: A = octave('[1,2.3,4.5]') # optional - octave + sage: A.sage() # optional - octave + (1.0, 2.3, 4.5) + sage: A = octave('[1,2.3+I,4.5]') # optional - octave + sage: A.sage() # optional - octave + (1.0, 2.3 + 1.0*I, 4.5) + """ + if self.isscalar(): return self._scalar_() - elif oc('isvector(%s)' % self): + elif self.isvector(): return self._vector_() - elif oc('ismatrix(%s)' % self): + elif self.ismatrix(): return self._matrix_() else: raise NotImplementedError('octave type is not recognized') - # An instance octave = Octave() From 16a3791a26e665843d0b9357a0bd56f4daf88881 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 5 Oct 2015 21:12:26 -0500 Subject: [PATCH 1284/1872] Marked a doctest as indirect doctest. --- src/sage/categories/super_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py index 84c1bc1503b..cfd3e944203 100644 --- a/src/sage/categories/super_algebras.py +++ b/src/sage/categories/super_algebras.py @@ -42,7 +42,7 @@ def extra_super_categories(self): """ EXAMPLES:: - sage: Algebras(ZZ).Super().super_categories() + sage: Algebras(ZZ).Super().super_categories() # indirect doctest [Category of graded algebras over Integer Ring, Category of super modules over Integer Ring] """ From 57f92dd1a206bb5af2ed00e4135ded0c586e99db Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 5 Oct 2015 21:40:37 -0500 Subject: [PATCH 1285/1872] Adding some doctests and making things use the filtered basis. --- src/sage/combinat/sf/orthogonal.py | 3 ++- src/sage/combinat/sf/sf.py | 10 ++++++++++ src/sage/combinat/sf/sfa.py | 23 ++++++++++++++++------- src/sage/combinat/sf/symplectic.py | 3 ++- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 2c3763958c9..5666750d450 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -161,7 +161,8 @@ def __init__(self, Sym): sage: o = SymmetricFunctions(QQ).o() sage: TestSuite(o).run() """ - sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "orthogonal", 'o') + sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "orthogonal", + 'o', graded=False) # Setup the coercions s = Sym.schur() diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 395182dcc6e..d15911abd56 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -1024,6 +1024,11 @@ def forgotten(self): def symplectic(self): """ The symplectic basis of the symmetric functions. + + EXAMPLES:: + + sage: SymmetricFunctions(QQ).symplectic() + Symmetric Functions over Rational Field in the symplectic basis """ import symplectic return symplectic.SymmetricFunctionAlgebra_symplectic(self) @@ -1032,6 +1037,11 @@ def symplectic(self): def orthogonal(self): """ The orthogonal basis of the symmetric functions. + + EXAMPLES:: + + sage: SymmetricFunctions(QQ).orthogonal() + Symmetric Functions over Rational Field in the orthogonal basis """ import orthogonal return orthogonal.SymmetricFunctionAlgebra_orthogonal(self) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index c99b2bd525f..2f1c7e1711f 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -335,7 +335,7 @@ class SymmetricFunctionsBases(Category_realization_of_parent): r""" The category of bases of the ring of symmetric functions. """ - def __init__(self, base): + def __init__(self, base, graded=True): r""" Initialize the bases of the ring of symmetric functions. @@ -343,6 +343,8 @@ def __init__(self, base): - ``self`` -- a category of bases for the symmetric functions - ``base`` -- ring of symmetric functions + - ``graded`` -- (default: ``True``) if ``True``, then the basis is + considered to be graded, otherwise it is considered to be filtered TESTS:: @@ -353,6 +355,7 @@ def __init__(self, base): sage: Sym.schur() in bases True """ + self._graded = graded Category_realization_of_parent.__init__(self, base) def _repr_(self): @@ -390,9 +393,13 @@ def super_categories(self): [Category of commutative graded hopf algebras with basis over Rational Field, Category of realizations of Symmetric Functions over Rational Field] """ - from sage.categories.all import CommutativeRings, GradedHopfAlgebrasWithBasis - return [GradedHopfAlgebrasWithBasis(self.base().base_ring()).Commutative(), - Realizations(self.base())] + from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis + cat = HopfAlgebrasWithBasis(self.base().base_ring()).Commutative() + if self._graded: + cat = cat.Graded() + else: + cat = cat.Filtered() + return [cat, Realizations(self.base())] class ParentMethods: @@ -1457,7 +1464,7 @@ class SymmetricFunctionAlgebra_generic(CombinatorialFreeModule): sage: s(m([2,1])) -2*s[1, 1, 1] + s[2, 1] """ - def __init__(self, Sym, basis_name = None, prefix = None): + def __init__(self, Sym, basis_name=None, prefix=None, graded=True): r""" Initializes the symmetric function algebra. @@ -1466,6 +1473,8 @@ def __init__(self, Sym, basis_name = None, prefix = None): - ``Sym`` -- the ring of symmetric functions - ``basis_name`` -- name of basis (default: ``None``) - ``prefix`` -- prefix used to display basis + - ``graded`` -- (default: ``True``) if ``True``, then the basis is + considered to be graded, otherwise the basis is filtered TESTS:: @@ -1490,8 +1499,8 @@ def __init__(self, Sym, basis_name = None, prefix = None): self._prefix = prefix self._sym = Sym CombinatorialFreeModule.__init__(self, Sym.base_ring(), _Partitions, - category = SymmetricFunctionsBases(Sym), - bracket = "", prefix = prefix) + category=SymmetricFunctionsBases(Sym, graded), + bracket="", prefix=prefix) _print_style = 'lex' diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index 4a975a6ed2c..58532997eb0 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -163,7 +163,8 @@ def __init__(self, Sym): sage: sp = SymmetricFunctions(QQ).sp() sage: TestSuite(sp).run() """ - sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "symplectic", 'sp') + sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "symplectic", + 'sp', graded=False) # Setup the coercions s = Sym.schur() From e79114af731f069c880a6d687953cd4586f07798 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 5 Oct 2015 22:53:33 -0500 Subject: [PATCH 1286/1872] First round of review changes. --- .../root_system/integrable_representations.py | 138 ++++++++++-------- 1 file changed, 78 insertions(+), 60 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 48e7cc24d0a..ebd2140573a 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -596,8 +596,8 @@ def to_dominant(self, n): def _freudenthal_roots_imaginary(self, nu): r""" - Return the set of imaginary roots `\alpha \in \Delta^+` in ``self`` - such that `\nu - \alpha \in Q^+`. + Iterate over the set of imaginary roots `\alpha \in \Delta^+` + in ``self`` such that `\nu - \alpha \in Q^+`. INPUT: @@ -607,21 +607,23 @@ def _freudenthal_roots_imaginary(self, nu): 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) + sage: [list(V._freudenthal_roots_imaginary(V.highest_weight() - mw)) ....: for mw in V.dominant_maximal_weights()] [[], [], [], [], []] """ l = self._from_weight_helper(nu) 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)] + for u in range(1, kp+1): + yield u * delta def _freudenthal_roots_real(self, nu): r""" - Return the set of real positive roots `\alpha \in \Delta^+` in - ``self`` such that `\nu - \alpha \in Q^+`. + Iterate over the set of real positive roots `\alpha \in \Delta^+` + in ``self`` such that `\nu - \alpha \in Q^+`. - See [Kac]_ Proposition 6.3 for the way to compute the set of real roots for twisted affine case. + See [Kac]_ Proposition 6.3 for the way to compute the set of real + roots for twisted affine case. INPUT: @@ -632,7 +634,7 @@ def _freudenthal_roots_real(self, nu): 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: list(V._freudenthal_roots_real(V.highest_weight() - mw)) [alpha[1], alpha[2], alpha[3], @@ -640,54 +642,70 @@ def _freudenthal_roots_real(self, nu): alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]] """ - ret = [] for al in self._classical_positive_roots: if all(x >= 0 for x in self._from_weight_helper(nu-al)): - ret.append(al) + yield al + + if self._cartan_type.is_untwisted_affine(): + # untwisted case + for al in self._classical_roots: + for ir in self._freudenthal_roots_imaginary(nu-al): + yield al+ir + return + from sage.combinat.root_system.cartan_type import CartanType - if self._cartan_type == CartanType(['B',self._classical_rank,1]).dual() or self._cartan_type == CartanType(['C',self._classical_rank,1]).dual() or self._cartan_type == CartanType(['F',4,1]).dual(): #case A^2_{2l-1} or case D^2_{l+1} or case E^2_6: + if self._cartan_type in [CartanType(['B',self._classical_rank,1]).dual(), + CartanType(['C',self._classical_rank,1]).dual(), + CartanType(['F',4,1]).dual()]: + #case A^2_{2l-1} or case D^2_{l+1} or case E^2_6: for al in self._classical_roots: if self._inner_qq(al,al) == 2: #if al is a short root: for ir in self._freudenthal_roots_imaginary(nu-al): - ret.append(al+ir) + yield al+ir else: - for ir in self._freudenthal_roots_imaginary(nu-al): - if 2*ir in self._freudenthal_roots_imaginary(nu-al): - ret.append(al+2*ir) + fri = list(self._freudenthal_roots_imaginary(nu-al)) + friset = set(fri) + for ir in fri: + if 2*ir in friset: + yield al+2*ir - elif self._cartan_type == CartanType(['BC',self._classical_rank,2]): #case A^2_{2l} + elif self._cartan_type == CartanType(['BC',self._classical_rank,2]): + #case A^2_{2l} + # We have to keep track of the roots we have visted for this case + ret = set(self._classical_positive_roots) for al in self._classical_roots: if self._inner_qq(al,al) == 2: #if al is a short root: for ir in self._freudenthal_roots_imaginary(nu-al): - ret.append(al+ir) + ret.add(al+ir) + yield al+ir else: - for ir in self._freudenthal_roots_imaginary(nu-al): - if 2*ir in self._freudenthal_roots_imaginary(nu-al): - ret.append(al+2*ir) - for ir in self._freudenthal_roots_imaginary(2*nu-al)[::2]: + fri = list(self._freudenthal_roots_imaginary(nu-al)) + friset = set(fri) + for ir in fri: + if 2*ir in friset: + ret.add(al+2*ir) + yield al+2*ir + alpha = self._Q.simple_roots() + fri = list(self._freudenthal_roots_imaginary(2*nu-al)) + for ir in fri[::2]: n = [x//2 for x in self._from_weight_helper(al+ir)] - alpha = self._Q.simple_roots() - if sum([val*alpha[i] for i,val in enumerate(n)]) not in ret: - ret.append(sum([val*alpha[i] for i,val in enumerate(n)])) + if sum(val*alpha[i] for i,val in enumerate(n)) not in ret: + rt = sum(val*alpha[i] for i,val in enumerate(n)) + ret.add(rt) + yield rt - elif self._cartan_type == CartanType(['D',4,3]) or self._cartan_type == CartanType(['G',2,1]).dual(): # case D^3_4 in the Kac notation + elif self._cartan_type in [CartanType(['D',4,3]), CartanType(['G',2,1]).dual()]: + # case D^3_4 in the Kac notation for al in self._classical_roots: if self._inner_qq(al,al) == 2: #if al is a short root: for ir in self._freudenthal_roots_imaginary(nu-al): - ret.append(al+ir) + yield al+ir else: - for ir in self._freudenthal_roots_imaginary(nu-al): - if 3*ir in self._freudenthal_roots_imaginary(nu-al): - ret.append(al+3*ir) - - - else: # untwisted case - for al in self._classical_roots: - for ir in self._freudenthal_roots_imaginary(nu-al): - ret.append(al+ir) - - - return ret + fri = list(self._freudenthal_roots_imaginary(nu-al)) + friset = set(fri) + for ir in fri: + if 3*ir in friset: + yield al+3*ir def _freudenthal_accum(self, nu, al): """ @@ -750,10 +768,14 @@ def _m_freudenthal(self, n): from sage.combinat.root_system.cartan_type import CartanType - if self._cartan_type == CartanType(['B',self._classical_rank,1]).dual(): - list = self._freudenthal_roots_imaginary(self._Lam - mu) - dict = {key:list[key-1] for key in range(1,len(list)+1)} - for k in dict: # k is a positive number, dict[k] is k*delta + if self._cartan_type.is_untwisted_affine(): + for al in self._freudenthal_roots_imaginary(self._Lam - mu): + num += self._classical_rank * self._freudenthal_accum(mu, al) + + elif self._cartan_type == CartanType(['B',self._classical_rank,1]).dual(): + d = {key+1: rt for key, rt in + enumerate(self._freudenthal_roots_imaginary(self._Lam - mu))} + for k in d: # k is a positive number, d[k] is k*delta num += (self._classical_rank-k%2) * self._freudenthal_accum(mu, dict[k]) elif self._cartan_type == CartanType(['BC',self._classical_rank,2]): @@ -761,29 +783,25 @@ def _m_freudenthal(self, n): num += self._classical_rank * self._freudenthal_accum(mu, al) elif self._cartan_type == CartanType(['C',self._classical_rank,1]).dual(): - list = self._freudenthal_roots_imaginary(self._Lam - mu) - dict = {key:list[key-1] for key in range(1,len(list)+1)} - for k in dict: # k is a positive number, dict[k] is k*delta - num += (self._classical_rank-(self._classical_rank -1)*(k%2)) * self._freudenthal_accum(mu, dict[k]) + d = {key+1: rt for key, rt in + enumerate(self._freudenthal_roots_imaginary(self._Lam - mu))} + for k in d: # k is a positive number, d[k] is k*delta + num += (self._classical_rank-(self._classical_rank -1)*(k%2)) * self._freudenthal_accum(mu, d[k]) elif self._cartan_type == CartanType(['F',4,1]).dual(): - list = self._freudenthal_roots_imaginary(self._Lam - mu) - dict = {key:list[key-1] for key in range(1,len(list)+1)} - for k in dict: # k is a positive number, dict[k] is k*delta - num += (4 - 2*(k%2)) * self._freudenthal_accum(mu, dict[k]) + d = {key+1: rt for key, rt in + enumerate(self._freudenthal_roots_imaginary(self._Lam - mu))} + for k in d: # k is a positive number, d[k] is k*delta + num += (4 - 2*(k%2)) * self._freudenthal_accum(mu, d[k]) - elif self._cartan_type == CartanType(['D',4,3]) or self._cartan_type == CartanType(['G',2,1]).dual(): - list = self._freudenthal_roots_imaginary(self._Lam - mu) - dict = {key:list[key-1] for key in range(1,len(list)+1)} - for k in dict: # k is a positive number, dict[k] is k*delta + elif self._cartan_type in [CartanType(['D',4,3]), CartanType(['G',2,1]).dual()]: + d = {key+1: rt for key, rt in + enumerate(self._freudenthal_roots_imaginary(self._Lam - mu))} + for k in d: # k is a positive number, d[k] is k*delta if k%3 == 0: - num += 2 * self._freudenthal_accum(mu, dict[k]) + num += 2 * self._freudenthal_accum(mu, d[k]) else: - num += self._freudenthal_accum(mu, dict[k]) - - else: - for al in self._freudenthal_roots_imaginary(self._Lam - mu): - num += self._classical_rank * self._freudenthal_accum(mu, al) + num += self._freudenthal_accum(mu, d[k]) try: return ZZ(num / den) From 3966f09d89f5d0c66eb6f803f1a91efd3e0bd979 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 5 Oct 2015 23:30:04 -0500 Subject: [PATCH 1287/1872] Getting some more speed and minor refactoring to improve readability/memory. --- .../root_system/integrable_representations.py | 163 +++++++++--------- 1 file changed, 83 insertions(+), 80 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index ebd2140573a..14e3386db3d 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -193,6 +193,9 @@ def __init__(self, Lam): self._P = Lam.parent() self._Q = self._P.root_system.root_lattice() + # Store some extra simple computations that appear in tight loops + self._Lam_rho = self._Lam + self._P.rho() + self._cartan_matrix = self._P.root_system.cartan_matrix() self._cartan_type = self._P.root_system.cartan_type() @@ -212,11 +215,14 @@ def __init__(self, Lam): 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() + # Extra data for the twisted cases + if not self._cartan_type.is_untwisted_affine(): + self._classical_short_roots = frozenset(al for al in self._classical_roots + if self._inner_qq(al,al) == 2) + def highest_weight(self): """ Returns the highest weight of ``self``. @@ -269,6 +275,7 @@ def level(self): """ return ZZ(self._inner_pq(self._Lam, self._Q.null_root())) + @cached_method def coxeter_number(self): """ Return the Coxeter number of the Cartan type of ``self``. @@ -283,8 +290,9 @@ def coxeter_number(self): sage: V.coxeter_number() 12 """ - return self._coxeter_number + return sum(self._a) + @cached_method def dual_coxeter_number(self): r""" Return the dual Coxeter number of the Cartan type of ``self``. @@ -299,7 +307,7 @@ def dual_coxeter_number(self): sage: V.dual_coxeter_number() 9 """ - return self._dual_coxeter_number + return sum(self._ac) def _repr_(self): """ @@ -643,69 +651,65 @@ def _freudenthal_roots_real(self, nu): alpha[1] + alpha[2] + alpha[3]] """ for al in self._classical_positive_roots: - if all(x >= 0 for x in self._from_weight_helper(nu-al)): + if min(self._from_weight_helper(nu-al)) >= 0: yield al if self._cartan_type.is_untwisted_affine(): # untwisted case for al in self._classical_roots: for ir in self._freudenthal_roots_imaginary(nu-al): - yield al+ir - return - - from sage.combinat.root_system.cartan_type import CartanType - if self._cartan_type in [CartanType(['B',self._classical_rank,1]).dual(), - CartanType(['C',self._classical_rank,1]).dual(), - CartanType(['F',4,1]).dual()]: - #case A^2_{2l-1} or case D^2_{l+1} or case E^2_6: - for al in self._classical_roots: - if self._inner_qq(al,al) == 2: #if al is a short root: - for ir in self._freudenthal_roots_imaginary(nu-al): - yield al+ir - else: - fri = list(self._freudenthal_roots_imaginary(nu-al)) - friset = set(fri) - for ir in fri: - if 2*ir in friset: - yield al+2*ir + yield al + ir - elif self._cartan_type == CartanType(['BC',self._classical_rank,2]): + elif self._cartan_type.type() == 'BC': #case A^2_{2l} # We have to keep track of the roots we have visted for this case ret = set(self._classical_positive_roots) for al in self._classical_roots: - if self._inner_qq(al,al) == 2: #if al is a short root: + if al in self._classical_short_roots: for ir in self._freudenthal_roots_imaginary(nu-al): - ret.add(al+ir) - yield al+ir + ret.add(al + ir) + yield al + ir else: fri = list(self._freudenthal_roots_imaginary(nu-al)) friset = set(fri) for ir in fri: if 2*ir in friset: - ret.add(al+2*ir) - yield al+2*ir + ret.add(al + 2*ir) + yield al + 2*ir alpha = self._Q.simple_roots() fri = list(self._freudenthal_roots_imaginary(2*nu-al)) for ir in fri[::2]: - n = [x//2 for x in self._from_weight_helper(al+ir)] - if sum(val*alpha[i] for i,val in enumerate(n)) not in ret: - rt = sum(val*alpha[i] for i,val in enumerate(n)) + rt = sum( val // 2 * alpha[i] for i,val in + enumerate(self._from_weight_helper(al+ir)) ) + if rt not in ret: ret.add(rt) yield rt - elif self._cartan_type in [CartanType(['D',4,3]), CartanType(['G',2,1]).dual()]: + elif self._cartan_type.dual().type() == 'G': # case D^3_4 in the Kac notation for al in self._classical_roots: - if self._inner_qq(al,al) == 2: #if al is a short root: + if al in self._classical_short_roots: for ir in self._freudenthal_roots_imaginary(nu-al): - yield al+ir + yield al + ir else: fri = list(self._freudenthal_roots_imaginary(nu-al)) friset = set(fri) for ir in fri: if 3*ir in friset: - yield al+3*ir + yield al + 3*ir + + elif self._cartan_type.dual().type() in ['B','C','F']: + #case A^2_{2l-1} or case D^2_{l+1} or case E^2_6: + for al in self._classical_roots: + if al in self._classical_short_roots: + for ir in self._freudenthal_roots_imaginary(nu-al): + yield al + ir + else: + fri = list(self._freudenthal_roots_imaginary(nu-al)) + friset = set(fri) + for ir in fri: + if 2*ir in friset: + yield al + 2*ir def _freudenthal_accum(self, nu, al): """ @@ -726,20 +730,20 @@ def _freudenthal_accum(self, nu, al): n_shift = self._from_weight_helper(al) ip_shift = self._inner_qq(al, al) - while all(val >= 0 for val in n): + while min(n) >= 0: # 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 + ret += 2 * self.m(tuple(n)) * ip return ret def _m_freudenthal(self, n): - """ + r""" Compute the weight multiplicity using the Freudenthal multiplicity formula in ``self``. + The multiplicities of the imaginary roots for the twisted affine case are different than those for the untwisted case. See [Carter]_ Corollary 18.10 for general type and Corollary @@ -760,49 +764,48 @@ 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) - num = 0 - - for al in self._freudenthal_roots_real(self._Lam - mu): - num += self._freudenthal_accum(mu, al) - - from sage.combinat.root_system.cartan_type import CartanType + cr = self._classical_rank + num = sum(self._freudenthal_accum(mu, alr) + for alr in self._freudenthal_roots_real(self._Lam - mu)) if self._cartan_type.is_untwisted_affine(): - for al in self._freudenthal_roots_imaginary(self._Lam - mu): - num += self._classical_rank * self._freudenthal_accum(mu, al) - - elif self._cartan_type == CartanType(['B',self._classical_rank,1]).dual(): - d = {key+1: rt for key, rt in - enumerate(self._freudenthal_roots_imaginary(self._Lam - mu))} - for k in d: # k is a positive number, d[k] is k*delta - num += (self._classical_rank-k%2) * self._freudenthal_accum(mu, dict[k]) - - elif self._cartan_type == CartanType(['BC',self._classical_rank,2]): - for al in self._freudenthal_roots_imaginary(self._Lam - mu): - num += self._classical_rank * self._freudenthal_accum(mu, al) - - elif self._cartan_type == CartanType(['C',self._classical_rank,1]).dual(): - d = {key+1: rt for key, rt in - enumerate(self._freudenthal_roots_imaginary(self._Lam - mu))} - for k in d: # k is a positive number, d[k] is k*delta - num += (self._classical_rank-(self._classical_rank -1)*(k%2)) * self._freudenthal_accum(mu, d[k]) - - elif self._cartan_type == CartanType(['F',4,1]).dual(): - d = {key+1: rt for key, rt in - enumerate(self._freudenthal_roots_imaginary(self._Lam - mu))} - for k in d: # k is a positive number, d[k] is k*delta - num += (4 - 2*(k%2)) * self._freudenthal_accum(mu, d[k]) + num += sum(cr * self._freudenthal_accum(mu, alr) + for alr in self._freudenthal_roots_imaginary(self._Lam - mu)) + + elif self._cartan_type.dual().type() == 'B': # A_{2n-1}^{(2)} + val = 1 + for rt in self._freudenthal_roots_imaginary(self._Lam - mu): + # k-th element (starting from 1) is k*delta + num += (cr - val) * self._freudenthal_accum(mu, rt) + val = 1 - val + + elif self._cartan_type.type() == 'BC': # A_{2n}^{(2)} + num += sum(cr * self._freudenthal_accum(mu, alr) + for alr in self._freudenthal_roots_imaginary(self._Lam - mu)) + + elif self._cartan_type.dual() == 'C': # D_{n+1}^{(2)} + val = 1 + for rt in self._freudenthal_roots_imaginary(self._Lam - mu): + # k-th element (starting from 1) is k*delta + num += (cr - (cr - 1)*val) * self._freudenthal_accum(mu, rt) + val = 1 - val + + elif self._cartan_type.dual().type() == 'F': # E_6^{(2)} + val = 1 + for rt in self._freudenthal_roots_imaginary(self._Lam - mu): + # k-th element (starting from 1) is k*delta + num += (4 - 2*val) * self._freudenthal_accum(mu, rt) + val = 1 - val - elif self._cartan_type in [CartanType(['D',4,3]), CartanType(['G',2,1]).dual()]: - d = {key+1: rt for key, rt in - enumerate(self._freudenthal_roots_imaginary(self._Lam - mu))} - for k in d: # k is a positive number, d[k] is k*delta - if k%3 == 0: - num += 2 * self._freudenthal_accum(mu, d[k]) + elif self._cartan_type.dual().type() == 'G': # D_4^{(3)} (or dual of G_2^{(1)}) + for k,rt in enumerate(self._freudenthal_roots_imaginary(self._Lam - mu)): + # k-th element (starting from 1) is k*delta + if (k+1) % 3 == 0: + num += 2 * self._freudenthal_accum(mu, rt) else: - num += self._freudenthal_accum(mu, d[k]) + num += self._freudenthal_accum(mu, rt) + den = 2*self._inner_pq(self._Lam_rho, al) - self._inner_qq(al, al) try: return ZZ(num / den) except TypeError: @@ -999,9 +1002,9 @@ def modular_characteristic(self, mu=None): else: n = self.from_weight(mu) k = self.level() - hd = self._dual_coxeter_number + hd = self.dual_coxeter_number() rho = self._P.rho() - m_Lambda = self._inner_pp(self._Lam+rho, self._Lam+rho) / (2*(k+hd)) \ + 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 From 7f3c0b9385b1c1353e04ffe8775eb7e546bac3c3 Mon Sep 17 00:00:00 2001 From: Michele Borassi Date: Tue, 6 Oct 2015 09:40:52 +0200 Subject: [PATCH 1288/1872] Use list instead of dict --- src/sage/graphs/base/boost_graph.pyx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index a68db5dcc73..02e6ebe9e81 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -180,7 +180,7 @@ cpdef edge_connectivity(g): # These variables are automatically deleted when the function terminates. cdef BoostVecGraph g_boost_und cdef BoostVecDiGraph g_boost_dir - cdef dict int_to_vertex = {i:v for i,v in enumerate(g.vertices())} + cdef list int_to_vertex = g.vertices() if isinstance(g, Graph): boost_graph_from_sage_graph(&g_boost_und, g) @@ -404,7 +404,7 @@ cpdef dominator_tree(g, root, return_dict = False): cdef BoostVecDiGraph g_boost_dir cdef vector[v_index] result cdef dict vertex_to_int = {v:i for i,v in enumerate(g.vertices())} - cdef dict int_to_vertex = {i:v for i,v in enumerate(g.vertices())} + cdef list int_to_vertex = g.vertices() if isinstance(g, Graph): boost_graph_from_sage_graph(&g_boost_und, g) @@ -421,7 +421,7 @@ cpdef dominator_tree(g, root, return_dict = False): if return_dict: return {v:(None if result[vertex_to_int[v]] == no_parent else int_to_vertex[ result[vertex_to_int[v]]]) for v in g.vertices()}; - edges = [[int_to_vertex[result[vertex_to_int[v]]], v] for v in g.vertices() if result[vertex_to_int[v]] != no_parent] + edges = [[int_to_vertex[ result[vertex_to_int[v]]], v] for v in g.vertices() if result[vertex_to_int[v]] != no_parent] if g.is_directed(): if len(edges) == 0: @@ -530,17 +530,17 @@ cpdef bandwidth_heuristics(g, algorithm = 'cuthill_mckee'): cdef BoostVecGraph g_boost cdef vector[v_index] result cdef dict vertex_to_int = {v:i for i,v in enumerate(g.vertices())} - cdef dict int_to_vertex = {i:v for i,v in enumerate(g.vertices())} + cdef list int_to_vertex = g.vertices() boost_graph_from_sage_graph(&g_boost, g) result = g_boost.bandwidth_ordering(algorithm=='cuthill_mckee') cdef int n = g.num_verts() - cdef dict pos = {int_to_vertex[result[i]]:i for i in range(n)} + cdef dict pos = {int_to_vertex[ result[i]]:i for i in range(n)} cdef int bandwidth = max([abs(pos[u]-pos[v]) for u,v in g.edges(labels=False)]) sig_off() - return (bandwidth, [int_to_vertex[result[i]] for i in range(n)]) + return (bandwidth, [int_to_vertex[ result[i]] for i in range(n)]) cpdef min_spanning_tree(g, weight_function=None, @@ -638,7 +638,7 @@ cpdef min_spanning_tree(g, cdef BoostVecWeightedGraph g_boost cdef vector[v_index] result cdef dict vertex_to_int = {v:i for i,v in enumerate(g.vertices())} - cdef dict int_to_vertex = {i:v for i,v in enumerate(g.vertices())} + cdef list int_to_vertex = g.vertices() try: boost_weighted_graph_from_sage_graph(&g_boost, g, weight_function) @@ -657,7 +657,7 @@ cpdef min_spanning_tree(g, if result.size() != 2 * (n - 1): return [] else: - edges = [(int_to_vertex[result[2*i]], int_to_vertex[result[2*i+1]]) for i in range(n-1)] + edges = [(int_to_vertex[ result[2*i]], int_to_vertex[ result[2*i+1]]) for i in range(n-1)] return sorted([(min(e[0],e[1]), max(e[0],e[1]), g.edge_label(e[0], e[1])) for e in edges]) From f84f27425b68b38859c24ce727397372833636de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 6 Oct 2015 10:03:34 +0200 Subject: [PATCH 1289/1872] trac #19284 correct typo in nonzero method --- src/sage/interfaces/octave.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index bb1fe260ab4..c599690cfc3 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -576,7 +576,7 @@ def _get_sage_ring(self): def __nonzero__(self): r""" - Test whether this element is zero. + Test whether this element is nonzero. EXAMPLES:: From 2049f5a4f3143479395827f1ab82c0a0b39089bc Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 6 Oct 2015 09:54:07 +0200 Subject: [PATCH 1290/1872] Move refine_root() to refine_root.pyx --- .../polynomial_rings_univar.rst | 1 + src/module_list.py | 4 + src/sage/rings/polynomial/complex_roots.py | 129 ++-------------- src/sage/rings/polynomial/refine_root.pyx | 141 ++++++++++++++++++ 4 files changed, 159 insertions(+), 116 deletions(-) create mode 100644 src/sage/rings/polynomial/refine_root.pyx 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 d84fd747804..bd55ed8b014 100644 --- a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst +++ b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst @@ -35,6 +35,7 @@ whereas others have multiple bases. sage/rings/polynomial/real_roots sage/rings/polynomial/complex_roots + sage/rings/polynomial/refine_root sage/rings/polynomial/ideal sage/rings/polynomial/polynomial_quotient_ring diff --git a/src/module_list.py b/src/module_list.py index 7108872b586..d0a48218689 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1570,6 +1570,10 @@ def uname_specific(name, value, alternative): sources = ['sage/rings/polynomial/real_roots.pyx'], libraries=['mpfr']), + Extension('sage.rings.polynomial.refine_root', + sources = ['sage/rings/polynomial/refine_root.pyx'], + libraries=['gmp', 'mpfr', 'mpfi']), + Extension('sage.rings.polynomial.symmetric_reduction', sources = ['sage/rings/polynomial/symmetric_reduction.pyx']), diff --git a/src/sage/rings/polynomial/complex_roots.py b/src/sage/rings/polynomial/complex_roots.py index 5056ea53222..42432118f68 100644 --- a/src/sage/rings/polynomial/complex_roots.py +++ b/src/sage/rings/polynomial/complex_roots.py @@ -24,128 +24,25 @@ [(1.167303978261419?, 1), (-0.764884433600585? - 0.352471546031727?*I, 1), (-0.764884433600585? + 0.352471546031727?*I, 1), (0.181232444469876? - 1.083954101317711?*I, 1), (0.181232444469876? + 1.083954101317711?*I, 1)] """ +#***************************************************************************** +# Copyright (C) 2007 Carl Witty +# +# 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 copy import copy -from sage.rings.real_mpfi import RealIntervalField from sage.rings.complex_field import ComplexField from sage.rings.complex_interval_field import ComplexIntervalField from sage.rings.qqbar import AA, QQbar from sage.rings.arith import sort_complex_numbers_for_display +from sage.rings.polynomial.refine_root import refine_root -def refine_root(ip, ipd, irt, fld): - """ - We are given a polynomial and its derivative (with complex - interval coefficients), an estimated root, and a complex interval - field to use in computations. We use interval arithmetic to - refine the root and prove that we have in fact isolated a unique - root. - - If we succeed, we return the isolated root; if we fail, we return - None. - - EXAMPLES:: - - sage: from sage.rings.polynomial.complex_roots import * - sage: x = polygen(ZZ) - sage: p = x^9 - 1 - sage: ip = CIF['x'](p); ip - x^9 - 1 - sage: ipd = CIF['x'](p.derivative()); ipd - 9*x^8 - sage: irt = CIF(CC(cos(2*pi/9), sin(2*pi/9))); irt - 0.76604444311897802? + 0.64278760968653926?*I - sage: ip(irt) - 0.?e-14 + 0.?e-14*I - sage: ipd(irt) - 6.89439998807080? - 5.78508848717885?*I - sage: refine_root(ip, ipd, irt, CIF) - 0.766044443118978? + 0.642787609686540?*I - """ - - # There has got to be a better way to do this, but I don't know - # what it is... - - # We start with a basic fact: if we do an interval Newton-Raphson - # step, and the refined interval is contained in the original interval, - # then the refined interval contains exactly one root. - - # Unfortunately, our initial estimated root almost certainly does not - # contain the actual root (our initial interval is a point, which - # is exactly equal to whatever floating-point estimate we got from - # the external solver). So we need to do multiple Newton-Raphson - # steps, and check this inclusion property on each step. - - # After a few steps of refinement, if the initial root estimate was - # close to a root, we should have an essentially perfect interval - # bound on the root (since Newton-Raphson has quadratic convergence), - # unless either the real or imaginary component of the root is zero. - # If the real or imaginary component is zero, then we could spend - # a long time computing closer and closer approximations to that - # component. (This doesn't happen for non-zero components, because - # of the imprecision of floating-point numbers combined with the - # outward interval rounding; but close to zero, MPFI provides - # extremely precise numbers.) - - # If the root is actually a real root, but we start with an imaginary - # component, we can bounce back and forth between having a positive - # and negative imaginary component, without ever hitting zero. - # To deal with this, on every other Newton-Raphson step, instead of - # replacing the old interval with the new one, we take the union. - - # If the containment check continues to fail many times in a row, - # we give up and return None; we also return None if we detect - # that the slope in our current interval is not bounded away - # from zero at any step. - - # After every refinement step, we check to see if the real or - # imaginary component of our interval includes zero. If so, we - # try setting it to exactly zero. This gives us a good chance of - # detecting real roots. However, we do this replacement at most - # once per component. - - refinement_steps = 10 - - smashed_real = False - smashed_imag = False - - for i in range(refinement_steps): - slope = ipd(irt) - if slope.contains_zero(): - return None - center = fld(irt.center()) - val = ip(center) - - nirt = center - val / slope - # print irt, nirt, (nirt in irt), nirt.diameter(), irt.diameter(), center, val, slope - if nirt in irt and (nirt.diameter() >= irt.diameter() >> 3 or i >= 8): - # If the new diameter is much less than the original diameter, - # then we have not yet converged. (Perhaps we were asked - # for a particularly high-precision result.) So we don't - # return yet. - return nirt - - if i & 1: - irt = nirt - else: - irt = irt.union(nirt) - # If we don't find a root after a while, try (approximately) - # tripling the size of the region. - if i >= 6: - rD = irt.real().absolute_diameter() - iD = irt.imag().absolute_diameter() - md = max(rD, iD) - md_intv = RealIntervalField(rD.prec())(-md, md) - md_cintv = ComplexIntervalField(rD.prec())(md_intv, md_intv) - irt = irt + md_cintv - - if not smashed_real and irt.real().contains_zero(): - irt = irt.parent()(0, irt.imag()) - smashed_real = True - if not smashed_imag and irt.imag().contains_zero(): - irt = irt.parent()(irt.real(), 0) - smashed_imag = True - - return None def interval_roots(p, rts, prec): """ @@ -335,7 +232,7 @@ def complex_roots(p, skip_squarefree=False, retval='interval', min_prec=0): TESTS: - Verify that trac 12026 is fixed:: + Verify that :trac:`12026` is fixed:: sage: f = matrix(QQ, 8, lambda i, j: 1/(i + j + 1)).charpoly() sage: from sage.rings.polynomial.complex_roots import complex_roots diff --git a/src/sage/rings/polynomial/refine_root.pyx b/src/sage/rings/polynomial/refine_root.pyx new file mode 100644 index 00000000000..aafbeb442f3 --- /dev/null +++ b/src/sage/rings/polynomial/refine_root.pyx @@ -0,0 +1,141 @@ +""" +Refine polynomial roots using Newton--Raphson + +This is an implementation of the Newton--Raphson algorithm to +approximate roots of complex polynomials. The implementation +is based on interval arithmetic + +AUTHORS: + +- Carl Witty (2007-11-18): initial version +""" + +#***************************************************************************** +# Copyright (C) 2007 Carl Witty +# +# 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.real_mpfi import RealIntervalField +from sage.rings.complex_interval_field import ComplexIntervalField + + +def refine_root(ip, ipd, irt, fld): + """ + We are given a polynomial and its derivative (with complex + interval coefficients), an estimated root, and a complex interval + field to use in computations. We use interval arithmetic to + refine the root and prove that we have in fact isolated a unique + root. + + If we succeed, we return the isolated root; if we fail, we return + None. + + EXAMPLES:: + + sage: from sage.rings.polynomial.refine_root import refine_root + sage: x = polygen(ZZ) + sage: p = x^9 - 1 + sage: ip = CIF['x'](p); ip + x^9 - 1 + sage: ipd = CIF['x'](p.derivative()); ipd + 9*x^8 + sage: irt = CIF(CC(cos(2*pi/9), sin(2*pi/9))); irt + 0.76604444311897802? + 0.64278760968653926?*I + sage: ip(irt) + 0.?e-14 + 0.?e-14*I + sage: ipd(irt) + 6.89439998807080? - 5.78508848717885?*I + sage: refine_root(ip, ipd, irt, CIF) + 0.766044443118978? + 0.642787609686540?*I + """ + + # There has got to be a better way to do this, but I don't know + # what it is... + + # We start with a basic fact: if we do an interval Newton-Raphson + # step, and the refined interval is contained in the original interval, + # then the refined interval contains exactly one root. + + # Unfortunately, our initial estimated root almost certainly does not + # contain the actual root (our initial interval is a point, which + # is exactly equal to whatever floating-point estimate we got from + # the external solver). So we need to do multiple Newton-Raphson + # steps, and check this inclusion property on each step. + + # After a few steps of refinement, if the initial root estimate was + # close to a root, we should have an essentially perfect interval + # bound on the root (since Newton-Raphson has quadratic convergence), + # unless either the real or imaginary component of the root is zero. + # If the real or imaginary component is zero, then we could spend + # a long time computing closer and closer approximations to that + # component. (This doesn't happen for non-zero components, because + # of the imprecision of floating-point numbers combined with the + # outward interval rounding; but close to zero, MPFI provides + # extremely precise numbers.) + + # If the root is actually a real root, but we start with an imaginary + # component, we can bounce back and forth between having a positive + # and negative imaginary component, without ever hitting zero. + # To deal with this, on every other Newton-Raphson step, instead of + # replacing the old interval with the new one, we take the union. + + # If the containment check continues to fail many times in a row, + # we give up and return None; we also return None if we detect + # that the slope in our current interval is not bounded away + # from zero at any step. + + # After every refinement step, we check to see if the real or + # imaginary component of our interval includes zero. If so, we + # try setting it to exactly zero. This gives us a good chance of + # detecting real roots. However, we do this replacement at most + # once per component. + + refinement_steps = 10 + + smashed_real = False + smashed_imag = False + + for i in range(refinement_steps): + slope = ipd(irt) + if slope.contains_zero(): + return None + center = fld(irt.center()) + val = ip(center) + + nirt = center - val / slope + # print irt, nirt, (nirt in irt), nirt.diameter(), irt.diameter(), center, val, slope + if nirt in irt and (nirt.diameter() >= irt.diameter() >> 3 or i >= 8): + # If the new diameter is much less than the original diameter, + # then we have not yet converged. (Perhaps we were asked + # for a particularly high-precision result.) So we don't + # return yet. + return nirt + + if i & 1: + irt = nirt + else: + irt = irt.union(nirt) + # If we don't find a root after a while, try (approximately) + # tripling the size of the region. + if i >= 6: + rD = irt.real().absolute_diameter() + iD = irt.imag().absolute_diameter() + md = max(rD, iD) + md_intv = RealIntervalField(rD.prec())(-md, md) + md_cintv = ComplexIntervalField(rD.prec())(md_intv, md_intv) + irt = irt + md_cintv + + if not smashed_real and irt.real().contains_zero(): + irt = irt.parent()(0, irt.imag()) + smashed_real = True + if not smashed_imag and irt.imag().contains_zero(): + irt = irt.parent()(irt.real(), 0) + smashed_imag = True + + return None From b2d69199df517b6b104f920fc699fdf47d83b678 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 6 Oct 2015 09:38:08 -0400 Subject: [PATCH 1291/1872] removed target_basis as a method (not used), doc changes, TestSuite doc tests --- src/sage/combinat/sf/character.py | 36 +++++++++++-------------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index d8eb03a04b2..1a2ccd2ce56 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -80,11 +80,11 @@ def _other_to_self(self, sexpr): We use triangularity to determine the expansion by subtracting off the leading term. The target basis - is specified by the method ``self.target_basis()``. + is specified by the method ``self._other``. INPUT: - - ``sexpr`` -- an element of ``self.target_basis()`` basis + - ``sexpr`` -- an element of ``self._other`` basis EXAMPLES:: @@ -179,6 +179,7 @@ def __init__(self, Sym, other_basis, bname, pfix): Symmetric Functions over Rational Field in the induced trivial character basis sage: st = SymmetricFunctions(QQ).st(); st Symmetric Functions over Rational Field in the irreducible symmetric group character basis + sage: TestSuite(ht).run() """ SFA_generic.__init__(self, Sym, basis_name=bname, prefix=pfix) self._other = other_basis @@ -191,27 +192,10 @@ def __init__(self, Sym, other_basis, bname, pfix): self.register_coercion( SetMorphism(Hom(self._other, self, categ), self._other_to_self)) - def target_basis(self): - r""" - Return the basis that was passed as the ``other_basis`` - in the intialization. - - EXAMPLES:: - - sage: Sym = SymmetricFunctions(QQ) - sage: ht = SymmetricFunctions(QQ).ht() - sage: st = SymmetricFunctions(QQ).st() - sage: ht.target_basis() - Symmetric Functions over Rational Field in the homogeneous basis - sage: st.target_basis() - Symmetric Functions over Rational Field in the Schur basis - """ - return self._other - @cached_method def _self_to_other_on_basis(self, lam): r""" - Convert a character-basis element to the ``self.target_basis()`` basis + Convert a character-basis element to the ``self._other`` basis This is a recursive procedure that is calculated by the assumption that the leading term of ``self(lam)`` @@ -223,7 +207,7 @@ def _self_to_other_on_basis(self, lam): OUTPUT: - - an expression in the ``self.target_basis()`` basis + - an expression in the ``self._other`` basis EXAMPLES:: @@ -276,6 +260,7 @@ class irreducible_character_basis(generic_character): st[1] + st[1, 1] + st[2] + st[2, 1] + st[3] sage: s[4,2].kronecker_product(s[5,1]) s[3, 2, 1] + s[3, 3] + s[4, 1, 1] + s[4, 2] + s[5, 1] + sage: TestSuite(st).run() """ def __init__(self, Sym, pfix): r""" @@ -292,12 +277,15 @@ def __init__(self, Sym, pfix): sage: Sym = SymmetricFunctions(QQ) sage: ht = SymmetricFunctions(QQ).ht(); ht - Symmetric Functions over Rational Field in the induced trivial character basis + Symmetric Functions over Rational Field in the induced trivial + character basis sage: st = SymmetricFunctions(QQ).st(); st - Symmetric Functions over Rational Field in the irreducible symmetric group character basis + Symmetric Functions over Rational Field in the irreducible + symmetric group character basis """ SFA_generic.__init__(self, Sym, \ - basis_name="irreducible symmetric group character", prefix=pfix) + basis_name="irreducible symmetric group character", \ + prefix=pfix) self._other = Sym.Schur() self._p = Sym.powersum() from sage.categories.graded_hopf_algebras_with_basis \ From 75b2f438073042e310adbcaea224959ba5f2105f Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 6 Oct 2015 10:20:58 -0400 Subject: [PATCH 1292/1872] Trac #19332: Return a cached tuple from discrete_complementarity_set(). This method takes a while to compute, so it makes sense to cache the output. Since it will be cached, an immutable tuple makes more sense as a return value than a mutable list. --- src/sage/geometry/cone.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index f9768c96406..d16221a6962 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -4348,6 +4348,7 @@ def lineality(self): """ return self.linear_subspace().dimension() + @cached_method def discrete_complementarity_set(self): r""" Compute a discrete complementarity set of this cone. @@ -4360,7 +4361,7 @@ def discrete_complementarity_set(self): OUTPUT: - A list of pairs `(x,s)` such that, + A tuple of pairs `(x,s)` such that, * `x` and `s` are nonzero. * `x` and `s` are orthogonal. @@ -4380,7 +4381,7 @@ def discrete_complementarity_set(self): sage: K = Cone([(1,0),(0,1)]) sage: K.discrete_complementarity_set() - [(N(1, 0), M(0, 1)), (N(0, 1), M(1, 0))] + ((N(1, 0), M(0, 1)), (N(0, 1), M(1, 0))) If a cone consists of a single ray, then the second components of a discrete complementarity set for that cone should generate @@ -4388,13 +4389,13 @@ def discrete_complementarity_set(self): sage: K = Cone([(1,0)]) sage: K.discrete_complementarity_set() - [(N(1, 0), M(0, 1)), (N(1, 0), M(0, -1))] + ((N(1, 0), M(0, 1)), (N(1, 0), M(0, -1))) sage: K = Cone([(1,0,0)]) sage: K.discrete_complementarity_set() - [(N(1, 0, 0), M(0, 1, 0)), + ((N(1, 0, 0), M(0, 1, 0)), (N(1, 0, 0), M(0, -1, 0)), (N(1, 0, 0), M(0, 0, 1)), - (N(1, 0, 0), M(0, 0, -1))] + (N(1, 0, 0), M(0, 0, -1))) When a cone is the entire space, its dual is the trivial cone, so the only discrete complementarity set for it is empty:: @@ -4403,14 +4404,14 @@ def discrete_complementarity_set(self): sage: K.is_full_space() True sage: K.discrete_complementarity_set() - [] + () Likewise for trivial cones, whose duals are the entire space:: sage: L = ToricLattice(0) sage: K = Cone([], ToricLattice(0)) sage: K.discrete_complementarity_set() - [] + () TESTS: @@ -4421,7 +4422,7 @@ def discrete_complementarity_set(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=6) sage: dcs_dual = K.dual().discrete_complementarity_set() - sage: expected = [ (x,s) for (s,x) in dcs_dual ] + sage: expected = tuple( (x,s) for (s,x) in dcs_dual ) sage: actual = K.discrete_complementarity_set() sage: sorted(actual) == sorted(expected) True @@ -4435,9 +4436,11 @@ def discrete_complementarity_set(self): sage: sum([ x.inner_product(s).abs() for (x,s) in dcs ]) 0 """ - return [ (x,s) for x in self - for s in self.dual() - if x.inner_product(s) == 0 ] + # Return an immutable tuple instead of a mutable list because + # the result will be cached. + return tuple( (x,s) for x in self + for s in self.dual() + if x.inner_product(s) == 0 ) def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, From 5cb0d4bbcbd32ed23686742fd773a28e77d72074 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 6 Oct 2015 12:13:58 -0500 Subject: [PATCH 1293/1872] Fixing doctests. --- src/sage/algebras/free_zinbiel_algebra.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index 6d0b6497c2c..83c489fd124 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -13,16 +13,12 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.monoids.free_monoid import FreeMonoid -from sage.monoids.free_monoid_element import FreeMonoidElement - from sage.misc.cachefunc import cached_method from sage.categories.magmatic_algebras import MagmaticAlgebras from sage.categories.rings import Rings -from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement +from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.words import Words from sage.combinat.words.alphabet import Alphabet -from sage.structure.element import generic_power from sage.sets.family import Family class FreeZinbielAlgebra(CombinatorialFreeModule): @@ -130,7 +126,7 @@ class FreeZinbielAlgebra(CombinatorialFreeModule): sage: ((x*x)*x)*x 6*Z[xxxx] sage: (((x*x)*x)*x)*x - 24*Z[xxxx] + 24*Z[xxxxx] REFERENCES: @@ -249,8 +245,6 @@ def product_on_basis(self, x, y): sage: Z. = algebras.FreeZinbiel(QQ) sage: (x*y)*z # indirect doctest Z[xyz] + Z[xzy] - sage: x^4 - 3*Z[xxxx] """ if not x: return self.monomial(y) From 6a9b8ea4e2af1b89194237bd53ab3929684c7fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 6 Oct 2015 19:23:28 +0200 Subject: [PATCH 1294/1872] trac #19336 fixing custom latex of Lambert W function --- src/sage/functions/log.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index ac1f2e0fd00..d60ab561515 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -723,12 +723,12 @@ def _maxima_init_evaled_(self, n, z): NotImplementedError: Non-principal branch lambert_w[1](x) is not implemented in Maxima """ if n == 0: - if isinstance(z,str): - maxima_z=z - elif hasattr(z,'_maxima_init_'): - maxima_z=z._maxima_init_() + if isinstance(z, str): + maxima_z = z + elif hasattr(z, '_maxima_init_'): + maxima_z = z._maxima_init_() else: - maxima_z=str(z) + maxima_z = str(z) return "lambert_w(%s)" % maxima_z else: raise NotImplementedError("Non-principal branch lambert_w[%s](%s) is not implemented in Maxima" % (n, z)) @@ -759,15 +759,17 @@ def _print_latex_(self, n, z): EXAMPLES:: sage: latex(lambert_w(1)) - \operatorname{W_0}(1) + \operatorname{W}({1}) sage: latex(lambert_w(0,x)) - \operatorname{W_0}(x) + \operatorname{W}({x}) sage: latex(lambert_w(1,x)) - \operatorname{W_{1}}(x) + \operatorname{W_{1}}({x}) + sage: latex(lambert_w(1,x+exp(x))) + \operatorname{W_{1}}({x + e^x}) """ if n == 0: - return r"\operatorname{W_0}(%s)" % z + return r"\operatorname{W}({%s})" % z else: - return r"\operatorname{W_{%s}}(%s)" % (n, z) + return r"\operatorname{W_{%s}}({%s})" % (n, z) lambert_w = Function_lambert_w() From bd49490b1b6c006ee43eb5dbdb98aa5d98ae541f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 6 Oct 2015 15:37:58 -0500 Subject: [PATCH 1295/1872] Changes from Mike and some added tests. --- src/sage/combinat/sf/orthogonal.py | 66 ++++++++++++++++++++++-------- src/sage/combinat/sf/symplectic.py | 63 ++++++++++++++++++++-------- 2 files changed, 94 insertions(+), 35 deletions(-) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 5666750d450..85b60da31a5 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -20,7 +20,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** import sfa -import sage.combinat.partition as partition +import sage.libs.lrcalc.lrcalc as lrcalc +from sage.combinat.partition import Partitions from sage.misc.cachefunc import cached_method from sage.rings.all import ZZ, QQ, Integer from sage.matrix.all import matrix @@ -164,12 +165,18 @@ def __init__(self, Sym): sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "orthogonal", 'o', graded=False) + # We make a strong reference since we use it for our computations + # and so we can define the coercion below (only codomains have + # strong references) + self._s = Sym.schur() + # Setup the coercions - s = Sym.schur() - M = s.module_morphism(self._s_to_o_on_basis, codomain=self, - triangular='upper', unitriangular=True) + M = self._s.module_morphism(self._s_to_o_on_basis, codomain=self, + triangular='upper', unitriangular=True) M.register_as_coercion() - (~M).register_as_coercion() + Mi = self.module_morphism(self._o_to_s_on_basis, codomain=self._s, + triangular='upper', unitriangular=True) + Mi.register_as_coercion() def _multiply(self, r, l): r""" @@ -182,8 +189,7 @@ def _multiply(self, r, l): sage: o([2]) * o([1,1]) # indirect doctest o[1, 1] + o[2] + o[2, 1, 1] + o[3, 1] """ - s = self.realization_of().schur() - return self(s(r) * s(l)) + return self(self._s(r) * self._s(l)) def counit(self, x): r""" @@ -197,8 +203,34 @@ def counit(self, x): sage: o.counit(o.an_element()) -1 """ - s = self.realization_of().schur() - return s.counit(s(x)) + return self._s.counit(self._s(x)) + + @cached_method + def _o_to_s_on_basis(self, lam): + r""" + Return the orthogonal symmetric function ``o[lam]`` expanded in + the Schur basis, where ``lam`` is a partition. + + TESTS: + + Check that this is the inverse:: + + sage: o = SymmetricFunctions(QQ).o() + sage: s = SymmetricFunctions(QQ).s() + sage: all(o(s(o[la])) == o[la] for i in range(5) for la in Partitions(i)) + True + sage: all(s(o(s[la])) == s[la] for i in range(5) for la in Partitions(i)) + True + """ + R = self.base_ring() + n = sum(lam) + return self._s._from_dict({ mu: R.sum( (-1)**j * lrcalc.lrcoef_unsafe(lam, mu, nu) + for nu in Partitions(2*j) + if all(nu.arm_length(i,i) == nu.leg_length(i,i)+1 + for i in range(nu.frobenius_rank())) + ) + for j in range(n//2+1) # // 2 for horizontal dominoes + for mu in Partitions(n-2*j) }) @cached_method def _s_to_o_on_basis(self, lam): @@ -222,17 +254,15 @@ def _s_to_o_on_basis(self, lam): sage: o._s_to_o_on_basis(Partition([])) o[] sage: o._s_to_o_on_basis(Partition([4,2,1])) - o[1] + 2*o[2, 1] + o[2, 2, 1] + o[3] + o[3, 1, 1] + o[3, 2] + o[4, 1] + o[4, 2, 1] + o[1] + 2*o[2, 1] + o[2, 2, 1] + o[3] + + o[3, 1, 1] + o[3, 2] + o[4, 1] + o[4, 2, 1] sage: s(o._s_to_o_on_basis(Partition([3,1]))) == s[3,1] True """ - import sage.libs.lrcalc.lrcalc as lrcalc - from sage.combinat.partition import Partitions R = self.base_ring() - # TODO: This is a brute force check and could likely be simplified - return self._from_dict({ mu: R.sum( lrcalc.lrcoef_unsafe(lam, mu, nu) - for j in range(sum(lam)-sum(mu)+1) - for nu in Partitions(j) - if all(x % 2 == 0 for x in nu) ) - for i in range(sum(lam)+1) for mu in Partitions(i) }) + n = sum(lam) + return self._from_dict({ mu: R.sum( lrcalc.lrcoef_unsafe(lam, mu, [2*x for x in nu]) + for nu in Partitions(j) ) + for j in range(n//2+1) # // 2 for horizontal dominoes + for mu in Partitions(n-2*j) }) diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index 58532997eb0..a924c7ac381 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -20,7 +20,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** import sfa -import sage.combinat.partition as partition +import sage.libs.lrcalc.lrcalc as lrcalc +from sage.combinat.partition import Partitions from sage.misc.cachefunc import cached_method from sage.rings.all import ZZ, QQ, Integer from sage.matrix.all import matrix @@ -166,12 +167,18 @@ def __init__(self, Sym): sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "symplectic", 'sp', graded=False) + # We make a strong reference since we use it for our computations + # and so we can define the coercion below (only codomains have + # strong references) + self._s = Sym.schur() + # Setup the coercions - s = Sym.schur() - M = s.module_morphism(self._s_to_sp_on_basis, codomain=self, - triangular='upper', unitriangular=True) + M = self._s.module_morphism(self._s_to_sp_on_basis, codomain=self, + triangular='upper', unitriangular=True) M.register_as_coercion() - (~M).register_as_coercion() + Mi = self.module_morphism(self._sp_to_s_on_basis, codomain=self._s, + triangular='upper', unitriangular=True) + Mi.register_as_coercion() def _multiply(self, r, l): r""" @@ -184,8 +191,7 @@ def _multiply(self, r, l): sage: sp([2]) * sp([1,1]) # indirect doctest sp[1, 1] + sp[2] + sp[2, 1, 1] + sp[3, 1] """ - s = self.realization_of().schur() - return self(s(r) * s(l)) + return self(self._s(r) * self._s(l)) def counit(self, x): r""" @@ -199,8 +205,34 @@ def counit(self, x): sage: sp.counit(sp.an_element()) 2 """ - s = self.realization_of().schur() - return s.counit(s(x)) + return self._s.counit(self._s(x)) + + @cached_method + def _sp_to_s_on_basis(self, lam): + r""" + Return the symplectic symmetric function ``sp[lam]`` expanded in + the Schur basis, where ``lam`` is a partition. + + TESTS: + + Check that this is the inverse:: + + sage: sp = SymmetricFunctions(QQ).sp() + sage: s = SymmetricFunctions(QQ).s() + sage: all(sp(s(sp[la])) == sp[la] for i in range(5) for la in Partitions(i)) + True + sage: all(s(sp(s[la])) == s[la] for i in range(5) for la in Partitions(i)) + True + """ + R = self.base_ring() + n = sum(lam) + return self._s._from_dict({ mu: R.sum( (-1)**j * lrcalc.lrcoef_unsafe(lam, mu, nu) + for nu in Partitions(2*j) + if all(nu.leg_length(i,i) == nu.arm_length(i,i)+1 + for i in range(nu.frobenius_rank())) + ) + for j in range(n//2+1) # // 2 for horizontal dominoes + for mu in Partitions(n-2*j) }) @cached_method def _s_to_sp_on_basis(self, lam): @@ -228,13 +260,10 @@ def _s_to_sp_on_basis(self, lam): sage: s(sp._s_to_sp_on_basis(Partition([3,1]))) == s[3,1] True """ - import sage.libs.lrcalc.lrcalc as lrcalc - from sage.combinat.partition import Partitions R = self.base_ring() - # TODO: This is a brute force check and could likely be simplified - return self._from_dict({ mu: R.sum( lrcalc.lrcoef_unsafe(lam, mu, nu) - for j in range(sum(lam)-sum(mu)+1) - for nu in Partitions(j) - if all(x % 2 == 0 for x in nu.conjugate()) ) - for i in range(sum(lam)+1) for mu in Partitions(i) }) + n = sum(lam) + return self._from_dict({ mu: R.sum( lrcalc.lrcoef_unsafe(lam, mu, sum([[x,x] for x in nu], [])) + for nu in Partitions(j) ) + for j in range(n//2+1) # // 2 for vertical dominoes + for mu in Partitions(n-2*j) }) From a7ee8574e639366db30427852671b0ee1bfb0cf3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 6 Oct 2015 15:46:12 -0500 Subject: [PATCH 1296/1872] Adding the Shimozono-Zabrocki paper as a reference. --- src/sage/combinat/sf/orthogonal.py | 1 + src/sage/combinat/sf/symplectic.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 85b60da31a5..9229f1cf0a7 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -56,6 +56,7 @@ class SymmetricFunctionAlgebra_orthogonal(sfa.SymmetricFunctionAlgebra_generic): REFERENCES: - [ChariKleber2000]_ + - [ShimozonoZabrocki2006]_ EXAMPLES: diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index a924c7ac381..f018baf0f32 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -59,6 +59,10 @@ class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): *Symmetric functions and representations of quantum affine algebras*. :arXiv:`math/0011161v1` + .. [ShimozonoZabrocki2006] Mark Shimozono and Mike Zabrocki. + *Deformed universal characters for classical and affine algebras*. + Journal of Algebra, **299** (2006). :arxiv:`math/0404288`. + EXAMPLES: Here are the first few symplectic symmetric functions, in various bases:: From be0c14deab2fef8da6289f6a62c94d5c5ca53b95 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 29 Sep 2015 13:00:55 +0200 Subject: [PATCH 1297/1872] trac #19311: A (729,336,153,156)-strongly regular graph --- src/sage/graphs/strongly_regular_db.pyx | 60 +++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index cfefb513375..33913de6b5c 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1522,6 +1522,65 @@ def SRG_560_208_72_80(): h.relabel() return h +def SRG_729_336_153_156(): + r""" + Return a `(729, 336, 153, 156)`-strongly regular graph. + + This graph is built from a 2-intersection code shared by L. Disset in his + thesis [Disset00]_ and available at + http://www.mat.uc.cl/~ldissett/newgraphs/. + + EXAMPLE:: + + sage: from sage.graphs.strongly_regular_db import SRG_729_336_153_156 + sage: G = SRG_729_336_153_156() # long time + sage: G.is_strongly_regular(parameters=True) # long time + (729, 336, 153, 156) + + REFERENCES: + + .. [Disset00] L. Dissett, + Combinatorial and computational aspects of finite geometries, + 2000, + https://tspace.library.utoronto.ca/bitstream/1807/14575/1/NQ49844.pdf + """ + from itertools import product, izip + L = [ + "101212212122202012010102120101112012121001201012120220122112001121201201201201010020012201001201201201202120121122012021201221021110200212121011211002012220000122201201", + "011100122001200111220011220020011222001200022000220012220122011220011101122012012001222010122200012011120112220112000120120012002012201122001220012122000201212001211211", + "000011111000011111112000001112000000111122222000001111112222000001111122222000111222222001111122222000001111112222000001112222000111122222000001111222000011122000011122", + "000000000111111111111000000000111111111111111222222222222222000000000000000111111111111222222222222000000000000000111111111111222222222222000000000000111111111222222222", + "000000000000000000000111111111111111111111111111111111111111000000000000000000000000000000000000000111111111111111111111111111111111111111222222222222222222222222222222", + "000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + "0"*168 + ] + + q = 3 + k = 6 + K = GF(q) + L = list(Matrix(GF(q),map(list,L)).transpose()) + g = Graph() + + # Vertices of the graph + V = [x for x in product(K,repeat=k+1) + if x[-1]] + + # For every point in F_q^{k+1} not on the hyperplane of L + for u in V: + uh = tuple([uu/u[-1] for uu in u]) + + # For every v point of L + for v in L: + + # u is adjacent with all vertices on a uv line. + for qq in K: + v_last = u[-1]+qq*(v[-1]-u[-1]) + if v_last: + g.add_edge(uh,tuple([(uu+qq*(vv-uu))/v_last + for uu,vv in izip(u,v)])) + g.relabel() + return g + def SRG_729_532_391_380(): r""" Return a `(729, 532, 391, 380)`-strongly regular graph. @@ -2275,6 +2334,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (560, 208, 72, 80): [SRG_560_208_72_80], (625, 416, 279,272): [SRG_625_416_279_272], (625, 364, 213,210): [SRG_625_364_213_210], + (729, 336, 153,156): [SRG_729_336_153_156], (729, 616, 523,506): [SRG_729_616_523_506], (729, 420, 243,240): [SRG_729_420_243_240], (729, 560, 433,420): [SRG_729_560_433_420], From 59b3692f5f1fb83aaeb6f6d99322537e2d0b9d57 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 30 Sep 2015 21:46:09 +0200 Subject: [PATCH 1298/1872] trac #19311: Draft of an individual function --- src/sage/graphs/strongly_regular_db.pyx | 94 ++++++++++++++++++------- 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 33913de6b5c..ac1fe890a92 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1522,6 +1522,71 @@ def SRG_560_208_72_80(): h.relabel() return h +def strongly_regular_from_two_intersection_set(M): + r""" + Return a strongly regular graph from a 2-intersection set. + + A set of points in the projective geometry `PG(k,q)` is said to be a + 2-intersection set if it intersects every hyperplane in either `h_1` or + `h_2` points, where `h_1,h_2\in \\NN`. + + From a 2-intersection set `S` can be defined a strongly-regular graph in the + following way: + + - Place the points of `S` on a hyperplane `H` in `PG(k+1,q)` + + - Define the graph `G` on all points of `PG(k+1,q)\backslash H` + + - Make two points of `V(G)=PG(k+1,q)\backslash H` adjacent if the line going + through them intersects `S` + + For more information, see e.g. [CDB13]_ where this explanation has been + taken from. + + INPUT: + + - `M` -- a `k \times |S|` matrix defined on `F_q` representing the points of + the 2-intersection set. + + **EXPLAIN HOMOGENEOUS COORDINATES AND HOW THEY ARE EXPECTED BY THIS FUNCTION** + + EXAMPLE:: + + ** Find examples** + + .. [CDB13] I. Cardinali and B. De Bruyn, + Spin-embeddings, two-intersection sets and two-weight codes, + Ars Comb. 109 (2013): 309-319. + https://biblio.ugent.be/publication/4241842/file/4241845.pdf + """ + from itertools import product, izip + K = M.base_ring() + k = M.ncols() + g = Graph() + + M = [list(p)+[0] for p in M] + + # Vertices of the graph + V = [x for x in product(K,repeat=k+1) + if x[-1]] + + # For every point in F_q^{k+1} not on the hyperplane of M + for u in V: + uh = tuple([uu/u[-1] for uu in u]) + + # For every v point of M + for v in M: + + # u is adjacent with all vertices on a uv line. + for qq in K: + v_last = u[-1]+qq*(v[-1]-u[-1]) + if v_last: + g.add_edge(uh,tuple([(uu+qq*(vv-uu))/v_last + for uu,vv in izip(u,v)])) + g.relabel() + return g + + def SRG_729_336_153_156(): r""" Return a `(729, 336, 153, 156)`-strongly regular graph. @@ -1544,7 +1609,6 @@ def SRG_729_336_153_156(): 2000, https://tspace.library.utoronto.ca/bitstream/1807/14575/1/NQ49844.pdf """ - from itertools import product, izip L = [ "101212212122202012010102120101112012121001201012120220122112001121201201201201010020012201001201201201202120121122012021201221021110200212121011211002012220000122201201", "011100122001200111220011220020011222001200022000220012220122011220011101122012012001222010122200012011120112220112000120120012002012201122001220012122000201212001211211", @@ -1552,34 +1616,10 @@ def SRG_729_336_153_156(): "000000000111111111111000000000111111111111111222222222222222000000000000000111111111111222222222222000000000000000111111111111222222222222000000000000111111111222222222", "000000000000000000000111111111111111111111111111111111111111000000000000000000000000000000000000000111111111111111111111111111111111111111222222222222222222222222222222", "000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", - "0"*168 ] - q = 3 - k = 6 - K = GF(q) - L = list(Matrix(GF(q),map(list,L)).transpose()) - g = Graph() - - # Vertices of the graph - V = [x for x in product(K,repeat=k+1) - if x[-1]] - - # For every point in F_q^{k+1} not on the hyperplane of L - for u in V: - uh = tuple([uu/u[-1] for uu in u]) - - # For every v point of L - for v in L: - - # u is adjacent with all vertices on a uv line. - for qq in K: - v_last = u[-1]+qq*(v[-1]-u[-1]) - if v_last: - g.add_edge(uh,tuple([(uu+qq*(vv-uu))/v_last - for uu,vv in izip(u,v)])) - g.relabel() - return g + L = Matrix(GF(3),map(list,L)).transpose() + return strongly_regular_from_two_intersection_set(L) def SRG_729_532_391_380(): r""" From 85e1bc1a868e3906b073e08fb1507918ee484c14 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 6 Oct 2015 16:04:35 -0700 Subject: [PATCH 1299/1872] docs and example and optimisation/simplification --- src/sage/graphs/strongly_regular_db.pyx | 33 +++++++++++-------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index ac1fe890a92..64e7c6f55dd 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1545,14 +1545,21 @@ def strongly_regular_from_two_intersection_set(M): INPUT: - - `M` -- a `k \times |S|` matrix defined on `F_q` representing the points of - the 2-intersection set. + - `M` -- a `|S| \times k` matrix with entries in `F_q` representing the points of + the 2-intersection set. We assume that the first non-zero entry of each row is + equal to `1`, that is, they give points in homogeneous coordinates. - **EXPLAIN HOMOGENEOUS COORDINATES AND HOW THEY ARE EXPECTED BY THIS FUNCTION** + The implementation does not check that `S` is actually a 2-intersection set. EXAMPLE:: - ** Find examples** + sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_intersection_set + sage: S=Matrix([(0,0,1),(0,1,0)] + map(lambda x: (1,x^2,x), GF(4,'b'))) + sage: g=strongly_regular_from_two_intersection_set(S) + sage: g.is_strongly_regular(parameters=True) + (64, 18, 2, 6) + + REFERENCES: .. [CDB13] I. Cardinali and B. De Bruyn, Spin-embeddings, two-intersection sets and two-weight codes, @@ -1564,25 +1571,15 @@ def strongly_regular_from_two_intersection_set(M): k = M.ncols() g = Graph() - M = [list(p)+[0] for p in M] - - # Vertices of the graph - V = [x for x in product(K,repeat=k+1) - if x[-1]] + M = [list(p) for p in M] # For every point in F_q^{k+1} not on the hyperplane of M - for u in V: - uh = tuple([uu/u[-1] for uu in u]) - + for u in [tuple(x) for x in product(K,repeat=k)]: # For every v point of M for v in M: - # u is adjacent with all vertices on a uv line. - for qq in K: - v_last = u[-1]+qq*(v[-1]-u[-1]) - if v_last: - g.add_edge(uh,tuple([(uu+qq*(vv-uu))/v_last - for uu,vv in izip(u,v)])) + g.add_edges([[u,tuple([u[i]+qq*v[i] for i in range(k)])] \ + for qq in K if not qq==K.zero()]) g.relabel() return g From 70d9d5158e99e59566b4f4508f40c1dac0d99672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Oct 2015 18:37:21 +0200 Subject: [PATCH 1300/1872] trac #19336 latex of lambert_w again, plus a few local enhancements --- src/sage/functions/log.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index d60ab561515..d75c7b2e2f1 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -565,8 +565,10 @@ def __init__(self): 0.567143290409784 """ BuiltinFunction.__init__(self, "lambert_w", nargs=2, - conversions={'mathematica':'ProductLog', - 'maple':'LambertW'}) + conversions={'mathematica': 'ProductLog', + 'maple': 'LambertW', + 'matlab': 'lambertw', + 'maxima': 'generalized_lambert_w'}) def __call__(self, *args, **kwds): r""" @@ -718,21 +720,18 @@ def _maxima_init_evaled_(self, n, z): sage: lambert_w(0, x)._maxima_() lambert_w(_SAGE_VAR_x) sage: lambert_w(1, x)._maxima_() - Traceback (most recent call last): - ... - NotImplementedError: Non-principal branch lambert_w[1](x) is not implemented in Maxima + generalized_lambert_w(1,_SAGE_VAR_x) """ + if isinstance(z, str): + maxima_z = z + elif hasattr(z, '_maxima_init_'): + maxima_z = z._maxima_init_() + else: + maxima_z = str(z) if n == 0: - if isinstance(z, str): - maxima_z = z - elif hasattr(z, '_maxima_init_'): - maxima_z = z._maxima_init_() - else: - maxima_z = str(z) return "lambert_w(%s)" % maxima_z else: - raise NotImplementedError("Non-principal branch lambert_w[%s](%s) is not implemented in Maxima" % (n, z)) - + return "generalized_lambert_w(%s,%s)" % (n, maxima_z) def _print_(self, n, z): """ @@ -765,11 +764,11 @@ def _print_latex_(self, n, z): sage: latex(lambert_w(1,x)) \operatorname{W_{1}}({x}) sage: latex(lambert_w(1,x+exp(x))) - \operatorname{W_{1}}({x + e^x}) + \operatorname{W_{1}}({x + e^{x}}) """ if n == 0: - return r"\operatorname{W}({%s})" % z + return r"\operatorname{W}({%s})" % z._latex_() else: - return r"\operatorname{W_{%s}}({%s})" % (n, z) + return r"\operatorname{W_{%s}}({%s})" % (n, z._latex_()) lambert_w = Function_lambert_w() From d79d3df614f6c0dc4d1131627673dafdfe9688cd Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 7 Oct 2015 13:44:56 -0500 Subject: [PATCH 1301/1872] Fixing typo. --- src/sage/algebras/free_zinbiel_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index 83c489fd124..9c00304eea7 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -89,7 +89,7 @@ class FreeZinbielAlgebra(CombinatorialFreeModule): .. WARNING:: - Currently the basis is indexed all words over the variables, + Currently the basis is indexed by all words over the variables, incuding the empty word. This is a slight abuse as it is suppose to be the indexed by all non-empty words. From 54a5af3afb61388c7fa97ca8e14bb274a9708029 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 7 Oct 2015 14:24:27 -0500 Subject: [PATCH 1302/1872] Initial round of revisions and trying to get the Hopf structure to work. --- src/sage/combinat/sf/character.py | 159 +++++++++++++++++++----------- 1 file changed, 102 insertions(+), 57 deletions(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 1a2ccd2ce56..6d39267b7bf 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -9,8 +9,9 @@ REFERENCES: .. [OZ2015] R. Orellana, M. Zabrocki, *Symmetric group characters - as symmetric functions*, :arxiv:`1510.00438`. + as symmetric functions*, :arxiv:`1510.00438`. """ + #***************************************************************************** # Copyright (C) 2015 Mike Zabrocki 0: - return 1/k*self._p.sum(moebius(k/d)*self._p([d]) for d in \ - divisors(k)) + if k > 0: + return ~k * self._p.sum(moebius(k/d)*self._p([d]) + for d in divisors(k)) def _b_power_k_r(self, k, r): r""" @@ -341,7 +384,7 @@ def _b_power_k_r(self, k, r): .. MATH:: \sum_{j=0}^r (-1)^{r-j}k^j\binom{r,j} \left( - \frac{1}{k} \sum_{d|k} \mu(d/k) p_d \right)_k + \frac{1}{k} \sum_{d|k} \mu(d/k) p_d \right)_k. INPUT: @@ -363,8 +406,9 @@ def _b_power_k_r(self, k, r): """ p = self._p - return p.sum((-1)**(r-j)*k**j*binomial(r,j)*p.prod( \ - self._b_power_k(k)-i*p.one() for i in range(j)) for j in range(r+1)) + return p.sum( (-1)**(r-j) * k**j * binomial(r,j) + * p.prod(self._b_power_k(k) - i*p.one() for i in range(j)) + for j in range(r+1) ) def _b_power_gamma(self, gamma): r""" @@ -375,7 +419,7 @@ def _b_power_gamma(self, gamma): .. MATH:: - {\mathbf p}_{\ga} = \sum_{k \geq 1} {\mathbf p}_{k^{m_k}} + {\mathbf p}_{\ga} = \sum_{k \geq 1} {\mathbf p}_{k^{m_k}}, where @@ -403,8 +447,8 @@ def _b_power_gamma(self, gamma): p[] + 5*p[1] + p[1, 1] - 5*p[3] - 2*p[3, 1] + p[3, 3] """ - return self._p.prod( self._b_power_k_r(Integer(k),Integer(r)) \ - for (k,r) in gamma.to_exp_dict().iteritems()) + return self._p.prod( self._b_power_k_r(Integer(k),Integer(r)) + for (k,r) in gamma.to_exp_dict().iteritems() ) def _self_to_power_on_basis(self, lam): r""" @@ -416,13 +460,13 @@ def _self_to_power_on_basis(self, lam): .. MATH:: \sum_{\gamma} \chi^{\lambda}(\gamma) - \frac{{\mathbf p}_\gamma}{z_\gamma} + \frac{{\mathbf p}_\gamma}{z_\gamma}, where `\chi^{\lambda}(\gamma)` is the irreducible character indexed by the partition `\lambda` and evaluated at an element of cycle structure `\gamma` and `{\mathbf p}_\gamma` is the power sum expression calculated in the method - ``_b_power_gamma``. + :meth:`_b_power_gamma`. INPUT: @@ -441,8 +485,9 @@ def _self_to_power_on_basis(self, lam): p[] - p[1] + 1/2*p[1, 1] - 1/2*p[2] """ - return self._p.sum(c*self._b_power_gamma(ga) for (ga, c) in \ - self._p(self._other(lam))) + return self._p.sum( c*self._b_power_gamma(ga) + for (ga, c) in self._p(self._other(lam)) ) + @cached_method def _self_to_other_on_basis(self, lam): r""" @@ -466,6 +511,6 @@ def _self_to_other_on_basis(self, lam): s[] - s[1] + s[1, 1] sage: st._self_to_other_on_basis(Partition([2,1])) 3*s[1] - 2*s[1, 1] - 2*s[2] + s[2, 1] - """ return self._other(self._self_to_power_on_basis(lam)) + From 2f8fe5e02cfbfaf1d1b624b29c125028c787a089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Oct 2015 21:30:15 +0200 Subject: [PATCH 1303/1872] fixing hidden doctests in geometry folder --- .../hyperbolic_space/hyperbolic_geodesic.py | 4 ++-- src/sage/geometry/lattice_polytope.py | 19 +++++++++---------- src/sage/geometry/polyhedron/base.py | 2 +- .../geometry/polyhedron/double_description.py | 2 +- .../double_description_inhomogeneous.py | 4 ++-- .../lattice_euclidean_group_element.py | 2 +- src/sage/geometry/polyhedron/palp_database.py | 10 +++++----- 7 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index 73fd2c6414e..3c2fe11daf6 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -1168,11 +1168,11 @@ 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 - the elements of `p` to `0`,`1`, and `\infty'. + the elements of `p` to `0`, `1`, and `\infty`. INPUT: - - a list of three distinct elements of three distinct elements + - a list of three distinct elements of `\mathbb{CP}^1` in affine coordinates; that is, each element must be a complex number, `\infty`, or symbolic. diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 8f0eca94c9b..d0cc12f77b6 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -839,19 +839,19 @@ def _copy_faces(self, other, reverse=False): reflexive polytopes, faces of this polytope and its polar are in inclusion reversing bijection. - .. note:: + .. NOTE:: This function does not perform any checks that this operation makes sense. INPUT: - - ``other`` - another LatticePolytope, whose facial structure will be + - ``other`` -- another LatticePolytope, whose facial structure will be copied - - ``reverse`` - (default: False) if True, the facial structure of the - other polytope will be reversed, i.e. vertices will correspond to - facets etc. + - ``reverse`` -- (default: ``False``) if ``True``, the facial + structure of the other polytope will be reversed, + i.e. vertices will correspond to facets etc. TESTS:: @@ -1101,8 +1101,8 @@ def _pullback(self, data): INPUT: - - ``data`` - rational point or matrix of points (as columns) in the - ambient space + - ``data`` -- rational point or matrix of points (as columns) in the + ambient space OUTPUT: The same point(s) in the coordinates of the affine subspace space spanned by this polytope. @@ -5752,7 +5752,7 @@ def _palp_convert_permutation(permutation): PALP specifies a permutation group element by its domain. Furthermore, it only supports permutations of up to 62 objects and labels these by - `0 \dots 9', 'a \dots z', and 'A \dots Z'. + `0 \dots 9`, `a \dots z`, and `A \dots Z`. INPUT: @@ -5760,8 +5760,7 @@ def _palp_convert_permutation(permutation): OUTPUT: - A :class:`permutation group element - `. + A :class:`permutation group element `. EXAMPLES:: diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 0d3fe99bad4..e270b03b004 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -2381,7 +2381,7 @@ def Minkowski_difference(self, other): return P.element_class(P, None, [new_ieqs, new_eqns]) def __sub__(self, other): - """ + r""" Implement minus binary operation Polyhedra are not a ring with respect to dilatation and diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index 3bff500b362..451e4638b90 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -628,7 +628,7 @@ def dim(self): return self._A.ncols() def __repr__(self): - """ + r""" Return a string representation. OUTPUT: diff --git a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py index 9d4c6bd3d7d..2425070aca6 100644 --- a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py +++ b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py @@ -232,7 +232,7 @@ def _init_Vrep(self, inequalities, equations): return self._pivot_inequalities(A) def _split_linear_subspace(self): - """ + r""" Split the linear subspace in a generator with `x_0\not=0` and the remaining generators with `x_0=0`. @@ -504,7 +504,7 @@ def is_trivial(ray): self.equations = self._linear_subspace.matrix().rows() def _repr_(self): - """ + r""" Return a string representation. OUTPUT: diff --git a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py index 96b2bc42eeb..f3fc6f54125 100644 --- a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py +++ b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py @@ -116,7 +116,7 @@ def __call__(self, x): return v def _repr_(self): - """ + r""" Return a string representation EXAMPLES:: diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index 98a85712530..4fb51d9312a 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -134,7 +134,7 @@ def _palp_Popen(self): return Popen(["class.x", "-b2a", "-di", self._data_basename], stdout=PIPE) def _read_vertices(self, stdout, rows, cols): - """ + r""" Read vertex data from the PALP output pipe. OUTPUT: @@ -158,7 +158,7 @@ def _read_vertices(self, stdout, rows, cols): return m def _read_vertices_transposed(self, stdout, rows, cols): - """ + r""" Read vertex data from the PALP output pipe. OUTPUT: @@ -428,9 +428,9 @@ def __init__(self, h11, h21, data_basename=None, **kwds): TESTS:: - sage: from sage.geometry.polyhedron.palp_database import Reflexive4dHodge - sage: Reflexive4dHodge(1,101) # optional - polytopes_db_4d - + sage: from sage.geometry.polyhedron.palp_database import Reflexive4dHodge + sage: Reflexive4dHodge(1,101) # optional - polytopes_db_4d + """ dim = 4 if data_basename is None: From 4d535262d98811febb3fa6ed1756b1987ef7ac22 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 7 Oct 2015 12:42:02 -0700 Subject: [PATCH 1304/1872] trac 19179: minor doc fixes --- src/sage/homology/chain_homotopy.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index 01f15542d9b..eedfd8101ea 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Chain homotopies and chain contractions. +Chain homotopies and chain contractions Chain homotopies are standard constructions in homological algebra: given chain complexes `C` and `D` and chain maps `f, g: C \to D`, say @@ -25,7 +25,7 @@ - `\pi \iota = 1_D`, - `\pi H = 0`, - `H \iota = 0`, -- `H \circ H = 0`. +- `H H = 0`. Such a chain homotopy provides a strong relation between the chain complexes `C` and `D`; for example, their homology groups are @@ -84,7 +84,8 @@ class ChainHomotopy(SageObject): gives the linear transformation `C_i \to D_{i+1}`. If `f` is specified but not `g`, then `g` can be recovered from - the defining formula. + the defining formula. That is, if `g` is not specified, then it + is defined to be `f - \partial_D H - H \partial_C`. Note that the degree of the differential on the chain complex `C` must agree with that for `D`, and those degrees determine the @@ -209,7 +210,7 @@ def __init__(self, matrices, f, g=None): def is_algebraic_gradient_vector_field(self): r""" An algebraic gradient vector field is a linear map - `H: C \to C` such that `H \circ H = 0`. + `H: C \to C` such that `H H = 0`. (Some authors also require that `H \partial H = H`, whereas some make this part of the definition of "homology gradient @@ -253,7 +254,7 @@ def is_algebraic_gradient_vector_field(self): def is_homology_gradient_vector_field(self): r""" A homology gradient vector field is an algebraic gradient vector - field `H: C \to C` (i.e., a chain homotopy satisfying `H \circ + field `H: C \to C` (i.e., a chain homotopy satisfying `H H = 0`) such that `\partial H \partial = \partial` and `H \partial H = H`. See Molina-Abril and Réal [M-AR]_ and Réal and Molina-Abril [RM-A]_ for this and related terminology. @@ -349,7 +350,7 @@ def codomain(self): return self._codomain def dual(self): - """ + r""" Dual chain homotopy to this one. That is, if this one is a chain homotopy between chain maps @@ -418,7 +419,7 @@ def _repr_(self): class ChainContraction(ChainHomotopy): r""" An algebraic gradient vector field `H: C \to C` (that is a chain - homotopy satisfying `H \circ H = 0`) for which there are chain + homotopy satisfying `H H = 0`) for which there are chain maps `\pi: C \to D` ("projection") and `\iota: D \to C` ("inclusion") such that @@ -590,7 +591,8 @@ def iota(self): def dual(self): """ The chain contraction dual to this one. - Useful when switching from homology to cohomology. + + This is useful when switching from homology to cohomology. EXAMPLES:: From 371714c6914b5392d5ee0b10df35fef48130809b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 4 Oct 2015 20:35:43 -0400 Subject: [PATCH 1305/1872] Trac #19368: Add LL() method for polyhedral closed convex cones. The Lyapunov-like transformations generalize the complementary slackness condition and were originally studied by Rudolf et al. under another name. It was later shown that the space of all Lyapunov-like transformations is the Lie algebra of the automorphism group of a proper cone. This result extends to all closed convex cones. Being a complementarity property, the Lyapunov-like property `(L*x).inner_product(s) == 0` need only be checked on pairs of vectors in the complementarity set of a cone. And in fact, it suffices to check only those pairs belonging to generating sets of the cone and its dual -- namely, the `discrete_complementarity_set()`. This commit adds a new `LL()` method for polyhedral closed convex cones. The method computes a basis for the space of all Lyapunov-like transformations on a given cone by constructing the orthogonal complement of a set based on the `discrete_complementarity_set()`. --- src/sage/geometry/cone.py | 147 +++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index d16221a6962..10c815ab6d0 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -207,10 +207,10 @@ is_ToricLatticeQuotient from sage.geometry.toric_plotter import ToricPlotter, label_list from sage.graphs.digraph import DiGraph -from sage.matrix.all import matrix +from sage.matrix.all import matrix, MatrixSpace from sage.misc.all import cached_method, flatten, latex from sage.misc.superseded import deprecation -from sage.modules.all import span, vector +from sage.modules.all import span, vector, VectorSpace from sage.rings.all import QQ, RR, ZZ, gcd from sage.structure.all import SageObject, parent from sage.libs.ppl import C_Polyhedron, Generator_System, Constraint_System, \ @@ -4442,6 +4442,149 @@ def discrete_complementarity_set(self): for s in self.dual() if x.inner_product(s) == 0 ) + def LL(self): + r""" + Compute a basis of Lyapunov-like transformations on this cone. + + A linear transformation `L` is said to be Lyapunov-like on this + cone if `L(x)` and `s` are orthogonal for every pair `(x,s)` in + its :meth:`discrete_complementarity_set`. The set of all such + transformations forms a vector space, namely the Lie algebra of + the automorphism group of this cone. + + OUTPUT: + + A list of matrices forming a basis for the space of all + Lyapunov-like transformations on this cone. + + REFERENCES: + + M. Orlitzky. The Lyapunov rank of an improper cone. + http://www.optimization-online.org/DB_HTML/2015/10/5135.html + + .. [Rudolf] G. Rudolf, N. Noyan, D. Papp, and F. Alizadeh. + Bilinear optimality constraints for the cone of positive + polynomials. Mathematical Programming, Series B, 129 (2011) 5-31. + + EXAMPLES: + + The trivial cone has no Lyapunov-like transformations:: + + sage: L = ToricLattice(0) + sage: K = Cone([], lattice=L) + sage: K.LL() + [] + + The Lyapunov-like transformations on the nonnegative orthant are + diagonal matrices:: + + sage: K = Cone([(1,)]) + sage: K.LL() + [[1]] + + sage: K = Cone([(1,0),(0,1)]) + sage: K.LL() + [ + [1 0] [0 0] + [0 0], [0 1] + ] + + sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) + sage: K.LL() + [ + [1 0 0] [0 0 0] [0 0 0] + [0 0 0] [0 1 0] [0 0 0] + [0 0 0], [0 0 0], [0 0 1] + ] + + Only the identity matrix is Lyapunov-like on the pyramids + defined by the one- and infinity-norms [Rudolf]_:: + + sage: l31 = Cone([(1,0,1), (0,-1,1), (-1,0,1), (0,1,1)]) + sage: l31.LL() + [ + [1 0 0] + [0 1 0] + [0 0 1] + ] + + sage: l3infty = Cone([(0,1,1), (1,0,1), (0,-1,1), (-1,0,1)]) + sage: l3infty.LL() + [ + [1 0 0] + [0 1 0] + [0 0 1] + ] + + Every transformation is Lyapunov-like on the ambient space:: + + sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) + sage: K.is_full_space() + True + sage: M = MatrixSpace(K.lattice().base_field(), K.lattice_dim()) + sage: M.basis() == K.LL() + True + + TESTS: + + The vectors `L(x)` and `s` are orthogonal for every pair `(x,s)` + in the :meth:`discrete_complementarity_set` of the cone:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=8) + sage: dcs = K.discrete_complementarity_set() + sage: ips = [ (L*x).inner_product(s) for (x,s) in dcs + ....: for L in K.LL() ] + sage: sum(map(abs, ips)) + 0 + + The Lyapunov-like transformations on a cone and its dual are + transposes of one another. However, there's no reason to expect + that one basis will consist of transposes of the other:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=8) + sage: LL2 = [ L.transpose() for L in K.dual().LL() ] + sage: V = VectorSpace(K.lattice().base_field(), K.lattice_dim()^2) + sage: LL1_vecs = [ V(m.list()) for m in K.LL() ] + sage: LL2_vecs = [ V(m.list()) for m in LL2 ] + sage: V.span(LL1_vecs) == V.span(LL2_vecs) + True + + The space of all Lyapunov-like transformations is a Lie algebra + and should therefore be closed under the lie bracket:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=4) + sage: W = VectorSpace(K.lattice().base_field(), K.lattice_dim()**2) + sage: LL_W = W.span([ W(m.list()) for m in K.LL() ]) + sage: brackets = [ W((L1*L2 - L2*L1).list()) for L1 in K.LL() + ....: for L2 in K.LL() ] + sage: all([ b in LL_W for b in brackets ]) + True + """ + # Matrices are not vectors in Sage, so we have to convert them + # to vectors explicitly before we can find a basis. We need these + # two values to construct the appropriate "long vector" space. + F = self.lattice().base_field() + n = self.lattice_dim() + + # These tensor products contain a basis for the orthogonal + # complement of the Lyapunov-like transformations on this cone. + tensor_products = [ s.tensor_product(x) + for (x,s) in self.discrete_complementarity_set() ] + + # Convert those tensor products to long vectors. + W = VectorSpace(F, n**2) + perp_vectors = [ W(tp.list()) for tp in tensor_products ] + + # Now find the Lyapunov-like transformations (as long vectors). + LL_vectors = W.span(perp_vectors).complement() + + # And finally convert the long vectors back to matrices. + M = MatrixSpace(F, n, n) + return [ M(v.list()) for v in LL_vectors.basis() ] + def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, min_rays=0, max_rays=None, strictly_convex=None, solid=None): From 54c08a6a30e748506729336d601b0db38f9512a9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 8 Oct 2015 00:14:03 -0500 Subject: [PATCH 1306/1872] Fixing transitions with the span of the unit element. --- src/sage/combinat/sf/character.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 6d39267b7bf..13e36e9b168 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -101,11 +101,14 @@ def _other_to_self(self, sexpr): sage: s = Sym.s() sage: st._other_to_self(s[1] + s([])) 2*st[] + st[1] + sage: 7 * st[[]] * st[[]] + 7*st[] """ if sexpr == 0: return self(0) if sexpr.support() == [[]]: - return self([]) + return self._from_dict({self.one_basis(): sexpr.coefficient([])}, + remove_zeros=False) out = self.zero() while sexpr: mup = max(sexpr.support(), key=self._my_key) From e94cf83e5699cca28746cdf70f201f3080440b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 8 Oct 2015 09:45:39 +0200 Subject: [PATCH 1307/1872] trac #18939 turn on visibility of example (alpha=1) --- 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 789e68e07f5..61502267446 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -287,7 +287,7 @@ def bezier_path(self): EXAMPLES:: sage: from sage.plot.arc import Arc - sage: op = {'alpha':0,'thickness':1,'rgbcolor':'blue','zorder':0, + sage: op = {'alpha':1,'thickness':1,'rgbcolor':'blue','zorder':0, ....: 'linestyle':'--'} sage: Arc(2,3,2.2,2.2,0,2,3,op).bezier_path() Graphics object consisting of 1 graphics primitive From bb25aaed742782da964a7e44d0ad596c51038057 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 8 Oct 2015 11:02:16 +0200 Subject: [PATCH 1308/1872] Add a pari_jupyter optional package --- build/pkgs/pari_jupyter/SPKG.txt | 22 +++++++++++++++++++++ build/pkgs/pari_jupyter/checksums.ini | 4 ++++ build/pkgs/pari_jupyter/dependencies | 1 + build/pkgs/pari_jupyter/package-version.txt | 1 + build/pkgs/pari_jupyter/spkg-install | 3 +++ build/pkgs/pari_jupyter/type | 1 + 6 files changed, 32 insertions(+) create mode 100644 build/pkgs/pari_jupyter/SPKG.txt create mode 100644 build/pkgs/pari_jupyter/checksums.ini create mode 100644 build/pkgs/pari_jupyter/dependencies create mode 100644 build/pkgs/pari_jupyter/package-version.txt create mode 100755 build/pkgs/pari_jupyter/spkg-install create mode 100644 build/pkgs/pari_jupyter/type diff --git a/build/pkgs/pari_jupyter/SPKG.txt b/build/pkgs/pari_jupyter/SPKG.txt new file mode 100644 index 00000000000..681cdc57f23 --- /dev/null +++ b/build/pkgs/pari_jupyter/SPKG.txt @@ -0,0 +1,22 @@ += pari_jupyter = + +== Description == + +A Jupyter kernel for PARI/GP + +== License == + +GPL version 3 or later + +== Upstream Contact == + +* https://github.com/jdemeyer/pari_jupyter +* Jeroen Demeyer + +== Dependencies == + +* Jupyter 4 +* Python (tested with 2.7.9) +* Cython (git master) +* PARI (git master) +* GMP or MPIR (any version which works with PARI) diff --git a/build/pkgs/pari_jupyter/checksums.ini b/build/pkgs/pari_jupyter/checksums.ini new file mode 100644 index 00000000000..d3b36f6aebb --- /dev/null +++ b/build/pkgs/pari_jupyter/checksums.ini @@ -0,0 +1,4 @@ +tarball=pari_jupyter-VERSION.tar.gz +sha1=404df06171e68056d9efe8a29804204138488885 +md5=902b290a997128e6be949c0bec44ca6e +cksum=3922118226 diff --git a/build/pkgs/pari_jupyter/dependencies b/build/pkgs/pari_jupyter/dependencies new file mode 100644 index 00000000000..5cf512f3f56 --- /dev/null +++ b/build/pkgs/pari_jupyter/dependencies @@ -0,0 +1 @@ +$(INST)/$(PARI) $(INST)/$(JUPYTER_CORE) | $(INST)/$(CYTHON) diff --git a/build/pkgs/pari_jupyter/package-version.txt b/build/pkgs/pari_jupyter/package-version.txt new file mode 100644 index 00000000000..3eefcb9dd5b --- /dev/null +++ b/build/pkgs/pari_jupyter/package-version.txt @@ -0,0 +1 @@ +1.0.0 diff --git a/build/pkgs/pari_jupyter/spkg-install b/build/pkgs/pari_jupyter/spkg-install new file mode 100755 index 00000000000..94ac1fed30e --- /dev/null +++ b/build/pkgs/pari_jupyter/spkg-install @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +cd src && ./setup.py install diff --git a/build/pkgs/pari_jupyter/type b/build/pkgs/pari_jupyter/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/pari_jupyter/type @@ -0,0 +1 @@ +optional From 4619fe72532b3aaffc4423326c8d24f873851f0a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 13:16:52 +0200 Subject: [PATCH 1309/1872] Trac #18182, comment 20, 2: rewrite OUTPUT-block --- src/sage/categories/pushout.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 0a43371f337..628d38466c5 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -300,7 +300,9 @@ def common_base(self, other_functor, self_bases, other_bases): OUTPUT: - Raise a :class:`~sage.structure.coerce_exceptions.CoercionException`. + Nothing, since a + :class:`~sage.structure.coerce_exceptions.CoercionException` + is raised. .. NOTE:: From bc70cb9f592a7f3eb93267b91591d9cd4ae7b358 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 13:26:26 +0200 Subject: [PATCH 1310/1872] Trac #18182, comment 20, 7: rename CartesianProductPolys --> CartesianProductPoly --- src/sage/categories/pushout.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 628d38466c5..4373c1708f6 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3524,23 +3524,23 @@ def pushout(R, S): sage: from sage.categories.pushout import PolynomialFunctor sage: from sage.sets.cartesian_product import CartesianProduct - sage: class CartesianProductPolys(CartesianProduct): + sage: class CartesianProductPoly(CartesianProduct): ....: def __init__(self, polynomial_rings): ....: sort = sorted(polynomial_rings, key=lambda P: P.variable_name()) - ....: super(CartesianProductPolys, self).__init__(sort, Sets().CartesianProducts()) + ....: super(CartesianProductPoly, self).__init__(sort, Sets().CartesianProducts()) ....: def vars(self): ....: return tuple(P.variable_name() for P in self.cartesian_factors()) ....: def _pushout_(self, other): - ....: if isinstance(other, CartesianProductPolys): + ....: if isinstance(other, CartesianProductPoly): ....: s_vars = self.vars() ....: o_vars = other.vars() ....: if s_vars == o_vars: ....: return - ....: return pushout(CartesianProductPolys( + ....: return pushout(CartesianProductPoly( ....: self.cartesian_factors() + ....: tuple(f for f in other.cartesian_factors() ....: if f.variable_name() not in s_vars)), - ....: CartesianProductPolys( + ....: CartesianProductPoly( ....: other.cartesian_factors() + ....: tuple(f for f in self.cartesian_factors() ....: if f.variable_name() not in o_vars))) @@ -3548,23 +3548,23 @@ def pushout(R, S): ....: if C is None: ....: return ....: elif isinstance(C[0], PolynomialFunctor): - ....: return pushout(self, CartesianProductPolys((other,))) + ....: return pushout(self, CartesianProductPoly((other,))) :: - sage: pushout(CartesianProductPolys((ZZ['x'],)), - ....: CartesianProductPolys((ZZ['y'],))) + sage: pushout(CartesianProductPoly((ZZ['x'],)), + ....: CartesianProductPoly((ZZ['y'],))) The cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Integer Ring) - sage: pushout(CartesianProductPolys((ZZ['x'], ZZ['y'])), - ....: CartesianProductPolys((ZZ['x'], ZZ['z']))) + sage: pushout(CartesianProductPoly((ZZ['x'], ZZ['y'])), + ....: CartesianProductPoly((ZZ['x'], ZZ['z']))) The cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Integer Ring, Univariate Polynomial Ring in z over Integer Ring) - sage: pushout(CartesianProductPolys((QQ['a,b']['x'], QQ['y'])), - ....: CartesianProductPolys((ZZ['b,c']['x'], SR['z']))) + sage: pushout(CartesianProductPoly((QQ['a,b']['x'], QQ['y'])), + ....: CartesianProductPoly((ZZ['b,c']['x'], SR['z']))) The cartesian product of (Univariate Polynomial Ring in x over Multivariate Polynomial Ring in a, b, c over Rational Field, @@ -3573,11 +3573,11 @@ def pushout(R, S): :: - sage: pushout(CartesianProductPolys((ZZ['x'],)), ZZ['y']) + sage: pushout(CartesianProductPoly((ZZ['x'],)), ZZ['y']) The cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Integer Ring) - sage: pushout(QQ['b,c']['y'], CartesianProductPolys((ZZ['a,b']['x'],))) + sage: pushout(QQ['b,c']['y'], CartesianProductPoly((ZZ['a,b']['x'],))) The cartesian product of (Univariate Polynomial Ring in x over Multivariate Polynomial Ring in a, b over Integer Ring, @@ -3586,7 +3586,7 @@ def pushout(R, S): :: - sage: pushout(CartesianProductPolys((ZZ['x'],)), ZZ) + sage: pushout(CartesianProductPoly((ZZ['x'],)), ZZ) Traceback (most recent call last): ... CoercionException: No common base ("join") found for From 56990b04de7ad1dbabdb24d7a83ccc4a0fbb3a3c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 14:48:31 +0200 Subject: [PATCH 1311/1872] Trac #19073, comment 20, 1: add missing INPUT/OUTPUT block of combine_exceptions --- src/sage/rings/asymptotic/growth_group.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index b740df6b91e..866306662d9 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -281,6 +281,16 @@ def combine_exceptions(e, f): r""" Helper function which combines the messages of the two given exceptions. + INPUT: + + - ``e`` -- an exception. + + - ``f`` -- an exception. + + OUTPUT: + + An exception. + EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import combine_exceptions From 88f00131181924c1a606b541d376c2166557202a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 14:53:35 +0200 Subject: [PATCH 1312/1872] adapt Trac #19073, comment 20, 1: add missing INPUT/OUTPUT block of combine_exceptions --- src/sage/rings/asymptotic/misc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index d1d2f05004c..3ab3cae616f 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -266,6 +266,16 @@ def combine_exceptions(e, *f): r""" Helper function which combines the messages of the given exceptions. + INPUT: + + - ``e`` -- an exception. + + - ``*f`` -- exceptions. + + OUTPUT: + + An exception. + EXAMPLES:: sage: from sage.rings.asymptotic.misc import combine_exceptions From f2e0d848ae53f0a6489c2aa1885ceb790c83799f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 14:56:25 +0200 Subject: [PATCH 1313/1872] Trac #19073, comment 20, 4: missing INPUT/OUTPUT block of merge_overlapping and extend description --- .../asymptotic/growth_group_cartesian.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index b6590f6fbb1..413f7e96e25 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -92,6 +92,35 @@ def merge_overlapping(A, B, key=None): r""" Merge the two overlapping tuples/lists. + INPUT: + + - ``A`` -- a list or tuple (type has to coincide with type of ``B``). + + - ``B`` -- a list or tuple (type has to coincide with type of ``A``). + + - ``key`` -- (default: ``None``) a function. If ``None``, then the + identity is used. This ``key``-function applied on an element + of the list/tuple is used for comparison. Thus elements with the + same key are considered as equal. + + OUTPUT: + + A pair of lists or tuples (depending on the type of ``A`` and ``B``). + + .. NOTE:: + + Suppose we can decompose the list `A=ac` and `B=cb` with + lists `a`, `b`, `c`, where `c` is nonempty. Then + :func:`merge_overlapping` returns the pair `(acb, acb)`. + + Suppose a ``key``-function is specified and `A=ac_A` and + `B=c_Bb`, where the list of keys of the elements of `c_A` + equals the list of keys of the elements of `c_B`. Then + :func:`merge_overlapping` returns the pair `(ac_Ab, ac_Bb)`. + + After unsuccessfully merging `A=ac` and `B=cb`, + a merge of `A=ca` and `B=bc` is tried. + TESTS:: sage: from sage.rings.asymptotic.growth_group_cartesian import merge_overlapping From 247ab5444ce061af9c246101c775b444d5b63ca2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:34:56 +0200 Subject: [PATCH 1314/1872] Trac #19073, comment 20, 4: cache keys --- .../asymptotic/growth_group_cartesian.py | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 413f7e96e25..5d13c81eee0 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -171,16 +171,20 @@ def merge_overlapping(A, B, key=None): [(1, 'b'), (2, 'b'), (3, 'b')]) """ if key is None: - key = lambda k: k + Akeys = A + Bkeys = B + else: + Akeys = tuple(key(a) for a in A) + Bkeys = tuple(key(b) for b in B) - def find_overlapping_index(A, B): + def find_overlapping_index(A, B, Akeys, Bkeys): if len(B) > len(A) - 2: raise StopIteration matches = iter(i for i in xrange(1, len(A) - len(B)) - if all(key(a) == key(b) for a, b in zip(A[i:i+len(B)], B))) + if Akeys[i:i+len(B)] == Bkeys) return next(matches) - def find_mergedoverlapping_index(A, B): + def find_mergedoverlapping_index(A, B, Akeys, Bkeys): """ Return in index i where to merge two overlapping tuples/lists ``A`` and ``B``. @@ -189,26 +193,26 @@ def find_mergedoverlapping_index(A, B): Adapted from http://stackoverflow.com/a/30056066/1052778. """ matches = iter(i for i in xrange(min(len(A), len(B)), 0, -1) - if all(key(a) == key(b) for a, b in zip(A[-i:], B[:i]))) + if Akeys[-i:] == Bkeys[:i]) return next(matches, 0) - i = find_mergedoverlapping_index(A, B) + i = find_mergedoverlapping_index(A, B, Akeys, Bkeys) if i > 0: return A + B[i:], A[:-i] + B - i = find_mergedoverlapping_index(B, A) + i = find_mergedoverlapping_index(B, A, Bkeys, Akeys) if i > 0: return B[:-i] + A, B + A[i:] try: - i = find_overlapping_index(A, B) + i = find_overlapping_index(A, B, Akeys, Bkeys) except StopIteration: pass else: return A, A[:i] + B + A[i+len(B):] try: - i = find_overlapping_index(B, A) + i = find_overlapping_index(B, A, Bkeys, Akeys) except StopIteration: pass else: From 753f2528f0cf564807ec565061ee06f009584341 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:38:53 +0200 Subject: [PATCH 1315/1872] Trac #19073, comment 20, 5: remove unnecessary list --- src/sage/rings/asymptotic/growth_group_cartesian.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 5d13c81eee0..2c4d68b5450 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -596,8 +596,8 @@ def get_factor(data): pass raise ValueError('%s is not in any of the factors of %s' % (data, self)) - return prod(list(self.cartesian_injection(*get_factor(f)) - for f in factors)) + return prod(self.cartesian_injection(*get_factor(f)) + for f in factors) def cartesian_injection(self, factor, element): From 2473d0211da9bba86193254d966bca147ce63571 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:41:22 +0200 Subject: [PATCH 1316/1872] Trac #19073, comment 20, 6: simplify try/except --- src/sage/rings/asymptotic/term_monoid.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 1ec2fb485e1..c163216da21 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1818,10 +1818,7 @@ def _element_constructor_(self, data, coefficient=None): try: if coefficient is not None: data = self.growth_group(data) - try: - return self.element_class(self, data, coefficient) - except: - raise + return self.element_class(self, data, coefficient) else: P = data.parent() from sage.symbolic.ring import SR From 6659ceea6cf424ee524c24297d4dd085fb4b17c1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:51:25 +0200 Subject: [PATCH 1317/1872] adapt Trac #19073, comment 20, 4: missing INPUT/OUTPUT block of merge_overlapping and extend description --- src/sage/rings/asymptotic/misc.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 3ab3cae616f..82443c640e3 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -345,6 +345,35 @@ def merge_overlapping(A, B, key=None): r""" Merge the two overlapping tuples/lists. + INPUT: + + - ``A`` -- a list or tuple (type has to coincide with type of ``B``). + + - ``B`` -- a list or tuple (type has to coincide with type of ``A``). + + - ``key`` -- (default: ``None``) a function. If ``None``, then the + identity is used. This ``key``-function applied on an element + of the list/tuple is used for comparison. Thus elements with the + same key are considered as equal. + + OUTPUT: + + A pair of lists or tuples (depending on the type of ``A`` and ``B``). + + .. NOTE:: + + Suppose we can decompose the list `A=ac` and `B=cb` with + lists `a`, `b`, `c`, where `c` is nonempty. Then + :func:`merge_overlapping` returns the pair `(acb, acb)`. + + Suppose a ``key``-function is specified and `A=ac_A` and + `B=c_Bb`, where the list of keys of the elements of `c_A` + equals the list of keys of the elements of `c_B`. Then + :func:`merge_overlapping` returns the pair `(ac_Ab, ac_Bb)`. + + After unsuccessfully merging `A=ac` and `B=cb`, + a merge of `A=ca` and `B=bc` is tried. + TESTS:: sage: from sage.rings.asymptotic.misc import merge_overlapping From 2008f6bd193f8d1d4df5ebd95b2cd9d524efaa0c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:53:12 +0200 Subject: [PATCH 1318/1872] adapt Trac #19073, comment 20, 4: cache keys --- src/sage/rings/asymptotic/misc.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 82443c640e3..1e1a950c7b5 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -424,16 +424,20 @@ def merge_overlapping(A, B, key=None): [(1, 'b'), (2, 'b'), (3, 'b')]) """ if key is None: - key = lambda k: k + Akeys = A + Bkeys = B + else: + Akeys = tuple(key(a) for a in A) + Bkeys = tuple(key(b) for b in B) - def find_overlapping_index(A, B): + def find_overlapping_index(A, B, Akeys, Bkeys): if len(B) > len(A) - 2: raise StopIteration matches = iter(i for i in xrange(1, len(A) - len(B)) - if all(key(a) == key(b) for a, b in zip(A[i:i+len(B)], B))) + if Akeys[i:i+len(B)] == Bkeys) return next(matches) - def find_mergedoverlapping_index(A, B): + def find_mergedoverlapping_index(A, B, Akeys, Bkeys): """ Return in index i where to merge two overlapping tuples/lists ``A`` and ``B``. @@ -442,26 +446,26 @@ def find_mergedoverlapping_index(A, B): Adapted from http://stackoverflow.com/a/30056066/1052778. """ matches = iter(i for i in xrange(min(len(A), len(B)), 0, -1) - if all(key(a) == key(b) for a, b in zip(A[-i:], B[:i]))) + if Akeys[-i:] == Bkeys[:i]) return next(matches, 0) - i = find_mergedoverlapping_index(A, B) + i = find_mergedoverlapping_index(A, B, Akeys, Bkeys) if i > 0: return A + B[i:], A[:-i] + B - i = find_mergedoverlapping_index(B, A) + i = find_mergedoverlapping_index(B, A, Bkeys, Akeys) if i > 0: return B[:-i] + A, B + A[i:] try: - i = find_overlapping_index(A, B) + i = find_overlapping_index(A, B, Akeys, Bkeys) except StopIteration: pass else: return A, A[:i] + B + A[i+len(B):] try: - i = find_overlapping_index(B, A) + i = find_overlapping_index(B, A, Bkeys, Akeys) except StopIteration: pass else: From 2aebbc891c7065ec9a26a0d19c0284575641ef25 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:55:20 +0200 Subject: [PATCH 1319/1872] Trac #19073, comment 20, 7: remove Poset category from AsymptoticRing --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index a34583bceb1..96402a7c1b1 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -906,8 +906,7 @@ def __init__(self, growth_group, coefficient_ring, category=None): raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,)) if category is None: - from sage.categories.posets import Posets - category = Rings() & Posets() + category = Rings() else: if not isinstance(category, tuple): category = (category,) @@ -1371,9 +1370,8 @@ def __init__(self, growth_group): self.growth_group = growth_group from sage.categories.rings import Rings - from sage.categories.posets import Posets super(ConstructionFunctor, self).__init__( - Rings(), Rings() & Posets()) + Rings(), Rings()) def _repr_(self): From 14941885df88ebdb20555268f193367e741fddb3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:56:29 +0200 Subject: [PATCH 1320/1872] adapt Trac #19073, comment 20, 7: remove Poset category from AsymptoticRing --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index dea416a3a07..83307f0e6f4 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1844,8 +1844,7 @@ def format_names(N): if category is None: from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.rings import Rings - from sage.categories.posets import Posets - category = CommutativeAlgebras(Rings()) & Posets() + category = CommutativeAlgebras(Rings()) if default_prec is None: from sage.misc.defaults import series_precision @@ -2650,9 +2649,8 @@ def __init__(self, growth_group): self.growth_group = growth_group from sage.categories.rings import Rings - from sage.categories.posets import Posets super(ConstructionFunctor, self).__init__( - Rings(), Rings() & Posets()) + Rings(), Rings()) def _repr_(self): From 5c94f329030caca699185e981044b8e15082147e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 16:06:32 +0200 Subject: [PATCH 1321/1872] Trac #19073, comment 20, 3: rewrite first few lines of _pushout_ --- src/sage/rings/asymptotic/growth_group.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 866306662d9..40cc0a4513a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1509,12 +1509,9 @@ def _pushout_(self, other): Growth Group x^ZZ * y^ZZ sage: sage.structure.element.coercion_traceback() # not tested """ - if isinstance(other, GenericGrowthGroup): - pass - if (other.construction() is not None and - isinstance(other.construction()[0], AbstractGrowthGroupFunctor)): - pass - else: + if not isinstance(other, GenericGrowthGroup) and \ + not (other.construction() is not None and + isinstance(other.construction()[0], AbstractGrowthGroupFunctor)): return if set(self.variable_names()).isdisjoint(set(other.variable_names())): From b3066794998b177bccbba2e4e50cf2f235a39ad9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 16:10:15 +0200 Subject: [PATCH 1322/1872] Trac #19073, comment 20, 3: document a test in pushout --- src/sage/rings/asymptotic/growth_group.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 40cc0a4513a..aaed6f8bc09 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1489,16 +1489,28 @@ def _pushout_(self, other): sage: cm = sage.structure.element.get_coercion_model() sage: A = GrowthGroup('QQ^x') sage: B = GrowthGroup('y^ZZ') + + When using growth groups with disjoint variable lists, then a + pushout can be constructed:: + sage: A._pushout_(B) Growth Group QQ^x * y^ZZ sage: cm.common_parent(A, B) Growth Group QQ^x * y^ZZ + + Single factored growth groups of the same variable cannot be + combined automatically, since there is no order relation (meaning + which one is larger than the other) between the two factors:: + sage: C = GrowthGroup('x^QQ') sage: cm.common_parent(A, C) Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: 'Growth Group QQ^x' and 'Growth Group x^QQ' + + :: + sage: cm.common_parent(GrowthGroup('x^ZZ'), GrowthGroup('y^ZZ')) Growth Group x^ZZ * y^ZZ From 8585ea1757b74d35f168d310459db9f67ed954bf Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 14:53:35 +0200 Subject: [PATCH 1323/1872] adapt Trac #19073, comment 20, 1: add missing INPUT/OUTPUT block of combine_exceptions --- src/sage/rings/asymptotic/misc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index dcc5097be84..7be79cc6a53 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -204,6 +204,16 @@ def combine_exceptions(e, *f): r""" Helper function which combines the messages of the given exceptions. + INPUT: + + - ``e`` -- an exception. + + - ``*f`` -- exceptions. + + OUTPUT: + + An exception. + EXAMPLES:: sage: from sage.rings.asymptotic.misc import combine_exceptions From 8b71dae7b8e7ce185783c7c360ebd5916a1826c9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:51:25 +0200 Subject: [PATCH 1324/1872] adapt Trac #19073, comment 20, 4: missing INPUT/OUTPUT block of merge_overlapping and extend description --- src/sage/rings/asymptotic/misc.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 7be79cc6a53..6c68a9b99ad 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -283,6 +283,35 @@ def merge_overlapping(A, B, key=None): r""" Merge the two overlapping tuples/lists. + INPUT: + + - ``A`` -- a list or tuple (type has to coincide with type of ``B``). + + - ``B`` -- a list or tuple (type has to coincide with type of ``A``). + + - ``key`` -- (default: ``None``) a function. If ``None``, then the + identity is used. This ``key``-function applied on an element + of the list/tuple is used for comparison. Thus elements with the + same key are considered as equal. + + OUTPUT: + + A pair of lists or tuples (depending on the type of ``A`` and ``B``). + + .. NOTE:: + + Suppose we can decompose the list `A=ac` and `B=cb` with + lists `a`, `b`, `c`, where `c` is nonempty. Then + :func:`merge_overlapping` returns the pair `(acb, acb)`. + + Suppose a ``key``-function is specified and `A=ac_A` and + `B=c_Bb`, where the list of keys of the elements of `c_A` + equals the list of keys of the elements of `c_B`. Then + :func:`merge_overlapping` returns the pair `(ac_Ab, ac_Bb)`. + + After unsuccessfully merging `A=ac` and `B=cb`, + a merge of `A=ca` and `B=bc` is tried. + TESTS:: sage: from sage.rings.asymptotic.misc import merge_overlapping From 74f04120f7d1395b97438acf62e6403b962bba0a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:53:12 +0200 Subject: [PATCH 1325/1872] adapt Trac #19073, comment 20, 4: cache keys --- src/sage/rings/asymptotic/misc.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 6c68a9b99ad..a3d6c443a41 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -362,16 +362,20 @@ def merge_overlapping(A, B, key=None): [(1, 'b'), (2, 'b'), (3, 'b')]) """ if key is None: - key = lambda k: k + Akeys = A + Bkeys = B + else: + Akeys = tuple(key(a) for a in A) + Bkeys = tuple(key(b) for b in B) - def find_overlapping_index(A, B): + def find_overlapping_index(A, B, Akeys, Bkeys): if len(B) > len(A) - 2: raise StopIteration matches = iter(i for i in xrange(1, len(A) - len(B)) - if all(key(a) == key(b) for a, b in zip(A[i:i+len(B)], B))) + if Akeys[i:i+len(B)] == Bkeys) return next(matches) - def find_mergedoverlapping_index(A, B): + def find_mergedoverlapping_index(A, B, Akeys, Bkeys): """ Return in index i where to merge two overlapping tuples/lists ``A`` and ``B``. @@ -380,26 +384,26 @@ def find_mergedoverlapping_index(A, B): Adapted from http://stackoverflow.com/a/30056066/1052778. """ matches = iter(i for i in xrange(min(len(A), len(B)), 0, -1) - if all(key(a) == key(b) for a, b in zip(A[-i:], B[:i]))) + if Akeys[-i:] == Bkeys[:i]) return next(matches, 0) - i = find_mergedoverlapping_index(A, B) + i = find_mergedoverlapping_index(A, B, Akeys, Bkeys) if i > 0: return A + B[i:], A[:-i] + B - i = find_mergedoverlapping_index(B, A) + i = find_mergedoverlapping_index(B, A, Bkeys, Akeys) if i > 0: return B[:-i] + A, B + A[i:] try: - i = find_overlapping_index(A, B) + i = find_overlapping_index(A, B, Akeys, Bkeys) except StopIteration: pass else: return A, A[:i] + B + A[i+len(B):] try: - i = find_overlapping_index(B, A) + i = find_overlapping_index(B, A, Bkeys, Akeys) except StopIteration: pass else: From 74cd89940a2aabe3e8162776d3313adbe0171d48 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 15:56:29 +0200 Subject: [PATCH 1326/1872] adapt Trac #19073, comment 20, 7: remove Poset category from AsymptoticRing --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 8e6cba8baf1..8f26c838c85 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1792,8 +1792,7 @@ def format_names(N): if category is None: from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.rings import Rings - from sage.categories.posets import Posets - category = CommutativeAlgebras(Rings()) & Posets() + category = CommutativeAlgebras(Rings()) if default_prec is None: from sage.misc.defaults import series_precision From 2a803463c229724167f2a10fa97ed347eb5bf43d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 8 Oct 2015 19:08:11 +0200 Subject: [PATCH 1327/1872] Trac #19073: simplify signatures of helper functions in merge_overlapping --- .../rings/asymptotic/growth_group_cartesian.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index dc5c33ef300..a306e289f26 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -177,14 +177,14 @@ def merge_overlapping(A, B, key=None): Akeys = tuple(key(a) for a in A) Bkeys = tuple(key(b) for b in B) - def find_overlapping_index(A, B, Akeys, Bkeys): + def find_overlapping_index(A, B): if len(B) > len(A) - 2: raise StopIteration matches = iter(i for i in xrange(1, len(A) - len(B)) - if Akeys[i:i+len(B)] == Bkeys) + if A[i:i+len(B)] == B) return next(matches) - def find_mergedoverlapping_index(A, B, Akeys, Bkeys): + def find_mergedoverlapping_index(A, B): """ Return in index i where to merge two overlapping tuples/lists ``A`` and ``B``. @@ -193,26 +193,26 @@ def find_mergedoverlapping_index(A, B, Akeys, Bkeys): Adapted from http://stackoverflow.com/a/30056066/1052778. """ matches = iter(i for i in xrange(min(len(A), len(B)), 0, -1) - if Akeys[-i:] == Bkeys[:i]) + if A[-i:] == B[:i]) return next(matches, 0) - i = find_mergedoverlapping_index(A, B, Akeys, Bkeys) + i = find_mergedoverlapping_index(Akeys, Bkeys) if i > 0: return A + B[i:], A[:-i] + B - i = find_mergedoverlapping_index(B, A, Bkeys, Akeys) + i = find_mergedoverlapping_index(Bkeys, Akeys) if i > 0: return B[:-i] + A, B + A[i:] try: - i = find_overlapping_index(A, B, Akeys, Bkeys) + i = find_overlapping_index(Akeys, Bkeys) except StopIteration: pass else: return A, A[:i] + B + A[i+len(B):] try: - i = find_overlapping_index(B, A, Bkeys, Akeys) + i = find_overlapping_index(Bkeys, Akeys) except StopIteration: pass else: From 1583ffcaa805fe5021fa014dbe1ab99636466e5f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 8 Oct 2015 19:08:30 +0200 Subject: [PATCH 1328/1872] Trac #19073: Reword and add doctest for _pushout_ --- src/sage/rings/asymptotic/growth_group.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index aaed6f8bc09..cdc62fe23fc 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1498,9 +1498,8 @@ def _pushout_(self, other): sage: cm.common_parent(A, B) Growth Group QQ^x * y^ZZ - Single factored growth groups of the same variable cannot be - combined automatically, since there is no order relation (meaning - which one is larger than the other) between the two factors:: + In general, growth groups of the same variable cannot be + combined automatically, since there is no order relation between the two factors:: sage: C = GrowthGroup('x^QQ') sage: cm.common_parent(A, C) @@ -1509,6 +1508,14 @@ def _pushout_(self, other): TypeError: no common canonical parent for objects with parents: 'Growth Group QQ^x' and 'Growth Group x^QQ' + However, combining is possible if the factors with the same variable + overlap:: + + sage: cm.common_parent(GrowthGroup('x^ZZ*log(x)^ZZ'), GrowthGroup('exp(x)^ZZ*x^ZZ')) + Growth Group exp(x)^ZZ * x^ZZ * log(x)^ZZ + sage: cm.common_parent(GrowthGroup('x^ZZ*log(x)^ZZ'), GrowthGroup('y^ZZ*x^ZZ')) + Growth Group x^ZZ * log(x)^ZZ * y^ZZ + :: sage: cm.common_parent(GrowthGroup('x^ZZ'), GrowthGroup('y^ZZ')) From c968782e777fe17f42c5d316412e15feba1255cd Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 8 Oct 2015 13:45:32 -0400 Subject: [PATCH 1329/1872] add Koike and Terada as a reference, link to full documentation for the bases in the top level --- src/sage/combinat/sf/orthogonal.py | 1 + src/sage/combinat/sf/sf.py | 4 ++++ src/sage/combinat/sf/symplectic.py | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 9229f1cf0a7..663a7b38489 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -56,6 +56,7 @@ class SymmetricFunctionAlgebra_orthogonal(sfa.SymmetricFunctionAlgebra_generic): REFERENCES: - [ChariKleber2000]_ + - [KoikeTerada1987]_ - [ShimozonoZabrocki2006]_ EXAMPLES: diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index d15911abd56..5c0cb5129a2 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -1025,6 +1025,8 @@ def symplectic(self): """ The symplectic basis of the symmetric functions. + .. SEEALSO:: :class:`~sage.combinat.sf.symplectic.SymmetricFunctionAlgebra_symplectic` + EXAMPLES:: sage: SymmetricFunctions(QQ).symplectic() @@ -1038,6 +1040,8 @@ def orthogonal(self): """ The orthogonal basis of the symmetric functions. + .. SEEALSO:: :class:`~sage.combinat.sf.orthogonal.SymmetricFunctionAlgebra_orthogonal` + EXAMPLES:: sage: SymmetricFunctions(QQ).orthogonal() diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index f018baf0f32..5234d06c554 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -59,6 +59,10 @@ class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): *Symmetric functions and representations of quantum affine algebras*. :arXiv:`math/0011161v1` + .. [KoikeTerada1987] K. Koike, I. Terada, *Young-diagrammatic methods for + the representation theory of the classical groups of type Bn, Cn, Dn*. + J. Algebra 107 (1987), no. 2, 466–511. + .. [ShimozonoZabrocki2006] Mark Shimozono and Mike Zabrocki. *Deformed universal characters for classical and affine algebras*. Journal of Algebra, **299** (2006). :arxiv:`math/0404288`. From a33daf903d8532cdc48e2b5474e20c965025d728 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 19:47:12 +0200 Subject: [PATCH 1330/1872] changes part 1 after comments of cheuberg --- src/doc/en/reference/rings/asymptotic_expansions_index.rst | 2 +- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/en/reference/rings/asymptotic_expansions_index.rst b/src/doc/en/reference/rings/asymptotic_expansions_index.rst index ad1107a5f44..3a15f21a3d1 100644 --- a/src/doc/en/reference/rings/asymptotic_expansions_index.rst +++ b/src/doc/en/reference/rings/asymptotic_expansions_index.rst @@ -15,7 +15,7 @@ Supplements ----------- Behind the scenes of working with asymptotic expressions a couple of -additional classes and tools turn up. For instance the growth in each +additional classes and tools turn up. For instance the growth of each summand is managed in growth groups, see below. diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index f7d48972de5..22aa3c51527 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -234,7 +234,7 @@ 1 + z^(-1) + z^(-2) + 1/2*z^(-3) + 1/3*z^(-4) + O(z^(-5)) -Multivariate Arithemtic +Multivariate Arithmetic ^^^^^^^^^^^^^^^^^^^^^^^ Now let us move on to arithmetic in the multivariate ring diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 64da815887e..d316f47d7ac 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1,5 +1,5 @@ r""" -Growth Groups as Cartesian Products +Cartesian Products of Growth Groups See :doc:`growth_group` for a description. From 2cba56bd14842af761cd4eb7eb1fb56a50424724 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 8 Oct 2015 19:47:55 +0200 Subject: [PATCH 1331/1872] rewrite informal description of growth elements and explain description strings --- src/sage/rings/asymptotic/asymptotic_ring.py | 36 +++++---- src/sage/rings/asymptotic/growth_group.py | 84 +++++++++++++------- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 22aa3c51527..b354fbc5b37 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -5,6 +5,8 @@ computations with :wikipedia:`asymptotic expansions `. +.. _asymptotic_ring_definition: + (Informal) Definition ===================== @@ -39,34 +41,40 @@ .. _asymptotic_ring_growth: -Growth Elements ---------------- +Growth Groups and Elements +-------------------------- -The elements of a :doc:`growth group ` are equipped with a partial -ordering and usually contain a variable. Examples are (among many -other possibilities) +The elements of a :doc:`growth group ` are equipped with +a partial order and usually contain a variable. Examples---the order +is described below these examples---are -- elements of the form `z^q` for some integer or rational `q` (growth - groups ``z^ZZ`` or ``z^QQ``), +- elements of the form `z^q` for some integer or rational `q` + (growth groups ``z^ZZ`` or ``z^QQ``), -- elements of the form `\log(z)^q` for some integer or rational `q` (growth - groups ``log(z)^ZZ`` or ``log(z)^QQ``), +- elements of the form `\log(z)^q` for some integer or rational `q` + (growth groups ``log(z)^ZZ`` or ``log(z)^QQ``), - elements of the form `a^z` for some rational `a` (growth group ``QQ^z``), or -- more sophisticated constructions like products `x^r \log(x)^s \cdot - a^y \cdot y^q` (this corresponds to an element of the growth group +- more sophisticated constructions like products + `x^r \cdot \log(x)^s \cdot a^y \cdot y^q` + (this corresponds to an element of the growth group ``x^QQ * log(x)^ZZ * QQ^y * y^QQ``). -The order in all these examples is the growth as `x`, `y`, or `z` -(independently) tend to `\infty`. For elements only using the -variable `z` this means, `g_1 \leq g_2` if +The order in all these examples induced by the magnitude of the +elements as `x`, `y`, or `z` (independently) tend to `\infty`. For +elements only using the variable `z` this means, `g_1 \leq g_2` if .. MATH:: \lim_{z\to\infty} \frac{g_1}{g_2} \leq 1. +To find out more about growth groups, on how they are created and +about the above used descriptions strings see the top of the +module :doc:`growth group `. + + .. WARNING:: As this code is experimental, a warning is thrown when an diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c8ca181e18f..6ee5ae441e4 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -8,35 +8,10 @@ gets large (tend to `\infty`) is compared. Growth groups are used for the calculations done in the -:doc:`asymptotic ring `. +:doc:`asymptotic ring `. There, take a look at the +:ref:`informal definition `, where +examples of growth groups and elements are given as well. -A Formal Definition -=================== - -The elements of a :doc:`growth group ` are equipped with a partial -ordering and usually contain a variable. Examples are (among many -other possibilities) - -- elements of the form `z^q` for some integer or rational `q` (growth - groups ``z^ZZ`` or ``z^QQ``), - -- elements of the form `\log(z)^q` for some integer or rational `q` (growth - groups ``log(z)^ZZ`` or ``log(z)^QQ``), - -- elements of the form `a^z` for some - rational `a` (growth group ``QQ^z``), or - -- more sophisticated constructions like products `x^r \log(x)^s \cdot - a^y \cdot y^q` (this corresponds to an element of the growth group - ``x^QQ * log(x)^ZZ * QQ^y * y^QQ``). - -The ordering in all these examples is the growth as `x`, `y`, or `z` -(independently) tend to `\infty`. For elements only using the -variable `z` this means, `g_1 \leq g_2` if - -.. MATH:: - - \lim_{z\to\infty} \frac{g_2}{g_1} \leq 1. .. WARNING:: @@ -60,8 +35,57 @@ See http://trac.sagemath.org/17601 for details. Growth Group x^ZZ * log(x)^ZZ -Overview -======== +.. _growth_group_description: + +Description of Growth Groups +============================ + +Many growth groups can be described by a string, which can also be used to +create them. For example, the string ``'x^QQ * log(x)^ZZ * QQ^y * y^QQ'`` +represents a growth group with the following properties: + +- It is a growth group in the two variables `x` and `y`. + +- Its elements are of the form + + .. MATH:: + + x^r \cdot \log(x)^s \cdot a^y \cdot y^q + + for `r\in\QQ`, `s\in\ZZ`, `a\in\QQ` and `q\in\QQ`. + +- The order is with respect to `x\to\infty` and `y\to\infty` independently + of each other. + +- To compare such elements, they are split into parts belonging to + only one variable. In the example above, + + .. MATH:: + + x^{r_1} \cdot \log(x)^{s_1} \leq x^{r_2} \cdot \log(x)^{s_2} + + if `(r_1, s_1) \leq (r_2, s_2)` lexicographically. This reflects the fact + that elements `x^r` are larger than elements `\log(x)^s` as `x\to\infty`. + The factors belonging to the variable `y` are compared analogously. + + The results of these comparisons are then put together using the + :wikipedia:`product order `, i.e., `\leq` if each component + satisfies `\leq`. + + +Each description string consists of ordered factors---yes, this means +``*`` is noncommutative---of strings describing "elementary" growth +groups (see the examples below). As stated in the example above, these +factors are split by their variable; factors with the same variable are +grouped. Reading such factors from left to right determines the order: +Comparing elements of two factors (growth groups) `L` and `R`, then all +elements of `L` are considered to be larger than each element of `R`. + + +.. _growth_group_creating: + +Creating a Growth Group +======================= For many purposes the factory ``GrowthGroup`` (see :class:`GrowthGroupFactory`) is the most convenient way to generate a From f15bf84f28da17b9bcfc3780a804a432eac3f6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 8 Oct 2015 20:15:42 +0200 Subject: [PATCH 1332/1872] correct hidden doc in graphs, and in particular in schnyder.py --- src/sage/graphs/independent_sets.pyx | 2 +- src/sage/graphs/schnyder.py | 145 +++++++++++++++------------ 2 files changed, 83 insertions(+), 64 deletions(-) diff --git a/src/sage/graphs/independent_sets.pyx b/src/sage/graphs/independent_sets.pyx index cbb99409f55..e91e0609dba 100644 --- a/src/sage/graphs/independent_sets.pyx +++ b/src/sage/graphs/independent_sets.pyx @@ -338,7 +338,7 @@ cdef class IndependentSets: - ``S`` -- a set of vertices to be tested. - TESTS:: + TESTS: All independent sets of PetersenGraph are... independent sets:: diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index c4b4b8398fc..6af206e9581 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -6,12 +6,14 @@ Walter Schnyder's Algorithm. AUTHORS: - -- Jonathan Bober, Emily Kirkman (2008-02-09): initial version + +- Jonathan Bober, Emily Kirkman (2008-02-09) -- initial version REFERENCE: - [1] Schnyder, Walter. Embedding Planar Graphs on the Grid. - Proc. 1st Annual ACM-SIAM Symposium on Discrete Algorithms, - San Francisco (1994), pp. 138-147. + +.. [1] Schnyder, Walter. Embedding Planar Graphs on the Grid. + Proc. 1st Annual ACM-SIAM Symposium on Discrete Algorithms, + San Francisco (1994), pp. 138-147. """ #***************************************************************************** # Copyright (C) 2008 Jonathan Bober and Emily Kirkman @@ -42,11 +44,13 @@ def _triangulate(g, comb_emb): method will work on one of these attempts.) INPUT: - g -- the graph to triangulate - comb_emb -- a planar combinatorial embedding of g - RETURNS: - A list of edges that are added to the graph (in place) + - g -- the graph to triangulate + - ``comb_emb`` -- a planar combinatorial embedding of g + + OUTPUT: + + A list of edges that are added to the graph (in place) EXAMPLES:: @@ -125,27 +129,33 @@ def _triangulate(g, comb_emb): return edges_added def _normal_label(g, comb_emb, external_face): - """ - Helper function to schnyder method for computing coordinates in the plane to - plot a planar graph with no edge crossings. + r""" + Helper function to schnyder method for computing coordinates in + the plane to plot a planar graph with no edge crossings. - Constructs a normal labelling of a triangular graph g, given the planar - combinatorial embedding of g and a designated external face. Returns labels - dictionary. The normal label is constructed by first contracting the graph - down to its external face, then expanding the graph back to the original while - simultaneously adding angle labels. + Constructs a normal labelling of a triangular graph g, given the + planar combinatorial embedding of g and a designated external + face. Returns labels dictionary. The normal label is constructed + by first contracting the graph down to its external face, then + expanding the graph back to the original while simultaneously + adding angle labels. INPUT: - g -- the graph to find the normal labeling of (g must be triangulated) - comb_emb -- a planar combinatorial embedding of g - external_face -- the list of three edges in the external face of g - RETURNS: - x -- tuple with entries - x[0] = dict of dicts of normal labeling for each vertex of g and each - adjacent neighbors u,v (u < v) of vertex: - { vertex : { (u,v): angel_label } } - x[1] = (v1,v2,v3) tuple of the three vertices of the external face. + - g -- the graph to find the normal labeling of (g must be triangulated) + - ``comb_emb`` -- a planar combinatorial embedding of g + - ``external_face`` -- the list of three edges in the external face of g + + OUTPUT: + + x -- tuple with entries + + x[0] = dict of dicts of normal labeling for each vertex of g and each + adjacent neighbors u,v (u < v) of vertex: + + { vertex : { (u,v): angel_label } } + + x[1] = (v1,v2,v3) tuple of the three vertices of the external face. EXAMPLES:: @@ -160,7 +170,6 @@ def _normal_label(g, comb_emb, external_face): sage: _realizer(g, tn) ({0: []}, (0, 1, 2)) - """ contracted = [] contractible = [] @@ -329,20 +338,27 @@ def _realizer(g, x, example=False): give a path to each of the three external vertices. INPUT: - g -- the graph to compute the realizer of - x -- tuple with entries - x[0] = dict of dicts representing a normal labeling of g. For - each vertex of g and each adjacent neighbors u,v (u < v) of - vertex: { vertex : { (u,v): angle_label } } - x[1] = (v1, v2, v3) tuple of the three external vertices (also - the roots of each tree) - - RETURNS: - x -- tuple with entries - x[0] = dict of lists of TreeNodes: - { root_vertex : [ list of all TreeNodes under root_vertex ] } - x[0] = (v1,v2,v3) tuple of the three external vertices (also the - roots of each tree) + + - g -- the graph to compute the realizer of + - x -- tuple with entries + + x[0] = dict of dicts representing a normal labeling of g. For + each vertex of g and each adjacent neighbors u,v (u < v) of + vertex: { vertex : { (u,v): angle_label } } + + x[1] = (v1, v2, v3) tuple of the three external vertices (also + the roots of each tree) + + OUTPUT: + + - x -- tuple with entries + + x[0] = dict of lists of TreeNodes: + + { root_vertex : [ list of all TreeNodes under root_vertex ] } + + x[1] = (v1,v2,v3) tuple of the three external vertices (also the + roots of each tree) EXAMPLES:: @@ -409,22 +425,26 @@ def _realizer(g, x, example=False): return tree_nodes, (v1,v2,v3) def _compute_coordinates(g, x): - """ + r""" Given a triangulated graph g with a dict of trees given by the realizer and tuple of the external vertices, we compute the coordinates of a planar geometric embedding in the grid. - The coordinates will be set to the _pos attribute of g. + The coordinates will be set to the ``_pos`` attribute of g. INPUT: - g -- the graph to compute the coordinates of - x -- tuple with entries - x[0] = dict of tree nodes for the three trees with each external - vertex as root - { root_vertex : [ list of all TreeNodes under root_vertex ] } - - x[1] = (v1, v2, v3) tuple of the three external vertices (also - the roots of each tree) + + - g -- the graph to compute the coordinates of + - x -- tuple with entries + + x[0] = dict of tree nodes for the three trees with each external + vertex as root: + + { root_vertex : [ list of all TreeNodes under root_vertex ] } + + x[1] = (v1, v2, v3) tuple of the three external vertices (also + the roots of each tree) + EXAMPLES:: sage: from sage.graphs.schnyder import _triangulate, _normal_label, _realizer, _compute_coordinates @@ -505,16 +525,17 @@ def _compute_coordinates(g, x): class TreeNode(): """ - A class to represent each node in the trees used by _realizer() and - _compute_coordinates() when finding a planar geometric embedding in + A class to represent each node in the trees used by :func:`_realizer` and + :func:`_compute_coordinates` when finding a planar geometric embedding in the grid. Each tree node is doubly linked to its parent and children. INPUT: - parent -- the parent TreeNode of self - children -- a list of TreeNode children of self - label -- the associated realizer vertex label + + - ``parent`` -- the parent TreeNode of ``self`` + - ``children`` -- a list of TreeNode children of ``self`` + - ``label`` -- the associated realizer vertex label EXAMPLES:: @@ -532,14 +553,14 @@ class TreeNode(): sage: tn.compute_depth_of_self_and_children() sage: tn3.depth 2 - """ def __init__(self, parent = None, children = None, label = None): """ INPUT: - parent -- the parent TreeNode of self - children -- a list of TreeNode children of self - label -- the associated realizer vertex label + + - ``parent`` -- the parent TreeNode of ``self`` + - ``children`` -- a list of TreeNode children of ``self`` + - ``label`` -- the associated realizer vertex label EXAMPLE:: @@ -557,7 +578,6 @@ def __init__(self, parent = None, children = None, label = None): sage: tn.compute_depth_of_self_and_children() sage: tn3.depth 2 - """ if children is None: children = [] @@ -566,10 +586,10 @@ def __init__(self, parent = None, children = None, label = None): self.label = label self.number_of_descendants = 1 - def compute_number_of_descendants(self): """ Computes the number of descendants of self and all descendants. + For each TreeNode, sets result as attribute self.number_of_descendants EXAMPLES:: @@ -599,6 +619,7 @@ def compute_number_of_descendants(self): def compute_depth_of_self_and_children(self): """ Computes the depth of self and all descendants. + For each TreeNode, sets result as attribute self.depth EXAMPLES:: @@ -617,7 +638,6 @@ def compute_depth_of_self_and_children(self): sage: tn.compute_depth_of_self_and_children() sage: tn3.depth 2 - """ if self.parent is None: self.depth = 1 @@ -646,7 +666,6 @@ def append_child(self, child): sage: tn.compute_depth_of_self_and_children() sage: tn3.depth 2 - """ if child in self.children: return From e1a1963ebd7351830f6e58fa63e8db796df1a1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 8 Oct 2015 20:17:36 +0200 Subject: [PATCH 1333/1872] one missing correction --- src/sage/graphs/hyperbolicity.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/hyperbolicity.pyx b/src/sage/graphs/hyperbolicity.pyx index bf8a8a2c8b4..07d3b4703f4 100644 --- a/src/sage/graphs/hyperbolicity.pyx +++ b/src/sage/graphs/hyperbolicity.pyx @@ -208,7 +208,7 @@ def _my_subgraph(G, vertices, relabel=False, return_map=False): etc.). If ``relabel`` is ``True``, the vertices of the new graph are relabeled - with integers in the range '0\cdots |vertices|-1'. The relabeling map is + with integers in the range '0\cdots \mid vertices \mid -1'. The relabeling map is returned if ``return_map`` is also ``True``. TESTS: From 30476c7ac05393358aa0eb7a3304a8eb8ac76e00 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 8 Oct 2015 15:54:10 -0400 Subject: [PATCH 1334/1872] Trac #19368: Rename LL() to lyapunov_like_basis(). This name is better for two reasons. First, it gives the user some idea what the method does. Second, it indicates that you get a basis (rather than a vector space object) back. --- src/sage/geometry/cone.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 10c815ab6d0..fd599013842 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -4442,7 +4442,7 @@ def discrete_complementarity_set(self): for s in self.dual() if x.inner_product(s) == 0 ) - def LL(self): + def lyapunov_like_basis(self): r""" Compute a basis of Lyapunov-like transformations on this cone. @@ -4472,25 +4472,25 @@ def LL(self): sage: L = ToricLattice(0) sage: K = Cone([], lattice=L) - sage: K.LL() + sage: K.lyapunov_like_basis() [] The Lyapunov-like transformations on the nonnegative orthant are diagonal matrices:: sage: K = Cone([(1,)]) - sage: K.LL() + sage: K.lyapunov_like_basis() [[1]] sage: K = Cone([(1,0),(0,1)]) - sage: K.LL() + sage: K.lyapunov_like_basis() [ [1 0] [0 0] [0 0], [0 1] ] sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: K.LL() + sage: K.lyapunov_like_basis() [ [1 0 0] [0 0 0] [0 0 0] [0 0 0] [0 1 0] [0 0 0] @@ -4501,7 +4501,7 @@ def LL(self): defined by the one- and infinity-norms [Rudolf]_:: sage: l31 = Cone([(1,0,1), (0,-1,1), (-1,0,1), (0,1,1)]) - sage: l31.LL() + sage: l31.lyapunov_like_basis() [ [1 0 0] [0 1 0] @@ -4509,7 +4509,7 @@ def LL(self): ] sage: l3infty = Cone([(0,1,1), (1,0,1), (0,-1,1), (-1,0,1)]) - sage: l3infty.LL() + sage: l3infty.lyapunov_like_basis() [ [1 0 0] [0 1 0] @@ -4522,7 +4522,7 @@ def LL(self): sage: K.is_full_space() True sage: M = MatrixSpace(K.lattice().base_field(), K.lattice_dim()) - sage: M.basis() == K.LL() + sage: M.basis() == K.lyapunov_like_basis() True TESTS: @@ -4533,8 +4533,9 @@ def LL(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=8) sage: dcs = K.discrete_complementarity_set() + sage: LL = K.lyapunov_like_basis() sage: ips = [ (L*x).inner_product(s) for (x,s) in dcs - ....: for L in K.LL() ] + ....: for L in LL ] sage: sum(map(abs, ips)) 0 @@ -4544,10 +4545,11 @@ def LL(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=8) - sage: LL2 = [ L.transpose() for L in K.dual().LL() ] + sage: LL1 = K.lyapunov_like_basis() + sage: LL2 = [L.transpose() for L in K.dual().lyapunov_like_basis()] sage: V = VectorSpace(K.lattice().base_field(), K.lattice_dim()^2) - sage: LL1_vecs = [ V(m.list()) for m in K.LL() ] - sage: LL2_vecs = [ V(m.list()) for m in LL2 ] + sage: LL1_vecs = [ V(m.list()) for m in LL1 ] + sage: LL2_vecs = [ V(m.list()) for m in LL2 ] sage: V.span(LL1_vecs) == V.span(LL2_vecs) True @@ -4556,10 +4558,11 @@ def LL(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=4) + sage: LL = K.lyapunov_like_basis() sage: W = VectorSpace(K.lattice().base_field(), K.lattice_dim()**2) - sage: LL_W = W.span([ W(m.list()) for m in K.LL() ]) - sage: brackets = [ W((L1*L2 - L2*L1).list()) for L1 in K.LL() - ....: for L2 in K.LL() ] + sage: LL_W = W.span([ W(m.list()) for m in LL ]) + sage: brackets = [ W((L1*L2 - L2*L1).list()) for L1 in LL + ....: for L2 in LL ] sage: all([ b in LL_W for b in brackets ]) True """ From cac1d88d687705fa90de0edac1b472f6e2d623b4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 8 Oct 2015 20:44:32 -0500 Subject: [PATCH 1335/1872] Doing some surgery on the categories. --- src/sage/categories/coalgebras.py | 28 +- src/sage/categories/coalgebras_with_basis.py | 2 + src/sage/combinat/sf/orthogonal.py | 29 +- src/sage/combinat/sf/sf.py | 12 +- src/sage/combinat/sf/sfa.py | 407 ++++++++++++------- src/sage/combinat/sf/symplectic.py | 29 +- 6 files changed, 289 insertions(+), 218 deletions(-) diff --git a/src/sage/categories/coalgebras.py b/src/sage/categories/coalgebras.py index a5fdc492111..c700ea8f7ab 100644 --- a/src/sage/categories/coalgebras.py +++ b/src/sage/categories/coalgebras.py @@ -226,7 +226,7 @@ def coproduct(self, x): def counit(self, x): r""" - Returns the counit of ``x``. + Return the counit of ``x``. EXAMPLES:: @@ -258,7 +258,8 @@ class ParentMethods: def coproduct_by_coercion(self, x): r""" - Returns the coproduct by coercion if coproduct_by_basis is not implemented. + Return the coproduct by coercion if ``coproduct_by_basis`` + is not implemented. EXAMPLES:: @@ -289,3 +290,26 @@ def coproduct_by_coercion(self, x): """ R = self.realization_of().a_realization() return self.tensor_square()(R(x).coproduct()) + + def counit_by_coercion(self, x): + r""" + Return the counit of ``x`` if ``counit_by_basis`` is + not implemented. + + EXAMPLES:: + + sage: sp = SymmetricFunctions(QQ).sp() + sage: sp.an_element() + 2*sp[] + 2*sp[1] + 3*sp[2] + sage: sp.counit(sp.an_element()) + 2 + + sage: o = SymmetricFunctions(QQ).o() + sage: o.an_element() + 2*o[] + 2*o[1] + 3*o[2] + sage: o.counit(o.an_element()) + -1 + """ + R = self.realization_of().a_realization() + return R(x).counit() + diff --git a/src/sage/categories/coalgebras_with_basis.py b/src/sage/categories/coalgebras_with_basis.py index ddcaad16d26..7f42b13f66c 100644 --- a/src/sage/categories/coalgebras_with_basis.py +++ b/src/sage/categories/coalgebras_with_basis.py @@ -126,6 +126,8 @@ def counit(self): """ if self.counit_on_basis is not NotImplemented: return self.module_morphism(self.counit_on_basis,codomain=self.base_ring()) + elif hasattr(self, "counit_by_coercion"): + return self.counit_by_coercion class ElementMethods: pass diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 663a7b38489..cd8ba3bac09 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -133,6 +133,8 @@ class SymmetricFunctionAlgebra_orthogonal(sfa.SymmetricFunctionAlgebra_generic): Some multiplication:: + sage: o([2]) * o([1,1]) + o[1, 1] + o[2] + o[2, 1, 1] + o[3, 1] sage: o([2,1,1]) * o([2]) o[1, 1] + o[1, 1, 1, 1] + 2*o[2, 1, 1] + o[2, 2] + o[2, 2, 1, 1] + o[3, 1] + o[3, 1, 1, 1] + o[3, 2, 1] + o[4, 1, 1] @@ -180,33 +182,6 @@ def __init__(self, Sym): triangular='upper', unitriangular=True) Mi.register_as_coercion() - def _multiply(self, r, l): - r""" - Return the product of ``r`` and ``l`` by coercing to the Schur - functions and then pulling back. - - EXAMPLES:: - - sage: o = SymmetricFunctions(QQ).o() - sage: o([2]) * o([1,1]) # indirect doctest - o[1, 1] + o[2] + o[2, 1, 1] + o[3, 1] - """ - return self(self._s(r) * self._s(l)) - - def counit(self, x): - r""" - Return the counit of ``x`` in ``self``. - - EXAMPLES:: - - sage: o = SymmetricFunctions(QQ).o() - sage: o.an_element() - 2*o[] + 2*o[1] + 3*o[2] - sage: o.counit(o.an_element()) - -1 - """ - return self._s.counit(self._s(x)) - @cached_method def _o_to_s_on_basis(self, lam): r""" diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 5c0cb5129a2..50261f61c96 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -152,7 +152,11 @@ class SymmetricFunctions(UniqueRepresentation, Parent): the mathematical properties of ``p``:: sage: p.categories() - [Category of bases of Symmetric Functions over Rational Field, Category of graded hopf algebras with basis over Rational Field, ...] + [Category of graded bases of Symmetric Functions over Rational Field, + Category of filtered bases of Symmetric Functions over Rational Field, + Category of bases of Symmetric Functions over Rational Field, + Category of graded hopf algebras with basis over Rational Field, + ...] To start with, ``p`` is a graded algebra, the grading being induced by the size of the partitions. Due to this, the one is the basis @@ -832,7 +836,7 @@ def __init__(self, R): def a_realization(self): r""" - Returns a particular realization of ``self`` (the Schur basis). + Return a particular realization of ``self`` (the Schur basis). EXAMPLES:: @@ -865,7 +869,7 @@ def schur(self): return schur.SymmetricFunctionAlgebra_schur(self) s = schur Schur = schur # Currently needed by SymmetricFunctions.__init_extra__ - # and sfa.SymmetricFunctionsBases.corresponding_basis_over + # and sfa.GradedSymmetricFunctionsBases.corresponding_basis_over def powersum(self): r""" @@ -933,7 +937,7 @@ def witt(self, coerce_h=True, coerce_e=False, coerce_p=False): import witt return witt.SymmetricFunctionAlgebra_witt(self, coerce_h=coerce_h, coerce_e=coerce_e, coerce_p=coerce_p) w = witt - # Currently needed by sfa.SymmetricFunctionsBases.corresponding_basis_over + # Currently needed by sfa.GradedSymmetricFunctionsBases.corresponding_basis_over Witt = witt def forgotten(self): diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 2f1c7e1711f..d03fedff474 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -14,7 +14,7 @@ integer partitions:: sage: s.category() - Category of bases of Symmetric Functions over Rational Field + Category of graded bases of Symmetric Functions over Rational Field sage: s.basis().keys() Partitions @@ -216,6 +216,8 @@ from sage.rings.polynomial.polynomial_element import is_Polynomial from sage.rings.polynomial.multi_polynomial import is_MPolynomial from sage.combinat.partition import _Partitions, Partitions, Partitions_n, Partition +from sage.categories.algebras import Algebras +from sage.categories.hopf_algebras import HopfAlgebras import sage.libs.symmetrica.all as symmetrica # used in eval() from sage.combinat.free_module import CombinatorialFreeModule from sage.matrix.constructor import matrix @@ -330,37 +332,31 @@ def is_SymmetricFunction(x): """ return isinstance(x, SymmetricFunctionAlgebra_generic.Element) -from sage.categories.realizations import Realizations, Category_realization_of_parent +##################################################################### +## Bases categories + +from sage.categories.realizations import Category_realization_of_parent class SymmetricFunctionsBases(Category_realization_of_parent): r""" The category of bases of the ring of symmetric functions. - """ - def __init__(self, base, graded=True): - r""" - Initialize the bases of the ring of symmetric functions. - - INPUT: - - ``self`` -- a category of bases for the symmetric functions - - ``base`` -- ring of symmetric functions - - ``graded`` -- (default: ``True``) if ``True``, then the basis is - considered to be graded, otherwise it is considered to be filtered + INPUT: - TESTS:: + - ``self`` -- a category of bases for the symmetric functions + - ``base`` -- ring of symmetric functions - sage: from sage.combinat.sf.sfa import SymmetricFunctionsBases - sage: Sym = SymmetricFunctions(QQ) - sage: bases = SymmetricFunctionsBases(Sym); bases - Category of bases of Symmetric Functions over Rational Field - sage: Sym.schur() in bases - True - """ - self._graded = graded - Category_realization_of_parent.__init__(self, base) + TESTS:: + sage: from sage.combinat.sf.sfa import SymmetricFunctionsBases + sage: Sym = SymmetricFunctions(QQ) + sage: bases = SymmetricFunctionsBases(Sym); bases + Category of bases of Symmetric Functions over Rational Field + sage: Sym.schur() in bases + True + """ def _repr_(self): r""" - Returns the representation of ``self``. + Return the representation of ``self``. INPUT: @@ -380,26 +376,19 @@ def super_categories(self): r""" The super categories of ``self``. - INPUT: - - - ``self`` -- a category of bases for the symmetric functions - EXAMPLES:: sage: from sage.combinat.sf.sfa import SymmetricFunctionsBases sage: Sym = SymmetricFunctions(QQ) sage: bases = SymmetricFunctionsBases(Sym) sage: bases.super_categories() - [Category of commutative graded hopf algebras with basis over Rational Field, + [Category of commutative hopf algebras with basis over Rational Field, Category of realizations of Symmetric Functions over Rational Field] """ - from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis - cat = HopfAlgebrasWithBasis(self.base().base_ring()).Commutative() - if self._graded: - cat = cat.Graded() - else: - cat = cat.Filtered() - return [cat, Realizations(self.base())] + cat = HopfAlgebras(self.base().base_ring()) + return [self.base().Realizations(), + cat.Commutative().WithBasis(), + cat.Graded().Realizations()] class ParentMethods: @@ -623,123 +612,6 @@ def degree_on_basis(self, b): """ return sum(b) - def antipode_by_coercion(self, element): - r""" - The antipode of ``element``. - - INPUT: - - - ``element`` -- element in a basis of the ring of symmetric functions - - EXAMPLES:: - - sage: Sym = SymmetricFunctions(QQ) - sage: p = Sym.p() - sage: s = Sym.s() - sage: e = Sym.e() - sage: h = Sym.h() - sage: (h([]) + h([1])).antipode() # indirect doctest - h[] - h[1] - sage: (s([]) + s([1]) + s[2]).antipode() - s[] - s[1] + s[1, 1] - sage: (p([2]) + p([3])).antipode() - -p[2] - p[3] - sage: (e([2]) + e([3])).antipode() - e[1, 1] - e[1, 1, 1] - e[2] + 2*e[2, 1] - e[3] - sage: f = Sym.f() - sage: f([3,2,1]).antipode() - -f[3, 2, 1] - 4*f[3, 3] - 2*f[4, 2] - 2*f[5, 1] - 6*f[6] - - The antipode is an involution:: - - sage: Sym = SymmetricFunctions(ZZ) - sage: s = Sym.s() - sage: all( s[u].antipode().antipode() == s[u] for u in Partitions(4) ) - True - - The antipode is an algebra homomorphism:: - - sage: Sym = SymmetricFunctions(FiniteField(23)) - sage: h = Sym.h() - sage: all( all( (s[u] * s[v]).antipode() == s[u].antipode() * s[v].antipode() - ....: for u in Partitions(3) ) - ....: for v in Partitions(3) ) - True - - TESTS: - - Everything works over `\ZZ`:: - - sage: Sym = SymmetricFunctions(ZZ) - sage: p = Sym.p() - sage: s = Sym.s() - sage: e = Sym.e() - sage: h = Sym.h() - sage: (h([]) + h([1])).antipode() # indirect doctest - h[] - h[1] - sage: (s([]) + s([1]) + s[2]).antipode() - s[] - s[1] + s[1, 1] - sage: (p([2]) + p([3])).antipode() - -p[2] - p[3] - sage: (e([2]) + e([3])).antipode() - e[1, 1] - e[1, 1, 1] - e[2] + 2*e[2, 1] - e[3] - """ - return self.degree_negation(element.omega()) - - def counit(self, element): - r""" - Return the counit of ``element``. - - The counit is the constant term of ``element``. - - INPUT: - - - ``element`` -- element in a basis of the ring of symmetric functions - - EXAMPLES:: - - sage: Sym = SymmetricFunctions(QQ) - sage: m = Sym.monomial() - sage: f = 2*m[2,1] + 3*m[[]] - sage: f.counit() - 3 - """ - return element.degree_zero_coefficient() - - def degree_negation(self, element): - r""" - Return the image of ``element`` under the degree negation - automorphism of the ring of symmetric functions. - - The degree negation is the automorphism which scales every - homogeneous element of degree `k` by `(-1)^k` (for all `k`). - - INPUT: - - - ``element`` -- symmetric function written in ``self`` - - EXAMPLES:: - - sage: Sym = SymmetricFunctions(ZZ) - sage: m = Sym.monomial() - sage: f = 2*m[2,1] + 4*m[1,1] - 5*m[1] - 3*m[[]] - sage: m.degree_negation(f) - -3*m[] + 5*m[1] + 4*m[1, 1] - 2*m[2, 1] - - TESTS: - - Using :meth:`degree_negation` on an element of a different - basis works correctly:: - - sage: e = Sym.elementary() - sage: m.degree_negation(e[3]) - -m[1, 1, 1] - sage: m.degree_negation(m(e[3])) - -m[1, 1, 1] - """ - return self.sum_of_terms([ (lam, (-1)**(sum(lam)%2) * a) - for lam, a in self(element) ]) - def corresponding_basis_over(self, R): r""" Return the realization of symmetric functions corresponding to @@ -1402,8 +1274,221 @@ def coeff_of_m_mu_in_result(mu): distinct=True) return self(r) - class ElementMethods: +class FilteredSymmetricFunctionsBases(Category_realization_of_parent): + r""" + The category of graded bases of the ring of symmetric functions. + + TESTS:: + + sage: from sage.combinat.sf.sfa import FilteredSymmetricFunctionsBases + sage: Sym = SymmetricFunctions(QQ) + sage: bases = FilteredSymmetricFunctionsBases(Sym); bases + Category of filtered bases of Symmetric Functions over Rational Field + sage: Sym.schur() in bases + True + sage: Sym.sp() in bases + True + """ + def _repr_(self): + r""" + Return the representation of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import FilteredSymmetricFunctionsBases + sage: Sym = SymmetricFunctions(QQ) + sage: bases = FilteredSymmetricFunctionsBases(Sym) + sage: bases._repr_() + 'Category of filtered bases of Symmetric Functions over Rational Field' + """ + return "Category of filtered bases of %s" % self.base() + + def super_categories(self): + r""" + The super categories of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import FilteredSymmetricFunctionsBases + sage: Sym = SymmetricFunctions(QQ) + sage: bases = FilteredSymmetricFunctionsBases(Sym) + sage: bases.super_categories() + [Category of bases of Symmetric Functions over Rational Field, + Join of Category of hopf algebras with basis over Rational Field + and Category of realizations of hopf algebras over Rational Field + and Category of filtered algebras with basis over Rational Field + and Category of commutative algebras over Rational Field] + """ + cat = HopfAlgebras(self.base().base_ring()).Commutative().WithBasis().Filtered() + return [SymmetricFunctionsBases(self.base()), cat] + +class GradedSymmetricFunctionsBases(Category_realization_of_parent): + r""" + The category of graded bases of the ring of symmetric functions. + + TESTS:: + + sage: from sage.combinat.sf.sfa import GradedSymmetricFunctionsBases + sage: Sym = SymmetricFunctions(QQ) + sage: bases = GradedSymmetricFunctionsBases(Sym); bases + Category of graded bases of Symmetric Functions over Rational Field + sage: Sym.schur() in bases + True + sage: Sym.sp() in bases + False + """ + def _repr_(self): + r""" + Return the representation of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import GradedSymmetricFunctionsBases + sage: Sym = SymmetricFunctions(QQ) + sage: bases = GradedSymmetricFunctionsBases(Sym) + sage: bases._repr_() + 'Category of graded bases of Symmetric Functions over Rational Field' + """ + return "Category of graded bases of %s" % self.base() + + def super_categories(self): + r""" + The super categories of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import GradedSymmetricFunctionsBases + sage: Sym = SymmetricFunctions(QQ) + sage: bases = GradedSymmetricFunctionsBases(Sym) + sage: bases.super_categories() + [Join of Category of hopf algebras with basis over Rational Field + and Category of realizations of hopf algebras over Rational Field + and Category of graded algebras over Rational Field + and Category of commutative algebras over Rational Field, + Category of filtered bases of Symmetric Functions over Rational Field] + """ + cat = HopfAlgebras(self.base().base_ring()).Commutative().WithBasis().Graded() + return [FilteredSymmetricFunctionsBases(self.base()), cat] + + class ParentMethods: + def antipode_by_coercion(self, element): + r""" + The antipode of ``element``. + + INPUT: + + - ``element`` -- element in a basis of the ring of symmetric functions + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ) + sage: p = Sym.p() + sage: s = Sym.s() + sage: e = Sym.e() + sage: h = Sym.h() + sage: (h([]) + h([1])).antipode() # indirect doctest + h[] - h[1] + sage: (s([]) + s([1]) + s[2]).antipode() + s[] - s[1] + s[1, 1] + sage: (p([2]) + p([3])).antipode() + -p[2] - p[3] + sage: (e([2]) + e([3])).antipode() + e[1, 1] - e[1, 1, 1] - e[2] + 2*e[2, 1] - e[3] + sage: f = Sym.f() + sage: f([3,2,1]).antipode() + -f[3, 2, 1] - 4*f[3, 3] - 2*f[4, 2] - 2*f[5, 1] - 6*f[6] + + The antipode is an involution:: + + sage: Sym = SymmetricFunctions(ZZ) + sage: s = Sym.s() + sage: all( s[u].antipode().antipode() == s[u] for u in Partitions(4) ) + True + + The antipode is an algebra homomorphism:: + + sage: Sym = SymmetricFunctions(FiniteField(23)) + sage: h = Sym.h() + sage: all( all( (s[u] * s[v]).antipode() == s[u].antipode() * s[v].antipode() + ....: for u in Partitions(3) ) + ....: for v in Partitions(3) ) + True + + TESTS: + Everything works over `\ZZ`:: + + sage: Sym = SymmetricFunctions(ZZ) + sage: p = Sym.p() + sage: s = Sym.s() + sage: e = Sym.e() + sage: h = Sym.h() + sage: (h([]) + h([1])).antipode() # indirect doctest + h[] - h[1] + sage: (s([]) + s([1]) + s[2]).antipode() + s[] - s[1] + s[1, 1] + sage: (p([2]) + p([3])).antipode() + -p[2] - p[3] + sage: (e([2]) + e([3])).antipode() + e[1, 1] - e[1, 1, 1] - e[2] + 2*e[2, 1] - e[3] + """ + return self.degree_negation(element.omega()) + + def counit(self, element): + r""" + Return the counit of ``element``. + + The counit is the constant term of ``element``. + + INPUT: + + - ``element`` -- element in a basis of the ring of symmetric functions + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ) + sage: m = Sym.monomial() + sage: f = 2*m[2,1] + 3*m[[]] + sage: f.counit() + 3 + """ + return element.degree_zero_coefficient() + + def degree_negation(self, element): + r""" + Return the image of ``element`` under the degree negation + automorphism of the ring of symmetric functions. + + The degree negation is the automorphism which scales every + homogeneous element of degree `k` by `(-1)^k` (for all `k`). + + INPUT: + + - ``element`` -- symmetric function written in ``self`` + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(ZZ) + sage: m = Sym.monomial() + sage: f = 2*m[2,1] + 4*m[1,1] - 5*m[1] - 3*m[[]] + sage: m.degree_negation(f) + -3*m[] + 5*m[1] + 4*m[1, 1] - 2*m[2, 1] + + TESTS: + + Using :meth:`degree_negation` on an element of a different + basis works correctly:: + + sage: e = Sym.elementary() + sage: m.degree_negation(e[3]) + -m[1, 1, 1] + sage: m.degree_negation(m(e[3])) + -m[1, 1, 1] + """ + return self.sum_of_terms([ (lam, (-1)**(sum(lam)%2) * a) + for lam, a in self(element) ]) + + class ElementMethods: def degree_negation(self): r""" Return the image of ``self`` under the degree negation @@ -1434,10 +1519,6 @@ def degree_zero_coefficient(self): r""" Returns the degree zero coefficient of ``self``. - INPUT: - - - ``self`` -- an element of the symmetric functions - EXAMPLES:: sage: Sym = SymmetricFunctions(QQ) @@ -1448,6 +1529,12 @@ def degree_zero_coefficient(self): """ return self.coefficient([]) +#SymmetricFunctionsBases.Filtered = FilteredSymmetricFunctionsBases +#SymmetricFunctionsBases.Graded = GradedSymmetricFunctionsBases + +##################################################################### +## ABC for bases of the symmetric functions + class SymmetricFunctionAlgebra_generic(CombinatorialFreeModule): r""" Abstract base class for symmetric function algebras. @@ -1498,8 +1585,12 @@ def __init__(self, Sym, basis_name=None, prefix=None, graded=True): if prefix is not None: self._prefix = prefix self._sym = Sym + if graded: + cat = GradedSymmetricFunctionsBases(Sym) + else: # Right now, there are no non-filted bases + cat = FilteredSymmetricFunctionsBases(Sym) CombinatorialFreeModule.__init__(self, Sym.base_ring(), _Partitions, - category=SymmetricFunctionsBases(Sym, graded), + category=cat, bracket="", prefix=prefix) _print_style = 'lex' diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index 5234d06c554..ea623769305 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -141,6 +141,8 @@ class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): Some multiplication:: + sage: sp([2]) * sp([1,1]) + sp[1, 1] + sp[2] + sp[2, 1, 1] + sp[3, 1] sage: sp([2,1,1]) * sp([2]) sp[1, 1] + sp[1, 1, 1, 1] + 2*sp[2, 1, 1] + sp[2, 2] + sp[2, 2, 1, 1] + sp[3, 1] + sp[3, 1, 1, 1] + sp[3, 2, 1] + sp[4, 1, 1] @@ -188,33 +190,6 @@ def __init__(self, Sym): triangular='upper', unitriangular=True) Mi.register_as_coercion() - def _multiply(self, r, l): - r""" - Return the product of ``r`` and ``l`` by coercing to the Schur - functions and then pulling back. - - EXAMPLES:: - - sage: sp = SymmetricFunctions(QQ).sp() - sage: sp([2]) * sp([1,1]) # indirect doctest - sp[1, 1] + sp[2] + sp[2, 1, 1] + sp[3, 1] - """ - return self(self._s(r) * self._s(l)) - - def counit(self, x): - r""" - Return the counit of ``x`` in ``self``. - - EXAMPLES:: - - sage: sp = SymmetricFunctions(QQ).sp() - sage: sp.an_element() - 2*sp[] + 2*sp[1] + 3*sp[2] - sage: sp.counit(sp.an_element()) - 2 - """ - return self._s.counit(self._s(x)) - @cached_method def _sp_to_s_on_basis(self, lam): r""" From 385d49edbeeea381052690a172445b8b9df1ec88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 9 Oct 2015 10:11:41 +0200 Subject: [PATCH 1336/1872] hidden doc in /homology --- src/sage/interfaces/chomp.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/interfaces/chomp.py b/src/sage/interfaces/chomp.py index 24fd9087940..d4d45b60d9b 100644 --- a/src/sage/interfaces/chomp.py +++ b/src/sage/interfaces/chomp.py @@ -126,10 +126,10 @@ def __call__(self, program, complex, subcomplex=None, **kwds): EXAMPLES:: - sage: from sage.interfaces.chomp import CHomP - sage: T = cubical_complexes.Torus() - sage: CHomP()('homcubes', T) # indirect doctest, optional - CHomP - {0: 0, 1: Z x Z, 2: Z} + sage: from sage.interfaces.chomp import CHomP + sage: T = cubical_complexes.Torus() + sage: CHomP()('homcubes', T) # indirect doctest, optional - CHomP + {0: 0, 1: Z x Z, 2: Z} """ from sage.misc.temporary_file import tmp_filename from sage.homology.all import CubicalComplex, cubical_complexes From 23c9b77b43ca19c73e49e7a5250c0e982b2859dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Fri, 9 Oct 2015 11:12:26 +0300 Subject: [PATCH 1337/1872] Modifications as suggested by kdilks. --- src/sage/combinat/posets/posets.py | 56 +++++++++++++++--------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 51bd45052d4..0fc6542ee6d 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -66,12 +66,12 @@ :meth:`~FinitePoset.has_bottom` | Return ``True`` if the poset has a unique minimal element. :meth:`~FinitePoset.has_top` | Return ``True`` if the poset has a unique maximal element. :meth:`~FinitePoset.is_bounded` | Return ``True`` if the poset has both unique minimal and unique maximal element. - :meth:`~FinitePoset.is_chain` | Return ``True`` if the poset is totally ordered. + :meth:`~FinitePoset.is_total_order` | Return ``True`` if the poset is totally ordered. :meth:`~FinitePoset.is_connected` | Return ``True`` if the poset is connected. :meth:`~FinitePoset.is_graded` | Return ``True`` if all maximal chains of the poset has same length. :meth:`~FinitePoset.is_ranked` | Return ``True`` if the poset has a rank function. :meth:`~FinitePoset.is_rank_symmetric` | Return ``True`` if the poset is rank symmetric. - :meth:`~FinitePoset.is_incomparable_chain_free` | Return ``True`` if the poset is `(m+n)`-free. + :meth:`~FinitePoset.is_incomparable_chain_free` | Return ``True`` if the poset is (m+n)-free. :meth:`~FinitePoset.is_slender` | Return ``True`` if the poset is slender. :meth:`~FinitePoset.is_join_semilattice` | Return ``True`` is the poset has a join operation. :meth:`~FinitePoset.is_meet_semilattice` | Return ``True`` if the poset has a meet operation. @@ -1957,12 +1957,14 @@ def is_incomparable_chain_free(self, m, n=None): - ''interval order'' is `(2+2)`-free - ''semiorder'' (or ''unit interval order'') is `(1+3)`-free and `(2+2)`-free - - ''weak order'' is `1+2`-free. + - ''weak order'' is `(1+2)`-free. INPUT: - - ``m``, ``n`` - positive integers, OR - - ``m`` - list of pairs of positive integers (``n`` must be ``None``) + - ``m``, ``n`` - positive integers + + It is also possible to give a list of integer pairs as argument. + See below for an example. EXAMPLES:: @@ -1986,10 +1988,8 @@ def is_incomparable_chain_free(self, m, n=None): We show how to get an incomparable chain pair:: sage: P = Posets.PentagonPoset() - sage: c1 = Posets.ChainPoset(1) - sage: c2 = Posets.ChainPoset(2) - sage: c1_2 = c1.disjoint_union(c2) - sage: incomps = P.isomorphic_subposets(c1_2)[0] + sage: chains_1_2 = Poset({0:[], 1:[2]}) + sage: incomps = P.isomorphic_subposets(chains_1_2)[0] sage: sorted(incomps.list()), incomps.cover_relations() ([1, 2, 3], [[2, 3]]) @@ -2413,31 +2413,33 @@ def is_bounded(self): """ return self._hasse_diagram.is_bounded() - def is_chain(self): + from sage.misc.superseded import deprecated_function_alias + def is_total_order(self): """ - Return ``True`` if the poset is totally ordered, and ``False`` - otherwise. + Return ``True`` if the poset is totally ordered ("chain"), and + ``False`` otherwise. EXAMPLES:: sage: I = Poset({0:[1], 1:[2], 2:[3], 3:[4]}) - sage: I.is_chain() + sage: I.is_total_order() True sage: II = Poset({0:[1], 2:[3]}) - sage: II.is_chain() + sage: II.is_total_order() False sage: V = Poset({0:[1, 2]}) - sage: V.is_chain() + sage: V.is_total_order() False TESTS:: - sage: [len([P for P in Posets(n) if P.is_chain()]) for n in range(5)] + sage: [len([P for P in Posets(n) if P.is_total_order()]) for n in range(5)] [1, 1, 1, 1, 1] """ return self._hasse_diagram.is_chain() + is_chain = deprecated_function_alias(19141, is_total_order) def is_chain_of_poset(self, o, ordered=False): """ @@ -2516,7 +2518,9 @@ def is_connected(self): """ Return ``True`` if the poset is connected, and ``False`` otherwise. - A poset is not connected if it can be divided to parts + A poset is connected if it's Hasse diagram is connected. + + If a poset is not connected, then it can be divided to parts `S_1` and `S_2` so that every element of `S_1` is incomparable to every element of `S_2`. @@ -2870,11 +2874,11 @@ def is_ranked(self): r""" Return ``True`` if the poset is ranked, and ``False`` otherwise. - Informally a ranked poset can be "levelized": every element is - on a "level", and no cover relation jumps over a level. + A poset is ranked if there is a function `r` from poset elements + to integers so that `r(x)=r(y)+1` when `x` covers `y`. - Formally defined, a ranked poset can have function `r` from - poset elements to integers so that `r(x)=r(y)+1` if `x` covers `y`. + Informally said a ranked poset can be "levelized": every element is + on a "level", and every cover relation goes only one level up. EXAMPLES:: @@ -2899,18 +2903,14 @@ def is_graded(self): r""" Return ``True`` if the poset is graded, and ``False`` otherwise. - Informally a graded poset can be "levelized" with every maximal chain - going throught all levels: every element is on a "level", no cover - relation jumps over a level, and no chain ends in the middle of - levels. + A poset is graded if all its maximal chains have the same length. - Formally defined a poset is graded if all its maximal chains have - the same length. There are various competing definitions for graded + There are various competing definitions for graded posets (see :wikipedia:`Graded_poset`). This definition is from section 3.1 of Richard Stanley's *Enumerative Combinatorics, Vol. 1* [EnumComb1]_. - Note that every graded poset is ranked. The converse is true + Every graded poset is ranked. The converse is true for bounded posets, including lattices. EXAMPLES:: From 89c82f758936fee2ebe81e7b8b50e9da79f825d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 9 Oct 2015 10:17:03 +0200 Subject: [PATCH 1338/1872] correct hidden doc in /tensor --- src/sage/tensor/coordinate_patch.py | 12 ++++-------- src/sage/tensor/differential_form_element.py | 6 +----- src/sage/tensor/differential_forms.py | 4 ++-- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/sage/tensor/coordinate_patch.py b/src/sage/tensor/coordinate_patch.py index 88df32a42d7..908e1f9d972 100644 --- a/src/sage/tensor/coordinate_patch.py +++ b/src/sage/tensor/coordinate_patch.py @@ -81,20 +81,18 @@ def __init__(self, coordinates, metric = None): INPUT: - ``coordinates`` -- a set of symbolic variables that serve - as coordinates on this space. + as coordinates on this space. - - ``metric`` (default: None) -- a metric tensor on this - coordinate patch. Providing anything other than ``None`` - is currently not defined. + - ``metric`` (default: ``None``) -- a metric tensor on this + coordinate patch. Providing anything other than ``None`` + is currently not defined. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z - """ - from sage.symbolic.ring import is_SymbolicVariable if not all(is_SymbolicVariable(c) for c in coordinates): @@ -107,8 +105,6 @@ def __init__(self, coordinates, metric = None): if metric is not None: raise NotImplementedError("Metric geometry not supported yet.") - - def __eq__(self, other): """ Return equality if and only if other has the same coordinates diff --git a/src/sage/tensor/differential_form_element.py b/src/sage/tensor/differential_form_element.py index e109d133ec4..de7e36523e3 100644 --- a/src/sage/tensor/differential_form_element.py +++ b/src/sage/tensor/differential_form_element.py @@ -396,7 +396,6 @@ def __init__(self, parent, degree, fun = None): if degree == 0 and fun is not None: self.__setitem__([], fun) - def __getitem__(self, subscript): r""" Return a given component of the differential form. @@ -404,8 +403,7 @@ def __getitem__(self, subscript): INPUT: - ``subscript``: subscript of the component. Must be an integer - or a list of integers. - + or a list of integers. EXAMPLES:: @@ -426,7 +424,6 @@ def __getitem__(self, subscript): sage: df[2] 0 """ - if isinstance(subscript, (Integer, int)): subscript = (subscript, ) else: @@ -447,7 +444,6 @@ def __getitem__(self, subscript): else: return 0 - def __setitem__(self, subscript, fun): r""" Modify a given component of the differential form. diff --git a/src/sage/tensor/differential_forms.py b/src/sage/tensor/differential_forms.py index 6f367db317b..d4d2332b19e 100644 --- a/src/sage/tensor/differential_forms.py +++ b/src/sage/tensor/differential_forms.py @@ -76,11 +76,13 @@ class DifferentialForms(Algebra): def __init__(self, coordinate_patch = None): """ Construct the algebra of differential forms on a given coordinate patch. + See ``DifferentialForms`` for details. INPUT: - ``coordinate_patch`` -- Coordinate patch where the algebra lives. + If no coordinate patch is given, a default coordinate patch with coordinates (x, y, z) is used. @@ -91,9 +93,7 @@ def __init__(self, coordinate_patch = None): Open subset of R^2 with coordinates p, q sage: F = DifferentialForms(U); F Algebra of differential forms in the variables p, q - """ - from sage.categories.graded_algebras_with_basis \ import GradedAlgebrasWithBasis from sage.structure.parent_gens import ParentWithGens From 55208bb52064f22c0f91ef07d68610f1d997eb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 9 Oct 2015 10:25:39 +0200 Subject: [PATCH 1339/1872] fixing hidden doc in matroids --- src/sage/matroids/lean_matrix.pyx | 6 +++--- src/sage/matroids/matroid.pyx | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/matroids/lean_matrix.pyx b/src/sage/matroids/lean_matrix.pyx index 08f0db2ee3a..715888bc68e 100644 --- a/src/sage/matroids/lean_matrix.pyx +++ b/src/sage/matroids/lean_matrix.pyx @@ -1039,7 +1039,7 @@ cdef class BinaryMatrix(LeanMatrix): bitset_free(self._temp) def __repr__(self): - """ + r""" Print representation string EXAMPLES:: @@ -1666,7 +1666,7 @@ cdef class TernaryMatrix(LeanMatrix): bitset_free(self._u) def __repr__(self): - """ + r""" Print representation string EXAMPLES:: @@ -2241,7 +2241,7 @@ cdef class QuaternaryMatrix(LeanMatrix): bitset_free(self._u) def __repr__(self): - """ + r""" Print representation string EXAMPLES:: diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index bd705e8f433..77aa227347b 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -5575,9 +5575,10 @@ cdef class Matroid(SageObject): ``True`` if the matroid is 3-connected, ``False`` otherwise. INPUT: + - ``basis`` -- a basis of the matroid. - ``fund_cocircuits`` -- a iterable of some fundamental cocircuits with - respect to ``basis``. It must contain all separating fundamental cocircuits. + respect to ``basis``. It must contain all separating fundamental cocircuits. OUTPUT: @@ -5598,8 +5599,8 @@ cdef class Matroid(SageObject): .. NOTE:: - The function does not check its input at all. You may want to make - sure the matroid is both simple and cosimple. + The function does not check its input at all. You may want to make + sure the matroid is both simple and cosimple. """ # Step 1: base case if self.rank() <= 2: From 0fbeeee15c26273d1edcac312bbd49ddfc3f03a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 9 Oct 2015 10:33:25 +0200 Subject: [PATCH 1340/1872] fixing hidden doc in dynamics --- .../dynamics/interval_exchanges/template.py | 33 +++++---- src/sage/sandpiles/sandpile.py | 70 +++++++++---------- 2 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/sage/dynamics/interval_exchanges/template.py b/src/sage/dynamics/interval_exchanges/template.py index ded494ef6d0..57cb4ada51c 100644 --- a/src/sage/dynamics/interval_exchanges/template.py +++ b/src/sage/dynamics/interval_exchanges/template.py @@ -1981,7 +1981,7 @@ class RauzyDiagram(SageObject): r""" Template for Rauzy diagrams. - .. warning: + .. warning:: Internal class! Do not use directly! @@ -2600,27 +2600,30 @@ def __init__(self, p, top_bottom_inversion=False, symmetric=False): r""" - self._succ contains successors - self._pred contains predecessors + - ``self._succ`` contains successors + + - ``self._pred`` contains predecessors - self._element_class is the class of elements of self - self._element is an instance of this class (hence contains the alphabet, - the representation mode, ...). It is used to store data about property - of permutations and also as a fast iterator. + - ``self._element_class`` is the class of elements of ``self`` - INPUT: + - ``self._element`` is an instance of this class (hence + contains the alphabet, the representation mode, ...). It is + used to store data about property of permutations and also as + a fast iterator. + + INPUT: - - ``right_induction`` - boolean or 'top' or 'bottom': consider the - right induction + - ``right_induction`` - boolean or 'top' or 'bottom': consider the + right induction - - ``left_induction`` - boolean or 'top' or 'bottom': consider the - left induction + - ``left_induction`` - boolean or 'top' or 'bottom': consider the + left induction - - ``left_right_inversion`` - consider the left right inversion + - ``left_right_inversion`` - consider the left right inversion - - ``top_bottom_inversion`` - consider the top bottom inversion + - ``top_bottom_inversion`` - consider the top bottom inversion - - ``symmetric`` - consider the symmetric + - ``symmetric`` - consider the symmetric TESTS:: diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index c7410b04368..6d2d2653696 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -490,14 +490,14 @@ def __init__(self, g, sink=None): INPUT: - - ``g`` -- dict for directed multigraph with edges weighted by - nonnegative integers (see NOTE), a Graph or DiGraph. + - ``g`` -- dict for directed multigraph with edges weighted by + nonnegative integers (see NOTE), a Graph or DiGraph. - - ``sink`` -- (optional) A sink vertex. Any outgoing edges from the - designated sink are ignored for the purposes of stabilization. It is - assumed that every vertex has a directed path into the sink. If the - ``sink`` argument is omitted, the first vertex in the list of the - Sandpile's vertices is set as the sink. + - ``sink`` -- (optional) A sink vertex. Any outgoing edges from the + designated sink are ignored for the purposes of stabilization. It is + assumed that every vertex has a directed path into the sink. If the + ``sink`` argument is omitted, the first vertex in the list of the + Sandpile's vertices is set as the sink. OUTPUT: @@ -517,41 +517,37 @@ def __init__(self, g, sink=None): sage: G = Sandpile(g,'d') Here is a square with unweighted edges. In this example, the graph is - also undirected. - - :: + also undirected. :: sage: g = {0:[1,2], 1:[0,3], 2:[0,3], 3:[1,2]} sage: G = Sandpile(g,3) In the following example, multiple edges and loops in the dictionary - become edge weights in the Sandpile. - - :: - - sage: s = Sandpile({0:[1,2,3], 1:[0,1,2,2,2], 2:[1,1,0,2,2,2,2]}) - sage: s.laplacian() - [ 3 -1 -1 -1] - [-1 4 -3 0] - [-1 -2 3 0] - [ 0 0 0 0] - sage: s.dict() - {0: {1: 1, 2: 1, 3: 1}, 1: {0: 1, 1: 1, 2: 3}, 2: {0: 1, 1: 2, 2: 4}} - - Sandpiles can be created from Graphs and DiGraphs. - - sage: g = DiGraph({0:{1:2,2:4}, 1:{1:3,2:1}, 2:{1:7}}, weighted=True) - sage: s = Sandpile(g) - sage: s.dict() - {0: {1: 2, 2: 4}, 1: {0: 0, 1: 3, 2: 1}, 2: {0: 0, 1: 7}} - sage: s.sink() - 0 - sage: s = sandpiles.Cycle(4) - sage: s.laplacian() - [ 2 -1 0 -1] - [-1 2 -1 0] - [ 0 -1 2 -1] - [-1 0 -1 2] + become edge weights in the Sandpile. :: + + sage: s = Sandpile({0:[1,2,3], 1:[0,1,2,2,2], 2:[1,1,0,2,2,2,2]}) + sage: s.laplacian() + [ 3 -1 -1 -1] + [-1 4 -3 0] + [-1 -2 3 0] + [ 0 0 0 0] + sage: s.dict() + {0: {1: 1, 2: 1, 3: 1}, 1: {0: 1, 1: 1, 2: 3}, 2: {0: 1, 1: 2, 2: 4}} + + Sandpiles can be created from Graphs and DiGraphs. :: + + sage: g = DiGraph({0:{1:2,2:4}, 1:{1:3,2:1}, 2:{1:7}}, weighted=True) + sage: s = Sandpile(g) + sage: s.dict() + {0: {1: 2, 2: 4}, 1: {0: 0, 1: 3, 2: 1}, 2: {0: 0, 1: 7}} + sage: s.sink() + 0 + sage: s = sandpiles.Cycle(4) + sage: s.laplacian() + [ 2 -1 0 -1] + [-1 2 -1 0] + [ 0 -1 2 -1] + [-1 0 -1 2] .. NOTE:: From 39d1e185906821d6fcece65560e1081eb11e1493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Fri, 9 Oct 2015 15:47:05 +0300 Subject: [PATCH 1341/1872] Back to is_chain. Was a bad idea. --- src/sage/combinat/posets/posets.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 0fc6542ee6d..435f8e88b16 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -66,7 +66,7 @@ :meth:`~FinitePoset.has_bottom` | Return ``True`` if the poset has a unique minimal element. :meth:`~FinitePoset.has_top` | Return ``True`` if the poset has a unique maximal element. :meth:`~FinitePoset.is_bounded` | Return ``True`` if the poset has both unique minimal and unique maximal element. - :meth:`~FinitePoset.is_total_order` | Return ``True`` if the poset is totally ordered. + :meth:`~FinitePoset.is_chain` | Return ``True`` if the poset is totally ordered. :meth:`~FinitePoset.is_connected` | Return ``True`` if the poset is connected. :meth:`~FinitePoset.is_graded` | Return ``True`` if all maximal chains of the poset has same length. :meth:`~FinitePoset.is_ranked` | Return ``True`` if the poset has a rank function. @@ -2413,8 +2413,7 @@ def is_bounded(self): """ return self._hasse_diagram.is_bounded() - from sage.misc.superseded import deprecated_function_alias - def is_total_order(self): + def is_chain(self): """ Return ``True`` if the poset is totally ordered ("chain"), and ``False`` otherwise. @@ -2422,24 +2421,23 @@ def is_total_order(self): EXAMPLES:: sage: I = Poset({0:[1], 1:[2], 2:[3], 3:[4]}) - sage: I.is_total_order() + sage: I.is_chain() True sage: II = Poset({0:[1], 2:[3]}) - sage: II.is_total_order() + sage: II.is_chain() False sage: V = Poset({0:[1, 2]}) - sage: V.is_total_order() + sage: V.is_chain() False TESTS:: - sage: [len([P for P in Posets(n) if P.is_total_order()]) for n in range(5)] + sage: [len([P for P in Posets(n) if P.is_chain()]) for n in range(5)] [1, 1, 1, 1, 1] """ return self._hasse_diagram.is_chain() - is_chain = deprecated_function_alias(19141, is_total_order) def is_chain_of_poset(self, o, ordered=False): """ From 8bda4c2134f5e6460c6ce9bae5e0ba96679e54c3 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 9 Oct 2015 10:26:07 -0400 Subject: [PATCH 1342/1872] Trac #19368: Clarify trivial cone/space doctest for lyapunov_like_basis(). The "trivial cone" referred to in one of the lyapunov_like_basis() doctests was really the trivial cone in a trivial space. The trivial space is the important part, and that doctest has been made clearer. A separate test was added for the trivial cone in a non-trivial space. --- src/sage/geometry/cone.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index fd599013842..68fd8ba37cc 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -4468,7 +4468,25 @@ def lyapunov_like_basis(self): EXAMPLES: - The trivial cone has no Lyapunov-like transformations:: + Every transformation is Lyapunov-like on the trivial cone:: + + sage: K = Cone([(0,0)]) + sage: M = MatrixSpace(K.lattice().base_field(), K.lattice_dim()) + sage: M.basis() == K.lyapunov_like_basis() + True + + And by duality, every transformation is Lyapunov-like on the + ambient space:: + + sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) + sage: K.is_full_space() + True + sage: M = MatrixSpace(K.lattice().base_field(), K.lattice_dim()) + sage: M.basis() == K.lyapunov_like_basis() + True + + However, in a trivial space, there are no non-trivial linear maps, + so there can be no Lyapunov-like basis:: sage: L = ToricLattice(0) sage: K = Cone([], lattice=L) @@ -4516,15 +4534,6 @@ def lyapunov_like_basis(self): [0 0 1] ] - Every transformation is Lyapunov-like on the ambient space:: - - sage: K = Cone([(1,0), (-1,0), (0,1), (0,-1)]) - sage: K.is_full_space() - True - sage: M = MatrixSpace(K.lattice().base_field(), K.lattice_dim()) - sage: M.basis() == K.lyapunov_like_basis() - True - TESTS: The vectors `L(x)` and `s` are orthogonal for every pair `(x,s)` From 47e4456b02bf7bab4fe9a828d93c5d8ba68e5132 Mon Sep 17 00:00:00 2001 From: John Cremona Date: Fri, 9 Oct 2015 16:50:46 +0100 Subject: [PATCH 1343/1872] #19382 move elliptic curve congruence graphs --- src/sage/graphs/graph.py | 34 ------------- .../elliptic_curves/ell_rational_field.py | 49 +++++++++++++++++++ 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 56282c0c86e..51e908ed23b 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -689,11 +689,6 @@ class Graph(GenericGraph): column C for each edge, where if C represents {i, j}, C[i] is -1 and C[j] is 1 - - ``'elliptic_curve_congruence'`` - data must be an - iterable container of elliptic curves, and the graph produced has - each curve as a vertex (it's Cremona label) and an edge E-F - labelled p if and only if E is congruent to F mod p - - ``NX`` - data must be a NetworkX Graph. .. NOTE:: @@ -1599,35 +1594,6 @@ def __init__(self, data=None, pos=None, loops=None, format=None, 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] - F = curves[j] - M = E.conductor() - N = F.conductor() - MN = lcm(M, N) - p_MN = prime_divisors(MN) - lim = prod([(j^(MN.ord(j)) + j^(MN.ord(j)-1)) for j in p_MN]) - a_E = E.anlist(lim) - a_F = F.anlist(lim) - l_list = [p for p in prime_range(lim) if p not in p_MN ] - p_edges = l_list - for l in l_list: - n = a_E[l] - a_F[l] - if n != 0: - P = prime_divisors(n) - 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, check=False) diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index d605573bf3a..390b7b95434 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -6996,3 +6996,52 @@ def is_approx_integral(P): return xs +def elliptic_curve_congruence_graph(curves): + r""" + Return the congruence graph for this set of elliptic curves. + + INPUT: + + - ``curves`` - a list of elliptic curves + + OUTPUT: + + The graph with each curve as a vertex (labelled by its Cremona + label) and an edge from E to F labelled p if and only if E is + congruent to F mod p + + EXAMPLE:: + + sage: from sage.schemes.elliptic_curves.ell_rational_field import elliptic_curve_congruence_graph + sage: curves = list(cremona_optimal_curves([11..30])) + sage: G = elliptic_curve_congruence_graph(curves) + sage: G + Graph on 12 vertices + """ + from sage.graphs.graph import Graph + from sage.rings.arith import lcm, prime_divisors + from sage.rings.fast_arith import prime_range + from sage.misc.all import prod + G = Graph() + G.add_vertices([curve.cremona_label() for curve in curves]) + n = len(curves) + for i in xrange(n): + E = curves[i] + M = E.conductor() + for j in xrange(i): + F = curves[j] + N = F.conductor() + MN = lcm(M, N) + lim = prod([(p-1)*p**(e-1) for p,e in MN.factor()]) + a_E = E.anlist(lim) + a_F = F.anlist(lim) + l_list = [p for p in prime_range(lim) if not p.divides(MN) ] + p_edges = l_list + for l in l_list: + n = a_E[l] - a_F[l] + if n != 0: + p_edges = [p for p in p_edges if p.divides(n)] + if len(p_edges) > 0: + G.add_edge(E.cremona_label(), F.cremona_label()) + G.set_edge_label(i,j,str(p_edges)[1:-1]) + return G From 5d04759b9631a3cb6b66920a82b09d72187dea3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 9 Oct 2015 18:22:54 +0200 Subject: [PATCH 1344/1872] trac #19379 reviewer's comments, done --- src/sage/dynamics/interval_exchanges/template.py | 16 ++++++++-------- src/sage/matroids/lean_matrix.pyx | 10 +++++----- src/sage/tensor/differential_form_element.py | 7 ++++--- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/sage/dynamics/interval_exchanges/template.py b/src/sage/dynamics/interval_exchanges/template.py index 57cb4ada51c..8d9ee2fd7f9 100644 --- a/src/sage/dynamics/interval_exchanges/template.py +++ b/src/sage/dynamics/interval_exchanges/template.py @@ -251,7 +251,7 @@ class Permutation(SageObject): r""" Template for all permutations. - .. warning:: + .. WARNING:: Internal class! Do not use directly! @@ -790,7 +790,7 @@ class PermutationIET(Permutation): """ Template for permutation from Interval Exchange Transformation. - .. warning:: + .. WARNING:: Internal class! Do not use directly! @@ -1582,7 +1582,7 @@ class PermutationLI(Permutation): r""" Template for quadratic permutation. - .. warning:: + .. WARNING:: Internal class! Do not use directly! @@ -1857,7 +1857,7 @@ class FlippedPermutation(Permutation): r""" Template for flipped generalized permutations. - .. warning:: + .. WARNING:: Internal class! Do not use directly! @@ -1916,7 +1916,7 @@ class FlippedPermutationIET(FlippedPermutation, PermutationIET): r""" Template for flipped Abelian permutations. - .. warning:: + .. WARNING:: Internal class! Do not use directly! @@ -1945,7 +1945,7 @@ class FlippedPermutationLI(FlippedPermutation, PermutationLI): r""" Template for flipped quadratic permutations. - .. warning:: + .. WARNING:: Internal class! Do not use directly! @@ -1981,7 +1981,7 @@ class RauzyDiagram(SageObject): r""" Template for Rauzy diagrams. - .. warning:: + .. WARNING:: Internal class! Do not use directly! @@ -3532,7 +3532,7 @@ class FlippedRauzyDiagram(RauzyDiagram): r""" Template for flipped Rauzy diagrams. - .. warning: + .. WARNING:: Internal class! Do not use directly! diff --git a/src/sage/matroids/lean_matrix.pyx b/src/sage/matroids/lean_matrix.pyx index 715888bc68e..2c920b21519 100644 --- a/src/sage/matroids/lean_matrix.pyx +++ b/src/sage/matroids/lean_matrix.pyx @@ -741,7 +741,7 @@ cdef class GenericMatrix(LeanMatrix): def __repr__(self): """ - Print representation. + Return representation. EXAMPLES:: @@ -1040,7 +1040,7 @@ cdef class BinaryMatrix(LeanMatrix): def __repr__(self): r""" - Print representation string + Return representation string EXAMPLES:: @@ -1667,7 +1667,7 @@ cdef class TernaryMatrix(LeanMatrix): def __repr__(self): r""" - Print representation string + Return representation string EXAMPLES:: @@ -2242,7 +2242,7 @@ cdef class QuaternaryMatrix(LeanMatrix): def __repr__(self): r""" - Print representation string + Return representation string EXAMPLES:: @@ -2829,7 +2829,7 @@ cdef class IntegerMatrix(LeanMatrix): def __repr__(self): """ - Print representation. + Return representation. EXAMPLES:: diff --git a/src/sage/tensor/differential_form_element.py b/src/sage/tensor/differential_form_element.py index de7e36523e3..87abcc47173 100644 --- a/src/sage/tensor/differential_form_element.py +++ b/src/sage/tensor/differential_form_element.py @@ -44,7 +44,7 @@ def sort_subscript(subscript): INPUT: - ``subscript`` -- a subscript, i.e. a range of not necessarily - distinct integers + distinct integers OUTPUT: @@ -402,7 +402,7 @@ def __getitem__(self, subscript): INPUT: - - ``subscript``: subscript of the component. Must be an integer + - ``subscript`` -- subscript of the component. Must be an integer or a list of integers. EXAMPLES:: @@ -450,7 +450,8 @@ def __setitem__(self, subscript, fun): INPUT: - - ``subscript``: subscript of the component. Must be an integer or a list of integers. + - ``subscript`` -- subscript of the component. Must be an integer + or a list of integers. EXAMPLES:: From 0cded598ebe90e7aaa73d595069c9d7b8f0f1770 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 09:33:29 +0200 Subject: [PATCH 1345/1872] trac #19381: A new module --- src/doc/en/reference/graphs/index.rst | 1 + src/sage/graphs/graph_input.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/sage/graphs/graph_input.py diff --git a/src/doc/en/reference/graphs/index.rst b/src/doc/en/reference/graphs/index.rst index f71db685e66..a27c03f556a 100644 --- a/src/doc/en/reference/graphs/index.rst +++ b/src/doc/en/reference/graphs/index.rst @@ -91,6 +91,7 @@ Libraries of algorithms sage/graphs/graph_latex sage/graphs/graph_editor sage/graphs/graph_list + sage/graphs/graph_input sage/graphs/hyperbolicity sage/graphs/tutte_polynomial sage/graphs/generic_graph_pyx diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py new file mode 100644 index 00000000000..a487fcb87f4 --- /dev/null +++ b/src/sage/graphs/graph_input.py @@ -0,0 +1,17 @@ +r""" +Functions for reading/building graphs/digraphs. + +This module gathers functions needed to build a graph from any other data. + + Note that because they are called by the constructors of :class:`Graph` and +:class:`DiGraph`, most of these functions modify a graph inplace. + +Functions +--------- + +""" + + +from sage.misc.rest_index_of_methods import gen_rest_table_index +import sys +__doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__])) From 5da21ca8331c9332be9e491dc06854c24e1e1cf7 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 09:58:17 +0200 Subject: [PATCH 1346/1872] trac #19381: graph6 --- src/sage/graphs/graph.py | 22 ++--------------- src/sage/graphs/graph_input.py | 45 +++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 56282c0c86e..f8bf86a25e2 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1267,26 +1267,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if weighted is None: weighted = 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') - if n == -1: - n = len(data) - ss = data[: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)) - elif len(m) < expected: - raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too short."%(ss,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 + from graph_input import from_graph6 + from_graph6(self, data) elif format == 'sparse6': if weighted is None: weighted = False diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index a487fcb87f4..a629706b966 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -3,14 +3,57 @@ This module gathers functions needed to build a graph from any other data. - Note that because they are called by the constructors of :class:`Graph` and +Note that because they are called by the constructors of :class:`Graph` and :class:`DiGraph`, most of these functions modify a graph inplace. +{INDEX_OF_FUNCTIONS} + Functions --------- """ +def from_graph6(G, g6_string): + r""" + Fill ``G`` with the data of a graph6 string. + + INPUT: + + - ``G`` -- a graph + + - ``g6_string`` -- a graph6 string + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_graph6 + sage: g = Graph() + sage: from_graph6(g, 'IheA@GUAo') + sage: g.is_isomorphic(graphs.PetersenGraph()) + True + + """ + from generic_graph_pyx import length_and_string_from_graph6, binary_string_from_graph6 + + if not isinstance(g6_string, str): + raise ValueError('If input format is graph6, then g6_string must be a string.') + n = g6_string.find('\n') + if n == -1: + n = len(g6_string) + ss = g6_string[:n] + n, s = length_and_string_from_graph6(ss) + m = 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)) + elif len(m) < expected: + raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too short."%(ss,n)) + G.add_vertices(range(n)) + k = 0 + for i in xrange(n): + for j in xrange(i): + if m[k] == '1': + G._backend.add_edge(i, j, None, False) + k += 1 from sage.misc.rest_index_of_methods import gen_rest_table_index import sys From 7a33fad6c1d0c4d754c7c525d97a2865ba57b22f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 10:05:42 +0200 Subject: [PATCH 1347/1872] trac #19381: sparse6 --- src/sage/graphs/graph.py | 35 ++--------------------- src/sage/graphs/graph_input.py | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 32 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index f8bf86a25e2..3469517ab15 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1274,38 +1274,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if weighted is None: weighted = False 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') - if n == -1: - n = len(data) - s = data[:n] - n, s = generic_graph_pyx.length_and_string_from_graph6(s[1:]) - if n == 0: - edges = [] - else: - k = int(ceil(log(n,2))) - 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.int_to_binary_string(o-63).zfill(6) for o in ords]) - b = [] - x = [] - for i in xrange(int(floor(len(bits)/(k+1)))): - b.append(int(bits[(k+1)*i:(k+1)*i+1],2)) - x.append(int(bits[(k+1)*i+1:(k+1)*i+k+1],2)) - v = 0 - edges = [] - for i in xrange(len(b)): - if b[i] == 1: - v += 1 - if x[i] > v: - v = x[i] - else: - if v < n: - edges.append((x[i],v)) - self.add_vertices(range(n)) - self.add_edges(edges) + from graph_input import from_sparse6 + from_sparse6(self, data) + elif format == 'adjacency_matrix': assert is_Matrix(data) # note: the adjacency matrix might be weighted and hence not diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index a629706b966..668e63008f0 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -55,6 +55,58 @@ def from_graph6(G, g6_string): G._backend.add_edge(i, j, None, False) k += 1 +def from_sparse6(G, g6_string): + r""" + Fill ``G`` with the data of a sparse6 string. + + INPUT: + + - ``G`` -- a graph + + - ``g6_string`` -- a sparse6 string + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_sparse6 + sage: g = Graph() + sage: from_sparse6(g, ':I`ES@obGkqegW~') + sage: g.is_isomorphic(graphs.PetersenGraph()) + True + """ + from generic_graph_pyx import length_and_string_from_graph6, int_to_binary_string + from math import ceil, floor + from sage.misc.functional import log + n = g6_string.find('\n') + if n == -1: + n = len(g6_string) + s = g6_string[:n] + n, s = length_and_string_from_graph6(s[1:]) + if n == 0: + edges = [] + else: + k = int(ceil(log(n,2))) + 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([int_to_binary_string(o-63).zfill(6) for o in ords]) + b = [] + x = [] + for i in xrange(int(floor(len(bits)/(k+1)))): + b.append(int(bits[(k+1)*i:(k+1)*i+1],2)) + x.append(int(bits[(k+1)*i+1:(k+1)*i+k+1],2)) + v = 0 + edges = [] + for i in xrange(len(b)): + if b[i] == 1: + v += 1 + if x[i] > v: + v = x[i] + else: + if v < n: + edges.append((x[i],v)) + G.add_vertices(range(n)) + G.add_edges(edges) + from sage.misc.rest_index_of_methods import gen_rest_table_index import sys __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__])) From efb842b6b5d15780c892f45d76baaea97e684cc4 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 10:08:22 +0200 Subject: [PATCH 1348/1872] trac #19381: disclaimer --- src/sage/graphs/graph_input.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 668e63008f0..95691855ccd 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -3,6 +3,12 @@ This module gathers functions needed to build a graph from any other data. +.. NOTE:: + + This is a **internal** module of Sage. All features implemented here are + made available to end-users through the constructors of :class:`Graph` and + :class:`DiGraph`. + Note that because they are called by the constructors of :class:`Graph` and :class:`DiGraph`, most of these functions modify a graph inplace. From d9522bbcaca763cf89a3c81f47cc2126e38b35a1 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 10:20:40 +0200 Subject: [PATCH 1349/1872] trac #19381: seidel adjacency matrix --- src/sage/graphs/graph.py | 34 +++--------------------- src/sage/graphs/graph_input.py | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 3469517ab15..afe35c4eb1b 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1370,39 +1370,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.add_vertices(range(data.nrows())) self.add_edges(positions) elif format == 'seidel_adjacency_matrix': - assert is_Matrix(data) - if data.base_ring() != ZZ: - try: - data = data.change_ring(ZZ) - except TypeError: - raise ValueError("Graph's Seidel adjacency matrix must"+ - " have only 0,1,-1 integer entries") - - if data.is_sparse(): - entries = set(data[i,j] for i,j in data.nonzero_positions()) - else: - entries = set(data.list()) - - if any(e < -1 or e > 1 for e in entries): - raise ValueError("Graph's Seidel adjacency matrix must"+ - " have only 0,1,-1 integer entries") - if any(i==j for i,j in data.nonzero_positions()): - raise ValueError("Graph's Seidel adjacency matrix must"+ - " have 0s on the main diagonal") - if not data.is_symmetric(): - raise ValueError("Graph's Seidel adjacency matrix must"+ - " be symmetric") multiedges = False weighted = False loops = False - self.allow_loops(False) - self.allow_multiple_edges(False) - self.add_vertices(range(data.nrows())) - e = [] - for i,j in data.nonzero_positions(): - if i <= j and data[i,j] < 0: - e.append((i,j)) - self.add_edges(e) + G.allow_loops(False) + G.allow_multiple_edges(False) + from graph_input import from_seidel_adjacency_matrix + from_seidel_adjacency_matrix(self, data) elif format == 'Graph': if loops is None: loops = data.allows_loops() if multiedges is None: multiedges = data.allows_multiple_edges() diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 95691855ccd..5c283d33b2f 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -113,6 +113,54 @@ def from_sparse6(G, g6_string): G.add_vertices(range(n)) G.add_edges(edges) +def from_seidel_adjacency_matrix(G, g6_string): + r""" + Fill ``G`` with the data of a Seidel adjacency matrix. + + INPUT: + + - ``G`` -- a graph + + - ``M`` -- a Seidel adjacency matrix + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_seidel_adjacency_matrix + sage: g = Graph() + sage: from_seidel_adjacency_matrix(g, ':I`ES@obGkqegW~') + sage: g.is_isomorphic(graphs.PetersenGraph()) + True + """ + assert is_Matrix(data) + if data.base_ring() != ZZ: + try: + data = data.change_ring(ZZ) + except TypeError: + raise ValueError("Graph's Seidel adjacency matrix must"+ + " have only 0,1,-1 integer entries") + + if data.is_sparse(): + entries = set(data[i,j] for i,j in data.nonzero_positions()) + else: + entries = set(data.list()) + + if any(e < -1 or e > 1 for e in entries): + raise ValueError("Graph's Seidel adjacency matrix must"+ + " have only 0,1,-1 integer entries") + if any(i==j for i,j in data.nonzero_positions()): + raise ValueError("Graph's Seidel adjacency matrix must"+ + " have 0s on the main diagonal") + if not data.is_symmetric(): + raise ValueError("Graph's Seidel adjacency matrix must"+ + " be symmetric") + G.add_vertices(range(data.nrows())) + e = [] + for i,j in data.nonzero_positions(): + if i <= j and data[i,j] < 0: + e.append((i,j)) + G.add_edges(e) + + from sage.misc.rest_index_of_methods import gen_rest_table_index import sys __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__])) From f0f8ee4cff832d33e43549d2f182d86e09d321dc Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 11:10:45 +0200 Subject: [PATCH 1350/1872] trac #19381: adjacency matrix --- src/sage/graphs/graph.py | 58 ++----------------------- src/sage/graphs/graph_input.py | 78 ++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 55 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index afe35c4eb1b..d79e4db04bc 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1278,61 +1278,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, from_sparse6(self, data) elif format == 'adjacency_matrix': - assert is_Matrix(data) - # note: the adjacency matrix might be weighted and hence not - # necessarily consists of integers - if not weighted and data.base_ring() != ZZ: - try: - data = data.change_ring(ZZ) - except TypeError: - if weighted is False: - raise ValueError("Non-weighted graph's"+ - " adjacency matrix must have only nonnegative"+ - " integer entries") - weighted = True - - if data.is_sparse(): - entries = set(data[i,j] for i,j in data.nonzero_positions()) - else: - entries = set(data.list()) - - if not weighted and any(e < 0 for e in entries): - if weighted is False: - raise ValueError("Non-weighted digraph's"+ - " adjacency matrix must have only nonnegative"+ - " integer entries") - weighted = True - if multiedges is None: multiedges = False - if weighted is None: - weighted = False - - if multiedges is None: - multiedges = ((not weighted) and any(e != 0 and e != 1 for e in entries)) + from graph_input import from_adjacency_matrix + from_adjacency_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) - if not loops and any(data[i,i] for i in xrange(data.nrows())): - if loops is False: - raise ValueError("Non-looped digraph's adjacency"+ - " matrix must have zeroes on the diagonal.") - loops = True - if loops is None: - loops = False - 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) @@ -1579,7 +1527,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, raise ValueError("Unknown input format '{}'".format(format)) if weighted is None: weighted = False - self._weighted = weighted + self._weighted = getattr(self,'_weighted',weighted) self._pos = pos diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 5c283d33b2f..7665af3b419 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -160,6 +160,84 @@ def from_seidel_adjacency_matrix(G, g6_string): e.append((i,j)) G.add_edges(e) +def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): + r""" + Fill ``G`` with the data of an adjacency matrix. + + INPUT: + + - ``G`` -- a graph + + - ``M`` -- an adjacency matrix + + - ``loops``, ``multiedges``, ``weighted`` (booleans) -- whether to consider + the graph as having loops, multiple edges, or weights. Set to ``False`` by default. + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_adjacency_matrix + sage: g = Graph() + sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix()) + sage: g.is_isomorphic(graphs.PetersenGraph()) + True + """ + assert is_Matrix(M) + # note: the adjacency matrix might be weighted and hence not + # necessarily consists of integers + if not weighted and M.base_ring() != ZZ: + try: + M = M.change_ring(ZZ) + except TypeError: + if weighted is False: + raise ValueError("Non-weighted graph's"+ + " adjacency matrix must have only nonnegative"+ + " integer entries") + weighted = True + + if M.is_sparse(): + entries = set(M[i,j] for i,j in M.nonzero_positions()) + else: + entries = set(M.list()) + + if not weighted and any(e < 0 for e in entries): + if weighted is False: + raise ValueError("Non-weighted digraph's"+ + " adjacency matrix must have only nonnegative"+ + " integer entries") + weighted = True + if multiedges is None: multiedges = False + if weighted is None: + weighted = False + + if multiedges is None: + multiedges = ((not weighted) and any(e != 0 and e != 1 for e in entries)) + + if not loops and any(M[i,i] for i in xrange(M.nrows())): + if loops is False: + raise ValueError("Non-looped digraph's adjacency"+ + " matrix must have zeroes on the diagonal.") + loops = True + if loops is None: + loops = False + G.allow_loops(loops, check=False) + G.allow_multiple_edges(multiedges, check=False) + G.add_vertices(range(M.nrows())) + e = [] + if weighted: + for i,j in M.nonzero_positions(): + if i <= j: + e.append((i,j,M[i][j])) + elif multiedges: + for i,j in M.nonzero_positions(): + if i <= j: + e += [(i,j)]*int(M[i][j]) + else: + for i,j in M.nonzero_positions(): + if i <= j: + e.append((i,j)) + G.add_edges(e) + G._weighted = weighted + from sage.misc.rest_index_of_methods import gen_rest_table_index import sys From 7a51fde66641266ec6ac91bdb0b54d82a7f6fc19 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 11:15:00 +0200 Subject: [PATCH 1351/1872] trac #19381: Fix seidel adjacency --- src/sage/graphs/graph.py | 4 ++-- src/sage/graphs/graph_input.py | 31 ++++++++++++++++++------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index d79e4db04bc..214b02edc19 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1321,8 +1321,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, multiedges = False weighted = False loops = False - G.allow_loops(False) - G.allow_multiple_edges(False) + self.allow_loops(False) + self.allow_multiple_edges(False) from graph_input import from_seidel_adjacency_matrix from_seidel_adjacency_matrix(self, data) elif format == 'Graph': diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 7665af3b419..2b190335bfe 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -113,7 +113,7 @@ def from_sparse6(G, g6_string): G.add_vertices(range(n)) G.add_edges(edges) -def from_seidel_adjacency_matrix(G, g6_string): +def from_seidel_adjacency_matrix(G, M): r""" Fill ``G`` with the data of a Seidel adjacency matrix. @@ -127,36 +127,39 @@ def from_seidel_adjacency_matrix(G, g6_string): sage: from sage.graphs.graph_input import from_seidel_adjacency_matrix sage: g = Graph() - sage: from_seidel_adjacency_matrix(g, ':I`ES@obGkqegW~') + sage: from_seidel_adjacency_matrix(g, graphs.PetersenGraph().seidel_adjacency_matrix()) sage: g.is_isomorphic(graphs.PetersenGraph()) True """ - assert is_Matrix(data) - if data.base_ring() != ZZ: + from sage.matrix.matrix import is_Matrix + from sage.rings.integer_ring import ZZ + assert is_Matrix(M) + + if M.base_ring() != ZZ: try: - data = data.change_ring(ZZ) + M = M.change_ring(ZZ) except TypeError: raise ValueError("Graph's Seidel adjacency matrix must"+ " have only 0,1,-1 integer entries") - if data.is_sparse(): - entries = set(data[i,j] for i,j in data.nonzero_positions()) + if M.is_sparse(): + entries = set(M[i,j] for i,j in M.nonzero_positions()) else: - entries = set(data.list()) + entries = set(M.list()) if any(e < -1 or e > 1 for e in entries): raise ValueError("Graph's Seidel adjacency matrix must"+ " have only 0,1,-1 integer entries") - if any(i==j for i,j in data.nonzero_positions()): + if any(i==j for i,j in M.nonzero_positions()): raise ValueError("Graph's Seidel adjacency matrix must"+ " have 0s on the main diagonal") - if not data.is_symmetric(): + if not M.is_symmetric(): raise ValueError("Graph's Seidel adjacency matrix must"+ " be symmetric") - G.add_vertices(range(data.nrows())) + G.add_vertices(range(M.nrows())) e = [] - for i,j in data.nonzero_positions(): - if i <= j and data[i,j] < 0: + for i,j in M.nonzero_positions(): + if i <= j and M[i,j] < 0: e.append((i,j)) G.add_edges(e) @@ -181,6 +184,8 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): sage: g.is_isomorphic(graphs.PetersenGraph()) True """ + from sage.matrix.matrix import is_Matrix + from sage.rings.integer_ring import ZZ assert is_Matrix(M) # note: the adjacency matrix might be weighted and hence not # necessarily consists of integers From 5abbd4b53f337acd89738db4a3a067c2b54618d5 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 12:07:09 +0200 Subject: [PATCH 1352/1872] trac #19381: Incidence matrix --- src/sage/graphs/graph.py | 51 ++++-------------------------- src/sage/graphs/graph_input.py | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 45 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 214b02edc19..10a0730c476 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -898,9 +898,7 @@ class Graph(GenericGraph): sage: Graph(Matrix([[1],[1],[1]])) Traceback (most recent call last): ... - ValueError: Non-symmetric or non-square matrix assumed to be an - incidence matrix: There must be one or two nonzero entries per - column. Got entries [1, 1, 1] in column 0 + ValueError: There must be one or two nonzero entries per column in an incidence matrix. Got entries [1, 1, 1] in column 0 sage: Graph(Matrix([[1],[1],[0]])) Graph on 3 vertices @@ -918,9 +916,7 @@ class Graph(GenericGraph): sage: Graph(M) Traceback (most recent call last): ... - ValueError: Non-symmetric or non-square matrix assumed to be an - incidence matrix: There must be one or two nonzero entries per - column. Got entries [1, 1] in column 2 + ValueError: There must be one or two nonzero entries per column in an incidence matrix. Got entries [1, 1] in column 2 Check that :trac:`9714` is fixed:: @@ -1140,9 +1136,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: Graph(matrix([[1,1],[1,1],[1,0]])) Traceback (most recent call last): ... - ValueError: Non-symmetric or non-square matrix assumed to be an - incidence matrix: There must be one or two nonzero entries per - column. Got entries [1, 1, 1] in column 0 + ValueError: There must be one or two nonzero entries per column in an incidence matrix. Got entries [1, 1, 1] in column 0 sage: Graph(matrix([[3,1,1],[0,1,1]])) Traceback (most recent call last): ... @@ -1150,7 +1144,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, to 2, but column 0 does not """ GenericGraph.__init__(self) - msg = '' + from sage.structure.element import is_Matrix if sparse is False: @@ -1201,7 +1195,6 @@ def __init__(self, data=None, pos=None, loops=None, format=None, format = 'adjacency_matrix' else: format = 'incidence_matrix' - msg += "Non-symmetric or non-square matrix assumed to be an incidence matrix: " if format is None and isinstance(data, Graph): format = 'Graph' from sage.graphs.all import DiGraph @@ -1282,41 +1275,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, from_adjacency_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) elif format == 'incidence_matrix': - assert is_Matrix(data) - - oriented = any(data[pos] < 0 for pos in data.nonzero_positions(copy=False)) - - positions = [] - for i in range(data.ncols()): - NZ = data.nonzero_positions_in_column(i) - if len(NZ) == 1: - if oriented: - raise ValueError("Column {} of the (oriented) incidence " - "matrix contains only one nonzero value".format(i)) - elif data[NZ[0],i] != 2: - raise ValueError("Each column of a non-oriented incidence " - "matrix must sum to 2, but column {} does not".format(i)) - if loops is None: - loops = True - positions.append((NZ[0],NZ[0])) - elif len(NZ) != 2 or \ - (oriented and not ((data[NZ[0],i] == +1 and data[NZ[1],i] == -1) or \ - (data[NZ[0],i] == -1 and data[NZ[1],i] == +1))) or \ - (not oriented and (data[NZ[0],i] != 1 or data[NZ[1],i] != 1)): - msg += "There must be one or two nonzero entries per column. " - msg += "Got entries {} in column {}".format([data[j,i] for j in NZ], i) - raise ValueError(msg) - else: - positions.append(tuple(NZ)) + from graph_input import from_incidence_matrix + from_incidence_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) - if weighted is None: weighted = False - if multiedges is None: - total = len(positions) - multiedges = (len(set(positions)) < total ) - self.allow_loops(False if loops is None else loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - self.add_vertices(range(data.nrows())) - self.add_edges(positions) elif format == 'seidel_adjacency_matrix': multiedges = False weighted = False diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 2b190335bfe..22ed464d5f4 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -243,6 +243,63 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): G.add_edges(e) G._weighted = weighted +def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): + r""" + Fill ``G`` with the data of an incidence matrix. + + INPUT: + + - ``G`` -- a graph + + - ``M`` -- an incidence matrix + + - ``loops``, ``multiedges``, ``weighted`` (booleans) -- whether to consider + the graph as having loops, multiple edges, or weights. Set to ``False`` by default. + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_incidence_matrix + sage: g = Graph() + sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix()) + sage: g.is_isomorphic(graphs.PetersenGraph()) + True + """ + from sage.matrix.matrix import is_Matrix + assert is_Matrix(M) + + oriented = any(M[pos] < 0 for pos in M.nonzero_positions(copy=False)) + + positions = [] + for i in range(M.ncols()): + NZ = M.nonzero_positions_in_column(i) + if len(NZ) == 1: + if oriented: + raise ValueError("Column {} of the (oriented) incidence " + "matrix contains only one nonzero value".format(i)) + elif M[NZ[0],i] != 2: + raise ValueError("Each column of a non-oriented incidence " + "matrix must sum to 2, but column {} does not".format(i)) + if loops is None: + loops = True + positions.append((NZ[0],NZ[0])) + elif len(NZ) != 2 or \ + (oriented and not ((M[NZ[0],i] == +1 and M[NZ[1],i] == -1) or \ + (M[NZ[0],i] == -1 and M[NZ[1],i] == +1))) or \ + (not oriented and (M[NZ[0],i] != 1 or M[NZ[1],i] != 1)): + msg = "There must be one or two nonzero entries per column in an incidence matrix. " + msg += "Got entries {} in column {}".format([M[j,i] for j in NZ], i) + raise ValueError(msg) + else: + positions.append(tuple(NZ)) + + if weighted is None: G._weighted = False + if multiedges is None: + total = len(positions) + multiedges = (len(set(positions)) < total ) + G.allow_loops(False if loops is None else loops, check=False) + G.allow_multiple_edges(multiedges, check=False) + G.add_vertices(range(M.nrows())) + G.add_edges(positions) from sage.misc.rest_index_of_methods import gen_rest_table_index import sys From cf7f5159941c63f64d54912c8bc97f5ec56235ac Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 12:25:22 +0200 Subject: [PATCH 1353/1872] trac #19381: dict_of_dicts --- src/sage/graphs/graph.py | 53 ++----------------------- src/sage/graphs/graph_input.py | 72 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 50 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 10a0730c476..436efca493f 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1344,57 +1344,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, 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') + from graph_input import from_dict_of_dicts + from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, + convert_empty_dict_labels_to_None = False if convert_empty_dict_labels_to_None is None else convert_empty_dict_labels_to_None) - if not all(isinstance(data[u], dict) for u in data): - raise ValueError("Input dict must be a consistent format.") - - if not loops and any(u in neighb for u,neighb in data.iteritems()): - if loops is False: - u = next(u for u,neighb in data.iteritems() if u in neighb) - raise ValueError("The graph was built with loops=False but input data has a loop at {}.".format(u)) - loops = True - if loops is None: - loops = False - - if weighted is None: weighted = False - for u in data: - for v in data[u]: - if hash(u) > hash(v): - if v in data and u in data[v]: - if data[u][v] != data[v][u]: - raise ValueError("Dict does not agree on edge (%s,%s)"%(u,v)) - continue - if multiedges is not False and not isinstance(data[u][v], list): - if multiedges is None: multiedges = False - if multiedges: - 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()) - 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.") diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 22ed464d5f4..9a35a2812fd 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -301,6 +301,78 @@ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): G.add_vertices(range(M.nrows())) G.add_edges(positions) +def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, convert_empty_dict_labels_to_None=False): + r""" + Fill ``G`` with the data of a dictionary of dictionaries. + + INPUT: + + - ``G`` -- a graph + + - ``M`` -- a dictionary of dictionaries. + + - ``loops``, ``multiedges``, ``weighted`` (booleans) -- whether to consider + the graph as having loops, multiple edges, or weights. Set to ``False`` by default. + + - ``convert_empty_dict_labels_to_None`` (boolean) -- whether to adjust for + empty dicts instead of None in NetworkX default edge labels. + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_dict_of_dicts + sage: g = Graph() + sage: from_dict_of_dicts(g, graphs.PetersenGraph().to_dictionary()) + sage: g.is_isomorphic(graphs.PetersenGraph()) + True + """ + if not all(isinstance(M[u], dict) for u in M): + raise ValueError("Input dict must be a consistent format.") + + if not loops and any(u in neighb for u,neighb in M.iteritems()): + if loops is False: + u = next(u for u,neighb in M.iteritems() if u in neighb) + raise ValueError("The graph was built with loops=False but input M has a loop at {}.".format(u)) + loops = True + if loops is None: + loops = False + + if weighted is None: G._weighted = False + for u in M: + for v in M[u]: + if hash(u) > hash(v): + if v in M and u in M[v]: + if M[u][v] != M[v][u]: + raise ValueError("Dict does not agree on edge (%s,%s)"%(u,v)) + continue + if multiedges is not False and not isinstance(M[u][v], list): + if multiedges is None: multiedges = False + if multiedges: + raise ValueError("Dict of dicts for multigraph must be in the format {v : {u : list}}") + if multiedges is None and len(M) > 0: + multiedges = True + G.allow_loops(loops, check=False) + G.allow_multiple_edges(multiedges, check=False) + verts = set().union(M.keys(), *M.values()) + G.add_vertices(verts) + if convert_empty_dict_labels_to_None: + for u in M: + for v in M[u]: + if hash(u) <= hash(v) or v not in M or u not in M[v]: + if multiedges: + for l in M[u][v]: + G._backend.add_edge(u,v,l,False) + else: + G._backend.add_edge(u,v,M[u][v] if M[u][v] != {} else None,False) + else: + for u in M: + for v in M[u]: + if hash(u) <= hash(v) or v not in M or u not in M[v]: + if multiedges: + for l in M[u][v]: + G._backend.add_edge(u,v,l,False) + else: + G._backend.add_edge(u,v,M[u][v],False) + from sage.misc.rest_index_of_methods import gen_rest_table_index import sys __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__])) From f9fc7a89220dced27599cec5b903c9feb26d0459 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 12:37:42 +0200 Subject: [PATCH 1354/1872] trac #19381: dict of lists --- src/sage/graphs/graph.py | 35 ++------------------- src/sage/graphs/graph_input.py | 56 +++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 436efca493f..b19a1104f47 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1349,38 +1349,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, convert_empty_dict_labels_to_None = False if convert_empty_dict_labels_to_None is None else convert_empty_dict_labels_to_None) 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.") - - verts = set().union(data.keys(),*data.values()) - if loops is None or loops is False: - for u in data: - if u in data[u]: - if loops is None: - loops = True - elif loops is False: - u = next(u for u,neighb in data.iteritems() if u in neighb) - raise ValueError("The graph was built with loops=False but input data has a loop at {}.".format(u)) - break - if loops is None: - loops = False - if weighted is None: weighted = False - for u in data: - if len(set(data[u])) != len(data[u]): - if multiedges is False: - v = next((v for v in data[u] if data[u].count(v) > 1)) - raise ValueError("Non-multigraph got several edges (%s,%s)"%(u,v)) - if multiedges is None: - multiedges = True - if multiedges is None: multiedges = False - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - self.add_vertices(verts) - 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) + from graph_input import from_dict_of_lists + from_dict_of_lists(self, data, loops=loops, multiedges=multiedges, weighted=weighted) + elif format == 'int': self.allow_loops(loops if loops else False, check=False) self.allow_multiple_edges(multiedges if multiedges else False, check=False) diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 9a35a2812fd..94e58f73be8 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -321,7 +321,7 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv sage: from sage.graphs.graph_input import from_dict_of_dicts sage: g = Graph() - sage: from_dict_of_dicts(g, graphs.PetersenGraph().to_dictionary()) + sage: from_dict_of_dicts(g, graphs.PetersenGraph().to_dictionary(edge_labels=True)) sage: g.is_isomorphic(graphs.PetersenGraph()) True """ @@ -373,6 +373,60 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv else: G._backend.add_edge(u,v,M[u][v],False) +def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False): + r""" + Fill ``G`` with the data of a dictionary of lists. + + INPUT: + + - ``G`` -- a graph + + - ``D`` -- a dictionary of lists. + + - ``loops``, ``multiedges``, ``weighted`` (booleans) -- whether to consider + the graph as having loops, multiple edges, or weights. Set to ``False`` by default. + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_dict_of_lists + sage: g = Graph() + sage: from_dict_of_lists(g, graphs.PetersenGraph().to_dictionary()) + sage: g.is_isomorphic(graphs.PetersenGraph()) + True + """ + if not all(isinstance(D[u], list) for u in D): + raise ValueError("Input dict must be a consistent format.") + + verts = set().union(D.keys(),*D.values()) + if loops is None or loops is False: + for u in D: + if u in D[u]: + if loops is None: + loops = True + elif loops is False: + u = next(u for u,neighb in D.iteritems() if u in neighb) + raise ValueError("The graph was built with loops=False but input D has a loop at {}.".format(u)) + break + if loops is None: + loops = False + if weighted is None: G._weighted = False + for u in D: + if len(set(D[u])) != len(D[u]): + if multiedges is False: + v = next((v for v in D[u] if D[u].count(v) > 1)) + raise ValueError("Non-multigraph got several edges (%s,%s)"%(u,v)) + if multiedges is None: + multiedges = True + if multiedges is None: multiedges = False + G.allow_loops(loops, check=False) + G.allow_multiple_edges(multiedges, check=False) + G.add_vertices(verts) + for u in D: + for v in D[u]: + if (multiedges or hash(u) <= hash(v) or + v not in D or u not in D[v]): + G._backend.add_edge(u,v,None,False) + from sage.misc.rest_index_of_methods import gen_rest_table_index import sys __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__])) From dd28d937cb552e4f97e764ce0e9a02c5e6073a31 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 12:46:24 +0200 Subject: [PATCH 1355/1872] trac #19381: dig6 --- src/sage/graphs/digraph.py | 25 ++++----------------- src/sage/graphs/graph_input.py | 41 +++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 3abc113977f..e4c6c2e64e4 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -676,29 +676,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # At this point, format has been set. We build the graph if format == 'dig6': - if weighted is None: weighted = False - if not isinstance(data, str): - raise ValueError('If input format is dig6, then data must be a string.') - n = data.find('\n') - if n == -1: - n = len(data) - ss = data[: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)) - elif len(m) < expected: - raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too short."%(ss,n)) + if weighted is None: self._weighted = False 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 + from graph_input import from_dig6 + from_dig6(self, data) + elif format == 'adjacency_matrix': assert is_Matrix(data) # note: the adjacency matrix might be weighted and hence not diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 94e58f73be8..f2071a4b282 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -36,7 +36,6 @@ def from_graph6(G, g6_string): sage: from_graph6(g, 'IheA@GUAo') sage: g.is_isomorphic(graphs.PetersenGraph()) True - """ from generic_graph_pyx import length_and_string_from_graph6, binary_string_from_graph6 @@ -113,6 +112,46 @@ def from_sparse6(G, g6_string): G.add_vertices(range(n)) G.add_edges(edges) +def from_dig6(G, dig6_string): + r""" + Fill ``G`` with the data of a dig6 string. + + INPUT: + + - ``G`` -- a graph + + - ``dig6_string`` -- a dig6 string + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_dig6 + sage: g = DiGraph() + sage: from_dig6(g, digraphs.Circuit(10).dig6_string()) + sage: g.is_isomorphic(digraphs.Circuit(10)) + True + """ + from generic_graph_pyx import length_and_string_from_graph6, binary_string_from_dig6 + if not isinstance(dig6_string, str): + raise ValueError('If input format is dig6, then dig6_string must be a string.') + n = dig6_string.find('\n') + if n == -1: + n = len(dig6_string) + ss = dig6_string[:n] + n, s = length_and_string_from_graph6(ss) + m = 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)) + elif len(m) < expected: + raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too short."%(ss,n)) + G.add_vertices(range(n)) + k = 0 + for i in xrange(n): + for j in xrange(n): + if m[k] == '1': + G._backend.add_edge(i, j, None, True) + k += 1 + def from_seidel_adjacency_matrix(G, M): r""" Fill ``G`` with the data of a Seidel adjacency matrix. From 9bdf527fd59509647ccefd86cbd87bb2e92071b4 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 16:29:49 +0200 Subject: [PATCH 1356/1872] trac #19381: Typo --- src/sage/graphs/graph_input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index f2071a4b282..1cec738f1c7 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -5,7 +5,7 @@ .. NOTE:: - This is a **internal** module of Sage. All features implemented here are + This is an **internal** module of Sage. All features implemented here are made available to end-users through the constructors of :class:`Graph` and :class:`DiGraph`. From 14b672decf9e60cf6a00593e15d4dcd0af5c4df2 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 9 Oct 2015 20:15:04 +0200 Subject: [PATCH 1357/1872] trac #19061: Split a line of doc --- src/sage/graphs/graph.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index ef59285c82d..61b2ede9b58 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -3204,13 +3204,12 @@ def degree_constrained_subgraph(self, bounds=None, solver=None, verbose=0): @doc_index("Connectivity, orientations, trees") def strong_orientation(self): r""" - Returns a strongly connected orientation of the current graph. See - also the :wikipedia:`Strongly_connected_component`. + Returns a strongly connected orientation of the current graph. - An orientation of an undirected graph is a digraph obtained by - giving an unique direction to each of its edges. An orientation - is said to be strong if there is a directed path between each - pair of vertices. + An orientation of an undirected graph is a digraph obtained by giving an + unique direction to each of its edges. An orientation is said to be + strong if there is a directed path between each pair of vertices. See + also the :wikipedia:`Strongly_connected_component`. If the graph is 2-edge-connected, a strongly connected orientation can be found in linear time. If the given graph is not 2-connected, From 5dfc679f85677227c372562cf29fdb77fa2b16d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 9 Oct 2015 20:16:29 +0200 Subject: [PATCH 1358/1872] trac #19357 fixing floordiv and dump in Laurent polynomials in several var --- src/sage/rings/polynomial/laurent_polynomial.pyx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 091fc1a2fb0..c96bad68969 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1332,8 +1332,11 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): sage: R. = LaurentPolynomialRing(QQ) sage: loads(dumps(x1)) == x1 # indirect doctest True + sage: z = x1/x2 + sage: loads(dumps(z)) == z + True """ - return self._parent, (self._poly,) + return self._parent, (self._poly, self._mon) cdef _new_c(self): """ @@ -1374,7 +1377,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): else: e = e.emin(k) if len(e.nonzero_positions()) > 0: - self._poly = self._poly / self._poly.parent()({e: 1}) + self._poly = self._poly // self._poly.parent()({e: 1}) self._mon = self._mon.eadd(e) else: e = None @@ -1382,7 +1385,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): if e is None or k[i] < e: e = k[i] if e > 0: - self._poly = self._poly / self._poly.parent().gen(i) + self._poly = self._poly // self._poly.parent().gen(i) self._mon = self._mon.eadd_p(e, i) def _dict(self): @@ -2047,8 +2050,15 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): x^2 - x*y^-1 + y^-2 sage: h * (f // h) == f True + + TESTS (:trac:`19357`):: + + sage: x // y + x*y^-1 """ cdef LaurentPolynomial_mpair ans = self._new_c() + self._normalize() + right._normalize() ans._mon = self._mon.esub((right)._mon) ans._poly = self._poly.__floordiv__((right)._poly) return ans From 0cc28a0202ba183faec750fa4e02083d1500e52d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 9 Oct 2015 16:47:37 -0500 Subject: [PATCH 1359/1872] Fixing some things. --- src/sage/combinat/integer_list.py | 8 ++++- src/sage/combinat/partition.py | 56 ++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/sage/combinat/integer_list.py b/src/sage/combinat/integer_list.py index b32c163abfb..774ea865bad 100644 --- a/src/sage/combinat/integer_list.py +++ b/src/sage/combinat/integer_list.py @@ -126,7 +126,8 @@ class IntegerListsLex(Parent): (default: `ClonableArray`). This merely sets the attribute ``self.Element``. See the examples for details. - - ``global_options`` -- a :class:`~sage.structure.global_options.GlobalOptions` + - ``global_options`` -- (deprecated) a + :class:`~sage.structure.global_options.GlobalOptions` object that will be assigned to the attribute ``_global_options``; for internal use only (subclasses, ...). @@ -524,6 +525,10 @@ class IntegerListsLex(Parent): in the class :class:`Partition`:: sage: IntegerListsLex(3, max_slope=0, element_class=Partition, global_options=Partitions.global_options).list() + doctest:...: DeprecationWarning: the global_options argument is + deprecated since, in general, pickling is broken; + create your own class instead + See http://trac.sagemath.org/15525 for details. [[3], [2, 1], [1, 1, 1]] Note that the :class:`Partition` further assumes the existence of @@ -943,6 +948,7 @@ def __init__(self, from sage.misc.superseded import deprecation deprecation(15525, 'the global_options argument is deprecated since, in general,' ' pickling is broken; create your own class instead') + self.global_options = global_options Parent.__init__(self, element_constructor=element_constructor, category=category) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index e4dcfb71244..362c7b86956 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -6703,9 +6703,21 @@ def __init__(self, ell, is_infinte=False): sage: P = Partitions(regular=2) sage: TestSuite(P).run() """ - self.ell = ell + self._ell = ell Partitions.__init__(self, is_infinte) + def ell(self): + r""" + Return the value `\ell`. + + EXAMPLES:: + + sage: P = Partitions(regular=2) + sage: P.ell() + 2 + """ + return self._ell + def __contains__(self, x): """ TESTS:: @@ -6731,8 +6743,8 @@ def __contains__(self, x): if not Partitions.__contains__(self, x): return False if isinstance(x, Partition): - return max(x.to_exp(1)) < self.ell - return all(x.count(i) < self.ell for i in set(x) if i > 0) + return max(x.to_exp(1)) < self._ell + return all(x.count(i) < self._ell for i in set(x) if i > 0) def _fast_iterator(self, n, max_part): """ @@ -6754,7 +6766,7 @@ def _fast_iterator(self, n, max_part): if n < max_part: max_part = n - bdry = self.ell - 1 + bdry = self._ell - 1 for i in reversed(range(1, max_part+1)): for p in self._fast_iterator(n-i, i): @@ -6792,7 +6804,7 @@ def _repr_(self): sage: RegularPartitions_all(3) 3-Regular Partitions """ - return "{}-Regular Partitions".format(self.ell) + return "{}-Regular Partitions".format(self._ell) def __iter__(self): """ @@ -6833,8 +6845,20 @@ def __init__(self, ell, max_len): sage: P = Partitions(regular=4, max_length=3) sage: TestSuite(P).run() """ - self.max_len = max_len - RegularPartitions.__init__(self, ell) + self._max_len = max_len + RegularPartitions.__init__(self, ell, True) + + def max_length(self): + """ + Return the maximum length of the partitions of ``self``. + + EXAMPLES:: + + sage: P = Partitions(regular=4, max_length=3) + sage: P.max_length() + 3 + """ + return self._max_len def __contains__(self, x): """ @@ -6848,7 +6872,7 @@ def __contains__(self, x): sage: [4, 2, 1, 1] in P False """ - return len(x) <= self.max_len and RegularPartitions.__contains__(self, x) + return len(x) <= self._max_len and RegularPartitions.__contains__(self, x) def _repr_(self): """ @@ -6858,7 +6882,7 @@ def _repr_(self): sage: RegularPartitions_truncated(4, 3) 4-Regular Partitions with max length 3 """ - return "{}-Regular Partitions with max length {}".format(self.ell, self.max_len) + return "{}-Regular Partitions with max length {}".format(self._ell, self._max_len) def __iter__(self): """ @@ -6891,19 +6915,19 @@ def _fast_iterator(self, n, max_part, depth=0): sage: list(P._fast_iterator(5, 6)) [[5], [4, 1], [3, 2]] """ - if n == 0 or depth >= self.max_len: + if n == 0 or depth >= self._max_len: yield [] return # Special case - if depth + 1 == self.max_len: + if depth + 1 == self._max_len: if max_part >= n: yield [n] return if n < max_part: max_part = n - bdry = self.ell - 1 + bdry = self._ell - 1 for i in reversed(range(1, max_part+1)): for p in self._fast_iterator(n-i, i, depth+1): @@ -6957,7 +6981,7 @@ def _repr_(self): sage: RegularPartitions_bounded(4, 3) 4-Regular 3-Bounded Partitions """ - return "{}-Regular {}-Bounded Partitions".format(self.ell, self.k) + return "{}-Regular {}-Bounded Partitions".format(self._ell, self.k) def __iter__(self): """ @@ -6970,7 +6994,7 @@ def __iter__(self): [[3, 2, 1], [3, 2], [3, 1], [3], [2, 1], [2], [1], []] """ k = self.k - for n in reversed(range(k*(k+1)/2 * self.ell)): + for n in reversed(range(k*(k+1)/2 * self._ell)): for p in self._fast_iterator(n, k): yield self.element_class(self, p) @@ -7007,7 +7031,7 @@ def _repr_(self): sage: RegularPartitions_n(3, 5) 5-Regular Partitions of the integer 3 """ - return "{}-Regular Partitions of the integer {}".format(self.ell, self.n) + return "{}-Regular Partitions of the integer {}".format(self._ell, self.n) def __contains__(self, x): """ @@ -7049,7 +7073,7 @@ def cardinality(self): sage: P.cardinality() == Partitions(5).cardinality() True """ - if self.ell > self.n: + if self._ell > self.n: return Partitions_n.cardinality(self) return ZZ.sum(1 for x in self) From 765e300aeaf9e58c34db97836bcc22bcbb40521f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 10 Oct 2015 08:38:06 +0200 Subject: [PATCH 1360/1872] trac #19357 undo the change to pickle (__reduce__) --- src/sage/rings/polynomial/laurent_polynomial.pyx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index c96bad68969..15384f60653 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1333,10 +1333,11 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): sage: loads(dumps(x1)) == x1 # indirect doctest True sage: z = x1/x2 - sage: loads(dumps(z)) == z + sage: loads(dumps(z)) == z # not tested (bug) True """ - return self._parent, (self._poly, self._mon) + # one should also record the monomial self._mon + return self._parent, (self._poly,) # THIS IS WRONG ! cdef _new_c(self): """ @@ -2051,7 +2052,9 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): sage: h * (f // h) == f True - TESTS (:trac:`19357`):: + TESTS: + + Check that :trac:`19357` is fixed:: sage: x // y x*y^-1 From fc53a493965bf3767e47be2552425fca4e70e483 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Tue, 18 Aug 2015 01:32:02 -0700 Subject: [PATCH 1361/1872] Trac 19016: Remove silly repr hash on Element and fix failures --- src/sage/categories/additive_magmas.py | 8 +++++--- src/sage/categories/magmas.py | 8 +++++--- src/sage/rings/function_field/function_field_element.pyx | 6 ++++++ src/sage/structure/element.pyx | 6 +++--- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index e84ede20193..3f990e84a0a 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -711,9 +711,11 @@ def _test_zero(self, **options): tester.assert_(self.is_parent_of(zero)) for x in tester.some_elements(): tester.assert_(x + zero == x) - # Check that zero is immutable by asking its hash: - tester.assertEqual(type(zero.__hash__()), int) - tester.assertEqual(zero.__hash__(), zero.__hash__()) + # Check that zero is immutable if it looks like we can: + if hasattr(zero,"is_immutable"): + tester.assertEqual(zero.is_immutable(),True) + if hasattr(zero,"is_mutable"): + tester.assertEqual(zero.is_mutable(),False) # Check that bool behave consistently on zero tester.assertFalse(bool(self.zero())) diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index c3f8f9ab458..42f03fc918a 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -468,9 +468,11 @@ def _test_one(self, **options): for x in tester.some_elements(): tester.assert_(x * one == x) tester.assert_(one * x == x) - # Check that one is immutable by asking its hash; - tester.assertEqual(type(one.__hash__()), int) - tester.assertEqual(one.__hash__(), one.__hash__()) + # Check that one is immutable if it looks like we can test this + if hasattr(one,"is_immutable"): + tester.assertEqual(one.is_immutable(),True) + if hasattr(one,"is_mutable"): + tester.assertEqual(one.is_mutable(),False) def is_empty(self): r""" diff --git a/src/sage/rings/function_field/function_field_element.pyx b/src/sage/rings/function_field/function_field_element.pyx index c701e7f8e39..b2dc3230839 100644 --- a/src/sage/rings/function_field/function_field_element.pyx +++ b/src/sage/rings/function_field/function_field_element.pyx @@ -361,6 +361,9 @@ cdef class FunctionFieldElement_polymod(FunctionFieldElement): """ return not not self._x + def __hash__(self): + return hash(self._x) + cpdef int _cmp_(self, Element other) except -2: """ EXAMPLES:: @@ -563,6 +566,9 @@ cdef class FunctionFieldElement_rational(FunctionFieldElement): """ return not not self._x + def __hash__(self): + return hash(self._x) + cpdef int _cmp_(self, Element other) except -2: """ EXAMPLES:: diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index b0d93cb1035..ad72a1cf532 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -526,9 +526,6 @@ cdef class Element(SageObject): pass return res - def __hash__(self): - return hash(str(self)) - def _im_gens_(self, codomain, im_gens): """ Return the image of ``self`` in codomain under the map that sends @@ -964,6 +961,9 @@ cdef class Element(SageObject): return 1 raise + def _cache_key(self): + return(self.parent(),str(self)) + cdef _richcmp(self, other, int op): """ Compare ``self`` and ``other`` using the coercion framework, From 6b14aba8ab15850a7a496094580fa81adf446cef Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 19 Aug 2015 15:20:18 +0200 Subject: [PATCH 1362/1872] Trac 19016: all test pass in combinat/crystals --- src/sage/combinat/crystals/affine.py | 24 +++++++++-- src/sage/combinat/crystals/affinization.py | 43 +++++++++---------- .../combinat/crystals/elementary_crystals.py | 24 ++++++++++- src/sage/combinat/crystals/fast_crystals.py | 37 +++++++--------- .../combinat/crystals/monomial_crystals.py | 12 ++++++ src/sage/combinat/crystals/subcrystal.py | 25 ++++++++--- 6 files changed, 110 insertions(+), 55 deletions(-) diff --git a/src/sage/combinat/crystals/affine.py b/src/sage/combinat/crystals/affine.py index 136a1873c32..08b6f3e2b4d 100644 --- a/src/sage/combinat/crystals/affine.py +++ b/src/sage/combinat/crystals/affine.py @@ -15,6 +15,7 @@ from sage.misc.abstract_method import abstract_method from sage.categories.regular_crystals import RegularCrystals from sage.categories.finite_crystals import FiniteCrystals +from sage.structure.element import parent from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper @@ -460,7 +461,7 @@ def phi(self, i): else: return self.lift().phi(i) - def __lt__(self, other): + def __eq__(self, other): """ Non elements of the crystal are incomparable with elements of the crystal (or should it return ``NotImplemented``?). Elements of this @@ -479,9 +480,24 @@ def __lt__(self, other): sage: b other.value + def __le__(self, other): + return parent(self) is parent(other) and self.value <= other.value + def __ge__(self, other): + return parent(self) is parent(other) and self.value >= other.value + + def __cmp__(self, other): + if parent(self) is parent(other): + return cmp(self.value, other.value) + else: + return cmp(parent(self), parent(other)) AffineCrystalFromClassical.Element = AffineCrystalFromClassicalElement diff --git a/src/sage/combinat/crystals/affinization.py b/src/sage/combinat/crystals/affinization.py index 3e0c1bb2713..62b1fb5c213 100644 --- a/src/sage/combinat/crystals/affinization.py +++ b/src/sage/combinat/crystals/affinization.py @@ -17,6 +17,7 @@ # http://www.gnu.org/licenses/ #**************************************************************************** +from sage.structure.element import parent from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import Element @@ -187,11 +188,23 @@ def _latex_(self): from sage.misc.latex import latex return latex(self._b) + "({})".format(self._m) - def __eq__(self, other): + def __hash__(self): + r""" + TESTS:: + + sage: A = crystals.KirillovReshetikhin(['A',2,1], 2, 2).affinization() + sage: mg = A.module_generators[0] + sage: hash(mg) + -6948036233304877976 # 64-bit + -1420700568 # 32-bit """ - Check equality. + return hash(self._b) ^ hash(self._m) - EXAMPLES:: + def __cmp__(self, other): + """ + Comparison. + + TESTS:: sage: A = crystals.KirillovReshetikhin(['A',2,1], 2, 2).affinization() sage: mg = A.module_generators[0] @@ -203,17 +216,6 @@ def __eq__(self, other): sage: A = crystals.AffinizationOf(KT) sage: A(KT.module_generators[3], 1).f(0) == A.module_generators[0] True - """ - if not isinstance(other, AffinizationOfCrystal.Element): - return False - return self.parent() == other.parent() \ - and self._b == other._b and self._m == other._m - - def __ne__(self, other): - """ - Check inequality. - - EXAMPLES:: sage: A = crystals.KirillovReshetikhin(['A',2,1], 2, 2).affinization() sage: mg = A.module_generators[0] @@ -221,14 +223,7 @@ def __ne__(self, other): True sage: mg != mg.f(2).e(2) False - """ - return not self.__eq__(other) - def __lt__(self, other): - """ - Check less than. - - EXAMPLES:: sage: A = crystals.KirillovReshetikhin(['A',2,1], 2, 2).affinization() sage: S = A.subcrystal(max_depth=2) @@ -241,8 +236,12 @@ def __lt__(self, other): [[1, 2], [2, 3]](1), [[1, 2], [3, 3]](1), [[2, 2], [3, 3]](2)] + """ - return self._m < other._m or (self._m == other._m and self._b < other._b) + if parent(self) is parent(other): + return cmp(self._m, other._m) or cmp(self._b, other._b) + else: + return cmp(parent(self), parent(other)) def e(self, i): """ diff --git a/src/sage/combinat/crystals/elementary_crystals.py b/src/sage/combinat/crystals/elementary_crystals.py index 925c11ba1f8..3745064c7b5 100644 --- a/src/sage/combinat/crystals/elementary_crystals.py +++ b/src/sage/combinat/crystals/elementary_crystals.py @@ -83,6 +83,7 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.root_system import RootSystem from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ class AbstractSingleCrystalElement(Element): r""" @@ -102,6 +103,17 @@ def __lt__(self,other): """ return False + def __hash__(self): + r""" + TESTS:: + + sage: C = crystals.elementary.Component("D7") + sage: c = C.highest_weight_vector() + sage: hash(c) # random + 879 + """ + return hash(self.parent()) + def __eq__(self,other): r""" EXAMPLES:: @@ -787,7 +799,7 @@ def _element_constructor_(self, m): sage: B(721) 721 """ - return self.element_class(self, m) + return self.element_class(self, ZZ(m)) def weight_lattice_realization(self): """ @@ -817,6 +829,16 @@ def __init__(self, parent, m): self._m = m Element.__init__(self, parent) + def __hash__(self): + r""" + TESTS:: + + sage: B = crystals.elementary.Elementary(['B',7],7) + sage: hash(B(17)) + 17 + """ + return hash(self._m) + def _repr_(self): r""" EXAMPLES:: diff --git a/src/sage/combinat/crystals/fast_crystals.py b/src/sage/combinat/crystals/fast_crystals.py index 9bf2a3ec596..7372dbd1f9d 100644 --- a/src/sage/combinat/crystals/fast_crystals.py +++ b/src/sage/combinat/crystals/fast_crystals.py @@ -364,7 +364,17 @@ def _repr_(self): else: raise NotImplementedError - def __eq__(self, other): + def __hash__(self): + r""" + TESTS:: + + sage: C = crystals.FastRankTwo(['A',2],shape=[2,1]) + sage: hash(C(0)) + 0 + """ + return hash(self.value) + + def __cmp__(self, other): """ EXAMPLES:: @@ -376,14 +386,6 @@ def __eq__(self, other): False sage: C(0) == D(0) False - """ - return self.__class__ is other.__class__ and \ - self.parent() == other.parent() and \ - self.value == other.value - - def __ne__(self, other): - """ - EXAMPLES:: sage: C = crystals.FastRankTwo(['A',2],shape=[2,1]) sage: D = crystals.FastRankTwo(['B',2],shape=[2,1]) @@ -393,13 +395,6 @@ def __ne__(self, other): True sage: C(0) != D(0) True - """ - return not self == other - - - def __cmp__(self, other): - """ - EXAMPLES:: sage: C = crystals.FastRankTwo(['A',2],shape=[2,1]) sage: C(1) < C(2) @@ -411,11 +406,10 @@ def __cmp__(self, other): sage: C(1) <= C(1) True """ - if type(self) is not type(other): - return cmp(type(self), type(other)) - if self.parent() != other.parent(): - return cmp(self.parent(), other.parent()) - return self.parent().cmp_elements(self, other) + if parent(self) is parent(other): + return cmp(self.value, other.value) + else: + return cmp(parent(self), parent(other)) def e(self, i): """ @@ -436,7 +430,6 @@ def e(self, i): r = self.parent()._rootoperators[self.value][2] return self.parent()(r) if r is not None else None - def f(self, i): """ Returns the action of `f_i` on self. diff --git a/src/sage/combinat/crystals/monomial_crystals.py b/src/sage/combinat/crystals/monomial_crystals.py index 147c9b5aecc..876a40600b7 100644 --- a/src/sage/combinat/crystals/monomial_crystals.py +++ b/src/sage/combinat/crystals/monomial_crystals.py @@ -162,6 +162,18 @@ def _repr_(self): return_str += "Y(%s,%s) "%(L[x][0][0],L[x][0][1]) return return_str + def __hash__(self): + r""" + TESTS:: + + sage: M = crystals.infinity.NakajimaMonomials(['C',5]) + sage: m1 = M.module_generators[0].f(1) + sage: hash(m1) + 4715601665014767730 # 64-bit + -512614286 # 32-bit + """ + return hash(frozenset(tuple(self._dict.iteritems()))) + def __eq__(self,other): r""" EXAMPLES:: diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index 341c3540231..ccacb83dfb5 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -25,6 +25,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element import parent from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper from sage.categories.crystals import Crystals @@ -285,7 +286,7 @@ class Element(ElementWrapper): """ An element of a subcrystal. Wraps an element in the ambient crystal. """ - def __lt__(self, other): + def __eq__(self, other): """ Check less than. @@ -307,11 +308,23 @@ def __lt__(self, other): [[-1, -1]](1), [[-1, -1]](2)] """ - if not isinstance(other, Subcrystal.Element): - return False - if other.parent() is not self.parent(): - return False - return self.value < other.value + return parent(self) is parent(other) and self.value == other.value + def __ne__(self, other): + return parent(self) is not parent(other) or self.value != other.value + def __lt__(self, other): + return parent(self) is parent(other) and self.value < other.value + def __le__(self, other): + return parent(self) is parent(other) and self.value <= other.value + def __gt__(self, other): + return parent(self) is parent(other) and self.value > other.value + def __ge__(self, other): + return parent(self) is parent(other) and self.value >= other.value + + def __cmp__(self, other): + if parent(self) is parent(other): + return cmp(self.value, other.value) + else: + return cmp(parent(self), parent(other)) def e(self, i): """ From cf1489d694224bbe6563b7837fa68615d6038a03 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 23 Aug 2015 07:54:53 -0300 Subject: [PATCH 1363/1872] Trac 19016: hash for quotient ring element --- src/sage/rings/quotient_ring_element.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index 9f681331d55..853d267a924 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -590,6 +590,18 @@ def __float__(self): """ return float(self.lift()) + def __hash__(self): + r""" + TESTS:: + + sage: R. = QQ[] + sage: S. = R.quo(x^2 + y^2) + sage: hash(a) + 15360174650385711 # 64-bit + 1505322287 # 32-bit + """ + return hash(self.__rep) + def __cmp__(self, other): """ EXAMPLES:: From a8d0fcaffaa977c297db52176041c38807cc55da Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 23 Aug 2015 15:08:13 -0300 Subject: [PATCH 1364/1872] Trac 19016: implement constant hash for ideals --- .../algebras/quatalg/quaternion_algebra.py | 12 ++++++- src/sage/rings/ideal.py | 32 +++++++++++++++++++ src/sage/rings/polynomial/ideal.py | 1 - .../polynomial/multi_polynomial_ideal.py | 12 +++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index e42bee8ae05..b591d5a18ee 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -1735,7 +1735,17 @@ def ternary_quadratic_form(self, include_basis=False): return Q class QuaternionFractionalIdeal(Ideal_fractional): - pass + def __hash__(self): + r""" + Stupid constant hash function! + + TESTS:: + + sage: R = QuaternionAlgebra(-11,-1).maximal_order() + sage: hash(R.right_ideal(R.basis())) + 0 + """ + return 0 class QuaternionFractionalIdeal_rational(QuaternionFractionalIdeal): """ diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 93b9e106461..0b9f6297e03 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -318,6 +318,22 @@ def __repr__(self): """ return "Ideal %s of %s"%(self._repr_short(), self.ring()) + def __hash__(self): + r""" + Very stupid constant hash function! + + TESTS:: + + sage: R = ZZ + sage: I = ZZ*2 + sage: J = ZZ*(-2) + sage: hash(I) + 0 + sage: hash(J) + 0 + """ + return 0 + def __cmp__(self, other): """ Compares the generators of two ideals. @@ -1229,6 +1245,22 @@ def __contains__(self, x): return x.is_zero() return self.gen().divides(x) + def __hash__(self): + r""" + Very stupid constant hash function! + + TESTS:: + + sage: P. = PolynomialRing(ZZ) + sage: I = P.ideal(x^2) + sage: J = [x, y^2 + x*y]*P + sage: hash(I) + 0 + sage: hash(J) + 0 + """ + return 0 + def __cmp__(self, other): """ Compare the two ideals. diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index a23f3e8567a..508496c75d4 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -64,4 +64,3 @@ def residue_field(self, names=None, check=True): from sage.rings.finite_rings.residue_field import ResidueField return ResidueField(self, names, check=False) - diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index da64b370cdb..deeeb17a13a 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -3013,6 +3013,18 @@ def __init__(self, ring, gens, coerce=True): Ideal_generic.__init__(self, ring, gens, coerce=coerce) self._gb_by_ordering = dict() + def __hash__(self): + r""" + Stupid constant hash function! + + TESTS:: + + sage: R. = PolynomialRing(IntegerRing(), 2, order='lex') + sage: hash(R.ideal([x, y])) + 0 + """ + return 0 + @cached_method def gens(self): """ From 33bd4a92709db4fcf35047e90bf89fea4a35cba8 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 26 Sep 2015 00:16:56 -0300 Subject: [PATCH 1365/1872] Trac 19016: change output order in documentation --- src/sage/categories/regular_crystals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index 9fa8085633b..8f46bd74ad9 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -560,7 +560,7 @@ def demazure_operator_simple(self, i, ring = None): sage: K = crystals.KirillovReshetikhin(['A',2,1],2,1) sage: t = K(rows=[[3],[2]]) sage: t.demazure_operator_simple(0) - B[[[2, 3]]] + B[[[1, 2]]] + B[[[1, 2]]] + B[[[2, 3]]] TESTS:: From cf53613abb473f53411b50bd2ddc049050cd6dbc Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 10 Oct 2015 16:07:56 +0200 Subject: [PATCH 1366/1872] trac #19385: Refactor DiGraph.__init__ --- src/sage/graphs/digraph.py | 141 +++------------------------------ src/sage/graphs/graph_input.py | 124 ++++++++++++++++++++--------- 2 files changed, 98 insertions(+), 167 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index e4c6c2e64e4..ab6e5501944 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -349,7 +349,7 @@ class DiGraph(GenericGraph): [ 0 1 -1] [ -1 0 -1/2] [ 1 1/2 0] - sage: G = DiGraph(M,sparse=True); G + sage: G = DiGraph(M,sparse=True,weighted=True); G Digraph on 3 vertices sage: G.weighted() True @@ -683,80 +683,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, from_dig6(self, data) elif format == 'adjacency_matrix': - assert is_Matrix(data) - # note: the adjacency matrix might be weighted and hence not - # necessarily consists of integers - if not weighted and data.base_ring() != ZZ: - try: - data = data.change_ring(ZZ) - except TypeError: - if weighted is False: - raise ValueError("Non-weighted graph's"+ - " adjacency matrix must have only nonnegative"+ - " integer entries") - weighted = True - - if data.is_sparse(): - entries = set(data[i,j] for i,j in data.nonzero_positions()) - else: - entries = set(data.list()) - - if not weighted and any(e < 0 for e in entries): - if weighted is False: - raise ValueError("Non-weighted digraph's"+ - " adjacency matrix must have only nonnegative"+ - " integer entries") - weighted = True - if multiedges is None: multiedges = False - if weighted is None: - weighted = False - - if multiedges is None: - multiedges = ((not weighted) and any(e != 0 and e != 1 for e in entries)) + from graph_input import from_adjacency_matrix + from_adjacency_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) - if not loops and any(data[i,i] for i in xrange(data.nrows())): - if loops is False: - raise ValueError("Non-looped digraph's adjacency"+ - " matrix must have zeroes on the diagonal.") - loops = True - 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() - if len(NZ) != 2: - msg += "There must be two nonzero entries (-1 & 1) per column." - raise ValueError(msg) - L = sorted(set(c.list())) - if L != [-1,0,1]: - msg += "Each column represents an edge: -1 goes to 1." - raise ValueError(msg) - if c[NZ[0]] == -1: - positions.append(tuple(NZ)) - else: - positions.append((NZ[1],NZ[0])) - if weighted is None: weighted = False - if multiedges is None: - total = len(positions) - multiedges = ( len(set(positions)) < total ) - 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) + from graph_input import from_oriented_incidence_matrix + from_oriented_incidence_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) + elif format == 'DiGraph': if loops is None: loops = data.allows_loops() elif not loops and data.has_loops(): @@ -784,66 +717,14 @@ def __init__(self, data=None, pos=None, loops=None, format=None, 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.") - - verts = set(data.keys()) - if loops is None or loops is False: - for u in data: - if u in data[u]: - if loops is None: - loops = True - elif loops is False: - u = next(u for u,neighb in data.iteritems() if u in neighb) - raise ValueError("The digraph was built with loops=False but input data has a loop at {}.".format(u)) - break - if loops is None: loops = False - if weighted is None: weighted = False - for u in data: - for v in data[u]: - if v not in verts: verts.add(v) - if multiedges is not False and not isinstance(data[u][v], list): - if multiedges is None: - multiedges = False - if multiedges: - 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) + from graph_input import from_dict_of_dicts + from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, + convert_empty_dict_labels_to_None = False if convert_empty_dict_labels_to_None is None else convert_empty_dict_labels_to_None) - 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): - data = {u: list(v) for u,v in data.iteritems()} - - if not loops and any(u in neighb for u,neighb in data.iteritems()): - if loops is False: - u = next(u for u,neighb in data.iteritems() if u in neighb) - raise ValueError("The digraph was built with loops=False but input data has a loop at {}.".format(u)) - loops = True - if loops is None: - loops = False - - if weighted is None: weighted = False + from graph_input import from_dict_of_lists + from_dict_of_lists(self, data, loops=loops, multiedges=multiedges, weighted=weighted) - if not multiedges and any(len(set(neighb)) != len(neighb) for neighb in data.itervalues()): - if multiedges is False: - uv = next((u,v) for u,neighb in data.iteritems() for v in neighb if neighb.count(v) > 1) - raise ValueError("Non-multidigraph got several edges (%s,%s)"%(u,v)) - 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()) - 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: diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 1cec738f1c7..cea82597dc3 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -208,7 +208,7 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): INPUT: - - ``G`` -- a graph + - ``G`` -- a :class:`Graph` or :class:`DiGraph`. - ``M`` -- an adjacency matrix @@ -267,18 +267,19 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): G.allow_multiple_edges(multiedges, check=False) G.add_vertices(range(M.nrows())) e = [] + if G.is_directed(): + pairs = M.nonzero_positions() + else: + pairs = ((i,j) for i,j in M.nonzero_positions() if i<=j) if weighted: - for i,j in M.nonzero_positions(): - if i <= j: - e.append((i,j,M[i][j])) + for i,j in pairs: + e.append((i,j,M[i][j])) elif multiedges: - for i,j in M.nonzero_positions(): - if i <= j: - e += [(i,j)]*int(M[i][j]) + for i,j in pairs: + e += [(i,j)]*int(M[i][j]) else: - for i,j in M.nonzero_positions(): - if i <= j: - e.append((i,j)) + for i,j in pairs: + e.append((i,j)) G.add_edges(e) G._weighted = weighted @@ -340,6 +341,56 @@ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): G.add_vertices(range(M.nrows())) G.add_edges(positions) +def from_oriented_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): + r""" + Fill ``G`` with the data of an *oriented* incidence matrix. + + An oriented incidence matrix is the incidence matrix of a directed graph, in + which each non-loop edge corresponds to a `+1` and a `-1`, indicating its + source and destination. + + INPUT: + + - ``G`` -- a :class:`DiGraph` + + - ``M`` -- an incidence matrix + + - ``loops``, ``multiedges``, ``weighted`` (booleans) -- whether to consider + the graph as having loops, multiple edges, or weights. Set to ``False`` by default. + + EXAMPLE:: + + sage: from sage.graphs.graph_input import from_oriented_incidence_matrix + sage: g = DiGraph() + sage: from_oriented_incidence_matrix(g, digraphs.Circuit(10).incidence_matrix()) + sage: g.is_isomorphic(digraphs.Circuit(10)) + True + """ + from sage.matrix.matrix import is_Matrix + assert is_Matrix(M) + + positions = [] + for c in M.columns(): + NZ = c.nonzero_positions() + if len(NZ) != 2: + raise ValueError("There must be two nonzero entries (-1 & 1) per column.") + L = sorted(set(c.list())) + if L != [-1,0,1]: + msg += "Each column represents an edge: -1 goes to 1." + raise ValueError(msg) + if c[NZ[0]] == -1: + positions.append(tuple(NZ)) + else: + positions.append((NZ[1],NZ[0])) + if weighted is None: weighted = False + if multiedges is None: + total = len(positions) + multiedges = ( len(set(positions)) < total ) + G.allow_loops(True if loops else False,check=False) + G.allow_multiple_edges(multiedges,check=False) + G.add_vertices(range(M.nrows())) + G.add_edges(positions) + def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, convert_empty_dict_labels_to_None=False): r""" Fill ``G`` with the data of a dictionary of dictionaries. @@ -347,7 +398,7 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv INPUT: - ``G`` -- a graph - +x - ``M`` -- a dictionary of dictionaries. - ``loops``, ``multiedges``, ``weighted`` (booleans) -- whether to consider @@ -378,11 +429,6 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv if weighted is None: G._weighted = False for u in M: for v in M[u]: - if hash(u) > hash(v): - if v in M and u in M[v]: - if M[u][v] != M[v][u]: - raise ValueError("Dict does not agree on edge (%s,%s)"%(u,v)) - continue if multiedges is not False and not isinstance(M[u][v], list): if multiedges is None: multiedges = False if multiedges: @@ -394,23 +440,22 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv verts = set().union(M.keys(), *M.values()) G.add_vertices(verts) if convert_empty_dict_labels_to_None: + relabel = lambda x : x if x!={} else None + else: + relabel = lambda x : x + + is_directed = G.is_directed() + if not is_directed and multiedges: + v_to_id = {v:i for i,v in enumerate(verts)} for u in M: for v in M[u]: - if hash(u) <= hash(v) or v not in M or u not in M[v]: - if multiedges: - for l in M[u][v]: - G._backend.add_edge(u,v,l,False) - else: - G._backend.add_edge(u,v,M[u][v] if M[u][v] != {} else None,False) + if v_to_id[u] <= v_to_id[v] or v not in M or u not in M[v] or u == v: + for l in M[u][v]: + G._backend.add_edge(u,v,relabel(l),False) else: for u in M: for v in M[u]: - if hash(u) <= hash(v) or v not in M or u not in M[v]: - if multiedges: - for l in M[u][v]: - G._backend.add_edge(u,v,l,False) - else: - G._backend.add_edge(u,v,M[u][v],False) + G._backend.add_edge(u,v,relabel(M[u][v]),is_directed) def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False): r""" @@ -418,7 +463,7 @@ def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False): INPUT: - - ``G`` -- a graph + - ``G`` -- a :class:`Graph` or :class:`DiGraph`. - ``D`` -- a dictionary of lists. @@ -433,9 +478,6 @@ def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False): sage: g.is_isomorphic(graphs.PetersenGraph()) True """ - if not all(isinstance(D[u], list) for u in D): - raise ValueError("Input dict must be a consistent format.") - verts = set().union(D.keys(),*D.values()) if loops is None or loops is False: for u in D: @@ -460,11 +502,19 @@ def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False): G.allow_loops(loops, check=False) G.allow_multiple_edges(multiedges, check=False) G.add_vertices(verts) - for u in D: - for v in D[u]: - if (multiedges or hash(u) <= hash(v) or - v not in D or u not in D[v]): - G._backend.add_edge(u,v,None,False) + + is_directed = G.is_directed() + if not is_directed and multiedges: + v_to_id = {v:i for i,v in enumerate(verts)} + for u in D: + for v in D[u]: + if (v_to_id[u] <= v_to_id[v] or + v not in D or u not in D[v] or u == v): + G._backend.add_edge(u,v,None,False) + else: + for u in D: + for v in D[u]: + G._backend.add_edge(u,v,None,is_directed) from sage.misc.rest_index_of_methods import gen_rest_table_index import sys From d2f690be75c4f68df5ad10837edc1d1bdf7a4073 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 09:25:44 -0500 Subject: [PATCH 1367/1872] Fix for sparse dot dense vector. --- src/sage/modules/free_module_element.pyx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 5d0b8159274..cfcb49095e9 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -4580,8 +4580,21 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): sage: w = vector(R, [], sparse=True) sage: parent(v._dot_product_coerce_(w)) Univariate Polynomial Ring in x over Real Double Field + + TESTS: + + Check that :trac:`19377` is fixed:: + + sage: w = vector(ZZ, (1,2,3), sparse=False) + sage: v = vector(ZZ, (1,2,3), sparse=True) + sage: v._dot_product_coerce_(w) + 14 """ - cdef dict e = (right)._entries + cdef dict e + if right.is_sparse_c(): + e = (right)._entries + else: + e = right.dict() z = left.base_ring().zero() if left.base_ring() is not right.base_ring(): z *= right.base_ring().zero() From ccfd5f827df03f150209d1b347de1853cff1036d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 09:50:11 -0500 Subject: [PATCH 1368/1872] Don't need to multiply if the vector is 0-dimensional. --- src/sage/matrix/matrix_mod2_dense.pyx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index be72592dd1f..6e1b3014f6f 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -625,6 +625,15 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse sage: r1 = A*v1 sage: r0.column(0) == r1 True + + TESTS: + + Check that :trac:`19378` is fixed:: + + sage: m = matrix(GF(2), 11, 0) + sage: v = vector(GF(2), 0) + sage: m * v + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) """ cdef mzd_t *tmp if not isinstance(v, Vector_mod2_dense): @@ -634,6 +643,9 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse raise ArithmeticError("number of columns of matrix must equal degree of vector") VS = VectorSpace(self._base_ring, self._nrows) + # If the vector is 0-dimensional, the result will be the 0-vector + if not self.ncols(): + return VS.zero() cdef Vector_mod2_dense c = Vector_mod2_dense.__new__(Vector_mod2_dense) c._init(self._nrows, VS) c._entries = mzd_init(1, self._nrows) From 99c8601b947b746cfd0cbbca4c836b82b3ac5dde Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 10 Oct 2015 17:55:55 +0200 Subject: [PATCH 1369/1872] trac #19385: Dictionary of lists for a digraph with labelled multiple edges. How I wish I could forget those stupid things. --- src/sage/graphs/graph_input.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index cea82597dc3..e2c07cf78aa 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -452,6 +452,11 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv if v_to_id[u] <= v_to_id[v] or v not in M or u not in M[v] or u == v: for l in M[u][v]: G._backend.add_edge(u,v,relabel(l),False) + elif multiedges: + for u in M: + for v in M[u]: + for l in M[u][v]: + G._backend.add_edge(u,v,relabel(l),is_directed) else: for u in M: for v in M[u]: From 7395b58933960ee9eaba588347ba516da27f533d Mon Sep 17 00:00:00 2001 From: Jessica Striker Date: Sat, 10 Oct 2015 11:49:05 -0500 Subject: [PATCH 1370/1872] Map from a noncrossing perfect matching to a noncrossing set partition --- src/sage/combinat/perfect_matching.py | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/combinat/perfect_matching.py b/src/sage/combinat/perfect_matching.py index 40852a14e1f..ac325241e49 100644 --- a/src/sage/combinat/perfect_matching.py +++ b/src/sage/combinat/perfect_matching.py @@ -808,6 +808,35 @@ def to_permutation(self): from sage.combinat.permutation import Permutation return Permutation(self.value) + def to_non_crossing_set_partition(self): + r""" + Returns the noncrossing set partition (on half as many elements) + corresponding to the perfect matching, if the perfect matching is + noncrossing. Otherwise, gives an error. + + OUTPUT: + + The realization of ``self`` as a noncrossing set partition. + + EXAMPLES:: + + sage: PerfectMatching([[1,3], [4,2]]).to_non_crossing_set_partition() + Traceback (most recent call last): + ... + ValueError: matching must be non-crossing + sage: PerfectMatching([[1,4], [3,2]]).to_non_crossing_set_partition() + {{1, 2}} + sage: PerfectMatching([]).to_non_crossing_set_partition() + {} + """ + from sage.combinat.set_partition import SetPartition + if not self.is_non_crossing(): + raise ValueError("matching must be non-crossing") + else: + perm = self.to_permutation() + perm2 = Permutation([(perm[2*i])/2 for i in range(len(perm)/2)]) + return SetPartition(perm2.cycle_tuples()) + class PerfectMatchings(UniqueRepresentation, Parent): r""" From 0d2ea83c0d4a66ff254e9382376b04f90d921964 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 10 Oct 2015 10:54:25 -0700 Subject: [PATCH 1371/1872] trac 6102: - speed up algebraic_topological_model - add version which works for Delta complexes --- .../homology/algebraic_topological_model.py | 303 +++++++++++++++++- src/sage/homology/cell_complex.py | 44 +-- src/sage/homology/delta_complex.py | 2 +- .../homology_vector_space_with_basis.py | 79 ++++- 4 files changed, 393 insertions(+), 35 deletions(-) diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index d36dacc7ff6..eaf16035dc6 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -1,7 +1,13 @@ # -*- coding: utf-8 -*- -""" +r""" Algebraic topological model for a cell complex +This file contains two functions, :func:`algebraic_topological_model` +and :func:`algebraic_topological_model_delta_complex`. The second +works more generally: for all simplicial, cubical, and +`\Delta`-complexes. The first only works for simplicial and cubical +complexes, but it is faster in those case. + AUTHORS: - John H. Palmieri (2015-09) @@ -20,7 +26,9 @@ # TODO: cythonize this. from sage.modules.free_module_element import vector +from sage.modules.free_module import VectorSpace from sage.matrix.constructor import matrix, zero_matrix +from sage.matrix.matrix_space import MatrixSpace from chain_complex import ChainComplex from chain_complex_morphism import ChainComplexMorphism from chain_homotopy import ChainContraction @@ -29,11 +37,11 @@ def algebraic_topological_model(K, base_ring=None): r""" Algebraic topological model for cell complex ``K`` - with coefficients in ``base_ring``. ``base_ring`` must be a field. + with coefficients in the field ``base_ring`` INPUT: - - ``K`` -- either a simplicial complex or a cubical complex. + - ``K`` -- either a simplicial complex or a cubical complex - ``base_ring`` -- coefficient ring (optional, default ``QQ``). Must be a field. @@ -190,19 +198,32 @@ def algebraic_topological_model(K, base_ring=None): for dim in range(K.dimension()+1): n_cells = K.n_cells(dim) - # No need to set zero values for any of the maps: we will - # assume any unset values are zero. - # From the paper: phi_dict[c] = 0. diff = C.differential(dim) + # diff is sparse and low density. Dense matrices are faster + # over finite fields, but for low density matrices, sparse + # matrices are faster over the rationals. + if base_ring != QQ: + diff = diff.dense_matrix() + rank = len(n_cells) old_rank = len(old_cells) - - for c_idx, c in enumerate(n_cells): - c_vec = vector(base_ring, rank, {c_idx: 1}) + V_old = VectorSpace(base_ring, old_rank) + zero = V_old.zero_vector() + + for c_idx, c in enumerate(zip(n_cells, VectorSpace(base_ring, rank).gens())): + # c is the pair (cell, the corresponding standard basis + # vector in the free module of chains). Separate its + # components, calling them c and c_vec: + c_vec = c[1] + c = c[0] + # No need to set zero values for any of the maps: we will + # assume any unset values are zero. + # From the paper: phi_dict[c] = 0. # c_bar = c - phi(bdry(c)) c_bar = c_vec bdry_c = diff * c_vec + # Apply phi to bdry_c and subtract from c_bar. for (idx, coord) in bdry_c.iteritems(): try: c_bar -= coord * phi_dict[dim-1][idx] @@ -212,7 +233,7 @@ def algebraic_topological_model(K, base_ring=None): bdry_c_bar = diff * c_bar # Evaluate pi(bdry(c_bar)). - pi_bdry_c_bar = vector(base_ring, old_rank) + pi_bdry_c_bar = zero for (idx, coeff) in bdry_c_bar.iteritems(): try: @@ -240,10 +261,7 @@ def algebraic_topological_model(K, base_ring=None): break # pi(c) = 0: no need to do anything about this. - for c_j_idx, c_j in enumerate(old_cells): - # c_j_vec: representative of c_j in the free - # module of chains in dimension dim-1. - c_j_vec = vector(base_ring, old_rank, {c_j_idx: 1}) + for c_j_idx in range(old_rank): # eta_ij = . try: eta_ij = pi_dict[dim-1][c_j_idx][u_idx] @@ -321,3 +339,260 @@ def algebraic_topological_model(K, base_ring=None): iota = ChainComplexMorphism(iota_data, M, C) phi = ChainContraction(phi_data, pi, iota) return phi, M + +def algebraic_topological_model_delta_complex(K, base_ring=None): + r""" + Algebraic topological model for cell complex ``K`` + with coefficients in the field ``base_ring`` + + This has the same basic functionality as + :func:`algebraic_topological_model`, but it also works for + `\Delta`-complexes. For simplicial and cubical complexes it is + somewhat slower, though. + + INPUT: + + - ``K`` -- a simplicial complex, a cubical complex, or a + Delta complex + - ``base_ring`` -- coefficient ring (optional, default ``QQ``) + Must be a field. + + OUTPUT: a pair ``(phi, M)`` consisting of + + - the chain contraction ``phi`` associated to `C`, `M`, `\pi: C + \to M`, and `\iota: M \to C` satisfying `\iota \pi = 1_M` and + `\pi \iota`. + - the chain complex `M` + + See :func:`algebraic_topological_model` for the main + documentation. The difference in implementation between the two: + this uses matrix and vector algebra. The other function does more + of the computations "by hand" and uses cells (given as simplices + or cubes) to index various dictionaries. Since the cells in + `\Delta`-complexes are not as nice, the other function does not + work for them, while this function relies almost entirely on the + structure of the associated chain complex. + + EXAMPLES:: + + sage: from sage.homology.algebraic_topological_model import algebraic_topological_model_delta_complex as AT_model + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: phi, M = AT_model(RP2, GF(2)) + sage: M.homology() + {0: Vector space of dimension 1 over Finite Field of size 2, + 1: Vector space of dimension 1 over Finite Field of size 2, + 2: Vector space of dimension 1 over Finite Field of size 2} + sage: T = delta_complexes.Torus() + sage: phi, M = AT_model(T, QQ) + sage: M.homology() + {0: Vector space of dimension 1 over Rational Field, + 1: Vector space of dimension 2 over Rational Field, + 2: Vector space of dimension 1 over Rational Field} + + If you want to work with cohomology rather than homology, just + dualize the outputs of this function:: + + sage: M.dual().homology() + {0: Vector space of dimension 1 over Rational Field, + 1: Vector space of dimension 2 over Rational Field, + 2: Vector space of dimension 1 over Rational Field} + sage: M.dual().degree_of_differential() + 1 + sage: phi.dual() + Chain homotopy between + Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field + and Chain complex morphism + From: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field + + In degree 0, the inclusion of the homology `M` into the chain + complex `C` sends the homology generator to a single vertex:: + + sage: K = simplicial_complexes.Simplex(2) + sage: phi, M = AT_model(K, QQ) + sage: phi.iota().in_degree(0) + [0] + [0] + [1] + + In cohomology, though, one needs the dual of every degree 0 chain + to detect the degree 0 cohomology generator:: + + sage: phi.dual().iota().in_degree(0) + [1] + [1] + [1] + + TESTS:: + + sage: T = cubical_complexes.Torus() + sage: C = T.chain_complex() + sage: H, M = AT_model(T) + sage: C.differential(1) * H.iota().in_degree(1).column(0) == 0 + True + sage: C.differential(1) * H.iota().in_degree(1).column(1) == 0 + True + sage: coC = T.chain_complex(cochain=True) + sage: coC.differential(1) * H.dual().iota().in_degree(1).column(0) == 0 + True + sage: coC.differential(1) * H.dual().iota().in_degree(1).column(1) == 0 + True + """ + def conditionally_sparse(m): + """ + Return a sparse matrix if the characteristic is zero. + + Multiplication of matrices with low density seems to quicker + if the matrices are sparse, when over the rationals. Over + finite fields, dense matrices, are faster regardless of + density. + """ + if base_ring == QQ: + return m.sparse_matrix() + else: + return m + + if base_ring is None: + base_ring = QQ + if not base_ring.is_field(): + raise ValueError('the coefficient ring must be a field.') + + # The following are all dictionaries indexed by dimension. + # For each n, gens[n] is an ordered list of the n-cells generating the complex M. + gens = {} + pi_data = {} + phi_data = {} + iota_data = {} + + for n in range(-1, K.dimension()+1): + gens[n] = [] + + C = K.chain_complex(base_ring=base_ring) + n_cells = [] + pi_cols = [] + iota_cols = {} + + for dim in range(K.dimension()+1): + # old_cells: cells one dimension lower. + old_cells = n_cells + # n_cells: the standard basis for the vector space C.free_module(dim). + n_cells = C.free_module(dim).gens() + diff = C.differential(dim) + rank = len(n_cells) + old_rank = len(old_cells) + + # Create some matrix spaces to try to speed up matrix creation. + MS_pi_t = MatrixSpace(base_ring, old_rank, len(gens[dim-1])) + # MS_phi_t = MatrixSpace(base_ring, old_rank, rank) + + pi_old = MS_pi_t.matrix(pi_cols).transpose() + iota_cols_old = iota_cols + iota_cols = {} + pi_cols_old = pi_cols + pi_cols = [] + phi_old = matrix(base_ring, rank, old_rank) + phi_old_cols = phi_old.columns() + phi_old = conditionally_sparse(phi_old) + to_be_deleted = [] + + zero_vector = vector(base_ring, rank) + pi_nrows = pi_old.nrows() + + for c_idx, c in enumerate(n_cells): + # c_bar = c - phi(bdry(c)): + # Avoid a bug in matrix-vector multiplication (trac 19378): + if not diff: + c_bar = c + pi_bdry_c_bar = False + else: + if base_ring == QQ: + c_bar = c - phi_old * (diff * c) + pi_bdry_c_bar = conditionally_sparse(pi_old) * (diff * c_bar) + else: + c_bar = c - phi_old * diff * c + pi_bdry_c_bar = conditionally_sparse(pi_old) * diff * c_bar + + # One small typo in the published algorithm: it says + # "if bdry(c_bar) == 0", but should say + # "if pi(bdry(c_bar)) == 0". + if not pi_bdry_c_bar: + # Append c to list of gens. + gens[dim].append(c_idx) + # iota(c) = c_bar + iota_cols[c_idx] = c_bar + # pi(c) = c + pi_cols.append(c) + else: + # Take any u in gens so that lambda_i = != 0. + # u_idx will be the index of the corresponding cell. + (u_idx, lambda_i) = pi_bdry_c_bar.leading_item() + for (u_idx, lambda_i) in pi_bdry_c_bar.iteritems(): + if u_idx not in to_be_deleted: + break + # This element/column needs to be deleted from gens and + # iota_old. Do that later. + to_be_deleted.append(u_idx) + # pi(c) = 0. + pi_cols.append(zero_vector) + for c_j_idx, c_j in enumerate(old_cells): + # eta_ij = . + # That is, eta_ij is the u_idx entry in the vector pi_old * c_j: + eta_ij = c_j.dot_product(pi_old.row(u_idx)) + if eta_ij: + # Adjust phi(c_j). + phi_old_cols[c_j_idx] += eta_ij * lambda_i**(-1) * c_bar + # Adjust pi(c_j). + pi_cols_old[c_j_idx] -= eta_ij * lambda_i**(-1) * pi_bdry_c_bar + + # The matrices involved have many zero entries. For + # such matrices, using sparse matrices is faster over + # the rationals, slower over finite fields. + phi_old = matrix(base_ring, phi_old_cols, sparse=(base_ring==QQ)).transpose() + keep = vector(base_ring, pi_nrows, {i:1 for i in range(pi_nrows) + if i not in to_be_deleted}) + cols = [v.pairwise_product(keep) for v in pi_cols_old] + pi_old = MS_pi_t.matrix(cols).transpose() + + # Here cols is a temporary storage for the columns of iota. + cols = [iota_cols_old[i] for i in sorted(iota_cols_old.keys())] + for r in sorted(to_be_deleted, reverse=True): + del cols[r] + del gens[dim-1][r] + iota_data[dim-1] = matrix(base_ring, len(gens[dim-1]), old_rank, cols).transpose() + # keep: rows to keep in pi_cols_old. Start with all + # columns, then delete those in to_be_deleted. + keep = sorted(set(range(pi_nrows)).difference(to_be_deleted)) + # Now cols is a temporary storage for columns of pi. + cols = [v.list_from_positions(keep) for v in pi_cols_old] + pi_data[dim-1] = matrix(base_ring, old_rank, len(gens[dim-1]), cols).transpose() + phi_data[dim-1] = phi_old + + V_gens = VectorSpace(base_ring, len(gens[dim])) + if pi_cols: + cols = [] + for v in pi_cols: + cols.append(V_gens(v.list_from_positions(gens[dim]))) + pi_cols = cols + + pi_data[dim] = matrix(base_ring, rank, len(gens[dim]), pi_cols).transpose() + cols = [iota_cols[i] for i in sorted(iota_cols.keys())] + iota_data[dim] = matrix(base_ring, len(gens[dim]), rank, cols).transpose() + + # M_data will contain (trivial) matrices defining the differential + # on M. Keep track of the sizes using "M_rows" and "M_cols", which are + # just the ranks of consecutive graded pieces of M. + M_data = {} + M_rows = 0 + for n in range(K.dimension()+1): + M_cols = len(gens[n]) + M_data[n] = zero_matrix(base_ring, M_rows, M_cols) + M_rows = M_cols + + M = ChainComplex(M_data, base_ring=base_ring, degree=-1) + + pi = ChainComplexMorphism(pi_data, C, M) + iota = ChainComplexMorphism(iota_data, M, C) + phi = ChainContraction(phi_data, pi, iota) + return phi, M diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 7329bf174b0..8c110df4bbf 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -689,7 +689,8 @@ def algebraic_topological_model(self, base_ring=None): Algebraic topological model, as defined by Pilarczyk and Réal [PR]_, for this cell complex with coefficients in ``base_ring``. - This is only implemented for simplicial and cubical complexes. + This is only implemented for simplicial, cubical, and + `\Delta`-complexes. INPUT: @@ -737,11 +738,12 @@ def algebraic_topological_model(self, base_ring=None): 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field} """ - from algebraic_topological_model import algebraic_topological_model + from algebraic_topological_model import algebraic_topological_model, algebraic_topological_model_delta_complex from cubical_complex import CubicalComplex from simplicial_complex import SimplicialComplex - if not isinstance(self, (CubicalComplex, SimplicialComplex)): - raise NotImplementedError('only implemented for simplicial and cubical complexes') + from delta_complex import DeltaComplex + if not isinstance(self, (CubicalComplex, SimplicialComplex, DeltaComplex)): + raise NotImplementedError('only implemented for simplicial, cubical, and Delta complexes') try: if not self.is_immutable(): raise ValueError('the complex must be immutable') @@ -749,6 +751,8 @@ def algebraic_topological_model(self, base_ring=None): # Cubical complexes don't have an is_immutable method, and # they are always immutable. pass + if isinstance(self, DeltaComplex): + return algebraic_topological_model_delta_complex(self, base_ring) return algebraic_topological_model(self, base_ring) # This is cached for uniqueness reasons: calling @@ -759,11 +763,10 @@ def algebraic_topological_model(self, base_ring=None): def homology_with_basis(self, dim, base_ring=None, cohomology=False): r""" Return the unreduced homology in dimension ``dim`` with - coefficients in ``base_ring`` with a chosen basis. Should be - suitable for computing cup products and (in positive - characteristic) cohomology operations. + coefficients in ``base_ring`` with a chosen basis. - This is only implemented for simplicial and cubical complexes. + This is only implemented for simplicial, cubical, and + `\Delta`-complexes. INPUTS: @@ -792,14 +795,18 @@ def homology_with_basis(self, dim, base_ring=None, cohomology=False): H = H.dual() return HomologyVectorSpaceWithBasis(dim, H, self) + # This is cached in effect via homology_with_basis. def cohomology_with_basis(self, dim, base_ring=None): r""" Return the unreduced cohomology in dimension ``dim`` with - coefficients in ``base_ring`` with a chosen basis. Should be - suitable for computing cup products and (in positive - characteristic) cohomology operations. + coefficients in ``base_ring`` with a chosen basis. - This is only implemented for simplicial and cubical complexes. + This is only implemented for simplicial, cubical, and + `\Delta`-complexes. For simplicial and cubical complexes, the + resulting elements are suitable for computing cup + products. For simplicial complexes, they should be suitable + for computing cohomology operations; at the moment, only mod 2 + cohomology operations have been implemented. INPUTS: @@ -818,16 +825,20 @@ def cohomology_with_basis(self, dim, base_ring=None): sage: K.cohomology_with_basis(1, GF(2)) Free module generated by (h^{1,0}, h^{1,1}) over Finite Field of size 2 + sage: X = delta_complexes.SurfaceOfGenus(2) + sage: X.cohomology_with_basis(1, QQ) + Free module generated by (h^{1,0}, h^{1,1}, h^{1,2}, h^{1,3}) over Rational Field + sage: H1 = simplicial_complexes.Torus().cohomology_with_basis(1, QQ) sage: x = H1.basis()[0]; x h^{1,0} sage: y = H1.basis()[1]; y h^{1,1} - sage: simplicial_complexes.Torus().cohomology_with_basis(2, QQ) Free module generated by (h^{2,0},) over Rational Field - You can compute cup products of cohomology classes:: + You can compute cup products of cohomology classes when + working with cubical or simplicial complexes:: sage: x.cup_product(y) h^{2,0} @@ -921,10 +932,7 @@ def cohomology_ring(self, base_ring=None): z_vec = z.to_vector() for j in range(z_vec.degree()): y_matrix_dict[(idx, start+j)] = z_vec[j] - # Use dense matrices because of a bug: try using sparse - # matrices and mod 2 coefficients, and run the method - # "is_unitary()" on the ring. See trac 19165. - matrices.append(matrix(base_ring, rank, rank, y_matrix_dict, sparse=False)) + matrices.append(matrix(base_ring, rank, rank, y_matrix_dict)) names = ['h{}{}'.format(y[0], y[1]) for y in sorted(basis)] return FiniteDimensionalAlgebra(base_ring, table=matrices, names=names) diff --git a/src/sage/homology/delta_complex.py b/src/sage/homology/delta_complex.py index d08e7ca8c32..b41cb1553d2 100644 --- a/src/sage/homology/delta_complex.py +++ b/src/sage/homology/delta_complex.py @@ -1129,7 +1129,7 @@ def connected_sum(self, other): old_idx += 1 # reindex all simplices to be processed and add them to data for s in process_now: - data[n].append([renaming[i] for i in s]) + data[n].append(tuple([renaming[i] for i in s])) # set up for next loop, one dimension down renaming = {} process_now = process_later diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index b9d7dbb00f0..8ddf535243b 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -20,7 +20,6 @@ - John H. Palmieri (2015-09) """ - ######################################################################## # Copyright (C) 2015 John H. Palmieri # @@ -32,6 +31,8 @@ ######################################################################## from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement +from simplicial_complex import SimplicialComplex +from cubical_complex import CubicalComplex class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): """Homology (or cohomology) vector space. @@ -347,8 +348,31 @@ def cup_product(self, other): -h^{2,0} sage: x.cup_product(x) 0 + + But not with `\Delta`-complexes:: + + sage: X = delta_complexes.SurfaceOfGenus(2) + sage: a,b,c,d = X.cohomology_with_basis(1, QQ).gens() + sage: a.cup_product(b) + Traceback (most recent call last): + ... + NotImplementedError: cup products are only implemented for simplicial and cubiical complexes + + A non-connected example:: + + sage: K = cubical_complexes.Torus().disjoint_union(cubical_complexes.Torus()) + sage: a,b,c,d = K.cohomology_with_basis(1, QQ).gens() + sage: x,y = K.cohomology_with_basis(0, QQ).gens() + sage: a.cup_product(x) == a + True + sage: a.cup_product(y) + 0 + sage: K.cohomology_ring(QQ).is_unitary() # long time + True """ complex = self.parent().complex() + if not isinstance(complex, (SimplicialComplex, CubicalComplex)): + raise NotImplementedError('cup products are only implemented for simplicial and cubiical complexes') base_ring = self.base_ring() if not (complex == other.parent().complex() and self.parent()._cohomology @@ -368,6 +392,58 @@ def cup_product(self, other): result.append((gamma.leading_support(), gamma_coeff)) return complex.cohomology_with_basis(deg_tot, base_ring).sum_of_terms(result) + __mul__ = cup_product + + def __pow__(self, n): + r""" + This element raised to the nth power + + INPUT: + + - ``n`` -- a non-negative integer + + If ``n`` is positive, this takes the iterated cup product + of the element with itself. If ``n`` is zero, this returns + the unit element of the cohomology ring (even if the + complex is not connected). + + EXAMPLES:: + + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: a = RP2.cohomology_with_basis(1, GF(2)).gens()[0] + sage: a**0 + h^{0,0} + sage: a**1 + h^{1,0} + sage: a**2 + h^{2,0} + sage: a**3 + 0 + + sage: a**(-2) + Traceback (most recent call last): + ... + ValueError: the power must be non-negative + + A non-connected example:: + + sage: K = cubical_complexes.Torus().disjoint_union(cubical_complexes.Sphere(2)) + sage: a,b = K.cohomology_with_basis(2, QQ).gens() + sage: a**0 + h^{0,0} + h^{0,1} + """ + if not self.parent()._cohomology: + raise ValueError('this is not a cohomology class') + if n < 0: + raise ValueError('the power must be non-negative') + if n == 0: + complex = self.parent().complex() + zeroth_cohomology = complex.cohomology_with_basis(0, self.base_ring()) + return sum(zeroth_cohomology.gens()) + if n == 1: + return self + return self.cup_product(self**(n-1)) + def Sq(self, i): r""" Return the result of applying Sq^i to this element. @@ -428,7 +504,6 @@ def Sq(self, i): ... ValueError: Steenrod squares are only defined in characteristic 2 """ - from simplicial_complex import SimplicialComplex complex = self.parent().complex() if not isinstance(complex, SimplicialComplex): raise NotImplementedError('Steenrod squares are only implemented for simplicial complexes') From 35a422c82b352d4aedbd18f2f0a73c9a84d78ff8 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Sat, 10 Oct 2015 13:21:11 -0500 Subject: [PATCH 1372/1872] changed first line of doc string to be one sentence --- src/sage/combinat/perfect_matching.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/perfect_matching.py b/src/sage/combinat/perfect_matching.py index ac325241e49..74f0ebe0c59 100644 --- a/src/sage/combinat/perfect_matching.py +++ b/src/sage/combinat/perfect_matching.py @@ -811,8 +811,8 @@ def to_permutation(self): def to_non_crossing_set_partition(self): r""" Returns the noncrossing set partition (on half as many elements) - corresponding to the perfect matching, if the perfect matching is - noncrossing. Otherwise, gives an error. + corresponding to the perfect matching if the perfect matching is + noncrossing, and otherwise gives an error. OUTPUT: From 9959af1ebf309622d5b1526530eaec35d2c31417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 10 Oct 2015 20:44:34 +0200 Subject: [PATCH 1373/1872] trac #6322 correct optional magma doctest --- .../explicit_methods_in_number_theory/nf_galois_groups.rst | 1 - 1 file changed, 1 deletion(-) 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 e4de374dda9..abae9503c11 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 @@ -90,7 +90,6 @@ groups in the GAP transitive groups database. sage: K. = NumberField(x^3 - 2) sage: K.galois_group(type="gap", algorithm='magma') # optional - magma - verbose... Galois group Transitive group number 2 of degree 3 of the Number Field in a with defining polynomial x^3 - 2 From a7d950423f34fb963379dad74ed8805856c0df2d Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Sat, 10 Oct 2015 11:54:55 -0700 Subject: [PATCH 1374/1872] trac 19016: defang erroneous doctest in "parent.register_embedding" (proper fix to be made on other ticket) --- src/sage/structure/parent.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 1936d2b69b9..7b08efa9abf 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2082,10 +2082,10 @@ cdef class Parent(category_object.CategoryObject): [ 0 1] [-272118 0] - sage: a.matrix() * b + sage: a.matrix() * b.matrix() [-272118 0] [ 0 -462] - sage: a * b.matrix() + sage: a.matrix() * b.matrix() [-272118 0] [ 0 -462] """ From 6490916c5aaf978e32cc3d073d2c5acc90500ba8 Mon Sep 17 00:00:00 2001 From: Jessica Striker Date: Sat, 10 Oct 2015 14:04:48 -0500 Subject: [PATCH 1375/1872] added gyration to FullyPackedLoop and link_pattern to AlternatingSignMatrix --- src/sage/combinat/alternating_sign_matrix.py | 20 ++++++++++++ src/sage/combinat/fully_packed_loop.py | 33 +++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 930a703e6af..cac15d3c1d9 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -521,6 +521,26 @@ def to_fully_packed_loop(self): from sage.combinat.fully_packed_loop import FullyPackedLoop return FullyPackedLoop(self) + def link_pattern(self): + """ + Return the link pattern corresponding to the fully packed loop + corresponding to self. + + EXAMPLES: + + We can extract the underlying link pattern (a non-crossing + partition) from a fully packed loop:: + + sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]]) + sage: A.link_pattern() + [(1, 2), (3, 6), (4, 5)] + + sage: B = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + sage: B.link_pattern() + [(1, 6), (2, 5), (3, 4)] + """ + return self.to_fully_packed_loop().link_pattern() + @combinatorial_map(name='gyration') def gyration(self): diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 0b053c3809c..a2c3ad3d1da 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -875,6 +875,37 @@ def plot(self): G.axes(False) return G + def gyration(self): + r""" + Return the fully packed loop obtained by applying gyration + to the alternating sign matrix in bijection with ``self``. + + Gyration was first defined in [Wieland00]_ as an action on + fully-packed loops. + + REFERENCES: + + .. [Wieland00] B. Wieland. *A large dihedral symmetry of the set of + alternating sign matrices*. Electron. J. Combin. 7 (2000). + + EXAMPLES:: + + sage: A = AlternatingSignMatrix([[1, 0, 0],[0, 1, 0],[0, 0, 1]]) + sage: fpl = FullyPackedLoop(A) + sage: fpl.gyration().to_alternating_sign_matrix() + [0 0 1] + [0 1 0] + [1 0 0] + sage: asm = AlternatingSignMatrix([[0, 0, 1],[1, 0, 0],[0, 1, 0]]) + sage: f = FullyPackedLoop(asm) + sage: f.gyration().to_alternating_sign_matrix() + [0 1 0] + [0 0 1] + [1 0 0] + """ + return FullyPackedLoop(self.to_alternating_sign_matrix().gyration()) + + def link_pattern(self): """ Return a link pattern corresponding to a fully packed loop. @@ -1416,4 +1447,4 @@ def _an_element_(self): #ASM = AlternatingSignMatrix(matrix.identity(self._n)) #SVM = ASM.to_six_vertex_model() SVM = SixVertexModel(self._n,boundary_conditions='ice').an_element() - return self.element_class(self, SVM) \ No newline at end of file + return self.element_class(self, SVM) From 2060ebfbdd68c6af2882f695377e9953dafb12d4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 14:10:12 -0500 Subject: [PATCH 1376/1872] Removing as_word from to_word and directly constructing a list, plus doc tweaks. --- src/sage/combinat/skew_tableau.py | 57 +++++++++++-------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 3e7b7b42332..026302b5228 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -404,19 +404,12 @@ def conjugate(self): return SkewTableau(conj) - def to_word_by_row(self, as_word=True): + def to_word_by_row(self): """ Return a word obtained from a row reading of ``self``. - Specifically, this is the word obtained by concatenating the - rows from the bottommost one (in English notation) to the - topmost one. - INPUT: - - - ``as_word`` -- boolean (default: ``True``); if ``True``, - the result is returned as a word (i.e., an element of - :class:`Words`), while otherwise it is returned as a - list + This is the word obtained by concatenating the rows from + the bottommost one (in English notation) to the topmost one. EXAMPLES:: @@ -433,8 +426,6 @@ def to_word_by_row(self, as_word=True): 1 sage: s.to_word_by_row() word: 1324 - sage: s.to_word_by_row(as_word=False) - [1, 3, 2, 4] TESTS:: @@ -444,24 +435,15 @@ def to_word_by_row(self, as_word=True): word: """ word = [x for row in reversed(self) for x in row if x is not None] - if not as_word: - return word return Words("positive integers")(word) - def to_word_by_column(self, as_word=True): + def to_word_by_column(self): """ Return the word obtained from a column reading of the skew tableau. - Specifically, this is the word obtained by concatenating the - columns from the rightmost one (in English notation) to the - leftmost one. - - INPUT: - - ``as_word`` -- boolean (default: ``True``); if ``True``, - the result is returned as a word (i.e., an element of - :class:`Words`), while otherwise it is returned as a - list + This is the word obtained by concatenating the columns from + the rightmost one (in English notation) to the leftmost one. EXAMPLES:: @@ -481,10 +463,8 @@ def to_word_by_column(self, as_word=True): 1 sage: s.to_word_by_column() word: 4231 - sage: s.to_word_by_column(as_word=False) - [4, 2, 3, 1] """ - return self.conjugate().to_word_by_row(as_word=as_word) + return self.conjugate().to_word_by_row() to_word = to_word_by_row @@ -875,18 +855,15 @@ def rectify(self, algorithm=None): """ Return a :class:`StandardTableau`, :class:`SemistandardTableau`, or just :class:`Tableau` formed by applying the jeu de taquin - process to ``self``. See page 15 of [FW]_. - - REFERENCES: + process to ``self``. - .. [FW] William Fulton, - *Young Tableaux*, - Cambridge University Press 1997. + See page 15 of [Fulton97]_. INPUT: - - ``algorithm`` -- optional: if set to ``'jdt'``, rectifies by jeu de taquin; - if set to ``'schensted'``, rectifies by Schensted insertion of the - reading word; otherwise, guesses which will be faster. + + - ``algorithm`` -- optional: if set to ``'jdt'``, rectifies by jeu de + taquin; if set to ``'schensted'``, rectifies by Schensted insertion + of the reading word; otherwise, guesses which will be faster. EXAMPLES:: @@ -911,6 +888,11 @@ def rectify(self, algorithm=None): [[None, 1], [2, 3]] sage: T [[None, None, None, 4], [None, None, 1, 6], [None, None, 5], [2, 3]] + + REFERENCES: + + .. [Fulton97] William Fulton, *Young Tableaux*, + Cambridge University Press 1997. """ mu_size = self.inner_shape().size() @@ -928,7 +910,8 @@ def rectify(self, algorithm=None): for i in range(mu_size): rect = rect.slide() elif algorithm == 'schensted': - rect = Tableau([]).insert_word(self.to_word(as_word=False)) + w = [x for row in reversed(self) for x in row if x is not None] + rect = Tableau([]).insert_word(w) else: raise ValueError("algorithm must be 'jdt', 'schensted', or None") if self in StandardSkewTableaux(): From 9a7d973760755605760baaf5a078b3667396f75d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 14:23:52 -0500 Subject: [PATCH 1377/1872] Removing some more as_word. --- src/sage/combinat/tableau.py | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 211b6783128..2dfe0da2d39 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -971,67 +971,45 @@ def pp(self): """ print self._repr_diagram() - def to_word_by_row(self, as_word=True): + def to_word_by_row(self): """ Return the word obtained from a row reading of the tableau ``self`` (starting with the lowermost row, reading every row from left to right). - INPUT: - - - ``as_word`` -- boolean (default: ``True``); if ``True``, - the result is returned as a word (i.e., an element of - :class:`Words`), while otherwise it is returned as a - list - EXAMPLES:: sage: Tableau([[1,2],[3,4]]).to_word_by_row() word: 3412 sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_row() word: 325146 - sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_row(as_word=False) - [3, 2, 5, 1, 4, 6] """ + from sage.combinat.words.word import Word w = [] for row in reversed(self): w += row - if not as_word: - return w - from sage.combinat.words.word import Word return Word(w) - def to_word_by_column(self, as_word=True): + def to_word_by_column(self): """ Return the word obtained from a column reading of the tableau ``self`` (starting with the leftmost column, reading every column from bottom to top). - INPUT: - - - ``as_word`` -- boolean (default: ``True``); if ``True``, - the result is returned as a word (i.e., an element of - :class:`Words`), while otherwise it is returned as a - list - EXAMPLES:: sage: Tableau([[1,2],[3,4]]).to_word_by_column() word: 3142 sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_column() word: 321546 - sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word_by_column(as_word=False) - [3, 2, 1, 5, 4, 6] """ + from sage.combinat.words.word import Word w = [] for row in self.conjugate(): w += row[::-1] - if not as_word: - return w - from sage.combinat.words.word import Word return Word(w) - def to_word(self, as_word=True): + def to_word(self): """ An alias for :meth:`to_word_by_row`. @@ -1041,10 +1019,8 @@ def to_word(self, as_word=True): word: 3412 sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word() word: 325146 - sage: Tableau([[1, 4, 6], [2, 5], [3]]).to_word(as_word=False) - [3, 2, 5, 1, 4, 6] """ - return self.to_word_by_row(as_word=as_word) + return self.to_word_by_row() def attacking_pairs(self): """ From c3e19027875151f04d94461c72eafa986770eadf Mon Sep 17 00:00:00 2001 From: Jessica Striker Date: Sat, 10 Oct 2015 14:35:50 -0500 Subject: [PATCH 1378/1872] Added a map from alternating sign matrices to Dyck words via the link pattern --- src/sage/combinat/alternating_sign_matrix.py | 26 ++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index cac15d3c1d9..28295586fea 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -541,11 +541,32 @@ def link_pattern(self): """ return self.to_fully_packed_loop().link_pattern() + def to_link_pattern_dyck_word(self): + """ + Return the Dyck word in bijection with the link pattern of self. + + EXAMPLES:: + + sage: A = AlternatingSignMatrices(3) + sage: asm = A([[0,1,0],[1,0,0],[0,0,1]]) + sage: asm.to_link_pattern_dyck_word() + [1, 0, 1, 0, 1, 0] + sage: asm = A([[0,1,0],[1,-1,1],[0,1,0]]) + sage: asm.to_link_pattern_dyck_word() + [1, 0, 1, 1, 0, 0] + """ + from sage.combinat.perfect_matching import PerfectMatching + from sage.combinat.dyck_word import DyckWords + p = PerfectMatching(self.link_pattern()).to_non_crossing_set_partition() + asm = self.to_matrix() + n = asm.nrows() + d = DyckWords(n) + return d.from_noncrossing_partition(p) @combinatorial_map(name='gyration') def gyration(self): r""" - Return the alternating sign matrix obtained by applying the gyration + Return the alternating sign matrix obtained by applying gyration to the height function in bijection with ``self``. Gyration acts on height functions as follows. Go through the entries of @@ -577,7 +598,6 @@ def gyration(self): [0 1 0] [0 0 1] [1 0 0] - sage: A = AlternatingSignMatrices(3) sage: A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]).gyration().gyration() [ 0 1 0] @@ -911,6 +931,8 @@ def to_semistandard_tableau(self): ssyt[i][j] = mt[j][-(i+1)] return SemistandardTableau(ssyt) + + def left_key(self): r""" Return the left key of the alternating sign matrix ``self``. From 80a70ce93d2cf6d4a7d76bd8b381a68f662f7465 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 14:39:07 -0500 Subject: [PATCH 1379/1872] Fixing missing imports. --- src/sage/combinat/skew_tableau.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 026302b5228..b49d163884b 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -40,7 +40,8 @@ from sage.structure.list_clone import ClonableList from sage.combinat.partition import Partition -from sage.combinat.tableau import Tableau, TableauOptions +from sage.combinat.tableau import (Tableau, TableauOptions, + StandardTableau, SemistandardTableau) from sage.combinat.skew_partition import SkewPartition, SkewPartitions from sage.combinat.integer_vector import IntegerVectors from sage.combinat.words.words import Words From 9ccedce4c0811fb8165879d10f447b5ffa3bdc08 Mon Sep 17 00:00:00 2001 From: Jessica Striker Date: Sat, 10 Oct 2015 14:44:15 -0500 Subject: [PATCH 1380/1872] Added another doc test --- src/sage/combinat/alternating_sign_matrix.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 28295586fea..6d68a4a2dc6 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -554,6 +554,10 @@ def to_link_pattern_dyck_word(self): sage: asm = A([[0,1,0],[1,-1,1],[0,1,0]]) sage: asm.to_link_pattern_dyck_word() [1, 0, 1, 1, 0, 0] + sage: A = AlternatingSignMatrices(4) + sage: asm = A([[0,0,1,0],[1,0,0,0],[0,1,-1,1],[0,0,1,0]]) + sage: asm.to_link_pattern_dyck_word() + [1, 1, 1, 0, 1, 0, 0, 0] """ from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.dyck_word import DyckWords From 4595847bc52ffb96ebf970944c7ebc8d3347cf3c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 15:47:36 -0500 Subject: [PATCH 1381/1872] Making changes based upon Kevin's comments. --- src/sage/combinat/colored_permutations.py | 137 +++++++++++++++++++--- 1 file changed, 123 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 3a501b65ebf..40e14878ce9 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -87,7 +87,7 @@ def _mul_(self, other): p = self._perm._left_to_right_multiply_on_right(other._perm) return self.__class__(self.parent(), colors, p) - def __invert__(self): + def inverse(self): """ Return the inverse of ``self``. @@ -105,6 +105,8 @@ def __invert__(self): tuple([-self._colors[i - 1] for i in ip]), # -1 for indexing ip) + __invert__ = inverse + def __eq__(self, other): """ Check equality. @@ -264,6 +266,23 @@ class ColoredPermutations(Parent, UniqueRepresentation): sage: s2*t*s2 [[0, 1, 0], [1, 2, 3]] + We can also create a colored permutation by passing + either a list of tuples consisting of ``(color, element)``:: + + sage: x = C([(2,1), (3,3), (3,2)]); x + [[2, 3, 3], [1, 3, 2]] + + or a list of colors and a permutation:: + + sage: C([[3,3,1], [1,3,2]]) + [[3, 3, 1], [1, 3, 2]] + + There is also the natural lift from permutations:: + + sage: P = Permutations(3) + sage: C(P.an_element()) + [[0, 0, 0], [3, 1, 2]] + REFERENCES: - :wikipedia:`Generalized_symmetric_group` @@ -364,8 +383,8 @@ def _element_constructor_(self, x): INPUT: - either a list of pairs (color, element) - or a pair of lists (colors, elements) + Either a list of pairs (color, element) + or a pair of lists (colors, elements). TESTS:: @@ -388,7 +407,41 @@ def _element_constructor_(self, x): if len(x) != 2: raise ValueError("input must be a pair of a list of colors and a permutation") - return self.element_class(self, map(self._C, x[0]), self._P(x[1])) + return self.element_class(self, [self._C(v) for v in x[0]], self._P(x[1])) + + def _coerce_map_from_(self, C): + """ + Return a coerce map from ``C`` if it exists and ``None`` otherwise. + + EXAMPLES:: + + sage: C = ColoredPermutations(2, 3) + sage: S = SignedPermutations(3) + sage: C.has_coerce_map_from(S) + True + + sage: C = ColoredPermutations(4, 3) + sage: C.has_coerce_map_from(S) + False + sage: S = SignedPermutations(4) + sage: C.has_coerce_map_from(S) + False + + sage: P = Permutations(3) + sage: C.has_coerce_map_from(P) + True + sage: P = Permutations(4) + sage: C.has_coerce_map_from(P) + False + """ + if isinstance(C, Permutations) and C.n == self._n: + return lambda P, x: P.element_class(P, [P._C.zero()]*P._n, x) + if self._m == 2 and isinstance(C, SignedPermutations) and C._n == self._n: + return lambda P, x: P.element_class(P, + [P._C.zero() if v == 1 else P._C.one() + for v in x._colors], + x._perm) + return super(ColoredPermutations, self)._coerce_map_from_(C) def __iter__(self): """ @@ -482,17 +535,20 @@ def degrees(self): return [self._m * i for i in range(1, self._n + 1)] def codegrees(self): - """ + r""" Return the codegrees of ``self``. Let `G` be a complex reflection group. The codegrees `d_1^* \leq d_2^* \leq \cdots \leq d_{\ell}^*` of `G` can be defined by: + .. MATH:: + \prod_{i=1}^{\ell} (q - d_i^* - 1) = \sum_{g \in G} \det(g) q^{\dim(V^g)}, - where `V` is the natural complex vector space that `G` acts on. + where `V` is the natural complex vector space that `G` acts on + and `\ell` is the :meth:`rank`. If `m = 1`, then we are in the special case of the symmetric group and the codegrees are `(n-2, n-3, \ldots 1, 0)`. Otherwise the degrees @@ -523,7 +579,7 @@ def codegrees(self): return list(reversed(range(self._n - 1))) return [self._m * i for i in reversed(range(self._n))] - def number_reflection_hyperplanes(self): + def number_of_reflection_hyperplanes(self): """ Return the number of reflection hyperplanes of ``self``. @@ -533,13 +589,13 @@ def number_reflection_hyperplanes(self): EXAMPLES:: sage: C = ColoredPermutations(1, 2) - sage: C.number_reflection_hyperplanes() + sage: C.number_of_reflection_hyperplanes() 1 sage: C = ColoredPermutations(1, 3) - sage: C.number_reflection_hyperplanes() + sage: C.number_of_reflection_hyperplanes() 3 sage: C = ColoredPermutations(4, 12) - sage: C.number_reflection_hyperplanes() + sage: C.number_of_reflection_hyperplanes() 276 """ return sum(self.codegrees()) + self.rank() @@ -548,15 +604,16 @@ def fixed_point_polynomial(self, q=None): r""" The fixed point polynomial of ``self``. - The fixed point polynomial `f_G` of a complex reflection group `G` is - counting the dimensions of fixed points subspaces: + The fixed point polynomial `f_G` of a complex reflection group `G` + is counting the dimensions of fixed points subspaces: .. MATH:: f_G(q) = \sum_{w \in W} q^{\dim V^w}. Furthermore, let `d_1, d_2, \ldots, d_{\ell}` be the degrees of `G`, - then the fixed point polynomial is given by + where `\ell` is the :meth:`rank`. Then the fixed point polynomial + is given by .. MATH:: @@ -772,6 +829,27 @@ class SignedPermutations(ColoredPermutations): sage: S.long_element().reduced_word() [4, 3, 4, 2, 3, 4, 1, 2, 3, 4] + We can also go between the 2-colored permutation group:: + + sage: C = ColoredPermutations(2, 3) + sage: S = SignedPermutations(3) + sage: S.an_element() + [-3, 1, 2] + sage: C(S.an_element()) + [[1, 0, 0], [3, 1, 2]] + sage: S(C(S.an_element())) == S.an_element() + True + sage: S(C.an_element()) + [1, 2, 3] + + There is also the natural lift from permutations:: + + sage: P = Permutations(3) + sage: x = S(P.an_element()); x + [3, 1, 2] + sage: x.parent() + Signed permutations of 3 + REFERENCES: - :wikipedia:`Hyperoctahedral_group` @@ -892,7 +970,7 @@ def _element_constructor_(self, x): raise ValueError("input must be a pair of a list of signs and a permutation") if any(s != 1 and s != -1 for s in x[0]): raise ValueError("the sign must be +1 or -1") - return self.element_class(self, map(ZZ, x[0]), self._P(x[1])) + return self.element_class(self, [ZZ(v) for v in x[0]], self._P(x[1])) def __iter__(self): """ @@ -911,6 +989,37 @@ def __iter__(self): for c in C: yield self.element_class(self, c, p) + def _coerce_map_from_(self, C): + """ + Return a coerce map from ``C`` if it exists and ``None`` otherwise. + + EXAMPLES:: + + sage: C = ColoredPermutations(2, 3) + sage: S = SignedPermutations(3) + sage: S.has_coerce_map_from(C) + True + + sage: C = ColoredPermutations(4, 3) + sage: S.has_coerce_map_from(C) + False + + sage: P = Permutations(3) + sage: C.has_coerce_map_from(P) + True + sage: P = Permutations(4) + sage: C.has_coerce_map_from(P) + False + """ + if isinstance(C, Permutations) and C.n == self._n: + return lambda P, x: P.element_class(P, [1]*P._n, x) + if isinstance(C, ColoredPermutations) and C._n == self._n and C._m == 2: + return lambda P, x: P.element_class(P, + [1 if v == 0 else -1 + for v in x._colors], + x._perm) + return super(SignedPermutations, self)._coerce_map_from_(C) + @cached_method def index_set(self): """ From e92b704774396ffb2fa1a25e9ceb45e8a2c8f9f0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 15:50:29 -0500 Subject: [PATCH 1382/1872] Following Jeroen's suggestion. --- src/sage/modules/free_module_element.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index cfcb49095e9..24de92f1e77 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -4591,9 +4591,9 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): 14 """ cdef dict e - if right.is_sparse_c(): - e = (right)._entries - else: + try: + e = (right)._entries + except: e = right.dict() z = left.base_ring().zero() if left.base_ring() is not right.base_ring(): From 26a0b6bc624b8eee81d35dfcf0dfa85b626a6245 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 16:01:09 -0500 Subject: [PATCH 1383/1872] TypeError... --- src/sage/modules/free_module_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 24de92f1e77..587bc33f032 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -4593,7 +4593,7 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): cdef dict e try: e = (right)._entries - except: + except TypeError: e = right.dict() z = left.base_ring().zero() if left.base_ring() is not right.base_ring(): From ef2220843f6bc126070520797e799b45a7650147 Mon Sep 17 00:00:00 2001 From: Jessica Striker Date: Sat, 10 Oct 2015 16:45:40 -0500 Subject: [PATCH 1384/1872] made a single to_dyck_word method with two different algorithms, 'last diagonal' and 'link pattern' --- src/sage/combinat/alternating_sign_matrix.py | 83 +++++++++++--------- 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 6d68a4a2dc6..ddef8a522ae 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -541,32 +541,6 @@ def link_pattern(self): """ return self.to_fully_packed_loop().link_pattern() - def to_link_pattern_dyck_word(self): - """ - Return the Dyck word in bijection with the link pattern of self. - - EXAMPLES:: - - sage: A = AlternatingSignMatrices(3) - sage: asm = A([[0,1,0],[1,0,0],[0,0,1]]) - sage: asm.to_link_pattern_dyck_word() - [1, 0, 1, 0, 1, 0] - sage: asm = A([[0,1,0],[1,-1,1],[0,1,0]]) - sage: asm.to_link_pattern_dyck_word() - [1, 0, 1, 1, 0, 0] - sage: A = AlternatingSignMatrices(4) - sage: asm = A([[0,0,1,0],[1,0,0,0],[0,1,-1,1],[0,0,1,0]]) - sage: asm.to_link_pattern_dyck_word() - [1, 1, 1, 0, 1, 0, 0, 0] - """ - from sage.combinat.perfect_matching import PerfectMatching - from sage.combinat.dyck_word import DyckWords - p = PerfectMatching(self.link_pattern()).to_non_crossing_set_partition() - asm = self.to_matrix() - n = asm.nrows() - d = DyckWords(n) - return d.from_noncrossing_partition(p) - @combinatorial_map(name='gyration') def gyration(self): r""" @@ -833,25 +807,62 @@ def ASM_compatible_smaller(self): return(output) @combinatorial_map(name='to Dyck word') - def to_dyck_word(self): + def to_dyck_word(self, method): r""" - Return the Dyck word determined by the last diagonal of - the monotone triangle corresponding to ``self``. + Return a Dyck word determined by one of the following methods: + 'last diagonal', which uses the last diagonal of the monotone triangle + corresponding to ``self``, or 'link pattern', which finds the Dyck word + in bijection with the link pattern of the fully packed loop. + + Note that these two methods in general yield different Dyck words for a + given alternating sign matrix. + + INPUT: + + - ``method`` - + + - ``'last diagonal'`` + - ``'link pattern'`` EXAMPLES:: sage: A = AlternatingSignMatrices(3) - sage: A([[0,1,0],[1,0,0],[0,0,1]]).to_dyck_word() + sage: A([[0,1,0],[1,0,0],[0,0,1]]).to_dyck_word(method = 'last diagonal') [1, 1, 0, 0, 1, 0] - sage: d = A([[0,1,0],[1,-1,1],[0,1,0]]).to_dyck_word(); d + sage: d = A([[0,1,0],[1,-1,1],[0,1,0]]).to_dyck_word(method = 'last diagonal'); d [1, 1, 0, 1, 0, 0] sage: parent(d) Complete Dyck words - """ - MT = self.to_monotone_triangle() - nplus = self._matrix.nrows() + 1 - parkfn = [nplus - row[0] for row in list(MT) if len(row) > 0] - return NonDecreasingParkingFunction(parkfn).to_dyck_word().reverse() + sage: A = AlternatingSignMatrices(3) + sage: asm = A([[0,1,0],[1,0,0],[0,0,1]]) + sage: asm.to_dyck_word(method = 'link pattern') + [1, 0, 1, 0, 1, 0] + sage: asm = A([[0,1,0],[1,-1,1],[0,1,0]]) + sage: asm.to_dyck_word(method = 'link pattern') + [1, 0, 1, 1, 0, 0] + sage: A = AlternatingSignMatrices(4) + sage: asm = A([[0,0,1,0],[1,0,0,0],[0,1,-1,1],[0,0,1,0]]) + sage: asm.to_dyck_word(method = 'link pattern') + [1, 1, 1, 0, 1, 0, 0, 0] + sage: asm.to_dyck_word() + Traceback (most recent call last): + ... + TypeError: to_dyck_word() takes exactly 2 arguments (1 given) + """ + if method == 'last diagonal': + MT = self.to_monotone_triangle() + nplus = self._matrix.nrows() + 1 + parkfn = [nplus - row[0] for row in list(MT) if len(row) > 0] + return NonDecreasingParkingFunction(parkfn).to_dyck_word().reverse() + + elif method == 'link pattern': + from sage.combinat.perfect_matching import PerfectMatching + from sage.combinat.dyck_word import DyckWords + p = PerfectMatching(self.link_pattern()).to_non_crossing_set_partition() + asm = self.to_matrix() + n = asm.nrows() + d = DyckWords(n) + return d.from_noncrossing_partition(p) def number_negative_ones(self): """ From 716469ac9519fc492467d4a635c80468880df94d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 17:22:00 -0500 Subject: [PATCH 1385/1872] Some smaller reviewer tweaks. --- .../homology/algebraic_topological_model.py | 40 ++++---- src/sage/homology/cell_complex.py | 63 ++++++++----- src/sage/homology/chain_homotopy.py | 74 +++++++-------- src/sage/homology/cubical_complex.py | 6 +- .../homology_vector_space_with_basis.py | 91 ++++++++++--------- 5 files changed, 146 insertions(+), 128 deletions(-) diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index eaf16035dc6..f1f85b43f4b 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -37,20 +37,20 @@ def algebraic_topological_model(K, base_ring=None): r""" Algebraic topological model for cell complex ``K`` - with coefficients in the field ``base_ring`` + with coefficients in the field ``base_ring``. INPUT: - ``K`` -- either a simplicial complex or a cubical complex - - ``base_ring`` -- coefficient ring (optional, default ``QQ``). - Must be a field. + - ``base_ring`` -- coefficient ring (optional, default ``QQ``); + must be a field OUTPUT: a pair ``(phi, M)`` consisting of - the chain contraction ``phi`` associated to `C`, `M`, `\pi: C \to M`, and `\iota: M \to C` satisfying `\iota \pi = 1_M` and - `\pi \iota`. - - the chain complex `M` + `\pi \iota`; and + - the chain complex `M`. This construction appears in a paper by Pilarczyk and Réal [PR]_. Given a cell complex `K` and a field `F`, there is a chain complex @@ -59,8 +59,8 @@ def algebraic_topological_model(K, base_ring=None): differential, along with chain maps `\pi: C \to M` and `\iota: M \to C` such that - - `\pi \circ \iota = 1_M`. - - There is a chain homotopy `\phi` between `1_C` and `\iota \circ \pi`. + - `\pi \circ \iota = 1_M`, and + - there is a chain homotopy `\phi` between `1_C` and `\iota \circ \pi`. In particular, `\pi` and `\iota` induce isomorphisms on homology, and since `M` has trivial differential, it is its own @@ -168,7 +168,7 @@ def algebraic_topological_model(K, base_ring=None): if base_ring is None: base_ring = QQ if not base_ring.is_field(): - raise ValueError('the coefficient ring must be a field.') + raise ValueError('the coefficient ring must be a field') # The following are all dictionaries indexed by dimension. # For each n, gens[n] is an ordered list of the n-cells generating the complex M. @@ -343,7 +343,7 @@ def algebraic_topological_model(K, base_ring=None): def algebraic_topological_model_delta_complex(K, base_ring=None): r""" Algebraic topological model for cell complex ``K`` - with coefficients in the field ``base_ring`` + with coefficients in the field ``base_ring``. This has the same basic functionality as :func:`algebraic_topological_model`, but it also works for @@ -354,15 +354,15 @@ def algebraic_topological_model_delta_complex(K, base_ring=None): - ``K`` -- a simplicial complex, a cubical complex, or a Delta complex - - ``base_ring`` -- coefficient ring (optional, default ``QQ``) - Must be a field. + - ``base_ring`` -- coefficient ring (optional, default ``QQ``); + must be a field OUTPUT: a pair ``(phi, M)`` consisting of - the chain contraction ``phi`` associated to `C`, `M`, `\pi: C \to M`, and `\iota: M \to C` satisfying `\iota \pi = 1_M` and - `\pi \iota`. - - the chain complex `M` + `\pi \iota`; and + - the chain complex `M`. See :func:`algebraic_topological_model` for the main documentation. The difference in implementation between the two: @@ -456,8 +456,8 @@ def conditionally_sparse(m): if base_ring is None: base_ring = QQ - if not base_ring.is_field(): - raise ValueError('the coefficient ring must be a field.') + elif not base_ring.is_field(): + raise ValueError('the coefficient ring must be a field') # The following are all dictionaries indexed by dimension. # For each n, gens[n] is an ordered list of the n-cells generating the complex M. @@ -480,19 +480,24 @@ def conditionally_sparse(m): # n_cells: the standard basis for the vector space C.free_module(dim). n_cells = C.free_module(dim).gens() diff = C.differential(dim) + # diff is sparse and low density. Dense matrices are faster + # over finite fields, but for low density matrices, sparse + # matrices are faster over the rationals. + if base_ring != QQ: + diff = diff.dense_matrix() + rank = len(n_cells) old_rank = len(old_cells) # Create some matrix spaces to try to speed up matrix creation. MS_pi_t = MatrixSpace(base_ring, old_rank, len(gens[dim-1])) - # MS_phi_t = MatrixSpace(base_ring, old_rank, rank) pi_old = MS_pi_t.matrix(pi_cols).transpose() iota_cols_old = iota_cols iota_cols = {} pi_cols_old = pi_cols pi_cols = [] - phi_old = matrix(base_ring, rank, old_rank) + phi_old = MatrixSpace(base_ring, rank, old_rank, sparse=(base_ring==QQ)).zero() phi_old_cols = phi_old.columns() phi_old = conditionally_sparse(phi_old) to_be_deleted = [] @@ -596,3 +601,4 @@ def conditionally_sparse(m): iota = ChainComplexMorphism(iota_data, M, C) phi = ChainContraction(phi_data, pi, iota) return phi, M + diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 8c110df4bbf..1c6af68409c 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -661,13 +661,13 @@ def n_chains(self, n, base_ring=None, cochains=False): - ``n`` -- integer - ``base_ring`` -- ring (optional, default `\ZZ`) - - ``cochains`` -- boolean (optional, default ``False``). If - ``True``, return cochains instead. + - ``cochains`` -- boolean (optional, default ``False``); if + ``True``, return cochains instead The only difference between chains and cochains is notation. In a simplicial complex, for example, a simplex ``(0,1,2)`` is written as "(0,1,2)" in the group of chains but - as "\\chi_(0,1,2)" in the group of cochains. + as "\chi_(0,1,2)" in the group of cochains. EXAMPLES:: @@ -686,11 +686,16 @@ def n_chains(self, n, base_ring=None, cochains=False): @cached_method def algebraic_topological_model(self, base_ring=None): r""" - Algebraic topological model, as defined by Pilarczyk and Réal - [PR]_, for this cell complex with coefficients in ``base_ring``. + Algebraic topological model for this cell complex with + coefficients in ``base_ring``. - This is only implemented for simplicial, cubical, and - `\Delta`-complexes. + The term algebraic topological model is defined by Pilarczyk + and Réal [PR]_. + + .. NOTE:: + + This is only implemented for simplicial, cubical, and + `\Delta`-complexes. INPUT: @@ -772,9 +777,9 @@ def homology_with_basis(self, dim, base_ring=None, cohomology=False): - ``dim`` -- dimension - ``base_ring`` -- coefficient ring (optional, default - ``QQ``). Must be a field. - - ``cohomology`` -- boolean (optional, default ``False``). If - ``True``, return cohomology instead of homology. + ``QQ``); must be a field + - ``cohomology`` -- boolean (optional, default ``False``); if + ``True``, return cohomology instead of homology Homology basis elements are named 'h_{dim,i}' where i ranges between 0 and `r-1`, if `r` is the rank of the homology @@ -812,9 +817,9 @@ def cohomology_with_basis(self, dim, base_ring=None): - ``dim`` -- dimension - ``base_ring`` -- coefficient ring (optional, default - ``QQ``). Must be a field. + ``QQ``); must be a field - The basis elements are named 'h^{dim,i}' where i ranges + The basis elements are named 'h^{dim,i}' where `i` ranges between 0 and `r-1`, if `r` is the rank of the homology group. EXAMPLES:: @@ -861,7 +866,7 @@ def cohomology_ring(self, base_ring=None): INPUT: - ``base_ring`` -- coefficient ring (optional, default - ``QQ``). Must be a field. + ``QQ``); must be a field This returns a finite-dimensional algebra: more precisely, an instance of @@ -1082,12 +1087,12 @@ class Chains(CombinatorialFreeModule): - ``n_cells`` -- tuple of `n`-cells, which thus forms a basis for this module - ``base_ring`` -- optional (default `\ZZ`) - - ``cochains`` -- boolean (optional, default ``False``). If - ``True``, return cochains instead. + - ``cochains`` -- boolean (optional, default ``False``); if + ``True``, return cochains instead One difference between chains and cochains is notation. In a simplicial complex, for example, a simplex ``(0,1,2)`` is written - as "(0,1,2)" in the group of chains but as "\\chi_(0,1,2)" in the + as "(0,1,2)" in the group of chains but as "\chi_(0,1,2)" in the group of cochains. Also, since the free modules of chains and cochains are dual, @@ -1118,7 +1123,15 @@ def __init__(self, n_cells, base_ring=None, cochains=False): sage: T = cubical_complexes.Torus() sage: T.n_chains(2, QQ) - Free module generated by {[1,1] x [0,1] x [1,1] x [0,1], [0,0] x [0,1] x [0,1] x [1,1], [0,0] x [0,1] x [1,1] x [0,1], [0,0] x [0,1] x [0,0] x [0,1], [0,1] x [1,1] x [0,1] x [0,0], [0,1] x [0,0] x [0,0] x [0,1], [1,1] x [0,1] x [0,1] x [0,0], [0,1] x [1,1] x [0,0] x [0,1], [0,0] x [0,1] x [0,1] x [0,0], [0,1] x [0,0] x [0,1] x [0,0], [0,1] x [0,0] x [1,1] x [0,1], [0,1] x [1,1] x [1,1] x [0,1], [0,1] x [0,0] x [0,1] x [1,1], [1,1] x [0,1] x [0,0] x [0,1], [1,1] x [0,1] x [0,1] x [1,1], [0,1] x [1,1] x [0,1] x [1,1]} over Rational Field + Free module generated by {[1,1] x [0,1] x [1,1] x [0,1], + [0,0] x [0,1] x [0,1] x [1,1], [0,0] x [0,1] x [1,1] x [0,1], + [0,0] x [0,1] x [0,0] x [0,1], [0,1] x [1,1] x [0,1] x [0,0], + [0,1] x [0,0] x [0,0] x [0,1], [1,1] x [0,1] x [0,1] x [0,0], + [0,1] x [1,1] x [0,0] x [0,1], [0,0] x [0,1] x [0,1] x [0,0], + [0,1] x [0,0] x [0,1] x [0,0], [0,1] x [0,0] x [1,1] x [0,1], + [0,1] x [1,1] x [1,1] x [0,1], [0,1] x [0,0] x [0,1] x [1,1], + [1,1] x [0,1] x [0,0] x [0,1], [1,1] x [0,1] x [0,1] x [1,1], + [0,1] x [1,1] x [0,1] x [1,1]} over Rational Field sage: T.n_chains(2).dimension() 16 @@ -1183,12 +1196,12 @@ def eval(self, other): ... ValueError: the elements are not compatible """ - if self.parent()._cochains: - if not (other.parent().indices() == self.parent().indices() - and other.base_ring() == self.base_ring() - and not other.parent()._cochains): - raise ValueError('the elements are not compatible') - result = sum(coeff * other.coefficient(cell) for cell, coeff in self) - return result - else: + if not self.parent()._cochains: raise ValueError('this element is not a cochain') + if not (other.parent().indices() == self.parent().indices() + and other.base_ring() == self.base_ring() + and not other.parent()._cochains): + raise ValueError('the elements are not compatible') + result = sum(coeff * other.coefficient(cell) for cell, coeff in self) + return result + diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index eedfd8101ea..6f1bba15a5f 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -7,9 +7,9 @@ with differential of degree `-1`, a *chain homotopy* `H` between `f` and `g` is a collection of maps `H_n: C_n \to D_{n+1}` satisfying -.. math:: +.. MATH:: - \partial_D H + H \partial_C = f - g + \partial_D H + H \partial_C = f - g. The presence of a chain homotopy defines an equivalence relation (*chain homotopic*) on chain maps. If `f` and `g` are chain homotopic, @@ -33,20 +33,19 @@ REFERENCES: -.. [M-AR] H. Molina-Abril and P. Réal, "Homology computation using spanning - trees" in Progress in Pattern Recognition, Image Analysis, - Computer Vision, and Applications, Lecture Notes in Computer - Science, volume 5856, pp 272-278, Springer, Berlin (2009). +.. [M-AR] H. Molina-Abril and P. Réal, *Homology computation using spanning + trees* in Progress in Pattern Recognition, Image Analysis, + Computer Vision, and Applications, Lecture Notes in Computer + Science, volume 5856, pp 272-278, Springer, Berlin (2009). -.. [PR] P. Pilarczyk and P. Réal, "Computation of cubical homology, - cohomology, and (co)homological operations via chain contraction", - Adv. Comput. Math. 41 (2015), pp 253--275. +.. [PR] P. Pilarczyk and P. Réal, *Computation of cubical homology, + cohomology, and (co)homological operations via chain contraction*, + Adv. Comput. Math. 41 (2015), pp 253--275. -.. [RM-A] P. Réal and H. Molina-Abril, "Cell AT-models for digital - volumes" in Torsello, Escolano, Brun (eds.), Graph-Based - Representations in Pattern Recognition, Lecture Notes in - Computer Science, volume 5534, pp. 314-3232, Springer, - Berlin (2009). +.. [RM-A] P. Réal and H. Molina-Abril, *Cell AT-models for digital + volumes* in Torsello, Escolano, Brun (eds.), Graph-Based + Representations in Pattern Recognition, Lecture Notes in + Computer Science, volume 5534, pp. 314-3232, Springer, Berlin (2009). """ ######################################################################## @@ -63,21 +62,22 @@ from sage.homology.chain_complex_morphism import ChainComplexMorphism class ChainHomotopy(SageObject): - r"""A chain homotopy. + r""" + A chain homotopy. A chain homotopy `H` between chain maps `f, g: C \to D` is a sequence of maps `H_n: C_n \to D_{n+1}` (if the chain complexes are graded homologically) satisfying - .. math:: + .. MATH:: - \partial_D H + H \partial_C = f - g + \partial_D H + H \partial_C = f - g. INPUT: - ``matrices`` -- dictionary of matrices, keyed by dimension - - ``f`` -- chain map `C \to D`. - - ``g`` (optional) -- chain map `C \to D`. + - ``f`` -- chain map `C \to D` + - ``g`` (optional) -- chain map `C \to D` The dictionary ``matrices`` defines ``H`` by specifying the matrix defining it in each degree: the entry `m` corresponding to key `i` @@ -103,7 +103,8 @@ class ChainHomotopy(SageObject): sage: g = Hom(C,D)({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: H = ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1)}, f, g) - Note that the maps `f` and `g` are stored in the attributes ``H._f`` and ``H._g``:: + Note that the maps `f` and `g` are stored in the attributes ``H._f`` + and ``H._g``:: sage: H._f Chain complex morphism @@ -126,15 +127,10 @@ def __init__(self, matrices, f, g=None): Create a chain homotopy between the given chain maps from a dictionary of matrices. - INPUT: - - - ``matrices`` -- dictionary of matrices, keyed by dimension - - ``f`` -- chain map `C \to D`. - - ``g`` (optional) -- chain map `C \to D`. - EXAMPLES: - If ``g`` is not specified, it is set equal to `f - (H \partial + \partial H)`. :: + If ``g`` is not specified, it is set equal to + `f - (H \partial + \partial H)`. :: sage: from sage.homology.chain_homotopy import ChainHomotopy sage: C = ChainComplex({1: matrix(ZZ, 1, 2, (1,0)), 2: matrix(ZZ, 2, 1, (0, 2))}, degree_of_differential=-1) @@ -256,8 +252,10 @@ def is_homology_gradient_vector_field(self): A homology gradient vector field is an algebraic gradient vector field `H: C \to C` (i.e., a chain homotopy satisfying `H H = 0`) such that `\partial H \partial = \partial` and `H - \partial H = H`. See Molina-Abril and Réal [M-AR]_ and Réal - and Molina-Abril [RM-A]_ for this and related terminology. + \partial H = H`. + + See Molina-Abril and Réal [M-AR]_ and Réal and Molina-Abril + [RM-A]_ for this and related terminology. See also :meth:`is_algebraic_gradient_vector_field`. @@ -287,7 +285,7 @@ def is_homology_gradient_vector_field(self): def in_degree(self, n): """ - The matrix representing this chain homotopy in degree ``n`` + The matrix representing this chain homotopy in degree ``n``. INPUT: @@ -303,7 +301,8 @@ def in_degree(self, n): sage: H.in_degree(1) [3 1] - This returns an appropriately sized zero matrix if the chain homotopy is not defined in degree n:: + This returns an appropriately sized zero matrix if the chain + homotopy is not defined in degree n:: sage: H.in_degree(-3) [] @@ -418,6 +417,8 @@ def _repr_(self): class ChainContraction(ChainHomotopy): r""" + A chain contraction. + An algebraic gradient vector field `H: C \to C` (that is a chain homotopy satisfying `H H = 0`) for which there are chain maps `\pi: C \to D` ("projection") and `\iota: D \to C` @@ -442,8 +443,8 @@ class ChainContraction(ChainHomotopy): sage: C = ChainComplex({0: zero_matrix(ZZ, 1), 1: identity_matrix(ZZ, 1)}) sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) - The chain complex `C` is chain homotopy equivalent to `D`, which is just a - copy of `\ZZ` in degree 0, and we construct a chain contraction:: + The chain complex `C` is chain homotopy equivalent to `D`, which is just + a copy of `\ZZ` in degree 0, and we construct a chain contraction:: sage: pi = Hom(C,D)({0: identity_matrix(ZZ, 1)}) sage: iota = Hom(D,C)({0: identity_matrix(ZZ, 1)}) @@ -453,12 +454,6 @@ def __init__(self, matrices, pi, iota): r""" Create a chain contraction from the given data. - INPUTS: - - - ``matrices`` -- dictionary of matrices, keyed by dimension - - ``pi`` -- a chain map `C \to D` - - ``iota`` -- a chain map `D \to C` - EXAMPLES:: sage: from sage.homology.chain_homotopy import ChainContraction @@ -632,3 +627,4 @@ def dual(self): deg = self.domain().degree_of_differential() matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} return ChainContraction(matrices, self.iota().dual(), self.pi().dual()) + diff --git a/src/sage/homology/cubical_complex.py b/src/sage/homology/cubical_complex.py index 1b26767a07d..07e5e3a19e5 100644 --- a/src/sage/homology/cubical_complex.py +++ b/src/sage/homology/cubical_complex.py @@ -552,10 +552,10 @@ def alexander_whitney(self, dim): r""" Subdivide this cube into pairs of cubes. - This provides a cubical approximation for the diagonal map `K - \to K \times K`. + This provides a cubical approximation for the diagonal map + `K \to K \times K`. - INPUTS: + INPUT: - ``dim`` -- integer between 0 and one more than the dimension of this cube diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 8ddf535243b..c24a755d737 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -7,13 +7,12 @@ REFERENCES: -.. [G-DR03] R. González-Díaz and P. Réal, "Computation of cohomology - operations on finite simplicial complexes" in Homology, - Homotopy and Applications 5 (2003), 83-93. +.. [G-DR03] R. González-Díaz and P. Réal, *Computation of cohomology + operations on finite simplicial complexes* in Homology, + Homotopy and Applications 5 (2003), 83-93. -.. [G-DR99] R. González-Díaz and P. Réal, "A combinatorial method for - computing Steenrod squares" in J. Pure Appl. Algebra 139 - (1999), 89-108. +.. [G-DR99] R. González-Díaz and P. Réal, *A combinatorial method for + computing Steenrod squares* in J. Pure Appl. Algebra 139 (1999), 89-108. AUTHORS: @@ -35,7 +34,8 @@ from cubical_complex import CubicalComplex class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): - """Homology (or cohomology) vector space. + """ + Homology (or cohomology) vector space. This is intended to provide enough structure to allow the computation of cup products and cohomology operations. The former @@ -44,13 +44,21 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): It also requires field coefficients (hence the "VectorSpace" in the name of the class). - .. note:: + .. NOTE:: This is not intended to be used directly by the user, but instead via the methods :meth:`cell_complex.CellComplex.homology_with_basis` and :meth:`cell_complex.CellComplex.cohomology_with_basis`. + INPUT: + + - ``deg`` -- the degree of this homology group + - ``contraction`` -- the chain contraction associated to this + homology computation + - ``cell_complex`` -- the cell complex whose homology we are + computing + EXAMPLES: Homology classes are denoted by ``h_{d,i}`` where ``d`` is the @@ -129,13 +137,7 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): """ def __init__(self, deg, contraction, cell_complex): """ - INPUTS: - - - ``deg`` -- the degree of this homology group - - ``contraction`` -- the chain contraction associated to this - homology computation - - ``cell_complex`` -- the cell complex whose homology we are - computing + Initialize ``self``. EXAMPLES:: @@ -161,7 +163,7 @@ def __init__(self, deg, contraction, cell_complex): CombinatorialFreeModule.__init__(self, M.base_ring(), range(rank)) def degree(self): - """ + r""" The degree of this homology group: if this is `H_n(K)` for some complex `K`, return `n`. @@ -204,7 +206,8 @@ def contraction(self): From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field - From the chain contraction, one can also recover the maps `\pi` and `\iota`:: + From the chain contraction, one can also recover the maps `\pi` + and `\iota`:: sage: phi = H1.contraction() sage: phi.pi() @@ -241,8 +244,8 @@ def _repr_(self): def _repr_term(self, i): """ - Return 'h_{d,i}' for the ith generator in degree d for homology, - 'h^{d,i}' for cohomology. + Return ``'h_{d,i}'`` for the ``i``-th generator in degree ``d`` + for homology, ``'h^{d,i}'`` for cohomology. EXAMPLES:: @@ -298,9 +301,9 @@ def cup_product(self, other): r""" The cup product of this element with ``other``. - INPUTS: + INPUT: - - ``other`` -- a cohomology class from the same cell complex. + - ``other`` -- a cohomology class from the same cell complex Algorithm: see González-Díaz and Réal [G-DR03]_, p. 88. Given two cohomology classes, lift them to cocycle @@ -370,11 +373,11 @@ def cup_product(self, other): sage: K.cohomology_ring(QQ).is_unitary() # long time True """ - complex = self.parent().complex() - if not isinstance(complex, (SimplicialComplex, CubicalComplex)): + scomplex = self.parent().complex() + if not isinstance(scomplex, (SimplicialComplex, CubicalComplex)): raise NotImplementedError('cup products are only implemented for simplicial and cubiical complexes') base_ring = self.base_ring() - if not (complex == other.parent().complex() + if not (scomplex == other.parent().complex() and self.parent()._cohomology and other.parent()._cohomology): raise ValueError('these are not cohomology classes from the same complex') @@ -382,21 +385,21 @@ def cup_product(self, other): deg_right = other.parent().degree() deg_tot = deg_left + deg_right result = [] - for gamma in complex.homology_with_basis(deg_tot, base_ring).basis(): + for gamma in scomplex.homology_with_basis(deg_tot, base_ring).basis(): gamma_coeff = base_ring.zero() for cell, coeff in gamma.to_cycle(): for (c, left_cell, right_cell) in cell.alexander_whitney(deg_left): - left = complex.n_chains(deg_left, base_ring)(left_cell) - right = complex.n_chains(deg_right, base_ring)(right_cell) + left = scomplex.n_chains(deg_left, base_ring)(left_cell) + right = scomplex.n_chains(deg_right, base_ring)(right_cell) gamma_coeff += c * coeff * self.to_cycle().eval(left) * other.to_cycle().eval(right) result.append((gamma.leading_support(), gamma_coeff)) - return complex.cohomology_with_basis(deg_tot, base_ring).sum_of_terms(result) + return scomplex.cohomology_with_basis(deg_tot, base_ring).sum_of_terms(result) __mul__ = cup_product def __pow__(self, n): r""" - This element raised to the nth power + This element raised to the ``n``-th power INPUT: @@ -437,8 +440,8 @@ def __pow__(self, n): if n < 0: raise ValueError('the power must be non-negative') if n == 0: - complex = self.parent().complex() - zeroth_cohomology = complex.cohomology_with_basis(0, self.base_ring()) + scomplex = self.parent().complex() + zeroth_cohomology = scomplex.cohomology_with_basis(0, self.base_ring()) return sum(zeroth_cohomology.gens()) if n == 1: return self @@ -446,13 +449,13 @@ def __pow__(self, n): def Sq(self, i): r""" - Return the result of applying Sq^i to this element. + Return the result of applying `Sq^i` to this element. INPUT: - ``i`` -- nonnegative integer - .. warning:: + .. WARNING:: This is only implemented for simplicial complexes, not cubical complexes. @@ -504,8 +507,8 @@ def Sq(self, i): ... ValueError: Steenrod squares are only defined in characteristic 2 """ - complex = self.parent().complex() - if not isinstance(complex, SimplicialComplex): + scomplex = self.parent().complex() + if not isinstance(scomplex, SimplicialComplex): raise NotImplementedError('Steenrod squares are only implemented for simplicial complexes') base_ring = self.base_ring() if base_ring.characteristic() != 2: @@ -517,7 +520,7 @@ def Sq(self, i): if i == 0: # Sq^0 is the identity. return self - target = complex.cohomology_with_basis(m, base_ring) + target = scomplex.cohomology_with_basis(m, base_ring) if target.dimension() == 0: return target.zero() if i > j: @@ -542,7 +545,7 @@ def Sq(self, i): # 3.2. result = [] cycle = self.to_cycle() - for gamma in complex.homology_with_basis(m, base_ring).basis(): + for gamma in scomplex.homology_with_basis(m, base_ring).basis(): gamma_coeff = base_ring.zero() for cell, coeff in gamma.to_cycle(): for indices in sums: @@ -579,21 +582,22 @@ def Sq(self, i): for k in range(right_endpoint, -1, -1): right = right.face(k) - left = complex.n_chains(j, base_ring)(left) - right = complex.n_chains(j, base_ring)(right) + left = scomplex.n_chains(j, base_ring)(left) + right = scomplex.n_chains(j, base_ring)(right) gamma_coeff += coeff * cycle.eval(left) * cycle.eval(right) result.append((gamma.leading_support(), gamma_coeff)) - return complex.cohomology_with_basis(m, base_ring).sum_of_terms(result) + return scomplex.cohomology_with_basis(m, base_ring).sum_of_terms(result) def sum_indices(k, i_k_plus_one, S_k_plus_one): - """This is a recursive function for computing the indices for the + r""" + This is a recursive function for computing the indices for the nested sums in González-Díaz and Réal [G-DR99]_, Corollary 3.2. In the paper, given indices `i_n`, `i_{n-1}`, ..., `i_{k+1}`, given `k`, and given `S(k+1)`, the number `S(k)` is defined to be - .. math:: + .. MATH:: S(k) = -S(k+1) + floor(k/2) + floor((k+1)/2) + i_{k+1}, @@ -605,7 +609,7 @@ def sum_indices(k, i_k_plus_one, S_k_plus_one): indices `[i_k, i_{k-1}, ..., i_1, i_0]` given by the above formula. - INPUTS: + INPUT: - ``k`` -- non-negative integer - ``i_k_plus_one`` -- the positive integer `i_{k+1}` @@ -618,7 +622,6 @@ def sum_indices(k, i_k_plus_one, S_k_plus_one): [[1, 0], [2, 1]] sage: sum_indices(0, 4, 2) [[2]] - """ S_k = -S_k_plus_one + k//2 + (k+1)//2 + i_k_plus_one if k == 0: From 535e32f11b264c9cb806ea07cda5ae4417dd2485 Mon Sep 17 00:00:00 2001 From: Jessica Striker Date: Sat, 10 Oct 2015 17:30:20 -0500 Subject: [PATCH 1386/1872] edit of doc, input, and value error on to_dyck_word --- src/sage/combinat/alternating_sign_matrix.py | 34 ++++++++++++-------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index ddef8a522ae..c7fefe77431 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -809,10 +809,12 @@ def ASM_compatible_smaller(self): @combinatorial_map(name='to Dyck word') def to_dyck_word(self, method): r""" - Return a Dyck word determined by one of the following methods: - 'last diagonal', which uses the last diagonal of the monotone triangle - corresponding to ``self``, or 'link pattern', which finds the Dyck word - in bijection with the link pattern of the fully packed loop. + Return a Dyck word determined by the specified method. + + The method 'last_diagonal' uses the last diagonal of the monotone + triangle corresponding to ``self``. The method 'link_pattern' returns + the Dyck word in bijection with the link pattern of the fully packed + loop. Note that these two methods in general yield different Dyck words for a given alternating sign matrix. @@ -821,41 +823,45 @@ def to_dyck_word(self, method): - ``method`` - - - ``'last diagonal'`` - - ``'link pattern'`` + - ``'last_diagonal'`` + - ``'link_pattern'`` EXAMPLES:: sage: A = AlternatingSignMatrices(3) - sage: A([[0,1,0],[1,0,0],[0,0,1]]).to_dyck_word(method = 'last diagonal') + sage: A([[0,1,0],[1,0,0],[0,0,1]]).to_dyck_word(method = 'last_diagonal') [1, 1, 0, 0, 1, 0] - sage: d = A([[0,1,0],[1,-1,1],[0,1,0]]).to_dyck_word(method = 'last diagonal'); d + sage: d = A([[0,1,0],[1,-1,1],[0,1,0]]).to_dyck_word(method = 'last_diagonal'); d [1, 1, 0, 1, 0, 0] sage: parent(d) Complete Dyck words sage: A = AlternatingSignMatrices(3) sage: asm = A([[0,1,0],[1,0,0],[0,0,1]]) - sage: asm.to_dyck_word(method = 'link pattern') + sage: asm.to_dyck_word(method = 'link_pattern') [1, 0, 1, 0, 1, 0] sage: asm = A([[0,1,0],[1,-1,1],[0,1,0]]) - sage: asm.to_dyck_word(method = 'link pattern') + sage: asm.to_dyck_word(method = 'link_pattern') [1, 0, 1, 1, 0, 0] sage: A = AlternatingSignMatrices(4) sage: asm = A([[0,0,1,0],[1,0,0,0],[0,1,-1,1],[0,0,1,0]]) - sage: asm.to_dyck_word(method = 'link pattern') + sage: asm.to_dyck_word(method = 'link_pattern') [1, 1, 1, 0, 1, 0, 0, 0] sage: asm.to_dyck_word() Traceback (most recent call last): ... TypeError: to_dyck_word() takes exactly 2 arguments (1 given) + sage: asm.to_dyck_word(method = 'notamethod') + Traceback (most recent call last): + ... + ValueError: unknown method 'notamethod' """ - if method == 'last diagonal': + if method == 'last_diagonal': MT = self.to_monotone_triangle() nplus = self._matrix.nrows() + 1 parkfn = [nplus - row[0] for row in list(MT) if len(row) > 0] return NonDecreasingParkingFunction(parkfn).to_dyck_word().reverse() - elif method == 'link pattern': + elif method == 'link_pattern': from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.dyck_word import DyckWords p = PerfectMatching(self.link_pattern()).to_non_crossing_set_partition() @@ -864,6 +870,8 @@ def to_dyck_word(self, method): d = DyckWords(n) return d.from_noncrossing_partition(p) + raise ValueError("unknown method '%s'" % method) + def number_negative_ones(self): """ Return the number of entries in ``self`` equal to -1. From ff97f0b11bb9f5dd9b27a6ee738f89d3efb6e6f0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 17:47:42 -0500 Subject: [PATCH 1387/1872] Getting one last reference. --- src/sage/combinat/skew_tableau.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index b49d163884b..cb1b6a308bc 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -780,7 +780,7 @@ def slide(self, corner=None): return the resulting tableau. If no corner is given, an arbitrary inner corner is chosen. - See [FW]_ p12-13. + See [Fulton97]_ p12-13. EXAMPLES:: From 6e7cb2173baacb6b5bbb8b29ec7cafb57c4ad6c7 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Sat, 10 Oct 2015 18:03:09 -0500 Subject: [PATCH 1388/1872] Created conversions of SymmetricGroupAlgebra to DiagramAlgebras as well as appropriate coercions where it makes sense --- src/sage/combinat/diagram_algebras.py | 56 ++++++++++++++++++--------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 6672e2e1a8d..90ef23e015f 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -31,7 +31,7 @@ from sage.structure.global_options import GlobalOptions from sage.combinat.set_partition import SetPartitions, SetPartition from sage.combinat.partition import Partitions -from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra +from sage.combinat.symmetric_group_algebra import (SymmetricGroupAlgebra, SymmetricGroupAlgebra_n) from sage.combinat.permutation import Permutations from sage.combinat.combinat import (bell_number, catalan_number) from sage.sets.set import Set @@ -1200,18 +1200,6 @@ class DiagramAlgebra(CombinatorialFreeModule): P{{-2, 2}, {-1}, {1}}, P{{-2, 2}, {-1, 1}}] - Due to the nature of diagrams, there is also a built-in coercion to turn - SymmetricGroupAlgebra elements into DiagramAlgebra elements. However, - this coercion can cause errors if the SymmetricGroupAlgebra element - is not actually valid in the algebra. For instance, not all - SymmetricGroupAlgebra elements are valid in the Temperely--Lieb algebra, - but the planar ones are. - - :: - - sage: S = SymmetricGroupAlgebra(R, 2) - sage: S([2,1])*D([[1,-1],[2,-2]]) - P{{-2, 1}, {-1, 2}} """ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): r""" @@ -1233,18 +1221,14 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): sage: D = da.DiagramAlgebra(2, x, R, 'P', da.PartitionDiagrams(2)) sage: TestSuite(D).run() """ - SymmetricGroupAlgebra(base_ring,k) # Necessary for some odd reason self._prefix = prefix self._q = base_ring(q) self._k = k self._base_diagrams = diagrams category = Algebras(base_ring).FiniteDimensional().WithBasis().or_subcategory(category) - KSS = SymmetricGroupAlgebra(base_ring, k) CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) - KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)), codomain=self).register_as_coercion() - def _element_constructor_(self, set_partition): r""" Construct an element of ``self``. @@ -1263,10 +1247,14 @@ def _element_constructor_(self, set_partition): True sage: D([{1,2},{-1,-2}]) == b_elt True + sage: S = SymmetricGroupAlgebra(SR,2) + sage: D(S([2,1])) + P{{-2, 1}, {-1, 2}} """ if self.basis().keys().is_parent_of(set_partition): return self.basis()[set_partition] - + if isinstance(set_partition, SymmetricGroupAlgebra_n.Element): + return self._element_constructor(self._perm_to_Blst(set_partition.support_of_term())) sp = self._base_diagrams(set_partition) # attempt conversion if sp in self.basis().keys(): return self.basis()[sp] @@ -1297,6 +1285,9 @@ def _perm_to_Blst(self, w): u = sorted(w) return [[u[i],-w[i]] for i in range(len(w))] + def _convert_perm_to_element_of_self(self, x): + return self(self._perm_to_Blst(x)) + def order(self): r""" Return the order of ``self``. @@ -1650,6 +1641,16 @@ class PartitionAlgebra(DiagramAlgebra): sage: a*a 17*P{{-1}, {1}} + Symmetric group algebra elements can also be coerced into the partition algebra. + + TESTS: + + sage: A = PartitionAlgebra(2, x, SR) + sage: S = SymmetricGroupAlgebra(SR, 2) + sage: S([2,1])*A([[1,-1],[2,-2]]) + P{{-2, 1}, {-1, 2}} + + REFERENCES: .. [HR2005] Tom Halverson and Arun Ram, *Partition algebras*. European @@ -1688,7 +1689,10 @@ def __init__(self, k, q, base_ring, prefix): self._k = k self._prefix = prefix self._q = base_ring(q) + KSS = SymmetricGroupAlgebra(base_ring, k) DiagramAlgebra.__init__(self, k, q, base_ring, prefix, PartitionDiagrams(k)) + KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)), codomain=self).register_as_coercion() + def _repr_(self): """ @@ -1835,6 +1839,16 @@ class BrauerAlgebra(SubPartitionAlgebra): x*B{{-2, -1}, {1, 2}} sage: b[2]^5 x^4*B{{-2, -1}, {1, 2}} + + Note, also that since the symmetric group algebra is contained in the Brauer algebra, + there is also a coercion between the two. :: + + sage: R. = ZZ[] + sage: B = BrauerAlgebra(2,x,R) + sage: S = SymmetricGroupAlgebra(R,2) + sage: S([2,1])*B([[1,-1],[2,-2]]) + B{{-2, 1}, {-1, 2}} + """ global_options = BrauerDiagramOptions @@ -1866,7 +1880,9 @@ def __init__(self, k, q, base_ring, prefix): sage: BA = BrauerAlgebra(2, q, R) sage: TestSuite(BA).run() """ + KSS = SymmetricGroupAlgebra(base_ring, k) SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, BrauerDiagrams(k)) + KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)), codomain=self).register_as_coercion() def _repr_(self): """ @@ -1900,6 +1916,8 @@ def _element_constructor_(self, set_partition): sage: BA([{1,2},{-1,-2}]) == b_elt True """ + if isinstance(set_partition, SymmetricGroupAlgebra_n.Element): + return DiagramAlgebra._element_constructor_(self, set_partition) set_partition = to_Brauer_partition(set_partition, k = self.order()) return DiagramAlgebra._element_constructor_(self, set_partition) @@ -2013,6 +2031,8 @@ def _element_constructor_(self, set_partition): sage: TL([{1,2},{-1,-2}]) == b_elt True """ + if isinstance(set_partition, SymmetricGroupAlgebra_n.Element): + return SubPartitionAlgebra._element_constructor_(self, set_partition) set_partition = to_Brauer_partition(set_partition, k = self.order()) return SubPartitionAlgebra._element_constructor_(self, set_partition) From 1ec481d803e3fa7d8c3d0e4038f4c476a73c0fd0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 10 Oct 2015 18:05:48 -0500 Subject: [PATCH 1389/1872] Addressing Kevin's comments. --- src/sage/combinat/partition.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 362c7b86956..cc4d0db3927 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -6687,12 +6687,20 @@ class RegularPartitions(Partitions): r""" Base class for `\ell`-regular partitions. - A partition is `\ell`-regular if `m_i < \ell` for all `i`. + Let `\ell` be a positive integer. A partition `\lambda` is + `\ell`-*regular* if `m_i < \ell` for all `i`, where `m_i` is the + multiplicity of `i` in `\lambda`. + + .. NOTE:: + + This is conjugate to the notion of `\ell`-*restricted* partitions, + where the difference between any two parts is at most `\ell`. INPUT: - - ``ell`` -- the value `\ell` - - ``is_infinite`` -- if the subset of `\ell`-regular partitions is infinite + - ``ell`` -- the integer `\ell` + - ``is_infinite`` -- boolean; if the subset of `\ell`-regular + partitions is infinite """ def __init__(self, ell, is_infinte=False): """ @@ -6779,7 +6787,7 @@ class RegularPartitions_all(RegularPartitions): INPUT: - - ``ell`` -- the value `\ell` + - ``ell`` -- the integer `\ell` .. SEEALSO:: @@ -6829,8 +6837,8 @@ class RegularPartitions_truncated(RegularPartitions): INPUT: - - ``ell`` -- the value `\ell` - - ``max_len`` -- the maximum length + - ``ell`` -- the integer `\ell` + - ``max_len`` -- integer; the maximum length .. SEEALSO:: @@ -6940,8 +6948,8 @@ class RegularPartitions_bounded(RegularPartitions): INPUT: - - ``ell`` -- the value `\ell` - - ``k`` -- the value `k` + - ``ell`` -- the integer `\ell` + - ``k`` -- integer; the value `k` .. SEEALSO:: @@ -7005,7 +7013,7 @@ class RegularPartitions_n(RegularPartitions, Partitions_n): INPUT: - ``n`` -- the integer `n` to partition - - ``ell`` -- the value `\ell` + - ``ell`` -- the integer `\ell` .. SEEALSO:: From ea857ff335ac439123ef7b7891bdd8909e5c3fb4 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Sat, 10 Oct 2015 19:11:11 -0500 Subject: [PATCH 1390/1872] added more negative unit tests for conversion from symmetric group algebra to diagram algebra. One test does not pass --- src/sage/combinat/diagram_algebras.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 90ef23e015f..7bc486265c6 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1247,9 +1247,16 @@ def _element_constructor_(self, set_partition): True sage: D([{1,2},{-1,-2}]) == b_elt True - sage: S = SymmetricGroupAlgebra(SR,2) + sage: S = SymmetricGroupAlgebra(R,2) sage: D(S([2,1])) P{{-2, 1}, {-1, 2}} + sage: D2 = da.DiagramAlgebra(2, x, R, 'P', da.PlanarDiagrams(2)) + sage: D2(S([1,2])) + P{{-2, 2}, {-1, 1}} + sage: D2(S([2,1])) + Traceback (most recent call last): + ... + ValueError: invalid input of [[1, -2], [2, -1]] """ if self.basis().keys().is_parent_of(set_partition): return self.basis()[set_partition] @@ -2030,6 +2037,13 @@ def _element_constructor_(self, set_partition): True sage: TL([{1,2},{-1,-2}]) == b_elt True + sage: S = SymmetricGroupAlgebra(R, 2) + sage: TL(S([1,2])) + T{{-2, 2}, {-1, 1}} + sage: TL(S([2,1])) + Traceback (most recent call last): + ... + ValueError: invalid input of [set([1, -2]), set([2, -1])] """ if isinstance(set_partition, SymmetricGroupAlgebra_n.Element): return SubPartitionAlgebra._element_constructor_(self, set_partition) From ec9cd10617f78bb1a8a0d1550d1accb6c765bc1e Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Sun, 11 Oct 2015 08:55:13 +0200 Subject: [PATCH 1391/1872] 17624: coerce factorizations to SR --- src/sage/symbolic/ring.pyx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index bdf639a1995..3891da5f05f 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -251,6 +251,18 @@ cdef class SymbolicRing(CommutativeRing): sage: bool(si == CC.0) True + Polynomial ring element factorizations:: + + sage: R. = QQ[] + sage: SR(factor(x^2 - 1)) + (x + 1)*(x - 1) + sage: R. = QQ[] + sage: SR(factor(x^2 - y^2)) + (x + y)*(x - y) + sage: R. = QQ[] + sage: SR(factor(x^2*y^3 + x^2*y^2*z - x*y^3 - x*y^2*z - 2*x*y*z - 2*x*z^2 + 2*y*z + 2*z^2)) + -(x*y^2 - 2*z)*(x - 1)*(y + z) + """ cdef GEx exp @@ -271,6 +283,7 @@ cdef class SymbolicRing(CommutativeRing): from sage.rings.infinity import (infinity, minus_infinity, unsigned_infinity) + from sage.structure.factorization import Factorization if isinstance(x, (Integer, RealNumber, float, long, complex)): GEx_construct_pyobject(exp, x) @@ -284,6 +297,9 @@ cdef class SymbolicRing(CommutativeRing): return new_Expression_from_GEx(self, g_UnsignedInfinity) elif isinstance(x, (RingElement, Matrix)): GEx_construct_pyobject(exp, x) + elif isinstance(x, Factorization): + from sage.misc.all import prod + return prod([SR(p)**e for p,e in x], SR.one()) else: raise TypeError From 85bec44fea218b440c2bee16b3bd1f856b9afaca Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 11 Oct 2015 11:30:07 +0200 Subject: [PATCH 1392/1872] trac #19390: Update the documentation of Graph/DiGraph constructors --- src/sage/graphs/digraph.py | 153 ++++++++++++------------------ src/sage/graphs/graph.py | 188 ++++++++++++++----------------------- 2 files changed, 134 insertions(+), 207 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index ab6e5501944..ff0a06e9229 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -119,94 +119,82 @@ class DiGraph(GenericGraph): - """Directed graph. + r""" + Directed graph. A digraph or directed graph is a set of vertices connected by oriented - edges. For more information, see the - `Wikipedia article on digraphs - `_. + edges. See also the `Wikipedia article on digraphs + `_.For a collection + of pre-defined digraphs, see the :mod:`~sage.graphs.digraph_generators` + module. - One can very easily create a directed graph in Sage by typing:: + A :class:`DiGraph` object has many methods whose list can be obtained by + typing ``g.`` (i.e. hit the 'tab' key) or by reading the documentation + of :mod:`~sage.graphs.digraph`, :mod:`~sage.graphs.generic_graph`, and + :mod:`~sage.graphs.graph`. - sage: g = DiGraph() - - By typing the name of the digraph, one can get some basic information - about it:: - - sage: g - Digraph on 0 vertices - - This digraph is not very interesting as it is by default the empty - graph. But Sage contains several pre-defined digraph classes that can - be listed this way: - - * Within a Sage sessions, type ``digraphs.`` - (Do not press "Enter", and do not forget the final period "." ) - * Hit "tab". - - You will see a list of methods which will construct named digraphs. For - example:: - - sage: g = digraphs.ButterflyGraph(3) - sage: g.plot() - Graphics object consisting of 81 graphics primitives - - You can also use the collection of pre-defined graphs, then create a - digraph from them. :: + INPUT: - sage: g = DiGraph(graphs.PetersenGraph()) - sage: g.plot() - Graphics object consisting of 50 graphics primitives + By default, a :class:`DiGraph` object is simple (i.e. no *loops* nor + *multiple edges*) and unweighted. This can be easily tuned with the + appropriate flags (see below). - Calling ``Digraph`` on a graph returns the original graph in which every - edge is replaced by two different edges going toward opposite directions. + - ``data`` -- can be any of the following (see the ``format`` argument): - In order to obtain more information about these digraph constructors, - access the documentation by typing ``digraphs.RandomDirectedGNP?``. + #. ``DiGraph()`` -- build a digraph on 0 vertices. - Once you have defined the digraph you want, you can begin to work on it - by using the almost 200 functions on graphs and digraphs in the Sage - library! If your digraph is named ``g``, you can list these functions as - previously this way + #. ``DiGraph(5)`` -- return an edgeless digraph on the 5 vertices 0,...,4. - * Within a Sage session, type ``g.`` - (Do not press "Enter", and do not forget the final period "." ) - * Hit "tab". + #. ``DiGraph(list_of_edges)`` -- return a digraph with a given list of + edges (see documentation of + :meth:`~sage.graphs.generic_graph.GenericGraph.add_edges`). - As usual, you can get some information about what these functions do by - typing (e.g. if you want to know about the ``diameter()`` method) - ``g.diameter?``. + To bypass auto-detection, prefer the more explicit ``DiGraph(L, + format='list_of_edges')``. - If you have defined a digraph ``g`` having several connected components - ( i.e. ``g.is_connected()`` returns False ), you can print each one of its - connected components with only two lines:: + #. ``DiGraph({1:[2,3,4],3:[4]})`` -- return a digraph by associating to + each vertex the list of its out-neighbors. - sage: for component in g.connected_components(): - ....: g.subgraph(component).plot() - Graphics object consisting of 50 graphics primitives + To bypass auto-detection, prefer the more explicit ``DiGraph(D, + format='dict_of_lists')``. - The same methods works for strongly connected components :: + #. ``DiGraph({1: {2: 'a', 3:'b'} ,3:{2:'c'}})`` -- return a graph by + associating a list of out-neighbors to each vertex and providing its + edge label. - sage: for component in g.strongly_connected_components(): - ....: g.subgraph(component).plot() - Graphics object consisting of 50 graphics primitives + To bypass auto-detection, prefer the more explicit ``DiGraph(D, + format='dict_of_dicts')``. + For digraphs with multiple edges, you can provide a list of labels + instead, e.g.: ``DiGraph({1: {2: ['a1', 'a2'], 3:['b']} + ,3:{2:['c']}})``. - INPUT: + #. ``DiGraph(a_matrix)`` -- return a digraph with given (weighted) adjacency + matrix (see documentation of + :meth:`~sage.graphs.generic_graph.GenericGraph.adjacency_matrix`). - - ``data`` - can be any of the following (see the ``format`` keyword): + To bypass auto-detection, prefer the more explicit ``DiGraph(M, + format='adjacency_matrix')``. To take weights into account, use + ``format='weighted_adjacency_matrix'`` instead. - #. A dictionary of dictionaries + #. ``DiGraph(a_nonsquare_matrix)`` -- return a digraph with given + incidence matrix (see documentation of + :meth:`~sage.graphs.generic_graph.GenericGraph.incidence_matrix`). - #. A dictionary of lists + To bypass auto-detection, prefer the more explicit ``DiGraph(M, + format='incidence_matrix')``. - #. A Sage adjacency matrix or incidence matrix + #. ``DiGraph([V, f])`` -- return a graph with a vertex set ``V`` and an + edge `u,f` whenever ``f(u,v)`` is ``True``. Example: ``DiGraph([ + [1..10], lambda x,y: abs(x-y).is_square()])`` - #. A pygraphviz graph + #. ``DiGraph('FOC@?OC@_?')`` -- return a graph from a dig6 string (see + documentation of :meth:`dif6_string`). - #. A NetworkX digraph - - #. An igraph Graph (see http://igraph.org/python/) + #. ``DiGraph(another_digraph)`` -- return a graph from a Sage graph, + `pygraphviz `__ digraph, `NetworkX + `__ digraph, or `igraph + `__ digraph. - ``pos`` - a positioning dictionary: for example, the spring layout from NetworkX for the 5-cycle is:: @@ -229,32 +217,13 @@ class DiGraph(GenericGraph): - ``weighted`` - whether digraph thinks of itself as weighted or not. See self.weighted() - - ``format`` - if None, DiGraph tries to guess- can be - several values, including: - - - ``'adjacency_matrix'`` - a square Sage matrix M, - with M[i,j] equal to the number of edges {i,j} - - - ``'incidence_matrix'`` - a Sage matrix, with one - column C for each edge, where if C represents {i, j}, C[i] is -1 - and C[j] is 1 - - - ``'weighted_adjacency_matrix'`` - a square Sage - matrix M, with M[i,j] equal to the weight of the single edge {i,j}. - Given this format, weighted is ignored (assumed True). - - - ``NX`` - data must be a NetworkX DiGraph. - - .. NOTE:: - - As Sage's default edge labels is ``None`` while NetworkX uses - ``{}``, the ``{}`` labels of a NetworkX digraph are automatically - set to ``None`` when it is converted to a Sage graph. This - behaviour can be overruled by setting the keyword - ``convert_empty_dict_labels_to_None`` to ``False`` (it is - ``True`` by default). - - - ``igraph`` - data must be an igraph directed Graph. + - ``format`` - if set to ``None`` (default), :class:`DiGraph` tries to guess + input's format. To avoid this possibly time-consuming step, one of the + following values can be specified (see description above): ``"int"``, + ``"dig6"``, ``"rule"``, ``"list_of_edges"``, ``"dict_of_lists"``, + ``"dict_of_dicts"``, ``"adjacency_matrix"``, + ``"weighted_adjacency_matrix"``, ``"incidence_matrix"``, ``"NX"``, + ``"igraph"``. - ``sparse`` (boolean) -- ``sparse=True`` is an alias for ``data_structure="sparse"``, and ``sparse=False`` is an alias for diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index b19a1104f47..ebcc3a5d702 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -559,94 +559,90 @@ class Graph(GenericGraph): Undirected graph. A graph is a set of vertices connected by edges. See also the - :wikipedia:`Wikipedia article on graphs `. + :wikipedia:`Wikipedia article on graphs `. For a + collection of pre-defined graphs, see the + :mod:`~sage.graphs.graph_generators` module. - One can very easily create a graph in Sage by typing:: + A :class:`Graph` object has many methods whose list can be obtained by + typing ``g.`` (i.e. hit the 'tab' key) or by reading the documentation + of :mod:`~sage.graphs.graph`, :mod:`~sage.graphs.generic_graph`, and + :mod:`~sage.graphs.digraph`. - sage: g = Graph() - - By typing the name of the graph, one can get some basic information - about it:: - - sage: g - Graph on 0 vertices - - This graph is not very interesting as it is by default the empty graph. - But Sage contains a large collection of pre-defined graph classes that - can be listed this way: - - * Within a Sage session, type ``graphs.`` - (Do not press "Enter", and do not forget the final period ".") - - * Hit "tab". - - You will see a list of methods which will construct named graphs. For - example:: - - sage: g = graphs.PetersenGraph() - sage: g.plot() - Graphics object consisting of 26 graphics primitives - - or:: + INPUT: - sage: g = graphs.ChvatalGraph() - sage: g.plot() - Graphics object consisting of 37 graphics primitives + By default, a :class:`Graph` object is simple (i.e. no *loops* nor *multiple + edges*) and unweighted. This can be easily tuned with the appropriate flags + (see below). - In order to obtain more information about these graph constructors, access - the documentation using the command ``graphs.RandomGNP?``. + - ``data`` -- can be any of the following (see the ``format`` argument): - Once you have defined the graph you want, you can begin to work on it - by using the almost 200 functions on graphs in the Sage library! - If your graph is named ``g``, you can list these functions as previously - this way + #. ``Graph()`` -- build a graph on 0 vertices. - * Within a Sage session, type ``g.`` - (Do not press "Enter", and do not forget the final period "." ) + #. ``Graph(5)`` -- return an edgeless graph on the 5 vertices 0,...,4. - * Hit "tab". + #. ``Graph(list_of_edges)`` -- return a graph with a given list of edges + (see documentation of + :meth:`~sage.graphs.generic_graph.GenericGraph.add_edges`). - As usual, you can get some information about what these functions do by - typing (e.g. if you want to know about the ``diameter()`` method) - ``g.diameter?``. + To bypass auto-detection, prefer the more explicit ``Graph(L, + format='list_of_edges')``. - If you have defined a graph ``g`` having several connected components - (i.e. ``g.is_connected()`` returns False), you can print each one of its - connected components with only two lines:: + #. ``Graph({1:[2,3,4],3:[4]})`` -- return a graph by associating to each + vertex the list of its neighbors. - sage: for component in g.connected_components(): - ....: g.subgraph(component).plot() - Graphics object consisting of 37 graphics primitives + To bypass auto-detection, prefer the more explicit ``Graph(D, + format='dict_of_lists')``. + #. ``Graph({1: {2: 'a', 3:'b'} ,3:{2:'c'}})`` -- return a graph by + associating a list of neighbors to each vertex and providing its edge + label. - INPUT: + To bypass auto-detection, prefer the more explicit ``Graph(D, + format='dict_of_dicts')``. - - ``data`` -- can be any of the following (see the ``format`` argument): + For graphs with multiple edges, you can provide a list of labels + instead, e.g.: ``Graph({1: {2: ['a1', 'a2'], 3:['b']} ,3:{2:['c']}})``. - #. An integer specifying the number of vertices + #. ``Graph(a_symmetric_matrix)`` -- return a graph with given (weighted) + adjacency matrix (see documentation of + :meth:`~sage.graphs.generic_graph.GenericGraph.adjacency_matrix`). - #. A dictionary of dictionaries + To bypass auto-detection, prefer the more explicit ``Graph(M, + format='adjacency_matrix')``. To take weights into account, use + ``format='weighted_adjacency_matrix'`` instead. - #. A dictionary of lists + #. ``Graph(a_nonsymmetric_matrix)`` -- return a graph with given incidence + matrix (see documentation of + :meth:`~sage.graphs.generic_graph.GenericGraph.incidence_matrix`). - #. A Sage adjacency matrix or incidence matrix + To bypass auto-detection, prefer the more explicit ``Graph(M, + format='incidence_matrix')``. - #. A Sage :meth:`Seidel adjacency matrix ` + #. ``Graph([V, f])`` -- return a graph with a vertex set ``V`` and an edge + `u,f` whenever ``f(u,v)`` is ``True``. Example: ``Graph([ [1..10], + lambda x,y: abs(x-y).is_square()])`` - #. A pygraphviz graph + #. ``Graph(':I`ES@obGkqegW~')`` -- return a graph from a graph6 or sparse6 + string (see documentation of :meth:`graph6_string` or + :meth:`sparse6_string`). - #. A NetworkX graph + #. ``Graph(a_seidel_matrix, format='seidel_adjacency_matrix')`` -- return + a graph with a given seidel adjacency matrix (see documentation of + :meth:`seidel_adjacency_matrix`). - #. An igraph graph (see http://igraph.org/python/) + #. ``Graph(another_graph)`` -- return a graph from a Sage graph, + `pygraphviz `__ graph, `NetworkX + `__ graph, or `igraph + `__ graph. - - ``pos`` - a positioning dictionary: for example, the - spring layout from NetworkX for the 5-cycle is:: + - ``pos`` - a positioning dictionary (cf. documentation of + :meth:`~sage.graphs.generic_graph.GenericGraph.layout`). For example, to + draw 4 vertices on a square:: - {0: [-0.91679746, 0.88169588], - 1: [ 0.47294849, 1.125 ], - 2: [ 1.125 ,-0.12867615], - 3: [ 0.12743933,-1.125 ], - 4: [-1.125 ,-0.50118505]} + {0: [-1,-1], + 1: [ 1,-1], + 2: [ 1, 1], + 3: [-1, 1]} - ``name`` - (must be an explicitly named parameter, i.e., ``name="complete")`` gives the graph a name @@ -655,57 +651,19 @@ class Graph(GenericGraph): if data is an instance of the ``Graph`` class) - ``multiedges`` - boolean, whether to allow multiple - edges (ignored if data is an instance of the ``Graph`` class) - - - ``weighted`` - whether graph thinks of itself as - weighted or not. See ``self.weighted()`` - - - ``format`` - if None, Graph tries to guess; can take - a number of values, namely: - - - ``'int'`` - an integer specifying the number of vertices in an - edge-free graph with vertices labelled from 0 to n-1 - - - ``'graph6'`` - Brendan McKay's graph6 format, in a - string (if the string has multiple graphs, the first graph is - taken) - - - ``'sparse6'`` - Brendan McKay's sparse6 format, in a - string (if the string has multiple graphs, the first graph is - taken) - - - ``'adjacency_matrix'`` - a square Sage matrix M, - with M[i,j] equal to the number of edges {i,j} - - - ``'weighted_adjacency_matrix'`` - a square Sage - matrix M, with M[i,j] equal to the weight of the single edge {i,j}. - Given this format, weighted is ignored (assumed True). - - - ``'seidel_adjacency_matrix'`` - a symmetric Sage matrix M - with 0s on the diagonal, and the other entries -1 or 1, - `M[i,j]=-1` indicating that {i,j} is an edge, otherwise `M[i,j]=1`. - - - ``'incidence_matrix'`` - a Sage matrix, with one - column C for each edge, where if C represents {i, j}, C[i] is -1 - and C[j] is 1 - - - ``'elliptic_curve_congruence'`` - data must be an - iterable container of elliptic curves, and the graph produced has - each curve as a vertex (it's Cremona label) and an edge E-F - labelled p if and only if E is congruent to F mod p - - - ``NX`` - data must be a NetworkX Graph. - - .. NOTE:: + edges (ignored if data is an instance of the ``Graph`` class). - As Sage's default edge labels is ``None`` while NetworkX uses - ``{}``, the ``{}`` labels of a NetworkX graph are automatically - set to ``None`` when it is converted to a Sage graph. This - behaviour can be overruled by setting the keyword - ``convert_empty_dict_labels_to_None`` to ``False`` (it is - ``True`` by default). + - ``weighted`` - whether graph thinks of itself as weighted or not. See + :meth:`~sage.graphs.generic_graph.GenericGraph.weighted`. - - ``igraph`` - data must be an `igraph `__ graph. + - ``format`` - if set to ``None`` (default), :class:`Graph` tries to guess + input's format. To avoid this possibly time-consuming step, one of the + following values can be specified (see description above): ``"int"``, + ``"graph6"``, ``"sparse6"``, ``"rule"``, ``"list_of_edges"``, + ``"dict_of_lists"``, ``"dict_of_dicts"``, ``"adjacency_matrix"``, + ``"weighted_adjacency_matrix"``, ``"seidel_adjacency_matrix"``, + ``"incidence_matrix"``, ``"elliptic_curve_congruence"``, ``"NX"``, + ``"igraph"``. - ``sparse`` (boolean) -- ``sparse=True`` is an alias for ``data_structure="sparse"``, and ``sparse=False`` is an alias for @@ -730,7 +688,7 @@ class Graph(GenericGraph): ``data_structure='static_sparse'``. Set to ``False`` by default. - ``vertex_labels`` - Whether to allow any object as a vertex (slower), or - only the integers 0, ..., n-1, where n is the number of vertices. + only the integers 0, ..., n-1, where n is the number of vertices. - ``convert_empty_dict_labels_to_None`` - this arguments sets the default edge labels used by NetworkX (empty dictionaries) From 45e9685ab5d01440a3e2cbea033f9e797eda2456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 11 Oct 2015 11:50:24 +0200 Subject: [PATCH 1393/1872] trac #17496 fixing the pdf doc --- src/sage/geometry/hyperplane_arrangement/arrangement.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index a1306b07250..032d7fcaaa9 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -1972,7 +1972,9 @@ def minimal_generated_number(self): Let `A` be a central hyperplane arrangement. Let `W_k` denote the solution space of the linear system corresponding to the linear dependencies among the hyperplanes of `A` of length at - most `k`. We say `A` is `k`-*generated* if `\dim W_k = \rank A`. + most `k`. We say `A` is `k`-*generated* if + `\dim W_k = \operatorname{rank} A`. + Equivalently this says all dependencies forming the Orlik-Terao ideal are generated by at most `k` hyperplanes. From 52a717a7c375d17b0dcdc58bce83114eed3030ad Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 8 Oct 2015 12:08:17 +0200 Subject: [PATCH 1394/1872] Use relative links to local help --- src/sage/repl/ipython_kernel/kernel.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/repl/ipython_kernel/kernel.py b/src/sage/repl/ipython_kernel/kernel.py index 9b00d8e25c9..c78e896cb4c 100644 --- a/src/sage/repl/ipython_kernel/kernel.py +++ b/src/sage/repl/ipython_kernel/kernel.py @@ -87,12 +87,12 @@ def help_links(self): sage: sk = SageKernel.__new__(SageKernel) sage: sk.help_links [{'text': 'Sage Documentation', - 'url': '/kernelspecs/sage_.../doc/index.html'}, + 'url': '../kernelspecs/sage_.../doc/index.html'}, ...] """ from sage.repl.ipython_kernel.install import SageKernelSpec identifier = SageKernelSpec.identifier() - kernel_url = lambda x: '/kernelspecs/{0}/{1}'.format(identifier, x) + kernel_url = lambda x: '../kernelspecs/{0}/{1}'.format(identifier, x) return [ { 'text': 'Sage Documentation', @@ -119,7 +119,7 @@ def help_links(self): 'url': kernel_url('doc/reference/index.html'), }, { - 'text': 'Developers Guide', + 'text': "Developer's Guide", 'url': kernel_url('doc/developer/index.html'), }, { From 4f06d3df612175c6fceb7f564495aff7ce52d7bf Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sun, 11 Oct 2015 11:59:02 +0200 Subject: [PATCH 1395/1872] Install Jupyter kernel and nbextensions in $SAGE_LOCAL --- build/make/deps | 6 +- src/bin/sage-notebook | 16 ++- src/sage/repl/ipython_kernel/install.py | 134 +++++++++++------------- src/sage/repl/ipython_kernel/kernel.py | 22 ++-- src/setup.py | 20 +++- 5 files changed, 102 insertions(+), 96 deletions(-) diff --git a/build/make/deps b/build/make/deps index 3d0fb935312..512b95c7401 100644 --- a/build/make/deps +++ b/build/make/deps @@ -101,6 +101,7 @@ base: $(INST)/$(BZIP2) $(INST)/$(PATCH) $(INST)/$(PKGCONF) # dependencies for Cython files (e.g. PARI, NTL, SAGE_MP_LIBRARY). sagelib: \ $(INST)/$(ATLAS) \ + $(INST)/$(BRIAL) \ $(INST)/$(CEPHES) \ $(INST)/$(CLIQUER) \ $(INST)/$(CYTHON) \ @@ -115,6 +116,7 @@ sagelib: \ $(INST)/$(GSL) \ $(INST)/$(IML) \ $(INST)/$(JINJA2) \ + $(INST)/$(JUPYTER_CORE) \ $(INST)/$(LCALC) \ $(INST)/$(LRCALC) \ $(INST)/$(LIBGAP) \ @@ -130,7 +132,6 @@ sagelib: \ $(INST)/$(NUMPY) \ $(INST)/$(PARI) \ $(INST)/$(PLANARITY) \ - $(INST)/$(BRIAL) \ $(INST)/$(PPL) \ $(INST)/$(PYNAC) \ $(INST)/$(PYTHON) \ @@ -140,7 +141,8 @@ sagelib: \ $(INST)/$(SINGULAR) \ $(INST)/$(SIX) \ $(INST)/$(SYMMETRICA) \ - $(INST)/$(ZN_POLY) + $(INST)/$(ZN_POLY) \ + $(EXTCODE) if [ -z "$$SAGE_INSTALL_FETCH_ONLY" ]; then \ cd $(SAGE_SRC) && source bin/sage-env && \ sage-logger 'time $(MAKE) sage' '$(SAGE_LOGS)/sage-$(SAGE_VERSION).log'; \ diff --git a/src/bin/sage-notebook b/src/bin/sage-notebook index 3766a840d53..cbe3e56c6f0 100755 --- a/src/bin/sage-notebook +++ b/src/bin/sage-notebook @@ -65,18 +65,16 @@ class NotebookSageNB(object): notebook(*self.args, **self.kwds) -class NotebookIPython(object): +class NotebookJupyter(object): PREREQUISITE_ERROR = textwrap.dedent(""" - The IPython notebook requires ssl, even if you do not use + The Jupyter notebook requires ssl, even if you do not use https. Install the openssl development packages in your system and then rebuild Python (sage -f python2). """) def __init__(self, argv): - from sage.repl.ipython_kernel.install import \ - SageKernelSpec, have_prerequisites - SageKernelSpec.update() + from sage.repl.ipython_kernel.install import have_prerequisites if not have_prerequisites(): print(self.PREREQUISITE_ERROR) raise SystemExit(1) @@ -118,8 +116,8 @@ EXAMPLES: notebook_launcher = { 'default': NotebookSageNB, # change this to change the default 'sagenb': NotebookSageNB, - 'ipython': NotebookIPython, - 'jupyter': NotebookIPython, + 'ipython': NotebookJupyter, + 'jupyter': NotebookJupyter, } notebook_names = ', '.join(notebook_launcher.keys()) @@ -182,8 +180,8 @@ if __name__ == '__main__': parser.print_help() elif launcher == NotebookSageNB: NotebookSageNB([], help=True) - elif launcher == NotebookIPython: - NotebookIPython(['help']) + elif launcher == NotebookJupyter: + NotebookJupyter(['help']) else: parser.print_help() sys.exit(0) diff --git a/src/sage/repl/ipython_kernel/install.py b/src/sage/repl/ipython_kernel/install.py index 55e03622122..fe8aafbce85 100644 --- a/src/sage/repl/ipython_kernel/install.py +++ b/src/sage/repl/ipython_kernel/install.py @@ -1,39 +1,38 @@ """ -Installing the Sage IPython Kernel +Installing the SageMath Jupyter Kernel and extensions -Kernels have to register themselves with IPython so that they appear -in the IPython notebook's kernel drop-down. This is done by +Kernels have to register themselves with Jupyter so that they appear +in the Jupyter notebook's kernel drop-down. This is done by :class:`SageKernelSpec`. """ import os import errno -from jupyter_client.kernelspec import get_kernel_spec, install_kernel_spec -from IPython.paths import get_ipython_dir - from sage.env import ( SAGE_ROOT, SAGE_DOC, SAGE_LOCAL, SAGE_EXTCODE, SAGE_VERSION ) -from sage.misc.temporary_file import tmp_dir +from jupyter_core.paths import ENV_JUPYTER_PATH +JUPYTER_PATH = ENV_JUPYTER_PATH[0] class SageKernelSpec(object): def __init__(self): """ - Utility to manage Sage kernels + Utility to manage SageMath kernels and extensions EXAMPLES:: sage: from sage.repl.ipython_kernel.install import SageKernelSpec sage: spec = SageKernelSpec() sage: spec._display_name # random output - 'Sage 6.6.beta2' + 'SageMath 6.9' """ - self._display_name = 'Sage {0}'.format(SAGE_VERSION) - self._ipython_dir = get_ipython_dir() + self._display_name = 'SageMath {0}'.format(SAGE_VERSION) + self.nbextensions_dir = os.path.join(JUPYTER_PATH, "nbextensions") + self.kernel_dir = os.path.join(JUPYTER_PATH, "kernels", self.identifier()) self._mkdirs() def _mkdirs(self): @@ -45,40 +44,33 @@ def _mkdirs(self): sage: from sage.repl.ipython_kernel.install import SageKernelSpec sage: spec = SageKernelSpec() sage: spec._mkdirs() - sage: nbextensions = os.path.join(spec._ipython_dir, 'nbextensions') - sage: os.path.exists(nbextensions) + sage: os.path.isdir(spec.nbextensions_dir) True """ - def mkdir_p(*path_components): - path = os.path.join(*path_components) + def mkdir_p(path): try: os.makedirs(path) - except OSError as err: - if err.errno == errno.EEXIST and os.path.isdir(path): - pass - else: + except OSError: + if not os.path.isdir(path): raise - mkdir_p(self._ipython_dir, 'nbextensions') + mkdir_p(self.nbextensions_dir) + mkdir_p(self.kernel_dir) @classmethod - def identifier(self): + def identifier(cls): """ - Internal identifier for the Sage kernel - - OUTPUT: + Internal identifier for the SageMath kernel - String. + OUTPUT: the string ``"sagemath"``. EXAMPLES:: sage: from sage.repl.ipython_kernel.install import SageKernelSpec - sage: SageKernelSpec.identifier() # random output - 'sage_6_6_beta3' - sage: SageKernelSpec.identifier().startswith('sage_') - True + sage: SageKernelSpec.identifier() + 'sagemath' """ - return 'Sage {0}'.format(SAGE_VERSION).lower().replace(' ', '_').replace('.', '_') - + return 'sagemath' + def symlink(self, src, dst): """ Symlink ``src`` to ``dst`` @@ -103,38 +95,48 @@ def symlink(self, src, dst): if err.errno == errno.EEXIST: return os.symlink(src, dst) - + def use_local_mathjax(self): """ - Symlink Sage's Mathjax Install to the IPython notebook. + Symlink SageMath's Mathjax install to the Jupyter notebook. EXAMPLES:: sage: from sage.repl.ipython_kernel.install import SageKernelSpec - sage: from IPython.paths import get_ipython_dir sage: spec = SageKernelSpec() sage: spec.use_local_mathjax() - sage: ipython_dir = get_ipython_dir() - sage: mathjax = os.path.join(ipython_dir, 'nbextensions', 'mathjax') - sage: os.path.exists(mathjax) + sage: mathjax = os.path.join(spec.nbextensions_dir, 'mathjax') + sage: os.path.isdir(mathjax) True """ src = os.path.join(SAGE_LOCAL, 'share', 'mathjax') - dst = os.path.join(self._ipython_dir, 'nbextensions', 'mathjax') + dst = os.path.join(self.nbextensions_dir, 'mathjax') self.symlink(src, dst) def use_local_jsmol(self): + """ + Symlink jsmol to the Jupyter notebook. + + EXAMPLES:: + + sage: from sage.repl.ipython_kernel.install import SageKernelSpec + sage: spec = SageKernelSpec() + sage: spec.use_local_jsmol() + sage: jsmol = os.path.join(spec.nbextensions_dir, 'jsmol') + sage: os.path.isdir(jsmol) + True + """ src = os.path.join(SAGE_LOCAL, 'share', 'jsmol') - dst = os.path.join(self._ipython_dir, 'nbextensions', 'jsmol') + dst = os.path.join(self.nbextensions_dir, 'jsmol') self.symlink(src, dst) def _kernel_cmd(self): """ - Helper to construct the Sage kernel command. - + Helper to construct the SageMath kernel command. + OUTPUT: - List of strings. The command to start a new Sage kernel. + List of strings. The command to start a new SageMath kernel. EXAMPLES:: @@ -142,7 +144,7 @@ def _kernel_cmd(self): sage: spec = SageKernelSpec() sage: spec._kernel_cmd() ['/.../sage', - '-python', + '--python', '-m', 'sage.repl.ipython_kernel', '-f', @@ -150,40 +152,34 @@ def _kernel_cmd(self): """ return [ os.path.join(SAGE_ROOT, 'sage'), - '-python', + '--python', '-m', 'sage.repl.ipython_kernel', '-f', '{connection_file}', ] - + def kernel_spec(self): """ Return the kernel spec as Python dictionary OUTPUT: - A dictionary. See the IPython documentation for details. + A dictionary. See the Jupyter documentation for details. EXAMPLES:: sage: from sage.repl.ipython_kernel.install import SageKernelSpec sage: spec = SageKernelSpec() sage: spec.kernel_spec() - {'argv': ..., 'display_name': 'Sage ...'} + {'argv': ..., 'display_name': 'SageMath ...'} """ return dict( argv=self._kernel_cmd(), display_name=self._display_name, ) - + def _install_spec(self): """ - Install the Sage IPython kernel - - It is safe to call this method multiple times, only one Sage - kernel spec is ever installed for any given Sage - version. However, it resets the IPython kernel spec directory - so additional resources symlinked there are lost. See - :meth:`symlink_resources`. + Install the SageMath Jupyter kernel EXAMPLES:: @@ -191,21 +187,17 @@ def _install_spec(self): sage: spec = SageKernelSpec() sage: spec._install_spec() # not tested """ + jsonfile = os.path.join(self.kernel_dir, "kernel.json") import json - temp = tmp_dir() - kernel_spec = os.path.join(temp, 'kernel.json') - with open(kernel_spec, 'w') as f: + with open(jsonfile, 'w') as f: json.dump(self.kernel_spec(), f) - identifier = self.identifier() - install_kernel_spec(temp, identifier, user=True, replace=True) - self._spec = get_kernel_spec(identifier) def _symlink_resources(self): """ Symlink miscellaneous resources - This method symlinks additional resources (like the Sage - documentation) into the Sage kernel directory. This is + This method symlinks additional resources (like the SageMath + documentation) into the SageMath kernel directory. This is necessary to make the help links in the notebook work. EXAMPLES:: @@ -215,25 +207,23 @@ def _symlink_resources(self): sage: spec._install_spec() # not tested sage: spec._symlink_resources() # not tested """ - assert self._spec, 'call _install_spec() first' - spec_dir = self._spec.resource_dir path = os.path.join(SAGE_EXTCODE, 'notebook-ipython') for filename in os.listdir(path): self.symlink( os.path.join(path, filename), - os.path.join(spec_dir, filename) + os.path.join(self.kernel_dir, filename) ) self.symlink( os.path.join(SAGE_DOC, 'output', 'html', 'en'), - os.path.join(spec_dir, 'doc') + os.path.join(self.kernel_dir, 'doc') ) - + @classmethod def update(cls): """ - Configure the IPython notebook for the Sage kernel - - This method does everything necessary to use the Sage kernel, + Configure the Jupyter notebook for the SageMath kernel + + This method does everything necessary to use the SageMath kernel, you should never need to call any of the other methods directly. @@ -249,7 +239,7 @@ def update(cls): instance._install_spec() instance._symlink_resources() - + def have_prerequisites(debug=True): """ Check that we have all prerequisites to run the Jupyter notebook. diff --git a/src/sage/repl/ipython_kernel/kernel.py b/src/sage/repl/ipython_kernel/kernel.py index c78e896cb4c..eb61032dbd7 100644 --- a/src/sage/repl/ipython_kernel/kernel.py +++ b/src/sage/repl/ipython_kernel/kernel.py @@ -1,8 +1,8 @@ """ The Sage ZMQ Kernel -Version of the IPython kernel when running Sage inside the IPython -notebook or remote IPython sessions. +Version of the Jupyter kernel when running Sage inside the Jupyter +notebook or remote Jupyter sessions. """ #***************************************************************************** @@ -27,7 +27,7 @@ class SageZMQInteractiveShell(SageNotebookInteractiveShell, ZMQInteractiveShell) pass -class SageKernel(IPythonKernel): +class SageKernel(IPythonKernel): implementation = 'sage' implementation_version = SAGE_VERSION @@ -35,11 +35,11 @@ class SageKernel(IPythonKernel): def __init__(self, **kwds): """ - The Sage IPython Kernel + The Sage Jupyter Kernel INPUT: - See the IPython documentation + See the Jupyter documentation EXAMPLES:: @@ -54,8 +54,8 @@ def __init__(self, **kwds): def banner(self): r""" The Sage Banner - - The value of this property is displayed in the IPython + + The value of this property is displayed in the Jupyter notebook. OUTPUT: @@ -75,11 +75,11 @@ def banner(self): @property def help_links(self): r""" - Help in the IPython Notebook - + Help in the Jupyter Notebook + OUTPUT: - See the IPython documentation. + See the Jupyter documentation. EXAMPLES:: @@ -87,7 +87,7 @@ def help_links(self): sage: sk = SageKernel.__new__(SageKernel) sage: sk.help_links [{'text': 'Sage Documentation', - 'url': '../kernelspecs/sage_.../doc/index.html'}, + 'url': '../kernelspecs/sagemath/doc/index.html'}, ...] """ from sage.repl.ipython_kernel.install import SageKernelSpec diff --git a/src/setup.py b/src/setup.py index 45694c063ec..cf0013689f4 100755 --- a/src/setup.py +++ b/src/setup.py @@ -324,6 +324,7 @@ def plural(n,noun): ######################################################################## from distutils.command.build_ext import build_ext +from distutils.command.install import install from distutils.dep_util import newer_group from distutils import log @@ -633,6 +634,22 @@ def run_cythonize(): print('Finished cleaning, time: %.2f seconds.' % (time.time() - t)) +######################################################### +### Install also Jupyter kernel spec +######################################################### + +# We cannot just add the installation of the kernel spec to data_files +# since the file is generated, not copied. +class sage_install(install): + def run(self): + install.run(self) + self.install_kernel_spec() + + def install_kernel_spec(self): + from sage.repl.ipython_kernel.install import SageKernelSpec + SageKernelSpec.update() + + ######################################################### ### Distutils ######################################################### @@ -647,6 +664,5 @@ def run_cythonize(): packages = python_packages, data_files = python_data_files, scripts = [], - cmdclass = { 'build_ext': sage_build_ext }, + cmdclass = dict(build_ext=sage_build_ext, install=sage_install), ext_modules = ext_modules) - From 4bc51d480bf228cf1bfbcaf25dc2737374a9c7e0 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 11 Oct 2015 15:43:51 +0200 Subject: [PATCH 1396/1872] trac #19390: Typos --- src/sage/graphs/digraph.py | 20 +++++++++----------- src/sage/graphs/graph.py | 6 +++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index ff0a06e9229..f4ef5312b43 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -123,10 +123,8 @@ class DiGraph(GenericGraph): Directed graph. A digraph or directed graph is a set of vertices connected by oriented - edges. See also the `Wikipedia article on digraphs - `_.For a collection - of pre-defined digraphs, see the :mod:`~sage.graphs.digraph_generators` - module. + edges. See also the :wikipedia:`Directed_graph`. For a collection of + pre-defined digraphs, see the :mod:`~sage.graphs.digraph_generators` module. A :class:`DiGraph` object has many methods whose list can be obtained by typing ``g.`` (i.e. hit the 'tab' key) or by reading the documentation @@ -158,7 +156,7 @@ class DiGraph(GenericGraph): To bypass auto-detection, prefer the more explicit ``DiGraph(D, format='dict_of_lists')``. - #. ``DiGraph({1: {2: 'a', 3:'b'} ,3:{2:'c'}})`` -- return a graph by + #. ``DiGraph({1: {2: 'a', 3:'b'} ,3:{2:'c'}})`` -- return a digraph by associating a list of out-neighbors to each vertex and providing its edge label. @@ -184,14 +182,14 @@ class DiGraph(GenericGraph): To bypass auto-detection, prefer the more explicit ``DiGraph(M, format='incidence_matrix')``. - #. ``DiGraph([V, f])`` -- return a graph with a vertex set ``V`` and an - edge `u,f` whenever ``f(u,v)`` is ``True``. Example: ``DiGraph([ + #. ``DiGraph([V, f])`` -- return a digraph with a vertex set ``V`` and an + edge `u,v` whenever ``f(u,v)`` is ``True``. Example: ``DiGraph([ [1..10], lambda x,y: abs(x-y).is_square()])`` - #. ``DiGraph('FOC@?OC@_?')`` -- return a graph from a dig6 string (see - documentation of :meth:`dif6_string`). + #. ``DiGraph('FOC@?OC@_?')`` -- return a digraph from a dig6 string (see + documentation of :meth:`dig6_string`). - #. ``DiGraph(another_digraph)`` -- return a graph from a Sage graph, + #. ``DiGraph(another_digraph)`` -- return a digraph from a Sage (di)graph, `pygraphviz `__ digraph, `NetworkX `__ digraph, or `igraph `__ digraph. @@ -248,7 +246,7 @@ class DiGraph(GenericGraph): ``data_structure='static_sparse'``. - ``vertex_labels`` - Whether to allow any object as a vertex (slower), or - only the integers 0, ..., n-1, where n is the number of vertices. + only the integers `0,...,n-1`, where `n` is the number of vertices. - ``convert_empty_dict_labels_to_None`` - this arguments sets the default edge labels used by NetworkX (empty dictionaries) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index ebcc3a5d702..6b075a7f2e7 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -619,7 +619,7 @@ class Graph(GenericGraph): format='incidence_matrix')``. #. ``Graph([V, f])`` -- return a graph with a vertex set ``V`` and an edge - `u,f` whenever ``f(u,v)`` is ``True``. Example: ``Graph([ [1..10], + `u,v` whenever ``f(u,v)`` is ``True``. Example: ``Graph([ [1..10], lambda x,y: abs(x-y).is_square()])`` #. ``Graph(':I`ES@obGkqegW~')`` -- return a graph from a graph6 or sparse6 @@ -630,7 +630,7 @@ class Graph(GenericGraph): a graph with a given seidel adjacency matrix (see documentation of :meth:`seidel_adjacency_matrix`). - #. ``Graph(another_graph)`` -- return a graph from a Sage graph, + #. ``Graph(another_graph)`` -- return a graph from a Sage (di)graph, `pygraphviz `__ graph, `NetworkX `__ graph, or `igraph `__ graph. @@ -688,7 +688,7 @@ class Graph(GenericGraph): ``data_structure='static_sparse'``. Set to ``False`` by default. - ``vertex_labels`` - Whether to allow any object as a vertex (slower), or - only the integers 0, ..., n-1, where n is the number of vertices. + only the integers `0,...,n-1`, where `n` is the number of vertices. - ``convert_empty_dict_labels_to_None`` - this arguments sets the default edge labels used by NetworkX (empty dictionaries) From a4c199d2842865c6385e6938b67974f39ebd8876 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Sun, 11 Oct 2015 12:01:47 -0500 Subject: [PATCH 1397/1872] added the necessary extra colon after tests --- src/sage/combinat/diagram_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 7bc486265c6..d8618f16500 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1650,7 +1650,7 @@ class PartitionAlgebra(DiagramAlgebra): Symmetric group algebra elements can also be coerced into the partition algebra. - TESTS: + TESTS:: sage: A = PartitionAlgebra(2, x, SR) sage: S = SymmetricGroupAlgebra(SR, 2) From 894330e1787253600523bea93f34ce793f25e05c Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 11 Oct 2015 19:02:44 +0200 Subject: [PATCH 1398/1872] trac #19226: Broken doctest --- src/sage/homology/simplicial_complex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index c8c188552f6..534340fbc16 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -775,7 +775,7 @@ class SimplicialComplex(CategoryObject, GenericCellComplex): sage: l=designs.ProjectiveGeometryDesign(2,1,GF(4,name='a')) sage: f = lambda S: not any(len(set(S).intersection(x))>2 for x in l) - sage: SimplicialComplex(from_characteristic_function=(f, range(21))) + sage: SimplicialComplex(from_characteristic_function=(f, l.ground_set())) Simplicial complex with 21 vertices and 168 facets TESTS: From f8bd45183a2894e9260073209ecd8b93b957f6c4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 11 Oct 2015 14:05:08 -0500 Subject: [PATCH 1399/1872] Moving code up from CFM to modules_with_basis. --- .../finite_dimensional_algebra_element.py | 19 + src/sage/algebras/jordan_algebra.py | 47 ++ .../algebras/steenrod/steenrod_algebra.py | 25 +- src/sage/algebras/weyl_algebra.py | 26 + src/sage/categories/algebras_with_basis.py | 6 +- src/sage/categories/modules_with_basis.py | 514 +++++++++++++++++- src/sage/combinat/free_module.py | 502 +++-------------- src/sage/combinat/ncsf_qsym/tutorial.py | 6 +- src/sage/combinat/sf/macdonald.py | 4 +- src/sage/combinat/sf/sfa.py | 4 +- src/sage/modules/free_module_element.pyx | 18 +- 11 files changed, 709 insertions(+), 462 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py index 898ceabe337..21e8ce2e954 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py @@ -134,6 +134,25 @@ def matrix(self): """ return self._matrix + def monomial_coefficients(self, copy=True): + """ + Return a dictionary whose keys are indices of basis in + the support of ``self`` and whose values are the corresponding + coefficients. + + INPUT: + + - ``copy`` -- ignored + + EXAMPLES:: + + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: elt = B(Matrix([[1,1], [-1,1]])) + sage: elt.monomial_coefficients() + {0: 1, 1: 1} + """ + return self._vector.dict(copy) + def left_matrix(self): """ Return the matrix for multiplication by ``self`` from the left. diff --git a/src/sage/algebras/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index d434996437b..eabcc3463ca 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -556,6 +556,30 @@ def _rmul_(self, other): """ return self.__class__(self.parent(), other * self._x) + def monomial_coefficients(self, copy=True): + """ + Return a dictionary whose keys are indices of basis in + the support of ``self`` and whose values are the corresponding + coefficients. + + INPUT: + + - ``copy`` -- (default: ``True``) if ``self`` is internally + represented by a dictionary ``d``, then make a copy of ``d``; + if ``False``, then this can cause undesired behavior by + mutating ``d`` + + EXAMPLES:: + + sage: F. = FreeAlgebra(QQ) + sage: J = JordanAlgebra(F) + sage: a,b,c = map(J, F.gens()) + sage: elt = a + 2*b - c + sage: elt.monomial_coefficients() + {x: 1, y: 2, z: -1} + """ + return self._x.monomial_coefficients(copy) + class JordanAlgebraSymmetricBilinear(JordanAlgebra): r""" A Jordan algebra given by a symmetric bilinear form `m`. @@ -935,6 +959,29 @@ def _rmul_(self, other): """ return self.__class__(self.parent(), other * self._s, other * self._v) + def monomial_coefficients(self, copy=True): + """ + Return a dictionary whose keys are indices of basis in + the support of ``self`` and whose values are the corresponding + coefficients. + + INPUT: + + - ``copy`` -- ignored + + EXAMPLES:: + + sage: m = matrix([[0,1],[1,1]]) + sage: J. = JordanAlgebra(m) + sage: elt = a + 2*b - c + sage: elt.monomial_coefficients() + {0: 1, 1: 2, 2: -1} + """ + d = {0: self._s} + for i,c in enumerate(self._v): + d[i+1] = c + return d + def trace(self): r""" Return the trace of ``self``. diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index de25ebb1564..e934d8d3308 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -404,12 +404,13 @@ 1 (2, 1) sage: c.monomial_coefficients() {(2, 1): 1, (5,): 1} - sage: c.monomials() + sage: sorted(c.monomials(), key=lambda x: x.support()) [Sq(2,1), Sq(5)] - sage: c.support() + sage: sorted(c.support()) [(2, 1), (5,)] sage: Adem = SteenrodAlgebra(basis='adem') - sage: (Adem.Sq(10) + Adem.Sq(9) * Adem.Sq(1)).monomials() + sage: elt = Adem.Sq(10) + Adem.Sq(9) * Adem.Sq(1) + sage: sorted(elt.monomials(), key=lambda x: x.support()) [Sq^9 Sq^1, Sq^10] sage: A7 = SteenrodAlgebra(p=7) @@ -1567,7 +1568,7 @@ def counit_on_basis(self, t): return self.base_ring().one() def _milnor_on_basis(self, t): - """ + r""" Convert the tuple t in the current basis to an element in the Milnor basis. @@ -3115,9 +3116,9 @@ class Element(CombinatorialFreeModuleElement): 1 (2, 1) sage: c.monomial_coefficients() {(2, 1): 1, (5,): 1} - sage: c.monomials() + sage: sorted(c.monomials(), key=lambda x: x.support()) [Sq(2,1), Sq(5)] - sage: c.support() + sage: sorted(c.support()) [(2, 1), (5,)] See the documentation for this module (type @@ -3451,8 +3452,8 @@ def excess(self): OUTPUT: ``excess`` - non-negative integer The excess of a Milnor basis element `\text{Sq}(a,b,c,...)` is - `a + b + c + ...`. When `p` is odd, the excess of `Q_{0}^{e_0} - Q_{1}^{e_1} ... P(r_1, r_2, ...)` is `\sum e_i + 2 \sum r_i`. + `a + b + c + \cdots`. When `p` is odd, the excess of `Q_{0}^{e_0} + Q_{1}^{e_1} \cdots P(r_1, r_2, ...)` is `\sum e_i + 2 \sum r_i`. The excess of a linear combination of Milnor basis elements is the minimum of the excesses of those basis elements. @@ -3470,9 +3471,11 @@ def excess(self): 6 sage: (Sq(0,0,1) + Sq(4,1) + Sq(7)).excess() 1 - sage: [m.excess() for m in (Sq(0,0,1) + Sq(4,1) + Sq(7)).monomials()] + sage: elt = Sq(0,0,1) + Sq(4,1) + Sq(7) + sage: M = sorted(elt.monomials(), key=lambda x: x.support()) + sage: [m.excess() for m in M] [1, 5, 7] - sage: [m for m in (Sq(0,0,1) + Sq(4,1) + Sq(7)).monomials()] + sage: [m for m in M] [Sq(0,0,1), Sq(4,1), Sq(7)] sage: B = SteenrodAlgebra(7) sage: a = B.Q(1,2,5) @@ -3495,7 +3498,7 @@ def excess_odd(mono): of factors, plus twice the sum of the terms in the second component. """ - if len(mono) == 0: + if not mono: return 0 else: return len(mono[0]) + 2 * sum(mono[1]) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 366b6bd99f2..993cf7b7d2e 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -402,6 +402,32 @@ def _lmul_(self, other): M = self.__monomials return self.__class__(self.parent(), {t: M[t]*other for t in M}) + def monomial_coefficients(self, copy=True): + """ + Return a dictionary which has the basis keys in the support + of ``self`` and their corresponding coefficients as values. + + INPUT: + + - ``copy`` -- (default: ``True``) if ``self`` is internally + represented by a dictionary ``d``, then make a copy of ``d``; + if ``False``, then this can cause undesired behavior by + mutating ``d`` + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ) + sage: dx,dy,dz = W.differentials() + sage: elt = (dy - (3*x - z)*dx) + sage: sorted(elt.monomial_coefficients().items()) + [(((0, 0, 0), (0, 1, 0)), 1), + (((0, 0, 1), (1, 0, 0)), 1), + (((1, 0, 0), (1, 0, 0)), -3)] + """ + if copy: + return dict(self.__monomials) + return self.__monomials + def __iter__(self): """ Return an iterator of ``self``. diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index d4b63827895..8f2c63d49e7 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -198,7 +198,7 @@ class ElementMethods: def __invert__(self): """ - Returns the inverse of self if self is a multiple of one, + Return the inverse of ``self`` if ``self`` is a multiple of one, and one is in the basis of this algebra. Otherwise throws an error. @@ -222,10 +222,10 @@ def __invert__(self): ValueError: cannot invert self (= B[word: a]) """ # FIXME: make this generic - mcs = self._monomial_coefficients + mcs = self.monomial_coefficients(copy=False) one = self.parent().one_basis() if len(mcs) == 1 and one in mcs: - return self.parent()( ~mcs[ one ] ) + return self.parent().term(one, ~mcs[one]) else: raise ValueError("cannot invert self (= %s)"%self) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index c780127492a..7d8c9f52416 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -16,8 +16,10 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.misc.lazy_import import LazyImport +from sage.misc.lazy_import import LazyImport, lazy_import +from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method +from sage.misc.abstract_method import abstract_method from sage.misc.sage_itertools import max_cmp, min_cmp from sage.categories.homsets import HomsetsCategory from sage.categories.cartesian_product import CartesianProductsCategory @@ -25,8 +27,8 @@ from sage.categories.dual import DualObjectsCategory from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.modules import Modules +from sage.categories.poor_man_map import PoorManMap from sage.structure.element import Element, parent -from sage.misc.lazy_import import lazy_import lazy_import('sage.modules.with_basis.morphism', ['ModuleMorphismByLinearity', 'ModuleMorphismFromMatrix', @@ -184,6 +186,8 @@ def is_abelian(self): Graded = LazyImport('sage.categories.graded_modules_with_basis', 'GradedModulesWithBasis') class ParentMethods: + # To implement a module_with_basis you need to implement either + # basis() or an _indices attribute and monomial(). @cached_method def basis(self): """ @@ -227,7 +231,8 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, - ``on_basis`` -- a function `f` from `I` to `Y` - ``diagonal`` -- a function `d` from `I` to `R` - ``function`` -- a function `f` from `X` to `Y` - - ``matrix`` -- a matrix of size `\dim X \times \dim Y` or `\dim Y \times \dim X` + - ``matrix`` -- a matrix of size `\dim X \times \dim Y` + or `\dim Y \times \dim X` Further options include: @@ -321,7 +326,8 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, sage: phi.category_for() # todo: not implemented (ZZ is currently not in Modules(ZZ)) Category of modules over Integer Ring - Or more generaly any ring admitting a coercion map from the base ring:: + Or more generaly any ring admitting a coercion map from + the base ring:: sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=RR ) sage: phi( 2 * X.monomial(1) + 3 * X.monomial(-1) ) @@ -378,13 +384,17 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y ) Traceback (most recent call last): ... - ValueError: codomain(=Free module generated by {'z'} over Rational Field) should be a module over the base ring of the domain(=Free module generated by {'x', 'y'} over Real Field with 53 bits of precision) + ValueError: codomain(=Free module generated by {'z'} over Rational Field) + should be a module over the base ring of the + domain(=Free module generated by {'x', 'y'} over Real Field with 53 bits of precision) sage: Y = CombinatorialFreeModule(RR['q'],['z']) sage: phi = Y.module_morphism( on_basis=on_basis, codomain=X ) Traceback (most recent call last): ... - ValueError: codomain(=Free module generated by {'x', 'y'} over Real Field with 53 bits of precision) should be a module over the base ring of the domain(=Free module generated by {'z'} over Univariate Polynomial Ring in q over Real Field with 53 bits of precision) + ValueError: codomain(=Free module generated by {'x', 'y'} over Real Field with 53 bits of precision) + should be a module over the base ring of the + domain(=Free module generated by {'z'} over Univariate Polynomial Ring in q over Real Field with 53 bits of precision) With the ``diagonal=d`` argument, this constructs the @@ -392,7 +402,7 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, .. MATH:: - `g(x_i) = d(i) y_i` + `g(x_i) = d(i) y_i`. This assumes that the respective bases `x` and `y` of `X` and `Y` have the same index set `I`:: @@ -512,7 +522,7 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, ValueError: diagonal (=3) should be a function """ - if not len([x for x in [matrix, on_basis, function, diagonal] if x is not None]) == 1: + if len([x for x in [matrix, on_basis, function, diagonal] if x is not None]) != 1: raise ValueError("module_morphism() takes exactly one option out of `matrix`, `on_basis`, `function`, `diagonal`") if matrix is not None: return ModuleMorphismFromMatrix(domain=self, matrix=matrix, **keywords) @@ -764,6 +774,235 @@ def tensor(*parents): """ return parents[0].__class__.Tensor(parents, category = tensor.category_from_parents(parents)) + def monomial(self, i): + """ + Return the basis element indexed by ``i``. + + INPUT: + + - ``i`` -- an element of the index set + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) + sage: F.monomial('a') + B['a'] + + ``F.monomial`` is in fact (almost) a map:: + + sage: F.monomial + Term map from {'a', 'b', 'c'} to Free module generated by {'a', 'b', 'c'} over Rational Field + """ + return self.basis()[i] + + def _sum_of_monomials(self, indices): + """ + TESTS:: + + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) + sage: F._sum_of_monomials(['a', 'b']) + B['a'] + B['b'] + """ + # TODO: optimize by calling directly _from_dict if we + # know that all indices are distinct as sum_of_terms; + # otherwise, maybe call dict_addition directly + return self.sum(self.monomial(index) for index in indices) + + @lazy_attribute + def sum_of_monomials(self): + """ + Return the sum of the corresponding basis elements. + + INPUT: + + - ``indices`` -- an list (or iterable) of indices of basis elements + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) + sage: F.sum_of_monomials(['a', 'b']) + B['a'] + B['b'] + + sage: F.sum_of_monomials(['a', 'b', 'a']) + 2*B['a'] + B['b'] + + ``F.sum_of_monomials`` is in fact (almost) a map:: + + sage: F.sum_of_monomials + A map to Free module generated by {'a', 'b', 'c'} over Rational Field + """ + # domain = sets of self.combinatorial_class(), + return PoorManMap(self._sum_of_monomials, codomain = self) + + def monomial_or_zero_if_none(self, i): + """ + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) + sage: F.monomial_or_zero_if_none('a') + B['a'] + sage: F.monomial_or_zero_if_none(None) + 0 + """ + if i is None: + return self.zero() + return self.monomial(i) + + def term(self, index, coeff=None): + """ + Construct a term in ``self``. + + INPUT: + + - ``index`` -- the index of a basis element + - ``coeff`` -- an element of the coefficient ring (default: one) + + EXAMPLES:: + + sage: m = matrix([[0,1],[1,1]]) + sage: J. = JordanAlgebra(m) + sage: J.term(1, -2) + 0 + (-2, 0) + + Design: should this do coercion on the coefficient ring? + """ + if coeff is None: + coeff = self.base_ring().one() + return coeff * self.monomial(index) + + def sum_of_terms(self, terms): + """ + Construct a sum of terms of ``self``. + + INPUT: + + - ``terms`` -- a list (or iterable) of pairs ``(index, coeff)`` + + EXAMPLES:: + + sage: m = matrix([[0,1],[1,1]]) + sage: J. = JordanAlgebra(m) + sage: J.sum_of_terms([(0, 2), (2, -3)]) + 2 + (0, -3) + """ + return self.sum(self.term(index, coeff) for (index, coeff) in terms) + + def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): + """ + Return the linear combination `\lambda_1 v_1 + \cdots + + \lambda_k v_k` (resp. the linear combination `v_1 \lambda_1 + + \cdots + v_k \lambda_k`) where ``iter_of_elements_coeff`` iterates + through the sequence `((\lambda_1, v_1), ..., (\lambda_k, v_k))`. + + INPUT: + + - ``iter_of_elements_coeff`` -- iterator of pairs + ``(element, coeff)`` with ``element`` in ``self`` and + ``coeff`` in ``self.base_ring()`` + + - ``factor_on_left`` -- (optional) if ``True``, the coefficients + are multiplied from the left if ``False``, the coefficients are + multiplied from the right + + EXAMPLES:: + + sage: m = matrix([[0,1],[1,1]]) + sage: J. = JordanAlgebra(m) + sage: J.linear_combination(((a+b, 1), (-2*b + c, -1))) + 1 + (3, -1) + """ + if factor_on_left: + return self.sum(coeff * element + for element, coeff in iter_of_elements_coeff) + else: + return self.sum(element * coeff + for element, coeff in iter_of_elements_coeff) + + def _apply_module_morphism(self, x, on_basis, codomain=False): + """ + Return the image of ``x`` under the module morphism defined by + extending :func:`on_basis` by linearity. + + INPUT: + + - ``x`` -- a element of ``self`` + + - ``on_basis`` -- a function that takes in a combinatorial + object indexing a basis element and returns an element of the + codomain + + - ``codomain`` -- (optional) the codomain of the morphism, otherwise + it is computed using :func:`on_basis` + + If ``codomain`` is not specified, then the function tries to + compute the codomain of the module morphism by finding the image + of one of the elements in the support, hence :func:`on_basis` + should return an element whose parent is the codomain. + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).schur() + sage: a = s([3]) + s([2,1]) + s([1,1,1]) + sage: b = 2*a + sage: f = lambda part: Integer( len(part) ) + sage: s._apply_module_morphism(a, f) #1+2+3 + 6 + sage: s._apply_module_morphism(b, f) #2*(1+2+3) + 12 + sage: s._apply_module_morphism(s(0), f) + 0 + sage: s._apply_module_morphism(s(1), f) + 0 + sage: s._apply_module_morphism(s(1), lambda part: len(part), ZZ) + 0 + sage: s._apply_module_morphism(s(1), lambda part: len(part)) + Traceback (most recent call last): + ... + ValueError: codomain could not be determined + """ + if x == self.zero(): + if not codomain: + from sage.combinat.family import Family + B = Family(self.basis()) + try: + z = B.first() + except StopIteration: + raise ValueError('codomain could not be determined') + codomain = on_basis(z).parent() + return codomain.zero() + + if not codomain: + keys = x.support() + key = keys[0] + try: + codomain = on_basis(key).parent() + except Exception: + raise ValueError('codomain could not be determined') + mc = x.monomial_coefficients(copy=False) + if hasattr( codomain, 'linear_combination' ): + return codomain.linear_combination( (on_basis(key), coeff) + for key, coeff in mc.iteritems() ) + else: + return_sum = codomain.zero() + for key, coeff in x._monomial_coefficients.iteritems(): + return_sum += coeff * on_basis( key ) + return return_sum + + def _apply_module_endomorphism(self, x, on_basis): + """ + This takes in a function from the basis elements to the elements of + self and applies it linearly to a. Note that + _apply_module_endomorphism does not require multiplication on + self to be defined. + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).schur() + sage: f = lambda part: 2*s(part.conjugate()) + sage: s._apply_module_endomorphism( s([2,1]) + s([1,1,1]), f) + 2*s[2, 1] + 2*s[3] + """ + return self.linear_combination( ( on_basis( key ), coeff ) for key, coeff in x._monomial_coefficients.iteritems() ) class ElementMethods: # TODO: Define the appropriate element methods here (instead of in @@ -777,6 +1016,262 @@ class ElementMethods: # """ # return self._lmul_(-self.parent().base_ring().one(), self) + @abstract_method + def monomial_coefficients(copy=True): + """ + Return a dictionary whose keys are indices of basis in + the support of ``self`` and whose values are the corresponding + coefficients. + + INPUT: + + - ``copy`` -- (default: ``True``) if ``self`` is internally + represented by a dictionary ``d``, then make a copy of ``d``; + if ``False``, then this can cause undesired behavior by + mutating ``d`` + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] + 3*B['c'] + sage: d = f.monomial_coefficients() + sage: d['a'] + 1 + sage: d['c'] + 3 + """ + + def __getitem__(self, m): + """ + Return the coefficient of ``m`` in ``self``. + + EXAMPLES:: + + sage: p = Partition([2,1]) + sage: q = Partition([1,1,1]) + sage: s = SymmetricFunctions(QQ).schur() + sage: a = s(p) + sage: a._coefficient_fast([2,1]) + Traceback (most recent call last): + ... + TypeError: unhashable type: 'list' + + :: + + sage: a._coefficient_fast(p) + 1 + sage: a._coefficient_fast(q) + 0 + sage: a[p] + 1 + sage: a[q] + 0 + """ + return self.monomial_coefficients(copy=False).get(m, self.base_ring().zero()) + + def coefficient(self, m): + """ + Return the coefficient of ``m`` in ``self`` and raises an error + if ``m`` is not in the basis indexing set. + + EXAMPLES:: + + sage: s = CombinatorialFreeModule(QQ, Partitions()) + sage: z = s([4]) - 2*s([2,1]) + s([1,1,1]) + s([1]) + sage: z.coefficient([4]) + 1 + sage: z.coefficient([2,1]) + -2 + sage: z.coefficient(Partition([2,1])) + -2 + sage: z.coefficient([1,2]) + Traceback (most recent call last): + ... + AssertionError: [1, 2] should be an element of Partitions + sage: z.coefficient(Composition([2,1])) + Traceback (most recent call last): + ... + AssertionError: [2, 1] should be an element of Partitions + + Test that coefficient also works for those parents that do + not yet have an element_class:: + + sage: G = DihedralGroup(3) + sage: F = CombinatorialFreeModule(QQ, G) + sage: hasattr(G, "element_class") + False + sage: g = G.an_element() + sage: (2*F.monomial(g)).coefficient(g) + 2 + """ + # NT: coefficient_fast should be the default, just with appropriate assertions + # that can be turned on or off + C = self.parent().basis().keys() + # TODO: This should raise a ValueError - TS + assert m in C, "%s should be an element of %s"%(m, C) + if hasattr(C, "element_class") and not isinstance(m, C.element_class): + m = C(m) + return self[m] + + def is_zero(self): + """ + Return ``True`` if and only if ``self == 0``. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] - 3*B['c'] + sage: f.is_zero() + False + sage: F.zero().is_zero() + True + + :: + + sage: s = SymmetricFunctions(QQ).schur() + sage: s([2,1]).is_zero() + False + sage: s(0).is_zero() + True + sage: (s([2,1]) - s([2,1])).is_zero() + True + """ + zero = self.parent().base_ring().zero() + return all(v == zero for v in self.monomial_coefficients(copy=False).values()) + + def __len__(self): + """ + Return the number of basis elements of self with nonzero + coefficients. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] - 3*B['c'] + sage: len(f) + 2 + + :: + + sage: s = SymmetricFunctions(QQ).schur() + sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) + sage: len(z) + 4 + """ + zero = self.parent().base_ring().zero() + return len([key for key, coeff in self.monomial_coefficients(copy=False).iteritems() + if coeff != zero]) + + def length(self): + """ + Return the number of basis elements of self with nonzero + coefficients. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] - 3*B['c'] + sage: f.length() + 2 + + :: + + sage: s = SymmetricFunctions(QQ).schur() + sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) + sage: z.length() + 4 + """ + return len(self) + + def support(self): + """ + Return a list of the combinatorial objects indexing the basis + elements of self which non-zero coefficients. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] - 3*B['c'] + sage: sorted(f.support()) + ['a', 'c'] + + :: + + sage: s = SymmetricFunctions(QQ).schur() + sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) + sage: sorted(z.support()) + [[1], [1, 1, 1], [2, 1], [4]] + """ + zero = self.parent().base_ring().zero() + return [key for key, coeff in self.monomial_coefficients(copy=False).iteritems() + if coeff != zero] + + def monomials(self): + """ + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] + 2*B['c'] + sage: f.monomials() + [B['a'], B['c']] + + sage: (F.zero()).monomials() + [] + """ + P = self.parent() + one = P.base_ring().one() + return [P.monomial(key) for key in self.support()] + + def terms(self): + """ + Return a list of the terms of ``self``. + + .. SEEALSO:: :meth:`monomials` + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] + 2*B['c'] + sage: f.terms() + [B['a'], 2*B['c']] + """ + P = self.parent() + zero = P.base_ring().zero() + return [P.term(key, value) + for key, value in self.monomial_coefficients(copy=False).iteritems() + if value != zero] + + def coefficients(self): + """ + Return a list of the coefficients appearing on the basis + elements in ``self``. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] - 3*B['c'] + sage: f.coefficients() + [1, -3] + + :: + + sage: s = SymmetricFunctions(QQ).schur() + sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) + sage: z.coefficients() + [1, 1, 1, 1] + """ + zero = self.parent().base_ring().zero() + return [value for key, value in + self.monomial_coefficients(copy=False).iteritems() + if value != zero] def support_of_term(self): """ @@ -801,7 +1296,7 @@ def support_of_term(self): if len(self) == 1: return self.support()[0] else: - raise ValueError("%s is not a single term"%(self)) + raise ValueError("{} is not a single term".format(self)) def leading_support(self, cmp=None): r""" @@ -831,7 +1326,6 @@ def leading_support(self, cmp=None): """ return max_cmp(self.support(), cmp) - def leading_item(self, cmp=None): r""" Return the pair ``(k, c)`` where diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index f75f58e56e9..c61fa2d4680 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -12,9 +12,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import Element, have_same_parent from sage.structure.parent import Parent -from sage.structure.element import have_same_parent from sage.structure.indexed_generators import IndexedGenerators -from sage.modules.free_module_element import vector from sage.misc.misc import repr_lincomb from sage.modules.module import Module from sage.rings.all import Integer @@ -24,11 +22,9 @@ from sage.combinat.cartesian_product import CartesianProduct from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.misc.cachefunc import cached_method -from sage.misc.all import lazy_attribute -from sage.categories.poor_man_map import PoorManMap +from sage.misc.lazy_attribute import lazy_attribute from sage.categories.all import Category, Sets, ModulesWithBasis from sage.combinat.dict_addition import dict_addition, dict_linear_combination -from sage.sets.family import Family from sage.typeset.ascii_art import AsciiArt, empty_ascii_art # TODO: move the content of this class to CombinatorialFreeModule.Element and ModulesWithBasis.Element @@ -131,12 +127,19 @@ def __hash__(self): """ return hash(frozenset(self._monomial_coefficients.items())) - def monomial_coefficients(self): + def monomial_coefficients(self, copy=True): """ Return the internal dictionary which has the combinatorial objects indexing the basis as keys and their corresponding coefficients as values. + INPUT: + + - ``copy`` -- (default: ``True``) if ``self`` is internally + represented by a dictionary ``d``, then make a copy of ``d``; + if ``False``, then this can cause undesired behavior by + mutating ``d`` + EXAMPLES:: sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) @@ -168,6 +171,8 @@ def monomial_coefficients(self): sage: d[ Partition([3,2]) ] 2 """ + if copy: + return dict(self._monomial_coefficients) return self._monomial_coefficients def _sorted_items_for_printing(self): @@ -257,12 +262,10 @@ def _ascii_art_(self): s = empty_ascii_art # "" first = True - i = 0 if scalar_mult is None: scalar_mult = "*" - all_atomic = True for (monomial,c) in terms: b = repr_monomial(monomial) # PCR if c != 0: @@ -516,10 +519,10 @@ def _sub_(self, other): F = self.parent() return F._from_dict( dict_linear_combination( [ ( self._monomial_coefficients, 1 ), (other._monomial_coefficients, -1 ) ] ), remove_zeros=False ) - def _coefficient_fast(self, m, default=None): + def _coefficient_fast(self, m): """ - Returns the coefficient of m in self, where m is key in - self._monomial_coefficients. + Return the coefficient of ``m`` in ``self``, where ``m`` is key in + ``self._monomial_coefficients``. EXAMPLES:: @@ -536,231 +539,17 @@ def _coefficient_fast(self, m, default=None): sage: a._coefficient_fast(p) 1 - sage: a._coefficient_fast(p, 2) - 1 sage: a._coefficient_fast(q) 0 - sage: a._coefficient_fast(q, 2) - 2 sage: a[p] 1 sage: a[q] 0 """ - if default is None: - default = self.base_ring()(0) - return self._monomial_coefficients.get(m, default) + return self._monomial_coefficients.get(m, self.base_ring().zero()) __getitem__ = _coefficient_fast - def coefficient(self, m): - """ - EXAMPLES:: - - sage: s = CombinatorialFreeModule(QQ, Partitions()) - sage: z = s([4]) - 2*s([2,1]) + s([1,1,1]) + s([1]) - sage: z.coefficient([4]) - 1 - sage: z.coefficient([2,1]) - -2 - sage: z.coefficient(Partition([2,1])) - -2 - sage: z.coefficient([1,2]) - Traceback (most recent call last): - ... - AssertionError: [1, 2] should be an element of Partitions - sage: z.coefficient(Composition([2,1])) - Traceback (most recent call last): - ... - AssertionError: [2, 1] should be an element of Partitions - - Test that coefficient also works for those parents that do not yet have an element_class:: - - sage: G = DihedralGroup(3) - sage: F = CombinatorialFreeModule(QQ, G) - sage: hasattr(G, "element_class") - False - sage: g = G.an_element() - sage: (2*F.monomial(g)).coefficient(g) - 2 - """ - # NT: coefficient_fast should be the default, just with appropriate assertions - # that can be turned on or off - C = self.parent()._indices - assert m in C, "%s should be an element of %s"%(m, C) - if hasattr(C, "element_class") and not isinstance(m, C.element_class): - m = C(m) - return self._coefficient_fast(m) - - - def is_zero(self): - """ - Returns True if and only self == 0. - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: B = F.basis() - sage: f = B['a'] - 3*B['c'] - sage: f.is_zero() - False - sage: F.zero().is_zero() - True - - :: - - sage: s = SymmetricFunctions(QQ).schur() - sage: s([2,1]).is_zero() - False - sage: s(0).is_zero() - True - sage: (s([2,1]) - s([2,1])).is_zero() - True - """ - BR = self.parent().base_ring() - zero = BR( 0 ) - return all( v == zero for v in self._monomial_coefficients.values() ) - - def __len__(self): - """ - Returns the number of basis elements of self with nonzero - coefficients. - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: B = F.basis() - sage: f = B['a'] - 3*B['c'] - sage: len(f) - 2 - - :: - - sage: s = SymmetricFunctions(QQ).schur() - sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) - sage: len(z) - 4 - """ - return self.length() - - def length(self): - """ - Returns the number of basis elements of self with nonzero - coefficients. - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: B = F.basis() - sage: f = B['a'] - 3*B['c'] - sage: f.length() - 2 - - :: - - sage: s = SymmetricFunctions(QQ).schur() - sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) - sage: z.length() - 4 - """ - BR = self.parent().base_ring() - zero = BR( 0 ) - return len( [ key for key, coeff in self._monomial_coefficients.iteritems() if coeff != zero ] ) - - def support(self): - """ - Returns a list of the combinatorial objects indexing the basis - elements of self which non-zero coefficients. - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: B = F.basis() - sage: f = B['a'] - 3*B['c'] - sage: f.support() - ['a', 'c'] - - :: - - sage: s = SymmetricFunctions(QQ).schur() - sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) - sage: z.support() - [[1], [1, 1, 1], [2, 1], [4]] - """ - BR = self.parent().base_ring() - zero = BR( 0 ) - - supp = sorted([ key for key, coeff in self._monomial_coefficients.iteritems() if coeff != zero ]) - - return supp - - def monomials(self): - """ - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: B = F.basis() - sage: f = B['a'] + 2*B['c'] - sage: f.monomials() - [B['a'], B['c']] - - sage: (F.zero()).monomials() - [] - """ - P = self.parent() - BR = P.base_ring() - zero = BR( 0 ) - one = BR( 1 ) - - supp = sorted([ key for key, coeff in self._monomial_coefficients.iteritems() if coeff != zero ]) - - return [ P._from_dict( { key : one }, remove_zeros=False ) for key in supp ] - - def terms(self): - """ - Returns a list of the terms of ``self`` - - .. seealso:: :meth:`monomials` - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: B = F.basis() - sage: f = B['a'] + 2*B['c'] - sage: f.terms() - [B['a'], 2*B['c']] - """ - BR = self.parent().base_ring() - zero = BR( 0 ) - v = sorted([ ( key, value ) for key, value in self._monomial_coefficients.iteritems() if value != zero ]) - from_dict = self.parent()._from_dict - return [ from_dict( { key : value } ) for key,value in v ] - - def coefficients(self): - """ - Returns a list of the coefficients appearing on the basis elements in - self. - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: B = F.basis() - sage: f = B['a'] - 3*B['c'] - sage: f.coefficients() - [1, -3] - - :: - - sage: s = SymmetricFunctions(QQ).schur() - sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1]) - sage: z.coefficients() - [1, 1, 1, 1] - """ - BR = self.parent().base_ring() - zero = BR( 0 ) - v = sorted([ ( key, value ) for key, value in self._monomial_coefficients.iteritems() if value != zero ]) - return [ value for key,value in v ] - def _vector_(self, new_base_ring=None): """ Returns ``self`` as a dense vector @@ -838,9 +627,9 @@ def _vector_(self, new_base_ring=None): to_vector = _vector_ - def _acted_upon_(self, scalar, self_on_left = False): + def _acted_upon_(self, scalar, self_on_left=False): """ - Returns the action of a scalar on self + Return the action of ``scalar`` on ``self``. EXAMPLES:: @@ -920,7 +709,7 @@ def _acted_upon_(self, scalar, self_on_left = False): def __div__(self, x, self_on_left=False ): """ - Division by coefficients + Division by coefficients. EXAMPLES:: @@ -937,19 +726,19 @@ def __div__(self, x, self_on_left=False ): sage: f/2 B[2] + 2*B[3] """ - if self.base_ring().is_field(): - F = self.parent() - x = self.base_ring()( x ) - x_inv = x**-1 - D = self._monomial_coefficients - if self_on_left: - D = dict_linear_combination( [ ( D, x_inv ) ], factor_on_left=False ) - else: - D = dict_linear_combination( [ ( D, x_inv ) ] ) + if not self.base_ring().is_field(): + return self.map_coefficients(lambda c: _divide_if_possible(c, x)) - return F._from_dict( D, remove_zeros=False ) + F = self.parent() + x = self.base_ring()( x ) + x_inv = x**-1 + D = self._monomial_coefficients + if self_on_left: + D = dict_linear_combination( [ ( D, x_inv ) ], factor_on_left=False ) else: - return self.map_coefficients(lambda c: _divide_if_possible(c, x)) + D = dict_linear_combination( [ ( D, x_inv ) ] ) + + return F._from_dict( D, remove_zeros=False ) def _divide_if_possible(x, y): """ @@ -1406,7 +1195,7 @@ def __contains__(self, x): def _element_constructor_(self, x): """ - Coerce x into self. + Convert ``x`` into ``self``. EXAMPLES:: @@ -1505,7 +1294,6 @@ def _element_constructor_(self, x): 2*[1, 2, 3] """ R = self.base_ring() - eclass = self.element_class #Coerce ints to Integers if isinstance(x, int): @@ -1535,7 +1323,7 @@ def _element_constructor_(self, x): def _an_element_impl(self): """ - Returns an element of self, namely the zero element. + Return an element of ``self``, namely the zero element. EXAMPLES:: @@ -1549,7 +1337,7 @@ def _an_element_impl(self): def dimension(self): """ - Returns the dimension of the combinatorial algebra (which is given + Return the dimension of the free module (which is given by the number of elements in the basis). EXAMPLES:: @@ -1584,17 +1372,19 @@ def gens(self): def set_order(self, order): """ - Sets the order of the elements of the basis. + Set the order of the elements of the basis. If :meth:`set_order` has not been called, then the ordering is 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 some computations have been - cached does not invalidate the cache, and is likely to - introduce 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:: @@ -1612,7 +1402,7 @@ def set_order(self, order): @cached_method def get_order(self): """ - Returns the order of the elements in the basis. + Return the order of the elements in the basis. EXAMPLES:: @@ -1679,7 +1469,7 @@ def _dense_free_module(self, base_ring=None): - ``base_ring`` -- a ring or ``None`` - If ``base_ring`` is None, then the base ring of ``self`` is used. + If ``base_ring`` is ``None``, then the base ring of ``self`` is used. This method is mostly used by :meth:`CombinatorialFreeModule.Element._vector_` @@ -1702,7 +1492,7 @@ def _dense_free_module(self, base_ring=None): def from_vector(self, vector): """ - Build an element of ``self`` from a (sparse) vector + Build an element of ``self`` from a (sparse) vector. .. SEEALSO:: :meth:`get_order`, :meth:`CombinatorialFreeModule.Element._vector_` @@ -1735,101 +1525,16 @@ def __cmp__(self, other): if c: return c return 0 - def _apply_module_morphism( self, x, on_basis, codomain=False ): - """ - Returns the image of ``x`` under the module morphism defined by - extending :func:`on_basis` by linearity. - - INPUT: - - - - ``x`` : a element of self - - - ``on_basis`` - a function that takes in a combinatorial - object indexing a basis element and returns an element of the - codomain - - - ``codomain`` (optional) - the codomain of the morphism, otherwise it is computed - using :func:`on_basis` - - If ``codomain`` is not specified, then the function tries to compute the codomain - of the module morphism by finding the image of one of the elements in the - support, hence :func:`on_basis` should return an element whose parent is the - codomain. - - EXAMPLES:: - - sage: s = SymmetricFunctions(QQ).schur() - sage: a = s([3]) + s([2,1]) + s([1,1,1]) - sage: b = 2*a - sage: f = lambda part: Integer( len(part) ) - sage: s._apply_module_morphism(a, f) #1+2+3 - 6 - sage: s._apply_module_morphism(b, f) #2*(1+2+3) - 12 - sage: s._apply_module_morphism(s(0), f) - 0 - sage: s._apply_module_morphism(s(1), f) - 0 - sage: s._apply_module_morphism(s(1), lambda part: len(part), ZZ) - 0 - sage: s._apply_module_morphism(s(1), lambda part: len(part)) - Traceback (most recent call last): - ... - ValueError: Codomain could not be determined - """ - - if x == self.zero(): - if not codomain: - B = Family(self.basis()) - try: - z = B.first() - except StopIteration: - raise ValueError('Codomain could not be determined') - codomain = on_basis(z).parent() - return codomain.zero() - else: - if not codomain: - keys = x.support() - key = keys[0] - try: - codomain = on_basis(key).parent() - except Exception: - raise ValueError('Codomain could not be determined') - - if hasattr( codomain, 'linear_combination' ): - return codomain.linear_combination( ( on_basis( key ), coeff ) for key, coeff in x._monomial_coefficients.iteritems() ) - else: - return_sum = codomain.zero() - for key, coeff in x._monomial_coefficients.iteritems(): - return_sum += coeff * on_basis( key ) - return return_sum - - def _apply_module_endomorphism(self, x, on_basis): - """ - This takes in a function from the basis elements to the elements of - self and applies it linearly to a. Note that - _apply_module_endomorphism does not require multiplication on - self to be defined. - - EXAMPLES:: - - sage: s = SymmetricFunctions(QQ).schur() - sage: f = lambda part: 2*s(part.conjugate()) - sage: s._apply_module_endomorphism( s([2,1]) + s([1,1,1]), f) - 2*s[2, 1] + 2*s[3] - """ - return self.linear_combination( ( on_basis( key ), coeff ) for key, coeff in x._monomial_coefficients.iteritems() ) - def sum(self, iter_of_elements): """ - overrides method inherited from commutative additive monoid as it is much faster on dicts directly + Return the sum of all elements in ``iter_of_elements``. - INPUT: + Overrides method inherited from commutative additive monoid as it + is much faster on dicts directly. - - ``iter_of_elements``: iterator of elements of ``self`` + INPUT: - Returns the sum of all elements in ``iter_of_elements`` + - ``iter_of_elements`` -- iterator of elements of ``self`` EXAMPLES:: @@ -1839,26 +1544,25 @@ def sum(self, iter_of_elements): sage: F.sum( f for _ in range(5) ) 10*B[1] + 10*B[2] """ - D = dict_addition( element._monomial_coefficients for element in iter_of_elements ) return self._from_dict( D, remove_zeros=False ) - def linear_combination( self, iter_of_elements_coeff, factor_on_left=True ): + def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): """ + Return the linear combination `\lambda_1 v_1 + \cdots + + \lambda_k v_k` (resp. the linear combination `v_1 \lambda_1 + + \cdots + v_k \lambda_k`) where ``iter_of_elements_coeff`` iterates + through the sequence `((\lambda_1, v_1), ..., (\lambda_k, v_k))`. + INPUT: - ``iter_of_elements_coeff`` -- iterator of pairs ``(element, coeff)`` with ``element`` in ``self`` and ``coeff`` in ``self.base_ring()`` - - ``factor_on_left`` (optional) -- if ``True``, the coefficients are + - ``factor_on_left`` -- (optional) if ``True``, the coefficients are multiplied from the left if ``False``, the coefficients are multiplied from the right - Returns the linear combination `\lambda_1 v_1 + ... + \lambda_k v_k` - (resp. the linear combination `v_1 \lambda_1 + ... + v_k \lambda_k`) - where ``iter_of_elements_coeff`` iterates through the sequence - `(\lambda_1, v_1) ... (\lambda_k, v_k)`. - EXAMPLES:: sage: F = CombinatorialFreeModule(QQ,[1,2]) @@ -1871,7 +1575,7 @@ def linear_combination( self, iter_of_elements_coeff, factor_on_left=True ): def term(self, index, coeff=None): """ - Constructs a term in ``self`` + Construct a term in ``self``. INPUT: @@ -1902,15 +1606,14 @@ def _monomial(self, index): """ return self._from_dict( {index: self.base_ring().one()}, remove_zeros = False ) - # This is generic, and should be lifted into modules_with_basis @lazy_attribute def monomial(self): """ - INPUT: + Return the basis element indexed by ``i``. - - ''i'' + INPUT: - Returns the basis element indexed by i + - ``i`` -- an element of the index set EXAMPLES:: @@ -1918,61 +1621,24 @@ def monomial(self): sage: F.monomial('a') B['a'] - F.monomial is in fact (almost) a map:: + ``F.monomial`` is in fact (almost) a map:: sage: F.monomial Term map from {'a', 'b', 'c'} to Free module generated by {'a', 'b', 'c'} over Rational Field """ # Should use a real Map, as soon as combinatorial_classes are enumerated sets, and therefore parents + from sage.categories.poor_man_map import PoorManMap return PoorManMap(self._monomial, domain=self._indices, codomain=self, name="Term map") - def _sum_of_monomials(self, indices): - """ - TESTS:: - - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: F._sum_of_monomials(['a', 'b']) - B['a'] + B['b'] - """ - # TODO: optimize by calling directly _from_dict if we - # know that all indices are distinct as sum_of_terms; - # otherwise, maybe call dict_addition directly - return self.sum(self.monomial(index) for index in indices) - - @lazy_attribute - def sum_of_monomials(self): - """ - INPUT: - - - ''indices'' -- an list (or iterable) of indices of basis elements - - Returns the sum of the corresponding basis elements - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: F.sum_of_monomials(['a', 'b']) - B['a'] + B['b'] - - sage: F.sum_of_monomials(['a', 'b', 'a']) - 2*B['a'] + B['b'] - - F.sum_of_monomials is in fact (almost) a map:: - - sage: F.sum_of_monomials - A map to Free module generated by {'a', 'b', 'c'} over Rational Field - """ - # domain = sets of self.combinatorial_class(), - return PoorManMap(self._sum_of_monomials, codomain = self) - def sum_of_terms(self, terms, distinct=False): """ - Constructs a sum of terms of ``self`` + Construct a sum of terms of ``self``. INPUT: - - ``terms`` -- a list (or iterable) of pairs (index, coeff) - - ``distinct`` -- whether the indices are guaranteed to be distinct (default: ``False``) + - ``terms`` -- a list (or iterable) of pairs ``(index, coeff)`` + - ``distinct`` -- (default: ``False``) whether the indices are + guaranteed to be distinct EXAMPLES:: @@ -1985,7 +1651,7 @@ def sum_of_terms(self, terms, distinct=False): sage: F.sum_of_terms([('a',2), ('c',3)], distinct = True) 2*B['a'] + 3*B['c'] - .. warning:: + .. WARNING:: Use ``distinct=True`` only if you are sure that the indices are indeed distinct:: @@ -2002,20 +1668,6 @@ def sum_of_terms(self, terms, distinct=False): return self._from_dict(dict(terms)) return self.sum(self.term(index, coeff) for (index, coeff) in terms) - def monomial_or_zero_if_none(self, i): - """ - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: F.monomial_or_zero_if_none('a') - B['a'] - sage: F.monomial_or_zero_if_none(None) - 0 - """ - if i is None: - return self.zero() - return self.monomial(i) - @cached_method def zero(self): """ @@ -2027,18 +1679,19 @@ def zero(self): """ return self._from_dict({}, remove_zeros=False) - def _from_dict( self, d, coerce=False, remove_zeros=True ): - """ - Construct an element of ``self`` from an `{index: coefficient}` dictionary. + def _from_dict(self, d, coerce=False, remove_zeros=True): + r""" + Construct an element of ``self`` from an ``{index: coefficient}`` + dictionary. INPUT: - - ``d`` -- a dictionary ``{index: coeff}`` where each ``index`` is the - index of a basis element and each ``coeff`` belongs to the + - ``d`` -- a dictionary ``{index: coeff}`` where each ``index`` is + the index of a basis element and each ``coeff`` belongs to the coefficient ring ``self.base_ring()`` - - ``coerce`` -- a boolean (default: ``False``), whether to coerce the - coefficients ``coeff`` to the coefficient ring + - ``coerce`` -- a boolean (default: ``False``), whether to coerce + the coefficients ``coeff`` to the coefficient ring - ``remove_zeros`` -- a boolean (default: ``True``), if some coefficients ``coeff`` may be zero and should therefore be removed @@ -2067,7 +1720,7 @@ def _from_dict( self, d, coerce=False, remove_zeros=True ): sage: s._from_dict({part:0}) 0 - .. warning:: + .. WARNING:: With ``remove_zeros=True``, it is assumed that no coefficient of the dictionary is zero. Otherwise, this may @@ -2079,9 +1732,9 @@ def _from_dict( self, d, coerce=False, remove_zeros=True ): assert isinstance(d, dict) if coerce: R = self.base_ring() - d = dict( (key, R(coeff)) for key,coeff in d.iteritems()) + d = {key: R(coeff) for key,coeff in d.iteritems()} if remove_zeros: - d = dict( (key, coeff) for key, coeff in d.iteritems() if coeff) + d = {key: coeff for key, coeff in d.iteritems() if coeff} return self.element_class( self, d ) class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): @@ -2686,3 +2339,4 @@ class Element(CombinatorialFreeModule.Element): # TODO: get rid of this inherita pass CombinatorialFreeModule.CartesianProduct = CombinatorialFreeModule_CartesianProduct + diff --git a/src/sage/combinat/ncsf_qsym/tutorial.py b/src/sage/combinat/ncsf_qsym/tutorial.py index 1c987793d64..4a20abdd1df 100644 --- a/src/sage/combinat/ncsf_qsym/tutorial.py +++ b/src/sage/combinat/ncsf_qsym/tutorial.py @@ -104,10 +104,10 @@ sage: z.degree() 6 - sage: z.coefficients() - [3, 2, 1] + sage: sorted(z.coefficients()) + [1, 2, 3] - sage: z.monomials() + sage: sorted(z.monomials(), key=lambda x: x.support()) [M[1, 2], M[3, 3], M[6]] sage: z.monomial_coefficients() diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 21e989c24a0..f7472b4aa42 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1391,7 +1391,7 @@ def _m_to_self( self, f ): 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() + sprt = sorted(g.support()) Hmu = mu_to_H(sprt[-1]) fl_sprt = fl(sprt[-1]) out[fl_sprt] = self._base(g.coefficient(sprt[-1]) / Hmu.coefficient(sprt[-1])) @@ -1625,7 +1625,7 @@ def _m_to_self( self, f ): g = f.omega_qt(q=subsval, t=0) out = {} while not g.is_zero(): - sprt = g.support() + sprt = sorted(g.support()) 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 diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index c99b2bd525f..e82edcf7bb7 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -2095,8 +2095,8 @@ def transition_matrix(self, basis, n): sage: a = s([3,1])+5*s([1,1,1,1])-s([4]) sage: a 5*s[1, 1, 1, 1] + s[3, 1] - s[4] - sage: mon = a.support() - sage: coeffs = a.coefficients() + sage: mon = sorted(a.support()) + sage: coeffs = [a[i] for i in mon] sage: coeffs [5, 1, -1] sage: mon diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 5d0b8159274..c61e2f32650 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -2077,15 +2077,15 @@ cdef class FreeModuleElement(Vector): # abstract base class def dict(self, copy=True): """ - Return dictionary of nonzero entries of self. + Return dictionary of nonzero entries of ``self``. INPUT: - - ``copy`` -- bool (default: True) + - ``copy`` -- bool (default: ``True``) OUTPUT: - - Python dictionary + - Python dictionary EXAMPLES:: @@ -2110,6 +2110,8 @@ cdef class FreeModuleElement(Vector): # abstract base class e[i] = c return e + monomial_coefficients = dict + ############################# # Plotting ############################# @@ -4821,15 +4823,15 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): def dict(self, copy=True): """ - Return dictionary of nonzero entries of self. + Return dictionary of nonzero entries of ``self``. INPUT: - - ``copy`` -- bool (default: True) + - ``copy`` -- bool (default: ``True``) OUTPUT: - - Python dictionary + - Python dictionary EXAMPLES:: @@ -4842,9 +4844,11 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): else: return self._entries + monomial_coefficients = dict + def list(self, copy=True): """ - Return list of elements of self. + Return list of elements of ``self``. INPUT: From 1bd3296cae6f5328180f985ad9d779a1bd9b3b0b Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sun, 11 Oct 2015 23:28:54 +0200 Subject: [PATCH 1400/1872] Do not use any Sage PATH in configure --- configure.ac | 2 -- 1 file changed, 2 deletions(-) diff --git a/configure.ac b/configure.ac index 3e814ebb8da..b8dad7fe9c9 100644 --- a/configure.ac +++ b/configure.ac @@ -80,8 +80,6 @@ SAGE_SHARE="$SAGE_LOCAL/share" SAGE_EXTCODE="$SAGE_SHARE/sage/ext" SAGE_SPKG_INST="$SAGE_LOCAL/var/lib/sage/installed" -export PATH="$SAGE_LOCAL/bin:$PATH" - ############################################################################### # Determine whether to use MPIR (default standard pkg) or GMP (optional pkg). ############################################################################### From 14f80d3624d95079c896cb5efe8f29988834e1ac Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 11 Oct 2015 19:36:44 -0500 Subject: [PATCH 1401/1872] Reviewer changes and fixing coercions. --- src/sage/combinat/diagram_algebras.py | 159 ++++++++++++++++---------- 1 file changed, 99 insertions(+), 60 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index d8618f16500..7752a564c42 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -27,19 +27,18 @@ CombinatorialFreeModuleElement) from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.combinat.combinat import (bell_number, catalan_number) +from sage.combinat.combinat import bell_number, catalan_number from sage.structure.global_options import GlobalOptions from sage.combinat.set_partition import SetPartitions, SetPartition from sage.combinat.partition import Partitions -from sage.combinat.symmetric_group_algebra import (SymmetricGroupAlgebra, SymmetricGroupAlgebra_n) +from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra_n from sage.combinat.permutation import Permutations -from sage.combinat.combinat import (bell_number, catalan_number) from sage.sets.set import Set from sage.graphs.graph import Graph from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.misc.flatten import flatten from sage.rings.all import ZZ -import operator BrauerDiagramOptions = GlobalOptions(name='Brauer diagram', doc=r""" @@ -1199,7 +1198,6 @@ class DiagramAlgebra(CombinatorialFreeModule): P{{-2, 1, 2}, {-1}}, P{{-2, 2}, {-1}, {1}}, P{{-2, 2}, {-1, 1}}] - """ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): r""" @@ -1225,7 +1223,8 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): self._q = base_ring(q) self._k = k self._base_diagrams = diagrams - category = Algebras(base_ring).FiniteDimensional().WithBasis().or_subcategory(category) + category = Algebras(base_ring.category()).FiniteDimensional().WithBasis() + category = category.or_subcategory(category) CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) @@ -1256,12 +1255,12 @@ def _element_constructor_(self, set_partition): sage: D2(S([2,1])) Traceback (most recent call last): ... - ValueError: invalid input of [[1, -2], [2, -1]] + ValueError: {{-2, 1}, {-1, 2}} is not an index of a basis element """ if self.basis().keys().is_parent_of(set_partition): return self.basis()[set_partition] if isinstance(set_partition, SymmetricGroupAlgebra_n.Element): - return self._element_constructor(self._perm_to_Blst(set_partition.support_of_term())) + return self._apply_module_morphism(set_partition, self._perm_to_Blst, self) sp = self._base_diagrams(set_partition) # attempt conversion if sp in self.basis().keys(): return self.basis()[sp] @@ -1287,13 +1286,25 @@ def __getitem__(self, i): raise ValueError("{0} is not an index of a basis element".format(i)) def _perm_to_Blst(self, w): + """ + Convert the permutation ``w`` to an element of ``self``. + + EXAMPLES:: + + sage: R. = QQ[] + sage: S = SymmetricGroupAlgebra(R,2) + sage: import sage.combinat.diagram_algebras as da + sage: D2 = da.DiagramAlgebra(2, x, R, 'P', da.PlanarDiagrams(2)) + sage: D2._perm_to_Blst([2,1]) + Traceback (most recent call last): + ... + ValueError: {{-2, 1}, {-1, 2}} is not an index of a basis element + """ ## 'perm' is a permutation in one-line notation ## turns w into an expression suitable for the element constructor. u = sorted(w) - return [[u[i],-w[i]] for i in range(len(w))] - - def _convert_perm_to_element_of_self(self, x): - return self(self._perm_to_Blst(x)) + p = [[u[i],-x] for i,x in enumerate(w)] + return self[p] def order(self): r""" @@ -1648,15 +1659,13 @@ class PartitionAlgebra(DiagramAlgebra): sage: a*a 17*P{{-1}, {1}} - Symmetric group algebra elements can also be coerced into the partition algebra. + Symmetric group algebra elements can also be coerced into the + partition algebra:: - TESTS:: - - sage: A = PartitionAlgebra(2, x, SR) sage: S = SymmetricGroupAlgebra(SR, 2) + sage: A = PartitionAlgebra(2, x, SR) sage: S([2,1])*A([[1,-1],[2,-2]]) P{{-2, 1}, {-1, 2}} - REFERENCES: @@ -1696,10 +1705,7 @@ def __init__(self, k, q, base_ring, prefix): self._k = k self._prefix = prefix self._q = base_ring(q) - KSS = SymmetricGroupAlgebra(base_ring, k) DiagramAlgebra.__init__(self, k, q, base_ring, prefix, PartitionDiagrams(k)) - KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)), codomain=self).register_as_coercion() - def _repr_(self): """ @@ -1715,6 +1721,31 @@ def _repr_(self): return "Partition Algebra of rank {} with parameter {} over {}".format( self._k, self._q, self.base_ring()) + def _coerce_map_from_(self, R): + """ + Return a coerce map from ``R`` if one exists and ``None`` otherwise. + + EXAMPLES:: + + sage: R. = QQ[] + sage: S = SymmetricGroupAlgebra(R, 4) + sage: A = PartitionAlgebra(4, x, R) + sage: A._coerce_map_from_(S) + Generic morphism: + From: Symmetric group algebra of order 4 over Univariate Polynomial Ring in x over Rational Field + To: Partition Algebra of rank 4 with parameter x over Univariate Polynomial Ring in x over Rational Field + sage: Sp = SymmetricGroupAlgebra(QQ, 4) + sage: A._coerce_map_from_(Sp) + Generic morphism: + From: Symmetric group algebra of order 4 over Rational Field + To: Partition Algebra of rank 4 with parameter x over Univariate Polynomial Ring in x over Rational Field + """ + if isinstance(R, SymmetricGroupAlgebra_n): + if R.n == self._k and self.base_ring().has_coerce_map_from(R.base_ring()): + return R.module_morphism(self._perm_to_Blst, codomain=self) + return None + return super(PartitionAlgebra, self)._coerce_map_from_(R) + class SubPartitionAlgebra(DiagramAlgebra): """ A subalgebra of the partition algebra indexed by a subset of the diagrams. @@ -1731,15 +1762,11 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): True """ DiagramAlgebra.__init__(self, k, q, base_ring, prefix, diagrams, category) - amb = self.ambient() - self.module_morphism(self.lift, codomain=amb, - category=self.category()).register_as_coercion() - #These methods allow for a sub algebra to be correctly identified in a partition algebra + #These methods allow for a subalgebra to be correctly identified in a partition algebra def ambient(self): r""" Return the partition algebra ``self`` is a sub-algebra of. - Generally, this method is not called directly. EXAMPLES:: @@ -1748,13 +1775,12 @@ def ambient(self): sage: BA.ambient() Partition Algebra of rank 2 with parameter x over Symbolic Ring """ - return PartitionAlgebra(self._k, self._q, self.base_ring(), prefix=self._prefix) + return self.lift.codomain() - def lift(self, x): + @lazy_attribute + def lift(self): r""" - Lift a diagram subalgebra element to the corresponding element - in the ambient space. This method is not intended to be called - directly. + Return the lift map from diagram subalgebra to the ambient space. EXAMPLES:: @@ -1766,20 +1792,16 @@ def lift(self, x): sage: lifted.parent() is BA.ambient() True """ - if x not in self: - raise ValueError("{0} is not in {1}".format(x, self)) - monomial_indices = x.support() - monomial_coefficients = x.coefficients() - result = 0 - for i in xrange(len(monomial_coefficients)): - result += monomial_coefficients[i]*self.ambient().monomial(monomial_indices[i]) - return result + amb = PartitionAlgebra(self._k, self._q, self.base_ring(), prefix=self._prefix) + phi = self.module_morphism(lambda d: amb.monomial(d), + codomain=amb, category=self.category()) + phi.register_as_coercion() + return phi def retract(self, x): r""" Retract an appropriate partition algebra element to the - corresponding element in the partition subalgebra. This method - is not intended to be called directly. + corresponding element in the partition subalgebra. EXAMPLES:: @@ -1790,14 +1812,10 @@ def retract(self, x): sage: BA.retract(E) in BA True """ - if x not in self.ambient() or reduce(operator.mul, [(i in self._indices) for i in x.support()]) == 0: + if ( x not in self.ambient() + or any(i not in self._indices for i in x.support()) ): raise ValueError("{0} cannot retract to {1}".format(x, self)) - monomial_indices = x.support() - monomial_coefficients = x.coefficients() - result = self.zero() - for i in xrange(len(monomial_coefficients)): - result += monomial_coefficients[i]*self.monomial(monomial_indices[i]) - return result + return self._from_dict(x._monomial_coefficients, remove_zeros=False) class BrauerAlgebra(SubPartitionAlgebra): r""" @@ -1825,8 +1843,8 @@ class BrauerAlgebra(SubPartitionAlgebra): EXAMPLES: - We now define the Brauer algebra of rank `2` with parameter ``x`` over - `\ZZ`:: + We now define the Brauer algebra of rank `2` with parameter ``x`` + over `\ZZ`:: sage: R. = ZZ[] sage: B = BrauerAlgebra(2, x, R) @@ -1847,15 +1865,14 @@ class BrauerAlgebra(SubPartitionAlgebra): sage: b[2]^5 x^4*B{{-2, -1}, {1, 2}} - Note, also that since the symmetric group algebra is contained in the Brauer algebra, - there is also a coercion between the two. :: + Note, also that since the symmetric group algebra is contained in + the Brauer algebra, there is also a conversion between the two. :: sage: R. = ZZ[] - sage: B = BrauerAlgebra(2,x,R) - sage: S = SymmetricGroupAlgebra(R,2) + sage: B = BrauerAlgebra(2, x, R) + sage: S = SymmetricGroupAlgebra(R, 2) sage: S([2,1])*B([[1,-1],[2,-2]]) B{{-2, 1}, {-1, 2}} - """ global_options = BrauerDiagramOptions @@ -1887,9 +1904,7 @@ def __init__(self, k, q, base_ring, prefix): sage: BA = BrauerAlgebra(2, q, R) sage: TestSuite(BA).run() """ - KSS = SymmetricGroupAlgebra(base_ring, k) SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, BrauerDiagrams(k)) - KSS.module_morphism(lambda i : self(self._perm_to_Blst(i)), codomain=self).register_as_coercion() def _repr_(self): """ @@ -1905,6 +1920,32 @@ def _repr_(self): return "Brauer Algebra of rank {} with parameter {} over {}".format( self._k, self._q, self.base_ring()) + # TODO: Make a mixin class for diagram algebras that have coercions from SGA? + def _coerce_map_from_(self, R): + """ + Return a coerce map from ``R`` if one exists and ``None`` otherwise. + + EXAMPLES:: + + sage: R. = QQ[] + sage: S = SymmetricGroupAlgebra(R, 4) + sage: A = BrauerAlgebra(4, x, R) + sage: A._coerce_map_from_(S) + Generic morphism: + From: Symmetric group algebra of order 4 over Univariate Polynomial Ring in x over Rational Field + To: Brauer Algebra of rank 4 with parameter x over Univariate Polynomial Ring in x over Rational Field + sage: Sp = SymmetricGroupAlgebra(QQ, 4) + sage: A._coerce_map_from_(Sp) + Generic morphism: + From: Symmetric group algebra of order 4 over Rational Field + To: Brauer Algebra of rank 4 with parameter x over Univariate Polynomial Ring in x over Rational Field + """ + if isinstance(R, SymmetricGroupAlgebra_n): + if R.n == self._k and self.base_ring().has_coerce_map_from(R.base_ring()): + return R.module_morphism(self._perm_to_Blst, codomain=self) + return None + return super(BrauerAlgebra, self)._coerce_map_from_(R) + def _element_constructor_(self, set_partition): r""" Construct an element of ``self``. @@ -1923,8 +1964,6 @@ def _element_constructor_(self, set_partition): sage: BA([{1,2},{-1,-2}]) == b_elt True """ - if isinstance(set_partition, SymmetricGroupAlgebra_n.Element): - return DiagramAlgebra._element_constructor_(self, set_partition) set_partition = to_Brauer_partition(set_partition, k = self.order()) return DiagramAlgebra._element_constructor_(self, set_partition) @@ -2043,7 +2082,7 @@ def _element_constructor_(self, set_partition): sage: TL(S([2,1])) Traceback (most recent call last): ... - ValueError: invalid input of [set([1, -2]), set([2, -1])] + ValueError: {{-2, 1}, {-1, 2}} is not an index of a basis element """ if isinstance(set_partition, SymmetricGroupAlgebra_n.Element): return SubPartitionAlgebra._element_constructor_(self, set_partition) @@ -2205,7 +2244,7 @@ def __init__(self, k, q, base_ring, prefix): sage: TestSuite(I).run() # Not tested -- needs non-unital algebras category """ # This should be the category of non-unital fin-dim algebras with basis - category = Algebras(base_ring).FiniteDimensional().WithBasis() + category = Algebras(base_ring.category()).FiniteDimensional().WithBasis() SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, IdealDiagrams(k), category) From 2e5e9691da0c2003d7eb3ddcf6c5c5010281f4dc Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 11 Oct 2015 23:00:53 -0500 Subject: [PATCH 1402/1872] Some minor reviewer tweaks and doc changes. --- src/sage/combinat/integer_lists/base.pyx | 3 +- src/sage/combinat/integer_lists/invlex.pyx | 91 ++++++++++++---------- src/sage/combinat/integer_lists/lists.py | 15 +++- 3 files changed, 64 insertions(+), 45 deletions(-) diff --git a/src/sage/combinat/integer_lists/base.pyx b/src/sage/combinat/integer_lists/base.pyx index fe146b0d175..de53d35ddd3 100644 --- a/src/sage/combinat/integer_lists/base.pyx +++ b/src/sage/combinat/integer_lists/base.pyx @@ -194,7 +194,8 @@ cdef class IntegerListsBackend(object): def _contains(self, comp): """ - Return ``True`` if ``comp`` meets the constraints imposed by the arguments. + Return ``True`` if ``comp`` meets the constraints imposed + by the arguments. EXAMPLES:: diff --git a/src/sage/combinat/integer_lists/invlex.pyx b/src/sage/combinat/integer_lists/invlex.pyx index 6eec68707d3..e8ef4ec870c 100644 --- a/src/sage/combinat/integer_lists/invlex.pyx +++ b/src/sage/combinat/integer_lists/invlex.pyx @@ -38,7 +38,8 @@ from sage.combinat.integer_lists.base import Infinity class IntegerListsLex(IntegerLists): r""" - Lists of nonnegative integers with constraints, in inverse lexicographic order. + Lists of nonnegative integers with constraints, in inverse + lexicographic order. An *integer list* is a list `l` of nonnegative integers, its *parts*. The slope (at position `i`) is the difference ``l[i+1]-l[i]`` between two @@ -286,7 +287,7 @@ class IntegerListsLex(IntegerLists): sage: IntegerListsLex().first() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set Here is a variant which could be enumerated in lexicographic order but not in inverse lexicographic order:: @@ -305,7 +306,7 @@ class IntegerListsLex(IntegerLists): sage: IntegerListsLex(3).first() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set If one wants to proceed anyway, one can sign a waiver by setting ``check=False`` (again, be warned that some valid lists may never appear):: @@ -823,6 +824,10 @@ class IntegerListsLex(IntegerLists): cdef class IntegerListsBackend_invlex(IntegerListsBackend): + """ + Cython back-end of an set of lists of integers with specified + constraints enumerated in inverse lexicographic order. + """ def __init__(self, *args, check=True, **kwds): """ Initialize ``self``. @@ -899,7 +904,7 @@ If you know what you are doing, you can set check=False to skip this warning.""" sage: L._check_finiteness() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set Indeed:: @@ -922,7 +927,7 @@ If you know what you are doing, you can set check=False to skip this warning.""" sage: iter(L) Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set Some other infinite examples:: @@ -930,25 +935,25 @@ If you know what you are doing, you can set check=False to skip this warning.""" sage: L.list() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set sage: L = IntegerListsLex(ceiling=[0], min_slope=1, max_slope=1) sage: L.list() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set sage: IntegerListsLex(ceiling=[0], min_slope=1, max_slope=1).list() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set The following example is actually finite, but not detected as such:: sage: IntegerListsLex(7, floor=[4], max_part=4, min_slope=-1).list() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set This is sad because the following equivalent example works just fine:: @@ -968,12 +973,12 @@ If you know what you are doing, you can set check=False to skip this warning.""" sage: IntegerListsLex(ceiling=lambda i: max(3-i,0))._check_finiteness() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set sage: IntegerListsLex(7, ceiling=lambda i:0).list() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set The next example shows a case that is finite because we remove trailing zeroes:: @@ -984,7 +989,7 @@ If you know what you are doing, you can set check=False to skip this warning.""" sage: L.list() Traceback (most recent call last): ... - ValueError: Could not prove that the specified constraints yield a finite set + ValueError: could not prove that the specified constraints yield a finite set In the next examples, there is either no solution, or the region is bounded:: @@ -1058,10 +1063,11 @@ If you know what you are doing, you can set check=False to skip this warning.""" return # Variant on ceiling.limit() ==0 where we actually discover that the ceiling limit is 0 - if self.max_slope == 0 and \ - (self.max_sum < Infinity or - (self.ceiling.limit_start() < Infinity and - any(self.ceiling(i) == 0 for i in range(self.ceiling.limit_start()+1)))): + if ( self.max_slope == 0 and + (self.max_sum < Infinity or + (self.ceiling.limit_start() < Infinity and + any(self.ceiling(i) == 0 for i in range(self.ceiling.limit_start()+1))) + ) ): return limit_start = max(self.ceiling.limit_start(), self.floor.limit_start()) @@ -1070,7 +1076,7 @@ If you know what you are doing, you can set check=False to skip this warning.""" if self.ceiling(i) < self.floor(i): return - raise ValueError("Could not prove that the specified constraints yield a finite set") + raise ValueError("could not prove that the specified constraints yield a finite set") def _iter(self): """ @@ -1095,7 +1101,7 @@ DECREASE = 2 POP = 1 STOP = 0 -class IntegerListsLexIter: +class IntegerListsLexIter(object): r""" Iterator class for IntegerListsLex. @@ -1368,13 +1374,15 @@ class IntegerListsLexIter: def _internal_list_valid(self): """ - Return whether the current list in the iteration variable ``self._current_list`` is a valid list. - - This method checks whether the sum of the parts in ``self._current_list`` - is in the right range, whether its length is in the - required range, and whether there are trailing zeroes. It does not check all of the - necessary conditions to verify that an arbitrary list satisfies the - constraints from the corresponding ``IntegerListsLex`` object, and should + Return whether the current list in the iteration variable + ``self._current_list`` is a valid list. + + This method checks whether the sum of the parts in + ``self._current_list`` is in the right range, whether its + length is in the required range, and whether there are trailing + zeroes. It does not check all of the necessary conditions to + verify that an arbitrary list satisfies the constraints from + the corresponding ``IntegerListsLex`` object, and should not be used except internally in the iterator class. EXAMPLES:: @@ -1397,14 +1405,14 @@ class IntegerListsLexIter: mu = self._current_list nu = self._current_sum l = self._j + 1 - good_sum = (nu >= p.min_sum and nu <= p.max_sum) - good_length = (l >= p.min_length and l <= p.max_length) - no_trailing_zeros = (l <= max(p.min_length,0) or mu[-1] != 0) - return good_sum and good_length and no_trailing_zeros + return (nu >= p.min_sum and nu <= p.max_sum # Good sum + and l >= p.min_length and l <= p.max_length # Good length + and (l <= max(p.min_length,0) or mu[-1] != 0)) # No trailing zeros def _m_interval(self, i, max_sum, prev=None): r""" - Return coarse lower and upper bounds for the part ``m`` at position ``i``. + Return coarse lower and upper bounds for the part ``m`` + at position ``i``. INPUT: @@ -1424,8 +1432,8 @@ class IntegerListsLexIter: Additionally, this raises an error if it can be detected that some part is neither directly nor indirectly bounded - above, which implies that the constraints possibly do not allow for - an inverse lexicographic iterator. + above, which implies that the constraints possibly do not + allow for an inverse lexicographic iterator. OUTPUT: @@ -1492,11 +1500,13 @@ class IntegerListsLexIter: def _lookahead(self): r""" - Return whether the current list can possibly be a prefix of a valid list. + Return whether the current list can possibly be a prefix + of a valid list. - OUTPUT: ``False`` if it is guaranteed that the current - list cannot be a prefix of a valid list and ``True`` - otherwise. + OUTPUT: + + ``False`` if it is guaranteed that the current list + cannot be a prefix of a valid list and ``True`` otherwise. EXAMPLES:: @@ -1546,9 +1556,9 @@ class IntegerListsLexIter: ALGORITHM: - Let ``j=self._j`` be the position of the last part `m` of + Let ``j = self._j`` be the position of the last part `m` of ``self._current_list``. The current algorithm computes, - for `k=j,j+1,\ldots`, a lower bound `l_k` and an upper + for `k = j, j+1, \ldots`, a lower bound `l_k` and an upper bound `u_k` for `v_0+\dots+v_k`, and stops if none of the invervals `[l_k, u_k]` intersect ``[min_sum, max_sum]``. @@ -1648,8 +1658,8 @@ class IntegerListsLexIter: # There cannot exist a valid list `v_j,\dots,v_l` with l>=k return False - if (p.max_slope <= 0 and up <= 0) or \ - (p.ceiling.limit() == 0 and k > p.ceiling.limit_start()): + if ( (p.max_slope <= 0 and up <= 0) + or (p.ceiling.limit() == 0 and k > p.ceiling.limit_start()) ): # This implies v_l=0 for l>=k: that is we would be generating # a list with trailing zeroes return False @@ -1661,3 +1671,4 @@ class IntegerListsLexIter: k += 1 return False + diff --git a/src/sage/combinat/integer_lists/lists.py b/src/sage/combinat/integer_lists/lists.py index 2b2be62baa0..e29545ec016 100644 --- a/src/sage/combinat/integer_lists/lists.py +++ b/src/sage/combinat/integer_lists/lists.py @@ -209,11 +209,11 @@ def __iter__(self): return self._element_iter(self.backend._iter(), self._element_constructor) @staticmethod - def _element_iter(iter, constructor): + def _element_iter(itr, constructor): """ - Given an iterator ``iter`` and an element constructor + Given an iterator ``itr`` and an element constructor ``constructor``, iterate over ``constructor(v)`` where `v` - are the values of ``iter``. + are the values of ``itr``. EXAMPLES:: @@ -221,7 +221,7 @@ def _element_iter(iter, constructor): sage: list(C._element_iter(C._iter(), tuple)) [(2, 0, 0), (1, 1, 0), (1, 0, 1), (0, 2, 0), (0, 1, 1), (0, 0, 2)] """ - for v in iter: + for v in itr: yield constructor(v) def __getattr__(self, name): @@ -231,6 +231,12 @@ def __getattr__(self, name): Ideally, this would be done using multiple inheritance, but Python doesn't support that for built-in types. + EXAMPLES:: + + sage: C = IntegerListsLex(2, length=3) + sage: C.min_length + 3 + TESTS: Check that uninitialized instances do not lead to infinite @@ -280,3 +286,4 @@ def _element_constructor_nocheck(self, l): [1, 2, 3] """ return self.element_class(self, l, check=False) + From 8b96bb5cca7f3a76a35b75e99406b7cb1c4cb0e5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 12 Oct 2015 09:53:22 -0500 Subject: [PATCH 1403/1872] Adding changes from #15525. --- src/sage/combinat/integer_lists/invlex.pyx | 4 ++++ src/sage/combinat/integer_lists/lists.py | 3 +++ src/sage/combinat/partition.py | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/integer_lists/invlex.pyx b/src/sage/combinat/integer_lists/invlex.pyx index e8ef4ec870c..c1bbc7163ad 100644 --- a/src/sage/combinat/integer_lists/invlex.pyx +++ b/src/sage/combinat/integer_lists/invlex.pyx @@ -522,6 +522,10 @@ class IntegerListsLex(IntegerLists): in the class :class:`Partition`:: sage: IntegerListsLex(3, max_slope=0, element_class=Partition, global_options=Partitions.global_options).list() + doctest:...: DeprecationWarning: the global_options argument is + deprecated since, in general, pickling is broken; + create your own class instead + See http://trac.sagemath.org/15525 for details. [[3], [2, 1], [1, 1, 1]] Note that the :class:`Partition` further assumes the existence of diff --git a/src/sage/combinat/integer_lists/lists.py b/src/sage/combinat/integer_lists/lists.py index e29545ec016..42ff0dd6214 100644 --- a/src/sage/combinat/integer_lists/lists.py +++ b/src/sage/combinat/integer_lists/lists.py @@ -100,6 +100,9 @@ def __init__(self, *args, **kwds): self.rename(kwds.pop("name")) if "global_options" in kwds: + from sage.misc.superseded import deprecation + deprecation(15525, 'the global_options argument is deprecated since, in general,' + ' pickling is broken; create your own class instead') self.global_options = kwds.pop("global_options") if "element_class" in kwds: diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index a36f90d8ea8..ea7bbb65773 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -7548,7 +7548,7 @@ def number_of_partitions(n, algorithm='default'): [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]] sage: len(v) 7 - sage: number_of_partitions(5, algorithm='bober') + sage: number_of_partitions(5, algorithm='bober') 7 The input must be a nonnegative integer or a ``ValueError`` is raised. From 8a32f1fa6d04cc3364430ece45895069ef7d5352 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 12 Oct 2015 16:54:04 +0200 Subject: [PATCH 1404/1872] correct PEP8-spacings in doctest --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cdc62fe23fc..8d084d35e8a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1511,9 +1511,9 @@ def _pushout_(self, other): However, combining is possible if the factors with the same variable overlap:: - sage: cm.common_parent(GrowthGroup('x^ZZ*log(x)^ZZ'), GrowthGroup('exp(x)^ZZ*x^ZZ')) + sage: cm.common_parent(GrowthGroup('x^ZZ * log(x)^ZZ'), GrowthGroup('exp(x)^ZZ * x^ZZ')) Growth Group exp(x)^ZZ * x^ZZ * log(x)^ZZ - sage: cm.common_parent(GrowthGroup('x^ZZ*log(x)^ZZ'), GrowthGroup('y^ZZ*x^ZZ')) + sage: cm.common_parent(GrowthGroup('x^ZZ * log(x)^ZZ'), GrowthGroup('y^ZZ * x^ZZ')) Growth Group x^ZZ * log(x)^ZZ * y^ZZ :: From e2ad1561bd6d9ef31b53abaaac3681df99035745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Mon, 12 Oct 2015 16:55:11 +0200 Subject: [PATCH 1405/1872] Made two tests pass --- src/sage/combinat/root_system/cartan_type.py | 2 +- src/sage/combinat/root_system/dynkin_diagram.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index d3e8c14cfa0..ffcf39270cb 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -1175,7 +1175,7 @@ def subtype(self, index_set): 0 1 2 3 BC3~ sage: ct.subtype([1,2,3]) - ['C', 3] + ['C', 3] relabelled by {1: 0, 2: 1, 3: 2} """ return self.cartan_matrix().subtype(index_set).cartan_type() diff --git a/src/sage/combinat/root_system/dynkin_diagram.py b/src/sage/combinat/root_system/dynkin_diagram.py index f1962a54a83..bebe22fabbf 100644 --- a/src/sage/combinat/root_system/dynkin_diagram.py +++ b/src/sage/combinat/root_system/dynkin_diagram.py @@ -563,9 +563,7 @@ def subtype(self, index_set): 0 1 2 3 BC3~ sage: D.subtype([1,2,3]) - O---O=<=O - 1 2 3 - C3 + Dynkin diagram of rank 3 """ return self.cartan_matrix().subtype(index_set).dynkin_diagram() From b16026193629c4674ee60e000403f8b550f1a264 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 12 Oct 2015 17:38:17 +0200 Subject: [PATCH 1406/1872] forgotten changes of last merge --- src/sage/rings/asymptotic/misc.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index a3d6c443a41..fb12fdcb8e8 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -368,14 +368,14 @@ def merge_overlapping(A, B, key=None): Akeys = tuple(key(a) for a in A) Bkeys = tuple(key(b) for b in B) - def find_overlapping_index(A, B, Akeys, Bkeys): + def find_overlapping_index(A, B): if len(B) > len(A) - 2: raise StopIteration matches = iter(i for i in xrange(1, len(A) - len(B)) - if Akeys[i:i+len(B)] == Bkeys) + if A[i:i+len(B)] == B) return next(matches) - def find_mergedoverlapping_index(A, B, Akeys, Bkeys): + def find_mergedoverlapping_index(A, B): """ Return in index i where to merge two overlapping tuples/lists ``A`` and ``B``. @@ -384,26 +384,26 @@ def find_mergedoverlapping_index(A, B, Akeys, Bkeys): Adapted from http://stackoverflow.com/a/30056066/1052778. """ matches = iter(i for i in xrange(min(len(A), len(B)), 0, -1) - if Akeys[-i:] == Bkeys[:i]) + if A[-i:] == B[:i]) return next(matches, 0) - i = find_mergedoverlapping_index(A, B, Akeys, Bkeys) + i = find_mergedoverlapping_index(Akeys, Bkeys) if i > 0: return A + B[i:], A[:-i] + B - i = find_mergedoverlapping_index(B, A, Bkeys, Akeys) + i = find_mergedoverlapping_index(Bkeys, Akeys) if i > 0: return B[:-i] + A, B + A[i:] try: - i = find_overlapping_index(A, B, Akeys, Bkeys) + i = find_overlapping_index(Akeys, Bkeys) except StopIteration: pass else: return A, A[:i] + B + A[i+len(B):] try: - i = find_overlapping_index(B, A, Bkeys, Akeys) + i = find_overlapping_index(Bkeys, Akeys) except StopIteration: pass else: From e6971e72338766abeda78fbaecd3be863a4041e9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 12 Oct 2015 11:34:10 -0500 Subject: [PATCH 1407/1872] Make sure that indexing sets are passed along by subtype. --- src/sage/combinat/root_system/cartan_matrix.py | 14 +++++++++++--- src/sage/combinat/root_system/cartan_type.py | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index a353705c512..6d152d57376 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -239,6 +239,9 @@ def __classcall_private__(cls, data=None, index_set=None, cartan_type = None subdivisions = None elif isinstance(data, CartanMatrix): + if index_set is not None: + d = {a: index_set[i] for i,a in enumerate(data.index_set())} + return data.relabel(d) return data else: dynkin_diagram = None @@ -258,7 +261,7 @@ def __classcall_private__(cls, data=None, index_set=None, if dynkin_diagram is not None: n = dynkin_diagram.rank() index_set = dynkin_diagram.index_set() - reverse = dict((index_set[i], i) for i in range(len(index_set))) + reverse = {a: i for i,a in enumerate(index_set)} data = {(i, i): 2 for i in range(n)} for (i,j,l) in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l @@ -272,6 +275,8 @@ def __classcall_private__(cls, data=None, index_set=None, if index_set is None: index_set = tuple(range(n)) + else: + index_set = tuple(index_set) if len(index_set) != n and len(set(index_set)) != n: raise ValueError("the given index set is not valid") @@ -480,14 +485,17 @@ def subtype(self, index_set): EXAMPLES:: sage: C = CartanMatrix(['F',4]) - sage: C.subtype([1,2,3]) + sage: S = C.subtype([1,2,3]) + sage: S [ 2 -1 0] [-1 2 -1] [ 0 -2 2] + sage: S.index_set() + (1, 2, 3) """ ind = self.index_set() I = [ind.index(i) for i in index_set] - return CartanMatrix(self.matrix_from_rows_and_columns(I, I)) + return CartanMatrix(self.matrix_from_rows_and_columns(I, I), index_set) def rank(self): r""" diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index ffcf39270cb..d3e8c14cfa0 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -1175,7 +1175,7 @@ def subtype(self, index_set): 0 1 2 3 BC3~ sage: ct.subtype([1,2,3]) - ['C', 3] relabelled by {1: 0, 2: 1, 3: 2} + ['C', 3] """ return self.cartan_matrix().subtype(index_set).cartan_type() From a87b14961e31957410948c8225febed4d66c8107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 12 Oct 2015 18:37:42 +0200 Subject: [PATCH 1408/1872] trac #19336 some more doctest for maxima lambert_w --- src/sage/functions/log.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index d75c7b2e2f1..a25b85f5976 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -721,6 +721,13 @@ def _maxima_init_evaled_(self, n, z): lambert_w(_SAGE_VAR_x) sage: lambert_w(1, x)._maxima_() generalized_lambert_w(1,_SAGE_VAR_x) + + TESTS:: + + sage: lambert_w(x)._maxima_()._sage_() + lambert_w(x) + sage: lambert_w(2, x)._maxima_()._sage_() + lambert_w(2, x) """ if isinstance(z, str): maxima_z = z From 226f47a20a662f387b74b03941a55962db3c68e6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 12 Oct 2015 11:37:32 -0500 Subject: [PATCH 1409/1872] Making KR crystals more robust against relabeling. --- src/sage/combinat/crystals/affine.py | 8 ++++---- .../rigged_configurations/kr_tableaux.py | 20 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/crystals/affine.py b/src/sage/combinat/crystals/affine.py index 136a1873c32..087d6ce08fe 100644 --- a/src/sage/combinat/crystals/affine.py +++ b/src/sage/combinat/crystals/affine.py @@ -349,7 +349,7 @@ def e(self, i): [[3]] sage: b.e(1) """ - if i == 0: + if i == self.parent()._cartan_type.special_node(): return self.e0() else: x = self.lift().e(i) @@ -374,7 +374,7 @@ def f(self, i): [[1]] sage: b.f(2) """ - if i == 0: + if i == self.parent()._cartan_type.special_node(): return self.f0() else: x = self.lift().f(i) @@ -417,7 +417,7 @@ def epsilon(self, i): sage: [x.epsilon(1) for x in A.list()] [0, 1, 0] """ - if i == 0: + if i == self.parent()._cartan_type.special_node(): return self.epsilon0() else: return self.lift().epsilon(i) @@ -455,7 +455,7 @@ def phi(self, i): sage: [x.phi(1) for x in A.list()] [1, 0, 0] """ - if i == 0: + if i == self.parent()._cartan_type.special_node(): return self.phi0() else: return self.lift().phi(i) diff --git a/src/sage/combinat/rigged_configurations/kr_tableaux.py b/src/sage/combinat/rigged_configurations/kr_tableaux.py index 1637d297003..b47e89e5556 100644 --- a/src/sage/combinat/rigged_configurations/kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/kr_tableaux.py @@ -1322,7 +1322,7 @@ def e(self, i): sage: KRT.module_generators[0].e(0) [[-2, 1], [-1, -1]] """ - if i == 0: + if i == self.parent()._cartan_type.special_node(): ret = self.to_kirillov_reshetikhin_crystal().e0() if ret is None: return None @@ -1343,7 +1343,7 @@ def f(self, i): sage: KRT.module_generators[0].f(0) [[1, 1], [2, -1]] """ - if i == 0: + if i == self.parent()._cartan_type.special_node(): ret = self.to_kirillov_reshetikhin_crystal().f0() if ret is None: return None @@ -1365,7 +1365,7 @@ def epsilon(self, i): sage: KRT.module_generators[0].epsilon(0) 2 """ - if i == 0: + if i == self.parent()._cartan_type.special_node(): return self.to_kirillov_reshetikhin_crystal().epsilon0() return TensorProductOfRegularCrystalsElement.epsilon(self, i) @@ -1383,7 +1383,7 @@ def phi(self, i): sage: KRT.module_generators[0].phi(0) 2 """ - if i == 0: + if i == self.parent()._cartan_type.special_node(): return self.to_kirillov_reshetikhin_crystal().phi0() return TensorProductOfRegularCrystalsElement.phi(self, i) @@ -1481,7 +1481,8 @@ def e(self, i): [[1], [3], [-4], [-2]] sage: KRT(-1, -4, 3, 2).e(3) """ - if i == 0: # Only need to do it once since we pull to the KR crystal + if i == self.parent()._cartan_type.special_node(): + # Only need to do it once since we pull to the KR crystal return KirillovReshetikhinTableauxElement.e(self, i) half = KirillovReshetikhinTableauxElement.e(self, i) @@ -1500,7 +1501,8 @@ def f(self, i): sage: KRT(-1, -4, 3, 2).f(3) [[2], [4], [-3], [-1]] """ - if i == 0: # Only need to do it once since we pull to the KR crystal + if i == self.parent()._cartan_type.special_node(): + # Only need to do it once since we pull to the KR crystal return KirillovReshetikhinTableauxElement.f(self, i) half = KirillovReshetikhinTableauxElement.f(self, i) @@ -1521,7 +1523,8 @@ def epsilon(self, i): sage: KRT(-1, -4, 3, 2).epsilon(3) 0 """ - if i == 0: # Don't need to half it since we pull to the KR crystal + if i == self.parent()._cartan_type.special_node(): + # Don't need to half it since we pull to the KR crystal return KirillovReshetikhinTableauxElement.epsilon(self, i) return KirillovReshetikhinTableauxElement.epsilon(self, i) // 2 @@ -1537,7 +1540,8 @@ def phi(self, i): sage: KRT(-1, -4, 3, 2).phi(3) 1 """ - if i == 0: # Don't need to half it since we pull to the KR crystal + if i == self.parent()._cartan_type.special_node(): + # Don't need to half it since we pull to the KR crystal return KirillovReshetikhinTableauxElement.phi(self, i) return KirillovReshetikhinTableauxElement.phi(self, i) // 2 From a39204c67440a804066b1877937cccdca7593e92 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 12 Oct 2015 18:48:46 +0200 Subject: [PATCH 1410/1872] changes part 2 (of 2) after comments of cheuberg --- src/sage/rings/asymptotic/asymptotic_ring.py | 97 +++++++++++++------- src/sage/rings/asymptotic/growth_group.py | 30 +++++- src/sage/rings/asymptotic/term_monoid.py | 4 +- src/sage/rings/big_oh.py | 6 +- 4 files changed, 95 insertions(+), 42 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b354fbc5b37..47abcaccf17 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -35,7 +35,9 @@ also called *Bachmann--Landau notation*) for growth group element `g` (:ref:`again see below `). -See :wikipedia:`Asymptotic_expansion` for more details. +See +:wikipedia:`the Wikipedia article on asymptotic expansions ` +for more details. Further examples of such elements can be found :ref:`here `. @@ -49,7 +51,8 @@ is described below these examples---are - elements of the form `z^q` for some integer or rational `q` - (growth groups ``z^ZZ`` or ``z^QQ``), + (growth groups with :ref:`description strings ` + ``z^ZZ`` or ``z^QQ``), - elements of the form `\log(z)^q` for some integer or rational `q` (growth groups ``log(z)^ZZ`` or ``log(z)^QQ``), @@ -70,9 +73,20 @@ \lim_{z\to\infty} \frac{g_1}{g_2} \leq 1. -To find out more about growth groups, on how they are created and -about the above used descriptions strings see the top of the -module :doc:`growth group `. +.. NOTE:: + + Asymptotic rings where the variable tend to some value distinct from + `\infty` are not yet implemented. + +To find out more about + +- growth groups, + +- on how they are created and + +- about the above used *descriptions strings* + +see the top of the module :doc:`growth group `. .. WARNING:: @@ -104,27 +118,45 @@ Introductory Examples ===================== +We start this series of examples by defining two asymptotic rings. + + +Two Rings +--------- + +A Univariate Asymptotic Ring +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + First, we construct the following (very simple) asymptotic ring in the variable `z`:: sage: A. = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ); A Asymptotic Ring over Integer Ring A typical element of this ring is - :: sage: A.an_element() z^(3/2) + O(z^(1/2)) This element consists of two summands: the exact term with coefficient -`-1` and growth `z^{3/2}` and the `O`-term `O(z^{1/2})`. Note that the +`1` and growth `z^{3/2}` and the `O`-term `O(z^{1/2})`. Note that the growth of `z^{3/2}` is larger than the growth of `z^{1/2}` as `z\to\infty`, thus this expansion cannot be simplified (which would be done automatically, see below). +Elements can be constructed via the generator `z` and the function +:func:`~sage.rings.big_oh.O`, for example + +:: + + sage: 4*z^2 + O(z) + 4*z^2 + O(z) + +A Multivariate Asymptotic Ring +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Next, we construct a more sophisticated asymptotic ring in the variables `x` and `y` by - :: sage: B. = AsymptoticRing(growth_group='x^QQ * log(x)^ZZ * QQ^y * y^QQ', coefficient_ring=QQ); B @@ -135,20 +167,24 @@ sage: B.an_element() 1/8*x^(3/2)*log(x)^3*(1/8)^y*y^(3/2) + O(x^(1/2)*log(x)*(1/2)^y*y^(1/2)) +Again, elements can be created using the generators `x` and `y`, as well as +the function :func:`~sage.rings.big_oh.O`:: + + sage: log(x)*y/42 + O(1/2^y) + 1/42*log(x)*y + O((1/2)^y) Arithmetical Operations ----------------------- -With the asymptotic rings constructed above (or more precisely with -their elements) we can do a lot of arithmetical -calculations. +In this section we explain how to perform various arithmetical +calculations with the elements of the asymptotic rings constructed +above. The Ring Operations Plus and Times ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We start our calculations in the ring - :: sage: A @@ -169,14 +205,12 @@ The central concepts of computations with asymptotic expansions is that the `O`-notation can be used. For example, we have - :: sage: z^3 + z^2 + z + O(z^2) z^3 + O(z^2) -where the result is simplified automatically. More advanced - +where the result is simplified automatically. A more sophisticated example is :: sage: (z+2*z^2+3*z^3+4*z^4) * (O(z)+z^2) @@ -186,26 +220,33 @@ Division ^^^^^^^^ -The asymptotic expansions support division. For example, we get can -expand `1/(1-z)` to a geometric series:: +The asymptotic expansions support division. For example, we can +expand `1/(z-1)` to a geometric series:: sage: 1 / (z-1) z^(-1) + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21)) -Since there is a default precision (parameter ``default_prec``) -defined, only the first `20` summands are calculated. However, if we -only want the first `5` exact terms, we cut of the rest by using +A default precision (parameter ``default_prec`` of +:class:`AsymptoticRing`) is predefined. Thus, only the first `20` +summands are calculated. However, if we only want the first `5` exact +terms, we cut of the rest by using :: sage: (1 / (z-1)).truncate(5) z^(-1) + z^(-2) + z^(-3) + z^(-4) + z^(-5) + O(z^(-6)) +or +:: + + sage: 1 / (z-1) + O(z^(-6)) + z^(-1) + z^(-2) + z^(-3) + z^(-4) + z^(-5) + O(z^(-6)) + Of course, we can work with more complicated expansions as well:: - sage: (4*z+1) / (z^3+z^2+z+O(A(1))) + sage: (4*z+1) / (z^3+z^2+z+O(z^0)) 4*z^(-2) - 3*z^(-3) - z^(-4) + O(z^(-5)) -Note that not all elements are invertible, for instance, +Not all elements are invertible, for instance, :: @@ -279,14 +320,6 @@ e - 1/2*e*n^(-1) + 11/24*e*n^(-2) - 7/16*e*n^(-3) + 2447/5760*e*n^(-4) + O(n^(-5)) -Example n+1 ------------ - -.. TODO:: - - write more examples - - Selected Technical Details ========================== @@ -426,7 +459,7 @@ class AsymptoticExpansion(CommutativeAlgebraElement): EXAMPLES: - There are several ways to create asymptotic expressions; usually + There are several ways to create asymptotic expansions; usually this is done by using the corresponding :class:`asymptotic rings `:: sage: R_x. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R_x @@ -639,7 +672,7 @@ def summands(self): def __nonzero__(self): r""" - Return whether this asymptotic expression is not identically zero. + Return whether this asymptotic expansion is not identically zero. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 00a05b045cc..7a817bd64f3 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -21,7 +21,8 @@ TESTS:: - sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup, GrowthGroup + sage: from sage.rings.asymptotic.growth_group import \ + ....: GenericGrowthGroup, GrowthGroup sage: GenericGrowthGroup(ZZ) doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change @@ -90,6 +91,7 @@ For many purposes the factory ``GrowthGroup`` (see :class:`GrowthGroupFactory`) is the most convenient way to generate a growth group. +:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup @@ -97,11 +99,28 @@ sage: GrowthGroup('z^ZZ') Growth Group z^ZZ - sage: GrowthGroup('z^QQ') + sage: M = GrowthGroup('z^QQ'); M Growth Group z^QQ Each of these two generated groups is a :class:`MonomialGrowthGroup`, whose elements are powers of a fixed symbol (above ``'z'``). +For the order of the elements it is assumed that `z\to\infty`. + +.. NOTE:: + + Growth groups where the variable tend to some value distinct from + `\infty` are not yet implemented. + +To create elements of `M`, a generator can be used:: + + sage: z = M.gen() + sage: z^(3/5) + z^(3/5) + +Strings can also be parsed:: + + sage: M('z^7') + z^7 Similarly, we can construct logarithmic factors by:: @@ -158,8 +177,8 @@ EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G_x = GrowthGroup('x^ZZ'); repr(G_x) - 'Growth Group x^ZZ' + sage: G_x = GrowthGroup('x^ZZ'); G_x + Growth Group x^ZZ sage: G_xy = GrowthGroup('x^ZZ * y^ZZ'); G_xy Growth Group x^ZZ * y^ZZ sage: G_xy.an_element() @@ -192,7 +211,8 @@ means that in the second growth group, ``log(x)`` is assumed to grow faster than ``x`` (which is nonsense, mathematically). See :class:`CartesianProduct ` -for more details. +for more details or see :ref:`above ` +for a more extensive description. Short notation also allows the construction of more complicated growth groups:: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 6ce09b68068..567d0757d99 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -228,7 +228,7 @@ def absorption(left, right): Let one of the two passed terms absorb the other. Helper function used by - :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpression`. + :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpansion`. .. NOTE:: @@ -282,7 +282,7 @@ def can_absorb(left, right): other. Helper function used by - :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpression`. + :class:`~sage.rings.asymptotic.asymptotic_ring.AsymptoticExpansion`. INPUT: diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 9e3080fe190..0e98a4a5bec 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -3,7 +3,7 @@ .. SEEALSO:: - - :mod:`asymptotic expressions ` + - `asymptotic expansions <../../asymptotic_expansions_index.html>`_ - `p-adic numbers <../../../padics/index.html>`_ - `power series <../../../power_series/index.html>`_ - `polynomials <../../../polynomial_rings/index.html>`_ @@ -78,8 +78,8 @@ def O(*x, **kwds): sage: K(11^-12, 15) 11^-12 + O(11^15) - We can also work with :mod:`asymptotic expressions - `:: + We can also work with :doc:`asymptotic expansions + `:: sage: A. = AsymptoticRing(growth_group='QQ^n * n^QQ * log(n)^QQ', coefficient_ring=QQ); A doctest:...: FutureWarning: From d29ccf7f1bfe811b320dfb686d28ec1ed0aa59c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 12 Oct 2015 19:20:14 +0200 Subject: [PATCH 1411/1872] trac #6322 now tested with magma --- .../explicit_methods_in_number_theory/nf_galois_groups.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 abae9503c11..530c26f614d 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 @@ -89,7 +89,7 @@ groups in the GAP transitive groups database. :: sage: K. = NumberField(x^3 - 2) - sage: K.galois_group(type="gap", algorithm='magma') # optional - magma + sage: K.galois_group(type="gap", algorithm='magma') # optional - magma # optional - database_gap Galois group Transitive group number 2 of degree 3 of the Number Field in a with defining polynomial x^3 - 2 From 6a17c58a5e6f13b8a55efd744521bc80d5828926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 12 Oct 2015 19:50:44 +0200 Subject: [PATCH 1412/1872] trac #16209 fixing now that seeds are not hashable --- src/sage/combinat/cluster_algebra_quiver/cluster_seed.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 7c6ba32b392..96c45affd02 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -3976,9 +3976,10 @@ def oriented_exchange_graph(self): covers = [] n = self.n() stack = [self] - known_clusters = {} + known_clusters = [] while stack: i = stack.pop() + Vari = tuple(sorted(i.cluster())) B = i.b_matrix() for k in range(n): # check if green @@ -3986,10 +3987,10 @@ def oriented_exchange_graph(self): j = i.mutate(k, inplace=False) Varj = tuple(sorted(j.cluster())) if Varj in known_clusters: - covers.append((i, known_clusters[Varj])) + covers.append((Vari, Varj)) else: - covers.append((i, j)) - known_clusters[Varj] = j + covers.append((Vari, Varj)) + known_clusters += [Varj] stack.append(j) return DiGraph(covers) From 2f76a4e74dae5398094d7c41df80c58b9e6cb9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 12 Oct 2015 20:28:15 +0200 Subject: [PATCH 1413/1872] trac #16209 details --- src/sage/combinat/cluster_algebra_quiver/cluster_seed.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 96c45affd02..dcff261ea1c 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -3986,10 +3986,8 @@ def oriented_exchange_graph(self): if all(B[i2][k] >= 0 for i2 in range(n, 2 * n)): j = i.mutate(k, inplace=False) Varj = tuple(sorted(j.cluster())) - if Varj in known_clusters: - covers.append((Vari, Varj)) - else: - covers.append((Vari, Varj)) + covers.append((Vari, Varj)) + if not(Varj in known_clusters): known_clusters += [Varj] stack.append(j) From 2485c770ee762b4bd8ca597507dd0bb909e2053f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 12 Oct 2015 13:32:39 -0500 Subject: [PATCH 1414/1872] Better iteration of RC's and a better doctest. --- .../rigged_configurations/kr_tableaux.py | 14 +++++------- .../rigged_configurations.py | 22 ++++--------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/sage/combinat/rigged_configurations/kr_tableaux.py b/src/sage/combinat/rigged_configurations/kr_tableaux.py index 1637d297003..acf1b1c9c85 100644 --- a/src/sage/combinat/rigged_configurations/kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/kr_tableaux.py @@ -308,20 +308,16 @@ def __iter__(self): EXAMPLES:: - sage: KR = crystals.KirillovReshetikhin(['A', 3, 1], 2, 1, model='KR') - sage: g = KR.__iter__() - sage: next(g) - [[1], [2]] - sage: next(g) - [[1], [3]] - sage: next(g) - [[2], [3]] + sage: KR = crystals.KirillovReshetikhin(['A', 5, 2], 2, 1, model='KR') + sage: L = [x for x in KR] + sage: len(L) + 15 """ index_set = self._cartan_type.classical().index_set() 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() + structure='graded').breadth_first_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 86f5c38263d..abfba3bc94b 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configurations.py +++ b/src/sage/combinat/rigged_configurations/rigged_configurations.py @@ -480,29 +480,15 @@ def __iter__(self): EXAMPLES:: sage: RC = RiggedConfigurations(['A', 3, 1], [[2,1], [1,1]]) - sage: g = RC.__iter__() - sage: next(g) - - (/) - - (/) - - (/) - - sage: next(g) # random - - 0[ ]0 - - 0[ ]0 - - (/) - + sage: L = [x for x in RC] + sage: len(L) + 24 """ index_set = self._cartan_type.classical().index_set() 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() + structure='graded').breadth_first_search_iterator() @lazy_attribute def module_generators(self): From d00d31b36950f948b0be0d1d26b10543b23e3957 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 12 Oct 2015 12:02:34 -0700 Subject: [PATCH 1415/1872] trac 6102: cup products for Delta complexes --- src/sage/homology/cell_complex.py | 29 +++++--- src/sage/homology/delta_complex.py | 36 ++++++++- .../homology_vector_space_with_basis.py | 73 ++++++++++++++----- 3 files changed, 107 insertions(+), 31 deletions(-) diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 1c6af68409c..0c563567424 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -770,7 +770,7 @@ def homology_with_basis(self, dim, base_ring=None, cohomology=False): Return the unreduced homology in dimension ``dim`` with coefficients in ``base_ring`` with a chosen basis. - This is only implemented for simplicial, cubical, and + This is implemented for simplicial, cubical, and `\Delta`-complexes. INPUTS: @@ -806,12 +806,12 @@ def cohomology_with_basis(self, dim, base_ring=None): Return the unreduced cohomology in dimension ``dim`` with coefficients in ``base_ring`` with a chosen basis. - This is only implemented for simplicial, cubical, and - `\Delta`-complexes. For simplicial and cubical complexes, the - resulting elements are suitable for computing cup - products. For simplicial complexes, they should be suitable - for computing cohomology operations; at the moment, only mod 2 - cohomology operations have been implemented. + This is implemented for simplicial, cubical, and + `\Delta`-complexes. The resulting elements are suitable for + computing cup products. For simplicial complexes, they should + be suitable for computing cohomology operations; at the + moment, only mod 2 cohomology operations have been + implemented. INPUTS: @@ -842,8 +842,7 @@ def cohomology_with_basis(self, dim, base_ring=None): sage: simplicial_complexes.Torus().cohomology_with_basis(2, QQ) Free module generated by (h^{2,0},) over Rational Field - You can compute cup products of cohomology classes when - working with cubical or simplicial complexes:: + You can compute cup products of cohomology classes:: sage: x.cup_product(y) h^{2,0} @@ -851,6 +850,15 @@ def cohomology_with_basis(self, dim, base_ring=None): -h^{2,0} sage: x.cup_product(x) 0 + + Cohomology operations:: + + sage: RP2 = simplicial_complexes.RealProjectivePlane() + sage: K = RP2.suspension() + sage: K.set_immutable() + sage: y = K.cohomology_with_basis(2, GF(2)).basis()[0] + sage: y.Sq(1) + h^{3,0} """ return self.homology_with_basis(dim, base_ring, cohomology=True) @@ -861,7 +869,8 @@ def cohomology_ring(self, base_ring=None): """ The cohomology ring of this cell complex, with field coefficients. - This is only implemented for simplicial and cubical complexes. + This is implemented for simplicial, cubical, and + `\Delta`-complexes. INPUT: diff --git a/src/sage/homology/delta_complex.py b/src/sage/homology/delta_complex.py index 9ad45970672..b859b480057 100644 --- a/src/sage/homology/delta_complex.py +++ b/src/sage/homology/delta_complex.py @@ -56,7 +56,7 @@ """ from copy import copy -from sage.homology.cell_complex import GenericCellComplex +from sage.homology.cell_complex import GenericCellComplex, Chains from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from sage.matrix.constructor import matrix @@ -1438,6 +1438,40 @@ def barycentric_subdivision(self): """ raise NotImplementedError("Barycentric subdivisions are not implemented for Delta complexes.") + def n_chains(self, n, base_ring=None, cochains=False): + r""" + Return the free module of chains in degree ``n`` over ``base_ring``. + + INPUTS: + + - ``n`` -- integer + - ``base_ring`` -- ring (optional, default `\ZZ`) + - ``cochains`` -- boolean (optional, default ``False``); if + ``True``, return cochains instead + + Since the list of `n`-cells for a `\Delta`-complex may have + some ambiguity -- for example, the list of edges may look like + ``[(0, 0), (0, 0), (0, 0)]`` if each edge starts and ends at + vertex 0 -- we record the indices of the cells along with + their tuples. So the basis of chains in such a case would look + like ``[(0, (0, 0)), (1, (0, 0)), (2, (0, 0))]``. + + The only difference between chains and cochains is notation: + the dual cochain to the chain basis element ``b`` is written + as ``\chi_b``. + + EXAMPLES:: + + sage: T = delta_complexes.Torus() + sage: T.n_chains(1, QQ) + Free module generated by {(0, (0, 0)), (1, (0, 0)), (2, (0, 0))} over Rational Field + sage: list(T.n_chains(1, QQ, cochains=False).basis()) + [(0, (0, 0)), (1, (0, 0)), (2, (0, 0))] + sage: list(T.n_chains(1, QQ, cochains=True).basis()) + [\chi_(0, (0, 0)), \chi_(1, (0, 0)), \chi_(2, (0, 0))] + """ + return Chains(tuple(enumerate(self.n_cells(n))), base_ring, cochains) + # the second barycentric subdivision is a simplicial complex. implement this somehow? # def simplicial_complex(self): # X = self.barycentric_subdivision().barycentric_subdivision() diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index c24a755d737..be28d181896 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -31,10 +31,9 @@ from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement from simplicial_complex import SimplicialComplex -from cubical_complex import CubicalComplex class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): - """ + r""" Homology (or cohomology) vector space. This is intended to provide enough structure to allow the @@ -105,7 +104,7 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): sage: x.cup_product(x) 0 - This works with both simplicial complexes and cubical complexes:: + This works with simplicial, cubical, and Delta complexes:: sage: Klein_c = cubical_complexes.KleinBottle() sage: H1 = Klein_c.cohomology_with_basis(1, GF(2)) @@ -117,14 +116,23 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): sage: y.cup_product(y) h^{2,0} + sage: Klein_d = delta_complexes.KleinBottle() + sage: H1 = Klein_d.cohomology_with_basis(1, GF(2)) + sage: u,v = H1.basis() + sage: u.cup_product(u) + h^{2,0} + sage: u.cup_product(v) + 0 + sage: v.cup_product(v) + h^{2,0} + + The basis elements in the simplicial complex case have been chosen + differently; apply the change of basis `x \mapsto a+b`, `y \mapsto + b` to see the same product structure. :: + sage: Klein_s = simplicial_complexes.KleinBottle() sage: H1 = Klein_s.cohomology_with_basis(1, GF(2)) sage: a,b = H1.basis() - - The basis elements have been chosen differently; apply the change - of basis `x \mapsto a+b`, `y \mapsto b` to see the same product - structure. :: - sage: a.cup_product(a) 0 sage: a.cup_product(b) @@ -352,14 +360,18 @@ def cup_product(self, other): sage: x.cup_product(x) 0 - But not with `\Delta`-complexes:: + and `\Delta`-complexes:: - sage: X = delta_complexes.SurfaceOfGenus(2) - sage: a,b,c,d = X.cohomology_with_basis(1, QQ).gens() + sage: T_d = delta_complexes.Torus() + sage: a,b = T_d.cohomology_with_basis(1, QQ).gens() sage: a.cup_product(b) - Traceback (most recent call last): - ... - NotImplementedError: cup products are only implemented for simplicial and cubiical complexes + h^{2,0} + sage: b.cup_product(a) + -h^{2,0} + sage: RP2 = delta_complexes.RealProjectivePlane() + sage: w = RP2.cohomology_with_basis(1, GF(2)).gens()[0] + sage: w.cup_product(w) + h^{2,0} A non-connected example:: @@ -374,8 +386,6 @@ def cup_product(self, other): True """ scomplex = self.parent().complex() - if not isinstance(scomplex, (SimplicialComplex, CubicalComplex)): - raise NotImplementedError('cup products are only implemented for simplicial and cubiical complexes') base_ring = self.base_ring() if not (scomplex == other.parent().complex() and self.parent()._cohomology @@ -388,10 +398,33 @@ def cup_product(self, other): for gamma in scomplex.homology_with_basis(deg_tot, base_ring).basis(): gamma_coeff = base_ring.zero() for cell, coeff in gamma.to_cycle(): - for (c, left_cell, right_cell) in cell.alexander_whitney(deg_left): + if hasattr(cell, 'alexander_whitney'): + # Simplicial and cubical case: each cell has a + # method 'alexander_whitney' which computes + # the appropriate faces. + for (c, left_cell, right_cell) in cell.alexander_whitney(deg_left): + left = scomplex.n_chains(deg_left, base_ring)(left_cell) + right = scomplex.n_chains(deg_right, base_ring)(right_cell) + gamma_coeff += c * coeff * self.to_cycle().eval(left) * other.to_cycle().eval(right) + else: + # Delta complex case: each "cell" in n_chains + # is just a pair (integer, tuple), where the + # integer is its index in the list, and the + # jth entry of the tuple is the index of its + # jth face in the list of (n-1)-chains. Use + # this data to compute the appropriate faces + # by hand. + left_cell = cell + for i in range(deg_tot, deg_left, -1): + idx = left_cell[1][i] + left_cell = (idx, scomplex.n_cells(i-1)[idx]) + right_cell = cell + for i in range(deg_tot, deg_right, -1): + idx = right_cell[1][0] + right_cell = (idx, scomplex.n_cells(i-1)[idx]) left = scomplex.n_chains(deg_left, base_ring)(left_cell) - right = scomplex.n_chains(deg_right, base_ring)(right_cell) - gamma_coeff += c * coeff * self.to_cycle().eval(left) * other.to_cycle().eval(right) + right = scomplex.n_chains(deg_left, base_ring)(right_cell) + gamma_coeff += coeff * self.to_cycle().eval(left) * other.to_cycle().eval(right) result.append((gamma.leading_support(), gamma_coeff)) return scomplex.cohomology_with_basis(deg_tot, base_ring).sum_of_terms(result) @@ -505,7 +538,7 @@ def Sq(self, i): sage: x.Sq(1) Traceback (most recent call last): ... - ValueError: Steenrod squares are only defined in characteristic 2 + ValueError: Steenrod squares are only defined in characteristic 2 """ scomplex = self.parent().complex() if not isinstance(scomplex, SimplicialComplex): From 1e97e1d5604f0119ebcbf5f599ff0047c79336a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Mon, 12 Oct 2015 21:33:46 +0200 Subject: [PATCH 1416/1872] Removed many blank spaces --- .../cluster_algebra_quiver/cluster_seed.py | 93 +++++++++---------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index dcff261ea1c..ad41db77a43 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -285,7 +285,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user self._user_labels_prefix = user_labels_prefix # initialize the rest - + self._C = matrix.identity(self._n) self._use_c_vec = True @@ -300,7 +300,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user self._mut_path = [ ] self._track_mut = True - + if user_labels: self._sanitize_init_vars(user_labels, user_labels_prefix) else: @@ -618,7 +618,7 @@ def use_fpolys(self, use=True, user_labels=None, user_labels_prefix=None): self._yhat = dict([ (self._U.gen(j),prod([self._R.gen(i)**self._M[i,j] for i in xrange(self._n+self._m)])) for j in xrange(self._n)]) elif self._cluster: raise ValueError("should not be possible to have cluster variables without f-polynomials") # added this as a sanity check. This error should never appear however. - elif self._track_mut == True: #If we can navigate from the root to where we are + elif self._track_mut == True: # If we can navigate from the root to where we are if not self._use_g_vec: self.use_g_vectors(True) catchup = ClusterSeed(self._b_initial, user_labels=user_labels, user_labels_prefix=user_labels_prefix) @@ -712,20 +712,20 @@ def track_mutations(self, use=True): def _sanitize_init_vars(self, user_labels, user_labels_prefix = 'x'): r""" Warning: This is an internal method that rewrites a user-given set of cluster variable names into a format that Sage can utilize. - + INPUT: - + - ``user_labels`` -- The labels that need sanitizing - ``user_labels_prefix`` -- (default:'x') The prefix to use for labels if integers given for labels - + EXAMPLES:: - + sage: S = ClusterSeed(['A',4]); S._init_vars {0: 'x0', 1: 'x1', 2: 'x2', 3: 'x3', 4: 'y0', 5: 'y1', 6: 'y2', 7: 'y3'} sage: S._sanitize_init_vars([1,2,3,4],'z') sage: S._init_vars {0: 'z1', 1: 'z2', 2: 'z3', 3: 'z4'} - + sage: S = ClusterSeed(['A',4]); S._init_vars {0: 'x0', 1: 'x1', 2: 'x2', 3: 'x3', 4: 'y0', 5: 'y1', 6: 'y2', 7: 'y3'} sage: S._sanitize_init_vars(['a', 'b', 'c', 'd']) @@ -828,13 +828,13 @@ def __eq__(self, other): True sage: S.mutate([0,1,0,1,0]) - sage: S.__eq__( T ) + sage: S.__eq__( T ) False sage: S.cluster() [x1, x0] sage: T.cluster() [x0, x1] - + sage: S.mutate([0,1,0,1,0]) sage: S.__eq__( T ) True @@ -1183,18 +1183,18 @@ def mutations(self): sage: S.mutate([0,1,0,2]) sage: S.mutations() [0, 1, 0, 2] - + sage: S.track_mutations(False) sage: S.mutations() Traceback (most recent call last): ... - ValueError: Not recording mutation sequence. Need to track mutations. + ValueError: Not recording mutation sequence. Need to track mutations. """ if self._track_mut: - return copy(self._mut_path) + return copy(self._mut_path) else: - raise ValueError("Not recording mutation sequence. Need to track mutations.") - + raise ValueError("Not recording mutation sequence. Need to track mutations.") + def cluster_variable(self, k): r""" Generates a cluster variable using F-polynomials @@ -1225,7 +1225,7 @@ def cluster_variable(self, k): else: raise ValueError('No cluster variable with index or label ' + str(k) + '.') elif self._track_mut: # if we can recreate the clusters - catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) + catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) catchup.use_c_vectors(use=self._use_c_vec, bot_is_c=self._bot_is_c) catchup.mutate(self.mutations()) return catchup.cluster_variable(k) @@ -1258,7 +1258,7 @@ def cluster(self): if not self._use_fpolys: if self._track_mut: # if we can recreate the clusters - catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) + catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) catchup.use_c_vectors(use=self._use_c_vec, bot_is_c=self._bot_is_c) catchup.mutate(self.mutations()) return catchup.cluster() @@ -1345,7 +1345,7 @@ def f_polynomial(self,k): return self._F[IE[k]] elif self._track_mut: - catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) + catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) catchup.use_c_vectors(use=self._use_c_vec, bot_is_c=self._bot_is_c) catchup.mutate(self.mutations()) @@ -1515,7 +1515,7 @@ def _g_mutate(self, k): J[j,k] += max(0, -eps*B[j,k]) J[k,k] = -1 self._G = self._G*J - + def c_vector(self,k): r""" Returns the ``k``-th *c-vector* of ``self``. It is obtained as the @@ -1631,7 +1631,7 @@ def d_vector(self, k): catchup.use_fpolys(False) catchup.use_g_vectors(False) catchup.use_c_vectors(False) - + catchup.mutate(self.mutations()) return copy(catchup._D).column(k) else: @@ -1640,7 +1640,7 @@ def d_vector(self, k): def d_matrix(self, show_warnings=True): r""" Returns the matrix of *d-vectors* of ``self``. - + EXAMPLES:: sage: S = ClusterSeed(['A',4]); S.d_matrix() [-1 0 0 0] @@ -1668,7 +1668,7 @@ def d_matrix(self, show_warnings=True): catchup.use_g_vectors(False) catchup.use_c_vectors(False) catchup.track_mutations(False) - + catchup.mutate(self.mutations()) return catchup.d_matrix() elif show_warnings: @@ -2301,7 +2301,7 @@ def mutate(self, sequence, inplace=True): # function should return either integer or sequence sequence = sequence(seed) - + if sequence is None: raise ValueError('Not mutating: No vertices given.') @@ -2312,17 +2312,17 @@ def mutate(self, sequence, inplace=True): n, m = seed.n(), seed.m() V = range(n)+IE - + if seed._use_fpolys and isinstance(sequence, str): sequence = seed.cluster_index(sequence) if sequence is None: raise ValueError("Variable provided is not in our cluster") - + if (sequence in xrange(n)) or (sequence in IE): seqq = [sequence] else: seqq = sequence - + if isinstance(seqq, tuple): @@ -2336,7 +2336,7 @@ def mutate(self, sequence, inplace=True): #raise ValueError('The quiver cannot be mutated at the vertex ' + str( v )) seq = iter(seqq) - + for k in seq: if k in xrange(n): @@ -2378,21 +2378,21 @@ def mutate(self, sequence, inplace=True): if not inplace: return seed - + def cluster_index(self, cluster_str): r""" Returns the index of a cluster if use_fpolys is on INPUT: - + - ``cluster_str`` -- The string to look for in the cluster - + OUTPUT: - + Returns an integer or None if the string is not a cluster variable - + EXAMPLES:: - + sage: S = ClusterSeed(['A',4],user_labels=['x','y','z','w']); S.mutate('x') sage: S.cluster_index('x') sage: S.cluster_index('(y+1)/x') @@ -2404,7 +2404,7 @@ def cluster_index(self, cluster_str): cluster_str = ClusterVariable( FractionField(self._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable',xdim=self._n ) if cluster_str in self.cluster(): return self.cluster().index(cluster_str) - + return None def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2,return_output='seed'): @@ -2721,7 +2721,7 @@ def exchangeable_part(self): from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part eval_dict = dict( [ ( self.y(i), 1 ) for i in xrange(self._m) ] ) - seed = ClusterSeed( _principal_part( self._M ), is_principal = True, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) + seed = ClusterSeed( _principal_part( self._M ), is_principal = True, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) seed.use_c_vectors(self._use_c_vec) seed.use_fpolys(self._use_fpolys) seed.use_g_vectors(self._use_g_vec) @@ -2813,7 +2813,7 @@ def universal_extension(self): for alpha in almost_positive_coroots]) M = self._M.stack(C) - seed = ClusterSeed(M, is_principal = False, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) + seed = ClusterSeed(M, is_principal = False, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) seed.use_c_vectors(self._use_c_vec) seed.use_fpolys(self._use_fpolys) seed.use_g_vectors(self._use_g_vec) @@ -2847,7 +2847,7 @@ def principal_extension(self): [ 0 0 1 0 0] [ 0 0 0 1 0] [ 0 0 0 0 1] - + sage: S = ClusterSeed(['A',4],user_labels=['a','b','c','d']) sage: T= S.principal_extension() sage: T.cluster() @@ -2871,7 +2871,7 @@ def principal_extension(self): self._user_labels = self._user_labels + ['y%s'%i for i in xrange(self._n)] elif isinstance(self._user_labels,dict): self._user_labels.update( {(i+self._n):'y%s'%i for i in xrange(self._n)} ) - seed = ClusterSeed(M, is_principal = is_principal, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) + seed = ClusterSeed(M, is_principal = is_principal, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) seed.use_c_vectors(self._use_c_vec) seed.use_fpolys(self._use_fpolys) seed.use_g_vectors(self._use_g_vec) @@ -2949,7 +2949,7 @@ def set_cluster( self, cluster, force=False ): sage: S.set_cluster(cluster2, force=True) sage: S.cluster() [x0, (x1 + 1)/x2, (x0*x2 + x1 + 1)/(x1*x2)] - + sage: S = ClusterSeed(['A',3]); S.use_fpolys(False) sage: S.set_cluster([1,1,1]) Warning: clusters not being tracked so this command is ignored. @@ -2966,7 +2966,7 @@ def set_cluster( self, cluster, force=False ): self._cluster = [ FractionField(self._R)(x) for x in cluster ][0:self._n] self._is_principal = None else: - print("Warning: clusters not being tracked so this command is ignored.") + print("Warning: clusters not being tracked so this command is ignored.") def reset_cluster( self ): r""" @@ -2993,12 +2993,12 @@ def reset_cluster( self ): sage: T.reset_cluster() sage: T.cluster() [x0, x1, x2] - + sage: S = ClusterSeed(['B',3],user_labels=[[1,2],[2,3],[3,4]],user_labels_prefix='p') sage: S.mutate([0,1]) sage: S.cluster() [(p_2_3 + 1)/p_1_2, (p_1_2*p_3_4^2 + p_2_3 + 1)/(p_1_2*p_2_3), p_3_4] - + sage: S.reset_cluster() sage: S.cluster() [p_1_2, p_2_3, p_3_4] @@ -3015,7 +3015,7 @@ def reset_cluster( self ): self._F = dict([(i,self._U(1)) for i in self._init_exch.values()]) if self._use_fpolys: self.set_cluster(self._R.gens(), force=True) - + def reset_coefficients( self ): r""" Resets the coefficients of ``self`` to the frozen variables but keeps the current cluster. @@ -3732,7 +3732,7 @@ def variable_class(self, depth=infinity, ignore_bipartite_belt=False): var_iter = self.variable_class_iter( depth=depth, ignore_bipartite_belt=ignore_bipartite_belt ) return sorted(var_iter) - def is_finite( self ): + def is_finite(self): r""" Returns True if ``self`` is of finite type. @@ -4164,9 +4164,9 @@ def get_green_vertices(C): INPUT: - ``C`` -- The C matrix to check - + EXAMPLES:: - + sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import get_green_vertices sage: S = ClusterSeed(['A',4]); S.mutate([1,2,3,2,0,1,2,0,3]) sage: get_green_vertices(S.c_matrix()) @@ -4284,4 +4284,3 @@ def almost_positive_root( self ): return sum( [ root[i]*Phiplus[ i+1 ] for i in range(self._n) ] ) else: raise ValueError('The cluster algebra for %s is not of finite type.'%self._repr_()) - From fe2e01fd1061c8675215050bcc120dd93dd83a5e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 12 Oct 2015 15:29:03 -0500 Subject: [PATCH 1417/1872] Fixed cluster seed not expicitly specifying an indexing set. --- src/sage/combinat/cluster_algebra_quiver/cluster_seed.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index d019d916ccf..1d59224cbdd 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -2803,7 +2803,8 @@ def universal_extension(self): A = 2 - self.b_matrix().apply_map(abs).transpose() - rs = CartanMatrix(A).root_space() + # We give the indexing set of the Cartan matrix to be [1, 2, ..., n] + rs = CartanMatrix(A, index_set=range(1,A.ncols()+1)).root_space() almost_positive_coroots = rs.almost_positive_roots() sign = [-1 if all(x <= 0 for x in self.b_matrix()[i]) else 1 From 12d4cc771196f0ee301198a6ee89485a4faafb98 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 12 Oct 2015 13:39:57 -0700 Subject: [PATCH 1418/1872] trac 6102: fix typo "left" -> "right" --- src/sage/homology/homology_vector_space_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index be28d181896..d52cd7b16ff 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -423,7 +423,7 @@ def cup_product(self, other): idx = right_cell[1][0] right_cell = (idx, scomplex.n_cells(i-1)[idx]) left = scomplex.n_chains(deg_left, base_ring)(left_cell) - right = scomplex.n_chains(deg_left, base_ring)(right_cell) + right = scomplex.n_chains(deg_right, base_ring)(right_cell) gamma_coeff += coeff * self.to_cycle().eval(left) * other.to_cycle().eval(right) result.append((gamma.leading_support(), gamma_coeff)) return scomplex.cohomology_with_basis(deg_tot, base_ring).sum_of_terms(result) From aa444d2681187c178d9eca7c410468056a14bb3d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 12 Oct 2015 17:18:39 -0500 Subject: [PATCH 1419/1872] Fixing doctests, trying to improve compatibility, and some changes. --- .../lie/weyl_character_ring.rst | 12 ++--- .../tutorial-objects-and-classes.rst | 2 +- src/sage/categories/category_types.py | 6 +-- .../finite_dimensional_modules_with_basis.py | 22 +++++++- src/sage/categories/modules_with_basis.py | 33 +++++++++--- src/sage/combinat/ncsf_qsym/tutorial.py | 4 +- .../hyperplane_arrangement/arrangement.py | 4 +- src/sage/geometry/linear_expression.py | 53 +++++++++++++++++-- .../book_schilling_zabrocki_kschur_primer.py | 2 +- 9 files changed, 111 insertions(+), 27 deletions(-) diff --git a/src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst b/src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst index 3caeb368547..af5ed9821dd 100644 --- a/src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst +++ b/src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst @@ -164,13 +164,13 @@ coefficients) through the usual free module accessors:: [((0, 0, 0), 1), ((1, 0, 0), 1), ((1, 1, 0), 1), ((1, 1, 1), 1)] sage: pprint(dict(chi)) {(0, 0, 0): 1, (1, 0, 0): 1, (1, 1, 0): 1, (1, 1, 1): 1} - sage: chi.monomials() + sage: M = sorted(chi.monomials(), key=lambda x: x.support()); M [B3(0,0,0), B3(1,0,0), B3(1,1,0), B3(1,1,1)] - sage: chi.support() + sage: sorted(chi.support()) [(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1)] sage: chi.coefficients() [1, 1, 1, 1] - sage: [r.degree() for r in chi.monomials()] + sage: [r.degree() for r in M] [1, 7, 21, 35] sage: sum(r.degree() for r in chi.monomials()) 64 @@ -484,10 +484,10 @@ itself, that is, the integral of `|tr(g)|^{10}`:: sage: tr^5 5*A2(2,2,1) + 6*A2(3,1,1) + 5*A2(3,2,0) + 4*A2(4,1,0) + A2(5,0,0) - sage: (tr^5).monomials() + sage: sorted((tr^5).monomials(), key=lambda x: x.support()) [A2(2,2,1), A2(3,1,1), A2(3,2,0), A2(4,1,0), A2(5,0,0)] - sage: (tr^5).coefficients() - [5, 6, 5, 4, 1] + sage: sorted((tr^5).coefficients()) + [1, 4, 5, 5, 6] sage: sum(x^2 for x in (tr^5).coefficients()) 103 diff --git a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst index 388d7d1d473..118e03c69c2 100644 --- a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst +++ b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst @@ -246,7 +246,7 @@ As an element of a vector space, ``el`` has a particular behavior:: sage: 2*el 2*B[[1, 2, 3]] + 6*B[[1, 3, 2]] + B[[3, 2, 1]] - sage: el.support() + sage: sorted(el.support()) [[1, 2, 3], [1, 3, 2], [3, 2, 1]] sage: el.coefficient([1, 2, 3]) 1 diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index 435e6a5f980..ea52ddb7e1e 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -566,11 +566,11 @@ def super_categories(self): EXAMPLES:: sage: ChainComplexes(Integers(9)).super_categories() - [Category of modules with basis over Ring of integers modulo 9] + [Category of modules over Ring of integers modulo 9] """ - from sage.categories.all import Fields, FreeModules, VectorSpaces + from sage.categories.all import Fields, Modules, VectorSpaces base_ring = self.base_ring() if base_ring in Fields(): return [VectorSpaces(base_ring)] - return [FreeModules(base_ring)] + return [Modules(base_ring)] diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 9a3264a4bc6..4b95ab77142 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -265,7 +265,27 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate return QuotientModuleWithBasis(submodule, category=category) class ElementMethods: - pass + def dense_coefficient_list(self, order=None): + """ + Return a list of *all* coefficients of ``self``. + + INPUT: + + - ``order`` -- (optional) an ordering of the basis indexing set + + EXAMPLES:: + + sage: v = vector([0, -1, -2]) + sage: v.dense_coefficient_list() + [0, -1, -2] + sage: v.dense_coefficient_list([2,1,0]) + [-2, -1, 0] + sage: sorted(v.coefficients()) + [-2, -1] + """ + if order is None: + order = sorted(self.basis().keys()) + return [self[i] for i in order] class MorphismMethods: def matrix(self, base_ring=None, side="left"): diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 7d8c9f52416..b0f3e89d8a0 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1190,7 +1190,8 @@ def length(self): def support(self): """ Return a list of the combinatorial objects indexing the basis - elements of self which non-zero coefficients. + elements of ``self`` which non-zero coefficients (in an + arbitrary order). EXAMPLES:: @@ -1213,6 +1214,9 @@ def support(self): def monomials(self): """ + Return a list of the monomials of ``self`` (in an arbitrary + order). + EXAMPLES:: sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) @@ -1230,7 +1234,7 @@ def monomials(self): def terms(self): """ - Return a list of the terms of ``self``. + Return a list of the terms of ``self`` (in an arbitrary order). .. SEEALSO:: :meth:`monomials` @@ -1248,10 +1252,19 @@ def terms(self): for key, value in self.monomial_coefficients(copy=False).iteritems() if value != zero] - def coefficients(self): + def coefficients(self, sort=True): """ - Return a list of the coefficients appearing on the basis - elements in ``self``. + Return a list of the (non-zero) coefficients appearing on + the basis elements in ``self`` (in an arbitrary order). + + INPUT: + + - ``sort`` -- (default: ``True``) to sort the coefficients + based upon the default ordering of the indexing set + + .. SEEALSO:: + + :meth:`~sage.categories.finite_dimensional_modules_with_basis.FiniteDimensionalModulesWithBasis.ElementMethods.dense_coefficient_list` EXAMPLES:: @@ -1269,9 +1282,13 @@ def coefficients(self): [1, 1, 1, 1] """ zero = self.parent().base_ring().zero() - return [value for key, value in - self.monomial_coefficients(copy=False).iteritems() - if value != zero] + mc = self.monomial_coefficients(copy=False) + if not sort: + return [value for key, value in mc.iteritems() if value != zero] + + v = sorted([(key, value) for key, value in mc.iteritems() + if value != zero]) + return [value for key, value in v] def support_of_term(self): """ diff --git a/src/sage/combinat/ncsf_qsym/tutorial.py b/src/sage/combinat/ncsf_qsym/tutorial.py index 4a20abdd1df..5cf429b0d17 100644 --- a/src/sage/combinat/ncsf_qsym/tutorial.py +++ b/src/sage/combinat/ncsf_qsym/tutorial.py @@ -92,8 +92,8 @@ sage: y.expand(4) x0*x1^2*x2 + x0*x1^2*x3 + x0*x2^2*x3 + x1*x2^2*x3 -The usual methods on free modules are available such as coefficients, degrees, -and the support:: +The usual methods on free modules are available such as coefficients, +degrees, and the support:: sage: z=3*M[1,2]+M[3]^2; z 3*M[1, 2] + 2*M[3, 3] + M[6] diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 2e7b4c8391d..10d654310fc 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -1418,7 +1418,7 @@ def _make_region(self, hyperplanes): sage: h._make_region([x, 1-x, y, 1-y]) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices """ - ieqs = [h.coefficients() for h in hyperplanes] + ieqs = [h.dense_coefficient_list() for h in hyperplanes] from sage.geometry.polyhedron.constructor import Polyhedron return Polyhedron(ieqs=ieqs, ambient_dim=self.dimension(), base_ring=self.parent().base_ring()) @@ -1468,7 +1468,7 @@ def regions(self): universe = Polyhedron(eqns=[[0] + [0] * dim], base_ring=R) regions = [universe] for hyperplane in self: - ieq = vector(R, hyperplane.coefficients()) + ieq = vector(R, hyperplane.dense_coefficient_list()) pos_half = Polyhedron(ieqs=[ ieq], base_ring=R) neg_half = Polyhedron(ieqs=[-ieq], base_ring=R) subdivided = [] diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index 93e7d05cf4f..dda5b5d1389 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -161,6 +161,31 @@ def coefficients(self): """ return [self._const] + list(self._coeffs) + dense_coefficient_list = coefficients + + def monomial_coefficients(self, copy=True): + """ + Return a dictionary whose keys are indices of basis in + the support of ``self`` and whose values are the corresponding + coefficients. + + INPUT: + + - ``copy`` -- ignored + + EXAMPLES:: + + sage: from sage.geometry.linear_expression import LinearExpressionModule + sage: L. = LinearExpressionModule(QQ) + sage: linear = L([1, 2, 3], 4) + sage: linear.monomial_coefficients() + {0: 1, 1: 2, 2: 3, 'b': 4} + """ + zero = self.parent().base_ring().zero() + d = {i: v for i,v in enumerate(self._coeffs) if v != zero} + d['b'] = self._const + return d + def _repr_vector(self, variable='x'): """ Return a string representation. @@ -458,9 +483,31 @@ def __init__(self, base_ring, names=tuple()): sage: TestSuite(L).run() """ from sage.categories.modules import Modules - super(LinearExpressionModule, self).__init__(base_ring, category=Modules(base_ring)) + super(LinearExpressionModule, self).__init__(base_ring, category=Modules(base_ring).WithBasis().FiniteDimensional()) self._names = names - + + @cached_method + def basis(self): + """ + Return a basis of ``self``. + + EXAMPLES:: + + sage: from sage.geometry.linear_expression import LinearExpressionModule + sage: L = LinearExpressionModule(QQ, ('x', 'y', 'z')) + sage: list(L.basis()) + [x + 0*y + 0*z + 0, + 0*x + y + 0*z + 0, + 0*x + 0*y + z + 0, + 0*x + 0*y + 0*z + 1] + """ + from sage.sets.family import Family + gens = self.gens() + d = {i: g for i,g in enumerate(gens)} + d['b'] = self.element_class(self, self.ambient_module().zero(), + self.base_ring().one()) + return Family(range(len(gens)) + ['b'], lambda i: d[i]) + @cached_method def ngens(self): """ @@ -576,7 +623,7 @@ def _element_constructor_(self, arg0, arg1=None): else: # Construct from list/tuple/iterable:: try: - arg0 = arg0.coefficients() + arg0 = arg0.dense_coefficient_list() except AttributeError: arg0 = list(arg0) const = arg0[0] diff --git a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py index 116e4a37784..15581a2cd6e 100644 --- a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py +++ b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py @@ -475,7 +475,7 @@ Sage example in ./kschurnotes/notes-mike-anne.tex, line 2810:: sage: c = Partition([3,2,1]).to_core(3) - sage: for p in f.support(): + sage: for p in sorted(f.support()): # Sorted for consistant doctest ordering ....: print p, SkewPartition([p.to_core(3).to_partition(),c.to_partition()]) ....: [3, 1, 1, 1, 1] [[5, 2, 1, 1, 1], [5, 2, 1]] From 954e3542ccc00ef3cc294f19019da3608d87a5a8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 12 Oct 2015 17:34:12 -0500 Subject: [PATCH 1420/1872] Added a test Darij requested. --- src/sage/categories/modules_with_basis.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index b0f3e89d8a0..8c795a3e648 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1017,7 +1017,7 @@ class ElementMethods: # return self._lmul_(-self.parent().base_ring().one(), self) @abstract_method - def monomial_coefficients(copy=True): + def monomial_coefficients(self, copy=True): """ Return a dictionary whose keys are indices of basis in the support of ``self`` and whose values are the corresponding @@ -1040,6 +1040,18 @@ def monomial_coefficients(copy=True): 1 sage: d['c'] 3 + + TESTS: + + We check that we make a copy of the coefficient dictonary:: + + sage: F = CombinatorialFreeModule(ZZ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] + 3*B['c'] + sage: d = f.monomial_coefficients() + sage: d['a'] = 5 + sage: f + B['a'] + 3*B['c'] """ def __getitem__(self, m): From e659186e20bbb4b4a942008dff32901659e42503 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 12 Oct 2015 17:46:39 -0500 Subject: [PATCH 1421/1872] Some pyflakes cleanup. --- src/sage/combinat/root_system/cartan_type.py | 1 - src/sage/combinat/root_system/coxeter_group.py | 1 - src/sage/combinat/root_system/coxeter_matrix.py | 8 -------- src/sage/combinat/root_system/coxeter_type.py | 1 - 4 files changed, 11 deletions(-) diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index d3e8c14cfa0..17fbc7cd24c 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -452,7 +452,6 @@ from sage.structure.global_options import GlobalOptions from sage.sets.family import Family from sage.misc.decorators import rename_keyword -from sage.misc.misc import union from __builtin__ import sorted # TODO: diff --git a/src/sage/combinat/root_system/coxeter_group.py b/src/sage/combinat/root_system/coxeter_group.py index 015f2c1abcb..b1d4aa5b2a6 100644 --- a/src/sage/combinat/root_system/coxeter_group.py +++ b/src/sage/combinat/root_system/coxeter_group.py @@ -16,7 +16,6 @@ from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.combinat.root_system.weyl_group import WeylGroup from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.combinat.root_system.cartan_type import CartanType from sage.groups.perm_gps.permgroup import PermutationGroup_generic diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 1ae4343a51b..856fbb17e00 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -18,22 +18,16 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.matrix.constructor import matrix -from sage.matrix.matrix import is_Matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall -from sage.matrix.matrix_integer_dense import Matrix_integer_dense from sage.matrix.matrix_generic_dense import Matrix_generic_dense from sage.graphs.graph import Graph -from sage.graphs.generators.basic import CycleGraph from sage.rings.all import ZZ, QQ, RR from sage.rings.infinity import infinity from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.coxeter_type import CoxeterType -from sage.combinat.root_system.root_system import RootSystem -from sage.sets.family import Family class CoxeterMatrix(CoxeterType): r""" @@ -1184,8 +1178,6 @@ def coxeter_matrix_as_function(t): """ t = CartanType(t) m = t.coxeter_matrix() - index_set = t.index_set() - reverse = dict((index_set[i], i) for i in range(len(index_set))) return lambda i, j: m[i, j] def coxeter_matrix(t): diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 37fe46d679f..ecbd5ab6a20 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -22,7 +22,6 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.combinat.root_system.cartan_type import CartanType from sage.matrix.all import MatrixSpace -from sage.rings.all import ZZ, QQ from sage.symbolic.ring import SR from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject From aab25331837e1e0a3cf8b2d9c793fbb7c905b9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Thu, 8 Oct 2015 10:53:10 +1300 Subject: [PATCH 1422/1872] First batch of fix for "El Capitan" --- build/pkgs/cliquer/spkg-install | 2 +- build/pkgs/conway_polynomials/spkg-install | 2 +- build/pkgs/git/spkg-install | 9 +++------ build/pkgs/r/spkg-install | 17 ++++++++++------- build/pkgs/singular/spkg-install | 5 +++++ build/pkgs/zn_poly/spkg-install | 1 + 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/build/pkgs/cliquer/spkg-install b/build/pkgs/cliquer/spkg-install index 4e7d6a5c5a8..87f23bb59c7 100755 --- a/build/pkgs/cliquer/spkg-install +++ b/build/pkgs/cliquer/spkg-install @@ -24,7 +24,6 @@ fi # Flags for building a dynamically linked shared object. if [ "$UNAME" = "Darwin" ]; then - export MACOSX_DEPLOYMENT_TARGET="10.3" SAGESOFLAGS="-dynamiclib -single_module -flat_namespace -undefined dynamic_lookup" elif [ "$UNAME" = "SunOS" ]; then SAGESOFLAGS="-shared -Wl,-h,libcliquer.so -Wl,-ztext" @@ -63,6 +62,7 @@ cp *.h "$SAGE_LOCAL/include/cliquer/" if [ "$UNAME" = "Darwin" ]; then cp -f libcliquer.so "$SAGE_LOCAL/lib/libcliquer.dylib" + install_name_tool -id "${SAGE_LOCAL}"/lib/libcliquer.dylib "${SAGE_LOCAL}"/lib/libcliquer.dylib elif [ "$UNAME" = "CYGWIN" ]; then cp -f libcliquer.so "$SAGE_LOCAL/lib/libcliquer.dll" fi diff --git a/build/pkgs/conway_polynomials/spkg-install b/build/pkgs/conway_polynomials/spkg-install index 0023233e122..441dc8e8381 100755 --- a/build/pkgs/conway_polynomials/spkg-install +++ b/build/pkgs/conway_polynomials/spkg-install @@ -1,7 +1,7 @@ #!/usr/bin/env python import os -from sage.all import save +from sage.structure.sage_object import save from sage.env import SAGE_SHARE install_root = os.path.join(SAGE_SHARE, 'conway_polynomials') diff --git a/build/pkgs/git/spkg-install b/build/pkgs/git/spkg-install index 6331ae29f5f..f9ba3204f16 100755 --- a/build/pkgs/git/spkg-install +++ b/build/pkgs/git/spkg-install @@ -49,13 +49,10 @@ done export NO_FINK=1 export NO_DARWIN_PORTS=1 -# Darwin 8 (Tiger) does not support common crypto -if { uname -sr | grep 'Darwin 8' ;} &>/dev/null; then - export NO_APPLE_COMMON_CRYPTO=1 -fi - # OSX Git with FSF GCC is broken, disable completely for now. See #17091 -export NO_APPLE_COMMON_CRYPTO=1 +if [ "$UNAME" = "Darwin" ]; then + export NO_OPENSSL=1 +fi # First make GIT-VERSION-FILE (we patched Makefile such that configure # no longer depends on this, so it's safer to explicitly build this). diff --git a/build/pkgs/r/spkg-install b/build/pkgs/r/spkg-install index 0e5f4f2c2a6..7f54d504e5d 100755 --- a/build/pkgs/r/spkg-install +++ b/build/pkgs/r/spkg-install @@ -82,15 +82,18 @@ fi if [ "$UNAME" = "Darwin" ]; then # We don't want to install R as a library framework on OSX R_CONFIGURE="--enable-R-framework=no $R_CONFIGURE" + # OS X 10.10 and/or Xcode 6.3 and over broke the R installation. See + # http://trac.sagemath.org/ticket/18254. + if { uname -r | grep '14\.' ;} &>/dev/null; then + echo "OS X 10.10: Configuring R without aqua support." + R_CONFIGURE="--with-aqua=no $R_CONFIGURE" + fi + if { uname -r | grep '15\.' ;} &>/dev/null; then + echo "OS X 10.11: Configuring R without aqua support." + R_CONFIGURE="--with-aqua=no $R_CONFIGURE" + fi 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 diff --git a/build/pkgs/singular/spkg-install b/build/pkgs/singular/spkg-install index d8ff399a465..4d7f0c318be 100755 --- a/build/pkgs/singular/spkg-install +++ b/build/pkgs/singular/spkg-install @@ -218,6 +218,11 @@ build_libsingular() return 1 fi + if [ "$UNAME" = "Darwin" ]; then + # on darwin we need to adjust the install name of the library + install_name_tool -id "${SAGE_LOCAL}"/lib/libsingular.dylib "${SAGE_LOCAL}"/lib/libsingular.dylib + fi + # singular does not install this header cp Singular/sing_dbm.h $SAGE_LOCAL/include/singular/ diff --git a/build/pkgs/zn_poly/spkg-install b/build/pkgs/zn_poly/spkg-install index 00067eab437..25161e48a1c 100755 --- a/build/pkgs/zn_poly/spkg-install +++ b/build/pkgs/zn_poly/spkg-install @@ -192,6 +192,7 @@ else echo >&2 "Error copying 'libzn_poly.dylib'." exit 1 fi + install_name_tool -id ${SAGE_LOCAL}/lib/libzn_poly.dylib "${SAGE_LOCAL}"/lib/libzn_poly.dylib fi ############################################################################### From 5b767551cce8561c26168ff216f7bcc82ff36eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Thu, 8 Oct 2015 12:18:24 +1300 Subject: [PATCH 1423/1872] Fix basic install_name problems in R - inspired by Gentoo prefix. --- build/pkgs/r/spkg-install | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/pkgs/r/spkg-install b/build/pkgs/r/spkg-install index 7f54d504e5d..f2ac97519ca 100755 --- a/build/pkgs/r/spkg-install +++ b/build/pkgs/r/spkg-install @@ -129,6 +129,12 @@ for patch in ../patches/*.patch; do fi done +if [ "$UNAME" = "Darwin" ]; then + # Fixing install_name(s) + sed -i -e 's:\"-install_name :\"-install_name ${libdir}/R/lib/:' configure + sed -i -e "/SHLIB_EXT/s/\.so/.dylib/" configure +fi + # Don't override R_HOME_DIR in local/bin/R while building R. # See patches/R.sh.patch export SAGE_BUILDING_R=yes From d3f5e995393794d56bc73bd05faebfaa784a2afe Mon Sep 17 00:00:00 2001 From: "R. Andrew Ohana" Date: Mon, 12 Oct 2015 18:16:29 -0700 Subject: [PATCH 1424/1872] more fixes for OSX 10.11 --- build/pkgs/lcalc/spkg-install | 5 +++++ build/pkgs/r/spkg-install | 8 ++------ src/bin/sage-env | 11 ++++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/build/pkgs/lcalc/spkg-install b/build/pkgs/lcalc/spkg-install index d1ff0c5c5e4..50bd1f97752 100755 --- a/build/pkgs/lcalc/spkg-install +++ b/build/pkgs/lcalc/spkg-install @@ -78,4 +78,9 @@ success "$MAKE" echo "Now installing lcalc binary, library and header files..." rm -fr "$SAGE_LOCAL"/include/libLfunction $MAKE install + +if [ "$UNAME" = "Darwin" ]; then + install_name_tool -id ${SAGE_LOCAL}/lib/libLfunction.dylib "${SAGE_LOCAL}"/lib/libLfunction.dylib +fi + success "$MAKE install" diff --git a/build/pkgs/r/spkg-install b/build/pkgs/r/spkg-install index f2ac97519ca..679d39e1b82 100755 --- a/build/pkgs/r/spkg-install +++ b/build/pkgs/r/spkg-install @@ -84,14 +84,10 @@ if [ "$UNAME" = "Darwin" ]; then R_CONFIGURE="--enable-R-framework=no $R_CONFIGURE" # OS X 10.10 and/or Xcode 6.3 and over broke the R installation. See # http://trac.sagemath.org/ticket/18254. - if { uname -r | grep '14\.' ;} &>/dev/null; then - echo "OS X 10.10: Configuring R without aqua support." + if [ $MACOSX_VERSION -ge 14 ]; then + echo "OS X 10.$[$MACOSX_VERSION-4] Configuring R without aqua support." R_CONFIGURE="--with-aqua=no $R_CONFIGURE" fi - if { uname -r | grep '15\.' ;} &>/dev/null; then - echo "OS X 10.11: Configuring R without aqua support." - R_CONFIGURE="--with-aqua=no $R_CONFIGURE" - fi fi if [ "$UNAME" = "CYGWIN" ]; then diff --git a/src/bin/sage-env b/src/bin/sage-env index 53246b12513..cac4860c415 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -279,13 +279,14 @@ if [ "$UNAME" = "Darwin" ]; then # cause lots of random "Abort trap" issues on OSX. see trac # #7095 for an example. MACOSX_VERSION=`uname -r | awk -F. '{print $1}'` - MACOSX_DEPLOYMENT_TARGET=10.$[$MACOSX_VERSION-4] - if [ $MACOSX_DEPLOYMENT_TARGET = '10.10' ]; then - # Workaround for the libtool version detection bug - # See http://trac.sagemath.org/ticket/17204 + if [ $MACOSX_VERSION -ge 14 ]; then + # various packages have still have issues with + # two digit OS X versions MACOSX_DEPLOYMENT_TARGET=10.9 + else + MACOSX_DEPLOYMENT_TARGET=10.$[$MACOSX_VERSION-4] fi - export MACOSX_DEPLOYMENT_TARGET + export MACOSX_DEPLOYMENT_TARGET MACOSX_VERSION fi # Compile-time path for libraries. This is the equivalent of From d9f2c454bab76af892452cfefbf4b62790feb6c5 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Tue, 13 Oct 2015 08:27:18 +0200 Subject: [PATCH 1425/1872] 17624: fix previous commit --- src/sage/symbolic/ring.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 3891da5f05f..061951f8571 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -254,14 +254,14 @@ cdef class SymbolicRing(CommutativeRing): Polynomial ring element factorizations:: sage: R. = QQ[] - sage: SR(factor(x^2 - 1)) - (x + 1)*(x - 1) + sage: SR(factor(5*x^2 - 5)) + 5*(x + 1)*(x - 1) sage: R. = QQ[] sage: SR(factor(x^2 - y^2)) (x + y)*(x - y) sage: R. = QQ[] sage: SR(factor(x^2*y^3 + x^2*y^2*z - x*y^3 - x*y^2*z - 2*x*y*z - 2*x*z^2 + 2*y*z + 2*z^2)) - -(x*y^2 - 2*z)*(x - 1)*(y + z) + (x*y^2 - 2*z)*(x - 1)*(y + z) """ cdef GEx exp @@ -299,7 +299,7 @@ cdef class SymbolicRing(CommutativeRing): GEx_construct_pyobject(exp, x) elif isinstance(x, Factorization): from sage.misc.all import prod - return prod([SR(p)**e for p,e in x], SR.one()) + return prod([SR(p)**e for p,e in x], SR.one()) * x.unit() else: raise TypeError From 6aa870d6da2da8ab73fbfe31d7e01a59a6eede04 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 13 Oct 2015 11:27:20 +0200 Subject: [PATCH 1426/1872] typo in doc --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 7a817bd64f3..ec5331e494b 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1350,7 +1350,7 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): Normalizes the input in order to ensure a unique representation. - For more information see :class:`MonomialGrowthGroup`. + For more information see :class:`GenericGrowthGroup`. TESTS:: From 40fa7f9e28a0de0f7c940182bf4da8b03c425129 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 13 Oct 2015 11:27:53 +0200 Subject: [PATCH 1427/1872] new method to determine category --- src/sage/rings/asymptotic/growth_group.py | 142 +++++++++++++++++++++- 1 file changed, 139 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ec5331e494b..7696adc2298 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1382,13 +1382,53 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): elif not isinstance(var, Variable): var = Variable(var, ignore=ignore_variables) + category = cls._determine_category_(category, base) + + return super(GenericGrowthGroup, cls).__classcall__( + cls, base, var, category) + + if category is None: from sage.categories.monoids import Monoids from sage.categories.posets import Posets - category = Monoids() & Posets() - return super(GenericGrowthGroup, cls).__classcall__( - cls, base, var, category) + + @staticmethod + def _determine_category_(category, base): + r""" + Return the category of this generic growth group. + + INPUT: + + - ``category`` -- a category or ``None``. + + - ``base`` -- the parent. + + OUTPUT: + + A category. + + .. NOTE:: + + If the input category is not ``None``, then this category + is returned. Otherwise the join category of monoids and posets + is returned. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: GenericGrowthGroup(ZZ, 'x').category() + Join of Category of monoids and Category of posets + sage: GenericGrowthGroup(ZZ, 'x', category=Groups()).category() + Category of groups + """ + if category is not None: + return category + + from sage.categories.monoids import Monoids + from sage.categories.posets import Posets + + return Monoids() & Posets() @sage.misc.superseded.experimental(trac_number=17601) @@ -2598,6 +2638,52 @@ class MonomialGrowthGroup(GenericGrowthGroup): Element = MonomialGrowthElement + @staticmethod + def _determine_category_(category, base): + r""" + Return the category of this monomial growth group. + + INPUT: + + - ``category`` -- a category or ``None``. + + - ``base`` -- the parent. + + OUTPUT: + + A category. + + .. NOTE:: + + If the input category is not ``None``, then this category + is returned. Otherwise the category is determined from + the given base. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup + sage: MonomialGrowthGroup(ZZ, 'x').category() + Join of Category of groups and Category of posets + sage: MonomialGrowthGroup(ZZ, 'x', category=Monoids()).category() + Category of monoids + """ + if category is not None: + return category + + from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups + from sage.categories.groups import Groups + from sage.categories.monoids import Monoids + from sage.categories.posets import Posets + + C = base.category() + if C.is_subcategory(CommutativeAdditiveGroups()): + category = Groups() + else: + category = Monoids() + + return category & Posets() + + def _repr_short_(self): r""" A short representation string of this monomial growth group. @@ -3182,6 +3268,56 @@ class ExponentialGrowthGroup(GenericGrowthGroup): Element = ExponentialGrowthElement + @staticmethod + def _determine_category_(category, base): + r""" + Return the category of this exponential growth group. + + INPUT: + + - ``category`` -- a category or ``None``. + + - ``base`` -- the parent. + + OUTPUT: + + A category. + + .. NOTE:: + + If the input category is not ``None``, then this category + is returned. Otherwise the category is determined from + the given base. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup + sage: ExponentialGrowthGroup(ZZ, 'x').category() + Join of Category of monoids and Category of posets + sage: ExponentialGrowthGroup(QQ, 'x').category() + Join of Category of groups and Category of posets + sage: ExponentialGrowthGroup(ZZ, 'x', category=Groups()).category() + Category of groups + sage: ExponentialGrowthGroup(QQ, 'x', category=Monoids()).category() + Category of monoids + """ + if category is not None: + return category + + from sage.categories.fields import Fields + from sage.categories.groups import Groups + from sage.categories.monoids import Monoids + from sage.categories.posets import Posets + + C = base.category() + if C.is_subcategory(Fields()) or C.is_subcategory(Groups()): + category = Groups() + else: + category = Monoids() + + return category & Posets() + + def _repr_short_(self): r""" A short representation string of this exponential growth group. From df32478963285bc44239297a825f606a3e288001 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 13 Oct 2015 11:28:06 +0200 Subject: [PATCH 1428/1872] correct _coerce_map_from_ --- src/sage/rings/asymptotic/growth_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 7696adc2298..6df9fc0fd5f 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1912,7 +1912,8 @@ def _coerce_map_from_(self, S): sage: GrowthGroup('x^QQ').has_coerce_map_from(GrowthGroup('QQ^x')) # indirect doctest False """ - if isinstance(S, type(self)) and self._var_ == S._var_: + from misc import underlying_class + if isinstance(S, underlying_class(self)) and self._var_ == S._var_: if self.base().has_coerce_map_from(S.base()): return True From 9293e442d18eaf107423830579cbf7a761ccd00d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 13 Oct 2015 11:29:05 +0200 Subject: [PATCH 1429/1872] add more output to a failing doctest This can be reverted once the bug is fixed (fix is somewhere else; doctest it there) --- src/sage/rings/asymptotic/growth_group_cartesian.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index d316f47d7ac..381c5afe26e 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -72,8 +72,11 @@ sage: cm.common_parent(A, D) Growth Group QQ^x * x^QQ sage: E = GrowthGroup('ZZ^x * x^QQ') + sage: cm.record_exceptions() sage: cm.common_parent(A, E) Growth Group QQ^x * x^QQ + sage: for t in cm.exception_stack(): + ....: print t :: From 43ec64071da5ff5e5f5f700fe61b53f8fa11330e Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 13 Oct 2015 12:40:48 +0200 Subject: [PATCH 1430/1872] Added a check in unencode to raise an appropriate exception if a code of dimension 0 is used --- src/sage/coding/encoder.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 6569ba13c11..556810e9a7b 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -176,7 +176,21 @@ def unencode(self, c, nocheck=False): Traceback (most recent call last): ... EncodingError: Given word is not in the code + + If ones tries to unencode "a" codeword of a code of dimension 0, it + returns an error:: + + sage: G = Matrix(GF(17), []) + sage: C = LinearCode(G) + sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) + sage: c = C.random_element() + sage: E.unencode(c) + Traceback (most recent call last): + ... + EncodingError: Impossible to unencode a word of a code of dimension 0 """ + if self.code().ambient_space().dimension() == 0: + raise EncodingError("Impossible to unencode a word of a code of dimension 0") if nocheck == False and c not in self.code(): raise EncodingError("Given word is not in the code") return self.unencode_nocheck(c) From 72044d263ced7e8db3b7355c6f25e749635b1c56 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 13 Oct 2015 13:35:11 +0200 Subject: [PATCH 1431/1872] Implement powering for complex intervals --- src/sage/rings/complex_interval.pyx | 102 +++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 2fc79377f4a..d59017017e4 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -40,22 +40,19 @@ heavily modified: #***************************************************************************** -import math -import operator - include "sage/ext/interrupt.pxi" +from cpython.number cimport PyNumber_Index from sage.structure.element cimport FieldElement, RingElement, Element, ModuleElement from complex_number cimport ComplexNumber import complex_interval_field from complex_field import ComplexField -import sage.misc.misc -import integer +from sage.rings.integer cimport Integer import infinity -import real_mpfi -import real_mpfr +cimport real_mpfi cimport real_mpfr +from sage.libs.pari.all import pari_gen cdef double LOG_TEN_TWO_PLUS_EPSILON = 3.321928094887363 # a small overestimate of log(10,2) @@ -121,7 +118,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): real, imag = (real).real(), (real).imag() elif isinstance(real, ComplexIntervalFieldElement): real, imag = (real).real(), (real).imag() - elif isinstance(real, sage.libs.pari.all.pari_gen): + elif isinstance(real, pari_gen): real, imag = real.real(), real.imag() elif isinstance(real, list) or isinstance(real, tuple): re, imag = real @@ -733,10 +730,93 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): '[0.99109735947126309 .. 1.1179269966896264] + [1.4042388462787560 .. 1.4984624123369835]*I' sage: CIF(-7, -1) ^ CIF(0.3) 1.117926996689626? - 1.408500714575360?*I + + Note that ``x^2`` is not the same as ``x*x``:: + + sage: a = CIF(RIF(-1,1)) + sage: print (a^2).str(style="brackets") + [0.00000000000000000 .. 1.0000000000000000] + sage: print (a*a).str(style="brackets") + [-1.0000000000000000 .. 1.0000000000000000] + sage: a = CIF(0, RIF(-1,1)) + sage: print (a^2).str(style="brackets") + [-1.0000000000000000 .. -0.00000000000000000] + sage: print (a*a).str(style="brackets") + [-1.0000000000000000 .. 1.0000000000000000] + sage: a = CIF(RIF(-1,1), RIF(-1,1)) + sage: print (a^2).str(style="brackets") + [-1.0000000000000000 .. 1.0000000000000000] + [-2.0000000000000000 .. 2.0000000000000000]*I + sage: print (a*a).str(style="brackets") + [-2.0000000000000000 .. 2.0000000000000000] + [-2.0000000000000000 .. 2.0000000000000000]*I + + We can take very high powers:: + + sage: RIF = RealIntervalField(27) + sage: CIF = ComplexIntervalField(27) + sage: s = RealField(27, rnd="RNDZ")(1/2)^(1/3) + sage: a = CIF(RIF(-s/2,s/2), RIF(-s, s)) + sage: r = a^(10^10000) + sage: print r.str(style="brackets") + [-2.107553304e1028 .. 2.107553304e1028] + [-2.107553304e1028 .. 2.107553304e1028]*I + + TESTS:: + + sage: [CIF(2) ^ RDF(i) for i in range(-2,3)] + [0.2500000000?, 0.5000000000?, 1, 2, 4] + sage: pow(CIF(1), CIF(1), CIF(1)) + Traceback (most recent call last): + ... + TypeError: pow() 3rd argument not allowed unless all arguments are integers """ - if isinstance(right, (int, long, integer.Integer)): - return RingElement.__pow__(self, right) - return (self.log() * self.parent()(right)).exp() + if modulus is not None: + raise TypeError("pow() 3rd argument not allowed unless all arguments are integers") + + cdef ComplexIntervalFieldElement z, z2 + z = self + + # This conversion code is the same as generic_power_c() in + # sage/structure/element.pyx + try: + e = PyNumber_Index(right) + except TypeError: + try: + e = int(Integer(right)) + except TypeError: + # Exponent is really not an integer + return (z.log() * z._parent(right)).exp() + + if e <= 1: + if e == 0: + return z._parent.one() + if e < 0: + e = -e + z = ~z + if e == 1: + return z + + # Use binary powering with special formula for squares. + + # Handle first bit more efficiently: + if e & 1: + res = z + else: + res = z._parent.one() + e >>= 1 + + while e: + # Compute z2 = z^2 using the formula + # (a + bi)^2 = (a^2 - b^2) + 2abi + z2 = z._new() + mpfi_sqr(z2.__re, z.__re) # a^2 + mpfi_sqr(z2.__im, z.__im) # b^2 + mpfi_sub(z2.__re, z2.__re, z2.__im) # a^2 - b^2 + mpfi_mul(z2.__im, z.__re, z.__im) # ab + mpfi_mul_2ui(z2.__im, z2.__im, 1) # 2ab + z = z2 + if e & 1: + res *= z + e >>= 1 + return res def _magma_init_(self, magma): r""" From 5562a662aec8385bd5e7209a7c0aeea480849a8d Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Tue, 13 Oct 2015 14:15:44 +0200 Subject: [PATCH 1432/1872] add two TODO-blocks --- src/sage/rings/asymptotic/asymptotic_ring.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index ed1b0106621..611e416f638 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1324,6 +1324,12 @@ def log(self, base=None, precision=None): the asymptotic expansion for `\log(1+t)` as `t` tends to `0` is used. + .. TODO:: + + As soon as `L`-terms are implemented, this + implementation has to be adapted as well in order to + yield correct results. + EXAMPLES:: sage: R. = AsymptoticRing('x^ZZ * log(x)^ZZ', QQ) @@ -1552,6 +1558,12 @@ def exp(self, precision=None): is within `O(1)`, try to expand the series and truncate according to the given precision. + .. TODO:: + + As soon as `L`-terms are implemented, this + implementation has to be adapted as well in order to + yield correct results. + EXAMPLES:: sage: A. = AsymptoticRing('SR^x * x^ZZ * log(x)^ZZ', SR) From 40ff5697119f0e9e425dabd195395ac18e41dbc1 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 13 Oct 2015 14:32:52 +0200 Subject: [PATCH 1433/1872] Add conversion from RealDoubleElement and float --- src/sage/rings/real_mpfi.pyx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 4402d06a71c..00b01808561 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -1141,7 +1141,17 @@ cdef class RealIntervalFieldElement(RingElement): sage: R('1.2456').str(style='brackets') '[1.0 .. 1.3]' - EXAMPLES: + :: + + sage: RIF = RealIntervalField(53) + sage: RIF(RR.pi()) + 3.1415926535897932? + sage: RIF(RDF.pi()) + 3.1415926535897932? + sage: RIF(math.pi) + 3.1415926535897932? + sage: RIF.pi() + 3.141592653589794? Rounding:: @@ -1172,8 +1182,12 @@ cdef class RealIntervalFieldElement(RingElement): mpfi_set_q(self.value, (x).value) elif isinstance(x, Integer): mpfi_set_z(self.value, (x).value) + elif isinstance(x, RealDoubleElement): + mpfi_set_d(self.value, (x)._value) elif isinstance(x, int): mpfi_set_si(self.value, x) + elif isinstance(x, float): + mpfi_set_d(self.value, x) elif hasattr(x, '_real_mpfi_'): d = x._real_mpfi_(self._parent) mpfi_set(self.value, d.value) From d09d3847fcf55f661e9be98cd4dfb3226e8d9a9d Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 13 Oct 2015 14:37:17 +0200 Subject: [PATCH 1434/1872] trac #19385: --- src/sage/graphs/digraph.py | 4 +++- src/sage/graphs/graph_input.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index ab6e5501944..d7e8f81a587 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -807,7 +807,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if data_structure == "static_sparse": from sage.graphs.base.static_sparse_backend import StaticSparseBackend - ib = StaticSparseBackend(self, loops = loops, multiedges = multiedges) + ib = StaticSparseBackend(self, + loops = self.allows_loops(), + multiedges = self.allows_multiple_edges()) self._backend = ib self._immutable = True diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index e2c07cf78aa..1a698b04610 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -435,6 +435,7 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv raise ValueError("Dict of dicts for multigraph must be in the format {v : {u : list}}") if multiedges is None and len(M) > 0: multiedges = True + G.allow_loops(loops, check=False) G.allow_multiple_edges(multiedges, check=False) verts = set().union(M.keys(), *M.values()) From ced36581c5258b40dc9e72a986fbaa9b7e12a8cc Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 13 Oct 2015 14:40:14 +0200 Subject: [PATCH 1435/1872] trac #19385: Typo T_T --- src/sage/graphs/graph_input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 1a698b04610..3692458a517 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -398,7 +398,7 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv INPUT: - ``G`` -- a graph -x + - ``M`` -- a dictionary of dictionaries. - ``loops``, ``multiedges``, ``weighted`` (booleans) -- whether to consider From b89f01470aba338aad524fe71f173de1e3915d9f Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 13 Oct 2015 14:56:18 +0200 Subject: [PATCH 1436/1872] Unencoding from a code of dimension 0 now returns the empty vector --- src/sage/coding/encoder.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 556810e9a7b..09a21db1fa4 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -177,21 +177,20 @@ def unencode(self, c, nocheck=False): ... EncodingError: Given word is not in the code - If ones tries to unencode "a" codeword of a code of dimension 0, it - returns an error:: + If ones tries to unencode a codeword of a code of dimension 0, it + returns the empty vector:: sage: G = Matrix(GF(17), []) sage: C = LinearCode(G) sage: E = codes.encoders.LinearCodeGeneratorMatrixEncoder(C) sage: c = C.random_element() sage: E.unencode(c) - Traceback (most recent call last): - ... - EncodingError: Impossible to unencode a word of a code of dimension 0 + () """ - if self.code().ambient_space().dimension() == 0: - raise EncodingError("Impossible to unencode a word of a code of dimension 0") - if nocheck == False and c not in self.code(): + C = self.code() + if C.ambient_space().dimension() == 0: + return vector(C.base_ring(), 0) + if nocheck == False and c not in C: raise EncodingError("Given word is not in the code") return self.unencode_nocheck(c) From 5e34b5cd33d30c38482363976ea9dd0ea3ca3988 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 13 Oct 2015 15:13:50 +0200 Subject: [PATCH 1437/1872] Use more logical rounding modes for mignitude/magnitude --- src/sage/rings/real_mpfi.pyx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 85d3b750787..83b1f46d0b9 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -2446,15 +2446,19 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): """ The largest absolute value of the elements of the interval. + OUTPUT: a real number with rounding mode ``RNDU`` + EXAMPLES:: sage: RIF(-2, 1).magnitude() 2.00000000000000 sage: RIF(-1, 2).magnitude() 2.00000000000000 + sage: parent(RIF(1).magnitude()) + Real Field with 53 bits of precision and rounding RNDU """ cdef RealNumber x - x = (self._parent).__middle_field._new() + x = (self._parent).__upper_field._new() mpfi_mag(x.value, self.value) return x @@ -2462,6 +2466,8 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): """ The smallest absolute value of the elements of the interval. + OUTPUT: a real number with rounding mode ``RNDD`` + EXAMPLES:: sage: RIF(-2, 1).mignitude() @@ -2470,9 +2476,11 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): 1.00000000000000 sage: RIF(3, 4).mignitude() 3.00000000000000 + sage: parent(RIF(1).mignitude()) + Real Field with 53 bits of precision and rounding RNDD """ cdef RealNumber x - x = (self._parent).__middle_field._new() + x = (self._parent).__lower_field._new() mpfi_mig(x.value, self.value) return x From 03dc834b54c57c8dbac7ff3372d81f80c79c7fc2 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 13 Oct 2015 15:21:18 +0200 Subject: [PATCH 1438/1872] Implement magnitude and mignitude for complex intervals --- src/sage/rings/complex_interval.pyx | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 2fc79377f4a..681caf462fb 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -476,6 +476,52 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): mpfi_union(x.__im, self.__im, other_intv.__im) return x + def magnitude(self): + """ + The largest absolute value of the elements of the interval. + + OUTPUT: a real number with rounding mode ``RNDU`` + + EXAMPLES:: + + sage: CIF(RIF(-1,1), RIF(-1,1)).magnitude() + 1.41421356237310 + sage: CIF(RIF(1,2), RIF(3,4)).magnitude() + 4.47213595499958 + sage: parent(CIF(1).magnitude()) + Real Field with 53 bits of precision and rounding RNDU + """ + cdef real_mpfi.RealIntervalField_class RIF = self._parent._real_field() + cdef real_mpfr.RealNumber x = RIF.__upper_field._new() + cdef real_mpfr.RealNumber y = RIF.__upper_field._new() + mpfi_mag(x.value, self.__re) + mpfi_mag(y.value, self.__im) + mpfr_hypot(x.value, x.value, y.value, MPFR_RNDA) + return x + + def mignitude(self): + """ + The smallest absolute value of the elements of the interval. + + OUTPUT: a real number with rounding mode ``RNDD`` + + EXAMPLES:: + + sage: CIF(RIF(-1,1), RIF(-1,1)).mignitude() + 0.000000000000000 + sage: CIF(RIF(1,2), RIF(3,4)).mignitude() + 3.16227766016837 + sage: parent(CIF(1).mignitude()) + Real Field with 53 bits of precision and rounding RNDD + """ + cdef real_mpfi.RealIntervalField_class RIF = self._parent._real_field() + cdef real_mpfr.RealNumber x = RIF.__lower_field._new() + cdef real_mpfr.RealNumber y = RIF.__lower_field._new() + mpfi_mig(x.value, self.__re) + mpfi_mig(y.value, self.__im) + mpfr_hypot(x.value, x.value, y.value, MPFR_RNDZ) + return x + def center(self): """ Returns the closest floating-point approximation to the center From ed67ee233a40eefc5ce785596cdb83a6d0e62c63 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 13 Oct 2015 17:14:53 +0200 Subject: [PATCH 1439/1872] Integrated reviewer's comments --- src/sage/coding/encoder.py | 4 ++-- src/sage/coding/encoders_catalog.py | 4 ++-- src/sage/coding/linear_code.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 09a21db1fa4..2eaa9241bd8 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -46,7 +46,7 @@ class Encoder(SageObject): by memory reference: if you build the same encoder twice, they will be different. If you need something more clever, override ``__eq__`` and ``__ne__`` in your subclass. - - As :class:`Encoder` is not designed to be instanciated, it does not have any representation + - As :class:`Encoder` is not designed to be instantiated, it does not have any representation methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. REFERENCES: @@ -99,7 +99,7 @@ def encode(self, word): .. NOTE:: - :meth:`encode` is a partial function over ``self``'s :meth:`message_space`. + :meth:`encode` might be a partial function over ``self``'s :meth:`message_space`. One should use the exception :class:`EncodingError` to catch attempts to encode words that are outside of the message space. diff --git a/src/sage/coding/encoders_catalog.py b/src/sage/coding/encoders_catalog.py index ec48db90837..36a0f84e34a 100644 --- a/src/sage/coding/encoders_catalog.py +++ b/src/sage/coding/encoders_catalog.py @@ -12,5 +12,5 @@ sage: from sage.coding.encoders_catalog import * """ -from sage.misc.lazy_import import lazy_import -lazy_import('sage.coding.linear_code', 'LinearCodeGeneratorMatrixEncoder') +from sage.misc.lazy_import import lazy_import as _lazy_import +_lazy_import('sage.coding.linear_code', 'LinearCodeGeneratorMatrixEncoder') diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 92c3f486fd6..f39e6e6d77c 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -740,7 +740,7 @@ class AbstractLinearCode(module.Module): .. WARNING:: The default encoder should always have `F^{k}` as message space, with `k` the dimension - of the code and `F` its base ring. + of the code and `F` is the base ring of the code. A lot of methods of the abstract class rely on the knowledge of a generator matrix. It is thus strongly recommended to set an encoder with a generator matrix implemented @@ -3741,4 +3741,4 @@ def generator_matrix(self): [1 1 0 1 0 0 1] """ return self.code().generator_matrix() -AbstractLinearCode._registered_encoders["GeneratorMatrix"] = LinearCodeGeneratorMatrixEncoder +LinearCode._registered_encoders["GeneratorMatrix"] = LinearCodeGeneratorMatrixEncoder From 8f099ef3c66be856ee0005dc42a249aeecefb756 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 13 Oct 2015 17:23:26 +0200 Subject: [PATCH 1440/1872] Allow direct Cython access to coercion_model --- src/sage/matrix/action.pyx | 10 ++++++---- src/sage/matrix/matrix1.pyx | 14 +++++++------- src/sage/rings/polynomial/multi_polynomial.pyx | 4 +--- .../polynomial/multi_polynomial_libsingular.pyx | 5 +++-- src/sage/rings/polynomial/polynomial_element.pyx | 10 +++++----- src/sage/rings/ring.pyx | 4 ++-- src/sage/structure/coerce_actions.pyx | 5 ++--- src/sage/structure/element.pxd | 1 + src/sage/structure/parent.pyx | 9 +++------ src/sage/symbolic/function.pyx | 4 ++-- 10 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index 23ea977ba36..e9df2451601 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -53,8 +53,10 @@ AUTHOR: #***************************************************************************** # Copyright (C) 2007 Robert Bradshaw # -# Distributed under the terms of the GNU General Public License (GPL) -# +# 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/ #***************************************************************************** @@ -63,6 +65,7 @@ import operator from matrix_space import MatrixSpace, is_MatrixSpace from sage.modules.free_module import FreeModule, is_FreeModule +from sage.structure.element cimport coercion_model cdef class MatrixMulAction(Action): @@ -70,8 +73,7 @@ cdef class MatrixMulAction(Action): if not is_MatrixSpace(G): raise TypeError, "Not a matrix space: %s" % G if G.base_ring() is not S.base_ring(): - from sage.structure.element import get_coercion_model - base = get_coercion_model().common_parent(G.base_ring(), S.base_ring()) + base = coercion_model.common_parent(G.base_ring(), S.base_ring()) else: base = G.base_ring() Action.__init__(self, G, S, is_left, operator.mul) diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 1a05c581e21..d65eba6305d 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -9,18 +9,20 @@ TESTS:: sage: TestSuite(A).run() """ -################################################################################ +#***************************************************************************** # Copyright (C) 2005, 2006 William Stein # -# Distributed under the terms of the GNU General Public License (GPL). -# The full text of the GPL is available at: -# +# 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/python.pxi" import sage.modules.free_module +from sage.structure.element cimport coercion_model cdef class Matrix(matrix0.Matrix): @@ -1363,8 +1365,6 @@ cdef class Matrix(matrix0.Matrix): top_ring = self._base_ring bottom_ring = other._base_ring if top_ring is not bottom_ring: - from sage.structure.element import get_coercion_model - coercion_model = get_coercion_model() R = coercion_model.common_parent(top_ring, bottom_ring) if top_ring is not R: self = self.change_ring(R) diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 0c56d646477..6abf48db402 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -4,7 +4,7 @@ Base class for elements of multivariate polynomial rings from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ - +from sage.structure.element cimport coercion_model from sage.misc.derivative import multi_derivative from sage.rings.infinity import infinity @@ -1207,8 +1207,6 @@ cdef class MPolynomial(CommutativeRingElement): from sage.matrix.constructor import matrix if self.parent() != right.parent(): - from sage.structure.element import get_coercion_model - coercion_model = get_coercion_model() a, b = coercion_model.canonical_coercion(self,right) if variable: variable = a.parent()(variable) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index e50037ea73a..cf5f9f1edd2 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -219,7 +219,7 @@ from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.rings.number_field.number_field_base cimport NumberField from sage.rings.arith import gcd -from sage.structure.element import coerce_binop, get_coercion_model +from sage.structure.element import coerce_binop from sage.structure.parent cimport Parent from sage.structure.parent_base cimport ParentWithBase @@ -231,6 +231,7 @@ from sage.structure.element cimport RingElement from sage.structure.element cimport ModuleElement from sage.structure.element cimport Element from sage.structure.element cimport CommutativeRingElement +from sage.structure.element cimport coercion_model from sage.structure.factorization import Factorization from sage.structure.sequence import Sequence @@ -2114,7 +2115,7 @@ cdef class MPolynomial_libsingular(sage.rings.polynomial.multi_polynomial.MPolyn cdef poly *res # ownership will be transferred to us in the next line singular_polynomial_call(&res, self._poly, _ring, coerced_x, MPolynomial_libsingular_get_element) - res_parent = get_coercion_model().common_parent(parent._base, *x) + res_parent = coercion_model.common_parent(parent._base, *x) if res == NULL: return res_parent(0) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 527a8aa878b..4df7f5ae4d6 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -41,7 +41,6 @@ TESTS:: cdef is_FractionField, is_RealField, is_ComplexField -cdef coerce_binop, generic_power, parent cdef ZZ, QQ, RR, CC, RDF, CDF import operator, copy, re @@ -73,8 +72,10 @@ from sage.rings.real_double import is_RealDoubleField, RDF from sage.rings.complex_double import is_ComplexDoubleField, CDF from sage.rings.real_mpfi import is_RealIntervalField -from sage.structure.element import RingElement, generic_power, parent -from sage.structure.element cimport Element, RingElement, ModuleElement, MonoidElement +from sage.structure.element import generic_power +from sage.structure.element cimport parent_c as parent +from sage.structure.element cimport (Element, RingElement, + ModuleElement, MonoidElement, coercion_model) from sage.rings.rational_field import QQ, is_RationalField from sage.rings.integer_ring import ZZ, is_IntegerRing @@ -3235,7 +3236,7 @@ cdef class Polynomial(CommutativeAlgebraElement): # calling the coercion model bin_op is much more accurate than using the # true division (which is bypassed by polynomials). But it does not work # in all cases!! - cm = sage.structure.element.get_coercion_model() + cm = coercion_model try: S = cm.bin_op(R.one(), ZZ.one(), operator.div).parent() Q = S.base_ring() @@ -4510,7 +4511,6 @@ cdef class Polynomial(CommutativeAlgebraElement): # sylvester_matrix() in multi_polynomial.pyx. if self.parent() != right.parent(): - coercion_model = sage.structure.element.get_coercion_model() a, b = coercion_model.canonical_coercion(self,right) variable = a.parent()(self.variables()[0]) #We add the variable to cover the case that right is a multivariate diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 7d84ca3bab1..eff0728ac7d 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -68,7 +68,7 @@ AUTHORS: from sage.misc.cachefunc import cached_method -from sage.structure.element import get_coercion_model +from sage.structure.element cimport coercion_model from sage.structure.parent_gens cimport ParentWithGens from sage.structure.parent cimport Parent from sage.structure.category_object import check_default_category @@ -1308,7 +1308,7 @@ cdef class CommutativeRing(Ring): try: return self.fraction_field() except (NotImplementedError,TypeError): - return get_coercion_model().division_parent(self) + return coercion_model.division_parent(self) def __pow__(self, n, _): """ diff --git a/src/sage/structure/coerce_actions.pyx b/src/sage/structure/coerce_actions.pyx index 30da0d9a117..18f19a13d95 100644 --- a/src/sage/structure/coerce_actions.pyx +++ b/src/sage/structure/coerce_actions.pyx @@ -18,14 +18,13 @@ import operator include "sage/ext/interrupt.pxi" from cpython.int cimport * from cpython.number cimport * -from sage.structure.element cimport parent_c +from sage.structure.element cimport parent_c, coercion_model from sage.categories.action import InverseAction, PrecomposedAction from coerce_exceptions import CoercionException cdef _record_exception(): - from element import get_coercion_model - get_coercion_model()._record_exception() + coercion_model._record_exception() cdef inline an_element(R): if isinstance(R, Parent): diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index c2317e745ae..66e6047cb52 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -148,5 +148,6 @@ cdef class CoercionModel: cpdef canonical_coercion(self, x, y) cpdef bin_op(self, x, y, op) +cdef CoercionModel coercion_model cdef generic_power_c(a, nn, one) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 1936d2b69b9..add09199810 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -95,7 +95,7 @@ This came up in some subtle bug once:: """ from types import MethodType -from element cimport parent_c +from .element cimport parent_c, coercion_model cimport sage.categories.morphism as morphism cimport sage.categories.map as map from sage.structure.debug_options import debug @@ -118,8 +118,7 @@ dummy_attribute_error = AttributeError(dummy_error_message) cdef _record_exception(): - from element import get_coercion_model - get_coercion_model()._record_exception() + coercion_model._record_exception() cdef object _Integer cdef bint is_Integer(x): @@ -1808,7 +1807,6 @@ cdef class Parent(category_object.CategoryObject): if embedding is not None: self.register_embedding(embedding) - def _unset_coercions_used(self): r""" Pretend that this parent has never been interrogated by the coercion @@ -1820,8 +1818,7 @@ cdef class Parent(category_object.CategoryObject): For internal use only! """ self._coercions_used = False - import sage.structure.element - sage.structure.element.get_coercion_model().reset_cache() + coercion_model.reset_cache() def _unset_embedding(self): r""" diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index ba2a3b64a26..08d51cfe37d 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -22,7 +22,7 @@ from expression cimport new_Expression_from_GEx, Expression from ring import SR from sage.structure.coerce cimport py_scalar_to_element, is_numpy_type -from sage.structure.element import get_coercion_model +from sage.structure.element cimport coercion_model # we keep a database of symbolic functions initialized in a session # this also makes the .operator() method of symbolic expressions work @@ -255,7 +255,7 @@ cdef class Function(SageObject): evalf = self._evalf_ # catch AttributeError early if any(self._is_numerical(x) for x in args): if not any(isinstance(x, Expression) for x in args): - p = get_coercion_model().common_parent(*args) + p = coercion_model.common_parent(*args) return evalf(*args, parent=p) except Exception: pass From 09cff050d07c9d32120f3e81e1d8a721d04ed35b Mon Sep 17 00:00:00 2001 From: "Johan S. R. Nielsen" Date: Tue, 13 Oct 2015 21:23:59 +0200 Subject: [PATCH 1441/1872] Alternative fix for the zero-dimensional unencoding bug --- src/sage/coding/encoder.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 2eaa9241bd8..d5051e7ccfe 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -187,10 +187,7 @@ def unencode(self, c, nocheck=False): sage: E.unencode(c) () """ - C = self.code() - if C.ambient_space().dimension() == 0: - return vector(C.base_ring(), 0) - if nocheck == False and c not in C: + if nocheck == False and c not in self.code(): raise EncodingError("Given word is not in the code") return self.unencode_nocheck(c) @@ -266,7 +263,7 @@ def unencode_nocheck(self, c): False """ U, info_set = self._unencoder_matrix() - cc = vector( c[i] for i in info_set ) + cc = vector(self.code().base_ring(), [c[i] for i in info_set]) return cc * U def code(self): From 8b59ed360471d53e7686d414cdf5cb95a6ab74f0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 13 Oct 2015 14:43:28 -0500 Subject: [PATCH 1442/1872] Making (co)homology into a graded module (algebra). --- src/sage/homology/cell_complex.py | 166 ++--- .../homology_vector_space_with_basis.py | 638 +++++++++++------- 2 files changed, 421 insertions(+), 383 deletions(-) diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 0c563567424..aa5130f7edc 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -760,12 +760,7 @@ def algebraic_topological_model(self, base_ring=None): return algebraic_topological_model_delta_complex(self, base_ring) return algebraic_topological_model(self, base_ring) - # This is cached for uniqueness reasons: calling - # K.homology_with_basis(...) twice should yield identical spaces, - # so that one can compare, say, x.cup_product(one) with x (if - # "one" is the identity element in H^0(K)). - @cached_method - def homology_with_basis(self, dim, base_ring=None, cohomology=False): + def homology_with_basis(self, base_ring=None, cohomology=False): r""" Return the unreduced homology in dimension ``dim`` with coefficients in ``base_ring`` with a chosen basis. @@ -775,7 +770,6 @@ def homology_with_basis(self, dim, base_ring=None, cohomology=False): INPUTS: - - ``dim`` -- dimension - ``base_ring`` -- coefficient ring (optional, default ``QQ``); must be a field - ``cohomology`` -- boolean (optional, default ``False``); if @@ -786,25 +780,35 @@ def homology_with_basis(self, dim, base_ring=None, cohomology=False): group. Cohomology basis elements are denoted `h^{dim,i}` instead. + .. SEEALSO:: + + If ``cohomology`` is ``True``, this returns the cohomology + as a graded module. For the ring structure, use + :meth:`cohomology_ring`. + EXAMPLES:: sage: K = simplicial_complexes.KleinBottle() - sage: K.homology_with_basis(1, QQ) - Free module generated by (h_{1,0},) over Rational Field - sage: K.homology_with_basis(1, GF(2)) - Free module generated by (h_{1,0}, h_{1,1}) over Finite Field of size 2 + sage: H = K.homology_with_basis(QQ); H + Homology module of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets over Rational Field + sage: sorted(H.basis(), key=str) + [h_{0,0}, h_{1,0}] + sage: H = K.homology_with_basis(GF(2)); H + Homology module of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets over Finite Field of size 2 + sage: sorted(H.basis(), key=str) + [h_{0,0}, h_{1,0}, h_{1,1}, h_{2,0}] """ from homology_vector_space_with_basis import HomologyVectorSpaceWithBasis - H, M = self.algebraic_topological_model(base_ring) - if cohomology: - H = H.dual() - return HomologyVectorSpaceWithBasis(dim, H, self) + if base_ring is None: + base_ring = QQ + return HomologyVectorSpaceWithBasis(base_ring, self, cohomology) - # This is cached in effect via homology_with_basis. - def cohomology_with_basis(self, dim, base_ring=None): + def cohomology_ring(self, base_ring=None): r""" - Return the unreduced cohomology in dimension ``dim`` with - coefficients in ``base_ring`` with a chosen basis. + Return the unreduced cohomology with coefficients in + ``base_ring`` with a chosen basis. This is implemented for simplicial, cubical, and `\Delta`-complexes. The resulting elements are suitable for @@ -825,22 +829,29 @@ def cohomology_with_basis(self, dim, base_ring=None): EXAMPLES:: sage: K = simplicial_complexes.KleinBottle() - sage: K.cohomology_with_basis(1, QQ) - Free module generated by (h^{1,0},) over Rational Field - sage: K.cohomology_with_basis(1, GF(2)) - Free module generated by (h^{1,0}, h^{1,1}) over Finite Field of size 2 + sage: H = K.cohomology_ring(QQ); H + Cohomology ring of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets over Rational Field + sage: sorted(H.basis(), key=str) + [h^{0,0}, h^{1,0}] + sage: H = K.cohomology_ring(GF(2)); H + Cohomology ring of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets over Finite Field of size 2 + sage: sorted(H.basis(), key=str) + [h^{0,0}, h^{1,0}, h^{1,1}, h^{2,0}] sage: X = delta_complexes.SurfaceOfGenus(2) - sage: X.cohomology_with_basis(1, QQ) - Free module generated by (h^{1,0}, h^{1,1}, h^{1,2}, h^{1,3}) over Rational Field - - sage: H1 = simplicial_complexes.Torus().cohomology_with_basis(1, QQ) - sage: x = H1.basis()[0]; x + sage: X.cohomology_ring(QQ) + Cohomology ring of Delta complex with 3 vertices and 29 simplices + over Rational Field + + sage: H = simplicial_complexes.Torus().cohomology_ring(QQ); H + Cohomology ring of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6) and 14 facets over Rational Field + sage: x = H.basis()[1,0]; x h^{1,0} - sage: y = H1.basis()[1]; y + sage: y = H.basis()[1,1]; y h^{1,1} - sage: simplicial_complexes.Torus().cohomology_with_basis(2, QQ) - Free module generated by (h^{2,0},) over Rational Field You can compute cup products of cohomology classes:: @@ -856,99 +867,12 @@ def cohomology_with_basis(self, dim, base_ring=None): sage: RP2 = simplicial_complexes.RealProjectivePlane() sage: K = RP2.suspension() sage: K.set_immutable() - sage: y = K.cohomology_with_basis(2, GF(2)).basis()[0] + sage: y = K.cohomology_ring(GF(2)).basis()[2,0] sage: y.Sq(1) h^{3,0} """ - return self.homology_with_basis(dim, base_ring, cohomology=True) - - # This is cached for speed reasons: it can be very slow to run - # this function. - @cached_method - def cohomology_ring(self, base_ring=None): - """ - The cohomology ring of this cell complex, with field coefficients. - - This is implemented for simplicial, cubical, and - `\Delta`-complexes. - - INPUT: - - - ``base_ring`` -- coefficient ring (optional, default - ``QQ``); must be a field - - This returns a finite-dimensional algebra: more precisely, an - instance of - :class:`sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra.FiniteDimensionalAlgebra`. Thus - the defining data are the matrices which define right - multiplication by each basis element. - - EXAMPLES:: - - sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) - sage: H = RP3.cohomology_ring(GF(2)) - sage: H - Finite-dimensional algebra of degree 4 over Finite Field of size 2 - sage: H.basis() - [h00, h10, h20, h30] - - The matrices specifying right multiplication by each basis element:: - - sage: H.table() - [ - [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] - [0 1 0 0] [0 0 1 0] [0 0 0 1] [0 0 0 0] - [0 0 1 0] [0 0 0 1] [0 0 0 0] [0 0 0 0] - [0 0 0 1], [0 0 0 0], [0 0 0 0], [0 0 0 0] - ] - sage: H.is_associative() - True - sage: H.is_commutative() # True because it's characteristic 2. - True - sage: T = cubical_complexes.Torus() - sage: T.cohomology_ring(QQ).is_commutative() - False - """ - from sage.matrix.constructor import matrix - from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra - if base_ring is None: - base_ring = QQ - # First construct the basis. This is a dictionary with keys - # (d, i): d is the degree of the cohomology class, i ranges - # from 0 to r-1, if r is the rank of H^d. List these elements - # in order of increasing d and i; then the value for each key - # is just its index. - basis = {} - idx = 0 - for d in range(self.dimension()+1): - for i in range(self.cohomology_with_basis(d, base_ring=base_ring).dimension()): - basis[(d,i)] = idx - idx += 1 - - # Now iterate over each basis element, in order, to construct - # the list of matrices representing right multiplication by - # each basis element. - matrices = [] - rank = len(basis) - for y in sorted(basis): - y_matrix_dict = {} - y_elt = self.cohomology_with_basis(y[0], base_ring).basis()[y[1]] - for x in basis: - x_elt = self.cohomology_with_basis(x[0], base_ring).basis()[x[1]] - z = x_elt.cup_product(y_elt) - d = z.parent().degree() - idx = basis[x] - try: - start = basis[(d,0)] - except KeyError: - # No cohomology in this degree. - pass - z_vec = z.to_vector() - for j in range(z_vec.degree()): - y_matrix_dict[(idx, start+j)] = z_vec[j] - matrices.append(matrix(base_ring, rank, rank, y_matrix_dict)) - names = ['h{}{}'.format(y[0], y[1]) for y in sorted(basis)] - return FiniteDimensionalAlgebra(base_ring, table=matrices, names=names) + from homology_vector_space_with_basis import CohomologyRing + return CohomologyRing(base_ring, self) ############################################################ # end of chain complexes, homology diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index d52cd7b16ff..f04aa1eb713 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -16,11 +16,12 @@ AUTHORS: -- John H. Palmieri (2015-09) +- John H. Palmieri, Travis Scrimshaw (2015-09) """ ######################################################################## # Copyright (C) 2015 John H. Palmieri +# Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -29,7 +30,12 @@ # http://www.gnu.org/licenses/ ######################################################################## +from sage.misc.cachefunc import cached_method +from sage.categories.algebras import Algebras +from sage.categories.modules import Modules from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement +from sage.modules.free_module import FreeModule +from sage.sets.family import Family from simplicial_complex import SimplicialComplex class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): @@ -45,18 +51,20 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): .. NOTE:: - This is not intended to be used directly by the user, but instead - via the methods + This is not intended to be created directly by the user, but + instead via the methods :meth:`cell_complex.CellComplex.homology_with_basis` and - :meth:`cell_complex.CellComplex.cohomology_with_basis`. + :meth:`cell_complex.CellComplex.cohomology_ring`. INPUT: - - ``deg`` -- the degree of this homology group - ``contraction`` -- the chain contraction associated to this homology computation - ``cell_complex`` -- the cell complex whose homology we are computing + - ``cohomology`` -- (default: ``False``) if ``True``, this reflects + the cohomology as a module + - ``category`` -- (optional) a subcategory of modules with basis EXAMPLES: @@ -65,36 +73,34 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): of basis elements. Cohomology classes are denoted ``h^{1,0}``:: sage: RP2 = cubical_complexes.RealProjectivePlane() - sage: RP2.homology_with_basis(1, GF(2)) - Free module generated by (h_{1,0},) over Finite Field of size 2 - sage: RP2.cohomology_with_basis(1, GF(2)) - Free module generated by (h^{1,0},) over Finite Field of size 2 - sage: simplicial_complexes.Torus().homology_with_basis(1, QQ) - Free module generated by (h_{1,0}, h_{1,1}) over Rational Field - - To access a basis element, use its index (0 or 1 in the 1st + sage: RP2.homology_with_basis(GF(2)) + Homology module of Cubical complex with 21 vertices and 81 cubes + over Finite Field of size 2 + sage: RP2.cohomology_ring(GF(2)) + Cohomology ring of Cubical complex with 21 vertices and 81 cubes + over Finite Field of size 2 + sage: simplicial_complexes.Torus().homology_with_basis(QQ) + Homology module of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6) and 14 facets over Rational Field + + To access a basis element, use its degree and index (0 or 1 in the 1st cohomology group of a torus):: - sage: H1 = simplicial_complexes.Torus().cohomology_with_basis(1, QQ) - sage: H1.indices() - {0, 1} - sage: H1.basis()[0] + sage: H = simplicial_complexes.Torus().cohomology_ring(QQ) + sage: H.basis(1) + Finite family {(1, 0): h^{1,0}, (1, 1): h^{1,1}} + sage: H.basis()[1,0] h^{1,0} - sage: H1.basis()[1] + sage: H.basis()[1,1] h^{1,1} You can then form linear combinations of these easily enough:: - sage: x = H1.basis()[0] - sage: y = H1.basis()[1] + sage: x = H.basis()[1,0] + sage: y = H.basis()[1,1] sage: 2*x-3*y 2*h^{1,0} - 3*h^{1,1} - Or you can use the :meth:`from_vector` method to do this in one step:: - - sage: H1.from_vector(vector((2, -3))) - 2*h^{1,0} - 3*h^{1,1} - You can compute cup products of cohomology classes:: sage: x.cup_product(y) @@ -107,8 +113,8 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): This works with simplicial, cubical, and Delta complexes:: sage: Klein_c = cubical_complexes.KleinBottle() - sage: H1 = Klein_c.cohomology_with_basis(1, GF(2)) - sage: x,y = H1.basis() + sage: H = Klein_c.cohomology_ring(GF(2)) + sage: x,y = H.basis(1) sage: x.cup_product(x) h^{2,0} sage: x.cup_product(y) @@ -117,8 +123,8 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): h^{2,0} sage: Klein_d = delta_complexes.KleinBottle() - sage: H1 = Klein_d.cohomology_with_basis(1, GF(2)) - sage: u,v = H1.basis() + sage: H = Klein_d.cohomology_ring(GF(2)) + sage: u,v = H.basis(1) sage: u.cup_product(u) h^{2,0} sage: u.cup_product(v) @@ -127,12 +133,12 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): h^{2,0} The basis elements in the simplicial complex case have been chosen - differently; apply the change of basis `x \mapsto a+b`, `y \mapsto + differently; apply the change of basis `x \mapsto a + b`, `y \mapsto b` to see the same product structure. :: sage: Klein_s = simplicial_complexes.KleinBottle() - sage: H1 = Klein_s.cohomology_with_basis(1, GF(2)) - sage: a,b = H1.basis() + sage: H = Klein_s.cohomology_ring(GF(2)) + sage: a,b = H.basis(1) sage: a.cup_product(a) 0 sage: a.cup_product(b) @@ -141,47 +147,78 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): h^{2,0} sage: b.cup_product(b) h^{2,0} - """ - def __init__(self, deg, contraction, cell_complex): + def __init__(self, base_ring, cell_complex, cohomology=False, cat=None): """ Initialize ``self``. EXAMPLES:: sage: RP2 = simplicial_complexes.ProjectivePlane() - sage: RP2.homology_with_basis(1, QQ) # indirect doctest - Free module generated by () over Rational Field - sage: RP2.homology_with_basis(1, GF(2)) - Free module generated by (h_{1,0},) over Finite Field of size 2 - sage: RP2.cohomology_with_basis(1, GF(2)) - Free module generated by (h^{1,0},) over Finite Field of size 2 - sage: RP2.cohomology_with_basis(1, GF(5)) - Free module generated by () over Finite Field of size 5 + sage: H = RP2.homology_with_basis(QQ) + sage: TestSuite(H).run() + sage: H = RP2.homology_with_basis(GF(2)) + sage: TestSuite(H).run() + sage: H = RP2.cohomology_ring(GF(2)) + sage: TestSuite(H).run() + sage: H = RP2.cohomology_ring(GF(5)) + sage: TestSuite(H).run() """ - self._contraction = contraction + H, M = cell_complex.algebraic_topological_model(base_ring) + if cohomology: + H = H.dual() + cat = Modules(base_ring).WithBasis().Graded().or_subcategory(cat) + self._contraction = H # M is the homology chain complex. + # Do we need this for when we construct the cohomology? M = self._contraction.pi()._codomain - self._degree = deg self._complex = cell_complex - rank = M.free_module_rank(deg) - # Homology vs. cohomology is detected by the degree of the - # differential in the relevant chain complexes: - self._cohomology = (M.degree_of_differential() == 1) - CombinatorialFreeModule.__init__(self, M.base_ring(), range(rank)) + self._cohomology = cohomology + self._graded_indices = {deg: range(M.free_module_rank(deg)) + for deg in range(cell_complex.dimension()+1)} + indices = [(deg, i) for deg in self._graded_indices + for i in self._graded_indices[deg]] + CombinatorialFreeModule.__init__(self, base_ring, indices, category=cat) + + def basis(self, d=None): + """ + Return (the degree ``d`` homogeneous component of) the basis + of ``self``. + + INPUT: + + - ``d`` -- (optional) the degree + + EXAMPLES:: + + sage: RP2 = simplicial_complexes.ProjectivePlane() + sage: H = RP2.homology_with_basis(QQ) + sage: H.basis() + Finite family {(0, 0): h_{0,0}} + sage: H.basis(0) + Finite family {(0, 0): h_{0,0}} + sage: H.basis(1) + Finite family {} + sage: H.basis(2) + Finite family {} + """ + if d is None: + return Family(self._indices, self.monomial) + else: + indices = [(d, i) for i in self._graded_indices.get(d, [])] + return Family(indices, self.monomial) - def degree(self): + def degree_on_basis(self, i): r""" - The degree of this homology group: if this is `H_n(K)` for some - complex `K`, return `n`. + Return the degree of the basis element indexed by ``i``. EXAMPLES:: - sage: H2 = simplicial_complexes.Torus().homology_with_basis(2, GF(7)) - sage: H2.degree() + sage: H = simplicial_complexes.Torus().homology_with_basis(GF(7)) + sage: H.degree_on_basis((2,0)) 2 """ - return self._degree + return i[0] def contraction(self): r""" @@ -199,13 +236,12 @@ def contraction(self): See :class:`chain_homotopy.ChainContraction` for information about chain contractions, and see :func:`algebraic_topological_model.algebraic_topological_model` - for the construction of this particular chain contraction - `\phi`. + for the construction of this particular chain contraction `\phi`. EXAMPLES:: - sage: H1 = simplicial_complexes.Simplex(2).homology_with_basis(1, QQ) - sage: H1.contraction() + sage: H = simplicial_complexes.Simplex(2).homology_with_basis(QQ) + sage: H.contraction() Chain homotopy between Chain complex morphism From: Chain complex with at most 3 nonzero terms over Rational Field @@ -217,7 +253,7 @@ def contraction(self): From the chain contraction, one can also recover the maps `\pi` and `\iota`:: - sage: phi = H1.contraction() + sage: phi = H.contraction() sage: phi.pi() Chain complex morphism From: Chain complex with at most 3 nonzero terms over Rational Field @@ -235,8 +271,8 @@ def complex(self): EXAMPLES:: - sage: H1 = simplicial_complexes.Simplex(2).homology_with_basis(1, QQ) - sage: H1.complex() + sage: H = simplicial_complexes.Simplex(2).homology_with_basis(QQ) + sage: H.complex() Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)} """ return self._complex @@ -245,10 +281,15 @@ def _repr_(self): """ EXAMPLES:: - sage: simplicial_complexes.Torus().homology_with_basis(1, QQ) - Free module generated by (h_{1,0}, h_{1,1}) over Rational Field + sage: simplicial_complexes.Torus().homology_with_basis(QQ) + Homology module of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6) and 14 facets over Rational Field """ - return "Free module generated by {} over {}".format(tuple(self.basis()), self.base_ring()) + if self._cohomology: + base = "Cohomology" + else: + base = "Homology" + return base + " module of {} over {}".format(self._complex, self.base_ring()) def _repr_term(self, i): """ @@ -257,36 +298,78 @@ def _repr_term(self, i): EXAMPLES:: - sage: H1 = simplicial_complexes.Torus().homology_with_basis(1, QQ) - sage: H1.basis()[0] # indirect doctest + sage: H = simplicial_complexes.Torus().homology_with_basis(QQ) + sage: H.basis()[1,0] # indirect doctest h_{1,0} - sage: latex(H1.basis()[1]) # indirect doctest + sage: latex(H.basis()[1,1]) # indirect doctest h_{1,1} - sage: co = simplicial_complexes.KleinBottle().homology_with_basis(1, GF(2), cohomology=True) - sage: co.basis()[0] # indirect doctest + sage: co = simplicial_complexes.KleinBottle().cohomology_ring(GF(2)) + sage: co.basis()[1,0] # indirect doctest h^{1,0} """ sym = '^' if self._cohomology else '_' - return 'h{}{{{},{}}}'.format(sym, self.degree(), i) + return 'h{}{{{},{}}}'.format(sym, i[0], i[1]) _latex_term = _repr_term - # We need an element class so we can apply iota to the elements, - # compute cup products, Steenrod operations, etc. + @cached_method + def _to_cycle_on_basis(self, i): + """ + Return the (co)cycle representative of the basis element + indexed by ``i``. - class Element(CombinatorialFreeModuleElement): + .. SEEALSO:: + + :meth:`HomologyVectorSpaceWithBasis.Element.to_cocycle` + EXAMPLES:: + + sage: S2 = simplicial_complexes.Sphere(2) + sage: H = S2.homology_with_basis(QQ) + sage: H._to_cycle_on_basis((2,0)) + -(0, 1, 2) + (0, 1, 3) - (0, 2, 3) + (1, 2, 3) + + sage: S2.cohomology_ring(QQ)._to_cycle_on_basis((2,0)) + \chi_(0, 1, 3) + sage: S2.cohomology_ring(QQ)._to_cycle_on_basis((0,0)) + \chi_(0,) + \chi_(1,) + \chi_(2,) + \chi_(3,) + + sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) + sage: H = RP3.cohomology_ring(GF(2)) + sage: H._to_cycle_on_basis((0,0)) + \chi_(1,) + \chi_(2,) + \chi_(3,) + \chi_(4,) + \chi_(5,) + \chi_(6,) + + \chi_(7,) + \chi_(8,) + \chi_(9,) + \chi_(10,) + \chi_(11,) + sage: H._to_cycle_on_basis((1,0)) + \chi_(1, 2) + \chi_(1, 3) + \chi_(1, 4) + \chi_(1, 7) + + \chi_(1, 10) + \chi_(2, 4) + \chi_(2, 6) + \chi_(2, 9) + + \chi_(2, 10) + \chi_(2, 11) + \chi_(3, 4) + \chi_(3, 5) + + \chi_(3, 11) + \chi_(4, 8) + \chi_(4, 9) + \chi_(5, 9) + + \chi_(5, 10) + \chi_(7, 9) + \chi_(8, 10) + sage: H._to_cycle_on_basis((2,0)) + \chi_(2, 3, 8) + \chi_(2, 7, 8) + \chi_(3, 4, 8) + \chi_(3, 5, 9) + + \chi_(3, 6, 7) + \chi_(3, 6, 8) + \chi_(3, 6, 10) + + \chi_(3, 8, 9) + \chi_(3, 9, 10) + \chi_(4, 5, 7) + + \chi_(4, 5, 9) + \chi_(5, 6, 7) + \chi_(5, 7, 8) + sage: H._to_cycle_on_basis((3,0)) + \chi_(3, 4, 5, 9) + """ + vec = self.contraction().iota().in_degree(i[0]).column(i[1]) + chains = self.complex().n_chains(i[0], self.base_ring(), + cochains=self._cohomology) + return chains.from_vector(vec) + + class Element(CombinatorialFreeModuleElement): def to_cycle(self): r""" - (Co)cycle representative of this (co)homology class. + (Co)cycle representative of this homogeneous (co)homology class. EXAMPLES:: sage: S2 = simplicial_complexes.Sphere(2) - sage: H2 = S2.homology_with_basis(2, QQ) - sage: H2.basis()[0] + sage: H = S2.homology_with_basis(QQ) + sage: h20 = H.basis()[2,0]; h20 h_{2,0} - sage: H2.basis()[0].to_cycle() + sage: h20.to_cycle() -(0, 1, 2) + (0, 1, 3) - (0, 2, 3) + (1, 2, 3) Chains are written as linear combinations of simplices @@ -294,24 +377,180 @@ def to_cycle(self): characteristic functions `\chi_{\sigma}` for those simplices:: - sage: S2.cohomology_with_basis(2, QQ).basis()[0].to_cycle() + sage: S2.cohomology_ring(QQ).basis()[2,0].to_cycle() \chi_(0, 1, 3) - sage: S2.cohomology_with_basis(0, QQ).basis()[0].to_cycle() + sage: S2.cohomology_ring(QQ).basis()[0,0].to_cycle() \chi_(0,) + \chi_(1,) + \chi_(2,) + \chi_(3,) """ - deg = self.parent().degree() - vec = self.parent().contraction().iota().in_degree(deg) * self.to_vector() - chains = self.parent().complex().n_chains(deg, self.base_ring(), - cochains=self.parent()._cohomology) - return chains.from_vector(vec) + if not self.is_homogeneous(): + raise ValueError("only defined for homogeneous elements") + deg = self.degree() + return sum(c * self.parent()._to_cycle_on_basis(i) for i,c in self) - def cup_product(self, other): - r""" - The cup product of this element with ``other``. +class CohomologyRing(HomologyVectorSpaceWithBasis): + """ + The cohomology ring. + """ + def __init__(self, base_ring, cell_complex): + """ + Initialize ``self``. - INPUT: + EXAMPLES:: + + sage: RP2 = simplicial_complexes.ProjectivePlane() + sage: H = RP2.cohomology_ring(GF(2)) + sage: TestSuite(H).run() + sage: H = RP2.cohomology_ring(GF(5)) + sage: TestSuite(H).run() + """ + cat = Algebras(base_ring).WithBasis().Graded() + HomologyVectorSpaceWithBasis.__init__(self, base_ring, cell_complex, True, cat) + + def _repr_(self): + """ + EXAMPLES:: + + sage: simplicial_complexes.Torus().cohomology_ring(QQ) + Cohomology ring of Simplicial complex with vertex set + (0, 1, 2, 3, 4, 5, 6) and 14 facets over Rational Field + """ + return "Cohomology ring of {} over {}".format(self._complex, self.base_ring()) + + @cached_method + def one(self): + """ + EXAMPLES:: + + sage: H = simplicial_complexes.Torus().cohomology_ring(QQ) + sage: H.one() + h^{0,0} + """ + one = self.base_ring().one() + d = {(0,i): one for i in self._graded_indices[0]} + return self._from_dict(d, remove_zeros=False) + + @cached_method + def product_on_basis(self, li, ri): + r""" + The cup product of the basis elements indexed by ``li`` and ``ri`` + in ``self``. + + INPUT: - - ``other`` -- a cohomology class from the same cell complex + - ``li``, ``ri`` -- index of a cohomology class + + .. SEEALSO:: + + :meth:`CohomologyRing.Element.cup_product` + + EXAMPLES:: + + sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) + sage: H = RP3.cohomology_ring(GF(2)) + sage: c = H.basis()[1,0] + sage: c.cup_product(c).cup_product(c) + h^{3,0} + + sage: T = simplicial_complexes.Torus() + sage: x,y = T.cohomology_ring(QQ).basis(1) + sage: x.cup_product(y) + h^{2,0} + sage: x.cup_product(x) + 0 + + sage: one = T.cohomology_ring(QQ).basis()[0,0] + sage: x.cup_product(one) + h^{1,0} + sage: one.cup_product(y) == y + True + sage: one.cup_product(one) + h^{0,0} + sage: x.cup_product(y) + y.cup_product(x) + 0 + + This also works with cubical complexes:: + + sage: T = cubical_complexes.Torus() + sage: x,y = T.cohomology_ring(QQ).basis(1) + sage: x.cup_product(y) + -h^{2,0} + sage: x.cup_product(x) + 0 + + and `\Delta`-complexes:: + + sage: T_d = delta_complexes.Torus() + sage: a,b = T_d.cohomology_ring(QQ).basis(1) + sage: a.cup_product(b) + h^{2,0} + sage: b.cup_product(a) + -h^{2,0} + sage: RP2 = delta_complexes.RealProjectivePlane() + sage: w = RP2.cohomology_ring(GF(2)).basis()[1,0] + sage: w.cup_product(w) + h^{2,0} + + A non-connected example:: + + sage: K = cubical_complexes.Torus().disjoint_union(cubical_complexes.Torus()) + sage: a,b,c,d = K.cohomology_ring(QQ).basis(1) + sage: x,y = K.cohomology_ring(QQ).basis(0) + sage: a.cup_product(x) == a + True + sage: a.cup_product(y) + 0 + """ + B = self.basis() + scomplex = self.complex() + base_ring = self.base_ring() + deg_left = li[0] + deg_right = ri[0] + deg_tot = deg_left + deg_right + left_cycle = self._to_cycle_on_basis(li) + right_cycle = self._to_cycle_on_basis(ri) + n_chains_left = scomplex.n_chains(deg_left, base_ring) + n_chains_right = scomplex.n_chains(deg_right, base_ring) + + result = {} + H = scomplex.homology_with_basis(base_ring) + for gamma_index in H._graded_indices.get(deg_tot, []): + gamma_coeff = base_ring.zero() + for cell, coeff in H._to_cycle_on_basis((deg_tot, gamma_index)): + if hasattr(cell, 'alexander_whitney'): + # Simplicial and cubical case: each cell has a + # method 'alexander_whitney' which computes + # the appropriate faces. + for (c, left_cell, right_cell) in cell.alexander_whitney(deg_left): + left = n_chains_left(left_cell) + right = n_chains_right(right_cell) + gamma_coeff += c * coeff * left_cycle.eval(left) * right_cycle.eval(right) + else: + # Delta complex case: each "cell" in n_chains + # is just a pair (integer, tuple), where the + # integer is its index in the list, and the + # jth entry of the tuple is the index of its + # jth face in the list of (n-1)-chains. Use + # this data to compute the appropriate faces + # by hand. + left_cell = cell + for i in range(deg_tot, deg_left, -1): + idx = left_cell[1][i] + left_cell = (idx, scomplex.n_cells(i-1)[idx]) + right_cell = cell + for i in range(deg_tot, deg_right, -1): + idx = right_cell[1][0] + right_cell = (idx, scomplex.n_cells(i-1)[idx]) + left = n_chains_left(left_cell) + right = n_chains_right(right_cell) + gamma_coeff += coeff * left_cycle.eval(left) * right_cycle.eval(right) + if gamma_coeff != base_ring.zero(): + result[(deg_tot, gamma_index)] = gamma_coeff + return self._from_dict(result) + + class Element(HomologyVectorSpaceWithBasis.Element): + def cup_product(self, other): + """ + Return the cup product of ``self`` and ``other``. Algorithm: see González-Díaz and Réal [G-DR03]_, p. 88. Given two cohomology classes, lift them to cocycle @@ -329,124 +568,17 @@ def cup_product(self, other): EXAMPLES:: sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) - sage: H1 = RP3.cohomology_with_basis(1, GF(2)) - sage: c = H1.basis()[0] - sage: c.cup_product(c).cup_product(c) - h^{3,0} - - sage: T = simplicial_complexes.Torus() - sage: x,y = list(T.cohomology_with_basis(1, QQ).basis()) - sage: x.cup_product(y) - h^{2,0} - sage: x.cup_product(x) - 0 - - sage: one = T.cohomology_with_basis(0, QQ).basis()[0] - sage: x.cup_product(one) - h^{1,0} - sage: one.cup_product(y) == y - True - sage: one.cup_product(one) - h^{0,0} - sage: x.cup_product(y) + y.cup_product(x) - 0 - - This also works with cubical complexes:: - - sage: T = cubical_complexes.Torus() - sage: x,y = list(T.cohomology_with_basis(1, QQ).basis()) - sage: x.cup_product(y) - -h^{2,0} - sage: x.cup_product(x) - 0 - - and `\Delta`-complexes:: - - sage: T_d = delta_complexes.Torus() - sage: a,b = T_d.cohomology_with_basis(1, QQ).gens() - sage: a.cup_product(b) - h^{2,0} - sage: b.cup_product(a) - -h^{2,0} - sage: RP2 = delta_complexes.RealProjectivePlane() - sage: w = RP2.cohomology_with_basis(1, GF(2)).gens()[0] - sage: w.cup_product(w) + sage: H = RP3.cohomology_ring(GF(2)) + sage: c = H.basis()[1,0] + sage: c.cup_product(c) h^{2,0} + sage: c * c * c + h^{3,0} - A non-connected example:: - - sage: K = cubical_complexes.Torus().disjoint_union(cubical_complexes.Torus()) - sage: a,b,c,d = K.cohomology_with_basis(1, QQ).gens() - sage: x,y = K.cohomology_with_basis(0, QQ).gens() - sage: a.cup_product(x) == a - True - sage: a.cup_product(y) - 0 - sage: K.cohomology_ring(QQ).is_unitary() # long time - True - """ - scomplex = self.parent().complex() - base_ring = self.base_ring() - if not (scomplex == other.parent().complex() - and self.parent()._cohomology - and other.parent()._cohomology): - raise ValueError('these are not cohomology classes from the same complex') - deg_left = self.parent().degree() - deg_right = other.parent().degree() - deg_tot = deg_left + deg_right - result = [] - for gamma in scomplex.homology_with_basis(deg_tot, base_ring).basis(): - gamma_coeff = base_ring.zero() - for cell, coeff in gamma.to_cycle(): - if hasattr(cell, 'alexander_whitney'): - # Simplicial and cubical case: each cell has a - # method 'alexander_whitney' which computes - # the appropriate faces. - for (c, left_cell, right_cell) in cell.alexander_whitney(deg_left): - left = scomplex.n_chains(deg_left, base_ring)(left_cell) - right = scomplex.n_chains(deg_right, base_ring)(right_cell) - gamma_coeff += c * coeff * self.to_cycle().eval(left) * other.to_cycle().eval(right) - else: - # Delta complex case: each "cell" in n_chains - # is just a pair (integer, tuple), where the - # integer is its index in the list, and the - # jth entry of the tuple is the index of its - # jth face in the list of (n-1)-chains. Use - # this data to compute the appropriate faces - # by hand. - left_cell = cell - for i in range(deg_tot, deg_left, -1): - idx = left_cell[1][i] - left_cell = (idx, scomplex.n_cells(i-1)[idx]) - right_cell = cell - for i in range(deg_tot, deg_right, -1): - idx = right_cell[1][0] - right_cell = (idx, scomplex.n_cells(i-1)[idx]) - left = scomplex.n_chains(deg_left, base_ring)(left_cell) - right = scomplex.n_chains(deg_right, base_ring)(right_cell) - gamma_coeff += coeff * self.to_cycle().eval(left) * other.to_cycle().eval(right) - result.append((gamma.leading_support(), gamma_coeff)) - return scomplex.cohomology_with_basis(deg_tot, base_ring).sum_of_terms(result) - - __mul__ = cup_product - - def __pow__(self, n): - r""" - This element raised to the ``n``-th power - - INPUT: - - - ``n`` -- a non-negative integer - - If ``n`` is positive, this takes the iterated cup product - of the element with itself. If ``n`` is zero, this returns - the unit element of the cohomology ring (even if the - complex is not connected). - - EXAMPLES:: + We can also take powers:: sage: RP2 = simplicial_complexes.RealProjectivePlane() - sage: a = RP2.cohomology_with_basis(1, GF(2)).gens()[0] + sage: a = RP2.cohomology_ring(GF(2)).basis()[1,0] sage: a**0 h^{0,0} sage: a**1 @@ -456,29 +588,14 @@ def __pow__(self, n): sage: a**3 0 - sage: a**(-2) - Traceback (most recent call last): - ... - ValueError: the power must be non-negative - A non-connected example:: sage: K = cubical_complexes.Torus().disjoint_union(cubical_complexes.Sphere(2)) - sage: a,b = K.cohomology_with_basis(2, QQ).gens() + sage: a,b = K.cohomology_ring(QQ).basis(2) sage: a**0 h^{0,0} + h^{0,1} """ - if not self.parent()._cohomology: - raise ValueError('this is not a cohomology class') - if n < 0: - raise ValueError('the power must be non-negative') - if n == 0: - scomplex = self.parent().complex() - zeroth_cohomology = scomplex.cohomology_with_basis(0, self.base_ring()) - return sum(zeroth_cohomology.gens()) - if n == 1: - return self - return self.cup_product(self**(n-1)) + return self * other def Sq(self, i): r""" @@ -496,29 +613,30 @@ def Sq(self, i): This cohomology operation is only defined in characteristic 2. - Algorithm: see González-Díaz and Réal [G-DR99]_, Corollary - 3.2. + Algorithm: see González-Díaz and Réal [G-DR99]_, + Corollary 3.2. EXAMPLES:: sage: RP2 = simplicial_complexes.RealProjectiveSpace(2) - sage: x = RP2.cohomology_with_basis(1, GF(2)).basis()[0] + sage: x = RP2.cohomology_ring(GF(2)).basis()[1,0] sage: x.Sq(1) h^{2,0} sage: K = RP2.suspension() sage: K.set_immutable() - sage: y = K.cohomology_with_basis(2, GF(2)).basis()[0] + sage: y = K.cohomology_ring(GF(2)).basis()[2,0] sage: y.Sq(1) h^{3,0} sage: RP4 = simplicial_complexes.RealProjectiveSpace(4) - sage: x = RP4.cohomology_with_basis(1, GF(2)).basis()[0] # long time - sage: y = RP4.cohomology_with_basis(2, GF(2)).basis()[0] # long time - sage: z = RP4.cohomology_with_basis(3, GF(2)).basis()[0] # long time + sage: H = RP4.cohomology_ring(GF(2)) + sage: x = H.basis()[1,0] + sage: y = H.basis()[2,0] + sage: z = H.basis()[3,0] sage: x.Sq(1) # long time h^{2,0} - sage: y.Sq(1) # long time + sage: y.Sq(1) 0 sage: y.Sq(2) # long time h^{4,0} @@ -528,59 +646,57 @@ def Sq(self, i): TESTS:: sage: T = cubical_complexes.Torus() - sage: x = T.cohomology_with_basis(1, GF(2)).basis()[0] + sage: x = T.cohomology_ring(GF(2)).basis()[1,0] sage: x.Sq(1) Traceback (most recent call last): ... NotImplementedError: Steenrod squares are only implemented for simplicial complexes sage: S2 = simplicial_complexes.Sphere(2) - sage: x = S2.cohomology_with_basis(2, GF(7)).basis()[0] + sage: x = S2.cohomology_ring(GF(7)).basis()[2,0] sage: x.Sq(1) Traceback (most recent call last): ... ValueError: Steenrod squares are only defined in characteristic 2 """ - scomplex = self.parent().complex() + P = self.parent() + scomplex = P.complex() if not isinstance(scomplex, SimplicialComplex): raise NotImplementedError('Steenrod squares are only implemented for simplicial complexes') - base_ring = self.base_ring() + base_ring = P.base_ring() if base_ring.characteristic() != 2: raise ValueError('Steenrod squares are only defined in characteristic 2') # We keep the same notation as in [G-DR99]. - j = self.parent().degree() - m = j+i # The trivial cases: if i == 0: # Sq^0 is the identity. return self - target = scomplex.cohomology_with_basis(m, base_ring) - if target.dimension() == 0: - return target.zero() - if i > j: - return target.zero() + j = self.degree() + m = j + i + if not P._graded_indices.get(m, []) or i > j: + return P.zero() if i == j: return self.cup_product(self) - n = j-i + n = j - i # Now assemble the indices over which the sums take place. # S(n) is defined to be floor((m+1)/2) + floor(n/2). S_n = (m+1)//2 + n//2 if n == 0: sums = [[S_n]] else: - sums = [] - for i_n in range(S_n, m+1): - sums.extend([[i_n] + _ for _ in sum_indices(n-1, i_n, S_n)]) + sums = [[i_n] + l for i_n in range(S_n, m+1) + for l in sum_indices(n-1, i_n, S_n)] # At this point, 'sums' is a list of lists of the form # [i_n, i_{n-1}, ..., i_0]. (It is reversed from the # obvious order because this is closer to the order in # which the face maps will be applied.) Now we sum over - # these, according to the formula in [G-DR99], Corollary - # 3.2. - result = [] + # these, according to the formula in [G-DR99], Corollary 3.2. + result = {} cycle = self.to_cycle() - for gamma in scomplex.homology_with_basis(m, base_ring).basis(): + n_chains = scomplex.n_chains(j, base_ring) + H = scomplex.homology_with_basis(base_ring) + for gamma_index in H._graded_indices.get(m, []): gamma_coeff = base_ring.zero() - for cell, coeff in gamma.to_cycle(): + for cell, coeff in H._to_cycle_on_basis((m, gamma_index)): for indices in sums: indices = list(indices) left = cell @@ -589,11 +705,11 @@ def Sq(self, i): if not m % 2: left_endpoint = m while indices: - right_endpoint = indices[0]-1 + right_endpoint = indices[0] - 1 for k in range(left_endpoint, indices.pop(0), -1): left = left.face(k) try: - left_endpoint = indices[0]-1 + left_endpoint = indices[0] - 1 for k in range(right_endpoint, indices.pop(0), -1): right = right.face(k) except IndexError: @@ -603,11 +719,11 @@ def Sq(self, i): else: right_endpoint = m while indices: - left_endpoint = indices[0]-1 + left_endpoint = indices[0] - 1 try: for k in range(right_endpoint, indices.pop(0), -1): right = right.face(k) - right_endpoint = indices[0]-1 + right_endpoint = indices[0] - 1 except IndexError: pass for k in range(left_endpoint, indices.pop(0), -1): @@ -615,12 +731,12 @@ def Sq(self, i): for k in range(right_endpoint, -1, -1): right = right.face(k) - left = scomplex.n_chains(j, base_ring)(left) - right = scomplex.n_chains(j, base_ring)(right) + left = n_chains(left) + right = n_chains(right) gamma_coeff += coeff * cycle.eval(left) * cycle.eval(right) - result.append((gamma.leading_support(), gamma_coeff)) - return scomplex.cohomology_with_basis(m, base_ring).sum_of_terms(result) - + if gamma_coeff != base_ring.zero(): + result[(m, gamma_index)] = gamma_coeff + return P.sum_of_terms(result) def sum_indices(k, i_k_plus_one, S_k_plus_one): r""" @@ -659,8 +775,6 @@ def sum_indices(k, i_k_plus_one, S_k_plus_one): S_k = -S_k_plus_one + k//2 + (k+1)//2 + i_k_plus_one if k == 0: return [[S_k]] - ans = [] - for i_k in range(S_k, i_k_plus_one): - ans.extend([[i_k] + _ for _ in sum_indices(k-1, i_k, S_k)]) - return ans + return [[i_k] + l for i_k in range(S_k, i_k_plus_one) + for l in sum_indices(k-1, i_k, S_k)] From 37517531687fffbe421b2d882e3073dcb13144e1 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 13 Oct 2015 15:08:36 -0500 Subject: [PATCH 1443/1872] Making Sq work for inhomogeneous elements. --- .../homology_vector_space_with_basis.py | 148 ++++++++++-------- 1 file changed, 81 insertions(+), 67 deletions(-) diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index f04aa1eb713..0a50bfb7fb2 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -384,7 +384,6 @@ def to_cycle(self): """ if not self.is_homogeneous(): raise ValueError("only defined for homogeneous elements") - deg = self.degree() return sum(c * self.parent()._to_cycle_on_basis(i) for i,c in self) class CohomologyRing(HomologyVectorSpaceWithBasis): @@ -545,7 +544,7 @@ def product_on_basis(self, li, ri): gamma_coeff += coeff * left_cycle.eval(left) * right_cycle.eval(right) if gamma_coeff != base_ring.zero(): result[(deg_tot, gamma_index)] = gamma_coeff - return self._from_dict(result) + return self._from_dict(result, remove_zeros=False) class Element(HomologyVectorSpaceWithBasis.Element): def cup_product(self, other): @@ -670,73 +669,88 @@ def Sq(self, i): if i == 0: # Sq^0 is the identity. return self - j = self.degree() - m = j + i - if not P._graded_indices.get(m, []) or i > j: - return P.zero() - if i == j: - return self.cup_product(self) - n = j - i - # Now assemble the indices over which the sums take place. - # S(n) is defined to be floor((m+1)/2) + floor(n/2). - S_n = (m+1)//2 + n//2 - if n == 0: - sums = [[S_n]] - else: - sums = [[i_n] + l for i_n in range(S_n, m+1) - for l in sum_indices(n-1, i_n, S_n)] - # At this point, 'sums' is a list of lists of the form - # [i_n, i_{n-1}, ..., i_0]. (It is reversed from the - # obvious order because this is closer to the order in - # which the face maps will be applied.) Now we sum over - # these, according to the formula in [G-DR99], Corollary 3.2. - result = {} - cycle = self.to_cycle() - n_chains = scomplex.n_chains(j, base_ring) + + # Construct each graded component of ``self`` + ret = P.zero() H = scomplex.homology_with_basis(base_ring) - for gamma_index in H._graded_indices.get(m, []): - gamma_coeff = base_ring.zero() - for cell, coeff in H._to_cycle_on_basis((m, gamma_index)): - for indices in sums: - indices = list(indices) - left = cell - right = cell - # Since we are working with a simplicial complex, 'cell' is a simplex. - if not m % 2: - left_endpoint = m - while indices: - right_endpoint = indices[0] - 1 - for k in range(left_endpoint, indices.pop(0), -1): - left = left.face(k) - try: - left_endpoint = indices[0] - 1 - for k in range(right_endpoint, indices.pop(0), -1): - right = right.face(k) - except IndexError: - pass - for k in range(right_endpoint, -1, -1): - right = right.face(k) - else: - right_endpoint = m - while indices: - left_endpoint = indices[0] - 1 - try: - for k in range(right_endpoint, indices.pop(0), -1): - right = right.face(k) + deg_comp = {} + for index,coeff in self: + d = deg_comp.get(index[0], {}) + d[index] = coeff + deg_comp[index[0]] = d + + # Do the square on each graded componenet of ``self``. + for j in deg_comp: + # Make it into an actual element + m = j + i + if not P._graded_indices.get(m, []) or i > j: + continue + elt = P._from_dict(deg_comp[j], remove_zeros=False) + if i == j: + ret += elt.cup_product(elt) + continue + + n = j - i + # Now assemble the indices over which the sums take place. + # S(n) is defined to be floor((m+1)/2) + floor(n/2). + S_n = (m+1) // 2 + n // 2 + if n == 0: + sums = [[S_n]] + else: + sums = [[i_n] + l for i_n in range(S_n, m+1) + for l in sum_indices(n-1, i_n, S_n)] + # At this point, 'sums' is a list of lists of the form + # [i_n, i_{n-1}, ..., i_0]. (It is reversed from the + # obvious order because this is closer to the order in + # which the face maps will be applied.) Now we sum over + # these, according to the formula in [G-DR99], Corollary 3.2. + result = {} + cycle = elt.to_cycle() + n_chains = scomplex.n_chains(j, base_ring) + for gamma_index in H._graded_indices.get(m, []): + gamma_coeff = base_ring.zero() + for cell, coeff in H._to_cycle_on_basis((m, gamma_index)): + for indices in sums: + indices = list(indices) + left = cell + right = cell + # Since we are working with a simplicial complex, 'cell' is a simplex. + if not m % 2: + left_endpoint = m + while indices: right_endpoint = indices[0] - 1 - except IndexError: - pass - for k in range(left_endpoint, indices.pop(0), -1): - left = left.face(k) - for k in range(right_endpoint, -1, -1): - right = right.face(k) - - left = n_chains(left) - right = n_chains(right) - gamma_coeff += coeff * cycle.eval(left) * cycle.eval(right) - if gamma_coeff != base_ring.zero(): - result[(m, gamma_index)] = gamma_coeff - return P.sum_of_terms(result) + for k in range(left_endpoint, indices.pop(0), -1): + left = left.face(k) + try: + left_endpoint = indices[0] - 1 + for k in range(right_endpoint, indices.pop(0), -1): + right = right.face(k) + except IndexError: + pass + for k in range(right_endpoint, -1, -1): + right = right.face(k) + else: + right_endpoint = m + while indices: + left_endpoint = indices[0] - 1 + try: + for k in range(right_endpoint, indices.pop(0), -1): + right = right.face(k) + right_endpoint = indices[0] - 1 + except IndexError: + pass + for k in range(left_endpoint, indices.pop(0), -1): + left = left.face(k) + for k in range(right_endpoint, -1, -1): + right = right.face(k) + + left = n_chains(left) + right = n_chains(right) + gamma_coeff += coeff * cycle.eval(left) * cycle.eval(right) + if gamma_coeff != base_ring.zero(): + result[(m, gamma_index)] = gamma_coeff + ret += P._from_dict(result, remove_zeros=False) + return ret def sum_indices(k, i_k_plus_one, S_k_plus_one): r""" From 6cee4b8edc2ee86f182c6ff38a533cd48c6bebd2 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 13 Oct 2015 16:07:35 -0500 Subject: [PATCH 1444/1872] We must use defined variable names, even for error messages. --- src/sage/groups/matrix_gps/morphism.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/matrix_gps/morphism.py b/src/sage/groups/matrix_gps/morphism.py index 775fb239b90..2d4a0e67d47 100644 --- a/src/sage/groups/matrix_gps/morphism.py +++ b/src/sage/groups/matrix_gps/morphism.py @@ -109,6 +109,19 @@ def __init__(self, homset, imgsH, check=True): sage: G = MatrixGroup([MS([3,0,0,1])]) sage: a = G.gens()[0]^2 sage: phi = G.hom([a]) + + TESTS: + + Check that :trac:`19406` is fixed:: + + sage: G = GL(2, GF(3)) + sage: H = GL(3, GF(2)) + sage: mat1 = H([[-1,0,0],[0,0,-1],[0,-1,0]]) + sage: mat2 = H([[1,1,1],[0,0,-1],[-1,0,0]]) + sage: phi = G.hom([mat1, mat2]) + Traceback (most recent call last): + ... + TypeError: images do not define a group homomorphism """ MatrixGroupMorphism.__init__(self, homset) # sets the parent from sage.libs.gap.libgap import libgap @@ -118,7 +131,7 @@ def __init__(self, homset, imgsH, check=True): imgs = [to_libgap(x) for x in imgsH] self._phi = phi = libgap.GroupHomomorphismByImages(G.gap(), H.gap(), gens, imgs) if not phi.IsGroupHomomorphism(): - raise ValueError('The map '+str(gensG)+'-->'+str(imgsH)+' is not a homomorphism') + raise ValueError('the map {}-->{} is not a homomorphism'.format(G.gens(), imgsH)) def gap(self): """ From eba7c6324b196e10b074b6deaa1997786eb2d249 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 13 Oct 2015 16:46:49 -0500 Subject: [PATCH 1445/1872] Fixing some homset setup for (matrix) groups. --- src/sage/groups/group_homset.py | 5 +---- src/sage/groups/matrix_gps/homset.py | 9 ++++----- src/sage/groups/matrix_gps/matrix_group.py | 19 ++++++++++++++----- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/sage/groups/group_homset.py b/src/sage/groups/group_homset.py index 6e26f9d10a0..e65ecd27d9c 100644 --- a/src/sage/groups/group_homset.py +++ b/src/sage/groups/group_homset.py @@ -14,9 +14,6 @@ from sage.categories.all import HomsetWithBase, Groups import sage.rings.integer_ring -GROUPS = Groups() - - def is_GroupHomset(H): return isinstance(H, GroupHomset_generic) @@ -30,7 +27,7 @@ class GroupHomset_generic(HomsetWithBase): is undefined and morphism.GroupHomomorphism_im_gens is undefined. """ def __init__(self, G, H): - HomsetWithBase.__init__(self, G, H, GROUPS, sage.rings.integer_ringer.ZZ) + HomsetWithBase.__init__(self, G, H, Groups(), sage.rings.integer_ringer.ZZ) def _repr_(self): return "Set of Homomorphisms from %s to %s"%(self.domain(), self.codomain()) diff --git a/src/sage/groups/matrix_gps/homset.py b/src/sage/groups/matrix_gps/homset.py index 0365797e4a5..f62de6173af 100644 --- a/src/sage/groups/matrix_gps/homset.py +++ b/src/sage/groups/matrix_gps/homset.py @@ -44,15 +44,15 @@ def is_MatrixGroupHomset(x): class MatrixGroupHomset(GroupHomset_generic): - def __init__(self, G, H): + def __init__(self, G, H, category=None): r""" Return the homset of two matrix groups. INPUT: - - ``G`` -- a matrix group. + - ``G`` -- a matrix group - - ``H`` -- a matrix group. + - ``H`` -- a matrix group OUTPUT: @@ -74,9 +74,8 @@ def __init__(self, G, H): [4 1], [0 1] ) """ - from sage.categories.groups import Groups from sage.categories.homset import HomsetWithBase - HomsetWithBase.__init__(self, G, H, Groups(), G.base_ring()) + HomsetWithBase.__init__(self, G, H, category, G.base_ring()) def __call__(self, im_gens, check=True): """ diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index a40675cb775..4195fa41e8a 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -400,9 +400,9 @@ def _Hom_(self, G, cat=None): INPUT: - - ``G`` -- group. The codomain. + - ``G`` -- group; the codomain - - ``cat`` -- a category. Must be unset. + - ``cat`` -- category; must be unset OUTPUT: @@ -420,13 +420,22 @@ def _Hom_(self, G, cat=None): [1 0] [1 2] [0 1], [3 4] ) + + TESTS: + + Check that :trac:`19407` is fixed:: + + sage: G = GL(2, GF(2)) + sage: H = GL(3, ZZ) + sage: Hom(G, H) + Set of Homomorphisms from General Linear Group of degree 2 + over Finite Field of size 2 to General Linear Group of degree 3 + over Integer Ring """ - if not (cat is None or (cat is G.category() and cat is self.category())): - raise TypeError if not is_MatrixGroup(G): raise TypeError("G (=%s) must be a matrix group."%G) import homset - return homset.MatrixGroupHomset(self, G) + return homset.MatrixGroupHomset(self, G, cat) def hom(self, x): """ From 9ee7cfe063e57d6266000370b37f6539b81153a2 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 14 Oct 2015 12:34:33 +0200 Subject: [PATCH 1446/1872] Optimize ComplexIntervalFieldElement.__pow__ --- src/sage/libs/flint/fmpz.pxd | 4 ++ src/sage/rings/complex_interval.pyx | 69 ++++++++++++++++++----------- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/sage/libs/flint/fmpz.pxd b/src/sage/libs/flint/fmpz.pxd index dc497331ce0..99e748be1a4 100644 --- a/src/sage/libs/flint/fmpz.pxd +++ b/src/sage/libs/flint/fmpz.pxd @@ -1,3 +1,5 @@ +# distutils: libraries = flint + from libc.stdio cimport FILE from sage.libs.gmp.types cimport mpz_t from sage.libs.flint.types cimport * @@ -45,6 +47,8 @@ cdef extern from "flint/fmpz.h": int fmpz_fits_si(fmpz_t f) void fmpz_zero(fmpz_t f) void fmpz_one(fmpz_t f) + void fmpz_setbit(fmpz_t f, ulong i) + int fmpz_tstbit(fmpz_t f, ulong i) # Input and output int fmpz_read(fmpz_t) diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index d59017017e4..470ab14f8a1 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -41,7 +41,8 @@ heavily modified: include "sage/ext/interrupt.pxi" -from cpython.number cimport PyNumber_Index +from sage.libs.gmp.mpz cimport mpz_sgn, mpz_cmpabs_ui +from sage.libs.flint.fmpz cimport * from sage.structure.element cimport FieldElement, RingElement, Element, ModuleElement from complex_number cimport ComplexNumber @@ -52,7 +53,7 @@ from sage.rings.integer cimport Integer import infinity cimport real_mpfi cimport real_mpfr -from sage.libs.pari.all import pari_gen +from sage.libs.pari.gen cimport gen as pari_gen cdef double LOG_TEN_TWO_PLUS_EPSILON = 3.321928094887363 # a small overestimate of log(10,2) @@ -761,8 +762,9 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): TESTS:: - sage: [CIF(2) ^ RDF(i) for i in range(-2,3)] - [0.2500000000?, 0.5000000000?, 1, 2, 4] + sage: CIF = ComplexIntervalField(7) + sage: [CIF(2) ^ RDF(i) for i in range(-5,6)] + [0.03125?, 0.06250?, 0.1250?, 0.2500?, 0.5000?, 1, 2, 4, 8, 16, 32] sage: pow(CIF(1), CIF(1), CIF(1)) Traceback (most recent call last): ... @@ -771,51 +773,66 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): if modulus is not None: raise TypeError("pow() 3rd argument not allowed unless all arguments are integers") - cdef ComplexIntervalFieldElement z, z2 + cdef ComplexIntervalFieldElement z, z2, t = None z = self - # This conversion code is the same as generic_power_c() in - # sage/structure/element.pyx - try: - e = PyNumber_Index(right) - except TypeError: + # Convert right to an integer + if not isinstance(right, Integer): try: - e = int(Integer(right)) + right = Integer(right) except TypeError: # Exponent is really not an integer return (z.log() * z._parent(right)).exp() - if e <= 1: - if e == 0: - return z._parent.one() - if e < 0: - e = -e - z = ~z - if e == 1: - return z - + cdef int s = mpz_sgn((right).value) + if s == 0: + return z._parent.one() + elif s < 0: + z = ~z + if not mpz_cmpabs_ui((right).value, 1): + return z + + # Convert exponent to fmpz_t + cdef fmpz_t e + fmpz_init(e) + fmpz_set_mpz(e, (right).value) + fmpz_abs(e, e) + + # Now we know that e >= 2. # Use binary powering with special formula for squares. # Handle first bit more efficiently: - if e & 1: + if fmpz_tstbit(e, 0): res = z else: res = z._parent.one() - e >>= 1 + fmpz_tdiv_q_2exp(e, e, 1) # e >>= 1 - while e: + # Allocate a temporary ComplexIntervalFieldElement + z2 = z._new() + + while True: # Compute z2 = z^2 using the formula # (a + bi)^2 = (a^2 - b^2) + 2abi - z2 = z._new() mpfi_sqr(z2.__re, z.__re) # a^2 mpfi_sqr(z2.__im, z.__im) # b^2 mpfi_sub(z2.__re, z2.__re, z2.__im) # a^2 - b^2 mpfi_mul(z2.__im, z.__re, z.__im) # ab mpfi_mul_2ui(z2.__im, z2.__im, 1) # 2ab z = z2 - if e & 1: + if fmpz_tstbit(e, 0): res *= z - e >>= 1 + fmpz_tdiv_q_2exp(e, e, 1) # e >>= 1 + if fmpz_is_zero(e): + break + + # Swap temporary elements z2 and t (allocate t first if needed) + if t is not None: + z2 = t + else: + z2 = z2._new() + t = z + fmpz_clear(e) return res def _magma_init_(self, magma): From 23b24efe0f7355f312b5b38f9cf8d520240903a3 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Wed, 14 Oct 2015 14:24:34 +0200 Subject: [PATCH 1447/1872] 17624: convert factorization unit to SR --- 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 061951f8571..488373d04f3 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -299,7 +299,7 @@ cdef class SymbolicRing(CommutativeRing): GEx_construct_pyobject(exp, x) elif isinstance(x, Factorization): from sage.misc.all import prod - return prod([SR(p)**e for p,e in x], SR.one()) * x.unit() + return prod([SR(p)**e for p,e in x], SR.one()) * SR(x.unit()) else: raise TypeError From 9d1432aa35cf5005a6431c0911b2e96b0de615f7 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Wed, 14 Oct 2015 14:55:27 +0200 Subject: [PATCH 1448/1872] 17426: cosmetics --- 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 488373d04f3..c3adf6750b8 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -299,7 +299,7 @@ cdef class SymbolicRing(CommutativeRing): GEx_construct_pyobject(exp, x) elif isinstance(x, Factorization): from sage.misc.all import prod - return prod([SR(p)**e for p,e in x], SR.one()) * SR(x.unit()) + return prod([SR(p)**e for p,e in x], SR(x.unit()) else: raise TypeError From 9c461e3f14d5d48fffc2bb59ee17e37a8afff125 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Wed, 14 Oct 2015 14:59:05 +0200 Subject: [PATCH 1449/1872] 17426: fix 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 c3adf6750b8..439d02de32c 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -299,7 +299,7 @@ cdef class SymbolicRing(CommutativeRing): GEx_construct_pyobject(exp, x) elif isinstance(x, Factorization): from sage.misc.all import prod - return prod([SR(p)**e for p,e in x], SR(x.unit()) + return prod([SR(p)**e for p,e in x], SR(x.unit())) else: raise TypeError From 1cdbd7829bc8428f6d994ea8234811a2d384fdb3 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Wed, 14 Oct 2015 17:00:28 +0200 Subject: [PATCH 1450/1872] Trac 19409: require prec >= 0 when creating power series --- src/sage/modular/modform/element.py | 8 ++++--- .../rings/laurent_series_ring_element.pyx | 5 +++- src/sage/rings/power_series_ring.py | 24 +++++++++++++++++++ src/sage/rings/power_series_ring_element.pyx | 10 ++++++-- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index b85a6573941..afd26301a54 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -466,17 +466,19 @@ def q_expansion(self, prec=None): O(q^1) sage: f.q_expansion(0) O(q^0) + sage: f.q_expansion(-1) + Traceback (most recent call last): + ... + ValueError: prec (= -1) must be non-negative """ if prec is None: prec = self.parent().prec() prec = rings.Integer(prec) - if prec < 0: - raise ValueError("prec (=%s) must be at least 0"%prec) try: current_prec, f = self.__q_expansion except AttributeError: current_prec = 0 - f = self.parent()._q_expansion_ring()(0, -1) + f = self.parent()._q_expansion_ring()(0, 0) if current_prec == prec: return f diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 391991b4329..9be40ed2bd1 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -641,8 +641,11 @@ cdef class LaurentSeries(AlgebraElement): """ if prec == infinity or prec >= self.prec(): return self + P = self._parent + if not self: + return LaurentSeries(P, P.power_series_ring()(0, prec=0), prec) u = self.__u.add_bigoh(prec - self.__n) - return LaurentSeries(self._parent, u, self.__n) + return LaurentSeries(P, u, self.__n) def degree(self): """ diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index e11fdf7f779..ff081f23dd4 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -499,6 +499,15 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False, sage: R.category() Category of complete discrete valuation rings sage: TestSuite(R).run() + + It is checked that the default precision is non-negative + (see :trac:`19409`):: + + sage: PowerSeriesRing(ZZ, 'x', default_prec=-5) + Traceback (most recent call last): + ... + ValueError: default_prec (= -5) must be non-negative + """ R = PolynomialRing(base_ring, name, sparse=sparse) self.__poly_ring = R @@ -506,6 +515,9 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False, if default_prec is None: from sage.misc.defaults import series_precision default_prec = series_precision() + elif default_prec < 0: + raise ValueError("default_prec (= %s) must be non-negative" + % default_prec) self.__params = (base_ring, name, default_prec, sparse) if use_lazy_mpoly_ring and (is_MPolynomialRing(base_ring) or \ @@ -710,7 +722,19 @@ def _element_constructor_(self, f, prec=infinity, check=True): ... ArithmeticError: self is a not a power series + It is checked that the precision is non-negative + (see :trac:`19409`):: + + sage: PowerSeriesRing(ZZ, 'x')(1, prec=-5) + Traceback (most recent call last): + ... + ValueError: prec (= -5) must be non-negative + """ + if prec is not infinity: + prec = integer.Integer(prec) + if prec < 0: + raise ValueError("prec (= %s) must be non-negative" % prec) if isinstance(f, power_series_ring_element.PowerSeries) and f.parent() is self: if prec >= f.prec(): return f diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index ab3f67a20cf..70ba02e47a2 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -165,8 +165,6 @@ cdef class PowerSeries(AlgebraElement): """ AlgebraElement.__init__(self, parent) self.__is_gen = is_gen - if not (prec is infinity): - prec = int(prec) self._prec = prec def __hash__(self): @@ -1023,6 +1021,12 @@ cdef class PowerSeries(AlgebraElement): ... ZeroDivisionError: leading coefficient must be a unit + A test for the case where the precision is 0:: + + sage: R. = PowerSeriesRing(ZZ, default_prec=0) + sage: ~(1+x) + O(x^0) + AUTHORS: - David Harvey (2006-09-09): changed to use Newton's method @@ -1048,6 +1052,8 @@ cdef class PowerSeries(AlgebraElement): if prec is infinity: return self._parent(first_coeff, prec=prec) + elif not prec: + return self._parent(0, prec=0) A = self.truncate() R = A.parent() # R is the corresponding polynomial ring From 925cf158855498ec46e1f8b330378a9a210bb65c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 18:25:27 +0200 Subject: [PATCH 1451/1872] Trac #19083: Keep longer versions of previous versions --- src/sage/rings/asymptotic/misc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 134c6701a77..774abedb0ad 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -37,12 +37,14 @@ def repr_short_to_parent(s): INPUT: - A string. + - ``s`` -- a string, short representation of a parent. OUTPUT: A parent. + The possible short representations are shown in the examples below. + EXAMPLES:: sage: from sage.rings.asymptotic.misc import repr_short_to_parent @@ -87,7 +89,7 @@ def parent_to_repr_short(P): INPUT: - A parent. + - ``P`` -- a parent. OUTPUT: From c9ff6433a270ce363f08fc2249118c4839759790 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 18:25:47 +0200 Subject: [PATCH 1452/1872] Trac #19083: Adapt description to generalized function --- src/sage/rings/asymptotic/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 774abedb0ad..d4748a27208 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -155,7 +155,7 @@ def abbreviate(P): def split_str_by_op(string, op, strip_parentheses=True): r""" Split the given string into a tuple of substrings arising by - splitting by '*' and taking care of parentheses. + splitting by ``op`` and taking care of parentheses. INPUT: From d4df04d34a1a28f0f2183e2ff0d50a79aae70bd0 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 18:26:51 +0200 Subject: [PATCH 1453/1872] Trac #19083: Add/remove missing/superfluous "TESTS::" and "EXAMPLES::" --- src/sage/rings/asymptotic/growth_group.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 7a817bd64f3..8036a291ad4 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -174,7 +174,7 @@ Some Examples ^^^^^^^^^^^^^ -EXAMPLES:: +:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G_x = GrowthGroup('x^ZZ'); G_x @@ -1630,6 +1630,8 @@ def _create_element_via_parent_(self, raw_element): An element. + EXAMPLES:: + sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') sage: G._create_element_via_parent_(3).parent() @@ -3472,8 +3474,6 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): (Growth Group (e^(n*log(n)))^ZZ * (e^n)^ZZ * n^ZZ * log(n)^ZZ, (e^(n*log(n)), e^n, n, log(n))) - TESTS:: - sage: TestSuite(GrowthGroup('x^ZZ')).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass From e7f7708eb6c046623c00c98456e59a2aa279a4f8 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 18:27:52 +0200 Subject: [PATCH 1454/1872] Trac #19083: minor language issues --- src/sage/rings/asymptotic/growth_group.py | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 8036a291ad4..e1c9efbcd22 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -572,7 +572,7 @@ def extract_variable_names(s): def is_lt_one(self): r""" - Return if this element is less than `1`. + Return whether this element is less than `1`. INPUT: @@ -1016,7 +1016,7 @@ def __invert__(self): def __eq__(self, other): r""" - Return if this growth element is equal to ``other``. + Return whether this growth element is equal to ``other``. INPUT: @@ -1076,7 +1076,7 @@ def __eq__(self, other): def _eq_(self, other): r""" - Return if this :class:`GenericGrowthElement` is equal to ``other``. + Return whether this :class:`GenericGrowthElement` is equal to ``other``. INPUT: @@ -1109,7 +1109,7 @@ def _eq_(self, other): def __ne__(self, other): r""" - Return if this growth element is not equal to ``other``. + Return whether this growth element is not equal to ``other``. INPUT: @@ -1143,7 +1143,7 @@ def __ne__(self, other): def __le__(self, other): r""" - Return if this growth element is at most (less than or equal + Return whether this growth element is at most (less than or equal to) ``other``. INPUT: @@ -1186,7 +1186,7 @@ def __le__(self, other): def _le_(self, other): r""" - Return if this :class:`GenericGrowthElement` is at most (less + Return whether this :class:`GenericGrowthElement` is at most (less than or equal to) ``other``. INPUT: @@ -1321,7 +1321,7 @@ class GenericGrowthGroup( - ``ignore_variables`` -- (default: ``None``) a tuple (or other iterable) of strings. The specified names are not considered as - a variable. + variables. .. NOTE:: @@ -1650,7 +1650,7 @@ def _create_element_via_parent_(self, raw_element): def le(self, left, right): r""" - Return if the growth of ``left`` is at most (less than or + Return whether the growth of ``left`` is at most (less than or equal to) the growth of ``right``. INPUT: @@ -1811,7 +1811,7 @@ def _convert_(self, data): def _coerce_map_from_(self, S): r""" - Return if ``S`` coerces into this growth group. + Return whether ``S`` coerces into this growth group. INPUT: @@ -2523,7 +2523,7 @@ def _rpow_element_(self, base): def _le_(self, other): r""" - Return if this :class:`MonomialGrowthElement` is at most + Return whether this :class:`MonomialGrowthElement` is at most (less than or equal to) ``other``. INPUT: @@ -3048,13 +3048,13 @@ def __pow__(self, exponent): INPUT: - - ``exponent`` -- a number. This can anything that is valid to be + - ``exponent`` -- a number. This can be anything that is valid to be on the right hand side of ``*`` with an elements of the parent's base. OUTPUT: - The result of this exponentiation a :class:`ExponentialGrowthElement`. + The result of this exponentiation as an :class:`ExponentialGrowthElement`. EXAMPLES:: @@ -3086,7 +3086,7 @@ def _log_factor_(self, base=None): A tuple of pairs, where the first entry is either a growth element or something out of which we can construct a growth element - and the second a multiplicative coefficient. + and the second is a multiplicative coefficient. TESTS:: @@ -3115,7 +3115,7 @@ def _log_factor_(self, base=None): def _le_(self, other): r""" - Return if this :class:`ExponentialGrowthElement` is at most + Return whether this :class:`ExponentialGrowthElement` is at most (less than or equal to) ``other``. INPUT: From b997a0ea78ff54dc6e2d2663c45fcfe61241d1b0 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 18:28:08 +0200 Subject: [PATCH 1455/1872] Trac #19083: incomplete formatting --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index e1c9efbcd22..53b0ef74b83 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2497,7 +2497,7 @@ def _rpow_element_(self, base): sage: x._rpow_element_(2) Traceback (most recent call last): ... - ValueError: Variable %s is not a log of something. + ValueError: Variable x is not a log of something. sage: G = GrowthGroup('log(x)^ZZ') sage: lx = G(raw_element=1); lx log(x) @@ -2508,7 +2508,7 @@ def _rpow_element_(self, base): """ var = str(self.parent()._var_) if not(var.startswith('log(') and self.exponent.is_one()): - raise ValueError('Variable %s is not a log of something.') + raise ValueError('Variable %s is not a log of something.' % (var,)) new_var = var[4:-1] if base == 'e': from sage.rings.integer_ring import ZZ From e7ffdf39c53494a2c266fa264346abd19ed5e365 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 18:28:23 +0200 Subject: [PATCH 1456/1872] Trac #19083: additional doctests --- src/sage/rings/asymptotic/growth_group.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 53b0ef74b83..39ecbb0ae9e 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2388,6 +2388,12 @@ def __invert__(self): x^(-2) sage: e2 == ~e1 True + sage: Q = GrowthGroup('x^NN'); Q + Growth Group x^((Non negative integer semiring)) + sage: e3 = ~Q('x'); e3 + x^(-1) + sage: e3.parent() + Growth Group x^ZZ """ return self.parent()._create_element_via_parent_(-self.exponent) @@ -2417,6 +2423,10 @@ def __pow__(self, exponent): x^(7/2) sage: (a^(1/2)).parent() Growth Group x^QQ + sage: a^(1/7) + x + sage: (a^(1/7)).parent() + Growth Group x^QQ sage: P = GrowthGroup('x^QQ') sage: b = P.gen()^(7/2); b x^(7/2) From ccf7dcad7f22efb681be2fb49bc8921a30e1de34 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 18:28:41 +0200 Subject: [PATCH 1457/1872] Trac #19083: additional link --- src/sage/rings/asymptotic/growth_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 39ecbb0ae9e..77b001d49c5 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1335,7 +1335,8 @@ class GenericGrowthGroup( .. SEEALSO:: - :class:`MonomialGrowthGroup` + :class:`MonomialGrowthGroup`, + :class:`ExponentialGrowthGroup` """ # TODO: implement some sort of 'assume', where basic assumptions # for the variables can be stored. --> within the cartesian product From 442ac03673f69ed13b581231f0e505e0b30a00b9 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 19:24:14 +0200 Subject: [PATCH 1458/1872] Trac #19083: Missing "EXAMPLES::" --- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index d316f47d7ac..835f9594031 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -354,6 +354,8 @@ def _create_element_via_parent_(self, element): An element. + EXAMPLES:: + sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ * log(z)^ZZ') sage: z = G('z')[0] From a047f66131002494e5c7d42c1363122f50b769bb Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 14 Oct 2015 19:24:41 +0200 Subject: [PATCH 1459/1872] Trac #19083: Language --- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 835f9594031..a1375a4eb9c 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -584,7 +584,7 @@ def cartesian_injection(self, factor, element): def _coerce_map_from_(self, S): r""" - Return if ``S`` coerces into this growth group. + Return whether ``S`` coerces into this growth group. INPUT: From 2a935f54705b998469f68f54cc8af77c440fb1f7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 14 Oct 2015 13:21:12 -0500 Subject: [PATCH 1460/1872] Made FreeModules in the category of finite dimensional free modules with basis. --- .../finite_dimensional_modules_with_basis.py | 5 +++- src/sage/modules/free_module.py | 24 +++++++++---------- src/sage/modules/free_module_homspace.py | 11 +++++---- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 4b95ab77142..72b94186759 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -284,7 +284,10 @@ def dense_coefficient_list(self, order=None): [-2, -1] """ if order is None: - order = sorted(self.basis().keys()) + try: + order = sorted(self.parent().basis().keys()) + except AttributeError: # Not a family, assume it is list-like + order = range(self.parent().dimension()) return [self[i] for i in order] class MorphismMethods: diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 85db5e993d1..5c4084fe5fd 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -683,17 +683,18 @@ def __init__(self, base_ring, rank, degree, sparse=False, Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring in x0, x1, x2 over Rational Field sage: FreeModule(GF(7),3).category() - Category of vector spaces with basis over (finite fields - and subquotients of monoids and quotients of semigroups) + Category of finite dimensional vector spaces with basis over + (finite fields and subquotients of monoids and quotients of semigroups) sage: V = QQ^4; V.category() - Category of vector spaces with basis over quotient fields + Category of finite dimensional vector spaces with basis over quotient fields sage: V = GF(5)**20; V.category() - Category of vector spaces with basis over (finite fields - and subquotients of monoids and quotients of semigroups) + Category of finite dimensional vector spaces with basis over + (finite fields and subquotients of monoids and quotients of semigroups) sage: FreeModule(ZZ,3).category() - Category of modules with basis over (euclidean domains and infinite enumerated sets) + Category of finite dimensional modules with basis over + (euclidean domains and infinite enumerated sets) sage: (QQ^0).category() - Category of vector spaces with basis over quotient fields + Category of finite dimensional vector spaces with basis over quotient fields TESTS:: @@ -734,7 +735,7 @@ def __init__(self, base_ring, rank, degree, sparse=False, if category is None: from sage.categories.all import FreeModules - category = FreeModules(base_ring.category()) + category = FreeModules(base_ring.category()).FiniteDimensional() super(FreeModule_generic, self).__init__(base_ring, category=category) self.__coordinate_ring = coordinate_ring @@ -3067,10 +3068,9 @@ def _Hom_(self, Y, category): sage: type(H) sage: H - Set of Morphisms from Vector space of dimension 2 over - Rational Field to Ambient free module of rank 3 over the - principal ideal domain Integer Ring in Category of vector - spaces with basis over quotient fields + Set of Morphisms from Vector space of dimension 2 over Rational Field + to Ambient free module of rank 3 over the principal ideal domain Integer Ring + in Category of finite dimensional vector spaces with basis over quotient fields """ if Y.base_ring().is_field(): import vector_space_homspace diff --git a/src/sage/modules/free_module_homspace.py b/src/sage/modules/free_module_homspace.py index 5d674f304e9..966587bd079 100644 --- a/src/sage/modules/free_module_homspace.py +++ b/src/sage/modules/free_module_homspace.py @@ -27,11 +27,12 @@ sage: V2 = FreeModule(IntegerRing(),2) sage: H = Hom(V3,V2) sage: H - Set of Morphisms from Ambient free module of rank 3 over the - principal ideal domain Integer Ring to Ambient free module - of rank 2 over the principal ideal domain Integer Ring in - Category of modules with basis over (euclidean domains and - infinite enumerated sets) + Set of Morphisms from Ambient free module of rank 3 over + the principal ideal domain Integer Ring + to Ambient free module of rank 2 + over the principal ideal domain Integer Ring + in Category of finite dimensional modules with basis + over (euclidean domains and infinite enumerated sets) sage: B = H.basis() sage: len(B) 6 From 11590100b6520e833cf8de16732d85407d836214 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 14 Oct 2015 20:23:08 +0200 Subject: [PATCH 1461/1872] trac #19341: Don't consider booleans as integers. Just don't. --- src/sage/combinat/matrices/hadamard_matrix.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 1145d3ea96f..7d8f9649fcc 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -111,7 +111,9 @@ def hadamard_matrix_paleyI(n): K = FiniteField(p,'x') K_list = list(K) K_list.insert(0,K.zero()) - H = matrix(ZZ, [[2*((x-y).is_square()-.5) for x in K_list] for y in K_list]) + H = matrix(ZZ, [[(1 if (x-y).is_square() else -1) + for x in K_list] + for y in K_list]) for i in range(n): H[0,i] = 1 H[i,i] = -1 @@ -171,7 +173,9 @@ def hadamard_matrix_paleyII(n): K = FiniteField(q,'x') K_list = list(K) K_list.insert(0,K.zero()) - H = matrix(ZZ, [[2*((x-y).is_square()-.5) for x in K_list] for y in K_list]) + H = matrix(ZZ, [[(1 if (x-y).is_square() else -1) + for x in K_list] + for y in K_list]) for i in range(q+1): H[0,i] = 1 H[i,0] = 1 From f1f05ef2e5c826c7a9844afa5d916d7281b5ec16 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 14 Oct 2015 14:32:57 -0500 Subject: [PATCH 1462/1872] removed duplicate citation --- src/sage/combinat/alternating_sign_matrix.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index c7fefe77431..72861bdc134 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -554,11 +554,6 @@ def gyration(self): still a height function. Gyration was first defined in [Wieland00]_ as an action on fully-packed loops. - REFERENCES: - - .. [Wieland00] B. Wieland. *A large dihedral symmetry of the set of - alternating sign matrices*. Electron. J. Combin. 7 (2000). - EXAMPLES:: sage: A = AlternatingSignMatrices(3) From d3aad85381e6c2ddde1aa353aa081e2d7a26885e Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 14 Oct 2015 15:13:10 -0700 Subject: [PATCH 1463/1872] TeX typo fix --- src/sage/graphs/strongly_regular_db.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 209dec6e182..fdd5bcbca6a 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1401,7 +1401,7 @@ def SRG_280_117_44_52(): Rosa [MR85]_: The vertices of the graph `G` are all partitions of a set of 9 elements - into `\{\{a,b,c\},\{d,e,f\},\{g,h,i}\}`. The cross-intersection of two + into `\{\{a,b,c\},\{d,e,f\},\{g,h,i\}\}`. The cross-intersection of two such partitions `P=\{P_1,P_2,P_3\}` and `P'=\{P'_1,P'_2,P'_3\}` being defined as `\{P_i \cap P'_j: 1\leq i,j\leq 3\}`, two vertices of `G` are set to be adjacent if the cross-intersection of their respective From 2554b511b5552aae39dbfe4affbe96e904ba1ac3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 14 Oct 2015 21:30:52 -0500 Subject: [PATCH 1464/1872] Fixing trivial doctests from the changes in the category. --- src/sage/categories/category.py | 2 +- src/sage/categories/homset.py | 18 +++++++++--------- src/sage/misc/functional.py | 2 +- .../tensor/modules/finite_rank_free_module.py | 5 +++-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index a43973e47f9..44af6bd41bf 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -35,7 +35,7 @@ sage: V = VectorSpace(RationalField(), 3) sage: V.category() - Category of vector spaces with basis over quotient fields + Category of finite dimensional vector spaces with basis over quotient fields sage: G = SymmetricGroup(9) sage: G.category() Join of Category of finite permutation groups and Category of finite weyl groups diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 51a3f327d18..d46d3da5bd5 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -651,7 +651,7 @@ def __reduce__(self): (, (Vector space of dimension 2 over Rational Field, Vector space of dimension 3 over Rational Field, - Category of vector spaces with basis over quotient fields, + Category of finite dimensional vector spaces with basis over quotient fields, False)) TESTS:: @@ -1168,18 +1168,18 @@ def reversed(self): sage: H = Hom(ZZ^2, ZZ^3); H Set of Morphisms from Ambient free module of rank 2 over - the principal ideal domain Integer Ring to Ambient free - module of rank 3 over the principal ideal domain Integer - Ring in Category of modules with basis over (euclidean - domains and infinite enumerated sets) + the principal ideal domain Integer Ring to Ambient free module + of rank 3 over the principal ideal domain Integer Ring in + Category of finite dimensional modules with basis over + (euclidean domains and infinite enumerated sets) sage: type(H) sage: H.reversed() Set of Morphisms from Ambient free module of rank 3 over - the principal ideal domain Integer Ring to Ambient free - module of rank 2 over the principal ideal domain Integer - Ring in Category of modules with basis over (euclidean - domains and infinite enumerated sets) + the principal ideal domain Integer Ring to Ambient free module + of rank 2 over the principal ideal domain Integer Ring in + Category of finite dimensional modules with basis over + (euclidean domains and infinite enumerated sets) sage: type(H.reversed()) """ diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 607cca30874..d433d86fe18 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -124,7 +124,7 @@ def category(x): sage: V = VectorSpace(QQ,3) sage: category(V) - Category of vector spaces with basis over quotient fields + Category of finite dimensional vector spaces with basis over quotient fields """ try: return x.category() diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 8fbe8419514..ba6eeb2bda0 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -243,7 +243,8 @@ class :class:`~sage.modules.free_module.FreeModule_generic` sage: M.category() Category of modules over Integer Ring sage: N.category() - Category of modules with basis over (euclidean domains and infinite enumerated sets) + Category of finite dimensional modules with basis + over (euclidean domains and infinite enumerated sets) In other words, the module created by ``FreeModule`` is actually `\ZZ^3`, while, in the absence of any distinguished basis, no *canonical* isomorphism @@ -367,7 +368,7 @@ class :class:`~sage.modules.free_module.FreeModule_generic` sage: V = VectorSpace(QQ,3) ; V Vector space of dimension 3 over Rational Field sage: V.category() - Category of vector spaces with basis over quotient fields + Category of finite dimensional vector spaces with basis over quotient fields sage: V is QQ^3 True sage: V.basis() From 4e51ab0a00e0784de44d7da40f92dc078c48f440 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 14 Oct 2015 22:46:08 -0500 Subject: [PATCH 1465/1872] Adding an e and following Kevin's suggestions. --- src/sage/combinat/posets/lattices.py | 20 +-- .../{mobius_algebra.py => moebius_algebra.py} | 161 +++++++++--------- src/sage/combinat/posets/posets.py | 6 +- 3 files changed, 95 insertions(+), 92 deletions(-) rename src/sage/combinat/posets/{mobius_algebra.py => moebius_algebra.py} (80%) diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index 48e36294c76..0b985eeb448 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -1148,20 +1148,20 @@ def frattini_sublattice(self): return LatticePoset(self.subposet([self[x] for x in self._hasse_diagram.frattini_sublattice()])) - def mobius_algebra(self, R): + def moebius_algebra(self, R): """ Return the Mobius algebra of ``self`` over ``R``. EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: L.mobius_algebra(QQ) - Mobius algebra of Finite lattice containing 16 elements over Rational Field + sage: L.moebius_algebra(QQ) + Moebius algebra of Finite lattice containing 16 elements over Rational Field """ - from sage.combinat.posets.mobius_algebra import MobiusAlgebra - return MobiusAlgebra(R, self) + from sage.combinat.posets.moebius_algebra import MoebiusAlgebra + return MoebiusAlgebra(R, self) - def quantum_mobius_algebra(self, q=None): + def quantum_moebius_algebra(self, q=None): """ Return the quantum Mobius algebra of ``self`` with parameter ``q``. @@ -1172,12 +1172,12 @@ def quantum_mobius_algebra(self, q=None): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: L.quantum_mobius_algebra() - Quantum Mobius algebra of Finite lattice containing 16 elements + sage: L.quantum_moebius_algebra() + Quantum Moebius algebra of Finite lattice containing 16 elements with q=q over Univariate Laurent Polynomial Ring in q over Integer Ring """ - from sage.combinat.posets.mobius_algebra import QuantumMobiusAlgebra - return QuantumMobiusAlgebra(self, q) + from sage.combinat.posets.moebius_algebra import QuantumMoebiusAlgebra + return QuantumMoebiusAlgebra(self, q) ############################################################################ diff --git a/src/sage/combinat/posets/mobius_algebra.py b/src/sage/combinat/posets/moebius_algebra.py similarity index 80% rename from src/sage/combinat/posets/mobius_algebra.py rename to src/sage/combinat/posets/moebius_algebra.py index 7d49dd2e4c7..1d57ca89062 100644 --- a/src/sage/combinat/posets/mobius_algebra.py +++ b/src/sage/combinat/posets/moebius_algebra.py @@ -1,5 +1,6 @@ +# -*- coding: utf-8 -*- r""" -Mobius Algebras +Möbius Algebras """ #***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw , @@ -44,21 +45,21 @@ def __getitem__(self, x): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: E = L.mobius_algebra(QQ).E() + sage: E = L.moebius_algebra(QQ).E() sage: E[5] E[5] - sage: C = L.quantum_mobius_algebra().C() + sage: C = L.quantum_moebius_algebra().C() sage: C[5] C[5] """ L = self.realization_of()._lattice return self.monomial(L(x)) -class MobiusAlgebra(Parent, UniqueRepresentation): +class MoebiusAlgebra(Parent, UniqueRepresentation): r""" - The Mobius algebra of a lattice. + The möbius algebra of a lattice. - Let `L` be a lattice. The *Mobius algebra* `M_L` was originally + Let `L` be a lattice. The *Möbius algebra* `M_L` was originally constructed by Solomon and has a natural basis `\{ E_x \mid x \in L \}` with multiplication given by `E_x \cdot E_y = E_{x \vee y}`. Moreover this has a basis given by @@ -70,17 +71,17 @@ class MobiusAlgebra(Parent, UniqueRepresentation): I_x = \sum_{y \leq x} \mu_L(y, x) E_x, - where `\mu_L` is the Mobius function of `L`. + where `\mu_L` is the Möbius function of `L`. REFERENCES: .. [Greene73] Curtis Greene. - *On the Mobius algebra of a partially ordered set*. + *On the Möbius algebra of a partially ordered set*. Advances in Mathematics, **10**, 1973. :doi:`10.1016/0001-8708(73)90106-0`. .. [Etienne98] Gwihen Etienne. - *On the Mobius algebra of geometric lattices*. + *On the Möbius algebra of geometric lattices*. European Journal of Combinatorics, **19**, 1998. :doi:`10.1006/eujc.1998.0227`. """ @@ -91,7 +92,7 @@ def __init__(self, R, L): TESTS:: sage: L = posets.BooleanLattice(4) - sage: M = L.mobius_algebra(QQ) + sage: M = L.moebius_algebra(QQ) sage: TestSuite(M).run() """ if not L.is_lattice(): @@ -110,10 +111,10 @@ def _repr_(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: L.mobius_algebra(QQ) - Mobius algebra of Finite lattice containing 16 elements over Rational Field + sage: L.moebius_algebra(QQ) + Moebius algebra of Finite lattice containing 16 elements over Rational Field """ - return "Mobius algebra of {} over {}".format(self._lattice, self.base_ring()) + return "Moebius algebra of {} over {}".format(self._lattice, self.base_ring()) def a_realization(self): r""" @@ -122,9 +123,9 @@ def a_realization(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: M = L.mobius_algebra(QQ) + sage: M = L.moebius_algebra(QQ) sage: M.a_realization() - Mobius algebra of Finite lattice containing 16 elements + Moebius algebra of Finite lattice containing 16 elements over Rational Field in the natural basis """ return self.E() @@ -136,7 +137,7 @@ def lattice(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: M = L.mobius_algebra(QQ) + sage: M = L.moebius_algebra(QQ) sage: M.lattice() Finite lattice containing 16 elements sage: M.lattice() == L @@ -146,7 +147,7 @@ def lattice(self): class E(BasisAbstract): r""" - The natural basis of a Mobius algebra. + The natural basis of a Möbius algebra. Let `E_x` and `E_y` be basis elements of `M_L` for some lattice `L`. Multiplication is given by `E_x E_y = E_{x \vee y}`. @@ -158,14 +159,14 @@ def __init__(self, M, prefix='E'): TESTS:: sage: L = posets.BooleanLattice(4) - sage: M = L.mobius_algebra(QQ) + sage: M = L.moebius_algebra(QQ) sage: TestSuite(M.E()).run() """ self._basis_name = "natural" CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, - category=MobiusAlgebraBases(M)) + category=MoebiusAlgebraBases(M)) @cached_method def _to_idempotent_basis(self, x): @@ -174,7 +175,7 @@ def _to_idempotent_basis(self, x): EXAMPLES:: - sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) sage: E = M.E() sage: all(E(E._to_idempotent_basis(x)) == E.monomial(x) ....: for x in E.basis().keys()) @@ -191,7 +192,7 @@ def product_on_basis(self, x, y): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: E = L.mobius_algebra(QQ).E() + sage: E = L.moebius_algebra(QQ).E() sage: E.product_on_basis(5, 14) E[15] sage: E.product_on_basis(2, 8) @@ -207,7 +208,7 @@ def one(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: E = L.mobius_algebra(QQ).E() + sage: E = L.moebius_algebra(QQ).E() sage: E.one() E[0] """ @@ -218,7 +219,7 @@ def one(self): class I(BasisAbstract): """ - The (orthogonal) idempotent basis of a Mobius algebra. + The (orthogonal) idempotent basis of a Möbius algebra. Let `I_x` and `I_y` be basis elements of `M_L` for some lattice `L`. Multiplication is given by `I_x I_y = \delta_{xy} I_x` where @@ -231,14 +232,14 @@ def __init__(self, M, prefix='I'): TESTS:: sage: L = posets.BooleanLattice(4) - sage: M = L.mobius_algebra(QQ) + sage: M = L.moebius_algebra(QQ) sage: TestSuite(M.I()).run() """ self._basis_name = "idempotent" CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, - category=MobiusAlgebraBases(M)) + category=MoebiusAlgebraBases(M)) ## Change of basis: E = M.E() @@ -260,7 +261,7 @@ def _to_natural_basis(self, x): EXAMPLES:: - sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) sage: I = M.I() sage: all(I(I._to_natural_basis(x)) == I.monomial(x) ....: for x in I.basis().keys()) @@ -278,7 +279,7 @@ def product_on_basis(self, x, y): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: I = L.mobius_algebra(QQ).I() + sage: I = L.moebius_algebra(QQ).I() sage: I.product_on_basis(5, 14) 0 sage: I.product_on_basis(2, 2) @@ -296,7 +297,7 @@ def one(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: I = L.mobius_algebra(QQ).I() + sage: I = L.moebius_algebra(QQ).I() sage: I.one() I[0] + I[1] + I[2] + I[3] + I[4] + I[5] + I[6] + I[7] + I[8] + I[9] + I[10] + I[11] + I[12] + I[13] + I[14] + I[15] @@ -314,7 +315,7 @@ def __getitem__(self, x): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: I = L.mobius_algebra(QQ).I() + sage: I = L.moebius_algebra(QQ).I() sage: I[5] I[5] """ @@ -323,11 +324,11 @@ def __getitem__(self, x): idempotent = I -class QuantumMobiusAlgebra(Parent, UniqueRepresentation): +class QuantumMoebiusAlgebra(Parent, UniqueRepresentation): r""" - The quantum Mobius algebra of a lattice. + The quantum Möbius algebra of a lattice. - Let `L` be a lattice, and we define the *quantum Mobius algebra* `M_L(q)` + Let `L` be a lattice, and we define the *quantum Möbius algebra* `M_L(q)` as the algebra with basis `\{ E_x \mid x \in L \}` with multiplication given by @@ -336,7 +337,7 @@ class QuantumMobiusAlgebra(Parent, UniqueRepresentation): E_x E_y = \sum_{z \geq a \geq x \vee y} \mu_L(a, z) q^{\operatorname{crk} a} E_z, - where `\mu_L` is the Mobius function of `L` and `\operatorname{crk}` + where `\mu_L` is the Möbius function of `L` and `\operatorname{crk}` is the corank function (i.e., `\operatorname{crk} a = \operatorname{rank} L - \operatorname{rank}` a). At `q = 1`, this reduces to the multiplication formula originally given by Solomon. @@ -348,7 +349,7 @@ def __init__(self, L, q=None): TESTS:: sage: L = posets.BooleanLattice(4) - sage: M = L.quantum_mobius_algebra() + sage: M = L.quantum_moebius_algebra() sage: TestSuite(M).run() # long time """ if not L.is_lattice(): @@ -371,11 +372,11 @@ def _repr_(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: L.quantum_mobius_algebra() - Quantum Mobius algebra of Finite lattice containing 16 elements + sage: L.quantum_moebius_algebra() + Quantum Moebius algebra of Finite lattice containing 16 elements with q=q over Univariate Laurent Polynomial Ring in q over Integer Ring """ - return "Quantum Mobius algebra of {} with q={} over {}".format( + return "Quantum Moebius algebra of {} with q={} over {}".format( self._lattice, self._q, self.base_ring()) def a_realization(self): @@ -385,9 +386,9 @@ def a_realization(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: M = L.quantum_mobius_algebra() + sage: M = L.quantum_moebius_algebra() sage: M.a_realization() - Quantum Mobius algebra of Finite lattice containing 16 elements + Quantum Moebius algebra of Finite lattice containing 16 elements with q=q over Univariate Laurent Polynomial Ring in q over Integer Ring in the natural basis """ @@ -400,7 +401,7 @@ def lattice(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: M = L.quantum_mobius_algebra() + sage: M = L.quantum_moebius_algebra() sage: M.lattice() Finite lattice containing 16 elements sage: M.lattice() == L @@ -410,7 +411,7 @@ def lattice(self): class E(BasisAbstract): r""" - The natural basis of a Mobius algebra. + The natural basis of a quantum Möbius algebra. Let `E_x` and `E_y` be basis elements of `M_L` for some lattice `L`. Multiplication is given by @@ -420,7 +421,7 @@ class E(BasisAbstract): E_x E_y = \sum_{z \geq a \geq x \vee y} \mu_L(a, z) q^{\operatorname{crk} a} E_z, - where `\mu_L` is the Mobius function of `L` and `\operatorname{crk}` + where `\mu_L` is the Möbius function of `L` and `\operatorname{crk}` is the corank function (i.e., `\operatorname{crk} a = \operatorname{rank} L - \operatorname{rank}` a). """ @@ -431,14 +432,14 @@ def __init__(self, M, prefix='E'): TESTS:: sage: L = posets.BooleanLattice(4) - sage: M = L.quantum_mobius_algebra() + sage: M = L.quantum_moebius_algebra() sage: TestSuite(M.E()).run() # long time """ self._basis_name = "natural" CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, - category=MobiusAlgebraBases(M)) + category=MoebiusAlgebraBases(M)) def product_on_basis(self, x, y): """ @@ -447,7 +448,7 @@ def product_on_basis(self, x, y): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: E = L.quantum_mobius_algebra().E() + sage: E = L.quantum_moebius_algebra().E() sage: E.product_on_basis(5, 14) E[15] sage: E.product_on_basis(2, 8) @@ -471,7 +472,7 @@ def one(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: E = L.quantum_mobius_algebra().E() + sage: E = L.quantum_moebius_algebra().E() sage: all(E.one() * b == b for b in E.basis()) True """ @@ -487,17 +488,18 @@ def one(self): class C(BasisAbstract): r""" - The characteristic basis of a Mobius algebra. + The characteristic basis of a quantum Möbius algebra. The characteristic basis `\{ C_x \mid x \in L \}` of `M_L` for some lattice `L` is defined by .. MATH:: - C_x = \sum_{a \geq x} P(I^x; q) E_a, + C_x = \sum_{a \geq x} P(F^x; q) E_a, - where `I^x = \{ y \in L \mid y \geq x \}` is the order filter and - `P(I^x; q)` is the characteristic polynomial of the (sub)poset `I^x`. + where `F^x = \{ y \in L \mid y \geq x \}` is the principal order + filter of `x` and `P(F^x; q)` is the characteristic polynomial + of the (sub)poset `F^x`. """ def __init__(self, M, prefix='C'): """ @@ -506,14 +508,14 @@ def __init__(self, M, prefix='C'): TESTS:: sage: L = posets.BooleanLattice(3) - sage: M = L.quantum_mobius_algebra() + sage: M = L.quantum_moebius_algebra() sage: TestSuite(M.C()).run() # long time """ self._basis_name = "characteristic" CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, - category=MobiusAlgebraBases(M)) + category=MoebiusAlgebraBases(M)) ## Change of basis: E = M.E() @@ -531,7 +533,7 @@ def _to_natural_basis(self, x): EXAMPLES:: - sage: M = posets.BooleanLattice(4).quantum_mobius_algebra() + sage: M = posets.BooleanLattice(4).quantum_moebius_algebra() sage: C = M.C() sage: all(C(C._to_natural_basis(x)) == C.monomial(x) ....: for x in C.basis().keys()) @@ -553,7 +555,7 @@ def _to_natural_basis(self, x): class KL(BasisAbstract): """ - The Kazhdan-Lusztig basis of a quantum Mobius algebra. + The Kazhdan-Lusztig basis of a quantum Möbius algebra. The Kazhdan-Lusztig basis `\{ B_x \mid x \in L \}` of `M_L` for some lattice `L` is defined by @@ -569,10 +571,11 @@ class KL(BasisAbstract): We construct some examples of Proposition 4.5 of [EPW14]_:: - sage: M = posets.BooleanLattice(4).quantum_mobius_algebra() + sage: M = posets.BooleanLattice(4).quantum_moebius_algebra() sage: KL = M.KL() sage: KL[4] * KL[5] - (q^2+q^3)*KL[5] + (q+2*q^2+q^3)*KL[7] + (q+2*q^2+q^3)*KL[13] + (1+3*q+3*q^2+q^3)*KL[15] + (q^2+q^3)*KL[5] + (q+2*q^2+q^3)*KL[7] + (q+2*q^2+q^3)*KL[13] + + (1+3*q+3*q^2+q^3)*KL[15] sage: KL[4] * KL[15] (1+3*q+3*q^2+q^3)*KL[15] sage: KL[4] * KL[10] @@ -585,14 +588,14 @@ def __init__(self, M, prefix='KL'): TESTS:: sage: L = posets.BooleanLattice(4) - sage: M = L.quantum_mobius_algebra() + sage: M = L.quantum_moebius_algebra() sage: TestSuite(M.KL()).run() # long time """ self._basis_name = "Kazhdan-Lusztig" CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, - category=MobiusAlgebraBases(M)) + category=MoebiusAlgebraBases(M)) ## Change of basis: E = M.E() @@ -610,7 +613,7 @@ def _to_natural_basis(self, x): EXAMPLES:: - sage: M = posets.BooleanLattice(4).quantum_mobius_algebra() + sage: M = posets.BooleanLattice(4).quantum_moebius_algebra() sage: KL = M.KL() sage: all(KL(KL._to_natural_basis(x)) == KL.monomial(x) # long time ....: for x in KL.basis().keys()) @@ -630,19 +633,19 @@ def _to_natural_basis(self, x): kazhdan_lusztig = KL -class MobiusAlgebraBases(Category_realization_of_parent): +class MoebiusAlgebraBases(Category_realization_of_parent): r""" - The category of bases of a Mobius algebra. + The category of bases of a Möbius algebra. INPUT: - - ``base`` -- a Mobius algebra + - ``base`` -- a Möbius algebra TESTS:: - sage: from sage.combinat.posets.mobius_algebra import MobiusAlgebraBases - sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) - sage: bases = MobiusAlgebraBases(M) + sage: from sage.combinat.posets.moebius_algebra import MoebiusAlgebraBases + sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) + sage: bases = MoebiusAlgebraBases(M) sage: M.E() in bases True """ @@ -652,10 +655,10 @@ def _repr_(self): EXAMPLES:: - sage: from sage.combinat.posets.mobius_algebra import MobiusAlgebraBases - sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) - sage: MobiusAlgebraBases(M) - Category of bases of Mobius algebra of Finite lattice + sage: from sage.combinat.posets.moebius_algebra import MoebiusAlgebraBases + sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) + sage: MoebiusAlgebraBases(M) + Category of bases of Moebius algebra of Finite lattice containing 16 elements over Rational Field """ return "Category of bases of {}".format(self.base()) @@ -666,12 +669,12 @@ def super_categories(self): EXAMPLES:: - sage: from sage.combinat.posets.mobius_algebra import MobiusAlgebraBases - sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) - sage: bases = MobiusAlgebraBases(M) + sage: from sage.combinat.posets.moebius_algebra import MoebiusAlgebraBases + sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) + sage: bases = MoebiusAlgebraBases(M) sage: bases.super_categories() [Category of finite dimensional commutative algebras with basis over Rational Field, - Category of realizations of Mobius algebra of Finite lattice + Category of realizations of Moebius algebra of Finite lattice containing 16 elements over Rational Field] """ return [self.base()._category, Realizations(self.base())] @@ -679,16 +682,16 @@ def super_categories(self): class ParentMethods: def _repr_(self): """ - Text representation of this basis of a Mobius algebra. + Text representation of this basis of a Möbius algebra. EXAMPLES:: - sage: M = posets.BooleanLattice(4).mobius_algebra(QQ) + sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) sage: M.E() - Mobius algebra of Finite lattice containing 16 elements + Moebius algebra of Finite lattice containing 16 elements over Rational Field in the natural basis sage: M.I() - Mobius algebra of Finite lattice containing 16 elements + Moebius algebra of Finite lattice containing 16 elements over Rational Field in the idempotent basis """ return "{} in the {} basis".format(self.realization_of(), self._basis_name) @@ -700,7 +703,7 @@ def product_on_basis(self, x, y): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: C = L.quantum_mobius_algebra().C() + sage: C = L.quantum_moebius_algebra().C() sage: C.product_on_basis(5, 14) q^3*C[15] sage: C.product_on_basis(2, 8) @@ -717,7 +720,7 @@ def one(self): EXAMPLES:: sage: L = posets.BooleanLattice(4) - sage: C = L.quantum_mobius_algebra().C() + sage: C = L.quantum_moebius_algebra().C() sage: all(C.one() * b == b for b in C.basis()) True """ diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 5bf70f58b65..b29cc3563be 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5721,9 +5721,9 @@ def kazhdan_lusztig_polynomial(self, x=None, y=None, q=None, canonical_labels=No We follow the definition given in [EPW14]_. Let `G` denote a graded poset with unique minimal and maximal elements and `\chi_G` denote the characteristic polynomial of `G`. Let `I_x` and `F^x` - denote the order ideal and filter of `x` respectively. Define the - *Kazhdan-Lusztig polynomial* of `G` as the unique polynomial - `P_G(q)` satisfying the following: + denote the principal order ideal and filter of `x` respectively. + Define the *Kazhdan-Lusztig polynomial* of `G` as the unique + polynomial `P_G(q)` satisfying the following: 1. If `\operatorname{rank} G = 0`, then `P_G(q) = 1`. 2. If `\operatorname{rank} G > 0`, then `\deg P_G(q) < From d64e45b7979eec1d32b42314adf3bfd33544ae08 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 15 Oct 2015 08:38:24 +0200 Subject: [PATCH 1466/1872] trac #19390: add a *symmetric* somewhere in the doc --- src/sage/graphs/graph.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 6b075a7f2e7..a8f1ffa1f20 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -618,9 +618,10 @@ class Graph(GenericGraph): To bypass auto-detection, prefer the more explicit ``Graph(M, format='incidence_matrix')``. - #. ``Graph([V, f])`` -- return a graph with a vertex set ``V`` and an edge - `u,v` whenever ``f(u,v)`` is ``True``. Example: ``Graph([ [1..10], - lambda x,y: abs(x-y).is_square()])`` + #. ``Graph([V, f])`` -- return a graph from a vertex set ``V`` and a + *symmetric* function ``f``. The graph contains an edge `u,v` whenever + ``f(u,v)`` is ``True``.. Example: ``Graph([ [1..10], lambda x,y: + abs(x-y).is_square()])`` #. ``Graph(':I`ES@obGkqegW~')`` -- return a graph from a graph6 or sparse6 string (see documentation of :meth:`graph6_string` or From 40a5f875def03f51ad389be5778bdd5e002f0768 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 15 Oct 2015 09:26:18 +0200 Subject: [PATCH 1467/1872] Fix floor(x), ceil(x) when RIF(x) is unbounded Also slightly simplify the implementation. --- src/sage/functions/other.py | 93 +++++++++++++++---------------------- 1 file changed, 37 insertions(+), 56 deletions(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 1dbe2c36b01..8cb74664a95 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -441,6 +441,8 @@ def __call__(self, x, maximum_bits=20000): 100000000000000000000000000000000000000000000000000 sage: ceil(int(10^50)) 100000000000000000000000000000000000000000000000000 + sage: ceil((1725033*pi - 5419351)/(25510582*pi - 80143857)) + -2 """ try: return x.ceil() @@ -453,39 +455,29 @@ def __call__(self, x, maximum_bits=20000): import numpy return numpy.ceil(x) - x_original = x - from sage.rings.all import RealIntervalField - # If x can be coerced into a real interval, then we should - # try increasing the number of bits of precision until - # we get the ceiling at each of the endpoints is the same. - # The precision will continue to be increased up to maximum_bits - # of precision at which point it will raise a value error. + bits = 53 + while bits < maximum_bits: + try: + x_interval = RealIntervalField(bits)(x) + except TypeError: + # If we cannot compute a numerical enclosure, leave the + # expression unevaluated. + return BuiltinFunction.__call__(self, SR(x)) + try: + return x_interval.unique_ceil() + except ValueError: + bits *= 2 + try: - x_interval = RealIntervalField(bits)(x) - upper_ceil = x_interval.upper().ceil() - lower_ceil = x_interval.lower().ceil() + return ceil(SR(x).full_simplify().canonicalize_radical()) + except ValueError: + pass - while upper_ceil != lower_ceil and bits < maximum_bits: - bits += 100 - x_interval = RealIntervalField(bits)(x) - upper_ceil = x_interval.upper().ceil() - lower_ceil = x_interval.lower().ceil() + raise ValueError("computing ceil(%s) requires more than %s bits of precision (increase maximum_bits to proceed)"%(x, maximum_bits)) - if bits < maximum_bits: - return lower_ceil - else: - try: - return ceil(SR(x).full_simplify().canonicalize_radical()) - except ValueError: - pass - raise ValueError("x (= %s) requires more than %s bits of precision to compute its ceiling"%(x, maximum_bits)) - except TypeError: - # If x cannot be coerced into a RealField, then - # it should be left as a symbolic expression. - return BuiltinFunction.__call__(self, SR(x_original)) def _eval_(self, x): """ @@ -612,6 +604,8 @@ def __call__(self, x, maximum_bits=20000): 99999999999999999999999999999999999999999999999999 sage: floor(int(10^50)) 100000000000000000000000000000000000000000000000000 + sage: floor((1725033*pi - 5419351)/(25510582*pi - 80143857)) + -3 """ try: return x.floor() @@ -624,40 +618,27 @@ def __call__(self, x, maximum_bits=20000): import numpy return numpy.floor(x) - x_original = x - from sage.rings.all import RealIntervalField - # If x can be coerced into a real interval, then we should - # try increasing the number of bits of precision until - # we get the floor at each of the endpoints is the same. - # The precision will continue to be increased up to maximum_bits - # of precision at which point it will raise a value error. bits = 53 - try: - x_interval = RealIntervalField(bits)(x) - upper_floor = x_interval.upper().floor() - lower_floor = x_interval.lower().floor() - - while upper_floor != lower_floor and bits < maximum_bits: - bits += 100 + while bits < maximum_bits: + try: x_interval = RealIntervalField(bits)(x) - upper_floor = x_interval.upper().floor() - lower_floor = x_interval.lower().floor() + except TypeError: + # If we cannot compute a numerical enclosure, leave the + # expression unevaluated. + return BuiltinFunction.__call__(self, SR(x)) + try: + return x_interval.unique_floor() + except ValueError: + bits *= 2 - if bits < maximum_bits: - return lower_floor - else: - try: - return floor(SR(x).full_simplify().canonicalize_radical()) - except ValueError: - pass - raise ValueError("x (= %s) requires more than %s bits of precision to compute its floor"%(x, maximum_bits)) - - except TypeError: - # If x cannot be coerced into a RealField, then - # it should be left as a symbolic expression. - return BuiltinFunction.__call__(self, SR(x_original)) + try: + return floor(SR(x).full_simplify().canonicalize_radical()) + except ValueError: + pass + + raise ValueError("computing floor(%s) requires more than %s bits of precision (increase maximum_bits to proceed)"%(x, maximum_bits)) def _eval_(self, x): """ From 2be05a18c0e07363da82d05fa94f7212e4cab1b7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 09:41:16 +0200 Subject: [PATCH 1468/1872] let underlying_class deal with non-parent input --- src/sage/rings/asymptotic/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 134c6701a77..fd476b6d02d 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -328,7 +328,7 @@ def underlying_class(P): """ cls = type(P) - if not P._is_category_initialized(): + if not hasattr(P, '_is_category_initialized') or not P._is_category_initialized(): return cls from sage.structure.misc import is_extension_type if is_extension_type(cls): From 9f20c58e1b8fc117cd78cc5dbdeccfeb52f30d5d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 09:42:12 +0200 Subject: [PATCH 1469/1872] use underlying_class instead of type --- src/sage/rings/asymptotic/growth_group_cartesian.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 381c5afe26e..98d72c4894e 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -674,9 +674,17 @@ def _pushout_(self, other): sage: F = GrowthGroup('z^QQ') sage: pushout(C, F) Growth Group QQ^x * x^QQ * y^ZZ * z^QQ + + :: + + sage: pushout(GrowthGroup('QQ^x * x^ZZ'), GrowthGroup('ZZ^x * x^QQ')) + Growth Group QQ^x * x^QQ + sage: cm.common_parent(GrowthGroup('QQ^x * x^ZZ'), GrowthGroup('ZZ^x * x^QQ')) + Growth Group QQ^x * x^QQ """ from growth_group import GenericGrowthGroup, AbstractGrowthGroupFunctor from misc import merge_overlapping + from misc import underlying_class if isinstance(other, GenericProduct): Ofactors = other.cartesian_factors() @@ -688,12 +696,11 @@ def _pushout_(self, other): else: return - def pushout_univariate_factors(self, other, var, Sfactors, Ofactors): try: return merge_overlapping( Sfactors, Ofactors, - lambda f: (type(f), f._var_.var_repr)) + lambda f: (underlying_class(f), f._var_.var_repr)) except ValueError: pass @@ -715,7 +722,7 @@ def subfactors(F): try: return merge_overlapping( tuple(subfactors(Sfactors)), tuple(subfactors(Ofactors)), - lambda f: (type(f), f._var_.var_repr)) + lambda f: (underlying_class(f), f._var_.var_repr)) except ValueError: pass From abd56197f189ccee6777b3c49bdd2ff082f7f230 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 09:43:43 +0200 Subject: [PATCH 1470/1872] restructure conversion of elements in ExponentialGrowthGroup to deal with 1 correctly --- src/sage/rings/asymptotic/growth_group.py | 24 +++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6df9fc0fd5f..cd98c6c0e86 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2805,6 +2805,11 @@ def _convert_(self, data): sage: P('1') 1 + + :: + + sage: GrowthGroup('x^QQ')(GrowthGroup('x^ZZ')(1)) + 1 """ if data == 1 or data == '1': return self.base().zero() @@ -3403,18 +3408,26 @@ def _convert_(self, data): e^x sage: P(exp(2*x)) (e^2)^x + + :: + + sage: GrowthGroup('QQ^x')(GrowthGroup('ZZ^x')(1)) + 1 """ - if data == 1 or data == '1': + if data == '1' or isinstance(data, int) and data == 1: return self.base().one() var = repr(self._var_) try: P = data.parent() except AttributeError: - if var not in str(data): + if data == 1: + return self.base().one() + s = str(data) + if var not in s: return # this has to end here - elif str(data).endswith('^' + var): - return self.base()(str(data).replace('^' + var, '') + elif s.endswith('^' + var): + return self.base()(s.replace('^' + var, '') .replace('(', '').replace(')', '')) else: return # end of parsing @@ -3439,6 +3452,9 @@ def _convert_(self, data): elif exponent.operator() == mul_vararg: return base ** (exponent / SR(var)) + elif data == 1: # can be expensive, so let's put it at the end + return self.base().one() + def gens(self): r""" From 1703ce857c56d5975493b1ece39c8faad0675bb0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 09:44:26 +0200 Subject: [PATCH 1471/1872] rewrite element constructor of growth groups to deal with different base rings --- src/sage/rings/asymptotic/growth_group.py | 28 ++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index cd98c6c0e86..82b4249719a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1793,9 +1793,19 @@ def _element_constructor_(self, data, raw_element=None): Traceback (most recent call last): ... ValueError: x is not in Growth Group y^ZZ. + + :: + + sage: GrowthGroup('QQ^x')(GrowthGroup('ZZ^x')('2^x')) + 2^x """ + from misc import underlying_class, combine_exceptions + if raw_element is None: - if isinstance(data, self.element_class): + if isinstance(data, int) and data == 0: + raise ValueError('No input specified. Cannot continue.') + + elif isinstance(data, self.element_class): if data.parent() == self: return data try: @@ -1804,10 +1814,22 @@ def _element_constructor_(self, data, raw_element=None): except AttributeError: pass raw_element = data._raw_element_ - elif isinstance(data, int) and data == 0: - raise ValueError('No input specified. Cannot continue.') + + elif isinstance(data, self.Element): + if self._var_ == data.parent()._var_: + try: + raw_element = self.base()(data._raw_element_) + except (TypeError, ValueError) as e: + raise combine_exceptions( + ValueError('%s is not in %s.' % (data, self)), e) + + elif isinstance(data, GenericGrowthElement): + if data.is_one(): + return self.one() + else: raw_element = self._convert_(data) + if raw_element is None: raise ValueError('%s is not in %s.' % (data, self)) elif not isinstance(data, int) or data != 0: From 27e30cfea58a86db5785a1fc73fabe27e81abaca Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 09:45:22 +0200 Subject: [PATCH 1472/1872] simplify one test in the element constructor --- src/sage/rings/asymptotic/growth_group.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 82b4249719a..949619b5e87 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1808,11 +1808,8 @@ def _element_constructor_(self, data, raw_element=None): elif isinstance(data, self.element_class): if data.parent() == self: return data - try: - if self._var_ != data.parent()._var_: - raise ValueError('%s is not in %s.' % (data, self)) - except AttributeError: - pass + if self._var_ != data.parent()._var_: + raise ValueError('%s is not in %s.' % (data, self)) raw_element = data._raw_element_ elif isinstance(data, self.Element): From 256ef2dcb14cb2feb7739ed5e234a67c985e3d32 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 10:01:24 +0200 Subject: [PATCH 1473/1872] mark a doctest as not tested and refer to follow up ticket #19411 --- src/sage/rings/asymptotic/growth_group_cartesian.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 98d72c4894e..dfbbf54fcdf 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -72,10 +72,10 @@ sage: cm.common_parent(A, D) Growth Group QQ^x * x^QQ sage: E = GrowthGroup('ZZ^x * x^QQ') - sage: cm.record_exceptions() + sage: cm.record_exceptions() # not tested, see #19411 sage: cm.common_parent(A, E) Growth Group QQ^x * x^QQ - sage: for t in cm.exception_stack(): + sage: for t in cm.exception_stack(): # not tested, see #19411 ....: print t :: From 3e7a7f5638ac8acfc234b592974376bb88253e5f Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Thu, 11 Jun 2015 09:20:29 +0200 Subject: [PATCH 1474/1872] Handle both arities of converting_dict.pop using *args Thanks to Marc Mezzarobba for suggesting this. --- src/sage/misc/converting_dict.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/sage/misc/converting_dict.py b/src/sage/misc/converting_dict.py index 1b18f915e0c..6273b7e5e12 100644 --- a/src/sage/misc/converting_dict.py +++ b/src/sage/misc/converting_dict.py @@ -201,16 +201,14 @@ def has_key(self, key): """ return key in self - _no_default_provided = object() - - def pop(self, key, default=_no_default_provided): + def pop(self, key, *args): r""" Remove and retreive a given element from the dictionary INPUT: - ``key`` -- A value identifying the element, will be converted. - - ``default`` -- The value to return if the element is not mapped. + - ``default`` -- The value to return if the element is not mapped, optional. EXAMPLES:: @@ -227,10 +225,7 @@ def pop(self, key, default=_no_default_provided): KeyError: ... """ key = self.key_conversion_function(key) - if default is self._no_default_provided: - return super(KeyConvertingDict, self).pop(key) - else: - return super(KeyConvertingDict, self).pop(key, default) + return super(KeyConvertingDict, self).pop(key, *args) def setdefault(self, key, default=None): r""" From ef257dbfeccce29abf6cbd3b8ff615e89ae160f6 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Fri, 29 May 2015 15:27:51 +0200 Subject: [PATCH 1475/1872] #18546 Make arb a standard package --- COPYING.txt | 1 + build/pkgs/arb/type | 2 +- src/module_list.py | 18 ++++++++---------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/COPYING.txt b/COPYING.txt index 4fc2393e21e..fc4dbd08c5b 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -28,6 +28,7 @@ the licenses of the components of Sage are included below as well. SOFTWARE LICENSE ----------------------------------------------------------------------- +arb GPLv2+ atlas Modified BSD boehm_gc MIT-like license (see below) backports_ssl_match_hostname Python License diff --git a/build/pkgs/arb/type b/build/pkgs/arb/type index 134d9bc32d5..a6a7b9cd726 100644 --- a/build/pkgs/arb/type +++ b/build/pkgs/arb/type @@ -1 +1 @@ -optional +standard diff --git a/src/module_list.py b/src/module_list.py index 7108872b586..dfe684cc5f1 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1221,11 +1221,10 @@ def uname_specific(name, value, alternative): libraries=['ntl'], language = 'c++'), - OptionalExtension("sage.rings.complex_ball_acb", - ["sage/rings/complex_ball_acb.pyx"], - libraries=['arb', 'mpfi', 'mpfr'], - include_dirs=[SAGE_INC + '/flint'], - package='arb'), + Extension("sage.rings.complex_ball_acb", + ["sage/rings/complex_ball_acb.pyx"], + libraries=['arb', 'mpfi', 'mpfr'], + include_dirs=[SAGE_INC + '/flint']), Extension('sage.rings.complex_double', sources = ['sage/rings/complex_double.pyx'], @@ -1294,11 +1293,10 @@ def uname_specific(name, value, alternative): Extension('sage.rings.real_interval_absolute', sources = ['sage/rings/real_interval_absolute.pyx']), - OptionalExtension("sage.rings.real_arb", - ["sage/rings/real_arb.pyx"], - libraries = ['arb', 'mpfi', 'mpfr'], - include_dirs = [SAGE_INC + '/flint'], - package = 'arb'), + Extension("sage.rings.real_arb", + ["sage/rings/real_arb.pyx"], + libraries = ['arb', 'mpfi', 'mpfr'], + include_dirs = [SAGE_INC + '/flint']), Extension('sage.rings.real_lazy', sources = ['sage/rings/real_lazy.pyx']), From a7a41bc6810b337484ff94aa7621ca7f5c623133 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Fri, 29 May 2015 15:49:59 +0200 Subject: [PATCH 1476/1872] #18546 Remove 'optional - arb' doctest flags --- src/sage/rings/complex_ball_acb.pyx | 294 +++++---- src/sage/rings/real_arb.pyx | 952 ++++++++++++++-------------- 2 files changed, 621 insertions(+), 625 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 6823960c101..a8225c1486f 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -5,12 +5,10 @@ AUTHORS: - Clemens Heuberger (2014-10-25): Initial version. -This is a rudimentary binding to the optional `Arb library +This is a rudimentary binding to the `Arb library `_; it may be useful to refer to its documentation for more details. -You may have to run ``sage -i arb`` to use the arb library. - .. WARNING:: Identical :class:`ComplexBall` objects are understood to give @@ -25,39 +23,39 @@ Comparison Two elements are equal if and only if they are the same object or if both are exact and equal:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() 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 + sage: a = CBF(1, 2) + sage: b = CBF(1, 2) + sage: a is b False - sage: a == b # optional - arb + sage: a == b True - sage: a = CBF(1/3, 1/5) # optional - arb - sage: b = CBF(1/3, 1/5) # optional - arb - sage: a.is_exact() # optional - arb + sage: a = CBF(1/3, 1/5) + sage: b = CBF(1/3, 1/5) + sage: a.is_exact() False - sage: b.is_exact() # optional - arb + sage: b.is_exact() False - sage: a is b # optional - arb + sage: a is b False - sage: a == b # optional - arb + sage: a == b False A ball is non-zero if and only if it does not contain zero. :: - sage: a = CBF(RIF(-0.5, 0.5)) # optional - arb - sage: bool(a) # optional - arb + sage: a = CBF(RIF(-0.5, 0.5)) + sage: bool(a) False - sage: a != 0 # optional - arb + sage: a != 0 False - sage: b = CBF(1/3, 1/5) # optional - arb - sage: bool(b) # optional - arb + sage: b = CBF(1/3, 1/5) + sage: bool(b) True - sage: b != 0 # optional - arb + sage: b != 0 True Classes and Methods @@ -142,18 +140,18 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb; indirect doctest - sage: CBF(1) # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() # indirect doctest + sage: CBF(1) 1.000000000000000 TESTS:: - sage: ComplexBallField(0) # optional - arb + sage: ComplexBallField(0) Traceback (most recent call last): ... ValueError: Precision must be at least 2. - sage: ComplexBallField(1) # optional - arb + sage: ComplexBallField(1) Traceback (most recent call last): ... ValueError: Precision must be at least 2. @@ -167,8 +165,8 @@ class ComplexBallField(UniqueRepresentation, Parent): TESTS:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: ComplexBallField(53) is ComplexBallField() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: ComplexBallField(53) is ComplexBallField() True """ return super(ComplexBallField, cls).__classcall__(cls, precision) @@ -184,9 +182,9 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: CBF(1) # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: CBF(1) 1.000000000000000 """ if precision < 2: @@ -201,10 +199,10 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: ComplexBallField() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: ComplexBallField() Complex ball field with 53 bits precision - sage: ComplexBallField(106) # optional - arb + sage: ComplexBallField(106) Complex ball field with 106 bits precision """ return "Complex ball field with {} bits precision".format(self._prec) @@ -215,10 +213,10 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: ComplexBallField()._coerce_map_from_(CIF) # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: ComplexBallField()._coerce_map_from_(CIF) False - sage: ComplexBallField()._coerce_map_from_(SR) # optional - arb + sage: ComplexBallField()._coerce_map_from_(SR) False """ return False @@ -229,9 +227,9 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional: arb - sage: CBF = ComplexBallField() # optional: arb - sage: CBF(1) # optional: arb; indirect doctest + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: CBF(1) # indirect doctest 1.000000000000000 """ return self.element_class(self, *args, **kwds) @@ -242,9 +240,9 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional: arb - sage: CBF = ComplexBallField() # optional: arb - sage: CBF._an_element_() # optional: arb; indirect doctest + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: CBF._an_element_() # indirect doctest [0.3333333333333333 +/- 1.49e-17] + [0.1666666666666667 +/- 4.26e-17]*I """ return self(1.0/3, 1.0/6) @@ -255,8 +253,8 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: ComplexBallField().precision() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: ComplexBallField().precision() 53 """ return self._prec @@ -267,8 +265,8 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: ComplexBallField().is_exact() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: ComplexBallField().is_exact() False """ return False @@ -279,8 +277,8 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: ComplexBallField().is_finite() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: ComplexBallField().is_finite() False """ return False @@ -291,8 +289,8 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: ComplexBallField().characteristic() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: ComplexBallField().characteristic() 0 """ return 0 @@ -304,7 +302,7 @@ cdef inline bint _do_sig(long prec): TESTS:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField """ return (prec > 1000) @@ -321,11 +319,11 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: a = ComplexBallField()(1, 1) # optional - arb - sage: a # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: a = ComplexBallField()(1, 1) + sage: a 1.000000000000000 + 1.000000000000000*I - sage: a._interval() # optional - arb + sage: a._interval() 1 + 1*I """ def __cinit__(self): @@ -334,8 +332,8 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: ComplexBallField(2)(0) # optional - arb; indirect doctest + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: ComplexBallField(2)(0) # indirect doctest 0 """ acb_init(self.value) @@ -346,9 +344,9 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: a = ComplexBallField(2)(0) # optional - arb; indirect doctest - sage: del a # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: a = ComplexBallField(2)(0) # indirect doctest + sage: del a """ acb_clear(self.value) @@ -373,29 +371,29 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: CBF(CIF(0, 1)) # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: from sage.rings.real_arb import RealBallField + sage: CBF = ComplexBallField() + sage: CBF(CIF(0, 1)) 1.000000000000000*I - sage: CBF(1) # optional - arb + sage: CBF(1) 1.000000000000000 - sage: CBF(1, 1) # optional - arb + sage: CBF(1, 1) 1.000000000000000 + 1.000000000000000*I - sage: CBF(x) # optional - arb + sage: CBF(x) Traceback (most recent call last): ... TypeError: unable to convert to a ComplexIntervalFieldElement - sage: RBF = RealBallField() # optional - arb - sage: CBF(RBF(1/3)) # optional - arb + sage: RBF = RealBallField() + sage: CBF(RBF(1/3)) [0.3333333333333333 +/- 7.04e-17] - sage: CBF(RBF(1/3), RBF(1/6)) # optional - arb + sage: CBF(RBF(1/3), RBF(1/6)) [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I - sage: CBF(1/3) # optional - arb + sage: CBF(1/3) [0.333333333333333 +/- 3.99e-16] - sage: CBF(1/3, 1/6) # optional - arb + sage: CBF(1/3, 1/6) [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I - sage: ComplexBallField(106)(1/3, 1/6) # optional - arb + sage: ComplexBallField(106)(1/3, 1/6) [0.33333333333333333333333333333333 +/- 6.94e-33] + [0.16666666666666666666666666666666 +/- 7.70e-33]*I """ Element.__init__(self, parent) @@ -452,10 +450,10 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: a = CBF(1/3, 1/5) # optional - arb - sage: a.real() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: a = CBF(1/3, 1/5) + sage: a.real() [0.3333333333333333 +/- 7.04e-17] """ cdef RealBall r @@ -473,10 +471,10 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: a = CBF(1/3, 1/5) # optional - arb - sage: a.imag() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: a = CBF(1/3, 1/5) + sage: a.imag() [0.2000000000000000 +/- 4.45e-17] """ cdef RealBall r @@ -494,13 +492,13 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: CBF(1/3) # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: CBF(1/3) [0.333333333333333 +/- 3.99e-16] - sage: CBF(0, 1/3) # optional - arb + sage: CBF(0, 1/3) [0.3333333333333333 +/- 7.04e-17]*I - sage: ComplexBallField()(1/3, 1/6) # optional - arb + sage: ComplexBallField()(1/3, 1/6) [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I """ if arb_is_zero(&self.value.imag): @@ -521,10 +519,10 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: a = CBF(CIF(2, 2)) # optional - arb - sage: a._interval() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: a = CBF(CIF(2, 2)) + sage: a._interval() 2 + 2*I """ cdef ComplexIntervalFieldElement target = ComplexIntervalField(prec(self))(0) @@ -539,11 +537,11 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: CBF(0).is_zero() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: CBF(0).is_zero() True - sage: CBF(RIF(-0.5, 0.5)).is_zero() # optional - arb + sage: CBF(RIF(-0.5, 0.5)).is_zero() False """ return acb_is_zero(self.value) @@ -555,15 +553,15 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: bool(CBF(pi, 1/3)) # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: bool(CBF(pi, 1/3)) True - sage: bool(CBF(RIF(-0.5, 0.5), 1/3)) # optional - arb + sage: bool(CBF(RIF(-0.5, 0.5), 1/3)) True - sage: bool(CBF(1/3, RIF(-0.5, 0.5))) #optional - arb + sage: bool(CBF(1/3, RIF(-0.5, 0.5))) True - sage: bool(CBF(RIF(-0.5, 0.5), RIF(-0.5, 0.5))) #optional - arb + sage: bool(CBF(RIF(-0.5, 0.5), RIF(-0.5, 0.5))) False """ return acb_is_nonzero(self.value) @@ -574,11 +572,11 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: CBF(1).is_exact() # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: CBF(1).is_exact() True - sage: CBF(1/3, 1/3).is_exact() # optional - arb + sage: CBF(1/3, 1/3).is_exact() False """ return acb_is_exact(self.value) @@ -591,21 +589,21 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: a = CBF(1) # optional - arb - sage: b = CBF(1) # optional - arb - sage: a is b # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: a = CBF(1) + sage: b = CBF(1) + sage: a is b False - sage: a == b # optional - arb + sage: a == b True - sage: a = CBF(1/3) # optional - arb - sage: a.is_exact() # optional - arb + sage: a = CBF(1/3) + sage: a.is_exact() False - sage: b = CBF(1/3) # optional - arb - sage: b.is_exact() # optional - arb + sage: b = CBF(1/3) + sage: b.is_exact() False - sage: a == b # optional - arb + sage: a == b False """ return (left)._richcmp(right, op) @@ -618,80 +616,80 @@ cdef class ComplexBall(Element): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb - sage: CBF = ComplexBallField() # optional - arb - sage: a = CBF(1, 2) # optional - arb - sage: b = CBF(1, 2) # optional - arb - sage: a is b # optional - arb + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: a = CBF(1, 2) + sage: b = CBF(1, 2) + sage: a is b False - sage: a == b # optional - arb + sage: a == b True TESTS: Balls whose intersection consists of one point:: - sage: a = CBF(RIF(1, 2), RIF(1, 2)) # optional - arb - sage: b = CBF(RIF(2, 4), RIF(2, 4)) # optional - arb - sage: a < b # optional - arb + sage: a = CBF(RIF(1, 2), RIF(1, 2)) + sage: b = CBF(RIF(2, 4), RIF(2, 4)) + sage: a < b Traceback (most recent call last): ... TypeError: No order is defined for ComplexBalls. - sage: a > b # optional - arb + sage: a > b Traceback (most recent call last): ... TypeError: No order is defined for ComplexBalls. - sage: a <= b # optional - arb + sage: a <= b Traceback (most recent call last): ... TypeError: No order is defined for ComplexBalls. - sage: a >= b # optional - arb + sage: a >= b Traceback (most recent call last): ... TypeError: No order is defined for ComplexBalls. - sage: a == b # optional - arb + sage: a == b False - sage: a != b # optional - arb + sage: a != b False Balls with non-trivial intersection:: - sage: a = CBF(RIF(1, 4), RIF(1, 4)) # optional - arb - sage: a = CBF(RIF(2, 5), RIF(2, 5)) # optional - arb - sage: a == b # optional - arb + sage: a = CBF(RIF(1, 4), RIF(1, 4)) + sage: a = CBF(RIF(2, 5), RIF(2, 5)) + sage: a == b False - sage: a != b # optional - arb + sage: a != b False One ball contained in another:: - sage: a = CBF(RIF(1, 4), RIF(1, 4)) # optional - arb - sage: b = CBF(RIF(2, 3), RIF(2, 3)) # optional - arb - sage: a == b # optional - arb + sage: a = CBF(RIF(1, 4), RIF(1, 4)) + sage: b = CBF(RIF(2, 3), RIF(2, 3)) + sage: a == b False - sage: a != b # optional - arb + sage: a != b False Disjoint balls:: - sage: a = CBF(1/3, 1/3) # optional - arb - sage: b = CBF(1/5, 1/5) # optional - arb - sage: a == b # optional - arb + sage: a = CBF(1/3, 1/3) + sage: b = CBF(1/5, 1/5) + sage: a == b False - sage: a != b # optional - arb + sage: a != b True Exact elements:: - sage: a = CBF(2, 2) # optional - arb - sage: b = CBF(2, 2) # optional - arb - sage: a.is_exact() # optional - arb + sage: a = CBF(2, 2) + sage: b = CBF(2, 2) + sage: a.is_exact() True - sage: b.is_exact() # optional - arb + sage: b.is_exact() True - sage: a == b # optional - arb + sage: a == b True - sage: a != b # optional - arb + sage: a != b False """ cdef ComplexBall lt, rt diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index f7ad8c92f67..2405ce375ae 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -5,11 +5,9 @@ AUTHORS: - Clemens Heuberger (2014-10-21): Initial version. -This is a binding to the optional `Arb library `_; it +This is a binding to the `Arb library `_; it may be useful to refer to its documentation for more details. -You may have to run ``sage -i arb`` to use the arb library. - Parts of the documentation for this module are copied or adapted from Arb's own documentation, licenced under the GNU General Public License version 2, or later. @@ -28,75 +26,75 @@ Comparison Two elements are equal if and only if they are the same object or if both are exact and equal:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: a = RBF(1) # optional - arb - sage: b = RBF(1) # optional - arb - sage: a is b # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() + sage: a = RBF(1) + sage: b = RBF(1) + sage: a is b False - sage: a == b # optional - arb + sage: a == b True - sage: a = RBF(1/3) # optional - arb - sage: b = RBF(1/3) # optional - arb - sage: a.is_exact() # optional - arb + sage: a = RBF(1/3) + sage: b = RBF(1/3) + sage: a.is_exact() False - sage: b.is_exact() # optional - arb + sage: b.is_exact() False - sage: a is b # optional - arb + sage: a is b False - sage: a == b # optional - arb + sage: a == b False A ball is non-zero if and only if it does not contain zero. :: - sage: a = RBF(RIF(-0.5, 0.5)) # optional - arb - sage: bool(a) # optional - arb + sage: a = RBF(RIF(-0.5, 0.5)) + sage: bool(a) False - sage: a != 0 # optional - arb + sage: a != 0 False - sage: b = RBF(1/3) # optional - arb - sage: bool(b) # optional - arb + sage: b = RBF(1/3) + sage: bool(b) True - sage: b != 0 # optional - arb + sage: b != 0 True A ball ``left`` is less than a ball ``right`` if all elements of ``left`` are less than all elements of ``right``. :: - sage: a = RBF(RIF(1, 2)) # optional - arb - sage: b = RBF(RIF(3, 4)) # optional - arb - sage: a < b # optional - arb + sage: a = RBF(RIF(1, 2)) + sage: b = RBF(RIF(3, 4)) + sage: a < b True - sage: a <= b # optional - arb + sage: a <= b True - sage: a > b # optional - arb + sage: a > b False - sage: a >= b # optional - arb + sage: a >= b False - sage: a = RBF(RIF(1, 3)) # optional - arb - sage: b = RBF(RIF(2, 4)) # optional - arb - sage: a < b # optional - arb + sage: a = RBF(RIF(1, 3)) + sage: b = RBF(RIF(2, 4)) + sage: a < b False - sage: a <= b # optional - arb + sage: a <= b False - sage: a > b # optional - arb + sage: a > b False - sage: a >= b # optional - arb + sage: a >= b False Comparisons with Sage symbolic infinities work with some limitations:: - sage: -infinity < RBF(1) < +infinity # optional - arb + sage: -infinity < RBF(1) < +infinity True - sage: -infinity < RBF(infinity) # optional - arb + sage: -infinity < RBF(infinity) True - sage: RBF(infinity) < infinity # optional - arb + sage: RBF(infinity) < infinity False - sage: RBF(NaN) < infinity # optional - arb + sage: RBF(NaN) < infinity Traceback (most recent call last): ... ValueError: infinite but not with +/- phase - sage: 1/RBF(0) <= infinity # optional - arb + sage: 1/RBF(0) <= infinity Traceback (most recent call last): ... ValueError: infinite but not with +/- phase @@ -104,15 +102,15 @@ Comparisons with Sage symbolic infinities work with some limitations:: Comparisons between elements of real ball fields, however, support special values and should be preferred:: - sage: RBF(NaN) < RBF(infinity) # optional - arb + sage: RBF(NaN) < RBF(infinity) False - sage: 1/RBF(0) <= RBF(infinity) # optional - arb + sage: 1/RBF(0) <= RBF(infinity) True TESTS:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: (RBF(pi) * identity_matrix(QQ, 3)).parent() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: (RBF(pi) * identity_matrix(QQ, 3)).parent() Full MatrixSpace of 3 by 3 dense matrices over Real ball field with 53 bits precision Classes and Methods @@ -203,8 +201,8 @@ cdef int arb_to_mpfi(mpfi_t target, arb_t source, const long precision) except - EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RIF(RBF(2)**(2**100)) # optional - arb, indirect doctest + sage: from sage.rings.real_arb import RBF + sage: RIF(RBF(2)**(2**100)) # indirect doctest Traceback (most recent call last): ... ArithmeticError: Error converting arb to mpfi. Overflow? @@ -237,38 +235,38 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb; indirect doctest - sage: RBF(1) # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() # indirect doctest + sage: RBF(1) 1.000000000000000 :: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: (1/2*RBF(1)) + AA(sqrt(2)) - 1 + polygen(QQ, x) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: (1/2*RBF(1)) + AA(sqrt(2)) - 1 + polygen(QQ, x) x + [0.914213562373095 +/- 4.10e-16] TESTS:: - sage: RBF.bracket(RBF(1/2), RBF(1/3)) # optional - arb + sage: RBF.bracket(RBF(1/2), RBF(1/3)) [+/- 5.56e-17] - sage: RBF.cardinality() # optional - arb + sage: RBF.cardinality() +Infinity - sage: RBF.cartesian_product(QQ).an_element()**2 # optional - arb + sage: RBF.cartesian_product(QQ).an_element()**2 ([1.440000000000000 +/- 4.98e-16], 1/4) - sage: RBF.coerce_embedding() is None # optional - arb + sage: RBF.coerce_embedding() is None True - sage: loads(dumps(RBF)) is RBF # optional - arb + sage: loads(dumps(RBF)) is RBF True - sage: RBF['x'].gens_dict_recursive() # optional - arb + sage: RBF['x'].gens_dict_recursive() {'x': x} - sage: RBF.is_finite() # optional - arb + sage: RBF.is_finite() False - sage: RBF.is_zero() # optional - arb + sage: RBF.is_zero() False - sage: RBF.one() # optional - arb + sage: RBF.one() 1.000000000000000 - sage: RBF.zero() # optional - arb + sage: RBF.zero() 0 """ Element = RealBall @@ -280,8 +278,8 @@ class RealBallField(UniqueRepresentation, Parent): TESTS:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField(53) is RealBallField() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField(53) is RealBallField() True """ return super(RealBallField, cls).__classcall__(cls, precision, category) @@ -296,15 +294,15 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: RBF(1) # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() + sage: RBF(1) 1.000000000000000 - sage: RealBallField(0) # optional - arb + sage: RealBallField(0) Traceback (most recent call last): ... ValueError: Precision must be at least 2. - sage: RealBallField(1) # optional - arb + sage: RealBallField(1) Traceback (most recent call last): ... ValueError: Precision must be at least 2. @@ -323,10 +321,10 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField() Real ball field with 53 bits precision - sage: RealBallField(106) # optional - arb + sage: RealBallField(106) Real ball field with 106 bits precision """ return "Real ball field with {} bits precision".format(self._prec) @@ -342,16 +340,16 @@ class RealBallField(UniqueRepresentation, Parent): TESTS:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField().has_coerce_map_from(RealBallField(54)) # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField().has_coerce_map_from(RealBallField(54)) True - sage: RealBallField().has_coerce_map_from(RealBallField(52)) # optional - arb + sage: RealBallField().has_coerce_map_from(RealBallField(52)) False - sage: RealBallField().has_coerce_map_from(RIF) # optional - arb + sage: RealBallField().has_coerce_map_from(RIF) False - sage: RealBallField().has_coerce_map_from(SR) # optional - arb + sage: RealBallField().has_coerce_map_from(SR) False - sage: RealBallField().has_coerce_map_from(RR) # optional - arb + sage: RealBallField().has_coerce_map_from(RR) False """ from sage.rings.qqbar import AA @@ -373,12 +371,12 @@ class RealBallField(UniqueRepresentation, Parent): anything that is convertible to a real interval can also be used to construct a real ball:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(RIF(0, 1)) # optional - arb; indirect doctest + sage: from sage.rings.real_arb import RBF + sage: RBF(RIF(0, 1)) # indirect doctest [+/- 1.01] - sage: RBF(1) # optional - arb + sage: RBF(1) 1.000000000000000 - sage: RBF(x) # optional - arb + sage: RBF(x) Traceback (most recent call last): ... TypeError: unable to convert x to a RealIntervalFieldElement @@ -386,9 +384,9 @@ class RealBallField(UniqueRepresentation, Parent): Various symbolic constants can be converted without going through real intervals. (This is faster and yields tighter error bounds.) :: - sage: RBF(e) # optional - arb + sage: RBF(e) [2.718281828459045 +/- 5.35e-16] - sage: RBF(pi) # optional - arb + sage: RBF(pi) [3.141592653589793 +/- 5.61e-16] """ try: @@ -411,10 +409,10 @@ class RealBallField(UniqueRepresentation, Parent): r""" EXAMPLE:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF.gens() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF.gens() (1.000000000000000,) - sage: RBF.gens_dict() # optional - arb + sage: RBF.gens_dict() {'1.000000000000000': 1.000000000000000} """ return (self.one(),) @@ -425,8 +423,8 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLE:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF.base() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF.base() Real ball field with 53 bits precision """ return self @@ -437,8 +435,8 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLE:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF.base_ring() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF.base_ring() Real ball field with 53 bits precision """ return self @@ -450,12 +448,12 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField(42) # optional - arb - sage: functor, base = RBF.construction() # optional - arb - sage: functor, base # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField(42) + sage: functor, base = RBF.construction() + sage: functor, base (Completion[+Infinity], Rational Field) - sage: functor(base) is RBF # optional - arb + sage: functor(base) is RBF True """ from sage.categories.pushout import CompletionFunctor @@ -470,8 +468,8 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField().precision() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField().precision() 53 """ return self._prec @@ -482,8 +480,8 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField().is_exact() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField().is_exact() False """ return False @@ -494,8 +492,8 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField().characteristic() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField().characteristic() 0 """ return 0 @@ -507,8 +505,8 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF.some_elements() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF.some_elements() [1.000000000000000, [0.3333333333333333 +/- 7.04e-17], [-4.733045976388941e+363922934236666733021124 +/- 3.46e+363922934236666733021108], @@ -534,17 +532,17 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF.sinpi(1) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF.sinpi(1) 0 - sage: RBF.sinpi(1/3) # optional - arb + sage: RBF.sinpi(1/3) [0.866025403784439 +/- 5.15e-16] - sage: RBF.sinpi(1 + 2^(-100)) # optional - arb + sage: RBF.sinpi(1 + 2^(-100)) [-2.478279624546525e-30 +/- 5.90e-46] TESTS:: - sage: RBF.sinpi(RLF(sqrt(2))) # optional - arb + sage: RBF.sinpi(RLF(sqrt(2))) [-0.96390253284988 +/- 4.11e-15] """ cdef RealBall res, x_as_ball @@ -581,15 +579,15 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF.cospi(1) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF.cospi(1) -1.000000000000000 - sage: RBF.cospi(1/3) # optional - arb + sage: RBF.cospi(1/3) 0.5000000000000000 TESTS:: - sage: RBF.cospi(RLF(sqrt(2))) # optional - arb + sage: RBF.cospi(RLF(sqrt(2))) [-0.26625534204142 +/- 5.38e-15] """ cdef RealBall res, x_as_ball @@ -626,19 +624,19 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF.gamma(5) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF.gamma(5) 24.00000000000000 - sage: RBF.gamma(10**20) # optional - arb + sage: RBF.gamma(10**20) [+/- 5.92e+1956570551809674821757] - sage: RBF.gamma(1/3) # optional - arb + sage: RBF.gamma(1/3) [2.678938534707747 +/- 8.99e-16] - sage: RBF.gamma(-5) # optional - arb + sage: RBF.gamma(-5) nan TESTS:: - sage: RBF.gamma(RLF(pi)) # optional - arb + sage: RBF.gamma(RLF(pi)) [2.2880377953400 +/- 4.29e-14] """ cdef RealBall res @@ -686,12 +684,12 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF.zeta(3) # abs tol 5e-16, optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF.zeta(3) # abs tol 5e-16 [1.202056903159594 +/- 2.87e-16] - sage: RBF.zeta(1) # optional - arb + sage: RBF.zeta(1) nan - sage: RBF.zeta(1/2) # optional - arb + sage: RBF.zeta(1/2) [-1.460354508809587 +/- 1.94e-16] """ cdef RealBall res @@ -714,25 +712,25 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: [RBF.bernoulli(n) for n in range(4)] # optional - arb + sage: from sage.rings.real_arb import RBF + sage: [RBF.bernoulli(n) for n in range(4)] [1.000000000000000, -0.5000000000000000, [0.1666666666666667 +/- 7.04e-17], 0] - sage: RBF.bernoulli(2**20) # optional - arb + sage: RBF.bernoulli(2**20) [-1.823002872104961e+5020717 +/- 7.16e+5020701] - sage: RBF.bernoulli(2**1000) # optional - arb + sage: RBF.bernoulli(2**1000) Traceback (most recent call last): ... ValueError: argument too large TESTS:: - sage: RBF.bernoulli(2r) # optional - arb + sage: RBF.bernoulli(2r) [0.1666666666666667 +/- 7.04e-17] - sage: RBF.bernoulli(2/3) # optional - arb + sage: RBF.bernoulli(2/3) Traceback (most recent call last): ... TypeError: no canonical coercion from Rational Field to Integer Ring - sage: RBF.bernoulli(-1) # optional - arb + sage: RBF.bernoulli(-1) Traceback (most recent call last): ... ValueError: expected a nonnegative index @@ -757,8 +755,8 @@ class RealBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: [RBF.fibonacci(n) for n in xrange(7)] # optional - arb + sage: from sage.rings.real_arb import RBF + sage: [RBF.fibonacci(n) for n in xrange(7)] [0, 1.000000000000000, 1.000000000000000, @@ -766,9 +764,9 @@ class RealBallField(UniqueRepresentation, Parent): 3.000000000000000, 5.000000000000000, 8.000000000000000] - sage: RBF.fibonacci(-2) # optional - arb + sage: RBF.fibonacci(-2) -1.000000000000000 - sage: RBF.fibonacci(10**20) # optional - arb + sage: RBF.fibonacci(10**20) [3.78202087472056e+20898764024997873376 +/- 4.01e+20898764024997873361] """ cdef fmpz_t tmpz @@ -791,9 +789,9 @@ cdef inline bint _do_sig(long prec): TESTS:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: _ = RealBallField()(1).psi() # optional - arb; indirect doctest - sage: _ = RealBallField(1500)(1).psi() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: _ = RealBallField()(1).psi() # indirect doctest + sage: _ = RealBallField(1500)(1).psi() """ return (prec > 1000) @@ -807,12 +805,12 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: a = RealBallField()(RIF(1)) # optional - arb; indirect doctest - sage: b = a.psi() # optional - arb - sage: b # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: a = RealBallField()(RIF(1)) # indirect doctest + sage: b = a.psi() + sage: b [-0.577215664901533 +/- 3.85e-16] - sage: RIF(b) # optional - arb + sage: RIF(b) -0.577215664901533? """ @@ -822,8 +820,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField()(RIF(1)) # optional - arb; indirect doctest + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField()(RIF(1)) # indirect doctest 1.000000000000000 """ arb_init(self.value) @@ -834,9 +832,9 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: a = RealBallField()(RIF(1)) # optional - arb; indirect doctest - sage: del a # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: a = RealBallField()(RIF(1)) # indirect doctest + sage: del a """ arb_clear(self.value) @@ -858,36 +856,36 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: RBF() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() + sage: RBF() 0 One can create exact real balls using elements of various exact parents, or using floating-point numbers:: - sage: RBF(3) # optional - arb + sage: RBF(3) 3.000000000000000 - sage: RBF(3r) # optional - arb + sage: RBF(3r) 3.000000000000000 - sage: RBF(1/3) # optional - arb + sage: RBF(1/3) [0.3333333333333333 +/- 7.04e-17] - sage: RBF(3.14) # optional - arb + sage: RBF(3.14) [3.140000000000000 +/- 1.25e-16] :: - sage: RBF(3, 0.125) # optional - arb + sage: RBF(3, 0.125) [3e+0 +/- 0.126] - sage: RBF(pi, 0.125r) # optional - arb + sage: RBF(pi, 0.125r) [3e+0 +/- 0.267] Note that integers and floating-point numbers are ''not'' rounded to the parent's precision:: - sage: b = RBF(11111111111111111111111111111111111111111111111); b # optional - arb + sage: b = RBF(11111111111111111111111111111111111111111111111); b [1.111111111111111e+46 +/- 1.12e+30] - sage: b.mid().exact_rational() # optional - arb + sage: b.mid().exact_rational() 11111111111111111111111111111111111111111111111 Similarly, converting a real ball from one real ball field to another @@ -895,35 +893,35 @@ cdef class RealBall(RingElement): the precision of operations involving it, not the actual representation of its center:: - sage: RBF100 = RealBallField(100) # optional - arb - sage: b100 = RBF100(1/3); b100 # optional - arb + sage: RBF100 = RealBallField(100) + sage: b100 = RBF100(1/3); b100 [0.333333333333333333333333333333 +/- 4.65e-31] - sage: b53 = RBF(b100); b53 # optional - arb + sage: b53 = RBF(b100); b53 [0.3333333333333333 +/- 3.34e-17] - sage: RBF100(b53) # optional - arb + sage: RBF100(b53) [0.333333333333333333333333333333 +/- 4.65e-31] Special values are supported:: - sage: RBF(oo).mid(), RBF(-oo).mid(), RBF(unsigned_infinity).mid() # optional - arb + sage: RBF(oo).mid(), RBF(-oo).mid(), RBF(unsigned_infinity).mid() (+infinity, -infinity, 0.000000000000000) - sage: RBF(NaN) # optional - arb + sage: RBF(NaN) nan TESTS:: - sage: from sage.rings.real_arb import RealBall # optional - arb - sage: RealBall(RBF, sage.symbolic.constants.Pi()) # abs tol 1e-16, optional - arb + sage: from sage.rings.real_arb import RealBall + sage: RealBall(RBF, sage.symbolic.constants.Pi()) # abs tol 1e-16 [3.141592653589793 +/- 5.62e-16] - sage: RealBall(RBF, sage.symbolic.constants.Log2()) # abs tol 1e-16, optional - arb + sage: RealBall(RBF, sage.symbolic.constants.Log2()) # abs tol 1e-16 [0.693147180559945 +/- 4.06e-16] - sage: RealBall(RBF, sage.symbolic.constants.Catalan()) # optional - arb + sage: RealBall(RBF, sage.symbolic.constants.Catalan()) [0.915965594177219 +/- 1.23e-16] - sage: RealBall(RBF, sage.symbolic.constants.Khinchin()) # optional - arb + sage: RealBall(RBF, sage.symbolic.constants.Khinchin()) [2.685452001065306 +/- 6.82e-16] - sage: RealBall(RBF, sage.symbolic.constants.Glaisher()) # optional - arb + sage: RealBall(RBF, sage.symbolic.constants.Glaisher()) [1.282427129100623 +/- 6.02e-16] - sage: RealBall(RBF, sage.symbolic.constants.e) # optional - arb + sage: RealBall(RBF, sage.symbolic.constants.e) [2.718281828459045 +/- 5.35e-16] """ cdef fmpz_t tmpz @@ -1018,8 +1016,8 @@ cdef class RealBall(RingElement): TESTS:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField()(2)**2 # indirect doctest, optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField()(2)**2 # indirect doctest 4.000000000000000 """ @@ -1038,8 +1036,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField()(RIF(1.9, 2)) # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField()(RIF(1.9, 2)) [2e+0 +/- 0.101] """ cdef char* c_result @@ -1065,9 +1063,9 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: a = RealBallField()(RIF(2)) # optional - arb - sage: RIF(a) # optional - arb, indirect doctest + sage: from sage.rings.real_arb import RealBallField + sage: a = RealBallField()(RIF(2)) + sage: RIF(a) # indirect doctest 2 """ cdef RealIntervalFieldElement result @@ -1081,14 +1079,14 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: ZZ(RBF(1, rad=0.1r)) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: ZZ(RBF(1, rad=0.1r)) 1 - sage: ZZ(RBF(1, rad=1.0r)) # optional - arb + sage: ZZ(RBF(1, rad=1.0r)) Traceback (most recent call last): ... ValueError: [+/- 2.01] does not contain a unique integer - sage: ZZ(RBF(pi)) # optional - arb + sage: ZZ(RBF(pi)) Traceback (most recent call last): ... ValueError: [3.141592653589793 +/- 5.61e-16] does not contain a unique integer @@ -1116,31 +1114,31 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: mypi = RBF(pi) # optional - arb - sage: RR(mypi) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: mypi = RBF(pi) + sage: RR(mypi) 3.14159265358979 - sage: Reals(rnd='RNDU')(mypi) # optional - arb + sage: Reals(rnd='RNDU')(mypi) 3.14159265358980 - sage: Reals(rnd='RNDD')(mypi) # optional - arb + sage: Reals(rnd='RNDD')(mypi) 3.14159265358979 - sage: Reals(rnd='RNDZ')(mypi) # optional - arb + sage: Reals(rnd='RNDZ')(mypi) 3.14159265358979 - sage: Reals(rnd='RNDZ')(-mypi) # optional - arb + sage: Reals(rnd='RNDZ')(-mypi) -3.14159265358979 - sage: Reals(rnd='RNDU')(-mypi) # optional - arb + sage: Reals(rnd='RNDU')(-mypi) -3.14159265358979 :: - sage: b = RBF(RIF(-1/2, 1)) # optional - arb - sage: RR(b) # optional - arb + sage: b = RBF(RIF(-1/2, 1)) + sage: RR(b) 0.250000000000000 - sage: Reals(rnd='RNDU')(b) # optional - arb + sage: Reals(rnd='RNDU')(b) 1.00000000093133 - sage: Reals(rnd='RNDD')(b) # optional - arb + sage: Reals(rnd='RNDD')(b) -0.500000000931323 - sage: Reals(rnd='RNDZ')(b) # optional - arb + sage: Reals(rnd='RNDZ')(b) 0.250000000000000 """ cdef RealNumber left, mid, right @@ -1183,16 +1181,16 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField, RBF # optional - arb - sage: RealBallField(16)(1/3).mid() # optional - arb + sage: from sage.rings.real_arb import RealBallField, RBF + sage: RealBallField(16)(1/3).mid() 0.3333 - sage: RealBallField(16)(1/3).mid().parent() # optional - arb + sage: RealBallField(16)(1/3).mid().parent() Real Field with 15 bits of precision :: - sage: b = RBF(2)^(2^1000) # optional - arb - sage: b.mid() # optional - arb + sage: b = RBF(2)^(2^1000) + sage: b.mid() Traceback (most recent call last): ... RuntimeError: unable to convert to MPFR (exponent out of range?) @@ -1211,10 +1209,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RealBallField()(1/3).rad() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RealBallField()(1/3).rad() 5.5511151e-17 - sage: RealBallField()(1/3).rad().parent() # optional - arb + sage: RealBallField()(1/3).rad().parent() Real Field with 30 bits of precision """ # Should we return a real number with rounding towards +∞ (or away from @@ -1238,13 +1236,13 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: mid = RealBallField(16)(1/3).squash() # optional - arb - sage: mid # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: mid = RealBallField(16)(1/3).squash() + sage: mid [0.3333 +/- 2.83e-5] - sage: mid.is_exact() # optional - arb + sage: mid.is_exact() True - sage: mid.parent() # optional - arb + sage: mid.parent() Real ball field with 16 bits precision """ cdef RealBall res = self._new() @@ -1260,13 +1258,13 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: rad = RBF(1/3).rad_as_ball() # optional - arb - sage: rad # optional - arb + sage: from sage.rings.real_arb import RBF + sage: rad = RBF(1/3).rad_as_ball() + sage: rad [5.55111512e-17 +/- 3.13e-26] - sage: rad.is_exact() # optional - arb + sage: rad.is_exact() True - sage: rad.parent() # optional - arb + sage: rad.parent() Real ball field with 30 bits precision """ cdef RealBall res = self._parent.element_class(RealBallField(MAG_BITS)) @@ -1285,11 +1283,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: b = RBF(pi.n(100)) # optional - arb - sage: b.mid() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: b = RBF(pi.n(100)) + sage: b.mid() 3.141592653589793238462643383 - sage: b.round().mid() # optional - arb + sage: b.round().mid() 3.1415926535898 """ cdef RealBall res = self._new() @@ -1308,12 +1306,12 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(pi).accuracy() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(pi).accuracy() 51 - sage: RBF(1).accuracy() # optional - arb + sage: RBF(1).accuracy() 9223372036854775807 - sage: RBF(NaN).accuracy() # optional - arb + sage: RBF(NaN).accuracy() -9223372036854775807 """ return arb_rel_accuracy_bits(self.value) @@ -1331,11 +1329,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: b = RBF(RIF(3.1415,3.1416)) # optional - arb - sage: b.mid() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: b = RBF(RIF(3.1415,3.1416)) + sage: b.mid() 3.14155000000000 - sage: b.trim().mid() # optional - arb + sage: b.trim().mid() 3.14155000 """ cdef RealBall res = self._new() @@ -1352,11 +1350,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: RBF(0).is_zero() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() + sage: RBF(0).is_zero() True - sage: RBF(RIF(-0.5, 0.5)).is_zero() # optional - arb + sage: RBF(RIF(-0.5, 0.5)).is_zero() False """ return arb_is_zero(self.value) @@ -1368,11 +1366,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: bool(RBF(pi)) # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() + sage: bool(RBF(pi)) True - sage: bool(RBF(RIF(-0.5, 0.5))) # optional - arb + sage: bool(RBF(RIF(-0.5, 0.5))) False """ return arb_is_nonzero(self.value) @@ -1383,11 +1381,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: RBF(1).is_exact() # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() + sage: RBF(1).is_exact() True - sage: RBF(RIF(0.1, 0.2)).is_exact() # optional - arb + sage: RBF(RIF(0.1, 0.2)).is_exact() False """ return arb_is_exact(self.value) @@ -1400,21 +1398,21 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: a = RBF(1) # optional - arb - sage: b = RBF(1) # optional - arb - sage: a is b # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() + sage: a = RBF(1) + sage: b = RBF(1) + sage: a is b False - sage: a == b # optional - arb + sage: a == b True - sage: a = RBF(1/3) # optional - arb - sage: a.is_exact() # optional - arb + sage: a = RBF(1/3) + sage: a.is_exact() False - sage: b = RBF(1/3) # optional - arb - sage: b.is_exact() # optional - arb + sage: b = RBF(1/3) + sage: b.is_exact() False - sage: a == b # optional - arb + sage: a == b False """ return (left)._richcmp(right, op) @@ -1427,163 +1425,163 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RealBallField # optional - arb - sage: RBF = RealBallField() # optional - arb - sage: a = RBF(1) # optional - arb - sage: b = RBF(1) # optional - arb - sage: a is b # optional - arb + sage: from sage.rings.real_arb import RealBallField + sage: RBF = RealBallField() + sage: a = RBF(1) + sage: b = RBF(1) + sage: a is b False - sage: a == b # optional - arb + sage: a == b True TESTS: Balls whose intersection consists of one point:: - sage: a = RBF(RIF(1, 2)) # optional - arb - sage: b = RBF(RIF(2, 4)) # optional - arb - sage: a < b # optional - arb + sage: a = RBF(RIF(1, 2)) + sage: b = RBF(RIF(2, 4)) + sage: a < b False - sage: a > b # optional - arb + sage: a > b False - sage: a <= b # optional - arb + sage: a <= b False - sage: a >= b # optional - arb + sage: a >= b False - sage: a == b # optional - arb + sage: a == b False - sage: a != b # optional - arb + sage: a != b False Balls with non-trivial intersection:: - sage: a = RBF(RIF(1, 4)) # optional - arb - sage: a = RBF(RIF(2, 5)) # optional - arb - sage: a < b # optional - arb + sage: a = RBF(RIF(1, 4)) + sage: a = RBF(RIF(2, 5)) + sage: a < b False - sage: a <= b # optional - arb + sage: a <= b False - sage: a > b # optional - arb + sage: a > b False - sage: a >= b # optional - arb + sage: a >= b False - sage: a == b # optional - arb + sage: a == b False - sage: a != b # optional - arb + sage: a != b False One ball contained in another:: - sage: a = RBF(RIF(1, 4)) # optional - arb - sage: b = RBF(RIF(2, 3)) # optional - arb - sage: a < b # optional - arb + sage: a = RBF(RIF(1, 4)) + sage: b = RBF(RIF(2, 3)) + sage: a < b False - sage: a <= b # optional - arb + sage: a <= b False - sage: a > b # optional - arb + sage: a > b False - sage: a >= b # optional - arb + sage: a >= b False - sage: a == b # optional - arb + sage: a == b False - sage: a != b # optional - arb + sage: a != b False Disjoint balls:: - sage: a = RBF(1/3) # optional - arb - sage: b = RBF(1/2) # optional - arb - sage: a < b # optional - arb + sage: a = RBF(1/3) + sage: b = RBF(1/2) + sage: a < b True - sage: a <= b # optional - arb + sage: a <= b True - sage: a > b # optional - arb + sage: a > b False - sage: a >= b # optional - arb + sage: a >= b False - sage: a == b # optional - arb + sage: a == b False - sage: a != b # optional - arb + sage: a != b True Exact elements:: - sage: a = RBF(2) # optional - arb - sage: b = RBF(2) # optional - arb - sage: a.is_exact() # optional - arb + sage: a = RBF(2) + sage: b = RBF(2) + sage: a.is_exact() True - sage: b.is_exact() # optional - arb + sage: b.is_exact() True - sage: a < b # optional - arb + sage: a < b False - sage: a <= b # optional - arb + sage: a <= b True - sage: a > b # optional - arb + sage: a > b False - sage: a >= b # optional - arb + sage: a >= b True - sage: a == b # optional - arb + sage: a == b True - sage: a != b # optional - arb + sage: a != b False Special values:: - sage: inf = RBF(+infinity) # optional - arb - sage: other_inf = RBF(+infinity, 42.r) # optional - arb - sage: neg_inf = RBF(-infinity) # optional - arb - sage: extended_line = 1/RBF(0) # optional - arb - sage: exact_nan = inf - inf # optional - arb - sage: exact_nan.mid(), exact_nan.rad() # optional - arb + sage: inf = RBF(+infinity) + sage: other_inf = RBF(+infinity, 42.r) + sage: neg_inf = RBF(-infinity) + sage: extended_line = 1/RBF(0) + sage: exact_nan = inf - inf + sage: exact_nan.mid(), exact_nan.rad() (NaN, 0.00000000) - sage: other_exact_nan = inf - inf # optional - arb + sage: other_exact_nan = inf - inf :: - sage: exact_nan == exact_nan, exact_nan <= exact_nan, exact_nan >= exact_nan # optional - arb + sage: exact_nan == exact_nan, exact_nan <= exact_nan, exact_nan >= exact_nan (False, False, False) - sage: exact_nan != exact_nan, exact_nan < exact_nan, exact_nan > exact_nan # optional - arb + sage: exact_nan != exact_nan, exact_nan < exact_nan, exact_nan > exact_nan (False, False, False) - sage: from operator import eq, ne, le, lt, ge, gt # optional - arb - sage: ops = [eq, ne, le, lt, ge, gt] # optional - arb - sage: any(op(exact_nan, other_exact_nan) for op in ops) # optional - arb + sage: from operator import eq, ne, le, lt, ge, gt + sage: ops = [eq, ne, le, lt, ge, gt] + sage: any(op(exact_nan, other_exact_nan) for op in ops) False - sage: any(op(exact_nan, b) for op in ops for b in [RBF(1), extended_line, inf, neg_inf]) # optional - arb + sage: any(op(exact_nan, b) for op in ops for b in [RBF(1), extended_line, inf, neg_inf]) False :: - sage: neg_inf < a < inf and inf > a > neg_inf # optional - arb + sage: neg_inf < a < inf and inf > a > neg_inf True - sage: neg_inf <= b <= inf and inf >= b >= neg_inf # optional - arb + sage: neg_inf <= b <= inf and inf >= b >= neg_inf True - sage: neg_inf <= extended_line <= inf and inf >= extended_line >= neg_inf # optional - arb + sage: neg_inf <= extended_line <= inf and inf >= extended_line >= neg_inf True - sage: neg_inf < extended_line or extended_line < inf # optional - arb + sage: neg_inf < extended_line or extended_line < inf False - sage: inf > extended_line or extended_line > neg_inf # optional - arb + sage: inf > extended_line or extended_line > neg_inf False :: - sage: all(b <= b == b >= b and not (b < b or b != b or b > b) # optional - arb + sage: all(b <= b == b >= b and not (b < b or b != b or b > b) ....: for b in [inf, neg_inf, other_inf]) True - sage: any(b1 == b2 for b1 in [inf, neg_inf, a, extended_line] # optional - arb + sage: any(b1 == b2 for b1 in [inf, neg_inf, a, extended_line] ....: for b2 in [inf, neg_inf, a, extended_line] ....: if not b1 is b2) False - sage: all(b1 != b2 and not b1 == b2 # optional - arb + sage: all(b1 != b2 and not b1 == b2 ....: for b1 in [inf, neg_inf, a] ....: for b2 in [inf, neg_inf, a] ....: if not b1 is b2) True - sage: neg_inf <= -other_inf == neg_inf == -other_inf < other_inf == inf <= other_inf # optional - arb + sage: neg_inf <= -other_inf == neg_inf == -other_inf < other_inf == inf <= other_inf True - sage: any(inf < b or b > inf # optional - arb + sage: any(inf < b or b > inf ....: for b in [inf, other_inf, a, extended_line]) False - sage: any(inf <= b or b >= inf for b in [a, extended_line]) # optional - arb + sage: any(inf <= b or b >= inf for b in [a, extended_line]) False """ cdef RealBall lt, rt @@ -1653,10 +1651,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: (RBF(2)^(2^1000)).is_finite() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: (RBF(2)^(2^1000)).is_finite() True - sage: RBF(oo).is_finite() # optional - arb + sage: RBF(oo).is_finite() False """ return arb_is_finite(self.value) @@ -1675,12 +1673,12 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).identical(RBF(3)-RBF(2)) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).identical(RBF(3)-RBF(2)) True - sage: RBF(1, rad=0.25r).identical(RBF(1, rad=0.25r)) # optional - arb + sage: RBF(1, rad=0.25r).identical(RBF(1, rad=0.25r)) True - sage: RBF(1).identical(RBF(1, rad=0.25r)) # optional - arb + sage: RBF(1).identical(RBF(1, rad=0.25r)) False """ return arb_equal(self.value, other.value) @@ -1695,10 +1693,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(pi).overlaps(RBF(pi) + 2**(-100)) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(pi).overlaps(RBF(pi) + 2**(-100)) True - sage: RBF(pi).overlaps(RBF(3)) # optional - arb + sage: RBF(pi).overlaps(RBF(3)) False """ return arb_overlaps(self.value, other.value) @@ -1718,29 +1716,29 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: b = RBF(1) # optional - arb - sage: b.contains_exact(1) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: b = RBF(1) + sage: b.contains_exact(1) True - sage: b.contains_exact(QQ(1)) # optional - arb + sage: b.contains_exact(QQ(1)) True - sage: b.contains_exact(1.) # optional - arb + sage: b.contains_exact(1.) True - sage: b.contains_exact(b) # optional - arb + sage: b.contains_exact(b) True :: - sage: RBF(1/3).contains_exact(1/3) # optional - arb + sage: RBF(1/3).contains_exact(1/3) True - sage: RBF(sqrt(2)).contains_exact(sqrt(2)) # optional - arb + sage: RBF(sqrt(2)).contains_exact(sqrt(2)) Traceback (most recent call last): ... TypeError TESTS:: - sage: b.contains_exact(1r) # optional - arb + sage: b.contains_exact(1r) True """ @@ -1781,13 +1779,13 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF, RealBallField # optional - arb - sage: sqrt(2) in RBF(sqrt(2)) # optional - arb + sage: from sage.rings.real_arb import RBF, RealBallField + sage: sqrt(2) in RBF(sqrt(2)) True A false negative:: - sage: sqrt(2) in RBF(RealBallField(100)(sqrt(2))) # optional - arb + sage: sqrt(2) in RBF(RealBallField(100)(sqrt(2))) False """ return self.contains_exact(self._parent(other)) @@ -1798,8 +1796,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(-infinity).is_negative_infinity() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(-infinity).is_negative_infinity() True """ return (arf_is_neg_inf(arb_midref(self.value)) @@ -1811,8 +1809,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(infinity).is_positive_infinity() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(infinity).is_positive_infinity() True """ return (arf_is_pos_inf(arb_midref(self.value)) @@ -1835,16 +1833,16 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(infinity).is_infinity() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(infinity).is_infinity() True - sage: RBF(-infinity).is_infinity() # optional - arb + sage: RBF(-infinity).is_infinity() True - sage: RBF(NaN).is_infinity() # optional - arb + sage: RBF(NaN).is_infinity() True - sage: (~RBF(0)).is_infinity() # optional - arb + sage: (~RBF(0)).is_infinity() True - sage: RBF(42, rad=1.r).is_infinity() # optional - arb + sage: RBF(42, rad=1.r).is_infinity() False """ return not self.is_finite() @@ -1857,8 +1855,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: -RBF(1/3) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: -RBF(1/3) [-0.3333333333333333 +/- 7.04e-17] """ cdef RealBall res = self._new() @@ -1874,12 +1872,12 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: ~RBF(5) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: ~RBF(5) [0.2000000000000000 +/- 4.45e-17] - sage: ~RBF(0) # optional - arb + sage: ~RBF(0) [+/- inf] - sage: RBF(RIF(-0.1,0.1)) # optional - arb + sage: RBF(RIF(-0.1,0.1)) [+/- 0.101] """ @@ -1898,8 +1896,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1) + RBF(1/3) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1) + RBF(1/3) [1.333333333333333 +/- 5.37e-16] """ cdef RealBall res = self._new() @@ -1918,8 +1916,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1) - RBF(1/3) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1) - RBF(1/3) [0.666666666666667 +/- 5.37e-16] """ cdef RealBall res = self._new() @@ -1938,8 +1936,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(-2) * RBF(1/3) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(-2) * RBF(1/3) [-0.666666666666667 +/- 4.82e-16] """ cdef RealBall res = self._new() @@ -1958,10 +1956,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(pi)/RBF(e) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(pi)/RBF(e) [1.155727349790922 +/- 8.43e-16] - sage: RBF(2)/RBF(0) # optional - arb + sage: RBF(2)/RBF(0) [+/- inf] """ cdef RealBall res = self._new() @@ -1974,30 +1972,30 @@ cdef class RealBall(RingElement): """ EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(e)^17 # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(e)^17 [24154952.7535753 +/- 9.30e-8] - sage: RBF(e)^(-1) # optional - arb + sage: RBF(e)^(-1) [0.367879441171442 +/- 4.50e-16] - sage: RBF(e)^(1/2) # optional - arb + sage: RBF(e)^(1/2) [1.648721270700128 +/- 4.96e-16] - sage: RBF(e)^RBF(pi) # optional - arb + sage: RBF(e)^RBF(pi) [23.1406926327793 +/- 9.16e-14] :: - sage: RBF(-1)^(1/3) # optional - arb + sage: RBF(-1)^(1/3) nan - sage: RBF(0)^(-1) # optional - arb + sage: RBF(0)^(-1) [+/- inf] - sage: RBF(-e)**RBF(pi) # optional - arb + sage: RBF(-e)**RBF(pi) nan TESTS:: - sage: RBF(e)**(2r) # optional - arb + sage: RBF(e)**(2r) [7.38905609893065 +/- 4.68e-15] - sage: RBF(e)**(-1r) # optional - arb + sage: RBF(e)**(-1r) [0.367879441171442 +/- 4.50e-16] """ cdef fmpz_t tmpz @@ -2030,10 +2028,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(2).sqrt() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(2).sqrt() [1.414213562373095 +/- 2.99e-16] - sage: RBF(-1/3).sqrt() # optional - arb + sage: RBF(-1/3).sqrt() nan """ cdef RealBall res = self._new() @@ -2051,12 +2049,12 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(2).sqrtpos() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(2).sqrtpos() [1.414213562373095 +/- 2.99e-16] - sage: RBF(-1/3).sqrtpos() # optional - arb + sage: RBF(-1/3).sqrtpos() 0 - sage: RBF(0, rad=2.r).sqrtpos() # optional - arb + sage: RBF(0, rad=2.r).sqrtpos() [+/- 1.42] """ cdef RealBall res = self._new() @@ -2073,10 +2071,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(2).rsqrt() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(2).rsqrt() [0.707106781186547 +/- 5.73e-16] - sage: RBF(0).rsqrt() # optional - arb + sage: RBF(0).rsqrt() nan """ cdef RealBall res = self._new() @@ -2092,11 +2090,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: eps = RBF(10^(-20)) # optional - arb - sage: (1 + eps).sqrt() - 1 # optional - arb + sage: from sage.rings.real_arb import RBF + sage: eps = RBF(10^(-20)) + sage: (1 + eps).sqrt() - 1 [+/- 1.12e-16] - sage: eps.sqrt1pm1() # optional - arb + sage: eps.sqrt1pm1() [5.00000000000000e-21 +/- 2.54e-36] """ cdef RealBall res = self._new() @@ -2113,8 +2111,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1000+1/3, rad=1.r).floor() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1000+1/3, rad=1.r).floor() [1.00e+3 +/- 1.01] """ cdef RealBall res = self._new() @@ -2129,8 +2127,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1000+1/3, rad=1.r).ceil() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1000+1/3, rad=1.r).ceil() [1.00e+3 +/- 2.01] """ cdef RealBall res = self._new() @@ -2147,10 +2145,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(3).log() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(3).log() [1.098612288668110 +/- 6.63e-16] - sage: RBF(-1/3).log() # optional - arb + sage: RBF(-1/3).log() nan """ cdef RealBall res = self._new() @@ -2166,11 +2164,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: eps = RBF(1e-30) # optional - arb - sage: (1 + eps).log() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: eps = RBF(1e-30) + sage: (1 + eps).log() [+/- 2.23e-16] - sage: eps.log1p() # optional - arb + sage: eps.log1p() [1.00000000000000e-30 +/- 2.68e-46] """ cdef RealBall res = self._new() @@ -2185,8 +2183,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).exp() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).exp() [2.718281828459045 +/- 5.41e-16] """ cdef RealBall res = self._new() @@ -2202,11 +2200,11 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: eps = RBF(1e-30) # optional - arb - sage: exp(eps) - 1 # optional - arb + sage: from sage.rings.real_arb import RBF + sage: eps = RBF(1e-30) + sage: exp(eps) - 1 [+/- 3.16e-30] - sage: eps.expm1() # optional - arb + sage: eps.expm1() [1.000000000000000e-30 +/- 8.34e-47] """ cdef RealBall res = self._new() @@ -2223,8 +2221,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(pi).sin() # abs tol 1e-16, optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(pi).sin() # abs tol 1e-16 [+/- 5.69e-16] """ cdef RealBall res = self._new() @@ -2241,8 +2239,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(pi).cos() # abs tol 1e-16, optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(pi).cos() # abs tol 1e-16 [-1.00000000000000 +/- 6.69e-16] """ cdef RealBall res = self._new() @@ -2257,10 +2255,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).tan() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).tan() [1.557407724654902 +/- 3.26e-16] - sage: RBF(pi/2).tan() # optional - arb + sage: RBF(pi/2).tan() [+/- inf] """ cdef RealBall res = self._new() @@ -2275,10 +2273,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).cot() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).cot() [0.642092615934331 +/- 4.79e-16] - sage: RBF(pi).cot() # optional - arb + sage: RBF(pi).cot() [+/- inf] """ cdef RealBall res = self._new() @@ -2293,10 +2291,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).arcsin() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).arcsin() [1.570796326794897 +/- 6.65e-16] - sage: RBF(1, rad=.125r).arcsin() # optional - arb + sage: RBF(1, rad=.125r).arcsin() nan """ cdef RealBall res = self._new() @@ -2311,10 +2309,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).arccos() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).arccos() 0 - sage: RBF(1, rad=.125r).arccos() # optional - arb + sage: RBF(1, rad=.125r).arccos() nan """ cdef RealBall res = self._new() @@ -2329,8 +2327,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).arctan() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).arctan() [0.785398163397448 +/- 3.91e-16] """ cdef RealBall res = self._new() @@ -2345,8 +2343,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).sinh() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).sinh() [1.175201193643801 +/- 6.18e-16] """ cdef RealBall res = self._new() @@ -2361,8 +2359,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).cosh() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).cosh() [1.543080634815244 +/- 5.28e-16] """ cdef RealBall res = self._new() @@ -2377,8 +2375,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).tanh() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).tanh() [0.761594155955765 +/- 2.81e-16] """ cdef RealBall res = self._new() @@ -2393,10 +2391,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).coth() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).coth() [1.313035285499331 +/- 4.97e-16] - sage: RBF(0).coth() # optional - arb + sage: RBF(0).coth() [+/- inf] """ cdef RealBall res = self._new() @@ -2411,10 +2409,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).arcsinh() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).arcsinh() [0.881373587019543 +/- 1.87e-16] - sage: RBF(0).arcsinh() # optional - arb + sage: RBF(0).arcsinh() 0 """ cdef RealBall res = self._new() @@ -2429,12 +2427,12 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(2).arccosh() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(2).arccosh() [1.316957896924817 +/- 6.61e-16] - sage: RBF(1).arccosh() # optional - arb + sage: RBF(1).arccosh() 0 - sage: RBF(0).arccosh() # optional - arb + sage: RBF(0).arccosh() nan """ cdef RealBall res = self._new() @@ -2449,12 +2447,12 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(0).arctanh() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(0).arctanh() 0 - sage: RBF(1/2).arctanh() # optional - arb + sage: RBF(1/2).arctanh() [0.549306144334055 +/- 3.32e-16] - sage: RBF(1).arctanh() # optional - arb + sage: RBF(1).arctanh() nan """ cdef RealBall res = self._new() @@ -2474,8 +2472,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1/2).gamma() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1/2).gamma() [1.772453850905516 +/- 3.41e-16] """ cdef RealBall res = self._new() @@ -2493,8 +2491,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1/2).log_gamma() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1/2).log_gamma() [0.572364942924700 +/- 4.87e-16] """ cdef RealBall res = self._new() @@ -2510,10 +2508,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(-1).rgamma() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(-1).rgamma() 0 - sage: RBF(3).rgamma() # optional - arb + sage: RBF(3).rgamma() 0.5000000000000000 """ cdef RealBall res = self._new() @@ -2528,8 +2526,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).psi() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).psi() [-0.577215664901533 +/- 3.85e-16] """ @@ -2550,12 +2548,12 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(-1).zeta() # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(-1).zeta() [-0.0833333333333333 +/- 4.36e-17] - sage: RBF(-1).zeta(1) # optional - arb + sage: RBF(-1).zeta(1) [-0.0833333333333333 +/- 6.81e-17] - sage: RBF(-1).zeta(2) # abs tol 1e-16, optional - arb + sage: RBF(-1).zeta(2) # abs tol 1e-16 [-1.083333333333333 +/- 4.09e-16] """ cdef RealBall a_ball @@ -2577,23 +2575,23 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: polylog(0, -1) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: polylog(0, -1) -1/2 - sage: RBF(-1).polylog(0) # optional - arb + sage: RBF(-1).polylog(0) [-0.50000000000000 +/- 1.29e-15] - sage: polylog(1, 1/2) # optional - arb + sage: polylog(1, 1/2) -log(1/2) - sage: RBF(1/2).polylog(1) # optional - arb + sage: RBF(1/2).polylog(1) [0.6931471805599 +/- 5.02e-14] - sage: RBF(1/3).polylog(1/2) # optional - arb + sage: RBF(1/3).polylog(1/2) [0.44210883528067 +/- 6.75e-15] - sage: RBF(1/3).polylog(RLF(pi)) # optional - arb + sage: RBF(1/3).polylog(RLF(pi)) [0.34728895057225 +/- 5.51e-15] TESTS:: - sage: RBF(1/3).polylog(2r) # optional - arb + sage: RBF(1/3).polylog(2r) [0.36621322997706 +/- 4.62e-15] """ cdef RealBall s_as_ball @@ -2621,16 +2619,16 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(pi).chebyshev_T(0) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(pi).chebyshev_T(0) 1.000000000000000 - sage: RBF(pi).chebyshev_T(1) # abs tol 1e-16, optional - arb + sage: RBF(pi).chebyshev_T(1) # abs tol 1e-16 [3.141592653589793 +/- 5.62e-16] - sage: RBF(pi).chebyshev_T(10**20) # optional - arb + sage: RBF(pi).chebyshev_T(10**20) Traceback (most recent call last): ... ValueError: index too large - sage: RBF(pi).chebyshev_T(-1) # optional - arb + sage: RBF(pi).chebyshev_T(-1) Traceback (most recent call last): ... ValueError: expected a nonnegative index @@ -2654,16 +2652,16 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(pi).chebyshev_U(0) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(pi).chebyshev_U(0) 1.000000000000000 - sage: RBF(pi).chebyshev_U(1) # optional - arb + sage: RBF(pi).chebyshev_U(1) [6.28318530717959 +/- 4.66e-15] - sage: RBF(pi).chebyshev_U(10**20) # optional - arb + sage: RBF(pi).chebyshev_U(10**20) Traceback (most recent call last): ... ValueError: index too large - sage: RBF(pi).chebyshev_U(-1) # optional - arb + sage: RBF(pi).chebyshev_U(-1) Traceback (most recent call last): ... ValueError: expected a nonnegative index @@ -2686,10 +2684,10 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: from sage.rings.real_arb import RBF # optional - arb - sage: RBF(1).agm(1) # optional - arb + sage: from sage.rings.real_arb import RBF + sage: RBF(1).agm(1) 1.000000000000000 - sage: RBF(sqrt(2)).agm(1)^(-1) # optional - arb + sage: RBF(sqrt(2)).agm(1)^(-1) [0.83462684167407 +/- 4.31e-15] """ cdef RealBall other_as_ball From 0e2e8eafec36ca99baf5e91695559ef86d4dd48f Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Fri, 29 May 2015 17:25:39 +0200 Subject: [PATCH 1477/1872] #18546 Include modules depending on arb in the reference manual --- src/doc/en/reference/rings_numerical/index.rst | 4 ++-- src/sage/rings/real_arb.pyx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/en/reference/rings_numerical/index.rst b/src/doc/en/reference/rings_numerical/index.rst index f7971505669..a60a2210743 100644 --- a/src/doc/en/reference/rings_numerical/index.rst +++ b/src/doc/en/reference/rings_numerical/index.rst @@ -41,8 +41,8 @@ ComplexBallField). sage/rings/complex_interval_field sage/rings/complex_interval -.. Modules depending on optional packages: -.. sage/rings/real_arb + sage/rings/real_arb + sage/rings/complex_ball_acb Exact Real Arithmetic --------------------- diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 2405ce375ae..3d0cf140b10 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -2486,7 +2486,7 @@ cdef class RealBall(RingElement): """ Return the image of this ball by the logarithmic Gamma function. - The complex branch structure is assumed, so if ``self`` ≤ 0, the result + The complex branch structure is assumed, so if ``self`` <= 0, the result is an indeterminate interval. EXAMPLES:: From 76883ad616a57fce3f9e94eca01e0c28fda24eed Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 3 Sep 2015 18:27:05 +0200 Subject: [PATCH 1478/1872] Trac #18546: remove optional - arb in real_mpfi --- src/sage/rings/real_mpfi.pyx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 85d3b750787..42fa845496e 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -5012,22 +5012,15 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): A :class:`RealIntervalFieldElement`. - This uses the optional `arb library `_. - You may have to install it via ``sage -i arb``. - EXAMPLES:: - sage: psi_1 = RIF(1).psi() # optional - arb - sage: psi_1 # optional - arb + sage: psi_1 = RIF(1).psi() + sage: psi_1 -0.577215664901533? - sage: psi_1.overlaps(-RIF.euler_constant()) # optional - arb + sage: psi_1.overlaps(-RIF.euler_constant()) True """ - try: - from sage.rings.real_arb import RealBallField - except ImportError: - raise TypeError("The optional arb package is not installed. " - "Consider installing it via 'sage -i arb'") + from sage.rings.real_arb import RealBallField return RealBallField(self.precision())(self).psi()._real_mpfi_(self._parent) # MPFI does not have: agm, erf, gamma, zeta From 4dbae98409bd6db7242b0725421a675da6cd6bec Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 24 Sep 2015 14:52:39 +0200 Subject: [PATCH 1479/1872] Trac #18546: make doctests 32-bit aware --- src/sage/libs/arb/arf.pxd | 2 ++ src/sage/rings/real_arb.pyx | 40 ++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/sage/libs/arb/arf.pxd b/src/sage/libs/arb/arf.pxd index ced559f8924..74d3f10d515 100644 --- a/src/sage/libs/arb/arf.pxd +++ b/src/sage/libs/arb/arf.pxd @@ -137,3 +137,5 @@ cdef extern from "arf.h": int arf_complex_mul(arf_t e, arf_t f, const arf_t a, const arf_t b, const arf_t c, const arf_t d, long prec, arf_rnd_t rnd) int arf_complex_mul_fallback(arf_t e, arf_t f, const arf_t a, const arf_t b, const arf_t c, const arf_t d, long prec, arf_rnd_t rnd) int arf_complex_sqr(arf_t e, arf_t f, const arf_t a, const arf_t b, long prec, arf_rnd_t rnd) + + long ARF_PREC_EXACT diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 3d0cf140b10..7dbfd19ff38 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -143,7 +143,7 @@ cimport sage.structure.element from sage.libs.arb.arb cimport * from sage.libs.arb.arf cimport arf_t, arf_init, arf_get_mpfr, arf_set_mpfr, arf_clear, arf_set_mag, arf_set -from sage.libs.arb.arf cimport arf_equal, arf_is_nan, arf_is_neg_inf, arf_is_pos_inf, arf_get_mag +from sage.libs.arb.arf cimport arf_equal, arf_is_nan, arf_is_neg_inf, arf_is_pos_inf, arf_get_mag, ARF_PREC_EXACT from sage.libs.arb.mag cimport mag_t, mag_init, mag_clear, mag_add, mag_set_d, MAG_BITS, mag_is_inf, mag_is_finite, mag_zero from sage.libs.flint.flint cimport flint_free from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_get_mpz, fmpz_set_mpz, fmpz_clear @@ -782,6 +782,27 @@ class RealBallField(UniqueRepresentation, Parent): fmpz_clear(tmpz) return res + def maximal_accuracy(self): + r""" + Return the relative accuracy of exact elements measured in bits. + + OUTPUT: + + An integer. + + EXAMPLES:: + + sage: from sage.rings.real_arb import RBF + sage: RBF.maximal_accuracy() + 9223372036854775807 # 64-bit + 2147483647 # 32-bit + + .. seealso:: + + :meth:`RealBall.accuracy` + """ + return ARF_PREC_EXACT + cdef inline bint _do_sig(long prec): """ @@ -1301,18 +1322,23 @@ cdef class RealBall(RingElement): Return the effective relative accuracy of this ball measured in bits. The accuracy is defined as the difference between the position of the - top bit in the midpoint and the top bit in the radius and , minus one. - The result is clamped between plus/minus ``ARF_PREC_EXACT``. + top bit in the midpoint and the top bit in the radius, minus one. + The result is clamped between plus/minus + :meth:`~RealBallField.maximal_accuracy`. EXAMPLES:: sage: from sage.rings.real_arb import RBF sage: RBF(pi).accuracy() 51 - sage: RBF(1).accuracy() - 9223372036854775807 - sage: RBF(NaN).accuracy() - -9223372036854775807 + sage: RBF(1).accuracy() == RBF.maximal_accuracy() + True + sage: RBF(NaN).accuracy() == -RBF.maximal_accuracy() + True + + .. seealso:: + + :meth:`~RealBallField.maximal_accuracy` """ return arb_rel_accuracy_bits(self.value) From 539dc7193dbb74914dbe9fbd25eacfa089b82d5d Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 15 Oct 2015 14:47:02 +0200 Subject: [PATCH 1480/1872] Allow RealNumber.__new__() --- src/sage/rings/real_mpfr.pxd | 14 ++-- src/sage/rings/real_mpfr.pyx | 142 +++++++++-------------------------- 2 files changed, 41 insertions(+), 115 deletions(-) diff --git a/src/sage/rings/real_mpfr.pxd b/src/sage/rings/real_mpfr.pxd index 4b2b1465cf8..cef3184333c 100644 --- a/src/sage/rings/real_mpfr.pxd +++ b/src/sage/rings/real_mpfr.pxd @@ -2,9 +2,7 @@ from sage.libs.mpfr cimport * cimport sage.rings.ring cimport sage.structure.element - -cdef extern from "pari/pari.h": - ctypedef long* GEN +from sage.libs.pari.types cimport GEN cdef class RealNumber(sage.structure.element.RingElement) # forward decl @@ -14,13 +12,15 @@ cdef class RealField_class(sage.rings.ring.Field): cdef bint sci_not cdef mpfr_rnd_t rnd cdef object rnd_str - cdef RealNumber _new(self) - + cdef inline RealNumber _new(self): + """Return a new real number with parent ``self``.""" + return (RealNumber.__new__(RealNumber, self)) cdef class RealNumber(sage.structure.element.RingElement): cdef mpfr_t value - cdef char init - cdef RealNumber _new(self) + cdef inline RealNumber _new(self): + """Return a new real number with same parent as ``self``.""" + return (RealNumber.__new__(RealNumber, self._parent)) cdef _set(self, x, int base) cdef _set_from_GEN_REAL(self, GEN g) cdef RealNumber abs(RealNumber self) diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index ac9e423689f..bdad36f0ac5 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -154,8 +154,6 @@ import sage.rings.infinity from sage.structure.parent_gens cimport ParentWithGens -cdef class RealNumber(sage.structure.element.RingElement) - #***************************************************************************** # # Implementation @@ -437,7 +435,6 @@ cdef class RealField_class(sage.rings.ring.Field): Real Field with 17 bits of precision and rounding RNDD """ global MY_MPFR_PREC_MAX - cdef RealNumber rn if prec < MPFR_PREC_MIN or prec > MY_MPFR_PREC_MAX: raise ValueError, "prec (=%s) must be >= %s and <= %s"%( prec, MPFR_PREC_MIN, MY_MPFR_PREC_MAX) @@ -453,34 +450,18 @@ cdef class RealField_class(sage.rings.ring.Field): from sage.categories.fields import Fields ParentWithGens.__init__(self, self, tuple([]), False, category = Fields()) - # hack, we cannot call the constructor here - rn = RealNumber.__new__(RealNumber) - rn._parent = self - mpfr_init2(rn.value, self.__prec) - rn.init = 1 - mpfr_set_d(rn.value, 0.0, self.rnd) + # Initialize zero and one + cdef RealNumber rn + rn = self._new() + mpfr_set_zero(rn.value, 1) self._zero_element = rn - rn = RealNumber.__new__(RealNumber) - rn._parent = self - mpfr_init2(rn.value, self.__prec) - rn.init = 1 - mpfr_set_d(rn.value, 1.0, self.rnd) + rn = self._new() + mpfr_set_ui(rn.value, 1, MPFR_RNDZ) self._one_element = rn self._populate_coercion_lists_(convert_method_name='_mpfr_') - cdef RealNumber _new(self): - """ - Return a new real number with parent ``self``. - """ - cdef RealNumber x - x = RealNumber.__new__(RealNumber) - x._parent = self - mpfr_init2(x.value, self.__prec) - x.init = 1 - return x - def _repr_(self): """ Return a string representation of ``self``. @@ -969,7 +950,6 @@ cdef class RealField_class(sage.rings.ring.Field): else: return RealField(prec, self.sci_not, _rounding_modes[self.rnd]) - # int mpfr_const_pi (mpfr_t rop, mp_rnd_t rnd) def pi(self): r""" Return `\pi` to the precision of this field. @@ -999,8 +979,6 @@ cdef class RealField_class(sage.rings.ring.Field): if self.__prec > SIG_PREC_THRESHOLD: sig_off() return x - - # int mpfr_const_euler (mpfr_t rop, mp_rnd_t rnd) def euler_constant(self): """ Returns Euler's gamma constant to the precision of this field. @@ -1017,7 +995,6 @@ cdef class RealField_class(sage.rings.ring.Field): sig_off() return x - # int mpfr_const_catalan (mpfr_t rop, mp_rnd_t rnd) def catalan_constant(self): """ Returns Catalan's constant to the precision of this field. @@ -1034,7 +1011,6 @@ cdef class RealField_class(sage.rings.ring.Field): if self.__prec > SIG_PREC_THRESHOLD: sig_off() return x - # int mpfr_const_log2 (mpfr_t rop, mp_rnd_t rnd) def log2(self): r""" Return `\log(2)` (i.e., the natural log of 2) to the precision @@ -1252,8 +1228,6 @@ cdef class RealField_class(sage.rings.ring.Field): # # RealNumber -- element of Real Field # -# -# #***************************************************************************** cdef class RealLiteral(RealNumber) @@ -1270,18 +1244,29 @@ cdef class RealNumber(sage.structure.element.RingElement): internal precision, in order to avoid confusing roundoff issues that occur because numbers are stored internally in binary. """ - cdef RealNumber _new(self): + def __cinit__(self, parent, x=None, base=None): """ - Return a new real number with same parent as self. + Initialize the parent of this element and allocate memory + + TESTS:: + + sage: from sage.rings.real_mpfr import RealNumber + sage: RealNumber.__new__(RealNumber, None) + Traceback (most recent call last): + ... + TypeError: Cannot convert NoneType to sage.rings.real_mpfr.RealField_class + sage: RealNumber.__new__(RealNumber, ZZ) + Traceback (most recent call last): + ... + TypeError: Cannot convert sage.rings.integer_ring.IntegerRing_class to sage.rings.real_mpfr.RealField_class + sage: RealNumber.__new__(RealNumber, RR) + NaN """ - cdef RealNumber x - x = RealNumber.__new__(RealNumber) - x._parent = self._parent - mpfr_init2(x.value, (self._parent).__prec) - x.init = 1 - return x + cdef RealField_class p = parent + mpfr_init2(self.value, p.__prec) + self._parent = p - def __init__(self, RealField_class parent, x=0, int base=10): + def __init__(self, parent, x=0, int base=10): """ Create a real number. Should be called by first creating a RealField, as illustrated in the examples. @@ -1326,16 +1311,8 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: TestSuite(R).run() """ - self.init = 0 - if parent is None: - raise TypeError - self._parent = parent - mpfr_init2(self.value, parent.__prec) - self.init = 1 - if x is None: - return - - self._set(x, base) + if x is not None: + self._set(x, base) def _magma_init_(self, magma): r""" @@ -1493,7 +1470,7 @@ cdef class RealNumber(sage.structure.element.RingElement): return (__create__RealNumber_version0, (self._parent, s, 32)) def __dealloc__(self): - if self.init: + if self._parent is not None: mpfr_clear(self.value) def __repr__(self): @@ -4374,15 +4351,6 @@ cdef class RealNumber(sage.structure.element.RingElement): sig_off() return x - ########################################################## - # it would be nice to get zero back here: - # sage: R(-1).acos().sin() - # _57 = -0.50165576126683320234e-19 - # i think this could be "fixed" by using MPFI. (put on to-do list.) - # - # this seems to work ok: - # sage: R(-1).acos().cos() - # _58 = -0.10000000000000000000e1 def sin(self): """ Return the sine of ``self``. @@ -4437,9 +4405,6 @@ cdef class RealNumber(sage.structure.element.RingElement): sig_off() return x,y - - # int mpfr_sin_cos (mpfr_t rop, mpfr_t op, mpfr_t, mp_rnd_t rnd) - def arccos(self): """ Return the inverse cosine of ``self``. @@ -4493,10 +4458,6 @@ cdef class RealNumber(sage.structure.element.RingElement): sig_off() return x - #int mpfr_acos _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); - #int mpfr_asin _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); - #int mpfr_atan _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); - def cosh(self): """ Return the hyperbolic cosine of ``self``. @@ -5651,41 +5612,6 @@ def __create__RealNumber_version0(parent, x, base=10): return RealNumber(parent, x, base=base) -cdef inline RealNumber empty_RealNumber(RealField_class parent): - """ - Create and return an empty initialized real number. - - EXAMPLES: - - These are indirect tests of this function:: - - sage: from sage.rings.real_mpfr import RRtoRR - sage: R10 = RealField(10) - sage: R100 = RealField(100) - sage: f = RRtoRR(R100, R10) - sage: a = R100(1.2) - sage: f(a) - 1.2 - sage: g = f.section() - sage: g - Generic map: - From: Real Field with 10 bits of precision - To: Real Field with 100 bits of precision - sage: g(f(a)) # indirect doctest - 1.1992187500000000000000000000 - sage: b = R10(2).sqrt() - sage: f(g(b)) - 1.4 - sage: f(g(b)) == b - True - """ - - cdef RealNumber y = RealNumber.__new__(RealNumber) - y._parent = parent - mpfr_init2(y.value, parent.__prec) - y.init = 1 - return y - cdef class RRtoRR(Map): cpdef Element _call_(self, x): """ @@ -5712,7 +5638,7 @@ cdef class RRtoRR(Map): True """ cdef RealField_class parent = self._codomain - cdef RealNumber y = empty_RealNumber(parent) + cdef RealNumber y = parent._new() if type(x) is RealLiteral: mpfr_set_str(y.value, (x).literal, (x).base, parent.rnd) else: @@ -5745,7 +5671,7 @@ cdef class ZZtoRR(Map): 1.2346e8 """ cdef RealField_class parent = self._codomain - cdef RealNumber y = empty_RealNumber(parent) + cdef RealNumber y = parent._new() mpfr_set_z(y.value, (x).value, parent.rnd) return y @@ -5760,7 +5686,7 @@ cdef class QQtoRR(Map): -0.33333333333333333333333333333333333333333333333333333333333 """ cdef RealField_class parent = self._codomain - cdef RealNumber y = empty_RealNumber(parent) + cdef RealNumber y = parent._new() mpfr_set_q(y.value, (x).value, parent.rnd) return y @@ -5780,7 +5706,7 @@ cdef class double_toRR(Map): 3.1415926535897931159979634685441851615905761718750000000000 """ cdef RealField_class parent = self._codomain - cdef RealNumber y = empty_RealNumber(parent) + cdef RealNumber y = parent._new() mpfr_set_d(y.value, x, parent.rnd) return y @@ -5808,6 +5734,6 @@ cdef class int_toRR(Map): 1.00000000000000 """ cdef RealField_class parent = self._codomain - cdef RealNumber y = empty_RealNumber(parent) + cdef RealNumber y = parent._new() mpfr_set_si(y.value, x, parent.rnd) return y From 842a66b0b7f36f465d02d2f792d24408e61ba1d0 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 15 Oct 2015 15:50:46 +0200 Subject: [PATCH 1481/1872] Fix a few details --- src/sage/rings/real_mpfi.pxd | 2 +- src/sage/rings/real_mpfi.pyx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/real_mpfi.pxd b/src/sage/rings/real_mpfi.pxd index 278d533cfd9..865381d25a6 100644 --- a/src/sage/rings/real_mpfi.pxd +++ b/src/sage/rings/real_mpfi.pxd @@ -31,7 +31,7 @@ cdef class RealIntervalField_class(sage.rings.ring.Field): cdef real_mpfr.RealField_class __middle_field cdef real_mpfr.RealField_class __upper_field cdef inline RealIntervalFieldElement _new(self): - """Return a new real number with parent ``self``.""" + """Return a new real interval with parent ``self``.""" return RealIntervalFieldElement.__new__(RealIntervalFieldElement, self) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 00b01808561..d57dce62d1b 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -1126,7 +1126,7 @@ cdef class RealIntervalFieldElement(RingElement): mpfi_init2(self.value, p.__prec) self._parent = p - def __init__(self, RealIntervalField_class parent, x=0, int base=10): + def __init__(self, parent, x=0, int base=10): """ Initialize a real interval element. Should be called by first creating a :class:`RealIntervalField`, as illustrated in the @@ -1210,7 +1210,7 @@ cdef class RealIntervalFieldElement(RingElement): ra = self._parent(a).lower() rb = self._parent(b).upper() mpfi_interv_fr(self.value, ra.value, rb.value) - elif isinstance(x, str): + elif isinstance(x, basestring): s = str(x).replace('..', ',').replace(' ','').replace('+infinity', '@inf@').replace('-infinity','-@inf@') if mpfi_set_str(self.value, s, base): raise TypeError("unable to convert {!r} to real interval".format(x)) From f9b5da0e38fc793122ac2615df86efa3a590f3ad Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 15 Oct 2015 09:28:12 -0500 Subject: [PATCH 1482/1872] Implement generic cardinality() and is_commutative(). --- .../finite_dimensional_algebras_with_basis.py | 17 ++++++++++++++ src/sage/categories/modules_with_basis.py | 23 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 862540e3bc3..da1a8701a89 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -948,6 +948,23 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): 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)) + @cached_method + def is_commutative(self): + """ + Return if ``self`` is a commutative algebra. + + EXAMPLES:: + + sage: S4 = SymmetricGroupAlgebra(QQ, 4) + sage: S4.is_commutative() + False + sage: S2 = SymmetricGroupAlgebra(QQ, 2) + sage: S2.is_commutative() + True + """ + B = list(self.basis()) + return all(b*bp == bp*b for i,b in enumerate(B) for bp in B[i+1:]) + class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index c780127492a..8e9a5c325d4 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -25,6 +25,7 @@ from sage.categories.dual import DualObjectsCategory from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.modules import Modules +from sage.rings.infinity import Infinity from sage.structure.element import Element, parent from sage.misc.lazy_import import lazy_import lazy_import('sage.modules.with_basis.morphism', @@ -764,6 +765,28 @@ def tensor(*parents): """ return parents[0].__class__.Tensor(parents, category = tensor.category_from_parents(parents)) + def cardinality(self): + """ + Return the cardinality of ``self``. + + EXAMPLES:: + + sage: S = SymmetricGroupAlgebra(QQ, 4) + sage: S.cardinality() + +Infinity + sage: S = SymmetricGroupAlgebra(GF(2), 4) + sage: S.cardinality() + 16777216 + sage: S.cardinality().factor() + 2^24 + + sage: s = SymmetricFunctions(GF(2)).s() + sage: s.cardinality() + +Infinity + """ + if self.dimension() == Infinity: + return Infinity + return self.base_ring().cardinality() ** self.dimension() class ElementMethods: # TODO: Define the appropriate element methods here (instead of in From 416f8154f67db7c0c86dac406a2583115ad94371 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 15 Oct 2015 16:51:55 +0200 Subject: [PATCH 1483/1872] #19403 Minor change in function description --- src/sage/rings/complex_interval.pyx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 681caf462fb..300bcc931d1 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -478,7 +478,8 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): def magnitude(self): """ - The largest absolute value of the elements of the interval. + The largest absolute value of the elements of the interval, rounded + away from zero. OUTPUT: a real number with rounding mode ``RNDU`` @@ -501,7 +502,8 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): def mignitude(self): """ - The smallest absolute value of the elements of the interval. + The smallest absolute value of the elements of the interval, rounded + towards zero. OUTPUT: a real number with rounding mode ``RNDD`` From 374cf4f1b325ea0dc4ce2d8cf56561334576d612 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 15 Oct 2015 13:30:13 +0200 Subject: [PATCH 1484/1872] trac #19417: A (Di)Graph([V,E]) constructor --- src/sage/graphs/digraph.py | 29 +++++++++++++++++++++++++++++ src/sage/graphs/graph.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index f4ef5312b43..f9c06360ef9 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -143,6 +143,12 @@ class DiGraph(GenericGraph): #. ``DiGraph(5)`` -- return an edgeless digraph on the 5 vertices 0,...,4. + #. ``DiGraph([list_of_vertices,list_of_edges])`` -- returns a digraph with + given vertices/edges. + + To bypass auto-detection, prefer the more explicit + ``DiGraph([V,E],format='vertices_and_edges')``. + #. ``DiGraph(list_of_edges)`` -- return a digraph with a given list of edges (see documentation of :meth:`~sage.graphs.generic_graph.GenericGraph.add_edges`). @@ -429,6 +435,13 @@ class DiGraph(GenericGraph): True sage: type(J_imm._backend) == type(G_imm._backend) True + + From a a list of vertices and a list of edges:: + + sage: G = DiGraph([[1,2,3],[(1,2)]]); G + Digraph on 3 vertices + sage: G.edges() + [(1, 2, None)] """ _directed = True @@ -592,6 +605,15 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if format is None and isinstance(data,list) and \ len(data)>=2 and callable(data[1]): format = 'rule' + + if (format is None and + isinstance(data,list) and + len(data) == 2 and + isinstance(data[0],list) and # a list of two lists, the second of + isinstance(data[1],list) and # which contains iterables (the edges) + (not data[1] or callable(getattr(data[1][0],"__iter__",None)))): + format = "vertices_and_edges" + if format is None and isinstance(data,dict): keys = data.keys() if len(keys) == 0: format = 'dict_of_dicts' @@ -683,6 +705,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, 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 == "vertices_and_edges": + self.allow_multiple_edges(bool(multiedges), check=False) + self.allow_loops(bool(loops), check=False) + self.add_vertices(data[0]) + self.add_edges(data[1]) + elif format == 'dict_of_dicts': from graph_input import from_dict_of_dicts from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index a8f1ffa1f20..740c2ad0a3d 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -580,6 +580,12 @@ class Graph(GenericGraph): #. ``Graph(5)`` -- return an edgeless graph on the 5 vertices 0,...,4. + #. ``Graph([list_of_vertices,list_of_edges])`` -- returns a graph with + given vertices/edges. + + To bypass auto-detection, prefer the more explicit + ``Graph([V,E],format='vertices_and_edges')``. + #. ``Graph(list_of_edges)`` -- return a graph with a given list of edges (see documentation of :meth:`~sage.graphs.generic_graph.GenericGraph.add_edges`). @@ -1001,6 +1007,12 @@ class Graph(GenericGraph): ... ValueError: Graph's Seidel adjacency matrix must have 0s on the main diagonal + From a a list of vertices and a list of edges:: + + sage: G = Graph([[1,2,3],[(1,2)]]); G + Graph on 3 vertices + sage: G.edges() + [(1, 2, None)] """ _directed = False @@ -1165,6 +1177,15 @@ def __init__(self, data=None, pos=None, loops=None, format=None, len(data)>=2 and callable(data[1])): format = 'rule' + + if (format is None and + isinstance(data,list) and + len(data) == 2 and + isinstance(data[0],list) and # a list of two lists, the second of + isinstance(data[1],list) and # which contains iterables (the edges) + (not data[1] or callable(getattr(data[1][0],"__iter__",None)))): + format = "vertices_and_edges" + if format is None and isinstance(data,dict): keys = data.keys() if len(keys) == 0: format = 'dict_of_dicts' @@ -1302,6 +1323,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, 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 == "vertices_and_edges": + self.allow_multiple_edges(bool(multiedges), check=False) + self.allow_loops(bool(loops), check=False) + self.add_vertices(data[0]) + self.add_edges(data[1]) + elif format == 'dict_of_dicts': from graph_input import from_dict_of_dicts from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, From 7d9146ab71b4b562ecde0a0ee7c3535bf66fc3fd Mon Sep 17 00:00:00 2001 From: Jonas Jermann Date: Thu, 30 Oct 2014 14:29:43 +0100 Subject: [PATCH 1485/1872] allow coercions from the forms over n=3 to forms over n=infinity --- .../modform_hecketriangle/abstract_ring.py | 45 ++++++++++++--- .../modform_hecketriangle/abstract_space.py | 56 ++++++++++++++----- .../modular/modform_hecketriangle/functors.py | 51 ++++++++++++++--- .../graded_ring_element.py | 24 ++++++++ .../modular/modform_hecketriangle/readme.py | 9 +++ 5 files changed, 154 insertions(+), 31 deletions(-) diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index 6577462c05f..af452f2fa4c 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -132,9 +132,9 @@ def _latex_(self): from sage.misc.latex import latex return "\\mathcal{{ {} }}_{{n={}}}({})".format(self._analytic_type.latex_space_name(), self._group.n(), latex(self._base_ring)) - def _element_constructor_(self, x): + def _element_constructor_(self, el): r""" - Return ``x`` coerced/converted into this forms ring. + Return ``el`` coerced/converted into this forms ring. EXAMPLES:: @@ -152,14 +152,34 @@ def _element_constructor_(self, x): False sage: MR(el).parent() == MR True + + sage: el = MR.Delta().full_reduce() + sage: MRinf = ModularFormsRing(n=infinity) + sage: MRinf(el) + (E4*f_i^4 - 2*E4^2*f_i^2 + E4^3)/4096 + sage: el.parent() + CuspForms(n=3, k=12, ep=1) over Integer Ring + sage: MRinf(el).parent() + ModularFormsRing(n=+Infinity) over Integer Ring """ from graded_ring_element import FormsRingElement - if isinstance(x, FormsRingElement): - x = self._rat_field(x._rat) + if isinstance(el, FormsRingElement): + if (self.hecke_n() == infinity and el.hecke_n() == ZZ(3)): + el_f = el._reduce_d()._rat + (x,y,z,d) = self.pol_ring().gens() + num1 = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).numerator() + num2 = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).denominator() + denom1 = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).numerator() + denom2 = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).denominator() + el = self._rat_field(num1*num2) / self._rat_field(denom1*denom2) + elif self.group() == el.group(): + el = self._rat_field(el._rat) + else: + raise ValueError("{} has group {} != {}".format(el, el.group(), self.group())) else: - x = self._rat_field(x) - return self.element_class(self, x) + el = self._rat_field(el) + return self.element_class(self, el) def _coerce_map_from_(self, S): r""" @@ -171,6 +191,8 @@ def _coerce_map_from_(self, S): sage: MR1 = QuasiWeakModularFormsRing(base_ring=CC) sage: MR2 = ModularFormsRing() sage: MR3 = CuspFormsRing() + sage: MR4 = ModularFormsRing(n=infinity) + sage: MR5 = ModularFormsRing(n=4) sage: MR3.has_coerce_map_from(MR2) False sage: MR1.has_coerce_map_from(MR2) @@ -181,6 +203,10 @@ def _coerce_map_from_(self, S): False sage: MR1.has_coerce_map_from(ZZ) True + sage: MR4.has_coerce_map_from(MR2) + True + sage: MR4.has_coerce_map_from(MR5) + False sage: from sage.modular.modform_hecketriangle.space import ModularForms, CuspForms sage: MF2 = ModularForms(k=6, ep=-1) @@ -189,14 +215,19 @@ def _coerce_map_from_(self, S): True sage: MR2.has_coerce_map_from(MF3) True + sage: MR4.has_coerce_map_from(MF2) + True """ from space import FormsSpace_abstract + from functors import _common_subgroup if ( isinstance(S, FormsRing_abstract)\ - and self._group == S._group\ + and self._group == _common_subgroup(self._group, S._group)\ and self._analytic_type >= S._analytic_type\ and self.base_ring().has_coerce_map_from(S.base_ring()) ): return True + elif isinstance(S, FormsRing_abstract): + return False elif isinstance(S, FormsSpace_abstract): raise RuntimeError( "This case should not occur." ) # return self._coerce_map_from_(S.graded_ring()) diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index 0cc399ad054..2ff0949c5fe 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -122,9 +122,9 @@ def _latex_(self): from sage.misc.latex import latex return "{}_{{ n={} }}({},\ {})({})".format(self._analytic_type.latex_space_name(), self._group.n(), self._weight, self._ep, latex(self._base_ring)) - def _element_constructor_(self, x): + def _element_constructor_(self, el): r""" - Return ``x`` coerced into this forms space. + Return ``el`` coerced into this forms space. EXAMPLES:: @@ -141,6 +141,14 @@ def _element_constructor_(self, x): sage: MF(Delta).parent() == MF True + sage: E2 = MF.E2() + sage: e2 = QuasiWeakModularForms(n=infinity, k=2, ep=-1)(E2) + sage: e2 + 1 - 24*q^2 - 72*q^4 + O(q^5) + sage: e2.parent() + QuasiWeakModularForms(n=+Infinity, k=2, ep=-1) over Integer Ring + sage: e2.as_ring_element() + (-f_i + 3*E2)/2 sage: MF(x^3) 1 + 720*q + 179280*q^2 + 16954560*q^3 + 396974160*q^4 + O(q^5) sage: MF(x^3).parent() == MF @@ -226,35 +234,47 @@ def _element_constructor_(self, x): """ from graded_ring_element import FormsRingElement - if isinstance(x, FormsRingElement): - return self.element_class(self, x._rat) + if isinstance(el, FormsRingElement): + if (self.hecke_n() == infinity and el.hecke_n() == ZZ(3)): + el_f = el._reduce_d()._rat + (x,y,z,d) = self.pol_ring().gens() + num1 = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).numerator() + num2 = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).denominator() + denom1 = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).numerator() + denom2 = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).denominator() + el = self._rat_field(num1*num2) / self._rat_field(denom1*denom2) + elif self.group() == el.group(): + el = el._rat + else: + raise ValueError("{} has group {} != {}".format(el, el.group(), self.group())) + return self.element_class(self, el) # This assumes that the series corresponds to a _weakly # holomorphic_ (quasi) form. It also assumes that the form is # holomorphic at -1 for n=infinity (this assumption however # can be changed in construct_form # resp. construct_quasi_form)) - P = parent(x) + P = parent(el) if is_LaurentSeriesRing(P) or is_PowerSeriesRing(P): if (self.is_modular()): - return self.construct_form(x) + return self.construct_form(el) else: - return self.construct_quasi_form(x) - if is_FreeModuleElement(x) and (self.module() is P or self.ambient_module() is P): - return self.element_from_ambient_coordinates(x) - if (not self.is_ambient()) and (isinstance(x, list) or isinstance(x, tuple) or is_FreeModuleElement(x)) and len(x) == self.rank(): + return self.construct_quasi_form(el) + if is_FreeModuleElement(el) and (self.module() is P or self.ambient_module() is P): + return self.element_from_ambient_coordinates(el) + if (not self.is_ambient()) and (isinstance(el, list) or isinstance(el, tuple) or is_FreeModuleElement(el)) and len(el) == self.rank(): try: - return self.element_from_coordinates(x) + return self.element_from_coordinates(el) except (ArithmeticError, TypeError): pass if self.ambient_module() and self.ambient_module().has_coerce_map_from(P): - return self.element_from_ambient_coordinates(self.ambient_module()(x)) - if (isinstance(x,list) or isinstance(x, tuple)) and len(x) == self.degree(): + return self.element_from_ambient_coordinates(self.ambient_module()(el)) + if (isinstance(el,list) or isinstance(el, tuple)) and len(el) == self.degree(): try: - return self.element_from_ambient_coordinates(x) + return self.element_from_ambient_coordinates(el) except (ArithmeticError, TypeError): pass - return self.element_class(self, x) + return self.element_class(self, el) def _coerce_map_from_(self, S): r""" @@ -268,6 +288,8 @@ def _coerce_map_from_(self, S): sage: MF3 = ModularForms(n=4, k=24, ep=-1) sage: MF4 = CuspForms(n=4, k=0, ep=1) sage: MF5 = ZeroForm(n=4, k=10, ep=-1) + sage: MF6 = QuasiWeakModularForms(n=3, k=24, ep=1) + sage: MF7 = QuasiWeakModularForms(n=infinity, k=24, ep=1) sage: subspace1 = MF3.subspace([MF3.gen(0), MF3.gen(1)]) sage: subspace2 = MF3.subspace([MF3.gen(2)]) sage: subspace3 = MF3.subspace([MF3.gen(0), MF3.gen(0)+MF3.gen(2)]) @@ -282,6 +304,10 @@ def _coerce_map_from_(self, S): False sage: MF1.has_coerce_map_from(ZZ) True + sage: MF7.has_coerce_map_from(MF6) + True + sage: MF7.has_coerce_map_from(MF2) + False sage: MF3.has_coerce_map_from(subspace1) True sage: subspace1.has_coerce_map_from(MF3) diff --git a/src/sage/modular/modform_hecketriangle/functors.py b/src/sage/modular/modform_hecketriangle/functors.py index 0b81ed0295e..f4e7c3e0c2b 100644 --- a/src/sage/modular/modform_hecketriangle/functors.py +++ b/src/sage/modular/modform_hecketriangle/functors.py @@ -92,6 +92,35 @@ def _get_base_ring(ring, var_name="d"): return base_ring +def _common_subgroup(group1, group2): + r""" + Return a common (Hecke triangle) subgroup of both given groups + ``group1`` and ``group2`` if it exists. Otherwise return ``None``. + + EXAMPLES:: + + sage: from sage.modular.modform_hecketriangle.functors import _common_subgroup + sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup + sage: _common_subgroup(HeckeTriangleGroup(n=3), HeckeTriangleGroup(n=infinity)) + Hecke triangle group for n = +Infinity + sage: _common_subgroup(HeckeTriangleGroup(n=infinity), HeckeTriangleGroup(n=3)) + Hecke triangle group for n = +Infinity + sage: _common_subgroup(HeckeTriangleGroup(n=4), HeckeTriangleGroup(n=infinity)) is None + True + sage: _common_subgroup(HeckeTriangleGroup(n=4), HeckeTriangleGroup(n=4)) + Hecke triangle group for n = 4 + """ + + if group1 == group2: + return group1 + elif (group1.n() == 3) and (group2.n() == infinity): + return group2 + elif (group1.n() == infinity) and (group2.n() == 3): + return group1 + else: + return None + + def ConstantFormsSpaceFunctor(group): r""" Construction functor for the space of constant forms. @@ -458,19 +487,21 @@ def merge(self, other): other = other._ambient_space_functor if isinstance(other, FormsSpaceFunctor): - if not (self._group == other._group): + group = _common_subgroup(self._group, other._group) + if group == None: return None analytic_type = self._analytic_type + other._analytic_type if (self._k == other._k) and (self._ep == other._ep): - return FormsSpaceFunctor(analytic_type, self._group, self._k, self._ep) + return FormsSpaceFunctor(analytic_type, group, self._k, self._ep) else: - return FormsRingFunctor(analytic_type, self._group, True) + return FormsRingFunctor(analytic_type, group, True) elif isinstance(other, FormsRingFunctor): - if not (self._group == other._group): + group = _common_subgroup(self._group, other._group) + if group == None: return None red_hom = other._red_hom analytic_type = self._analytic_type + other._analytic_type - return FormsRingFunctor(analytic_type, self._group, red_hom) + return FormsRingFunctor(analytic_type, group, red_hom) def __eq__(self, other): r""" @@ -647,17 +678,19 @@ def merge(self, other): other = other._ambient_space_functor if isinstance(other, FormsSpaceFunctor): - if not (self._group == other._group): + group = _common_subgroup(self._group, other._group) + if group == None: return None red_hom = self._red_hom analytic_type = self._analytic_type + other._analytic_type - return FormsRingFunctor(analytic_type, self._group, red_hom) + return FormsRingFunctor(analytic_type, group, red_hom) elif isinstance(other, FormsRingFunctor): - if not (self._group == other._group): + group = _common_subgroup(self._group, other._group) + if group == None: return None red_hom = self._red_hom & other._red_hom analytic_type = self._analytic_type + other._analytic_type - return FormsRingFunctor(analytic_type, self._group, red_hom) + return FormsRingFunctor(analytic_type, group, red_hom) def __eq__(self, other): r""" diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index d743dec533e..f6e669d6a63 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -713,6 +713,12 @@ def _add_(self,other): 2 - 32*q + 736*q^2 - 896*q^3 + 6368*q^4 + O(q^5) sage: (MF.E4() + MF.f_i()^2).parent() ModularForms(n=+Infinity, k=4, ep=1) over Integer Ring + + sage: el = ModularForms(n=3).Delta() + MF.E4()*MF.E6() + sage: el + (E4*f_i^4 - 2*E4^2*f_i^2 + E4^3 + 4096*E4^2*f_i)/4096 + sage: el.parent() + ModularFormsRing(n=+Infinity) over Integer Ring """ return self.parent()(self._rat+other._rat) @@ -763,6 +769,12 @@ def _sub_(self,other): 64*q - 512*q^2 + 1792*q^3 - 4096*q^4 + O(q^5) sage: (MF.E4() - MF.f_i()^2).parent() ModularForms(n=+Infinity, k=4, ep=1) over Integer Ring + + sage: el = ModularForms(n=3).Delta() - MF.E4() + sage: el + (E4*f_i^4 - 2*E4^2*f_i^2 + E4^3 - 4096*E4)/4096 + sage: el.parent() + ModularFormsRing(n=+Infinity) over Integer Ring """ #reduce at the end? See example "sage: ((E4+E6)-E6).parent()" @@ -838,6 +850,12 @@ def _mul_(self,other): q + 8*q^2 + 12*q^3 - 64*q^4 + O(q^5) sage: (MF.E4()*MF.f_inf()).parent() ModularForms(n=+Infinity, k=8, ep=1) over Integer Ring + + sage: el = ModularForms(n=3).E2()*MF.E6() + sage: el + 1 - 8*q - 272*q^2 - 1760*q^3 - 2560*q^4 + O(q^5) + sage: el.parent() + QuasiModularForms(n=+Infinity, k=8, ep=1) over Integer Ring """ res = self.parent().rat_field()(self._rat*other._rat) @@ -918,6 +936,12 @@ def _div_(self,other): 1/2 - 4*q - 236*q^2 - 2128*q^3 + 49428*q^4 + O(q^5) sage: (MF.f_i()/(MF.E4() + MF.f_i()^2)).parent() MeromorphicModularForms(n=+Infinity, k=-2, ep=-1) over Integer Ring + + sage: el = ModularForms(n=3).E2()/MF.E2() + sage: el + 1 + 8*q + 48*q^2 + 480*q^3 + 4448*q^4 + O(q^5) + sage: el.parent() + QuasiMeromorphicModularForms(n=+Infinity, k=0, ep=1) over Integer Ring """ res = self.parent().rat_field()(self._rat/other._rat) diff --git a/src/sage/modular/modform_hecketriangle/readme.py b/src/sage/modular/modform_hecketriangle/readme.py index 3f39d16b300..92e12e89781 100644 --- a/src/sage/modular/modform_hecketriangle/readme.py +++ b/src/sage/modular/modform_hecketriangle/readme.py @@ -1146,6 +1146,15 @@ sage: MF.q_basis(m=-1, order_1=-1, min_exp=-1) q^-1 - 203528/7*q^5 + O(q^6) + Elements with respect to the full group are automatically coerced + to elements of the Theta subgroup if necessary: + + sage: el = QuasiMeromorphicModularFormsRing(n=3).Delta().full_reduce() + E2 + sage: el + (E4*f_i^4 - 2*E4^2*f_i^2 + E4^3 + 4096*E2)/4096 + sage: el.parent() + QuasiModularFormsRing(n=+Infinity) over Integer Ring + - **Determine exact coefficients from numerical ones:** There is some experimental support for replacing numerical coefficients with From 4d36e7ad1de8254133e254d3a161e95ef63216a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 13 Sep 2015 20:57:10 +0200 Subject: [PATCH 1486/1872] trac #17261 fixing doc formatting in readme --- src/sage/modular/modform_hecketriangle/readme.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/modform_hecketriangle/readme.py b/src/sage/modular/modform_hecketriangle/readme.py index 92e12e89781..1387c5f8c4b 100644 --- a/src/sage/modular/modform_hecketriangle/readme.py +++ b/src/sage/modular/modform_hecketriangle/readme.py @@ -1146,8 +1146,8 @@ sage: MF.q_basis(m=-1, order_1=-1, min_exp=-1) q^-1 - 203528/7*q^5 + O(q^6) - Elements with respect to the full group are automatically coerced - to elements of the Theta subgroup if necessary: + Elements with respect to the full group are automatically coerced + to elements of the Theta subgroup if necessary:: sage: el = QuasiMeromorphicModularFormsRing(n=3).Delta().full_reduce() + E2 sage: el From dbf5f26791e609e7f8a8b91bded913a19bd2122b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 13 Sep 2015 20:59:24 +0200 Subject: [PATCH 1487/1872] trac #17261 again better doc in readme --- src/sage/modular/modform_hecketriangle/readme.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/modular/modform_hecketriangle/readme.py b/src/sage/modular/modform_hecketriangle/readme.py index 1387c5f8c4b..418c2a175db 100644 --- a/src/sage/modular/modform_hecketriangle/readme.py +++ b/src/sage/modular/modform_hecketriangle/readme.py @@ -2,8 +2,8 @@ Overview of Hecke triangle groups and modular forms for Hecke triangle groups AUTHORS: -- Jonas Jermann (2013): initial version +- Jonas Jermann (2013): initial version Hecke triangle groups and elements: @@ -460,7 +460,7 @@ - **Block decomposition of elements:** - For each group element a very specfic conjugacy representative + For each group element a very specific conjugacy representative can be obtained. For hyperbolic and parabolic elements the representative is a product ``V(j)``-matrices. They all have non-negative trace and the number of factors is called @@ -1093,7 +1093,7 @@ - **Theta subgroup:** The Hecke triangle group corresponding to ``n=infinity`` is also completely supported. In particular the (special) behavior around - the cusp ``-1`` is considered and can be specfied. + the cusp ``-1`` is considered and can be specified. EXAMPLES:: From 1eb79b25af1480974e871d797c0ad0aa410005e7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:11:36 +0200 Subject: [PATCH 1488/1872] cleanup (delete forgotten lines) --- src/sage/rings/asymptotic/growth_group.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 949619b5e87..16580cbec60 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1388,11 +1388,6 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): cls, base, var, category) - if category is None: - from sage.categories.monoids import Monoids - from sage.categories.posets import Posets - - @staticmethod def _determine_category_(category, base): r""" From 5c480721e16a515b09225bea020e4a499ddfb665 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:12:52 +0200 Subject: [PATCH 1489/1872] use category of commutative groups --- src/sage/rings/asymptotic/growth_group.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 16580cbec60..e0db4885caf 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2680,6 +2680,7 @@ def _determine_category_(category, base): sage: MonomialGrowthGroup(ZZ, 'x').category() Join of Category of groups and Category of posets sage: MonomialGrowthGroup(ZZ, 'x', category=Monoids()).category() + Join of Category of commutative groups and Category of posets Category of monoids """ if category is not None: @@ -2692,7 +2693,7 @@ def _determine_category_(category, base): C = base.category() if C.is_subcategory(CommutativeAdditiveGroups()): - category = Groups() + category = Groups().Commutative() else: category = Monoids() @@ -3315,8 +3316,8 @@ def _determine_category_(category, base): sage: ExponentialGrowthGroup(ZZ, 'x').category() Join of Category of monoids and Category of posets sage: ExponentialGrowthGroup(QQ, 'x').category() - Join of Category of groups and Category of posets sage: ExponentialGrowthGroup(ZZ, 'x', category=Groups()).category() + Join of Category of commutative groups and Category of posets Category of groups sage: ExponentialGrowthGroup(QQ, 'x', category=Monoids()).category() Category of monoids @@ -3330,8 +3331,8 @@ def _determine_category_(category, base): from sage.categories.posets import Posets C = base.category() - if C.is_subcategory(Fields()) or C.is_subcategory(Groups()): - category = Groups() + if C.is_subcategory(Fields()) or C.is_subcategory(Groups().Commutative()): + category = Groups().Commutative() else: category = Monoids() From 8840f1e106ddc4332316fc1a79ca667e16f14a54 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:13:03 +0200 Subject: [PATCH 1490/1872] mark doctests as indirect --- src/sage/rings/asymptotic/growth_group.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index e0db4885caf..044b73fa25c 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1412,9 +1412,9 @@ def _determine_category_(category, base): TESTS:: sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup - sage: GenericGrowthGroup(ZZ, 'x').category() + sage: GenericGrowthGroup(ZZ, 'x').category() # indirect doctest Join of Category of monoids and Category of posets - sage: GenericGrowthGroup(ZZ, 'x', category=Groups()).category() + sage: GenericGrowthGroup(ZZ, 'x', category=Groups()).category() # indirect doctest Category of groups """ if category is not None: @@ -2677,10 +2677,9 @@ def _determine_category_(category, base): TESTS:: sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup - sage: MonomialGrowthGroup(ZZ, 'x').category() - Join of Category of groups and Category of posets - sage: MonomialGrowthGroup(ZZ, 'x', category=Monoids()).category() + sage: MonomialGrowthGroup(ZZ, 'x').category() # indirect doctest Join of Category of commutative groups and Category of posets + sage: MonomialGrowthGroup(ZZ, 'x', category=Monoids()).category() # indirect doctest Category of monoids """ if category is not None: @@ -3313,13 +3312,13 @@ def _determine_category_(category, base): TESTS:: sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup - sage: ExponentialGrowthGroup(ZZ, 'x').category() + sage: ExponentialGrowthGroup(ZZ, 'x').category() # indirect doctest Join of Category of monoids and Category of posets - sage: ExponentialGrowthGroup(QQ, 'x').category() - sage: ExponentialGrowthGroup(ZZ, 'x', category=Groups()).category() + sage: ExponentialGrowthGroup(QQ, 'x').category() # indirect doctest Join of Category of commutative groups and Category of posets + sage: ExponentialGrowthGroup(ZZ, 'x', category=Groups()).category() # indirect doctest Category of groups - sage: ExponentialGrowthGroup(QQ, 'x', category=Monoids()).category() + sage: ExponentialGrowthGroup(QQ, 'x', category=Monoids()).category() # indirect doctest Category of monoids """ if category is not None: From 4456b2997c0d60e878c995a603502934dda312fc Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:39:43 +0200 Subject: [PATCH 1491/1872] Trac #19094/#19083 comment 60, 1: improve docstring of split_str_by_op and explain op=None --- src/sage/rings/asymptotic/misc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 134c6701a77..5f2ff6decbb 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -153,13 +153,15 @@ def abbreviate(P): def split_str_by_op(string, op, strip_parentheses=True): r""" Split the given string into a tuple of substrings arising by - splitting by '*' and taking care of parentheses. + splitting by the given operator ``op`` and taking care of parentheses. INPUT: - ``string`` -- a string. - - ``op`` -- a string. + - ``op`` -- a string. This is used by ``str.split``. Thus, if this + is ``None``, then any whitespace string is a separator and empty + strings are removed from the result. - ``strip_parentheses`` -- (default: ``True``) a boolean. From 17f8f4663eb091d14e486835829791bd126926c9 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:40:06 +0200 Subject: [PATCH 1492/1872] Trac #19094/#19083 comment 60, 1: correct a bug with op=None --- src/sage/rings/asymptotic/misc.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 5f2ff6decbb..e6b649a4ab2 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -191,6 +191,14 @@ def split_str_by_op(string, op, strip_parentheses=True): ('a^b', 'c') sage: split_str_by_op('a^(b^c)', '^') ('a', 'b^c') + :: + + sage: split_str_by_op(' ( t ) ', op=None) + ('t',) + sage: split_str_by_op(' ( t )s', op=None) + ('(t)s',) + sage: split_str_by_op(' ( t ) s', op=None) + ('t', 's') """ factors = list() balanced = True @@ -206,7 +214,7 @@ def split_str_by_op(string, op, strip_parentheses=True): raise ValueError("'%s' is invalid since a '%s' follows a '%s'." % (string, op, op)) if not balanced: - s = factors.pop() + op + s + s = factors.pop() + (op if op else '') + s balanced = s.count('(') == s.count(')') factors.append(s) From a46d0f44384f08241bd811a9ce9d523e708cf925 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:40:56 +0200 Subject: [PATCH 1493/1872] Trac #19094/#19083 comment 60, 1: doctest for split_parentheses --- src/sage/rings/asymptotic/misc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index e6b649a4ab2..6ffab5c71dd 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -191,6 +191,16 @@ def split_str_by_op(string, op, strip_parentheses=True): ('a^b', 'c') sage: split_str_by_op('a^(b^c)', '^') ('a', 'b^c') + + :: + + sage: split_str_by_op('(a) + (b)', op='+', strip_parentheses=True) + ('a', 'b') + sage: split_str_by_op('(a) + (b)', op='+', strip_parentheses=False) + ('(a)', '(b)') + sage: split_str_by_op(' ( t ) ', op='+', strip_parentheses=False) + ('( t )',) + :: sage: split_str_by_op(' ( t ) ', op=None) From aabd48a7c4397e0871f1509fac159897430fbfa4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:44:18 +0200 Subject: [PATCH 1494/1872] rewrite growth_group.Variable.__init__ to make strip of parentheses in all elements of a list input --- src/sage/rings/asymptotic/growth_group.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 7a817bd64f3..467cbeae865 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -349,11 +349,11 @@ def __init__(self, var, repr=None, ignore=None): ValueError: ':-' is not a valid name for a variable. """ from sage.symbolic.ring import isidentifier + from misc import split_str_by_op if not isinstance(var, (list, tuple)): - from misc import split_str_by_op - var = split_str_by_op(str(var), None) # we strip off parentheses - var = tuple(str(v).strip() for v in var) + var = (var,) + var = tuple(''.join(split_str_by_op(str(v), None)) for v in var) # we strip off parentheses if ignore is None: ignore = tuple() From 3c4e974c42f570b3d9ec120d8d03798570bac54c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 15 Oct 2015 11:46:23 -0500 Subject: [PATCH 1495/1872] Fixing failing doctest. --- src/sage/categories/homset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 51a3f327d18..39db9c114d7 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -479,7 +479,7 @@ def End(X, category=None): Category of finite groups sage: H = Hom(G,G) sage: H.homset_category() - Category of groups + Category of finite groups sage: H.category() Category of endsets of unital magmas From d577aeb29da017dbcbc74aa6d5dc9e2b7b040573 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:48:22 +0200 Subject: [PATCH 1496/1872] Trac #19094/#19083 comment 60, 2: repr_op: add operators -, / --- src/sage/rings/asymptotic/misc.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 6ffab5c71dd..b902a94b405 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -264,13 +264,20 @@ def repr_op(left, op, right=None): sage: from sage.rings.asymptotic.misc import repr_op sage: repr_op('a^b', '^', 'c') '(a^b)^c' + + TESTS:: + + sage: repr_op('a-b', '^', 'c') + '(a-b)^c' + sage: repr_op('a+b', '^', 'c') + '(a+b)^c' """ left = str(left) right = str(right) if right is not None else '' def add_parentheses(s, op): if op == '^': - signals = ('^', '*', '+', ' ') + signals = ('^', '/', '*', '-', '+', ' ') else: return s if any(sig in s for sig in signals): From 7a806e1f2d58db9f19162dbe7359fbbfbcde119a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 18:59:05 +0200 Subject: [PATCH 1497/1872] make global functions used in files growth_group* private --- src/sage/rings/asymptotic/growth_group.py | 17 ++++++++--------- .../rings/asymptotic/growth_group_cartesian.py | 14 +++++++------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 467cbeae865..6854d013946 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -570,7 +570,7 @@ def extract_variable_names(s): return tuple(str(s) for s in SR(s).variables()) -def is_lt_one(self): +def _is_lt_one_(self): r""" Return if this element is less than `1`. @@ -595,7 +595,7 @@ def is_lt_one(self): return self <= one and self != one -def log(self, base=None): +def _log_(self, base=None): r""" Return the logarithm of this element. @@ -696,7 +696,7 @@ def log(self, base=None): return g -def log_factor(self, base=None): +def _log_factor_(self, base=None): r""" Return the logarithm of the factorization of this element. @@ -766,7 +766,7 @@ def log_factor(self, base=None): return log_factor -def rpow(self, base): +def _rpow_(self, base): r""" Calculate the power of ``base`` to this element. @@ -1215,8 +1215,8 @@ def _le_(self, other): raise NotImplementedError('Only implemented in concrete realizations.') - log = log - log_factor = log_factor + log = _log_ + log_factor = _log_factor_ def _log_factor_(self, base=None): @@ -1249,8 +1249,7 @@ def _log_factor_(self, base=None): 'of %s in abstract base class.' % (self,)) - - rpow = rpow + rpow = _rpow_ def _rpow_element_(self, base): @@ -1300,7 +1299,7 @@ def factors(self): return (self,) - is_lt_one = is_lt_one + is_lt_one = _is_lt_one_ class GenericGrowthGroup( diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index d316f47d7ac..06c8d01dab1 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -838,8 +838,8 @@ def variable_names(self): class Element(CartesianProductPoset.Element): - from growth_group import is_lt_one - is_lt_one = is_lt_one + from growth_group import _is_lt_one_ + is_lt_one = _is_lt_one_ def _repr_(self): @@ -950,9 +950,9 @@ def factors(self): tuple()) - from growth_group import log_factor, log - log = log - log_factor = log_factor + from growth_group import _log_factor_, _log_ + log = _log_ + log_factor = _log_factor_ def _log_factor_(self, base=None): @@ -1001,8 +1001,8 @@ def try_create_growth(g): (self, self.parent())), e) - from growth_group import rpow - rpow = rpow + from growth_group import _rpow_ + rpow = _rpow_ def _rpow_element_(self, base): From fbce040690db466f917810368285bb392eaf64ac Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 19:02:34 +0200 Subject: [PATCH 1498/1872] Trac #19094/#19083 comment 60, 3, 4, 5: mark doctests as indirect --- src/sage/rings/asymptotic/growth_group.py | 40 +++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 6854d013946..3dc1b14bc25 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -586,9 +586,9 @@ def _is_lt_one_(self): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('x^ZZ'); x = G(x) - sage: (x^42).is_lt_one() + sage: (x^42).is_lt_one() # indirect doctest False - sage: (x^(-42)).is_lt_one() + sage: (x^(-42)).is_lt_one() # indirect doctest True """ one = self.parent().one() @@ -615,7 +615,7 @@ def _log_(self, base=None): sage: x, = G.gens_monomial() sage: log(x) # indirect doctest log(x) - sage: log(x^5) + sage: log(x^5) # indirect doctest Traceback (most recent call last): ... ArithmeticError: When calculating log(x^5) a factor 5 != 1 appeared, @@ -627,12 +627,12 @@ def _log_(self, base=None): sage: x, = G.gens_monomial() sage: el = x.rpow(2); el 2^x - sage: log(el) + sage: log(el) # indirect doctest Traceback (most recent call last): ... ArithmeticError: When calculating log(2^x) a factor log(2) != 1 appeared, which is not contained in Growth Group QQ^x * x^ZZ. - sage: log(el, base=2) + sage: log(el, base=2) # indirect doctest x :: @@ -648,7 +648,7 @@ def _log_(self, base=None): :: sage: x = GrowthGroup('x^ZZ').an_element() - sage: log(x) + sage: log(x) # indirect doctest Traceback (most recent call last): ... ArithmeticError: Cannot build log(x) since log(x) is not in @@ -658,9 +658,9 @@ def _log_(self, base=None): sage: G = GrowthGroup("(e^x)^QQ * x^ZZ") sage: x, = G.gens_monomial() - sage: log(exp(x)) + sage: log(exp(x)) # indirect doctest x - sage: G.one().log() + sage: G.one().log() # indirect doctest Traceback (most recent call last): ... ArithmeticError: log(1) is zero, which is not contained in @@ -670,9 +670,9 @@ def _log_(self, base=None): sage: G = GrowthGroup("(e^x)^ZZ * x^ZZ") sage: x, = G.gens_monomial() - sage: log(exp(x)) + sage: log(exp(x)) # indirect doctest x - sage: G.one().log() + sage: G.one().log() # indirect doctest Traceback (most recent call last): ... ArithmeticError: log(1) is zero, which is not contained in @@ -721,11 +721,11 @@ def _log_factor_(self, base=None): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ') sage: x, y = G.gens_monomial() - sage: (x * y).log_factor() + sage: (x * y).log_factor() # indirect doctest ((log(x), 1), (log(y), 1)) - sage: (x^123).log_factor() + sage: (x^123).log_factor() # indirect doctest ((log(x), 123),) - sage: (G('2^x') * x^2).log_factor(base=2) + sage: (G('2^x') * x^2).log_factor(base=2) # indirect doctest ((x, 1), (log(x), 2/log(2))) :: @@ -735,7 +735,7 @@ def _log_factor_(self, base=None): :: - sage: log(x).log_factor() + sage: log(x).log_factor() # indirect doctest Traceback (most recent call last): ... ArithmeticError: Cannot build log(log(x)) since log(log(x)) is @@ -750,7 +750,7 @@ def _log_factor_(self, base=None): sage: G = GrowthGroup("(e^x)^ZZ * x^ZZ * log(x)^ZZ") sage: x, = G.gens_monomial() - sage: (exp(x) * x).log_factor() + sage: (exp(x) * x).log_factor() # indirect doctest ((x, 1), (log(x), 1)) """ log_factor = self._log_factor_(base=base) @@ -783,18 +783,18 @@ def _rpow_(self, base): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('QQ^x * x^ZZ') sage: x = G('x') - sage: x.rpow(2) + sage: x.rpow(2) # indirect doctest 2^x - sage: x.rpow(1/2) + sage: x.rpow(1/2) # indirect doctest (1/2)^x :: - sage: x.rpow(0) + sage: x.rpow(0) # indirect doctest Traceback (most recent call last): ... ValueError: 0 is not an allowed base for calculating the power to x. - sage: (x^2).rpow(2) + sage: (x^2).rpow(2) # indirect doctest Traceback (most recent call last): ... ArithmeticError: Cannot construct 2^(x^2) in Growth Group QQ^x * x^ZZ @@ -805,7 +805,7 @@ def _rpow_(self, base): sage: G = GrowthGroup('QQ^(x*log(x)) * x^ZZ * log(x)^ZZ') sage: x = G('x') - sage: (x * log(x)).rpow(2) + sage: (x * log(x)).rpow(2) # indirect doctest 2^(x*log(x)) """ if base == 0: From f3080d8f77e4c235332fa68149d15b742a27081d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 19:15:17 +0200 Subject: [PATCH 1499/1872] Trac #19094/#19083 comment 60, 3, 4, 5: document the usage of functions in growth_group as methods --- src/sage/rings/asymptotic/growth_group.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 3dc1b14bc25..67056db0ae8 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -570,6 +570,8 @@ def extract_variable_names(s): return tuple(str(s) for s in SR(s).variables()) +# The following function is used in the classes GenericGrowthElement and +# GenericProduct.Element as a method. def _is_lt_one_(self): r""" Return if this element is less than `1`. @@ -595,6 +597,8 @@ def _is_lt_one_(self): return self <= one and self != one +# The following function is used in the classes GenericGrowthElement and +# GenericProduct.Element as a method. def _log_(self, base=None): r""" Return the logarithm of this element. @@ -696,6 +700,8 @@ def _log_(self, base=None): return g +# The following function is used in the classes GenericGrowthElement and +# GenericProduct.Element as a method. def _log_factor_(self, base=None): r""" Return the logarithm of the factorization of this @@ -766,6 +772,8 @@ def _log_factor_(self, base=None): return log_factor +# The following function is used in the classes GenericGrowthElement and +# GenericProduct.Element as a method. def _rpow_(self, base): r""" Calculate the power of ``base`` to this element. From aa92e9c3f66889cad53ad0ae5b973ce6eca03166 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 19:18:52 +0200 Subject: [PATCH 1500/1872] Trac #19094/#19083 comment 60, 4: doctest for "results in a sum" --- src/sage/rings/asymptotic/growth_group.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 67056db0ae8..841e25cee84 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -681,6 +681,17 @@ def _log_(self, base=None): ... ArithmeticError: log(1) is zero, which is not contained in Growth Group (e^x)^ZZ * x^ZZ. + + :: + + sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ') + sage: x, y = G.gens_monomial() + sage: (x * y).log() # indirect doctest + Traceback (most recent call last): + ... + ArithmeticError: Calculating log(x*y) results in a sum, + which is not contained in + Growth Group QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ. """ log_factor = self.log_factor(base=base) if not log_factor: From d05f6a8f545a5f0cd5791c1f7e32dbf55caf02d5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 19:21:08 +0200 Subject: [PATCH 1501/1872] Trac #19094/#19083 comment 60, 5: remove not needed import --- src/sage/rings/asymptotic/growth_group.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 841e25cee84..57cdbb47a3f 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -772,7 +772,6 @@ def _log_factor_(self, base=None): """ log_factor = self._log_factor_(base=base) - from growth_group import GenericGrowthGroup for g, c in log_factor: if hasattr(g, 'parent') and \ isinstance(g.parent(), GenericGrowthGroup): From df77d22b058f3c6d6ce88d480928ce3cfb32caf1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 15 Oct 2015 19:22:09 +0200 Subject: [PATCH 1502/1872] Trac #19094/#19083 comment 60, 6: delete unnecessary NOTE-box --- src/sage/rings/asymptotic/growth_group.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 57cdbb47a3f..b86a249626b 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1137,14 +1137,6 @@ def __ne__(self, other): A boolean. - .. NOTE:: - - This function uses the coercion model to find a common - parent for the two operands. - - The comparison of two elements with the same parent is done in - :meth:`_eq_`. - TESTS:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup From ba88e5e6aea7e7443eb682084405750ea99775d0 Mon Sep 17 00:00:00 2001 From: Jonas Jermann Date: Thu, 15 Oct 2015 19:41:46 +0200 Subject: [PATCH 1503/1872] improvements after review from chapoton --- .../modform_hecketriangle/abstract_ring.py | 16 ++++++++-------- .../modform_hecketriangle/abstract_space.py | 12 +++++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index af452f2fa4c..5a0ac3f5e64 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -18,13 +18,11 @@ from sage.rings.all import FractionField, PolynomialRing, PowerSeriesRing, ZZ, QQ, infinity from sage.algebras.free_algebra import FreeAlgebra -from sage.rings.arith import bernoulli, sigma from sage.structure.parent import Parent from sage.misc.cachefunc import cached_method -from hecke_triangle_groups import HeckeTriangleGroup -from constructor import FormsRing, FormsSpace, rational_type +from constructor import FormsRing, FormsSpace from series_constructor import MFSeriesConstructor @@ -168,11 +166,13 @@ def _element_constructor_(self, el): if (self.hecke_n() == infinity and el.hecke_n() == ZZ(3)): el_f = el._reduce_d()._rat (x,y,z,d) = self.pol_ring().gens() - num1 = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).numerator() - num2 = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).denominator() - denom1 = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).numerator() - denom2 = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).denominator() - el = self._rat_field(num1*num2) / self._rat_field(denom1*denom2) + + num_sub = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)) + denom_sub = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)) + new_num = num_sub.numerator()*denom_sub.denominator() + new_denom = denom_sub.numerator()*num_sub.denominator() + + el = self._rat_field(new_num) / self._rat_field(new_denom) elif self.group() == el.group(): el = self._rat_field(el._rat) else: diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index 2ff0949c5fe..76f28b569b4 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -238,11 +238,13 @@ def _element_constructor_(self, el): if (self.hecke_n() == infinity and el.hecke_n() == ZZ(3)): el_f = el._reduce_d()._rat (x,y,z,d) = self.pol_ring().gens() - num1 = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).numerator() - num2 = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).denominator() - denom1 = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).numerator() - denom2 = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)).denominator() - el = self._rat_field(num1*num2) / self._rat_field(denom1*denom2) + + num_sub = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)) + denom_sub = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)) + new_num = num_sub.numerator()*denom_sub.denominator() + new_denom = denom_sub.numerator()*num_sub.denominator() + + el = self._rat_field(new_num) / self._rat_field(new_denom) elif self.group() == el.group(): el = el._rat else: From e9777f4745743eb8f68cc11ff3217d67e2dfa528 Mon Sep 17 00:00:00 2001 From: Jonas Jermann Date: Tue, 24 Mar 2015 00:37:11 +0100 Subject: [PATCH 1504/1872] partial support for HyperbolicPlane() --- .../graded_ring_element.py | 36 +++++ .../hecke_triangle_group_element.py | 134 +++++++++++++----- 2 files changed, 137 insertions(+), 33 deletions(-) diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index d743dec533e..4fc191f4140 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -21,6 +21,7 @@ from sage.symbolic.all import pi, i from sage.structure.parent_gens import localvars from sage.modules.free_module_element import vector +from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane from sage.structure.element import CommutativeAlgebraElement from sage.structure.unique_representation import UniqueRepresentation @@ -1207,6 +1208,9 @@ def order_at(self, tau=infinity): Return the (overall) order of ``self`` at ``tau`` if easily possible: Namely if ``tau`` is ``infinity`` or congruent to ``i`` resp. ``rho``. + It is possible to determine the order of points from ``HyperbolicPlane()``. + In this case the coordinates of the upper half plane model are used. + If ``self`` is homogeneous and modular then the rational function ``self.rat()`` is used. Otherwise only ``tau=infinity`` is supported by using the Fourier expansion with increasing precision @@ -1281,8 +1285,18 @@ def order_at(self, tau=infinity): 3 sage: (1/MR.f_inf()^2).order_at(-1) 0 + + sage: p = HyperbolicPlane().PD().get_point(I) + sage: MR((x-y)^10).order_at(p) + 10 + sage: MR.zero().order_at(p) + +Infinity """ + # if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model + if (tau in HyperbolicPlane()): + tau = tau.to_model('UHP').coordinates() + if self.is_zero(): return infinity @@ -1779,6 +1793,9 @@ def evaluate(self, tau, prec = None, num_prec = None, check=False): (and fail) for certain (many) choices of (``base_ring``, ``tau.parent()``). + It is possible to evalutate at points of ``HyperbolicPlane()``. + In this case the coordinates of the upper half plane model are used. + To obtain a precise and fast result the parameters ``prec`` and ``num_prec`` both have to be considered/balanced. A high ``prec`` value is usually quite costly. @@ -2064,8 +2081,27 @@ def evaluate(self, tau, prec = None, num_prec = None, check=False): sage: (f.q_expansion_fixed_d().polynomial())(exp((2*pi*i).n(1000)*az/G.lam())) # long time -140.471170232432551196978... + 469.079369280804086032719...*I + + It is possible to evaluate at points of ``HyperbolicPlane()``: + + :: + + sage: p = HyperbolicPlane().PD().get_point(-I/2) + sage: bool(p.to_model('UHP').coordinates() == I/3) + True + sage: E4(p) == E4(I/3) + True + sage: p = HyperbolicPlane().PD().get_point(I) + sage: f_inf(p, check=True) == 0 + True + sage: (1/(E2^2-E4))(p) == infinity + True """ + # if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model + if (tau in HyperbolicPlane()): + tau = tau.to_model('UHP').coordinates() + if (prec == None): prec = self.parent().default_prec() if (num_prec == None): diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index 135ad6032ed..2e05fea4009 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -3068,11 +3068,13 @@ def fixed_points(self, embedded=False, order="default"): return (root1, root2) - def acton(self, z): + def acton(self, tau): r""" - Return the image of ``z`` under the action of ``self`` + Return the image of ``tau`` under the action of ``self`` by linear fractional transformations or by conjugation - in case ``z`` is an element of the parent of ``self``. + in case ``tau`` is an element of the parent of ``self``. + + It is possible to act on points of ``HyperbolicPlane()``. .. NOTE: @@ -3083,7 +3085,7 @@ def acton(self, z): INPUT: - - ``z`` -- Either an element of ``self`` or any + - ``tau`` -- Either an element of ``self`` or any element to which a linear fractional transformation can be applied in the usual way. @@ -3091,6 +3093,9 @@ def acton(self, z): In particular ``infinity`` is a possible argument and a possible return value. + As mentioned it is also possible to use + points of ``HyperbolicPlane()``. + EXAMPLES:: sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup @@ -3116,52 +3121,85 @@ def acton(self, z): sage: G.V(2).inverse().acton(G.U()) [ 0 -1] [ 1 lam] + + sage: p = HyperbolicPlane().PD().get_point(-I/2+1/8) + sage: G.V(2).acton(p) + Point in PD -((-(47*I + 161)*sqrt(5) - 47*I - 161)/(145*sqrt(5) + 94*I + 177) + I)/(I*(-(47*I + 161)*sqrt(5) - 47*I - 161)/(145*sqrt(5) + 94*I + 177) + 1) + sage: bool(G.V(2).acton(p).to_model('UHP').coordinates() == G.V(2).acton(p.to_model('UHP').coordinates())) + True + + sage: p = HyperbolicPlane().PD().get_point(I) + sage: G.U().acton(p) + Boundary point in PD 1/2*(sqrt(5) - 2*I + 1)/(-1/2*I*sqrt(5) - 1/2*I + 1) + sage: G.U().acton(p).to_model('UHP') == HyperbolicPlane().UHP().get_point(G.lam()) + True + sage: G.U().acton(p) == HyperbolicPlane().UHP().get_point(G.lam()).to_model('PD') + True """ - if z.parent() == self.parent(): - return self*z*self.inverse() + + if tau.parent() == self.parent(): + return self*tau*self.inverse() + + # if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model + # TODO: Make it possible to interpret elements as isometries of the HyperbolicPlane + # and possibly use/implement actions using the HyperbolicPlane model + from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane + + model = None + if (tau in HyperbolicPlane()): + model = tau.model() + tau = tau.to_model('UHP').coordinates() a,b,c,d = self._matrix.list() - if z == infinity: + if tau == infinity: if c.is_zero(): - return infinity + result = infinity else: - return a/c - elif not c.is_zero() and c*z == -d: - return infinity + result = a/c + elif c*tau + d == 0: + result = infinity else: - return (a*z + b) / (c*z + d) + result = (a*tau + b) / (c*tau + d) + + if model is None: + return result + else: + return HyperbolicPlane().UHP().get_point(result).to_model(model) # def _act_on_(self, other, self_on_left): # TODO: implement default actions for "suitable" other # if (self_on_left): # return self.acton(other) - def slash(self, f, z=None, k=None): + def slash(self, f, tau=None, k=None): r""" Return the `slash-operator` of weight ``k`` to applied to ``f``, - evaluated at ``z``. I.e. ``(f|_k[self])(z)``. + evaluated at ``tau``. I.e. ``(f|_k[self])(tau)``. INPUT: - - ``f`` -- A function in ``z`` (or an object for which - evaluation at ``self.acton(z)`` makes sense. + - ``f`` -- A function in ``tau`` (or an object for which + evaluation at ``self.acton(tau)`` makes sense. + + - ``tau`` -- Where to evaluate the result. + This should be a valid argument for :meth:`acton`. - - ``z`` -- Where to evaluate the result. - This should be a valid argument for :meth:`acton`. + If ``tau`` is a point of ``HyperbolicPlane()`` then + its coordinates in the upper half plane model are used. - Default: ``None`` in which case ``f`` has to be - a rational function / polynomial in one variable and - the generator of the polynomial ring is used for ``z``. - That way ``slash`` acts on rational functions / polynomials. + Default: ``None`` in which case ``f`` has to be + a rational function / polynomial in one variable and + the generator of the polynomial ring is used for ``tau``. + That way ``slash`` acts on rational functions / polynomials. - - ``k`` -- An even integer. + - ``k`` -- An even integer. - Default: ``None`` in which case ``f`` either - has to be a rational function / polynomial in one - variable (then -degree is used). - Or ``f`` needs to have a ``weight`` attribute which - is then used. + Default: ``None`` in which case ``f`` either + has to be a rational function / polynomial in one + variable (then -degree is used). + Or ``f`` needs to have a ``weight`` attribute which + is then used. EXAMPLES:: @@ -3177,10 +3215,14 @@ def slash(self, f, z=None, k=None): sage: E4(z) 32288.0558881... - 118329.856601...*I + sage: z = HyperbolicPlane().PD().get_point(CC(-I/2 + 1/8)) + sage: (G.V(2)*G.V(3)).slash(E4, z) + -(21624.437... - 12725.035...*I)/((0.610... + 0.324...*I)*sqrt(5) + 2.720... + 0.648...*I)^4 + sage: z = PolynomialRing(G.base_ring(), 'z').gen() sage: rat = z^2 + 1/(z-G.lam()) sage: dr = rat.numerator().degree() - rat.denominator().degree() - sage: G.S().slash(rat) == G.S().slash(rat, z=None, k=-dr) + sage: G.S().slash(rat) == G.S().slash(rat, tau=None, k=-dr) True sage: G.S().slash(rat) (z^6 - lam*z^4 - z^3)/(-lam*z^4 - z^3) @@ -3189,6 +3231,7 @@ def slash(self, f, z=None, k=None): sage: G.S().slash(rat, k=-4) (z^8 - lam*z^6 - z^5)/(-lam*z^4 - z^3) """ + if k is None: if hasattr(f, 'weight'): k = f.weight() @@ -3207,10 +3250,35 @@ def slash(self, f, z=None, k=None): except TypeError: raise ValueError("k={} must be an even integer!".format(k)) - if z is None: + if tau is None: try: - z = f.numerator().parent().gen() + tau = f.numerator().parent().gen() except (ValueError, TypeError, AttributeError): - raise ValueError("f={} is not a rational function or a polynomial in one variable, so z has to be specfied explicitely!".format(f)) + raise ValueError("f={} is not a rational function or a polynomial in one variable, so tau has to be specfied explicitely!".format(f)) + + from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane + + if (tau in HyperbolicPlane()): + tau = tau.to_model('UHP').coordinates() + + return (self.c()*tau + self.d())**(-k) * f(self.acton(tau)) + + def as_isometry(self): + r""" + Return ``self`` as an isometry of ``HyperbolicPlane()`` (in the upper half plane model). + + EXAMPLES:: + + sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup + sage: el = HeckeTriangleGroup(7).V(4) + sage: el.as_isometry() + Isometry in UHP + [lam^2 - 1 lam] + [lam^2 - 1 lam^2 - 1] + sage: el.as_isometry().parent() + Set of Morphisms from Hyperbolic plane in the Upper Half Plane Model model to Hyperbolic plane in the Upper Half Plane Model model in Category of hyperbolic models of Hyperbolic plane + """ + + from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane - return (self.c()*z + self.d())**(-k) * f(self.acton(z)) + return HyperbolicPlane().UHP().get_isometry(self.matrix()) From 532b56f363191cf915953484d21c536def7bfff1 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 15 Oct 2015 20:10:10 +0200 Subject: [PATCH 1505/1872] Trac #19083: Minor language adjustments --- src/sage/rings/asymptotic/term_monoid.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 567d0757d99..d35bc70b5ec 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1123,7 +1123,7 @@ def _eq_(self, other): def is_constant(self): r""" - Return if this term is an (exact) constant. + Return whether this term is an (exact) constant. INPUT: @@ -1159,7 +1159,7 @@ def is_constant(self): def is_little_o_of_one(self): r""" - Return if this generic term is of order `o(1)`. + Return whether this generic term is of order `o(1)`. INPUT: @@ -1178,18 +1178,18 @@ def is_little_o_of_one(self): sage: T.an_element().is_little_o_of_one() Traceback (most recent call last): ... - NotImplementedError: Cannot check if Generic Term with growth x is o(1) + NotImplementedError: Cannot check whether Generic Term with growth x is o(1) in the abstract base class Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field. sage: T = TermWithCoefficientMonoid(GrowthGroup('x^ZZ'), QQ) sage: T.an_element().is_little_o_of_one() Traceback (most recent call last): ... - NotImplementedError: Cannot check if Term with coefficient 1/2 and growth x + NotImplementedError: Cannot check whether Term with coefficient 1/2 and growth x is o(1) in the abstract base class Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field. """ - raise NotImplementedError('Cannot check if %s is o(1) in the ' + raise NotImplementedError('Cannot check whether %s is o(1) in the ' 'abstract base class %s.' % (self, self.parent())) @@ -1296,7 +1296,7 @@ class GenericTermMonoid(sage.structure.unique_representation.UniqueRepresentatio @staticmethod def __classcall__(cls, growth_group, coefficient_ring, category=None): r""" - Normalizes the input in order to ensure a unique + Normalize the input in order to ensure a unique representation of the parent. TESTS:: @@ -1954,7 +1954,7 @@ def __pow__(self, exponent): def can_absorb(self, other): r""" - Check, whether this `O`-term can absorb ``other``. + Check whether this `O`-term can absorb ``other``. INPUT: @@ -2074,7 +2074,7 @@ def log_term(self, base=None): def is_little_o_of_one(self): r""" - Return if this O-term is of order `o(1)`. + Return whether this O-term is of order `o(1)`. INPUT: @@ -2246,7 +2246,7 @@ def _create_element_(self, growth, coefficient): from misc import combine_exceptions raise combine_exceptions( ValueError('Cannot create O(%s) since given coefficient %s ' - 'is not a valid in %s.' % + 'is not valid in %s.' % (growth, coefficient, self)), e) return self.element_class(self, growth) @@ -3059,7 +3059,7 @@ def log_term(self, base=None): def is_constant(self): r""" - Return if this term is an (exact) constant. + Return whether this term is an (exact) constant. INPUT: @@ -3093,7 +3093,7 @@ def is_constant(self): def is_little_o_of_one(self): r""" - Return if this exact term is of order `o(1)`. + Return whether this exact term is of order `o(1)`. INPUT: From bb5c08b7c8261e82ac05ee7a855b3bbb56a89785 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 15 Oct 2015 20:10:54 +0200 Subject: [PATCH 1506/1872] Trac #19083: Make doctest more explicit by showing intermediate output --- src/sage/rings/asymptotic/term_monoid.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index d35bc70b5ec..5b1c395917d 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1143,7 +1143,9 @@ def is_constant(self): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import (GenericTermMonoid, TermMonoid) sage: T = GenericTermMonoid(GrowthGroup('x^ZZ * log(x)^ZZ'), QQ) - sage: T.an_element().is_constant() + sage: t = T.an_element(); t + Generic Term with growth x*log(x) + sage: t.is_constant() False :: From 7204167a1a20d0428db33cfbfd3cb7ba6c743af2 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 15 Oct 2015 20:11:20 +0200 Subject: [PATCH 1507/1872] Trac #19083: Remove unused part of a doctest --- src/sage/rings/asymptotic/term_monoid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 5b1c395917d..b94157d28bf 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1359,7 +1359,7 @@ def __init__(self, growth_group, coefficient_ring, category): :: - sage: G = GrowthGroup('x^ZZ'); x = G.gen() + sage: G = GrowthGroup('x^ZZ') sage: T_ZZ = TermWithCoefficientMonoid(G, ZZ); T_ZZ Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring sage: T_QQ = TermWithCoefficientMonoid(G, QQ); T_QQ From 47d76534120984a1499bb4cabddf79890e0f01b4 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 15 Oct 2015 20:11:35 +0200 Subject: [PATCH 1508/1872] Trac #19083: Add missing "EXAMPLES::" --- src/sage/rings/asymptotic/term_monoid.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index b94157d28bf..16d90dcf7cc 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1645,6 +1645,8 @@ def _create_element_via_parent_(self, growth, coefficient): An element. + EXAMPLES:: + sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') From c5dadf7a1bb3bb7785a49cb4ffd6cadc279a9084 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 15 Oct 2015 20:13:10 +0200 Subject: [PATCH 1509/1872] Trac #19083: More interesting doctest by including a coefficient --- src/sage/rings/asymptotic/term_monoid.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 16d90dcf7cc..cd6a285c926 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2502,12 +2502,13 @@ def _calculate_pow_(self, exponent): sage: from sage.rings.asymptotic.term_monoid import TermWithCoefficientMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') - sage: t = TermWithCoefficientMonoid(G, ZZ).an_element(); t - Term with coefficient 1 and growth z + sage: T = TermWithCoefficientMonoid(G, ZZ) + sage: t = T('2*z'); t + Term with coefficient 2 and growth z sage: t._calculate_pow_(3) - Term with coefficient 1 and growth z^3 + Term with coefficient 8 and growth z^3 sage: t._calculate_pow_(-2) - Term with coefficient 1 and growth z^(-2) + Term with coefficient 1/4 and growth z^(-2) """ try: c = self.coefficient ** exponent @@ -2918,12 +2919,13 @@ def __pow__(self, exponent): sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') - sage: t = TermMonoid('exact', G, ZZ).an_element(); t - z + sage: T = TermMonoid('exact', G, ZZ) + sage: t = T('2*z'); t + 2*z sage: t^3 # indirect doctest - z^3 + 8*z^3 sage: t^(1/2) # indirect doctest - z^(1/2) + sqrt(2)*z^(1/2) """ return self._calculate_pow_(exponent) From 792aab7202f9e62d389c0dcb10c21ccfb5f24ec9 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Thu, 15 Oct 2015 20:26:53 +0200 Subject: [PATCH 1510/1872] Updated Sage version to 6.10.beta0 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-banner | 5 ++++- src/bin/sage-version.sh | 4 ++-- src/sage/version.py | 4 ++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 68733eba217..9d90d562953 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Sage version 6.9, released 2015-10-10 +Sage version 6.10.beta0, released 2015-10-15 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index ad47e649554..0c170545927 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=beb4de16a8e5a632516a6b5f63313e66c6770183 -md5=d6922f63e807c1d240582601e746dcb1 -cksum=2973216508 +sha1=3e0d10789b34d6f890e1575c2a06894a90e4807e +md5=020a9b7f31e61b57056969b6816455f1 +cksum=2662451870 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 078fa0fe576..52bd8e43afb 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -119 +120 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index 955061b92e5..4a95ae46233 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,8 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath Version 6.9, Release Date: 2015-10-10 │ +│ SageMath Version 6.10.beta0, Release Date: 2015-10-15 │ │ Type "notebook()" for the browser-based notebook interface. │ │ Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Warning: this is a prerelease version, and it may be unstable. ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 7b35690365e..b8eaf7940b3 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.9' -SAGE_RELEASE_DATE='2015-10-10' +SAGE_VERSION='6.10.beta0' +SAGE_RELEASE_DATE='2015-10-15' diff --git a/src/sage/version.py b/src/sage/version.py index da4209e58b1..13ac1cb1b05 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.9' -date = '2015-10-10' +version = '6.10.beta0' +date = '2015-10-15' From 9bfc2d2881810588de6eb1ad85870a7ac95a1b28 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 15 Oct 2015 11:49:23 -0700 Subject: [PATCH 1511/1872] trac 6102: documentation, minor cleanup --- .../homology/algebraic_topological_model.py | 82 +++++----- src/sage/homology/cell_complex.py | 117 +++++++++----- .../homology_vector_space_with_basis.py | 148 ++++++++++++------ 3 files changed, 211 insertions(+), 136 deletions(-) diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index f1f85b43f4b..1d4c40fd477 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -42,15 +42,12 @@ def algebraic_topological_model(K, base_ring=None): INPUT: - ``K`` -- either a simplicial complex or a cubical complex - - ``base_ring`` -- coefficient ring (optional, default ``QQ``); - must be a field + - ``base_ring`` -- coefficient ring; must be a field OUTPUT: a pair ``(phi, M)`` consisting of - - the chain contraction ``phi`` associated to `C`, `M`, `\pi: C - \to M`, and `\iota: M \to C` satisfying `\iota \pi = 1_M` and - `\pi \iota`; and - - the chain complex `M`. + - chain contraction ``phi`` + - chain complex `M` This construction appears in a paper by Pilarczyk and Réal [PR]_. Given a cell complex `K` and a field `F`, there is a chain complex @@ -59,18 +56,18 @@ def algebraic_topological_model(K, base_ring=None): differential, along with chain maps `\pi: C \to M` and `\iota: M \to C` such that - - `\pi \circ \iota = 1_M`, and - - there is a chain homotopy `\phi` between `1_C` and `\iota \circ \pi`. + - `\pi \iota = 1_M`, and + - there is a chain homotopy `\phi` between `1_C` and `\iota \pi`. In particular, `\pi` and `\iota` induce isomorphisms on homology, - and since `M` has trivial differential, it is its own - homology. Thus `\iota` lifts homology classes to their cycle - representatives. + and since `M` has trivial differential, it is its own homology, + and thus also the homology of `C`. Thus `\iota` lifts homology + classes to their cycle representatives. The chain homotopy `\phi` satisfies some additional properties, making it a *chain contraction*: - - `\phi \circ \phi = 0`, + - `\phi \phi = 0`, - `\pi \phi = 0`, - `\phi \iota = 0`. @@ -78,21 +75,23 @@ def algebraic_topological_model(K, base_ring=None): compute cup products and cohomology operations on the cohomology of `K`, as described in [G-DR03]_ and [PR]_. - Implementation details: the cell complex `K` must have a - :meth:`cell_complex.GenericCellComplex.n_cells` method from which - we can extract a list of cells in each dimension. Combining the - lists in increasing order of dimension then defines a filtration - of the complex: a list of cells in which the boundary of each cell - consists of cells earlier in the list. This is required by - Pilarczyk and Réal's algorithm. There must also be a - :meth:`cell_complex.GenericCellComplex.chain_complex` method, to - construct the chain complex `C` associated to this chain complex. - - In particular, this should work on simplicial complexes and - cubical complexes. It doesn't work for delta complexes, though: - the list of their n-cells has the wrong format. - - Note that from the chain contraction ``\phi``, one can recover the + Implementation details: the cell complex `K` must have an + :meth:`~sage.homology.cell_complex.GenericCellComplex.n_cells` + method from which we can extract a list of cells in each + dimension. Combining the lists in increasing order of dimension + then defines a filtration of the complex: a list of cells in which + the boundary of each cell consists of cells earlier in the + list. This is required by Pilarczyk and Réal's algorithm. There + must also be a + :meth:`~sage.homology.cell_complex.GenericCellComplex.chain_complex` + method, to construct the chain complex `C` associated to this + chain complex. + + In particular, this works for simplicial complexes and cubical + complexes. It doesn't work for `\Delta`-complexes, though: the list + of their `n`-cells has the wrong format. + + Note that from the chain contraction ``phi``, one can recover the chain maps `\pi` and `\iota` via ``phi.pi()`` and ``phi.iota()``. Then one can recover `C` and `M` from, for example, ``phi.pi().domain()`` and ``phi.pi().codomain()``, @@ -142,7 +141,7 @@ def algebraic_topological_model(K, base_ring=None): [0] [1] - In cohomology, though, one needs the dual of every degree 0 chain + In cohomology, though, one needs the dual of every degree 0 cell to detect the degree 0 cohomology generator:: sage: phi.dual().iota().in_degree(0) @@ -165,8 +164,6 @@ def algebraic_topological_model(K, base_ring=None): sage: coC.differential(1) * H.dual().iota().in_degree(1).column(1) == 0 True """ - if base_ring is None: - base_ring = QQ if not base_ring.is_field(): raise ValueError('the coefficient ring must be a field') @@ -353,16 +350,13 @@ def algebraic_topological_model_delta_complex(K, base_ring=None): INPUT: - ``K`` -- a simplicial complex, a cubical complex, or a - Delta complex - - ``base_ring`` -- coefficient ring (optional, default ``QQ``); - must be a field + `\Delta`-complex + - ``base_ring`` -- coefficient ring; must be a field OUTPUT: a pair ``(phi, M)`` consisting of - - the chain contraction ``phi`` associated to `C`, `M`, `\pi: C - \to M`, and `\iota: M \to C` satisfying `\iota \pi = 1_M` and - `\pi \iota`; and - - the chain complex `M`. + - chain contraction ``phi`` + - chain complex `M` See :func:`algebraic_topological_model` for the main documentation. The difference in implementation between the two: @@ -410,14 +404,14 @@ def algebraic_topological_model_delta_complex(K, base_ring=None): In degree 0, the inclusion of the homology `M` into the chain complex `C` sends the homology generator to a single vertex:: - sage: K = simplicial_complexes.Simplex(2) + sage: K = delta_complexes.Simplex(2) sage: phi, M = AT_model(K, QQ) sage: phi.iota().in_degree(0) [0] [0] [1] - In cohomology, though, one needs the dual of every degree 0 chain + In cohomology, though, one needs the dual of every degree 0 cell to detect the degree 0 cohomology generator:: sage: phi.dual().iota().in_degree(0) @@ -429,7 +423,7 @@ def algebraic_topological_model_delta_complex(K, base_ring=None): sage: T = cubical_complexes.Torus() sage: C = T.chain_complex() - sage: H, M = AT_model(T) + sage: H, M = AT_model(T, QQ) sage: C.differential(1) * H.iota().in_degree(1).column(0) == 0 True sage: C.differential(1) * H.iota().in_degree(1).column(1) == 0 @@ -444,9 +438,9 @@ def conditionally_sparse(m): """ Return a sparse matrix if the characteristic is zero. - Multiplication of matrices with low density seems to quicker + Multiplication of matrices with low density seems to be quicker if the matrices are sparse, when over the rationals. Over - finite fields, dense matrices, are faster regardless of + finite fields, dense matrices are faster regardless of density. """ if base_ring == QQ: @@ -454,9 +448,7 @@ def conditionally_sparse(m): else: return m - if base_ring is None: - base_ring = QQ - elif not base_ring.is_field(): + if not base_ring.is_field(): raise ValueError('the coefficient ring must be a field') # The following are all dictionaries indexed by dimension. diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index aa5130f7edc..f0767a22201 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -413,7 +413,7 @@ def homology(self, dim=None, **kwds): .. note:: The keyword arguments to this function get passed on to - :meth:``chain_complex`` and its homology. + :meth:`chain_complex` and its homology. ALGORITHM: @@ -425,14 +425,14 @@ def homology(self, dim=None, **kwds): CHomP computes homology, not cohomology, and only works over the integers or finite prime fields. Therefore if any of these conditions fails, or if CHomP is not present, or if - ``algorithm`` is set to 'no_chomp', go to plan B: if ``self`` + ``algorithm`` is set to 'no_chomp', go to plan B: if this complex has a ``_homology`` method -- each simplicial complex has this, for example -- then call that. Such a method implements specialized algorithms for the particular type of cell complex. Otherwise, move on to plan C: compute the chain complex of - ``self`` and compute its homology groups. To do this: over a + this complex and compute its homology groups. To do this: over a field, just compute ranks and nullities, thus obtaining dimensions of the homology groups as vector spaces. Over the integers, compute Smith normal form of the boundary matrices @@ -689,13 +689,11 @@ def algebraic_topological_model(self, base_ring=None): Algebraic topological model for this cell complex with coefficients in ``base_ring``. - The term algebraic topological model is defined by Pilarczyk + The term "algebraic topological model" is defined by Pilarczyk and Réal [PR]_. - .. NOTE:: - - This is only implemented for simplicial, cubical, and - `\Delta`-complexes. + This is implemented for simplicial, cubical, and + `\Delta`-complexes, not for arbitrary generic cell complexes. INPUT: @@ -707,37 +705,36 @@ def algebraic_topological_model(self, base_ring=None): `M` with zero differential, with the same homology as `C`, along with chain maps `\pi: C \to M` and `\iota: M \to C` satisfying `\iota \pi = 1_M` and `\pi \iota` chain homotopic - to `1_C`. The chain homotopy `H` must satisfy + to `1_C`. The chain homotopy `\phi` must satisfy - - `H \circ H = 0`, - - `\pi H = 0`, - - `H \iota = 0`. + - `\phi \phi = 0`, + - `\pi \phi = 0`, + - `\phi \iota = 0`. Such a chain homotopy is called a *chain contraction*. OUTPUT: a pair consisting of - - chain contraction ``H`` associated to `C`, `M`, `\pi`, and + - chain contraction ``phi`` associated to `C`, `M`, `\pi`, and `\iota` - the chain complex `M` - Note that from the chain contraction ``H``, one can recover the - chain maps `\pi` and `\iota` via ``H.pi()`` and - ``H.iota()``. Then one can recover `C` and `M` from, for - example, ``H.pi().domain()`` and ``H.pi().codomain()``, + Note that from the chain contraction ``phi``, one can recover the + chain maps `\pi` and `\iota` via ``phi.pi()`` and + ``phi.iota()``. Then one can recover `C` and `M` from, for + example, ``phi.pi().domain()`` and ``phi.pi().codomain()``, respectively. EXAMPLES:: - sage: from sage.homology.algebraic_topological_model import algebraic_topological_model sage: RP2 = simplicial_complexes.RealProjectivePlane() - sage: H, M = RP2.algebraic_topological_model(GF(2)) + sage: phi, M = RP2.algebraic_topological_model(GF(2)) sage: M.homology() {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} sage: T = simplicial_complexes.Torus() - sage: H, M = T.algebraic_topological_model(QQ) + sage: phi, M = T.algebraic_topological_model(QQ) sage: M.homology() {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 2 over Rational Field, @@ -747,26 +744,21 @@ def algebraic_topological_model(self, base_ring=None): from cubical_complex import CubicalComplex from simplicial_complex import SimplicialComplex from delta_complex import DeltaComplex + if base_ring is None: + base_ring = QQ if not isinstance(self, (CubicalComplex, SimplicialComplex, DeltaComplex)): raise NotImplementedError('only implemented for simplicial, cubical, and Delta complexes') - try: - if not self.is_immutable(): - raise ValueError('the complex must be immutable') - except AttributeError: - # Cubical complexes don't have an is_immutable method, and - # they are always immutable. - pass if isinstance(self, DeltaComplex): return algebraic_topological_model_delta_complex(self, base_ring) return algebraic_topological_model(self, base_ring) def homology_with_basis(self, base_ring=None, cohomology=False): r""" - Return the unreduced homology in dimension ``dim`` with + Return the unreduced homology of this complex with coefficients in ``base_ring`` with a chosen basis. This is implemented for simplicial, cubical, and - `\Delta`-complexes. + `\Delta`-complexes, not for arbitrary generic cell complexes. INPUTS: @@ -799,6 +791,16 @@ def homology_with_basis(self, base_ring=None, cohomology=False): (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets over Finite Field of size 2 sage: sorted(H.basis(), key=str) [h_{0,0}, h_{1,0}, h_{1,1}, h_{2,0}] + + The homology is constructed as a graded object, so for + example, you can ask for the basis in a single degree:: + + sage: H.basis(1) + Finite family {(1, 0): h_{1,0}, (1, 1): h_{1,1}} + sage: S3 = delta_complexes.Sphere(3) + sage: H = S3.homology_with_basis(QQ, cohomology=True) + sage: list(H.basis(3)) + [h^{3,0}] """ from homology_vector_space_with_basis import HomologyVectorSpaceWithBasis if base_ring is None: @@ -811,20 +813,30 @@ def cohomology_ring(self, base_ring=None): ``base_ring`` with a chosen basis. This is implemented for simplicial, cubical, and - `\Delta`-complexes. The resulting elements are suitable for - computing cup products. For simplicial complexes, they should - be suitable for computing cohomology operations; at the - moment, only mod 2 cohomology operations have been - implemented. + `\Delta`-complexes, not for arbitrary generic cell complexes. + The resulting elements are suitable for computing cup + products. For simplicial complexes, they should be suitable + for computing cohomology operations; so far, only mod 2 + cohomology operations have been implemented. INPUTS: - - ``dim`` -- dimension - ``base_ring`` -- coefficient ring (optional, default ``QQ``); must be a field - The basis elements are named 'h^{dim,i}' where `i` ranges - between 0 and `r-1`, if `r` is the rank of the homology group. + The basis elements in dimension ``dim`` are named 'h^{dim,i}' + where `i` ranges between 0 and `r-1`, if `r` is the rank of + the cohomology group. + + .. NOTE:: + + For all but the smallest complexes, this is likely to be + slower than :meth:`cohomology` (with field coefficients), + possibly by several orders of magnitute. This and its + companion :meth:`homology_with_basis` carry extra + information which allows computation of cup products, for + example, but because of speed issues, you may only wish to + use these if you need that extra information. EXAMPLES:: @@ -841,9 +853,11 @@ def cohomology_ring(self, base_ring=None): [h^{0,0}, h^{1,0}, h^{1,1}, h^{2,0}] sage: X = delta_complexes.SurfaceOfGenus(2) - sage: X.cohomology_ring(QQ) + sage: H = X.cohomology_ring(QQ); H Cohomology ring of Delta complex with 3 vertices and 29 simplices over Rational Field + sage: sorted(H.basis(1), key=str) + [h^{1,0}, h^{1,1}, h^{1,2}, h^{1,3}] sage: H = simplicial_complexes.Torus().cohomology_ring(QQ); H Cohomology ring of Simplicial complex with vertex set @@ -857,6 +871,8 @@ def cohomology_ring(self, base_ring=None): sage: x.cup_product(y) h^{2,0} + sage: x * y # alternate notation + h^{2,0} sage: y.cup_product(x) -h^{2,0} sage: x.cup_product(x) @@ -867,11 +883,34 @@ def cohomology_ring(self, base_ring=None): sage: RP2 = simplicial_complexes.RealProjectivePlane() sage: K = RP2.suspension() sage: K.set_immutable() - sage: y = K.cohomology_ring(GF(2)).basis()[2,0] + sage: y = K.cohomology_ring(GF(2)).basis()[2,0]; y + h^{2,0} sage: y.Sq(1) h^{3,0} + + To compute the cohomology ring, the complex must be + "immutable". This is only relevant for simplicial complexes, + and most simplicial complexes are immutable, but certain + constructions make them mutable. The suspension is one + example, and this is the reason for calling + ``K.set_immutable()`` above. Another example:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: T = S1.product(S1) + sage: T.is_immutable() + False + sage: T.cohomology_ring() + Traceback (most recent call last): + ... + ValueError: This simplicial complex must be immutable. Call set_immutable(). + sage: T.set_immutable() + sage: T.cohomology_ring() + Cohomology ring of Simplicial complex with 9 vertices and + 18 facets over Rational Field """ from homology_vector_space_with_basis import CohomologyRing + if base_ring is None: + base_ring = QQ return CohomologyRing(base_ring, self) ############################################################ diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 0a50bfb7fb2..bb67ea1f41b 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -34,7 +34,6 @@ from sage.categories.algebras import Algebras from sage.categories.modules import Modules from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement -from sage.modules.free_module import FreeModule from sage.sets.family import Family from simplicial_complex import SimplicialComplex @@ -42,9 +41,9 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): r""" Homology (or cohomology) vector space. - This is intended to provide enough structure to allow the - computation of cup products and cohomology operations. The former - has been implemented, but not the latter (yet). + This provides enough structure to allow the computation of cup + products and cohomology operations. See the class + :class:`CohomologyRing` (which derives from this) for examples. It also requires field coefficients (hence the "VectorSpace" in the name of the class). @@ -53,16 +52,17 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): This is not intended to be created directly by the user, but instead via the methods - :meth:`cell_complex.CellComplex.homology_with_basis` and - :meth:`cell_complex.CellComplex.cohomology_ring`. + :meth:`~sage.homology.cell_complex.GenericCellComplex.homology_with_basis` and + :meth:`~sage.homology.cell_complex.GenericCellComplex.cohomology_ring` + for the class of :class:`cell + complexes`. INPUT: - - ``contraction`` -- the chain contraction associated to this - homology computation + - ``base_ring`` -- must be a field - ``cell_complex`` -- the cell complex whose homology we are computing - - ``cohomology`` -- (default: ``False``) if ``True``, this reflects + - ``cohomology`` -- (default: ``False``) if ``True``, return the cohomology as a module - ``category`` -- (optional) a subcategory of modules with basis @@ -70,7 +70,8 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): Homology classes are denoted by ``h_{d,i}`` where ``d`` is the degree of the homology class and ``i`` is their index in the list - of basis elements. Cohomology classes are denoted ``h^{1,0}``:: + of basis elements in that degree. Cohomology classes are denoted + ``h^{1,0}``:: sage: RP2 = cubical_complexes.RealProjectivePlane() sage: RP2.homology_with_basis(GF(2)) @@ -89,15 +90,10 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): sage: H = simplicial_complexes.Torus().cohomology_ring(QQ) sage: H.basis(1) Finite family {(1, 0): h^{1,0}, (1, 1): h^{1,1}} - sage: H.basis()[1,0] + sage: x = H.basis()[1,0]; x h^{1,0} - sage: H.basis()[1,1] + sage: y = H.basis()[1,1]; y h^{1,1} - - You can then form linear combinations of these easily enough:: - - sage: x = H.basis()[1,0] - sage: y = H.basis()[1,1] sage: 2*x-3*y 2*h^{1,0} - 3*h^{1,1} @@ -110,7 +106,7 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): sage: x.cup_product(x) 0 - This works with simplicial, cubical, and Delta complexes:: + This works with simplicial, cubical, and `\Delta`-complexes:: sage: Klein_c = cubical_complexes.KleinBottle() sage: H = Klein_c.cohomology_ring(GF(2)) @@ -163,15 +159,19 @@ def __init__(self, base_ring, cell_complex, cohomology=False, cat=None): sage: TestSuite(H).run() sage: H = RP2.cohomology_ring(GF(5)) sage: TestSuite(H).run() + sage: H = simplicial_complexes.ComplexProjectivePlane().cohomology_ring() + sage: TestSuite(H).run() """ - H, M = cell_complex.algebraic_topological_model(base_ring) + # phi is the associated chain contraction. + # M is the homology chain complex. + phi, M = cell_complex.algebraic_topological_model(base_ring) if cohomology: - H = H.dual() + phi = phi.dual() + # We only need the rank of M in each degree, and since + # we're working over a field, we don't need to dualize M + # if working with cohomology. cat = Modules(base_ring).WithBasis().Graded().or_subcategory(cat) - self._contraction = H - # M is the homology chain complex. - # Do we need this for when we construct the cohomology? - M = self._contraction.pi()._codomain + self._contraction = phi self._complex = cell_complex self._cohomology = cohomology self._graded_indices = {deg: range(M.free_module_rank(deg)) @@ -183,7 +183,7 @@ def __init__(self, base_ring, cell_complex, cohomology=False, cat=None): def basis(self, d=None): """ Return (the degree ``d`` homogeneous component of) the basis - of ``self``. + of this graded vector space. INPUT: @@ -233,9 +233,9 @@ def contraction(self): OUTPUT: `\phi` - See :class:`chain_homotopy.ChainContraction` for information + See :class:`~sage.homology.chain_homotopy.ChainContraction` for information about chain contractions, and see - :func:`algebraic_topological_model.algebraic_topological_model` + :func:`~sage.homology.algebraic_topological_model.algebraic_topological_model` for the construction of this particular chain contraction `\phi`. EXAMPLES:: @@ -293,8 +293,8 @@ def _repr_(self): def _repr_term(self, i): """ - Return ``'h_{d,i}'`` for the ``i``-th generator in degree ``d`` - for homology, ``'h^{d,i}'`` for cohomology. + Return ``'h_{i[0],i[1]}'`` for homology, ``'h^{i[0],i[1]}'`` for + cohomology, for the basis element indexed by ``i``. EXAMPLES:: @@ -306,6 +306,7 @@ def _repr_term(self, i): sage: co = simplicial_complexes.KleinBottle().cohomology_ring(GF(2)) sage: co.basis()[1,0] # indirect doctest h^{1,0} + """ sym = '^' if self._cohomology else '_' return 'h{}{{{},{}}}'.format(sym, i[0], i[1]) @@ -389,6 +390,42 @@ def to_cycle(self): class CohomologyRing(HomologyVectorSpaceWithBasis): """ The cohomology ring. + + .. NOTE:: + + This is not intended to be created directly by the user, but + instead via the + :meth:`cohomology ring` + of a :class:`cell + complex`. + + INPUT: + + - ``base_ring`` -- must be a field + - ``cell_complex`` -- the cell complex whose homology we are + computing + + EXAMPLES:: + + sage: CP2 = simplicial_complexes.ComplexProjectivePlane() + sage: H = CP2.cohomology_ring(QQ) + sage: H.basis(2) + Finite family {(2, 0): h^{2,0}} + sage: x = H.basis(2)[2,0] + + The product structure is the cup product:: + + sage: x.cup_product(x) + h^{4,0} + sage: x * x + h^{4,0} + + There are mod 2 cohomology operations defined, also:: + + sage: Hmod2 = CP2.cohomology_ring(GF(2)) + sage: y = Hmod2.basis(2)[2,0] + sage: y.Sq(2) + h^{4,0} """ def __init__(self, base_ring, cell_complex): """ @@ -418,11 +455,15 @@ def _repr_(self): @cached_method def one(self): """ + The multiplicative identity element. + EXAMPLES:: sage: H = simplicial_complexes.Torus().cohomology_ring(QQ) sage: H.one() h^{0,0} + sage: all(H.one() * x == x == x * H.one() for x in H.basis()) + True """ one = self.base_ring().one() d = {(0,i): one for i in self._graded_indices[0]} @@ -432,7 +473,7 @@ def one(self): def product_on_basis(self, li, ri): r""" The cup product of the basis elements indexed by ``li`` and ``ri`` - in ``self``. + in this cohomology ring. INPUT: @@ -440,14 +481,15 @@ def product_on_basis(self, li, ri): .. SEEALSO:: - :meth:`CohomologyRing.Element.cup_product` + :meth:`CohomologyRing.Element.cup_product` -- the + documentation for this method describes the algorithm. EXAMPLES:: sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) sage: H = RP3.cohomology_ring(GF(2)) sage: c = H.basis()[1,0] - sage: c.cup_product(c).cup_product(c) + sage: c.cup_product(c).cup_product(c) # indirect doctest h^{3,0} sage: T = simplicial_complexes.Torus() @@ -548,21 +590,27 @@ def product_on_basis(self, li, ri): class Element(HomologyVectorSpaceWithBasis.Element): def cup_product(self, other): - """ - Return the cup product of ``self`` and ``other``. + r""" + Return the cup product of this element and ``other``. Algorithm: see González-Díaz and Réal [G-DR03]_, p. 88. Given two cohomology classes, lift them to cocycle - representatives using :meth:`to_cycle`. In the sum of - their dimensions, look at all of the homology classes - `\gamma`: lift each of those to a cycle representative, - apply the Alexander-Whitney diagonal map to each cell in - the cycle, evaluate the two cocycles on these factors, and - multiply. The result is the value of the cup product - cocycle on this homology class. After this has been done - for all homology classes, since homology and cohomology - are dual, one can tell which cohomology class corresponds - to the cup product. + representatives via the chain contraction for this + complex, using + :meth:`~HomologyVectorSpaceWithBasis.Element.to_cycle`. In + the sum of their dimensions, look at all of the homology + classes `\gamma`: lift each of those to a cycle + representative, apply the Alexander-Whitney diagonal map + to each cell in the cycle, evaluate the two cocycles on + these factors, and multiply. The result is the value of + the cup product cocycle on this homology class. After this + has been done for all homology classes, since homology and + cohomology are dual, one can tell which cohomology class + corresponds to the cup product. + + .. SEEALSO:: + + :meth:`CohomologyRing.product_on_basis` EXAMPLES:: @@ -593,6 +641,7 @@ def cup_product(self, other): sage: a,b = K.cohomology_ring(QQ).basis(2) sage: a**0 h^{0,0} + h^{0,1} + """ return self * other @@ -606,8 +655,7 @@ def Sq(self, i): .. WARNING:: - This is only implemented for simplicial complexes, not - cubical complexes. + This is only implemented for simplicial complexes. This cohomology operation is only defined in characteristic 2. @@ -633,12 +681,8 @@ def Sq(self, i): sage: x = H.basis()[1,0] sage: y = H.basis()[2,0] sage: z = H.basis()[3,0] - sage: x.Sq(1) # long time - h^{2,0} - sage: y.Sq(1) - 0 - sage: y.Sq(2) # long time - h^{4,0} + sage: x.Sq(1) == y + True sage: z.Sq(1) # long time h^{4,0} From f810aa668c8d0c74ec861e9ab307bedc7777036a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 15 Oct 2015 17:50:12 -0500 Subject: [PATCH 1512/1872] Reworking the category of manifolds. --- src/sage/categories/category_with_axiom.py | 4 +- src/sage/categories/examples/manifolds.py | 27 +- src/sage/categories/manifolds.py | 372 +++++++++------------ 3 files changed, 181 insertions(+), 222 deletions(-) diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 5ad5572945d..f7c23c29ec7 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1673,8 +1673,8 @@ class ``Sets.Finite``), or in a separate file (typically in a class all_axioms = AxiomContainer() all_axioms += ("Flying", "Blue", - "Compact", "Complex", - "Differentiable", "Smooth", "Analytic", "AlmostComplex", "Real", + "Compact", + "Differentiable", "Smooth", "Analytic", "AlmostComplex", "FinitelyGeneratedAsMagma", "Facade", "Finite", "Infinite", "Complete", diff --git a/src/sage/categories/examples/manifolds.py b/src/sage/categories/examples/manifolds.py index 68d428856c2..a71b7cf30e3 100644 --- a/src/sage/categories/examples/manifolds.py +++ b/src/sage/categories/examples/manifolds.py @@ -23,41 +23,42 @@ class Plane(UniqueRepresentation, Parent): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: M = Manifolds().example(); M - An example of a manifold: the 3-dimensional plane + sage: M = Manifolds(QQ).example(); M + An example of a Rational Field manifold: the 3-dimensional plane sage: M.category() - Category of manifolds + Category of manifolds over Rational Field We conclude by running systematic tests on this manifold:: sage: TestSuite(M).run() """ - def __init__(self, n=3): + def __init__(self, n=3, base_ring=None): r""" EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: M = Manifolds().example(6); M - An example of a manifold: the 6-dimensional plane + sage: M = Manifolds(QQ).example(6); M + An example of a Rational Field manifold: the 6-dimensional plane TESTS:: sage: TestSuite(M).run() """ self._n = n - Parent.__init__(self, category=Manifolds()) + Parent.__init__(self, base=base_ring, category=Manifolds(base_ring)) def _repr_(self): r""" TESTS:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds().example() - An example of a manifold: the 3-dimensional plane + sage: Manifolds(QQ).example() + An example of a Rational Field manifold: the 3-dimensional plane """ - return "An example of a manifold: the {}-dimensional plane".format(self._n) + return "An example of a {} manifold: the {}-dimensional plane".format( + self.base_ring(), self._n) def dimension(self): """ @@ -66,7 +67,7 @@ def dimension(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: M = Manifolds().example() + sage: M = Manifolds(QQ).example() sage: M.dimension() 3 """ @@ -80,11 +81,11 @@ def an_element(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: M = Manifolds().example() + sage: M = Manifolds(QQ).example() sage: M.an_element() (0, 0, 0) """ - zero = QQ.zero() + zero = self.base_ring().zero() return self(tuple([zero]*self._n)) Element = ElementWrapper diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index 884e9cb8ef6..972ca4cedfe 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -19,7 +19,7 @@ class Manifolds(Category_over_base_ring): r""" - The category of manifolds over any field. + The category of manifolds over any topological field. Let `k` be a topological field. A `d`-dimensional `k`-*manifold* `M` is a second countable Hausdorff space such that the neighborhood of @@ -35,7 +35,7 @@ class Manifolds(Category_over_base_ring): TESTS:: - sage: TestSuite(C).run() + sage: TestSuite(C).run(skip="_test_category_over_bases") """ def __init__(self, base, name=None): r""" @@ -45,7 +45,7 @@ def __init__(self, base, name=None): sage: from sage.categories.manifolds import Manifolds sage: C = Manifolds(RR) - sage: TestSuite(C).run() + sage: TestSuite(C).run(skip="_test_category_over_bases") """ if base not in Fields().Topological(): raise ValueError("base must be a topological field") @@ -108,7 +108,6 @@ def Connected(self): TESTS:: - sage: TestSuite(Manifolds(RR).Connected()).run() sage: Manifolds(RR).Connected.__module__ 'sage.categories.manifolds' """ @@ -130,32 +129,92 @@ def FiniteDimensional(self): TESTS:: sage: from sage.categories.manifolds import Manifolds - sage: C = Manifolds(RR).Connected().FiniteDimensional() - sage: TestSuite(C).run() sage: Manifolds(RR).Connected().FiniteDimensional.__module__ 'sage.categories.manifolds' """ return self._with_axiom('FiniteDimensional') @cached_method - def Real(self): + def Differentiable(self): """ - Return the subcategory of manifolds over `\RR` of ``self``. + Return the subcategory of the differentiable objects + of ``self``. EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real() - Category of real manifolds + sage: Manifolds(RR).Differentiable() + Category of differentiable manifolds over Real Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds(RR).Real()).run() - sage: Manifolds(RR).Real.__module__ + sage: TestSuite(Manifolds(RR).Differentiable()).run() + sage: Manifolds(RR).Differentiable.__module__ 'sage.categories.manifolds' """ - return self._with_axiom('Real') + return self._with_axiom('Differentiable') + + @cached_method + def Smooth(self): + """ + Return the subcategory of the smooth objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds(RR).Smooth() + Category of smooth manifolds + over Real Field with 53 bits of precision + + TESTS:: + + sage: TestSuite(Manifolds(RR).Smooth()).run() + sage: Manifolds(RR).Smooth.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Smooth') + + @cached_method + def Analytic(self): + """ + Return the subcategory of the analytic objects of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds(RR).Analytic() + Category of analytic manifolds + over Real Field with 53 bits of precision + + TESTS:: + + sage: TestSuite(Manifolds(RR).Analytic()).run() + sage: Manifolds(RR).Analytic.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('Analytic') + + @cached_method + def AlmostComplex(self): + """ + Return the subcategory of the almost complex objects + of ``self``. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds(RR).AlmostComplex() + Category of almost complex manifolds + over Real Field with 53 bits of precision + + TESTS:: + + sage: TestSuite(Manifolds(RR).AlmostComplex()).run() + sage: Manifolds(RR).AlmostComplex.__module__ + 'sage.categories.manifolds' + """ + return self._with_axiom('AlmostComplex') @cached_method def Complex(self): @@ -165,229 +224,128 @@ def Complex(self): EXAMPLES:: sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Complex() - Category of complex manifolds - over Real Field with 53 bits of precision + sage: Manifolds(CC).Complex() + Category of complex manifolds over + Complex Field with 53 bits of precision TESTS:: - sage: TestSuite(Manifolds(RR).Complex()).run() - sage: Manifolds(RR).Complex.__module__ + sage: TestSuite(Manifolds(CC).Complex()).run() + sage: Manifolds(CC).Complex.__module__ 'sage.categories.manifolds' """ - return self._with_axiom('Complex') + return ComplexManifolds(self.base())._with_axioms(self.axioms()) - class FiniteDimensional(CategoryWithAxiom_over_base_ring): - """ - Category of finite dimensional manifolds. + class Differentiable(CategoryWithAxiom_over_base_ring): """ + The category of differentiable manifolds. - class Connected(CategoryWithAxiom_over_base_ring): - """ - The category of connected manifolds. + A differentiable manifold is a manifold with a differentiable atlas. """ - class Real(CategoryWithAxiom_over_base_ring): + class Smooth(CategoryWithAxiom_over_base_ring): """ - The category of manifolds over `\RR`. + The category of smooth manifolds. + + A smooth manifold is a manifold with a smooth atlas. """ - class SubcategoryMethods: - @cached_method - def Complex(self): - r""" - Raise an error as a manifold over `\RR` is not a manifold - over `\CC`. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real().Complex() - Traceback (most recent call last): - ... - TypeError: a real manifold is not a complex manifold - """ - raise TypeError("a real manifold is not a complex manifold") - - @cached_method - def Differentiable(self): - """ - Return the subcategory of the differentiable objects - of ``self``. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real().Differentiable() - Category of differentiable real manifolds - over Real Field with 53 bits of precision - - TESTS:: - - sage: TestSuite(Manifolds(RR).Real().Differentiable()).run() - sage: Manifolds(RR).Real().Differentiable.__module__ - 'sage.categories.manifolds' - """ - return self._with_axiom('Differentiable') - - @cached_method - def Smooth(self): - """ - Return the subcategory of the smooth objects of ``self``. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real().Smooth() - Category of smooth real manifolds - over Real Field with 53 bits of precision - - TESTS:: - - sage: TestSuite(Manifolds(RR).Real().Smooth()).run() - sage: Manifolds(RR).Real().Smooth.__module__ - 'sage.categories.manifolds' - """ - return self._with_axiom('Smooth') - - @cached_method - def Analytic(self): - """ - Return the subcategory of the analytic objects of ``self``. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real().Analytic() - Category of analytic real manifolds - over Real Field with 53 bits of precision - - TESTS:: - - sage: TestSuite(Manifolds(RR).Real().Analytic()).run() - sage: Manifolds(RR).Real().Analytic.__module__ - 'sage.categories.manifolds' - """ - return self._with_axiom('Analytic') - - @cached_method - def AlmostComplex(self): - """ - Return the subcategory of the almost complex objects - of ``self``. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real().AlmostComplex() - Category of almost complex real manifolds - over Real Field with 53 bits of precision - - TESTS:: - - sage: TestSuite(Manifolds(RR).Real().AlmostComplex()).run() - sage: Manifolds(RR).Real().AlmostComplex.__module__ - 'sage.categories.manifolds' - """ - return self._with_axiom('AlmostComplex') - - class Differentiable(CategoryWithAxiom_over_base_ring): + def extra_super_categories(self): """ - The category of differentiable manifolds over `\RR`. + Return the extra super categories of ``self``. - A `d`-dimensional differentiable manifold is a manifold whose - underlying vector space is `\RR^d` and differentiable atlas. - """ + A smooth manifold is differentiable. + + EXAMPLES:: - class Smooth(CategoryWithAxiom_over_base_ring): + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds(RR).Smooth().super_categories() # indirect doctest + [Category of differentiable manifolds + over Real Field with 53 bits of precision] """ - The category of smooth manifolds over `\RR`. + return [Manifolds(self.base()).Differentiable()] + + class Analytic(CategoryWithAxiom_over_base_ring): + r""" + The category of complex manifolds. - A `d`-dimensional differentiable manifold is a manifold whose - underlying vector space is `\RR^d` and smooth atlas. + An analytic manifold is a manifold with an analytic atlas. + """ + def extra_super_categories(self): """ - def extra_super_categories(self): - """ - Return the extra super categories of ``self``. + Return the extra super categories of ``self``. - A smooth manifold is differentiable. + An analytic manifold is smooth. - EXAMPLES:: + EXAMPLES:: - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real().Smooth().super_categories() # indirect doctest - [Category of differentiable real manifolds - over Real Field with 53 bits of precision] - """ - return [Manifolds(self.base()).Real().Differentiable()] + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds(RR).Analytic().super_categories() # indirect doctest + [Category of smooth manifolds + over Real Field with 53 bits of precision] + """ + return [Manifolds(self.base()).Smooth()] - class Analytic(CategoryWithAxiom_over_base_ring): - r""" - The category of complex manifolds. + class AlmostComplex(CategoryWithAxiom_over_base_ring): + r""" + The category of almost complex manifolds. - A `d`-dimensional analytic manifold is a manifold whose underlying - vector space is `\RR^d` and an analytic atlas. + An *almost complex manifold* `M` is a manifold with a smooth tensor + field `J` of rank `(1, 1)` such that `J^2 = -1` when regarded as a + vector bundle isomorphism `J : TM \to TM` on the tangent bundle. + The tensor field `J` is called the *almost complex structure* of `M`. + """ + def extra_super_categories(self): """ - def extra_super_categories(self): - """ - Return the extra super categories of ``self``. - - An analytic manifold is smooth. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real().Analytic().super_categories() # indirect doctest - [Category of smooth real manifolds - over Real Field with 53 bits of precision] - """ - return [Manifolds(self.base()).Real().Smooth()] - - class AlmostComplex(CategoryWithAxiom_over_base_ring): - r""" - The category of almost complex manifolds. - - A `d`-dimensional almost complex manifold `M` is a manifold - whose underlying vector space is `\RR^d` with a smooth tensor - field `J` of rank `(1, 1)` such that `J^2 = -1` when regarded as a - vector bundle isomorphism `J : TM \to TM` on the tangent bundle. - The tensor field `J` is called the almost complex structure of `M`. + Return the extra super categories of ``self``. + + An almost complex manifold is smooth. + + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds(RR).AlmostComplex().super_categories() # indirect doctest + [Category of smooth manifolds + over Real Field with 53 bits of precision] """ - def extra_super_categories(self): - """ - Return the extra super categories of ``self``. + return [Manifolds(self.base()).Smooth()] + + class FiniteDimensional(CategoryWithAxiom_over_base_ring): + """ + Category of finite dimensional manifolds. - An analytic manifold is smooth. + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds(RR).FiniteDimensional() + sage: TestSuite(C).run(skip="_test_category_over_bases") + """ - EXAMPLES:: + class Connected(CategoryWithAxiom_over_base_ring): + """ + The category of connected manifolds. - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Real().Analytic().super_categories() # indirect doctest - [Category of smooth real manifolds - over Real Field with 53 bits of precision] - """ - return [Manifolds(self.base()).Real().Smooth()] + EXAMPLES:: - class Complex(CategoryWithAxiom_over_base_ring): - r""" - The category of complex manifolds. + sage: from sage.categories.manifolds import Manifolds + sage: C = Manifolds(RR).Connected() + sage: TestSuite(C).run(skip="_test_category_over_bases") + """ - A `d`-dimensional complex manifold is a manifold whose underlying - vector space is `\CC^d` and a holomorphic atlas. +class ComplexManifolds(Category_over_base_ring): + r""" + The category of complex manifolds. + + A `d`-dimensional complex manifold is a manifold whose underlying + vector space is `\CC^d` and has a holomorphic atlas. + """ + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: from sage.categories.manifolds import Manifolds + sage: Manifolds(RR).super_categories() + [Category of topological spaces] """ - class SubcategoryMethods: - @cached_method - def Real(self): - r""" - Raise an error as a manifold over `\RR` is not a manifold - over `\CC`. - - EXAMPLES:: - - sage: from sage.categories.manifolds import Manifolds - sage: Manifolds(RR).Complex().Real() - Traceback (most recent call last): - ... - TypeError: a complex manifold is not a real manifold - """ - raise TypeError("a complex manifold is not a real manifold") + return [Manifolds(self.base()).Analytic()] From b17c1c9be0d07acf40d4d293304d46c810608f98 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Thu, 15 Oct 2015 19:38:29 -0500 Subject: [PATCH 1513/1872] Updated the Nazarov reference to be abbreviated as Naz instead of N. --- src/sage/combinat/diagram_algebras.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 8a6930b63ce..4d570c180f2 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1969,11 +1969,11 @@ def _element_constructor_(self, set_partition): def jucys_murphy(self, j): r""" - Returns a generalized Jucys-Murphy elements for the Brauer algebra. These are outlined in [N]_. + Returns a generalized Jucys-Murphy elements for the Brauer algebra. These are outlined in [Naz]_. REFERENCES: - .. [N] Maxim Nazarov, Young's Orthogonal Form for Brauer's Centralizer + .. [Naz] Maxim Nazarov, Young's Orthogonal Form for Brauer's Centralizer Algebra. Journal of Algebra 182 (1996), 664--693. EXAMPLES: From 15aa5a132c33abfa833a6f5a8974bcf93b3776b0 Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Thu, 15 Oct 2015 19:40:21 -0500 Subject: [PATCH 1514/1872] Made docstring declarative. --- src/sage/combinat/diagram_algebras.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 4d570c180f2..e05983c8593 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1969,7 +1969,8 @@ def _element_constructor_(self, set_partition): def jucys_murphy(self, j): r""" - Returns a generalized Jucys-Murphy elements for the Brauer algebra. These are outlined in [Naz]_. + Return a generalized Jucys-Murphy elements for the Brauer algebra. + These are outlined in [Naz]_. REFERENCES: From e2a0c6ebae7d21727e776ff4d90e58c65f60abae Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 08:53:24 +0200 Subject: [PATCH 1515/1872] Trac #19083: minor language issues --- src/sage/rings/asymptotic/asymptotic_ring.py | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d6ee4e0faf1..3e4aee5a9dd 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -29,10 +29,10 @@ this module these summands are the following: - Exact terms `c\cdot g` with a coefficient `c` and an element `g` of - an growth group (:ref:`see below `). + a growth group (:ref:`see below `). - `O`-terms `O(g)` (see :wikipedia:`Big O notation `; - also called *Bachmann--Landau notation*) for growth group + also called *Bachmann--Landau notation*) for a growth group element `g` (:ref:`again see below `). See @@ -65,9 +65,9 @@ (this corresponds to an element of the growth group ``x^QQ * log(x)^ZZ * QQ^y * y^QQ``). -The order in all these examples induced by the magnitude of the +The order in all these examples is induced by the magnitude of the elements as `x`, `y`, or `z` (independently) tend to `\infty`. For -elements only using the variable `z` this means, `g_1 \leq g_2` if +elements only using the variable `z` this means that `g_1 \leq g_2` if .. MATH:: @@ -177,7 +177,7 @@ ----------------------- In this section we explain how to perform various arithmetical -calculations with the elements of the asymptotic rings constructed +operations with the elements of the asymptotic rings constructed above. @@ -697,7 +697,7 @@ def __nonzero__(self): def __eq__(self, other): r""" - Return if this asymptotic expansion is equal to ``other``. + Return whether this asymptotic expansion is equal to ``other``. INPUT: @@ -732,7 +732,7 @@ def __eq__(self, other): def __ne__(self, other): r""" - Return if this asymptotic expansion is not equal to ``other``. + Return whether this asymptotic expansion is not equal to ``other``. INPUT: @@ -765,7 +765,7 @@ def __ne__(self, other): def has_same_summands(self, other): r""" - Return if this asymptotic expansion and ``other`` have the + Return whether this asymptotic expansion and ``other`` have the same summands. INPUT: @@ -814,7 +814,7 @@ def has_same_summands(self, other): def _has_same_summands_(self, other): r""" - Return, if this :class:`AsymptoticExpansion` has the same + Return whether this :class:`AsymptoticExpansion` has the same summands as ``other``. INPUT: @@ -1440,13 +1440,13 @@ def log(self, base=None, precision=None): sage: log(R(0)) Traceback (most recent call last): ... - ArithmeticError: Cannot build log(0) in + ArithmeticError: Cannot compute log(0) in Asymptotic Ring over Rational Field. """ P = self.parent() if not self.summands: - raise ArithmeticError('Cannot build log(0) in %s.' % (self.parent(),)) + raise ArithmeticError('Cannot compute log(0) in %s.' % (self.parent(),)) elif len(self.summands) == 1: if self.is_one(): @@ -1493,7 +1493,7 @@ def log(self, base=None, precision=None): def is_little_o_of_one(self): r""" - Return if this expansion is of order `o(1)`. + Return whether this expansion is of order `o(1)`. INPUT: @@ -1641,7 +1641,7 @@ def exp(self, precision=None): .. NOTE:: The exponential function of this expansion can only be - computed exactly, if the respective growth element can be + computed exactly if the respective growth element can be constructed in the underlying growth group. ALGORITHM: @@ -1743,7 +1743,7 @@ class AsymptoticRing(Algebra, UniqueRepresentation): Asymptotic Ring over Rational Field Other growth groups are available. See :doc:`asymptotic_ring` for - a lot more examples. + more examples. Below there are some technical details. @@ -1815,8 +1815,8 @@ def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, sage: AR. = AsymptoticRing(growth_group='log(x)^ZZ', coefficient_ring=ZZ) Traceback (most recent call last): ... - ValueError: Growth Group log(x)^ZZ does not privide any generators - but name 'lx' given. + ValueError: Growth Group log(x)^ZZ does not provide any + generators but name 'lx' given. :: @@ -1886,7 +1886,7 @@ def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, def format_names(N): return ('s ' if len(N) != 1 else ' ') + ', '.join("'%s'" % n for n in N) if names and not strgens: - raise ValueError('%s does not privide any generators but name%s given.' % + raise ValueError('%s does not provide any generators but name%s given.' % (growth_group, format_names(names))) elif names is not None and len(names) == 1 and len(strgens) == 1: pass From ac9d4bce20e54cfcbdeb7208c6dc131c3703a26b Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 08:54:14 +0200 Subject: [PATCH 1516/1872] Trac #19083: ReSt errors --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 3e4aee5a9dd..9d613870eaa 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -236,6 +236,7 @@ z^(-1) + z^(-2) + z^(-3) + z^(-4) + z^(-5) + O(z^(-6)) or + :: sage: 1 / (z-1) + O(z^(-6)) @@ -1294,9 +1295,9 @@ def __pow__(self, exponent, precision=None): sage: _.parent() Asymptotic Ring over Symbolic Ring - :: + See :trac:`19110`:: - sage: O(x)^(-1) # see :trac:`19110` + sage: O(x)^(-1) Traceback (most recent call last): ... ZeroDivisionError: Cannot take O(x) to exponent -1. @@ -2074,6 +2075,8 @@ def _create_element_via_parent_(self, term, old_parent=None): An element. + EXAMPLES:: + sage: A = AsymptoticRing('z^ZZ', ZZ) sage: term = next(A.an_element().summands.elements_topological()) sage: A._create_element_via_parent_(term, A) From b6ac6c195ac0527dea5d260d5e0a9274c8f41fa6 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 08:54:45 +0200 Subject: [PATCH 1517/1872] Trac #19083: abbreviate link --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 9d613870eaa..dcb199fc0a2 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -556,7 +556,7 @@ class AsymptoticExpansion(CommutativeAlgebraElement): :doc:`growth_group`, :doc:`term_monoid`, - :mod:`sage.data_structures.mutable_poset`. + :mod:`~sage.data_structures.mutable_poset`. """ def __init__(self, parent, summands, simplify=True, convert=True): r""" From b85176ab4e7eb53ad4d25f3fd84d2ae60c044c7e Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 08:55:07 +0200 Subject: [PATCH 1518/1872] Trac #19083: break long lines --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index dcb199fc0a2..aff75454b97 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1593,7 +1593,8 @@ def rpow(self, base, precision=None): except (TypeError, ValueError) as e: from misc import combine_exceptions raise combine_exceptions( - ValueError('Cannot construct the power of %s to the exponent %s in %s.' % + ValueError('Cannot construct the power of %s to the ' + 'exponent %s in %s.' % (base, self, self.parent())), e) # then: expand expr_o @@ -1788,8 +1789,8 @@ class AsymptoticRing(Algebra, UniqueRepresentation): @staticmethod - def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, - category=None, default_prec=None): + def __classcall__(cls, growth_group=None, coefficient_ring=None, + names=None, category=None, default_prec=None): r""" Normalizes the input in order to ensure a unique representation of the parent. From 6b45b796ec07b16caf5afde9702ece3a598fcd1c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 08:55:21 +0200 Subject: [PATCH 1519/1872] Trac #19083: mark one doctest as indirect --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index aff75454b97..315ada30565 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1061,7 +1061,7 @@ def _rmul_(self, other): TESTS:: sage: A. = AsymptoticRing(growth_group='QQ^a * a^QQ * log(a)^QQ', coefficient_ring=ZZ) - sage: 2*a + sage: 2*a # indirect doctest 2*a """ if other.is_zero(): From 0481cda4e0fdefaccf4ebca4a652c386316f33d1 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 08:55:39 +0200 Subject: [PATCH 1520/1872] Trac #19083: simplify doctest --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 315ada30565..9f6f26d6185 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1562,7 +1562,7 @@ def rpow(self, base, precision=None): EXAMPLES:: - sage: A. = AsymptoticRing('x^ZZ * y^ZZ', QQ) + sage: A. = AsymptoticRing('x^ZZ', QQ) sage: (1/x).rpow('e', precision=5) 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + 1/24*x^(-4) + O(x^(-5)) """ From 58677872d6af9f390cfa9da3d24609298707cc9c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 08:56:03 +0200 Subject: [PATCH 1521/1872] Trac #19083: o(1) instead of O(1) for use of taylor series --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 9f6f26d6185..bb9cfbf6293 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1650,7 +1650,7 @@ def exp(self, precision=None): If the corresponding growth can be constructed, return the exact exponential function. Otherwise, if this term - is within `O(1)`, try to expand the series and truncate + is `o(1)`, try to expand the series and truncate according to the given precision. .. TODO:: From 2c60570eb1755791db1a82aa3e3ab70ddbb505c0 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 08:56:15 +0200 Subject: [PATCH 1522/1872] Trac #19083: additional doctest and explanation --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index bb9cfbf6293..abfae72f8ef 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1820,8 +1820,13 @@ def __classcall__(cls, growth_group=None, coefficient_ring=None, ValueError: Growth Group log(x)^ZZ does not provide any generators but name 'lx' given. - :: + The names of the generators have to agree with the names used in + the growth group except for univariate rings:: + sage: A. = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ); A + Asymptotic Ring over Integer Ring + sage: icecream + x sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ); A Asymptotic Ring over Integer Ring sage: A. = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ) From 91465db6ae525b442c9f75a0e3e3dddd48265f1c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 09:58:29 +0200 Subject: [PATCH 1523/1872] Trac #19094/#19083 comment 60, 7+18: rewrite and simplify _rpow_element_ --- src/sage/rings/asymptotic/growth_group.py | 15 +++++++-------- .../rings/asymptotic/growth_group_cartesian.py | 13 +++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index b86a249626b..ce5b16fca83 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -830,15 +830,11 @@ def _rpow_(self, base): raise ValueError('%s is not an allowed base for calculating the ' 'power to %s.' % (base, self)) - element = None + var = str(self) + try: element = self._rpow_element_(base) except ValueError: - pass - - var = str(self) - - if element is None: if base == 'e': from sage.rings.integer_ring import ZZ from misc import repr_op @@ -1281,9 +1277,12 @@ def _rpow_element_(self, base): sage: G = GrowthGroup('QQ^x') sage: x = G(raw_element=3) sage: x._rpow_element_(2) is None - True + Traceback (most recent call last): + ... + ValueError: Cannot compute 2 to the generic element 3^x. """ - pass + raise ValueError('Cannot compute %s to the generic element %s.' % + (base, self)) def factors(self): diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 06c8d01dab1..ac4c9f570f4 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1030,15 +1030,12 @@ def _rpow_element_(self, base): """ factors = self.factors() if len(factors) != 1: - return + raise ValueError # calling method has to deal with it... from growth_group import MonomialGrowthGroup - for factor in factors: - if not isinstance(factor.parent(), MonomialGrowthGroup): - continue - try: - return factor._rpow_element_(base) - except ValueError: - pass + factor = factors[0] + if not isinstance(factor.parent(), MonomialGrowthGroup): + raise ValueError # calling method has to deal with it... + return factor._rpow_element_(base) def exp(self): From a2ab0f2c0b029128a2887a18243bb68c0a092968 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 09:59:03 +0200 Subject: [PATCH 1524/1872] Trac #19094/#19083 comment 60, 7: rewrite docstrings of _rpow_element_ --- src/sage/rings/asymptotic/growth_group.py | 17 +++++++++++++---- .../rings/asymptotic/growth_group_cartesian.py | 13 +++++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ce5b16fca83..3575fdfa583 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1261,7 +1261,7 @@ def _log_factor_(self, base=None): def _rpow_element_(self, base): r""" Return an element which is the power of ``base`` to this - element; it lives (in contrast to :meth:`rpow`) in its own group. + element. INPUT: @@ -1269,7 +1269,7 @@ def _rpow_element_(self, base): OUTPUT: - A growth element or ``None``. + Nothing since a ``ValueError`` is raised in this generic method. TESTS:: @@ -2485,7 +2485,7 @@ def _log_factor_(self, base=None): def _rpow_element_(self, base): r""" Return an element which is the power of ``base`` to this - element; it lives (in contrast to :meth:`rpow`) in its own group. + element. INPUT: @@ -2493,7 +2493,16 @@ def _rpow_element_(self, base): OUTPUT: - A growth element or ``None``. + A growth element. + + .. NOTE:: + + The parent of the result can be different to the parent + of this element. + + A ``ValueError`` is raised if the calculation is not possible + within this method. (Then the calling method should take care + of the calculation.) TESTS:: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index ac4c9f570f4..ff2d2608a8d 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1008,7 +1008,7 @@ def try_create_growth(g): def _rpow_element_(self, base): r""" Return an element which is the power of ``base`` to this - element; it lives (in contrast to :meth:`rpow`) in its own group. + element. INPUT: @@ -1016,7 +1016,16 @@ def _rpow_element_(self, base): OUTPUT: - A growth element or ``None``. + A growth element. + + .. NOTE:: + + The parent of the result can be different to the parent + of this element. + + A ``ValueError`` is raised if the calculation is not possible + within this method. (Then the calling method should take care + of the calculation.) TESTS:: From d4749acd1b8ffe357ec949c30a2614e8a728a065 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 10:06:21 +0200 Subject: [PATCH 1525/1872] Trac #19094/#19083 comment 60, 8: rewrite description of _create_element_via_parent_ methods --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- src/sage/rings/asymptotic/growth_group.py | 3 ++- src/sage/rings/asymptotic/growth_group_cartesian.py | 3 ++- src/sage/rings/asymptotic/term_monoid.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 47abcaccf17..943588d20c8 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2050,7 +2050,7 @@ def _create_empty_summands_(): def _create_element_via_parent_(self, term, old_parent=None): r""" - Create an element with a possibly other parent. + Create an element whose parent is chosen according to the input. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 3575fdfa583..3be852ae450 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1628,7 +1628,8 @@ def some_elements(self): def _create_element_via_parent_(self, raw_element): r""" - Create an element with a possibly other parent. + Create an element whose parent is chosen according to the input + ``raw_element``. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index ff2d2608a8d..7d9e7b38f8a 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -344,7 +344,8 @@ def some_elements(self): def _create_element_via_parent_(self, element): r""" - Create an element with a possibly other parent. + Create an element whose parent is chosen according to the input + ``element``. INPUT: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 567d0757d99..898a986e9f0 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1633,7 +1633,7 @@ def _create_element_(self, growth, coefficient): def _create_element_via_parent_(self, growth, coefficient): r""" - Create an element with a possibly other parent. + Create an element whose parent is chosen according to the input. INPUT: From 73fcd56d963a1cb32f1399ac9e94e733a0cb8541 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 16 Oct 2015 10:07:10 +0200 Subject: [PATCH 1526/1872] Remove comparison boilerplate - part 5 --- src/sage/rings/fraction_field_FpT.pyx | 20 +++++------ src/sage/rings/fraction_field_element.pyx | 20 +++++------ src/sage/rings/padics/CA_template.pxi | 16 --------- src/sage/rings/padics/CR_template.pxi | 16 --------- src/sage/rings/padics/FM_template.pxi | 16 --------- src/sage/rings/padics/morphism.pyx | 19 +++++----- .../rings/padics/padic_ZZ_pX_FM_element.pyx | 19 ---------- .../rings/padics/padic_generic_element.pyx | 36 +++++++++++++++++++ .../rings/polynomial/laurent_polynomial.pyx | 30 ++++------------ .../multi_polynomial_libsingular.pyx | 9 +---- src/sage/rings/polynomial/pbori.pyx | 9 +---- src/sage/rings/polynomial/plural.pyx | 23 +----------- .../rings/polynomial/polynomial_element.pyx | 12 ------- .../rings/polynomial/polynomial_template.pxi | 10 +----- src/sage/rings/real_mpfr.pyx | 28 +++------------ .../rings/semirings/tropical_semiring.pyx | 31 +++------------- 16 files changed, 80 insertions(+), 234 deletions(-) diff --git a/src/sage/rings/fraction_field_FpT.pyx b/src/sage/rings/fraction_field_FpT.pyx index 4898d3c5760..ee3c10cf786 100644 --- a/src/sage/rings/fraction_field_FpT.pyx +++ b/src/sage/rings/fraction_field_FpT.pyx @@ -341,18 +341,6 @@ cdef class FpTElement(RingElement): else: return "\\frac{%s}{%s}" % (self.numer()._latex_(), self.denom()._latex_()) - def __richcmp__(left, right, int op): - """ - EXAMPLES:: - - sage: K = Frac(GF(5)['t']); t = K.gen() - sage: t == 1 - False - sage: t + 1 < t^2 - True - """ - return (left)._richcmp(right, op) - cpdef int _cmp_(self, Element other) except -2: """ Compares this with another element. The ordering is arbitrary, @@ -387,6 +375,14 @@ cdef class FpTElement(RingElement): True sage: b < 1/a False + + :: + + sage: K = Frac(GF(5)['t']); t = K.gen() + sage: t == 1 + False + sage: t + 1 < t^2 + True """ # They are normalized. cdef int j = sage_cmp_nmod_poly_t(self._numer, (other)._numer) diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index 4796600bbdf..86d12adfb26 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -841,18 +841,6 @@ cdef class FractionFieldElement(FieldElement): """ return float(self.__numerator) / float(self.__denominator) - def __richcmp__(left, right, int op): - """ - EXAMPLES:: - - sage: K. = Frac(ZZ['x,y']) - sage: x > y - True - sage: 1 > y - False - """ - return (left)._richcmp(right, op) - cpdef int _cmp_(self, Element other) except -2: """ EXAMPLES:: @@ -864,6 +852,14 @@ cdef class FractionFieldElement(FieldElement): True sage: t == t/5 False + + :: + + sage: K. = Frac(ZZ['x,y']) + sage: x > y + True + sage: 1 > y + False """ return cmp(self.__numerator * \ (other).__denominator, diff --git a/src/sage/rings/padics/CA_template.pxi b/src/sage/rings/padics/CA_template.pxi index 9ca4a54a8c5..1f56e90b3af 100644 --- a/src/sage/rings/padics/CA_template.pxi +++ b/src/sage/rings/padics/CA_template.pxi @@ -160,22 +160,6 @@ cdef class CAElement(pAdicTemplateElement): """ return unpickle_cae_v2, (self.__class__, self.parent(), cpickle(self.value, self.prime_pow), self.absprec) - def __richcmp__(self, right, int op): - """ - Compare this element to ``right`` using the comparison operator ``op``. - - TESTS:: - - sage: R = ZpCA(5) - sage: a = R(17) - sage: b = R(21) - sage: a == b - False - sage: a < b - True - """ - return (self)._richcmp(right, op) - cpdef ModuleElement _neg_(self): """ Return the additive inverse of this element. diff --git a/src/sage/rings/padics/CR_template.pxi b/src/sage/rings/padics/CR_template.pxi index 45c70d9ccec..41f63a68b0e 100644 --- a/src/sage/rings/padics/CR_template.pxi +++ b/src/sage/rings/padics/CR_template.pxi @@ -270,22 +270,6 @@ cdef class CRElement(pAdicTemplateElement): """ return unpickle_cre_v2, (self.__class__, self.parent(), cpickle(self.unit, self.prime_pow), self.ordp, self.relprec) - def __richcmp__(self, right, int op): - """ - Compare this element to ``right`` using the comparison operator ``op``. - - TESTS:: - - sage: R = Zp(5) - sage: a = R(17) - sage: b = R(21) - sage: a == b - False - sage: a < b # indirect doctest - True - """ - return (self)._richcmp(right, op) - cpdef ModuleElement _neg_(self): """ Return the additive inverse of this element. diff --git a/src/sage/rings/padics/FM_template.pxi b/src/sage/rings/padics/FM_template.pxi index e9c21608613..f7c446439bb 100644 --- a/src/sage/rings/padics/FM_template.pxi +++ b/src/sage/rings/padics/FM_template.pxi @@ -155,22 +155,6 @@ cdef class FMElement(pAdicTemplateElement): """ return unpickle_fme_v2, (self.__class__, self.parent(), cpickle(self.value, self.prime_pow)) - def __richcmp__(self, right, int op): - """ - Compare this element to ``right`` using the comparison operator ``op``. - - TESTS:: - - sage: R = ZpFM(5) - sage: a = R(17) - sage: b = R(21) - sage: a == b - False - sage: a < b - True - """ - return (self)._richcmp(right, op) - cpdef ModuleElement _neg_(self): r""" Return the additive inverse of this element. diff --git a/src/sage/rings/padics/morphism.pyx b/src/sage/rings/padics/morphism.pyx index 49bb5fb5ff1..20c6a31a720 100644 --- a/src/sage/rings/padics/morphism.pyx +++ b/src/sage/rings/padics/morphism.pyx @@ -1,12 +1,16 @@ -"Frobenius endomorphisms on padic fields" +""" +Frobenius endomorphisms on p-adic fields +""" -############################################################################# -# Copyright (C) 2013 Xavier Caruso -# -# Distributed under the terms of the GNU General Public License (GPL) +#***************************************************************************** +# Copyright (C) 2013 Xavier Caruso # +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. # http://www.gnu.org/licenses/ -#**************************************************************************** +#***************************************************************************** from sage.rings.integer cimport Integer from sage.rings.infinity import Infinity @@ -288,9 +292,6 @@ cdef class FrobeniusEndomorphism_padics(RingHomomorphism): codomain = self.codomain() return hash((domain,codomain,('Frob',self._power))) - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - 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 377f2f6713b..317b69f56dc 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx @@ -445,25 +445,6 @@ cdef class pAdicZZpXFMElement(pAdicZZpXElement): ans.prime_pow = self.prime_pow return ans - def __richcmp__(left, right, op): - """ - Compares ``left`` and ``right`` under the operation ``op``. - - 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: w == 1 # indirect doctest - False - sage: y = 1 + w - sage: z = 1 + w + w^27 - sage: y == z - True - """ - return (left)._richcmp(right, op) - 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.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 7d9fd5dacd4..1a334b28f17 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -76,6 +76,42 @@ cdef class pAdicGenericElement(LocalGenericElement): 3 + O(19^5) sage: a < b True + + :: + + sage: R = Zp(5); a = R(5, 6); b = R(5 + 5^6, 8) + sage: a == b #indirect doctest + True + + :: + + sage: R = Zp(5) + sage: a = R(17) + sage: b = R(21) + sage: a == b + False + sage: a < b + True + + :: + + sage: R = ZpCA(5) + sage: a = R(17) + sage: b = R(21) + sage: a == b + False + sage: a < b + True + + :: + + sage: R = ZpFM(5) + sage: a = R(17) + sage: b = R(21) + sage: a == b + False + sage: a < b + True """ m = min(left.precision_absolute(), right.precision_absolute()) x_ordp = left.valuation() diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 0ef044296ef..536fb84a60d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -844,30 +844,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial_generic): rl = LaurentPolynomial_univariate(self._parent, r, 0) return (ql, rl) - def __richcmp__(left, right, int op): - """ - Return the rich comparison of ``left`` and ``right`` defined by ``op``. - - EXAMPLES:: - - sage: R. = LaurentPolynomialRing(QQ) - sage: f = x^(-1) + 1 + x - sage: g = x^(-1) + 2 - sage: f == g - False - sage: f != g - True - sage: f < g - True - sage: f <= g - True - sage: f > g - False - sage: f >= g - False - """ - return (left)._richcmp(right, op) - cpdef int _cmp_(self, Element right_r) except -2: r""" Comparison of ``self`` and ``right_r``. @@ -886,10 +862,16 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial_generic): sage: g = x^(-1) + 2 sage: f == g False + sage: f != g + True sage: f < g True + sage: f <= g + True sage: f > g False + sage: f >= g + False :: diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index e50037ea73a..8c31d26678d 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2128,10 +2128,6 @@ cdef class MPolynomial_libsingular(sage.rings.polynomial.multi_polynomial.MPolyn sage_res = res_parent(sage_res) return sage_res - # you may have to replicate this boilerplate code in derived classes if you override - # __richcmp__. The python documentation at http://docs.python.org/api/type-structs.html - # explains how __richcmp__, __hash__, and __cmp__ are tied together. - def __hash__(self): """ This hash incorporates the variable name in an effort to @@ -2155,7 +2151,7 @@ cdef class MPolynomial_libsingular(sage.rings.polynomial.multi_polynomial.MPolyn """ return self._hash_c() - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, Element right) except -2: """ Compare left and right and return -1, 0, and 1 for <,==, and > respectively. @@ -2207,9 +2203,6 @@ cdef class MPolynomial_libsingular(sage.rings.polynomial.multi_polynomial.MPolyn sage: (66*x^2 + 23) > (66*x^2 + 2) True """ - return (left)._richcmp(right, op) - - 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/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index e789f33ce02..a87a589da69 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -2200,9 +2200,6 @@ cdef class BooleanMonomial(MonoidElement): self._ring = parent._ring self._pbmonom = PBMonom_Constructor((self._ring)._pbring) - def __dealloc__(self): - pass # destruction by C++ object's destructor - def __reduce__(self): """ Pickling @@ -2219,7 +2216,7 @@ cdef class BooleanMonomial(MonoidElement): gens = self._parent.gens() return self._parent, (tuple([gens.index(x) for x in self.variables()]),) - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, Element right) except -2: """ Compare BooleanMonomial objects. @@ -2243,10 +2240,6 @@ cdef class BooleanMonomial(MonoidElement): sage: M(x) >= M(x) True """ - # boilerplate code from sage.structure.parent - return (left)._richcmp(right, op) - - cpdef int _cmp_(left, Element right) except -2: cdef int res res = left._pbmonom.compare((right)._pbmonom) return res diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 56a572dc4fb..650918aa013 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -1385,9 +1385,6 @@ cdef class NCPolynomial_plural(RingElement): """ return unpickle_NCPolynomial_plural, (self._parent, self.dict()) - # you may have to replicate this boilerplate code in derived classes if you override - # __richcmp__. The python documentation at http://docs.python.org/api/type-structs.html - # explains how __richcmp__, __hash__, and __cmp__ are tied together. def __hash__(self): """ This hash incorporates the variable name in an effort to @@ -1411,7 +1408,7 @@ cdef class NCPolynomial_plural(RingElement): """ return self._hash_c() - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, Element right) except -2: """ Compare left and right and return -1, 0, and 1 for <,==, and > respectively. @@ -1431,9 +1428,6 @@ cdef class NCPolynomial_plural(RingElement): sage: y^2 > x False -## sage: (2/3*x^2 + 1/2*y + 3) > (2/3*x^2 + 1/4*y + 10) -# True - TESTS:: sage: A. = FreeAlgebra(QQ, 3) @@ -1458,22 +1452,7 @@ cdef class NCPolynomial_plural(RingElement): sage: (x+1) > x True - -# sage: f = 3/4*x^2*y + 1/2*x + 2/7 -# sage: f > f -# False -# sage: f < f -# False -# sage: f == f -# True - -# sage: P. = PolynomialRing(GF(127), order='degrevlex') -# sage: (66*x^2 + 23) > (66*x^2 + 2) -# True """ - return (left)._richcmp(right, op) - - 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 ebe25afc471..c3dfa3c9b80 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -924,9 +924,6 @@ cdef class Polynomial(CommutativeAlgebraElement): if c: return c return 0 - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - def __nonzero__(self): """ EXAMPLES:: @@ -971,9 +968,6 @@ cdef class Polynomial(CommutativeAlgebraElement): """ return (self.parent(), tuple(self)) - # you may have to replicate this boilerplate code in derived classes if you override - # __richcmp__. The python documentation at http://docs.python.org/api/type-structs.html - # explains how __richcmp__, __hash__, and __cmp__ are tied together. def __hash__(self): return self._hash_c() @@ -7932,15 +7926,9 @@ cdef class Polynomial_generic_dense(Polynomial): del x[n] n -= 1 - # you may have to replicate this boilerplate code in derived classes if you override - # __richcmp__. The python documentation at http://docs.python.org/api/type-structs.html - # explains how __richcmp__, __hash__, and __cmp__ are tied together. def __hash__(self): return self._hash_c() - def __richcmp__(left, right, int op): - return (left)._richcmp(right, op) - def __getitem__(self, n): """ EXAMPLES:: diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index d2aee68f334..57f4550b27d 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -529,7 +529,7 @@ cdef class Polynomial_template(Polynomial): """ return not celement_is_zero(&self.x, (self)._cparent) - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, Element right) except -2: """ EXAMPLE:: @@ -541,14 +541,6 @@ cdef class Polynomial_template(Polynomial): sage: x > 1 True """ - return (left)._richcmp(right, op) - - cpdef int _cmp_(left, Element right) except -2: - """ - EXAMPLE:: - - sage: P. = GF(2)[] - """ return celement_cmp(&(left).x, &(right).x, (left)._cparent) def __hash__(self): diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index ac9e423689f..8e8248b4d1a 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -3764,10 +3764,11 @@ cdef class RealNumber(sage.structure.element.RingElement): """ return mpfr_sgn(self.value) != 0 - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, Element right) except -2: """ - Return the Cython rich comparison operator (see the Cython - documentation for details). + Return ``-1`` if exactly one of the numbers is ``NaN``. Return ``-1`` + if ``left`` is less than ``right``, ``0`` if ``left`` and ``right`` + are equal, and ``1`` if ``left`` is greater than ``right``. EXAMPLES:: @@ -3797,27 +3798,6 @@ cdef class RealNumber(sage.structure.element.RingElement): False sage: RR('1')>=RR('1') True - """ - return (left)._richcmp(right, op) - - 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`` - are equal, and ``1`` if ``left`` is greater than ``right``. - - EXAMPLES:: - - sage: RR('1')<=RR('1') - True - sage: RR('1')RR('1') - False - sage: RR('1')>=RR('1') - True - sage: RR('nan')==R('nan') - False sage: RR('inf')==RR('inf') True sage: RR('inf')==RR('-inf') diff --git a/src/sage/rings/semirings/tropical_semiring.pyx b/src/sage/rings/semirings/tropical_semiring.pyx index cc4d1104ab8..fa06154e1e6 100644 --- a/src/sage/rings/semirings/tropical_semiring.pyx +++ b/src/sage/rings/semirings/tropical_semiring.pyx @@ -134,10 +134,11 @@ cdef class TropicalSemiringElement(RingElement): return hash(self._val) # Comparisons - - def __richcmp__(left, right, int op): + cpdef int _cmp_(left, Element right) except -2: """ - Rich comparisons. + Return ``-1`` if ``left`` is less than ``right``, ``0`` if + ``left`` and ``right`` are equal, and ``1`` if ``left`` is + greater than ``right``. EXAMPLES:: @@ -170,30 +171,6 @@ cdef class TropicalSemiringElement(RingElement): False sage: T.infinity() >= T.infinity() True - """ - return (left)._richcmp(right, op) - - 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 - greater than ``right``. - - EXAMPLES:: - - sage: T = TropicalSemiring(QQ) - sage: T(2) == T(2) - True - sage: T(2) != T(4) - True - sage: T(2) < T(4) - True - sage: T(2) > T(4) - False - sage: T.infinity() == T.infinity() - True - sage: T(4) <= T.infinity() - True Using the `\max` definition:: From 20a89c68496e57f854e6f531f7a5879f45233859 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 10:08:18 +0200 Subject: [PATCH 1527/1872] Trac #19094/#19083 comment 60, 9: remove "monomial" from GenericGrowthGroup.gens --- src/sage/rings/asymptotic/growth_group.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 3be852ae450..18cf84871fe 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1987,8 +1987,7 @@ def gens_monomial(self): def gens(self): r""" - Return a tuple of all generators of this monomial growth - group. + Return a tuple of all generators of this growth group. INPUT: @@ -1996,8 +1995,7 @@ def gens(self): OUTPUT: - A tuple whose entries are instances of - :class:`MonomialGrowthElement`. + A tuple whose entries are growth elements. EXAMPLES:: From 5c2695b47112e81f96dc94a24b55be204fd9163f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 10:33:36 +0200 Subject: [PATCH 1528/1872] Trac #19094/#19083 comment 60, 11: check base in a branch in _log_factor_ --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 18cf84871fe..c4f93081df6 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2471,7 +2471,7 @@ def _log_factor_(self, base=None): base is not None and b == str(base): return ((e, coefficient),) - if var.startswith('exp('): + if base is None and var.startswith('exp('): assert(var[-1] == ')') return ((var[4:-1], coefficient),) From 8692577df65d75d8620994a640fd30cd1bf959f7 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 20 Aug 2015 16:26:59 +0200 Subject: [PATCH 1529/1872] libs/arb: pxd bindings for acb and acb_hypergeom --- src/sage/libs/arb/acb.pxd | 142 +++++++++++++++++++++++++++++- src/sage/libs/arb/acb_hypgeom.pxd | 61 +++++++++++++ 2 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 src/sage/libs/arb/acb_hypgeom.pxd diff --git a/src/sage/libs/arb/acb.pxd b/src/sage/libs/arb/acb.pxd index 61336196ee3..0c6ac913efb 100644 --- a/src/sage/libs/arb/acb.pxd +++ b/src/sage/libs/arb/acb.pxd @@ -1,26 +1,166 @@ +from sage.libs.arb.arf cimport arf_t from sage.libs.arb.arb cimport arb_t, arb_struct +from sage.libs.arb.mag cimport mag_t +from sage.libs.flint.types cimport fmpz_t, fmpq_t cdef extern from "acb.h": ctypedef struct acb_struct: arb_struct real arb_struct imag ctypedef acb_struct[1] acb_t + ctypedef acb_struct *acb_ptr + ctypedef const acb_struct *acb_srcptr + + arb_t acb_realref(acb_t x) + arb_t acb_imagref(acb_t x) void acb_init(acb_t x) void acb_clear(acb_t x) + acb_ptr _acb_vec_init(long n) + void _acb_vec_clear(acb_ptr v, long n) bint acb_is_zero(const acb_t z) + bint acb_is_one(const acb_t z) + bint acb_is_finite(const acb_t z) bint acb_is_exact(const acb_t z) + bint acb_is_int(const acb_t z) + void acb_zero(acb_t z) + void acb_one(acb_t z) + void acb_onei(acb_t z) void acb_set(acb_t z, const acb_t x) - void acb_set_ui(acb_t z, unsigned long c) + void acb_set_ui(acb_t z, long x) + void acb_set_si(acb_t z, long x) + void acb_set_fmpz(acb_t z, const fmpz_t x) + void acb_set_arb(acb_t z, const arb_t c) + void acb_set_fmpq(acb_t z, const fmpq_t x, long prec) + void acb_set_round(acb_t z, const acb_t x, long prec) + void acb_set_round_fmpz(acb_t z, const fmpz_t x, long prec) + void acb_set_round_arb(acb_t z, const arb_t x, long prec) + void acb_swap(acb_t z, acb_t x) + + void acb_print(const acb_t x) + void acb_printd(const acb_t z, long digits) + + # void acb_randtest(acb_t z, flint_rand_t state, long prec, long mag_bits) + # void acb_randtest_special(acb_t z, flint_rand_t state, long prec, long mag_bits) + # void acb_randtest_precise(acb_t z, flint_rand_t state, long prec, long mag_bits) + # void acb_randtest_param(acb_t z, flint_rand_t state, long prec, long mag_bits) bint acb_equal(const acb_t x, const acb_t y) + bint acb_eq(const acb_t x, const acb_t y) + bint acb_ne(const acb_t x, const acb_t y) bint acb_overlaps(const acb_t x, const acb_t y) + void acb_get_abs_ubound_arf(arf_t u, const acb_t z, long prec) + void acb_get_abs_lbound_arf(arf_t u, const acb_t z, long prec) + void acb_get_rad_ubound_arf(arf_t u, const acb_t z, long prec) + void acb_get_mag(mag_t u, const acb_t x) + void acb_get_mag_lower(mag_t u, const acb_t x) + bint acb_contains_fmpq(const acb_t x, const fmpq_t y) + bint acb_contains_fmpz(const acb_t x, const fmpz_t y) + bint acb_contains(const acb_t x, const acb_t y) + bint acb_contains_zero(const acb_t x) + long acb_rel_error_bits(const acb_t x) + long acb_rel_accuracy_bits(const acb_t x) + long acb_bits(const acb_t x) + void acb_indeterminate(acb_t x) + void acb_trim(acb_t y, const acb_t x) + bint acb_is_real(const acb_t x) + bint acb_get_unique_fmpz(fmpz_t z, const acb_t x) + + void acb_arg(arb_t r, const acb_t z, long prec) + void acb_abs(arb_t r, const acb_t z, long prec) + void acb_neg(acb_t z, const acb_t x) + void acb_conj(acb_t z, const acb_t x) + void acb_add_ui(acb_t z, const acb_t x, unsigned long y, long prec) + void acb_add_fmpz(acb_t z, const acb_t x, const fmpz_t y, long prec) + void acb_add_arb(acb_t z, const acb_t x, const arb_t y, long prec) void acb_add(acb_t z, const acb_t x, const acb_t y, long prec) + void acb_sub_ui(acb_t z, const acb_t x, unsigned long y, long prec) + void acb_sub_fmpz(acb_t z, const acb_t x, const fmpz_t y, long prec) + void acb_sub_arb(acb_t z, const acb_t x, const arb_t y, long prec) void acb_sub(acb_t z, const acb_t x, const acb_t y, long prec) + void acb_mul_onei(acb_t z, const acb_t x) + void acb_div_onei(acb_t z, const acb_t x) + void acb_mul_ui(acb_t z, const acb_t x, unsigned long y, long prec) + void acb_mul_si(acb_t z, const acb_t x, long y, long prec) + void acb_mul_fmpz(acb_t z, const acb_t x, const fmpz_t y, long prec) + void acb_mul_arb(acb_t z, const acb_t x, const arb_t y, long prec) void acb_mul(acb_t z, const acb_t x, const acb_t y, long prec) + void acb_mul_2exp_si(acb_t z, const acb_t x, long e) + void acb_mul_2exp_fmpz(acb_t z, const acb_t x, const fmpz_t e) + void acb_cube(acb_t z, const acb_t x, long prec) + void acb_addmul(acb_t z, const acb_t x, const acb_t y, long prec) + void acb_addmul_ui(acb_t z, const acb_t x, unsigned long y, long prec) + void acb_addmul_si(acb_t z, const acb_t x, long y, long prec) + void acb_addmul_fmpz(acb_t z, const acb_t x, const fmpz_t y, long prec) + void acb_addmul_arb(acb_t z, const acb_t x, const arb_t y, long prec) + void acb_submul(acb_t z, const acb_t x, const acb_t y, long prec) + void acb_submul_ui(acb_t z, const acb_t x, unsigned long y, long prec) + void acb_submul_si(acb_t z, const acb_t x, long y, long prec) + void acb_submul_fmpz(acb_t z, const acb_t x, const fmpz_t y, long prec) + void acb_submul_arb(acb_t z, const acb_t x, const arb_t y, long prec) + void acb_inv(acb_t z, const acb_t x, long prec) + void acb_div_ui(acb_t z, const acb_t x, unsigned long y, long prec) + void acb_div_si(acb_t z, const acb_t x, long y, long prec) + void acb_div_fmpz(acb_t z, const acb_t x, const fmpz_t y, long prec) void acb_div(acb_t z, const acb_t x, const acb_t y, long prec) + void acb_const_pi(acb_t y, long prec) + + void acb_sqrt(acb_t r, const acb_t z, long prec) + void acb_rsqrt(acb_t r, const acb_t z, long prec) + void acb_pow_fmpz(acb_t y, const acb_t b, const fmpz_t e, long prec) + void acb_pow_ui(acb_t y, const acb_t b, unsigned long e, long prec) + void acb_pow_si(acb_t y, const acb_t b, long e, long prec) + void acb_pow_arb(acb_t z, const acb_t x, const arb_t y, long prec) void acb_pow(acb_t z, const acb_t x, const acb_t y, long prec) + + void acb_exp(acb_t y, const acb_t z, long prec) + void acb_exp_pi_i(acb_t y, const acb_t z, long prec) + void acb_exp_invexp(acb_t s, acb_t t, const acb_t z, long prec) + void acb_log(acb_t y, const acb_t z, long prec) + void acb_log1p(acb_t z, const acb_t x, long prec) + + void acb_sin(acb_t s, const acb_t z, long prec) + void acb_cos(acb_t c, const acb_t z, long prec) + void acb_sin_cos(arb_t s, arb_t c, const acb_t z, long prec) + void acb_tan(acb_t s, const acb_t z, long prec) + void acb_cot(acb_t s, const acb_t z, long prec) + void acb_sin_pi(acb_t s, const acb_t z, long prec) + void acb_cos_pi(acb_t s, const acb_t z, long prec) + void acb_sin_cos_pi(acb_t s, acb_t c, const acb_t z, long prec) + void acb_tan_pi(acb_t s, const acb_t z, long prec) + void acb_cot_pi(acb_t s, const acb_t z, long prec) + + void acb_atan(acb_t s, const acb_t z, long prec) + + void acb_sinh(acb_t s, const acb_t z, long prec) + void acb_cosh(acb_t c, const acb_t z, long prec) + void acb_sinh_cosh(acb_t s, acb_t c, const acb_t z, long prec) + void acb_tanh(acb_t s, const acb_t z, long prec) + void acb_coth(acb_t s, const acb_t z, long prec) + + void acb_rising_ui_bs(acb_t z, const acb_t x, unsigned long n, long prec) + void acb_rising_ui_rs(acb_t z, const acb_t x, unsigned long n, unsigned long step, long prec) + void acb_rising_ui_rec(acb_t z, const acb_t x, unsigned long n, long prec) + void acb_rising_ui(acb_t z, const acb_t x, unsigned long n, long prec) + + void acb_gamma(acb_t y, const acb_t x, long prec) + void acb_rgamma(acb_t y, const acb_t x, long prec) + void acb_lgamma(acb_t y, const acb_t x, long prec) + void acb_digamma(acb_t y, const acb_t x, long prec) + void acb_log_sin_pi(acb_t res, const acb_t z, long prec) + void acb_polygamma(acb_t z, const acb_t s, const acb_t z, long prec) + void acb_barnes_g(acb_t res, const acb_t z, long prec) + void acb_log_barnes_g(acb_t res, const acb_t z, long prec) + + void acb_zeta(acb_t z, const acb_t s, long prec) + void acb_hurwitz_zeta(acb_t z, const acb_t s, const acb_t a, long prec) + + void acb_polylog(acb_t w, const acb_t s, const acb_t z, long prec) + void acb_polylog_si(acb_t w, long s, const acb_t z, long prec) + + void acb_agm1(acb_t m, const acb_t z, long prec) + void acb_agm1_cpx(acb_ptr m, const acb_t z, long len, long prec) diff --git a/src/sage/libs/arb/acb_hypgeom.pxd b/src/sage/libs/arb/acb_hypgeom.pxd new file mode 100644 index 00000000000..0b3935c5851 --- /dev/null +++ b/src/sage/libs/arb/acb_hypgeom.pxd @@ -0,0 +1,61 @@ +from sage.libs.arb.acb cimport acb_t, acb_srcptr +from sage.libs.arb.mag cimport mag_t + +cdef extern from "acb_hypgeom.h": + void acb_hypgeom_pfq_bound_factor(mag_t C, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, unsigned long n) + long acb_hypgeom_pfq_choose_n(acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, long prec) + void acb_hypgeom_pfq_sum_forward(acb_t s, acb_t t, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, long n, long prec) + void acb_hypgeom_pfq_sum_rs(acb_t s, acb_t t, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, long n, long prec) + void acb_hypgeom_pfq_sum_bs(acb_t s, acb_t t, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, long n, long prec) + void acb_hypgeom_pfq_sum_fme(acb_t s, acb_t t, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, long n, long prec) + void acb_hypgeom_pfq_sum(acb_t s, acb_t t, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, long n, long prec) + void acb_hypgeom_pfq_sum_bs_invz(acb_t s, acb_t t, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t w, long n, long prec) + void acb_hypgeom_pfq_sum_invz(acb_t s, acb_t t, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, const acb_t w, long n, long prec) + void acb_hypgeom_pfq_direct(acb_t res, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, long n, long prec) + # void acb_hypgeom_pfq_series_direct(acb_poly_t res, const acb_poly_struct * a, long p, const acb_poly_struct * b, long q, const acb_poly_t z, int regularized, long n, long len, long prec) + void acb_hypgeom_u_asymp(acb_t res, const acb_t a, const acb_t b, const acb_t z, long n, long prec) + int acb_hypgeom_u_use_asymp(const acb_t z, long prec) + # void acb_hypgeom_u_1f1_series(acb_poly_t res, const acb_poly_t a, const acb_poly_t b, const acb_poly_t z, long len, long prec) + void acb_hypgeom_u_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, long prec) + void acb_hypgeom_u(acb_t res, const acb_t a, const acb_t b, const acb_t z, long prec) + void acb_hypgeom_m_asymp(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, long prec) + void acb_hypgeom_m_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, long prec) + void acb_hypgeom_m(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, long prec) + void acb_hypgeom_erf_1f1a(acb_t res, const acb_t z, long prec) + void acb_hypgeom_erf_1f1b(acb_t res, const acb_t z, long prec) + void acb_hypgeom_erf_asymp(acb_t res, const acb_t z, long prec, long prec2) + void acb_hypgeom_erf(acb_t res, const acb_t z, long prec) + void acb_hypgeom_erfc(acb_t res, const acb_t z, long prec) + void acb_hypgeom_erfi(acb_t res, const acb_t z, long prec) + void acb_hypgeom_bessel_j_asymp(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_bessel_j_0f1(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_bessel_j(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_bessel_y(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_bessel_i_asymp(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_bessel_i_0f1(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_bessel_i(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_bessel_k_asymp(acb_t res, const acb_t nu, const acb_t z, long prec) + # void acb_hypgeom_bessel_k_0f1_series(acb_poly_t res, const acb_poly_t nu, const acb_poly_t z, long len, long prec) + void acb_hypgeom_bessel_k_0f1(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_bessel_k(acb_t res, const acb_t nu, const acb_t z, long prec) + void acb_hypgeom_gamma_upper_asymp(acb_t res, const acb_t s, const acb_t z, int modified, long prec) + void acb_hypgeom_gamma_upper_1f1a(acb_t res, const acb_t s, const acb_t z, int modified, long prec) + void acb_hypgeom_gamma_upper_1f1b(acb_t res, const acb_t s, const acb_t z, int modified, long prec) + void acb_hypgeom_gamma_upper_singular(acb_t res, long s, const acb_t z, int modified, long prec) + void acb_hypgeom_gamma_upper(acb_t res, const acb_t s, const acb_t z, int modified, long prec) + void acb_hypgeom_expint(acb_t res, const acb_t s, const acb_t z, long prec) + void acb_hypgeom_ei_asymp(acb_t res, const acb_t z, long prec) + void acb_hypgeom_ei_2f2(acb_t res, const acb_t z, long prec) + void acb_hypgeom_ei(acb_t res, const acb_t z, long prec) + void acb_hypgeom_si_asymp(acb_t res, const acb_t z, long prec) + void acb_hypgeom_si_1f2(acb_t res, const acb_t z, long prec) + void acb_hypgeom_si(acb_t res, const acb_t z, long prec) + void acb_hypgeom_ci_asymp(acb_t res, const acb_t z, long prec) + void acb_hypgeom_ci_2f3(acb_t res, const acb_t z, long prec) + void acb_hypgeom_ci(acb_t res, const acb_t z, long prec) + void acb_hypgeom_shi(acb_t res, const acb_t z, long prec) + void acb_hypgeom_chi_asymp(acb_t res, const acb_t z, long prec) + void acb_hypgeom_chi_2f3(acb_t res, const acb_t z, long prec) + void acb_hypgeom_chi(acb_t res, const acb_t z, long prec) + void acb_hypgeom_li(acb_t res, const acb_t z, int offset, long prec) + From 77ef7fcb01513336ed4d44e06f7bac3932ae2df4 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 20 Aug 2015 16:35:23 +0200 Subject: [PATCH 1530/1872] complex_ball_acb: minor documentation improvements --- src/sage/rings/complex_ball_acb.pyx | 40 +++++++++++++++++++++++------ src/sage/rings/real_arb.pyx | 3 +-- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index f5044f58318..12de2f4a3aa 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -5,9 +5,36 @@ AUTHORS: - Clemens Heuberger (2014-10-25): Initial version. -This is a rudimentary binding to the `Arb library -`_; it may be useful to refer to its -documentation for more details. +This is a binding to the `Arb library `_; it +may be useful to refer to its documentation for more details. + +Parts of the documentation for this module are copied or adapted from +Arb's own documentation, licenced under the GNU General Public License +version 2, or later. + +.. SEEALSO:: + + - :mod:`sage.rings.real_arb` + - :mod:`sage.rings.complex_interval_field` + - :mod:`sage.rings.complex_interval` + +Data Structure +============== + +A :class:`ComplexBall` represents a complex number with error bounds. It wraps +an Arb object of type ``acb_t``, which consists of a pair of real number balls +representing the real and imaginary part with separate error bounds. + +A :class:`ComplexBall` thus represents a rectangle `[m_1-r_1, m_1+r_1] + +[m_2-r_2, m_2+r_2] i` in the complex plane. This is used in Arb instead of a +disk or square representation (consisting of a complex floating-point midpoint +with a single radius), since it allows implementing many operations more +conveniently by splitting into ball operations on the real and imaginary parts. +It also allows tracking when complex numbers have an exact (for example exactly +zero) real part and an inexact imaginary part, or vice versa. + +Comparison +========== .. WARNING:: @@ -17,9 +44,6 @@ documentation for more details. to a ball enclosing the set `\{t^2 : t \in x\}` and not the (generally larger) set `\{tu : t \in x, u \in x\}`. -Comparison -========== - Two elements are equal if and only if they are the same object or if both are exact and equal:: @@ -131,8 +155,8 @@ cdef int acb_to_ComplexIntervalFieldElement( class ComplexBallField(UniqueRepresentation, Parent): r""" - An approximation of the field of complex numbers using mid-rad - intervals, also known as balls. + An approximation of the field of complex numbers using pairs of mid-rad + intervals. INPUT: diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 196bc3b09f0..d0f26617c6f 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -366,8 +366,7 @@ class RealBallField(UniqueRepresentation, Parent): Convert ``mid`` to an element of this real ball field, perhaps non-canonically. - In addition to the inputs supported by - :meth:`ElementConstructor.__init__`, + In addition to the inputs supported by :meth:`RealBall.__init__`, anything that is convertible to a real interval can also be used to construct a real ball:: From 0c728071b4dcd19c2049c605365476c54dd844ef Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 20 Aug 2015 18:39:45 +0200 Subject: [PATCH 1531/1872] complex_ball_acb: improve elt __init__, _element_constructor_ --- src/sage/rings/complex_ball_acb.pxd | 4 +- src/sage/rings/complex_ball_acb.pyx | 219 +++++++++++++++++++--------- src/sage/rings/real_arb.pyx | 11 +- 3 files changed, 155 insertions(+), 79 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pxd b/src/sage/rings/complex_ball_acb.pxd index 094ce48b392..a8f7342d817 100644 --- a/src/sage/rings/complex_ball_acb.pxd +++ b/src/sage/rings/complex_ball_acb.pxd @@ -1,7 +1,7 @@ from sage.libs.arb.acb cimport acb_t from sage.rings.complex_interval cimport ComplexIntervalFieldElement from sage.rings.real_arb cimport RealBall -from sage.structure.element cimport Element +from sage.structure.element cimport RingElement cdef void ComplexIntervalFieldElement_to_acb( acb_t target, @@ -11,7 +11,7 @@ cdef int acb_to_ComplexIntervalFieldElement( ComplexIntervalFieldElement target, const acb_t source) except -1 -cdef class ComplexBall(Element): +cdef class ComplexBall(RingElement): cdef acb_t value cdef ComplexBall _new(self) cpdef ComplexIntervalFieldElement _interval(self) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 12de2f4a3aa..ba2eca39481 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -48,10 +48,10 @@ Two elements are equal if and only if they are the same object or if both are exact and equal:: sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: CBF = ComplexBallField() 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: CBF = ComplexBallField() sage: a = CBF(1, 2) sage: b = CBF(1, 2) sage: a is b @@ -98,12 +98,20 @@ include "sage/ext/python.pxi" include "sage/ext/stdsage.pxi" import sage.categories.fields + +cimport sage.rings.integer +cimport sage.rings.rational + from sage.libs.arb.arb cimport * from sage.libs.arb.acb cimport * +from sage.libs.arb.acb_hypgeom cimport * +from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_get_mpz, fmpz_set_mpz, fmpz_clear +from sage.libs.flint.fmpq cimport fmpq_t, fmpq_init, fmpq_set_mpq, fmpq_clear 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 +from sage.structure.element cimport Element from sage.structure.parent cimport Parent from sage.structure.unique_representation import UniqueRepresentation @@ -183,7 +191,7 @@ class ComplexBallField(UniqueRepresentation, Parent): Element = ComplexBall @staticmethod - def __classcall__(cls, long precision=53): + def __classcall__(cls, long precision=53, category=None): r""" Normalize the arguments for caching. @@ -193,10 +201,10 @@ class ComplexBallField(UniqueRepresentation, Parent): sage: ComplexBallField(53) is ComplexBallField() True """ - return super(ComplexBallField, cls).__classcall__(cls, precision) + return super(ComplexBallField, cls).__classcall__(cls, precision, category) @experimental(17218) - def __init__(self, precision): + def __init__(self, precision, category): r""" Initialize the complex ball field. @@ -213,7 +221,7 @@ class ComplexBallField(UniqueRepresentation, Parent): """ if precision < 2: raise ValueError("Precision must be at least 2.") - super(ComplexBallField, self).__init__(category=[sage.categories.fields.Fields()]) + super(ComplexBallField, self).__init__(category=category or [sage.categories.fields.Fields()]) self._prec = precision self.RealBallField = RealBallField(precision) @@ -245,18 +253,88 @@ class ComplexBallField(UniqueRepresentation, Parent): """ return False - def _element_constructor_(self, *args, **kwds): + def _element_constructor_(self, x=None, y=None): r""" - Construct a :class:`ComplexBall`. + Convert (x, y) to an element of this complex ball field, perhaps + non-canonically. + + INPUT: + + - ``x``, ``y`` (optional) -- either a complex number, interval or ball, + or two real ones (see examples below for more information on accepted + number types). + + .. SEEALSO:: :meth:`sage.rings.real_arb.RealBallField._element_constructor_` EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: CBF = ComplexBallField() + sage: from sage.rings.real_arb import RBF + sage: from sage.rings.complex_ball_acb import CBF, ComplexBallField + sage: CBF() + 0 sage: CBF(1) # indirect doctest 1.000000000000000 + sage: CBF(1, 1) + 1.000000000000000 + 1.000000000000000*I + sage: CBF(pi, sqrt(2)) + [3.141592653589793 +/- 5.61e-16] + [1.414213562373095 +/- 4.10e-16]*I + sage: CBF(I) + 1.000000000000000*I + sage: CBF(pi+I/3) + [3.141592653589793 +/- 5.61e-16] + [0.3333333333333333 +/- 7.04e-17]*I + sage: CBF(CIF(0, 1)) + 1.000000000000000*I + sage: CBF(RBF(1/3)) + [0.3333333333333333 +/- 7.04e-17] + sage: CBF(RBF(1/3), RBF(1/6)) + [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I + sage: CBF(1/3) + [0.3333333333333333 +/- 7.04e-17] + sage: CBF(1/3, 1/6) + [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I + sage: ComplexBallField(106)(1/3, 1/6) + [0.33333333333333333333333333333333 +/- 6.94e-33] + [0.16666666666666666666666666666666 +/- 7.70e-33]*I + sage: CBF(infinity, NaN) + [+/- inf] + nan*I + sage: CBF(x) + Traceback (most recent call last): + ... + TypeError: unable to convert x to a ComplexBall + + TESTS:: + + sage: CBF(1+I, 2) + Traceback (most recent call last): + ... + TypeError: unable to convert I + 1 to a RealBall """ - return self.element_class(self, *args, **kwds) + try: + return self.element_class(self, x, y) + except TypeError: + pass + + if y is None: + try: + x = self.RealBallField(x) + return self.element_class(self, x) + except (TypeError, ValueError): + pass + try: + y = self._real_field()(x.imag()) + x = self._real_field()(x.real()) + return self.element_class(self, x, y) + except (AttributeError, TypeError): + pass + try: + x = ComplexIntervalField(prec(self))(x) + return self.element_class(self, x) + except TypeError: + pass + raise TypeError("unable to convert {} to a ComplexBall".format(x)) + else: + x = self.RealBallField(x) + y = self.RealBallField(y) + return self.element_class(self, x, y) def _an_element_(self): r""" @@ -336,7 +414,7 @@ cdef inline long prec(ComplexBall ball): cdef inline Parent real_ball_field(ComplexBall ball): return ball._parent.RealBallField -cdef class ComplexBall(Element): +cdef class ComplexBall(RingElement): """ Hold one ``acb_t`` of the `Arb library `_ @@ -376,84 +454,79 @@ cdef class ComplexBall(Element): def __init__(self, parent, x=None, y=None): """ - Initialize the :class:`ComplexBall` using `x` and `y`. + Initialize the :class:`ComplexBall`. INPUT: - ``parent`` -- a :class:`ComplexBallField`. - - ``x`` -- (default: ``None``) ``None`` or a - :class:`~sage.rings.complex_interval.ComplexIntervalFieldElement` or - a :class:`sage.rings.real_arb.RealBall`. + - ``x``, ``y`` (optional) -- either a complex number, interval or ball, + or two real ones. - - ``y`` -- (default: ``None``) ``None`` or a - :class:`sage.rings.real_arb.RealBall`. - - OUTPUT: + .. SEEALSO:: :meth:`ComplexBallField._element_constructor_` - None. - - EXAMPLES:: + TESTS:: - sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: from sage.rings.real_arb import RealBallField - sage: CBF = ComplexBallField() - sage: CBF(CIF(0, 1)) - 1.000000000000000*I - sage: CBF(1) - 1.000000000000000 - sage: CBF(1, 1) - 1.000000000000000 + 1.000000000000000*I - sage: CBF(x) + sage: from sage.rings.complex_ball_acb import ComplexBallField, ComplexBall + sage: from sage.rings.real_arb import RBF + sage: CBF53, CBF100 = ComplexBallField(53), ComplexBallField(100) + sage: ComplexBall(CBF100) + 0 + sage: ComplexBall(CBF100, ComplexBall(CBF53, ComplexBall(CBF100, 1/3))) + [0.333333333333333333333333333333 +/- 4.65e-31] + sage: ComplexBall(CBF100, RBF(pi)) + [3.141592653589793 +/- 5.61e-16] + sage: ComplexBall(CBF100, -3r) + -3.000000000000000000000000000000 + sage: ComplexBall(CBF100, 10^100) + 1.000000000000000000000000000000e+100 + sage: ComplexBall(CBF100, CIF(1, 2)) + 1.000000000000000000000000000000 + 2.000000000000000000000000000000*I + sage: ComplexBall(CBF100, RBF(1/3), RBF(1)) + [0.3333333333333333 +/- 7.04e-17] + 1.000000000000000000000000000000*I + sage: ComplexBall(CBF100, 1, 2) Traceback (most recent call last): ... - TypeError: unable to convert to a ComplexIntervalFieldElement - sage: RBF = RealBallField() - sage: CBF(RBF(1/3)) - [0.3333333333333333 +/- 7.04e-17] - sage: CBF(RBF(1/3), RBF(1/6)) - [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I - sage: CBF(1/3) - [0.333333333333333 +/- 3.99e-16] - sage: CBF(1/3, 1/6) - [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I - sage: ComplexBallField(106)(1/3, 1/6) - [0.33333333333333333333333333333333 +/- 6.94e-33] + [0.16666666666666666666666666666666 +/- 7.70e-33]*I + TypeError: unsupported initializer """ + cdef fmpz_t tmpz + cdef fmpq_t tmpq + Element.__init__(self, parent) if x is None: return - - if y is None: - # we assume x to be a complex number - if isinstance(x, RealBall): - arb_set(&self.value.real, ( x).value) - arb_set_ui(&self.value.imag, 0) - else: - if not isinstance(x, ComplexIntervalFieldElement): - try: - x = ComplexIntervalField(prec(self))(x) - except TypeError: - raise TypeError("unable to convert to a " - "ComplexIntervalFieldElement") + elif y is None: + if isinstance(x, ComplexBall): + acb_set(self.value, ( x).value) + elif isinstance(x, RealBall): + acb_set_arb(self.value, ( x).value) + elif isinstance(x, int): + acb_set_si(self.value, PyInt_AS_LONG(x)) + elif isinstance(x, sage.rings.integer.Integer): + if _do_sig(prec(self)): sig_on() + fmpz_init(tmpz) + fmpz_set_mpz(tmpz, ( x).value) + acb_set_fmpz(self.value, tmpz) + fmpz_clear(tmpz) + if _do_sig(prec(self)): sig_off() + elif isinstance(x, sage.rings.rational.Rational): + if _do_sig(prec(self)): sig_on() + fmpq_init(tmpq) + fmpq_set_mpq(tmpq, ( x).value) + acb_set_fmpq(self.value, tmpq, prec(self)) + fmpq_clear(tmpq) + if _do_sig(prec(self)): sig_off() + elif isinstance(x, ComplexIntervalFieldElement): ComplexIntervalFieldElement_to_acb(self.value, x) + else: + raise TypeError("unsupported initializer") + elif isinstance(x, RealBall) and isinstance(y, RealBall): + arb_set(acb_realref(self.value), ( x).value) + arb_set(acb_imagref(self.value), ( y).value) else: - if not isinstance(x, RealBall): - try: - x = real_ball_field(self)(x) - except TypeError: - raise TypeError("unable to convert to a " - "RealBall") - if not isinstance(y, RealBall): - try: - y = real_ball_field(self)(y) - except TypeError: - raise TypeError("unable to convert to a " - "RealBall") - arb_set(&self.value.real, ( x).value) - arb_set(&self.value.imag, ( y).value) + raise TypeError("unsupported initializer") cdef ComplexBall _new(self): """ @@ -519,7 +592,7 @@ cdef class ComplexBall(Element): sage: from sage.rings.complex_ball_acb import ComplexBallField sage: CBF = ComplexBallField() sage: CBF(1/3) - [0.333333333333333 +/- 3.99e-16] + [0.3333333333333333 +/- 7.04e-17] sage: CBF(0, 1/3) [0.3333333333333333 +/- 7.04e-17]*I sage: ComplexBallField()(1/3, 1/6) @@ -719,3 +792,5 @@ cdef class ComplexBall(Element): elif op == Py_GT or op == Py_GE or op == Py_LT or op == Py_LE: raise TypeError("No order is defined for ComplexBalls.") + +CBF = ComplexBallField() diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index d0f26617c6f..7885c763846 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -378,7 +378,7 @@ class RealBallField(UniqueRepresentation, Parent): sage: RBF(x) Traceback (most recent call last): ... - TypeError: unable to convert x to a RealIntervalFieldElement + TypeError: unable to convert x to a RealBall Various symbolic constants can be converted without going through real intervals. (This is faster and yields tighter error bounds.) :: @@ -392,17 +392,16 @@ class RealBallField(UniqueRepresentation, Parent): return self.element_class(self, mid, rad) except TypeError: pass - try: return self.element_class(self, mid.pyobject(), rad) except (AttributeError, TypeError): pass - try: mid = RealIntervalField(self._prec)(mid) + return self.element_class(self, mid, rad) except TypeError: - raise TypeError("unable to convert {} to a RealIntervalFieldElement".format(mid)) - return self.element_class(self, mid, rad) + pass + raise TypeError("unable to convert {} to a RealBall".format(mid)) def gens(self): r""" @@ -874,6 +873,8 @@ cdef class RealBall(RingElement): floating-point, the radius is adjusted to account for the roundoff error. + .. SEEALSO:: :meth:`RealBallField._element_constructor_` + EXAMPLES:: sage: from sage.rings.real_arb import RealBallField From f36ecf18cba9f4fbcdd4dea7b7f2f27361893bf1 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Fri, 21 Aug 2015 10:19:37 +0200 Subject: [PATCH 1532/1872] ComplexBall: fix _repr_ of elts with exact imaginary part --- src/sage/rings/complex_ball_acb.pyx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index ba2eca39481..c990f7da170 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -597,11 +597,21 @@ cdef class ComplexBall(RingElement): [0.3333333333333333 +/- 7.04e-17]*I sage: ComplexBallField()(1/3, 1/6) [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I + + TESTS:: + + sage: CBF(1-I/2) + 1.000000000000000 - 0.5000000000000000*I """ - if arb_is_zero(&self.value.imag): + cdef arb_t real = acb_realref(self.value) + cdef arb_t imag = acb_imagref(self.value) + if arb_is_zero(imag): return self.real()._repr_() - elif arb_is_zero(&self.value.real): + elif arb_is_zero(real): return "{}*I".format(self.imag()._repr_()) + elif arb_is_exact(imag) and arb_is_negative(imag): + return "{} - {}*I".format(self.real()._repr_(), + (-self.imag())._repr_()) else: return "{} + {}*I".format(self.real()._repr_(), self.imag()._repr_()) From 69239038e0b78430f815c21acb6d897c559e7221 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Fri, 21 Aug 2015 10:20:09 +0200 Subject: [PATCH 1533/1872] ComplexBall: implement basic arithmetic --- src/sage/rings/complex_ball_acb.pyx | 143 +++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index c990f7da170..ce98053b48b 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -111,7 +111,7 @@ 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 -from sage.structure.element cimport Element +from sage.structure.element cimport Element, ModuleElement from sage.structure.parent cimport Parent from sage.structure.unique_representation import UniqueRepresentation @@ -803,4 +803,145 @@ cdef class ComplexBall(RingElement): elif op == Py_GT or op == Py_GE or op == Py_LT or op == Py_LE: raise TypeError("No order is defined for ComplexBalls.") + # Arithmetic + + def __neg__(self): + """ + Return the opposite of this ball. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: -CBF(1/3 + I) + [-0.3333333333333333 +/- 7.04e-17] - 1.000000000000000*I + """ + cdef ComplexBall res = self._new() + acb_neg(res.value, self.value) + return res + + def conjugate(self): + """ + Return the complex conjugate of this ball. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(-2 + I/3).conjugate() + -2.000000000000000 + [-0.3333333333333333 +/- 7.04e-17]*I + """ + cdef ComplexBall res = self._new() + acb_conj(res.value, self.value) + return res + + cpdef ModuleElement _add_(self, ModuleElement other): + """ + Return the sum of two balls, rounded to the ambient field's precision. + + The resulting ball is guaranteed to contain the sums of any two points + of the respective input balls. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(1) + CBF(I) + 1.000000000000000 + 1.000000000000000*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_add(res.value, self.value, ( other).value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + cpdef ModuleElement _sub_(self, ModuleElement other): + """ + Return the difference of two balls, rounded to the ambient field's + precision. + + The resulting ball is guaranteed to contain the differences of any two + points of the respective input balls. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(1) - CBF(I) + 1.000000000000000 - 1.000000000000000*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_sub(res.value, self.value, ( other).value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def __invert__(self): + """ + Return the inverse of this ball. + + The result is guaranteed to contain the inverse of any point of the + input ball. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: ~CBF(i/3) + [-3.00000000000000 +/- 9.44e-16]*I + sage: ~CBF(0) + [+/- inf] + sage: ~CBF(RIF(10,11)) + [0.1 +/- 9.53e-3] + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_inv(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + cpdef RingElement _mul_(self, RingElement other): + """ + Return the product of two balls, rounded to the ambient field's + precision. + + The resulting ball is guaranteed to contain the products of any two + points of the respective input balls. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(-2, 1)*CBF(1, 1/3) + [-2.333333333333333 +/- 5.37e-16] + [0.333333333333333 +/- 4.82e-16]*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_mul(res.value, self.value, ( other).value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + cpdef RingElement _div_(self, RingElement other): + """ + Return the quotient of two balls, rounded to the ambient field's + precision. + + The resulting ball is guaranteed to contain the quotients of any two + points of the respective input balls. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: from sage.rings.real_arb import RBF + + sage: CBF(-2, 1)/CBF(1, 1/3) + [-1.50000000000000 +/- 1.27e-15] + [1.500000000000000 +/- 8.94e-16]*I + + sage: CBF(2+I)/CBF(0) + [+/- inf] + [+/- inf]*I + sage: CBF(1)/CBF(0) + [+/- inf] + sage: CBF(1)/CBF(RBF(0, 1.)) + nan + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_div(res.value, self.value, ( other).value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + CBF = ComplexBallField() From ac69ca2b037e9e413ae34eb3fc8c6f0d4dabf9c0 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 22 Aug 2015 12:12:02 +0200 Subject: [PATCH 1534/1872] ComplexBallField: generators and coercions --- src/sage/rings/complex_ball_acb.pyx | 199 +++++++++++++++++++++++++--- src/sage/rings/real_arb.pyx | 28 +++- 2 files changed, 202 insertions(+), 25 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index ce98053b48b..a3083373a55 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -47,11 +47,10 @@ Comparison Two elements are equal if and only if they are the same object or if both are exact and equal:: - sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: from sage.rings.complex_ball_acb import CBF 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: CBF = ComplexBallField() sage: a = CBF(1, 2) sage: b = CBF(1, 2) sage: a is b @@ -82,6 +81,18 @@ A ball is non-zero if and only if it does not contain zero. :: sage: b != 0 True +Coercion +======== + +Automatic coercions work as expected:: + + sage: from sage.rings.real_arb import RealBallField + sage: bpol = 1/3*CBF(i) + AA(sqrt(2)) + (polygen(RealBallField(20), 'x') + QQbar(i)) + sage: bpol + x + [1.41421 +/- 5.09e-6] + [1.33333 +/- 3.97e-6]*I + sage: bpol.parent() + Univariate Polynomial Ring in x over Complex ball field with 20 bits precision + Classes and Methods =================== """ @@ -218,12 +229,70 @@ class ComplexBallField(UniqueRepresentation, Parent): sage: CBF = ComplexBallField() sage: CBF(1) 1.000000000000000 + + TESTS:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF.base() + Real ball field with 53 bits precision + sage: CBF.base_ring() + Real ball field with 53 bits precision + + There are direct coercions from ZZ and QQ (for which arb provides + construction functions):: + + sage: CBF.coerce_map_from(ZZ) + Conversion map: + From: Integer Ring + To: Complex ball field with 53 bits precision + sage: CBF.coerce_map_from(QQ) + Conversion map: + From: Rational Field + To: Complex ball field with 53 bits precision + + Various other coercions are available through real ball fields or CLF:: + + sage: CBF.coerce_map_from(RLF) + Composite map: + From: Real Lazy Field + To: Complex ball field with 53 bits precision + Defn: Conversion map: + From: Real Lazy Field + To: Real ball field with 53 bits precision + then + Conversion map: + From: Real ball field with 53 bits precision + To: Complex ball field with 53 bits precision + sage: CBF.has_coerce_map_from(AA) + True + sage: CBF.has_coerce_map_from(QuadraticField(-1)) + True + sage: CBF.has_coerce_map_from(QQbar) + True + sage: CBF.has_coerce_map_from(CLF) + True """ if precision < 2: raise ValueError("Precision must be at least 2.") - super(ComplexBallField, self).__init__(category=category or [sage.categories.fields.Fields()]) + real_field = RealBallField(precision) + super(ComplexBallField, self).__init__( + base=real_field, + category=category or [sage.categories.fields.Fields()]) self._prec = precision - self.RealBallField = RealBallField(precision) + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ + from sage.rings.real_lazy import CLF + self._populate_coercion_lists_([ZZ, QQ, real_field, CLF]) + + def _real_field(self): + """ + TESTS:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF._real_field() + Real ball field with 53 bits precision + """ + return self._base def _repr_(self): r""" @@ -239,19 +308,104 @@ class ComplexBallField(UniqueRepresentation, Parent): """ return "Complex ball field with {} bits precision".format(self._prec) - def _coerce_map_from_(self, S): - r""" - Currently, there is no coercion. + def construction(self): + """ + Returns the construction of a complex ball field as the algebraic + closure of the real ball field with the same precision. EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: ComplexBallField()._coerce_map_from_(CIF) + sage: from sage.rings.complex_ball_acb import CBF + sage: functor, base = CBF.construction() + sage: functor, base + (AlgebraicClosureFunctor, Real ball field with 53 bits precision) + sage: functor(base) is CBF + True + """ + from sage.categories.pushout import AlgebraicClosureFunctor + return (AlgebraicClosureFunctor(), self._real_field()) + + def ngens(self): + r""" + EXAMPLE:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF.ngens() + 1 + """ + return 1 + + def gen(self, i): + r""" + EXAMPLE:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF.0 + 1.000000000000000*I + sage: CBF.gen(1) + Traceback (most recent call last): + ... + ValueError: only one generator + """ + if i == 0: + return self(0, 1) + else: + raise ValueError("only one generator") + + def gens(self): + r""" + EXAMPLE:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF.gens() + (1.000000000000000*I,) + sage: CBF.gens_dict() + {'1.000000000000000*I': 1.000000000000000*I} + """ + return (self(0, 1),) + + def _coerce_map_from_(self, other): + r""" + Parents that canonically coerce into complex ball fields include: + + - anything that coerces into the corresponding real ball field; + + - real and complex ball fields with a larger precision; + + - various exact or lazy parents representing subsets of the complex + numbers, such as ``QQbar``, ``CLF``, and number fields equipped + with complex embeddings. + + TESTS:: + + sage: from sage.rings.complex_ball_acb import CBF, ComplexBallField + sage: from sage.rings.real_arb import RBF, RealBallField + sage: CBF.coerce_map_from(CBF) + Identity endomorphism of Complex ball field with 53 bits precision + sage: CBF.coerce_map_from(ComplexBallField(100)) + Conversion map: + From: Complex ball field with 100 bits precision + To: Complex ball field with 53 bits precision + sage: CBF.has_coerce_map_from(ComplexBallField(42)) False - sage: ComplexBallField()._coerce_map_from_(SR) + sage: CBF.has_coerce_map_from(RealBallField(54)) + True + sage: CBF.has_coerce_map_from(RealBallField(52)) + False + + Check that there are no coercions from interval or floating-point parents:: + + sage: CBF.has_coerce_map_from(RIF) + False + sage: CBF.has_coerce_map_from(CIF) + False + sage: CBF.has_coerce_map_from(RR) + False + sage: CBF.has_coerce_map_from(CC) False """ - return False + if isinstance(other, (RealBallField, ComplexBallField)): + return (other._prec >= self._prec) def _element_constructor_(self, x=None, y=None): r""" @@ -282,6 +436,10 @@ class ComplexBallField(UniqueRepresentation, Parent): 1.000000000000000*I sage: CBF(pi+I/3) [3.141592653589793 +/- 5.61e-16] + [0.3333333333333333 +/- 7.04e-17]*I + sage: CBF(QQbar(i/7)) + [0.1428571428571428 +/- 9.09e-17]*I + sage: CBF(AA(sqrt(2))) + [1.414213562373095 +/- 4.10e-16] sage: CBF(CIF(0, 1)) 1.000000000000000*I sage: CBF(RBF(1/3)) @@ -315,7 +473,7 @@ class ComplexBallField(UniqueRepresentation, Parent): if y is None: try: - x = self.RealBallField(x) + x = self._real_field()(x) return self.element_class(self, x) except (TypeError, ValueError): pass @@ -326,14 +484,14 @@ class ComplexBallField(UniqueRepresentation, Parent): except (AttributeError, TypeError): pass try: - x = ComplexIntervalField(prec(self))(x) + x = ComplexIntervalField(self._prec)(x) return self.element_class(self, x) except TypeError: pass raise TypeError("unable to convert {} to a ComplexBall".format(x)) else: - x = self.RealBallField(x) - y = self.RealBallField(y) + x = self._real_field()(x) + y = self._real_field()(y) return self.element_class(self, x, y) def _an_element_(self): @@ -342,12 +500,11 @@ class ComplexBallField(UniqueRepresentation, Parent): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: CBF = ComplexBallField() - sage: CBF._an_element_() # indirect doctest - [0.3333333333333333 +/- 1.49e-17] + [0.1666666666666667 +/- 4.26e-17]*I + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF.an_element() # indirect doctest + [0.3333333333333333 +/- 1.49e-17] - [0.1666666666666667 +/- 4.26e-17]*I """ - return self(1.0/3, 1.0/6) + return self(1.0/3, -1.0/6) def precision(self): """ @@ -412,7 +569,7 @@ cdef inline long prec(ComplexBall ball): return ball._parent._prec cdef inline Parent real_ball_field(ComplexBall ball): - return ball._parent.RealBallField + return ball._parent._real_field() cdef class ComplexBall(RingElement): """ diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 7885c763846..82d6d9d39d7 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -314,6 +314,9 @@ class RealBallField(UniqueRepresentation, Parent): # FIXME: RBF is not even associative, but CompletionFunctor only works with rings. category=category or sage.categories.rings.Rings().Infinite()) self._prec = precision + from sage.rings.qqbar import AA + from sage.rings.real_lazy import RLF + self._populate_coercion_lists_([ZZ, QQ, AA, RLF]) def _repr_(self): r""" @@ -352,12 +355,8 @@ class RealBallField(UniqueRepresentation, Parent): sage: RealBallField().has_coerce_map_from(RR) False """ - from sage.rings.qqbar import AA - from sage.rings.real_lazy import RLF if isinstance(other, RealBallField): return (other._prec >= self._prec) - elif (other is ZZ) or (other is QQ) or (other is AA) or (other is RLF): - return True else: return False @@ -460,6 +459,27 @@ class RealBallField(UniqueRepresentation, Parent): {'type': 'Ball'}) return functor, QQ + def complex_field(self): + """ + Return the complex ball field with the same precision. + + EXAMPLES:: + + sage: from sage.rings.real_arb import RBF, RealBallField + sage: from sage.rings.complex_ball_acb import ComplexBallField + 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: RBF.complex_field() + Complex ball field with 53 bits precision + sage: RealBallField(3).algebraic_closure() + Complex ball field with 3 bits precision + """ + from sage.rings.complex_ball_acb import ComplexBallField + return ComplexBallField(self._prec) + + algebraic_closure = complex_field + def precision(self): """ Return the bit precision used for operations on elements of this field. From 4527d43a458ec4ed243fa324e4c1e787788cd228 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 22 Aug 2015 12:30:31 +0200 Subject: [PATCH 1535/1872] ComplexBallField: implement some_elements() --- src/sage/rings/complex_ball_acb.pyx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index a3083373a55..b553ea1f5ca 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -554,6 +554,31 @@ class ComplexBallField(UniqueRepresentation, Parent): """ return 0 + def some_elements(self): + """ + Complex ball fields contain elements with exact, inexact, infinite, or + undefined real and imaginary parts. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF.some_elements() + [1.000000000000000, + -0.5000000000000000*I, + 1.000000000000000 + [0.3333333333333333 +/- 1.49e-17]*I, + [-0.3333333333333333 +/- 1.49e-17] + 0.2500000000000000*I, + [-2.175556475109056e+181961467118333366510562 +/- 1.29e+181961467118333366510545], + [+/- inf], + [+/- inf]*I, + [+/- inf] + [+/- inf]*I, + nan, + nan + nan*I, + [+/- inf] + nan*I] + """ + return [self(1), self(0, -1./2), self(1, 1./3), self(-1./3, 1./4), + -self(1, 1)**(sage.rings.integer.Integer(2)**80), + self('inf'), self(1/3, 'inf'), self('inf', 'inf'), + self('nan'), self('nan', 'nan'), self('inf', 'nan')] cdef inline bint _do_sig(long prec): """ From bc260756a1c5487dda35c4cf48c9c67635ac6ca2 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 22 Aug 2015 14:09:19 +0200 Subject: [PATCH 1536/1872] Fix RealBall.mid(), implement ComplexBall.{mid(),squash()} --- src/sage/rings/complex_ball_acb.pyx | 140 +++++++++++++++++++--------- src/sage/rings/real_arb.pyx | 18 ++-- 2 files changed, 109 insertions(+), 49 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index b553ea1f5ca..8fb5daddeb9 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -116,9 +116,12 @@ cimport sage.rings.rational from sage.libs.arb.arb cimport * from sage.libs.arb.acb cimport * from sage.libs.arb.acb_hypgeom cimport * +from sage.libs.arb.arf cimport arf_t, arf_init, arf_get_mpfr, arf_set_mpfr, arf_clear, arf_set_mag, arf_set +from sage.libs.arb.mag cimport mag_t, mag_init, mag_clear, mag_add, mag_set_d, MAG_BITS, mag_is_inf, mag_is_finite, mag_zero from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_get_mpz, fmpz_set_mpz, fmpz_clear from sage.libs.flint.fmpq cimport fmpq_t, fmpq_init, fmpq_set_mpq, fmpq_clear from sage.misc.superseded import experimental +from sage.rings.complex_field import ComplexField 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 @@ -719,48 +722,6 @@ cdef class ComplexBall(RingElement): x._parent = self._parent return x - cpdef RealBall real(self): - """ - Return the real part of this ball. - - OUTPUT: - - A :class:`RealBall`. - - EXAMPLES:: - - sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: CBF = ComplexBallField() - sage: a = CBF(1/3, 1/5) - sage: a.real() - [0.3333333333333333 +/- 7.04e-17] - """ - cdef RealBall r - r = real_ball_field(self)(0) - arb_set(r.value, &self.value.real) - return r - - cpdef RealBall imag(self): - """ - Return the imaginary part of this ball. - - OUTPUT: - - A :class:`RealBall`. - - EXAMPLES:: - - sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: CBF = ComplexBallField() - sage: a = CBF(1/3, 1/5) - sage: a.imag() - [0.2000000000000000 +/- 4.45e-17] - """ - cdef RealBall r - r = real_ball_field(self)(0) - arb_set(r.value, &self.value.imag) - return r - def _repr_(self): """ Return a string representation of ``self``. @@ -818,6 +779,101 @@ cdef class ComplexBall(RingElement): acb_to_ComplexIntervalFieldElement(target, self.value) return target + # Real and imaginary part, midpoint + + cpdef RealBall real(self): + """ + Return the real part of this ball. + + OUTPUT: + + A :class:`RealBall`. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: a = CBF(1/3, 1/5) + sage: a.real() + [0.3333333333333333 +/- 7.04e-17] + """ + cdef RealBall r + r = real_ball_field(self)(0) + arb_set(r.value, &self.value.real) + return r + + cpdef RealBall imag(self): + """ + Return the imaginary part of this ball. + + OUTPUT: + + A :class:`RealBall`. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: CBF = ComplexBallField() + sage: a = CBF(1/3, 1/5) + sage: a.imag() + [0.2000000000000000 +/- 4.45e-17] + """ + cdef RealBall r + r = real_ball_field(self)(0) + arb_set(r.value, &self.value.imag) + return r + + def mid(self): + """ + Return the floating-point complex number formed by the centers of the + real and imaginary parts of this ball. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(1/3, 1).mid() + 0.333333333333333 + 1.00000000000000*I + sage: CBF(1/3, 1).mid().parent() + Complex Field with 53 bits of precision + sage: CBF('inf', 'nan').mid() + +infinity - NaN*I + sage: CBF('nan', 'inf').mid() + NaN + +infinity*I + sage: CBF('nan').mid() + NaN + sage: CBF('inf').mid() + +infinity + sage: CBF(0, 'inf').mid() + +infinity*I + """ + re, im = self.real().mid(), self.imag().mid() + field = ComplexField(max(prec(self), re.prec(), im.prec())) + return field(re, im) + + def squash(self): + """ + Return an exact ball with the same midpoint as this ball. + + .. SEEALSO:: :meth:`mid` + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: mid = CBF(1/3, 1/10).squash() + sage: mid + [0.3333333333333333 +/- 1.49e-17] + [0.09999999999999999 +/- 1.68e-18]*I + sage: mid.parent() + Complex ball field with 53 bits precision + sage: mid.is_exact() + True + """ + cdef ComplexBall res = self._new() + arf_set(arb_midref(acb_realref(res.value)), arb_midref(acb_realref(self.value))) + arf_set(arb_midref(acb_imagref(res.value)), arb_midref(acb_imagref(self.value))) + mag_zero(arb_radref(acb_realref(res.value))) + mag_zero(arb_radref(acb_imagref(res.value))) + return res + # Comparisons and predicates def is_zero(self): diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 82d6d9d39d7..5d6a13da7f1 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1226,7 +1226,11 @@ cdef class RealBall(RingElement): sage: RealBallField(16)(1/3).mid() 0.3333 sage: RealBallField(16)(1/3).mid().parent() - Real Field with 15 bits of precision + Real Field with 16 bits of precision + sage: RealBallField(16)(RBF(1/3)).mid().parent() + Real Field with 53 bits of precision + sage: RBF('inf').mid() + +infinity :: @@ -1236,7 +1240,7 @@ cdef class RealBall(RingElement): ... RuntimeError: unable to convert to MPFR (exponent out of range?) """ - cdef long mid_prec = arb_bits(self.value) or prec(self) + cdef long mid_prec = max(arb_bits(self.value), prec(self)) if mid_prec < MPFR_PREC_MIN: mid_prec = MPFR_PREC_MIN cdef RealField_class mid_field = RealField(mid_prec) @@ -1271,7 +1275,7 @@ cdef class RealBall(RingElement): def squash(self): """ - Return an exact ball with the same center of this ball. + Return an exact ball with the same center as this ball. .. SEEALSO:: :meth:`mid`, :meth:`rad_as_ball` @@ -1329,7 +1333,7 @@ cdef class RealBall(RingElement): sage: b.mid() 3.141592653589793238462643383 sage: b.round().mid() - 3.1415926535898 + 3.14159265358979 """ cdef RealBall res = self._new() if _do_sig(prec(self)): sig_on() @@ -1376,11 +1380,11 @@ cdef class RealBall(RingElement): EXAMPLES:: sage: from sage.rings.real_arb import RBF - sage: b = RBF(RIF(3.1415,3.1416)) + sage: b = RBF(0.11111111111111, rad=.001) sage: b.mid() - 3.14155000000000 + 0.111111111111110 sage: b.trim().mid() - 3.14155000 + 0.111111104488373 """ cdef RealBall res = self._new() if _do_sig(prec(self)): sig_on() From e9f36a514e642cccf2824bdb51ec4440893be787 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 22 Aug 2015 16:37:15 +0200 Subject: [PATCH 1537/1872] ComplexBall: round(), accuracy(), trim() --- src/sage/rings/complex_ball_acb.pyx | 71 +++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 8fb5daddeb9..dff52b65b90 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -874,6 +874,77 @@ cdef class ComplexBall(RingElement): mag_zero(arb_radref(acb_imagref(res.value))) return res + # Precision + + def round(self): + """ + Return a copy of this ball rounded to the precision of the parent. + + .. SEEALSO:: :meth:`trim` + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: b = CBF(exp(I*pi/3).n(100)) + sage: b.mid() + 0.50000000000000000000000000000 + 0.86602540378443864676372317075*I + sage: b.round().mid() + 0.500000000000000 + 0.866025403784439*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_set_round(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def accuracy(self): + """ + Return the effective relative accuracy of this ball measured in bits. + + This is computed as if calling + :meth:`~sage.rings.real_arb.RealBall.accuracy()` + on the real ball whose midpoint is the larger out of the real and + imaginary midpoints of this complex ball, and whose radius is the + larger out of the real and imaginary radii of this complex ball. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(exp(I*pi/3)).accuracy() + 51 + sage: CBF(I/2).accuracy() + 9223372036854775807 + sage: CBF('nan', 'inf').accuracy() + -9223372036854775807 + """ + return acb_rel_accuracy_bits(self.value) + + def trim(self): + """ + Return a trimmed copy of this ball. + + Return a copy of this ball with both the real and imaginary parts + trimmed (see :meth:`~sage.rings.real_arb.RealBall.trim()`). + + .. SEEALSO:: :meth:`round` + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: from sage.rings.real_arb import RBF + sage: b = CBF(1/3, RBF(1/3, rad=.01)) + sage: b.mid() + 0.333333333333333 + 0.333333333333333*I + sage: b.trim().mid() + 0.333333333333333 + 0.333333015441895*I + + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_trim(res.value, self.value) + if _do_sig(prec(self)): sig_off() + return res + # Comparisons and predicates def is_zero(self): From 5cff19ceb2e6dba8d131b323897c14a8b52efcb7 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 22 Aug 2015 17:39:48 +0200 Subject: [PATCH 1538/1872] ComplexBall: conversions to ZZ, RR, RIF, CC, CIF --- src/sage/rings/complex_ball_acb.pxd | 2 +- src/sage/rings/complex_ball_acb.pyx | 107 ++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pxd b/src/sage/rings/complex_ball_acb.pxd index a8f7342d817..0f9882f36ef 100644 --- a/src/sage/rings/complex_ball_acb.pxd +++ b/src/sage/rings/complex_ball_acb.pxd @@ -14,6 +14,6 @@ cdef int acb_to_ComplexIntervalFieldElement( cdef class ComplexBall(RingElement): cdef acb_t value cdef ComplexBall _new(self) - cpdef ComplexIntervalFieldElement _interval(self) + cpdef ComplexIntervalFieldElement _complex_mpfi_(self, parent) cpdef RealBall real(self) cpdef RealBall imag(self) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index dff52b65b90..026a8a54372 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -610,8 +610,6 @@ cdef class ComplexBall(RingElement): sage: a = ComplexBallField()(1, 1) sage: a 1.000000000000000 + 1.000000000000000*I - sage: a._interval() - 1 + 1*I """ def __cinit__(self): """ @@ -759,25 +757,108 @@ cdef class ComplexBall(RingElement): return "{} + {}*I".format(self.real()._repr_(), self.imag()._repr_()) - cpdef ComplexIntervalFieldElement _interval(self): + # Conversions + + cpdef ComplexIntervalFieldElement _complex_mpfi_(self, parent): """ Return :class:`ComplexIntervalFieldElement` of the same value. - OUTPUT: + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CIF(CBF(1/3, 1/3)) # indirect doctest + 0.3333333333333333? + 0.3333333333333333?*I + """ + cdef ComplexIntervalFieldElement res = parent.zero() + res = res._new() # FIXME after modernizing CIF + acb_to_ComplexIntervalFieldElement(res, self.value) + return res - A :class:`ComplexIntervalFieldElement`. + def _integer_(self, _): + """ + Check that this ball contains a single integer and return that integer. EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: CBF = ComplexBallField() - sage: a = CBF(CIF(2, 2)) - sage: a._interval() - 2 + 2*I + sage: from sage.rings.complex_ball_acb import CBF + sage: from sage.rings.real_arb import RBF + sage: ZZ(CBF(-42, RBF(.1, rad=.2))) # indirect doctest + -42 + sage: ZZ(CBF(i)) + Traceback (most recent call last): + ... + ValueError: 1.000000000000000*I does not contain a unique integer + """ + cdef sage.rings.integer.Integer res + cdef fmpz_t tmp + fmpz_init(tmp) + try: + if acb_get_unique_fmpz(tmp, self.value): + res = sage.rings.integer.Integer.__new__(sage.rings.integer.Integer) + fmpz_get_mpz(res.value, tmp) + else: + raise ValueError("{} does not contain a unique integer".format(self)) + finally: + fmpz_clear(tmp) + return res + + def _complex_mpfr_field_(self, parent): + r""" + Convert this complex ball to a complex number. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CC(CBF(1/3, 1/3)) + 0.333333333333333 + 0.333333333333333*I + sage: ComplexField(100)(CBF(1/3, 1/3)) + 0.33333333333333331482961625625 + 0.33333333333333331482961625625*I + """ + real_field = parent._real_field() + return parent(real_field(self.real()), real_field(self.imag())) + + def _real_mpfi_(self, parent): + r""" + Try to convert this complex ball to a real number. + + Fail if the imaginary part is not exactly zero. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: from sage.rings.real_arb import RBF + sage: RIF(CBF(RBF(1/3, rad=1e-5))) + 0.3334? + sage: RIF(CBF(RBF(1/3, rad=1e-5), 1e-10)) + Traceback (most recent call last): + ... + ValueError: nonzero imaginary part """ - cdef ComplexIntervalFieldElement target = ComplexIntervalField(prec(self))(0) - acb_to_ComplexIntervalFieldElement(target, self.value) - return target + if acb_is_real(self.value): + return parent(self.real()) + else: + raise ValueError("nonzero imaginary part") + + def _mpfr_(self, parent): + r""" + Try to convert this complex ball to a real number. + + Fail if the imaginary part is not exactly zero. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: RR(CBF(1/3)) + 0.333333333333333 + sage: RR(CBF(1, 1/3) - CBF(0, 1/3)) + Traceback (most recent call last): + ... + ValueError: nonzero imaginary part + """ + if acb_is_real(self.value): + return parent(self.real()) + else: + raise ValueError("nonzero imaginary part") # Real and imaginary part, midpoint From 7fe74c6d22f71ba973452e2a2a9d3339171b21fd Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 23 Aug 2015 10:14:52 +0200 Subject: [PATCH 1539/1872] ComplexBallField: faster access to real field (following the removal of the cdef attribute _real_field in favor of _base) --- src/sage/rings/complex_ball_acb.pyx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 026a8a54372..dda2e7b8b8b 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -326,7 +326,7 @@ class ComplexBallField(UniqueRepresentation, Parent): True """ from sage.categories.pushout import AlgebraicClosureFunctor - return (AlgebraicClosureFunctor(), self._real_field()) + return (AlgebraicClosureFunctor(), self._base) def ngens(self): r""" @@ -476,13 +476,13 @@ class ComplexBallField(UniqueRepresentation, Parent): if y is None: try: - x = self._real_field()(x) + x = self._base(x) return self.element_class(self, x) except (TypeError, ValueError): pass try: - y = self._real_field()(x.imag()) - x = self._real_field()(x.real()) + y = self._base(x.imag()) + x = self._base(x.real()) return self.element_class(self, x, y) except (AttributeError, TypeError): pass @@ -493,8 +493,8 @@ class ComplexBallField(UniqueRepresentation, Parent): pass raise TypeError("unable to convert {} to a ComplexBall".format(x)) else: - x = self._real_field()(x) - y = self._real_field()(y) + x = self._base(x) + y = self._base(y) return self.element_class(self, x, y) def _an_element_(self): @@ -597,7 +597,7 @@ cdef inline long prec(ComplexBall ball): return ball._parent._prec cdef inline Parent real_ball_field(ComplexBall ball): - return ball._parent._real_field() + return ball._parent._base cdef class ComplexBall(RingElement): """ @@ -814,7 +814,7 @@ cdef class ComplexBall(RingElement): sage: ComplexField(100)(CBF(1/3, 1/3)) 0.33333333333333331482961625625 + 0.33333333333333331482961625625*I """ - real_field = parent._real_field() + real_field = parent._base return parent(real_field(self.real()), real_field(self.imag())) def _real_mpfi_(self, parent): From 09c1089b0c4eb40da924a09ef336188ccade26ab Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 23 Aug 2015 11:19:04 +0200 Subject: [PATCH 1540/1872] {Real,Complex}Ball: implement conversions to QQ --- src/sage/rings/complex_ball_acb.pyx | 20 ++++++++++++++++++++ src/sage/rings/real_arb.pyx | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index dda2e7b8b8b..27856d8e3c7 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -802,6 +802,26 @@ cdef class ComplexBall(RingElement): fmpz_clear(tmp) return res + def _rational_(self): + """ + Check that this ball contains a single rational number and return that + number. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: QQ(CBF(12345/2^5)) + 12345/32 + sage: QQ(CBF(i)) + Traceback (most recent call last): + ... + ValueError: 1.000000000000000*I does not contain a unique rational number + """ + if acb_is_real(self.value) and acb_is_exact(self.value): + return self.real().mid().exact_rational() + else: + raise ValueError("{} does not contain a unique rational number".format(self)) + def _complex_mpfr_field_(self, parent): r""" Convert this complex ball to a complex number. diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 5d6a13da7f1..ff1427ea0ba 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1146,6 +1146,26 @@ cdef class RealBall(RingElement): fmpz_clear(tmp) return res + def _rational_(self): + """ + Check that this ball contains a single rational number and return that + number. + + EXAMPLES:: + + sage: from sage.rings.real_arb import RBF + sage: QQ(RBF(123456/2^12)) + 1929/64 + sage: QQ(RBF(1/3)) + Traceback (most recent call last): + ... + ValueError: [0.3333333333333333 +/- 7.04e-17] does not contain a unique rational number + """ + if arb_is_exact(self.value): + return self.mid().exact_rational() + else: + raise ValueError("{} does not contain a unique rational number".format(self)) + def _mpfr_(self, RealField_class field): """ Convert this real ball to a real number. From d29459fe83307b8d4664368e67832925ea19a09c Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 22 Aug 2015 18:07:02 +0200 Subject: [PATCH 1541/1872] ComplexBall: containment and overlapping predicates --- src/sage/rings/complex_ball_acb.pyx | 120 ++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 27856d8e3c7..64287358ecb 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -1098,6 +1098,22 @@ cdef class ComplexBall(RingElement): """ return acb_is_exact(self.value) + def is_real(self): + """ + Return ``True`` iff the imaginary part of this ball is exactly zero. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(1/3, 0).is_real() + True + sage: (CBF(i/3) - CBF(1, 1/3)).is_real() + False + sage: CBF('inf').is_real() + True + """ + return acb_is_real(self.value) + cpdef _richcmp_(left, Element right, int op): """ Compare ``left`` and ``right``. @@ -1213,6 +1229,110 @@ cdef class ComplexBall(RingElement): elif op == Py_GT or op == Py_GE or op == Py_LT or op == Py_LE: raise TypeError("No order is defined for ComplexBalls.") + def identical(self, ComplexBall other): + """ + Return True iff ``self`` and ``other`` are equal as set, i.e. if their + real and imaginary parts each have the same midpoint and radius. + + Note that this is not the same thing as testing whether both ``self`` + and ``other`` certainly represent the complex real number, unless either + ``self`` or ``other`` is exact (and neither contains NaN). To test + whether both operands might represent the same mathematical quantity, + use :meth:`overlaps` or :meth:`contains`, depending on the + circumstance. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(1, 1/3).identical(1 + CBF(0, 1)/3) + True + sage: CBF(1, 1).identical(1 + CBF(0, 1/3)*3) + False + """ + return acb_equal(self.value, other.value) + + def overlaps(self, ComplexBall other): + """ + Return True iff ``self`` and ``other`` have some point in common. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(1, 1).overlaps(1 + CBF(0, 1/3)*3) + True + sage: CBF(1, 1).overlaps(CBF(1, 'nan')) + True + sage: CBF(1, 1).overlaps(CBF(0, 'nan')) + False + """ + return acb_overlaps(self.value, other.value) + + def contains_exact(self, other): + """ + Returns nonzero *iff* the given number (or ball) ``other`` is contained + in the interval represented by ``self``. + + Use ``other in self`` for a test that works for a wider range of inputs + but may return false negatives. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: from sage.rings.real_arb import RealBallField + sage: CBF(RealBallField(100)(1/3), 0).contains_exact(1/3) + True + sage: 1/3 in CBF(RealBallField(100)(1/3), 0) + False + sage: CBF(1).contains_exact(1) + True + sage: CBF(1).contains_exact(CBF(1)) + True + """ + cdef fmpz_t tmpz + cdef fmpq_t tmpq + if _do_sig(prec(self)): sig_on() + try: + if isinstance(other, ComplexBall): + res = acb_contains(self.value, ( other).value) + elif isinstance(other, sage.rings.integer.Integer): + fmpz_init(tmpz) + fmpz_set_mpz(tmpz, ( other).value) + res = acb_contains_fmpz(self.value, tmpz) + fmpz_clear(tmpz) + elif isinstance(other, sage.rings.rational.Rational): + fmpq_init(tmpq) + fmpq_set_mpq(tmpq, ( other).value) + res = acb_contains_fmpq(self.value, tmpq) + fmpq_clear(tmpq) + else: + raise TypeError + finally: + if _do_sig(prec(self)): sig_off() + return res + + def __contains__(self, other): + """ + Return True if ``other`` can be verified to be contained in ``self``. + + The test is done using interval arithmetic with a precision determined + by the parent of ``self`` and may return false negatives. + + .. SEEALSO:: :meth:`contains_exact` + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: 1/3*i in CBF(0, 1/3) + True + + A false negative:: + + sage: from sage.rings.real_arb import RealBallField + sage: 1/3 in CBF(RealBallField(100)(1/3), 0) + False + """ + return self.contains_exact(self._parent(other)) + # Arithmetic def __neg__(self): From 96eba3d9c01f52111ca1b4e3ac77db6bfb6a892e Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 23 Aug 2015 10:17:28 +0200 Subject: [PATCH 1542/1872] ComplexBall: abs(), arg() plus minor improvements to real() and imag() --- src/sage/rings/complex_ball_acb.pyx | 44 +++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 64287358ecb..d7f9c7f79f5 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -898,9 +898,8 @@ cdef class ComplexBall(RingElement): sage: a.real() [0.3333333333333333 +/- 7.04e-17] """ - cdef RealBall r - r = real_ball_field(self)(0) - arb_set(r.value, &self.value.real) + cdef RealBall r = RealBall(real_ball_field(self)) + arb_set(r.value, acb_realref(self.value)) return r cpdef RealBall imag(self): @@ -919,9 +918,42 @@ cdef class ComplexBall(RingElement): sage: a.imag() [0.2000000000000000 +/- 4.45e-17] """ - cdef RealBall r - r = real_ball_field(self)(0) - arb_set(r.value, &self.value.imag) + cdef RealBall r = RealBall(real_ball_field(self)) + arb_set(r.value, acb_imagref(self.value)) + return r + + def abs(self): + """ + Return the absolute value of this complex ball. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(1 + i).abs() + [1.414213562373095 +/- 2.99e-16] + sage: CBF(1 + i).abs().parent() + Real ball field with 53 bits precision + """ + cdef RealBall r = RealBall(real_ball_field(self)) + acb_abs(r.value, self.value, prec(self)) + return r + + def arg(self): + """ + Return the argument of this complex ball. + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import CBF + sage: CBF(1 + i).arg() + [0.785398163397448 +/- 3.91e-16] + sage: CBF(-1).arg() + [3.141592653589793 +/- 5.61e-16] + sage: CBF(-1).arg().parent() + Real ball field with 53 bits precision + """ + cdef RealBall r = RealBall(real_ball_field(self)) + acb_arg(r.value, self.value, prec(self)) return r def mid(self): From 30778b98f8744a2a4be93aaec801eb9aeb69e545 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 23 Aug 2015 10:23:46 +0200 Subject: [PATCH 1543/1872] RealBall: implement abs() --- src/sage/rings/real_arb.pyx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index ff1427ea0ba..d1552bf412f 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1232,7 +1232,7 @@ cdef class RealBall(RingElement): return field(0) raise ValueError("unknown rounding mode") - # Center and radius + # Center and radius, absolute value def mid(self): """ @@ -1337,6 +1337,20 @@ cdef class RealBall(RingElement): mag_zero(arb_radref(res.value)) return res + def abs(self): + """ + Return the absolute value of this ball. + + EXAMPLES:: + + sage: from sage.rings.real_arb import RBF + sage: RBF(-1/3).abs() + [0.3333333333333333 +/- 7.04e-17] + """ + cdef RealBall r = self._new() + arb_abs(r.value, self.value) + return r + # Precision def round(self): From ef39dda6c6f3aacfe596b98ec4a03312ac91aa89 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 23 Aug 2015 11:42:23 +0200 Subject: [PATCH 1544/1872] {Real,Complex}Ball: implement {above,below}_abs() --- src/sage/rings/complex_ball_acb.pyx | 57 +++++++++++++++++++++++++++ src/sage/rings/real_arb.pyx | 60 +++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index d7f9c7f79f5..2ff6fc28378 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -938,6 +938,63 @@ cdef class ComplexBall(RingElement): acb_abs(r.value, self.value, prec(self)) return r + def below_abs(self, test_zero=False): + """ + Return a lower bound for the absolute value of this complex ball. + + INPUT: + + - ``test_zero`` (boolean, default False) -- if True, make sure that the + returned lower bound is positive, raising an error if the ball + contains zero. + + .. SEEALSO:: :meth:`abs`, :meth:`above_abs` + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import ComplexBallField, CBF + sage: b = ComplexBallField(8)(1+i).below_abs() + sage: b + [1.4 +/- 0.0141] + sage: b.is_exact() + True + sage: QQ(b)*128 + 181 + sage: (CBF(1/3) - 1/3).below_abs() + 0 + sage: (CBF(1/3) - 1/3).below_abs(test_zero=True) + Traceback (most recent call last): + ... + ValueError: ball contains zero + """ + cdef RealBall res = RealBall(real_ball_field(self)) + acb_get_abs_lbound_arf(arb_midref(res.value), self.value, prec(self)) + if test_zero and arb_contains_zero(res.value): + assert acb_contains_zero(self.value) + raise ValueError("ball contains zero") + return res + + def above_abs(self): + """ + Return an upper bound for the absolute value of this complex ball. + + .. SEEALSO:: :meth:`abs`, :meth:`below_abs` + + EXAMPLES:: + + sage: from sage.rings.complex_ball_acb import ComplexBallField + sage: b = ComplexBallField(8)(1+i).above_abs() + sage: b + [1.4 +/- 0.0219] + sage: b.is_exact() + True + sage: QQ(b)*128 + 182 + """ + cdef RealBall res = RealBall(real_ball_field(self)) + acb_get_abs_ubound_arf(arb_midref(res.value), self.value, prec(self)) + return res + def arg(self): """ Return the argument of this complex ball. diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index d1552bf412f..4b7a9f3e446 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1351,6 +1351,66 @@ cdef class RealBall(RingElement): arb_abs(r.value, self.value) return r + def below_abs(self, test_zero=False): + """ + Return a lower bound for the absolute value of this ball. + + INPUT: + + - ``test_zero`` (boolean, default False) -- if True, make sure that the + returned lower bound is positive, raising an error if the ball + contains zero. + + .. SEEALSO:: :meth:`abs`, :meth:`above_abs` + + EXAMPLES:: + + sage: from sage.rings.real_arb import RealBallField, RBF + sage: RealBallField(8)(1/3).below_abs() + [0.33 +/- 7.82e-5] + sage: b = RealBallField(8)(1/3).below_abs() + sage: b + [0.33 +/- 7.82e-5] + sage: b.is_exact() + True + sage: QQ(b) + 169/512 + + sage: RBF(0).below_abs() + 0 + sage: RBF(0).below_abs(test_zero=True) + Traceback (most recent call last): + ... + ValueError: ball contains zero + """ + cdef RealBall res = self._new() + arb_get_abs_lbound_arf(arb_midref(res.value), self.value, prec(self)) + if test_zero and arb_contains_zero(res.value): + assert arb_contains_zero(self.value) + raise ValueError("ball contains zero") + return res + + def above_abs(self): + """ + Return an upper bound for the absolute value of this ball. + + .. SEEALSO:: :meth:`abs`, :meth:`below_abs` + + EXAMPLES:: + + sage: from sage.rings.real_arb import RealBallField + sage: b = RealBallField(8)(1/3).above_abs() + sage: b + [0.33 +/- 3.99e-3] + sage: b.is_exact() + True + sage: QQ(b) + 171/512 + """ + cdef RealBall res = self._new() + arb_get_abs_ubound_arf(arb_midref(res.value), self.value, prec(self)) + return res + # Precision def round(self): From 21d65cf4231aec7f605a55cf46548dc07eed852d Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Fri, 4 Sep 2015 13:39:33 +0200 Subject: [PATCH 1545/1872] ComplexBallField: minor documentation improvements --- src/sage/rings/complex_ball_acb.pyx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 2ff6fc28378..f6309837573 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -14,9 +14,9 @@ version 2, or later. .. SEEALSO:: - - :mod:`sage.rings.real_arb` - - :mod:`sage.rings.complex_interval_field` - - :mod:`sage.rings.complex_interval` + - :mod:`Real intervals using Arb ` + - :mod:`Complex interval field (using MPFI) ` + - :mod:`Complex intervals (using MPFI) ` Data Structure ============== @@ -313,7 +313,7 @@ class ComplexBallField(UniqueRepresentation, Parent): def construction(self): """ - Returns the construction of a complex ball field as the algebraic + Return the construction of a complex ball field as the algebraic closure of the real ball field with the same precision. EXAMPLES:: @@ -330,6 +330,8 @@ class ComplexBallField(UniqueRepresentation, Parent): def ngens(self): r""" + Return 1 as the only generator is the imaginary unit. + EXAMPLE:: sage: from sage.rings.complex_ball_acb import CBF @@ -340,6 +342,8 @@ class ComplexBallField(UniqueRepresentation, Parent): def gen(self, i): r""" + For i = 0, return the imaginary unit in this complex ball field. + EXAMPLE:: sage: from sage.rings.complex_ball_acb import CBF @@ -357,6 +361,9 @@ class ComplexBallField(UniqueRepresentation, Parent): def gens(self): r""" + Return the tuple of generators of this complex ball field, i.e. + ``(i,)``. + EXAMPLE:: sage: from sage.rings.complex_ball_acb import CBF From 9b915750aeb4331b53bcf73dd40494742e6d2a53 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Sep 2015 15:16:33 +0200 Subject: [PATCH 1546/1872] Trac #19063: Fix indentation in doctest Reviewer patch. --- src/sage/rings/complex_ball_acb.pyx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index f6309837573..0df89743225 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -573,17 +573,17 @@ class ComplexBallField(UniqueRepresentation, Parent): sage: from sage.rings.complex_ball_acb import CBF sage: CBF.some_elements() - [1.000000000000000, - -0.5000000000000000*I, - 1.000000000000000 + [0.3333333333333333 +/- 1.49e-17]*I, - [-0.3333333333333333 +/- 1.49e-17] + 0.2500000000000000*I, - [-2.175556475109056e+181961467118333366510562 +/- 1.29e+181961467118333366510545], - [+/- inf], - [+/- inf]*I, - [+/- inf] + [+/- inf]*I, - nan, - nan + nan*I, - [+/- inf] + nan*I] + [1.000000000000000, + -0.5000000000000000*I, + 1.000000000000000 + [0.3333333333333333 +/- 1.49e-17]*I, + [-0.3333333333333333 +/- 1.49e-17] + 0.2500000000000000*I, + [-2.175556475109056e+181961467118333366510562 +/- 1.29e+181961467118333366510545], + [+/- inf], + [+/- inf]*I, + [+/- inf] + [+/- inf]*I, + nan, + nan + nan*I, + [+/- inf] + nan*I] """ return [self(1), self(0, -1./2), self(1, 1./3), self(-1./3, 1./4), -self(1, 1)**(sage.rings.integer.Integer(2)**80), From cd5c605c070086e9ba9de1499cd8140b10b95544 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Sep 2015 15:16:59 +0200 Subject: [PATCH 1547/1872] Trac #19063: Simplify doctest Reviewer patch. --- src/sage/rings/complex_ball_acb.pyx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 0df89743225..8b45256f9c2 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -737,13 +737,12 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: from sage.rings.complex_ball_acb import ComplexBallField - sage: CBF = ComplexBallField() + sage: from sage.rings.complex_ball_acb import CBF sage: CBF(1/3) [0.3333333333333333 +/- 7.04e-17] sage: CBF(0, 1/3) [0.3333333333333333 +/- 7.04e-17]*I - sage: ComplexBallField()(1/3, 1/6) + sage: CBF(1/3, 1/6) [0.3333333333333333 +/- 7.04e-17] + [0.1666666666666667 +/- 7.04e-17]*I TESTS:: From 893af34c3b5bd9b39865005697bb08f8487ff733 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Sep 2015 15:17:38 +0200 Subject: [PATCH 1548/1872] Trac #19063: RESt formatting Reviewer patch --- src/sage/rings/complex_ball_acb.pyx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 8b45256f9c2..c67370b1b67 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -950,9 +950,9 @@ cdef class ComplexBall(RingElement): INPUT: - - ``test_zero`` (boolean, default False) -- if True, make sure that the - returned lower bound is positive, raising an error if the ball - contains zero. + - ``test_zero`` (boolean, default ``False``) -- if ``True``, + make sure that the returned lower bound is positive, raising + an error if the ball contains zero. .. SEEALSO:: :meth:`abs`, :meth:`above_abs` @@ -1552,10 +1552,8 @@ cdef class ComplexBall(RingElement): sage: from sage.rings.complex_ball_acb import CBF sage: from sage.rings.real_arb import RBF - sage: CBF(-2, 1)/CBF(1, 1/3) [-1.50000000000000 +/- 1.27e-15] + [1.500000000000000 +/- 8.94e-16]*I - sage: CBF(2+I)/CBF(0) [+/- inf] + [+/- inf]*I sage: CBF(1)/CBF(0) From dafd05e2c61b0240d796b1365ca415db645bf600 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Sep 2015 15:17:59 +0200 Subject: [PATCH 1549/1872] Trac #19063: Replace "nonzero" by "True" Reviewer patch. --- 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 c67370b1b67..06efcc2de7e 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -1364,7 +1364,7 @@ cdef class ComplexBall(RingElement): def contains_exact(self, other): """ - Returns nonzero *iff* the given number (or ball) ``other`` is contained + Return ``True`` *iff* the given number (or ball) ``other`` is contained in the interval represented by ``self``. Use ``other in self`` for a test that works for a wider range of inputs From 1d33fe0cff25df41ca845cd867094ec41a719238 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Sep 2015 15:32:08 +0200 Subject: [PATCH 1550/1872] fixup: true/false --- src/sage/rings/real_arb.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 4b7a9f3e446..9558479b335 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1357,9 +1357,9 @@ cdef class RealBall(RingElement): INPUT: - - ``test_zero`` (boolean, default False) -- if True, make sure that the - returned lower bound is positive, raising an error if the ball - contains zero. + - ``test_zero`` (boolean, default ``False``) -- if ``True``, + make sure that the returned lower bound is positive, raising + an error if the ball contains zero. .. SEEALSO:: :meth:`abs`, :meth:`above_abs` From df4337f5f55d6a9e66adce58f54ea5b4d9893394 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Sep 2015 15:39:52 +0200 Subject: [PATCH 1551/1872] Trac #19063: replace a few "int" by "bint" --- src/sage/libs/arb/acb_hypgeom.pxd | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/libs/arb/acb_hypgeom.pxd b/src/sage/libs/arb/acb_hypgeom.pxd index 0b3935c5851..7577adf7b84 100644 --- a/src/sage/libs/arb/acb_hypgeom.pxd +++ b/src/sage/libs/arb/acb_hypgeom.pxd @@ -14,13 +14,13 @@ cdef extern from "acb_hypgeom.h": void acb_hypgeom_pfq_direct(acb_t res, acb_srcptr a, long p, acb_srcptr b, long q, const acb_t z, long n, long prec) # void acb_hypgeom_pfq_series_direct(acb_poly_t res, const acb_poly_struct * a, long p, const acb_poly_struct * b, long q, const acb_poly_t z, int regularized, long n, long len, long prec) void acb_hypgeom_u_asymp(acb_t res, const acb_t a, const acb_t b, const acb_t z, long n, long prec) - int acb_hypgeom_u_use_asymp(const acb_t z, long prec) + bint acb_hypgeom_u_use_asymp(const acb_t z, long prec) # void acb_hypgeom_u_1f1_series(acb_poly_t res, const acb_poly_t a, const acb_poly_t b, const acb_poly_t z, long len, long prec) void acb_hypgeom_u_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, long prec) void acb_hypgeom_u(acb_t res, const acb_t a, const acb_t b, const acb_t z, long prec) - void acb_hypgeom_m_asymp(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, long prec) - void acb_hypgeom_m_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, long prec) - void acb_hypgeom_m(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, long prec) + void acb_hypgeom_m_asymp(acb_t res, const acb_t a, const acb_t b, const acb_t z, bint regularized, long prec) + void acb_hypgeom_m_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, bint regularized, long prec) + void acb_hypgeom_m(acb_t res, const acb_t a, const acb_t b, const acb_t z, bint regularized, long prec) void acb_hypgeom_erf_1f1a(acb_t res, const acb_t z, long prec) void acb_hypgeom_erf_1f1b(acb_t res, const acb_t z, long prec) void acb_hypgeom_erf_asymp(acb_t res, const acb_t z, long prec, long prec2) @@ -38,11 +38,11 @@ cdef extern from "acb_hypgeom.h": # void acb_hypgeom_bessel_k_0f1_series(acb_poly_t res, const acb_poly_t nu, const acb_poly_t z, long len, long prec) void acb_hypgeom_bessel_k_0f1(acb_t res, const acb_t nu, const acb_t z, long prec) void acb_hypgeom_bessel_k(acb_t res, const acb_t nu, const acb_t z, long prec) - void acb_hypgeom_gamma_upper_asymp(acb_t res, const acb_t s, const acb_t z, int modified, long prec) - void acb_hypgeom_gamma_upper_1f1a(acb_t res, const acb_t s, const acb_t z, int modified, long prec) - void acb_hypgeom_gamma_upper_1f1b(acb_t res, const acb_t s, const acb_t z, int modified, long prec) - void acb_hypgeom_gamma_upper_singular(acb_t res, long s, const acb_t z, int modified, long prec) - void acb_hypgeom_gamma_upper(acb_t res, const acb_t s, const acb_t z, int modified, long prec) + void acb_hypgeom_gamma_upper_asymp(acb_t res, const acb_t s, const acb_t z, bint modified, long prec) + void acb_hypgeom_gamma_upper_1f1a(acb_t res, const acb_t s, const acb_t z, bint modified, long prec) + void acb_hypgeom_gamma_upper_1f1b(acb_t res, const acb_t s, const acb_t z, bint modified, long prec) + void acb_hypgeom_gamma_upper_singular(acb_t res, long s, const acb_t z, bint modified, long prec) + void acb_hypgeom_gamma_upper(acb_t res, const acb_t s, const acb_t z, bint modified, long prec) void acb_hypgeom_expint(acb_t res, const acb_t s, const acb_t z, long prec) void acb_hypgeom_ei_asymp(acb_t res, const acb_t z, long prec) void acb_hypgeom_ei_2f2(acb_t res, const acb_t z, long prec) From a50fde3b9ef95528168d05a34a92c69df247dbcf Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Sep 2015 15:46:37 +0200 Subject: [PATCH 1552/1872] Trac #19063: Replace interval by ball in title --- 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 06efcc2de7e..a9b5762e50b 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -1,5 +1,5 @@ r""" -Arbitrary Precision Complex Intervals using Arb +Arbitrary Precision Complex Balls using Arb AUTHORS: From e3233c506eb7318d424ff8b1a4c437f79f55732d Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Tue, 8 Sep 2015 14:30:58 +0200 Subject: [PATCH 1553/1872] #19063 Implement reviewer's comments --- src/sage/rings/complex_ball_acb.pyx | 91 ++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index a9b5762e50b..5713e8a656a 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -579,7 +579,7 @@ class ComplexBallField(UniqueRepresentation, Parent): [-0.3333333333333333 +/- 1.49e-17] + 0.2500000000000000*I, [-2.175556475109056e+181961467118333366510562 +/- 1.29e+181961467118333366510545], [+/- inf], - [+/- inf]*I, + [0.3333333333333333 +/- 1.49e-17] + [+/- inf]*I, [+/- inf] + [+/- inf]*I, nan, nan + nan*I, @@ -587,7 +587,7 @@ class ComplexBallField(UniqueRepresentation, Parent): """ return [self(1), self(0, -1./2), self(1, 1./3), self(-1./3, 1./4), -self(1, 1)**(sage.rings.integer.Integer(2)**80), - self('inf'), self(1/3, 'inf'), self('inf', 'inf'), + self('inf'), self(1./3, 'inf'), self('inf', 'inf'), self('nan'), self('nan', 'nan'), self('inf', 'nan')] cdef inline bint _do_sig(long prec): @@ -682,7 +682,7 @@ cdef class ComplexBall(RingElement): cdef fmpz_t tmpz cdef fmpq_t tmpq - Element.__init__(self, parent) + RingElement.__init__(self, parent) if x is None: return @@ -832,6 +832,11 @@ cdef class ComplexBall(RingElement): r""" Convert this complex ball to a complex number. + INPUT: + + - ``parent`` - :class:`~sage.rings.complex_field.ComplexField_class`, + target parent. + EXAMPLES:: sage: from sage.rings.complex_ball_acb import CBF @@ -845,10 +850,15 @@ cdef class ComplexBall(RingElement): def _real_mpfi_(self, parent): r""" - Try to convert this complex ball to a real number. + Try to convert this complex ball to a real interval. Fail if the imaginary part is not exactly zero. + INPUT: + + - ``parent`` - :class:`~sage.rings.real_mpfi.RealIntervalField_class`, + target parent. + EXAMPLES:: sage: from sage.rings.complex_ball_acb import CBF @@ -871,6 +881,11 @@ cdef class ComplexBall(RingElement): Fail if the imaginary part is not exactly zero. + INPUT: + + - ``parent`` - :class:`~sage.rings.real_mpfr.RealField_class`, + target parent. + EXAMPLES:: sage: from sage.rings.complex_ball_acb import CBF @@ -1021,8 +1036,15 @@ cdef class ComplexBall(RingElement): def mid(self): """ - Return the floating-point complex number formed by the centers of the - real and imaginary parts of this ball. + Return the midpoint of this ball. + + OUTPUT: + + :class:`~sage.rings.complex_number.ComplexNumber`, floating-point + complex number formed by the centers of the real and imaginary parts of + this ball. + + .. SEEALSO:: :meth:`squash` EXAMPLES:: @@ -1050,6 +1072,10 @@ cdef class ComplexBall(RingElement): """ Return an exact ball with the same midpoint as this ball. + OUTPUT: + + A :class:`ComplexBall`. + .. SEEALSO:: :meth:`mid` EXAMPLES:: @@ -1326,14 +1352,22 @@ cdef class ComplexBall(RingElement): def identical(self, ComplexBall other): """ - Return True iff ``self`` and ``other`` are equal as set, i.e. if their + Return whether ``self`` and ``other`` represent the same ball. + + INPUT: + + - ``other`` -- a :class:`ComplexBall`. + + OUTPUT: + + Return True iff ``self`` and ``other`` are equal as sets, i.e. if their real and imaginary parts each have the same midpoint and radius. Note that this is not the same thing as testing whether both ``self`` - and ``other`` certainly represent the complex real number, unless either - ``self`` or ``other`` is exact (and neither contains NaN). To test - whether both operands might represent the same mathematical quantity, - use :meth:`overlaps` or :meth:`contains`, depending on the + and ``other`` certainly represent the complex real number, unless + either ``self`` or ``other`` is exact (and neither contains NaN). To + test whether both operands might represent the same mathematical + quantity, use :meth:`overlaps` or ``in``, depending on the circumstance. EXAMPLES:: @@ -1350,6 +1384,10 @@ cdef class ComplexBall(RingElement): """ Return True iff ``self`` and ``other`` have some point in common. + INPUT: + + - ``other`` -- a :class:`ComplexBall`. + EXAMPLES:: sage: from sage.rings.complex_ball_acb import CBF @@ -1364,11 +1402,18 @@ cdef class ComplexBall(RingElement): def contains_exact(self, other): """ - Return ``True`` *iff* the given number (or ball) ``other`` is contained - in the interval represented by ``self``. + Return ``True`` *iff* ``other`` is contained in ``self``. + + INPUT: - Use ``other in self`` for a test that works for a wider range of inputs - but may return false negatives. + - ``other`` -- :class:`ComplexBall`, + :class:`~sage.rings.integer.Integer`, + or :class:`~sage.rings.rational.Rational` + + .. SEEALSO:: + + Use ``other in self`` for a test that works for a wider range of + inputs but may return false negatives. EXAMPLES:: @@ -1376,8 +1421,6 @@ cdef class ComplexBall(RingElement): sage: from sage.rings.real_arb import RealBallField sage: CBF(RealBallField(100)(1/3), 0).contains_exact(1/3) True - sage: 1/3 in CBF(RealBallField(100)(1/3), 0) - False sage: CBF(1).contains_exact(1) True sage: CBF(1).contains_exact(CBF(1)) @@ -1409,8 +1452,9 @@ cdef class ComplexBall(RingElement): """ Return True if ``other`` can be verified to be contained in ``self``. - The test is done using interval arithmetic with a precision determined - by the parent of ``self`` and may return false negatives. + Depending on the type of ``other``, the test may use interval + arithmetic with a precision determined by the parent of ``self`` and + may return false negatives. .. SEEALSO:: :meth:`contains_exact` @@ -1423,10 +1467,15 @@ cdef class ComplexBall(RingElement): A false negative:: sage: from sage.rings.real_arb import RealBallField - sage: 1/3 in CBF(RealBallField(100)(1/3), 0) + sage: RLF(1/3) in CBF(RealBallField(100)(1/3), 0) False """ - return self.contains_exact(self._parent(other)) + if not isinstance(other, ( + ComplexBall, + sage.rings.integer.Integer, + sage.rings.rational.Rational)): + other = self._parent(other) + return self.contains_exact(other) # Arithmetic From fa41787b7f670f82ba79ad2fa9ebe67ef5c2eb24 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 24 Sep 2015 15:02:19 +0200 Subject: [PATCH 1554/1872] Trac #19063: fix doctests on 32 bit --- src/sage/rings/complex_ball_acb.pyx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 5713e8a656a..7540f736738 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -1134,10 +1134,14 @@ cdef class ComplexBall(RingElement): sage: from sage.rings.complex_ball_acb import CBF sage: CBF(exp(I*pi/3)).accuracy() 51 - sage: CBF(I/2).accuracy() - 9223372036854775807 - sage: CBF('nan', 'inf').accuracy() - -9223372036854775807 + sage: CBF(I/2).accuracy() == CBF.base().maximal_accuracy() + True + sage: CBF('nan', 'inf').accuracy() == -CBF.base().maximal_accuracy() + True + + .. seealso:: + + :meth:`~sage.rings.real_arb.RealBallField.maximal_accuracy` """ return acb_rel_accuracy_bits(self.value) From f80c871157d115fffcd97b544fc6d2f1e0293c88 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 11:33:30 +0200 Subject: [PATCH 1555/1872] add log_string function --- src/sage/rings/asymptotic/misc.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index b902a94b405..7b91d558d18 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -499,3 +499,30 @@ def find_mergedoverlapping_index(A, B): return B[:i] + A + B[i+len(A):], B raise ValueError('Input does not have an overlap.') + + +def log_string(element, base=None): + r""" + Return a representation of the log of the given element to the + given base. + + INPUT: + + - ``element`` -- an object. + + - ``base`` -- an object or ``None``. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.misc import log_string + sage: log_string(3) + 'log(3)' + sage: log_string(3, base=42) + 'log(3, base=42)' + """ + basestr = ', base=' + str(base) if base else '' + return 'log(%s%s)' % (element, basestr) From 0ca6efda638f8a5819577629d3c360fcfd4a2f3c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 11:35:24 +0200 Subject: [PATCH 1556/1872] Trac #19094/#19083 comment 60, 11: correct wrong log and give log in errors a base --- src/sage/rings/asymptotic/growth_group.py | 40 ++++++++++++++++------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c4f93081df6..d8941696bce 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -693,21 +693,23 @@ def _log_(self, base=None): which is not contained in Growth Group QQ^x * x^ZZ * log(x)^ZZ * y^ZZ * log(y)^ZZ. """ + from misc import log_string + log_factor = self.log_factor(base=base) if not log_factor: - raise ArithmeticError('log(%s) is zero, ' + raise ArithmeticError('%s is zero, ' 'which is not contained in %s.' % - (self, self.parent())) + (log_string(self, base), self.parent())) if len(log_factor) != 1: - raise ArithmeticError('Calculating log(%s) results in a sum, ' + raise ArithmeticError('Calculating %s results in a sum, ' 'which is not contained in %s.' % - (self, self.parent())) + (log_string(self, base), self.parent())) g, c = log_factor[0] if c != 1: - raise ArithmeticError('When calculating log(%s) a factor %s != 1 ' + raise ArithmeticError('When calculating %s a factor %s != 1 ' 'appeared, which is not contained in %s.' % - (self, c, self.parent())) + (log_string(self, base), c, self.parent())) return g @@ -776,8 +778,10 @@ def _log_factor_(self, base=None): if hasattr(g, 'parent') and \ isinstance(g.parent(), GenericGrowthGroup): continue - raise ArithmeticError('Cannot build log(%s) since %s ' - 'is not in %s.' % (self, g, self.parent())) + from misc import log_string + raise ArithmeticError('Cannot build %s since %s ' + 'is not in %s.' % (log_string(self, base), + g, self.parent())) return log_factor @@ -2456,6 +2460,16 @@ def _log_factor_(self, base=None): ... ArithmeticError: Cannot build log(x) since log(x) is not in Growth Group x^QQ. + + :: + + sage: G = GrowthGroup('exp(x)^ZZ * x^ZZ') + sage: log(G('exp(x)'), base=2) + Traceback (most recent call last): + ... + ArithmeticError: When calculating log(exp(x), base=2) a factor + 1/log(2) != 1 appeared, which is not contained in + Growth Group exp(x)^ZZ * x^ZZ. """ if self.is_one(): return tuple() @@ -2471,14 +2485,16 @@ def _log_factor_(self, base=None): base is not None and b == str(base): return ((e, coefficient),) - if base is None and var.startswith('exp('): + if var.startswith('exp('): assert(var[-1] == ')') - return ((var[4:-1], coefficient),) + v = var[4:-1] + else: + v = 'log(%s)' % (var,) if base is not None: from sage.functions.log import log coefficient = coefficient / log(base) - return (('log(%s)' % (self.parent()._var_,), coefficient),) + return ((v, coefficient),) def _rpow_element_(self, base): @@ -3109,7 +3125,7 @@ def _log_factor_(self, base=None): sage: G('4^x').log_factor(base=2) # indirect doctest Traceback (most recent call last): ... - ArithmeticError: Cannot build log(4^x) since x is not in + ArithmeticError: Cannot build log(4^x, base=2) since x is not in Growth Group QQ^x. """ if self.is_one(): From 71802dac512847136a46cf7a0f261e4240d44589 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 11:37:14 +0200 Subject: [PATCH 1557/1872] Trac #19094/#19083 comment 60, 8: rename to _create_element_in_extension_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 ++++++++-------- src/sage/rings/asymptotic/growth_group.py | 14 +++++++------- .../rings/asymptotic/growth_group_cartesian.py | 10 +++++----- src/sage/rings/asymptotic/term_monoid.py | 18 +++++++++--------- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 943588d20c8..f3a51687138 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1155,7 +1155,7 @@ def __invert__(self, precision=None): elif len(self.summands) == 1: element = next(self.summands.elements()) - return self.parent()._create_element_via_parent_( + return self.parent()._create_element_in_extension_( ~element, element.parent()) max_elem = tuple(self.summands.maximal_elements()) @@ -1169,7 +1169,7 @@ def __invert__(self, precision=None): if imax_elem.parent() is max_elem.parent(): new_self = self else: - new_self = self.parent()._create_element_via_parent_( + new_self = self.parent()._create_element_in_extension_( imax_elem, max_elem.parent()).parent()(self) one = new_self.parent().one() @@ -1326,7 +1326,7 @@ def __pow__(self, exponent, precision=None): if isinstance(exponent, AsymptoticExpansion) and element.is_constant(): return exponent.rpow(base=element.coefficient, precision=precision) try: - return self.parent()._create_element_via_parent_( + return self.parent()._create_element_in_extension_( element ** exponent, element.parent()) except (ArithmeticError, TypeError, ValueError): if not isinstance(exponent, AsymptoticExpansion): @@ -1446,7 +1446,7 @@ def log(self, base=None, precision=None): if self.is_one(): return P.zero() element = next(self.summands.elements()) - return sum(P._create_element_via_parent_(l, element.parent()) + return sum(P._create_element_in_extension_(l, element.parent()) for l in element.log_term(base=base)) max_elem = tuple(self.summands.maximal_elements()) @@ -1460,7 +1460,7 @@ def log(self, base=None, precision=None): if imax_elem.parent() is max_elem.parent(): new_self = self else: - new_self = P._create_element_via_parent_( + new_self = P._create_element_in_extension_( imax_elem, max_elem.parent()).parent()(self) one = new_self.parent().one() @@ -1580,7 +1580,7 @@ def rpow(self, base, precision=None): try: large_result = P.prod( - P._create_element_via_parent_(term.rpow(base), + P._create_element_in_extension_(term.rpow(base), term.parent()) for term in large_terms) except (TypeError, ValueError) as e: @@ -2048,7 +2048,7 @@ def _create_empty_summands_(): merge=absorption) - def _create_element_via_parent_(self, term, old_parent=None): + def _create_element_in_extension_(self, term, old_parent=None): r""" Create an element whose parent is chosen according to the input. @@ -2064,7 +2064,7 @@ def _create_element_via_parent_(self, term, old_parent=None): sage: A = AsymptoticRing('z^ZZ', ZZ) sage: term = next(A.an_element().summands.elements_topological()) - sage: A._create_element_via_parent_(term, A) + sage: A._create_element_in_extension_(term, A) O(z) """ if old_parent is None or term.parent() is old_parent: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index d8941696bce..b25b36d2324 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1630,7 +1630,7 @@ def some_elements(self): for e in self.base().some_elements()) - def _create_element_via_parent_(self, raw_element): + def _create_element_in_extension_(self, raw_element): r""" Create an element whose parent is chosen according to the input ``raw_element``. @@ -1645,9 +1645,9 @@ def _create_element_via_parent_(self, raw_element): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') - sage: G._create_element_via_parent_(3).parent() + sage: G._create_element_in_extension_(3).parent() Growth Group z^ZZ - sage: G._create_element_via_parent_(1/2).parent() + sage: G._create_element_in_extension_(1/2).parent() Growth Group z^QQ """ if raw_element.parent() is self.base(): @@ -2398,7 +2398,7 @@ def __invert__(self): sage: e2 == ~e1 True """ - return self.parent()._create_element_via_parent_(-self.exponent) + return self.parent()._create_element_in_extension_(-self.exponent) def __pow__(self, exponent): @@ -2432,7 +2432,7 @@ def __pow__(self, exponent): sage: b^12 x^42 """ - return self.parent()._create_element_via_parent_(self.exponent * exponent) + return self.parent()._create_element_in_extension_(self.exponent * exponent) def _log_factor_(self, base=None): @@ -3069,7 +3069,7 @@ def __invert__(self): sage: (~P(raw_element=1)).parent() Growth Group QQ^x """ - return self.parent()._create_element_via_parent_(1 / self.base) + return self.parent()._create_element_in_extension_(1 / self.base) def __pow__(self, exponent): @@ -3099,7 +3099,7 @@ def __pow__(self, exponent): sage: b^12 117649^x """ - return self.parent()._create_element_via_parent_(self.base ** exponent) + return self.parent()._create_element_in_extension_(self.base ** exponent) def _log_factor_(self, base=None): diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 7d9e7b38f8a..45cfbb084ea 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -342,7 +342,7 @@ def some_elements(self): izip(*tuple(F.some_elements() for F in self.cartesian_factors()))) - def _create_element_via_parent_(self, element): + def _create_element_in_extension_(self, element): r""" Create an element whose parent is chosen according to the input ``element``. @@ -359,9 +359,9 @@ def _create_element_via_parent_(self, element): sage: G = GrowthGroup('z^ZZ * log(z)^ZZ') sage: z = G('z')[0] sage: lz = G('log(z)')[1] - sage: G._create_element_via_parent_((z^3, lz)).parent() + sage: G._create_element_in_extension_((z^3, lz)).parent() Growth Group z^ZZ * log(z)^ZZ - sage: G._create_element_via_parent_((z^(1/2), lz)).parent() + sage: G._create_element_in_extension_((z^(1/2), lz)).parent() Growth Group z^QQ * log(z)^ZZ """ factors = self.cartesian_factors() @@ -898,7 +898,7 @@ def __pow__(self, exponent): sage: (x^(21/5) * log(x)^7)^(1/42) # indirect doctest x^(1/10)*log(x)^(1/6) """ - return self.parent()._create_element_via_parent_( + return self.parent()._create_element_in_extension_( tuple(x ** exponent for x in self.cartesian_factors())) @@ -1113,7 +1113,7 @@ def __invert__(self): sage: (~g).parent() Growth Group QQ^x * x^ZZ """ - return self.parent()._create_element_via_parent_( + return self.parent()._create_element_in_extension_( tuple(~x for x in self.cartesian_factors())) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 898a986e9f0..6f0aa937b06 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -634,7 +634,7 @@ def _calculate_pow_(self, exponent, coefficient=None): raise combine_exceptions( ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) - return self.parent()._create_element_via_parent_(g, coefficient) + return self.parent()._create_element_in_extension_(g, coefficient) def can_absorb(self, other): @@ -905,7 +905,7 @@ def _log_growth_(self, base=None): :meth:`ExactTerm.log_term`, :meth:`OTerm.log_term`. """ - return tuple(self.parent()._create_element_via_parent_(g, c) + return tuple(self.parent()._create_element_in_extension_(g, c) for g, c in self.growth.log_factor(base=base)) @@ -1631,7 +1631,7 @@ def _create_element_(self, growth, coefficient): return self.element_class(self, growth) - def _create_element_via_parent_(self, growth, coefficient): + def _create_element_in_extension_(self, growth, coefficient): r""" Create an element whose parent is chosen according to the input. @@ -1647,9 +1647,9 @@ def _create_element_via_parent_(self, growth, coefficient): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') sage: T = TermMonoid('exact', G, ZZ) - sage: T._create_element_via_parent_(G.an_element(), 3) + sage: T._create_element_in_extension_(G.an_element(), 3) 3*z - sage: T._create_element_via_parent_(G.an_element(), 3/2).parent() + sage: T._create_element_in_extension_(G.an_element(), 3/2).parent() Exact Term Monoid z^ZZ with coefficients in Rational Field """ if (growth.parent() is self.growth_group) and \ @@ -2547,7 +2547,7 @@ def _log_coefficient_(self, base=None): if self.coefficient.is_one(): return tuple() from sage.functions.log import log - return (self.parent()._create_element_via_parent_( + return (self.parent()._create_element_in_extension_( self.parent().growth_group.one(), log(self.coefficient, base=base)),) @@ -2894,7 +2894,7 @@ def __invert__(self): raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' 'cannot be inverted.' % (self, self.coefficient)) g = ~self.growth - return self.parent()._create_element_via_parent_(g, c) + return self.parent()._create_element_in_extension_(g, c) def __pow__(self, exponent): @@ -3181,10 +3181,10 @@ def rpow(self, base): if self.is_constant(): if not hasattr(base, 'parent'): base = P.coefficient_ring(base) - return P._create_element_via_parent_( + return P._create_element_in_extension_( P.growth_group.one(), base ** self.coefficient) - elem = P._create_element_via_parent_( + elem = P._create_element_in_extension_( self.growth.rpow(base), P.coefficient_ring.one()) return elem ** self.coefficient From e2285e7012435f27c5ed0d2dfab34db255912244 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 11:39:54 +0200 Subject: [PATCH 1558/1872] Trac #19094/#19083 comment 60, 8: rewrite description of _create_element_in_extension_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 ++- src/sage/rings/asymptotic/growth_group.py | 4 ++-- src/sage/rings/asymptotic/growth_group_cartesian.py | 4 ++-- src/sage/rings/asymptotic/term_monoid.py | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index f3a51687138..d683d196fe9 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2050,7 +2050,8 @@ def _create_empty_summands_(): def _create_element_in_extension_(self, term, old_parent=None): r""" - Create an element whose parent is chosen according to the input. + Create an element in an extension of this asymptotic ring which + is chosen according to the input. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index b25b36d2324..ab5279d4b04 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1632,8 +1632,8 @@ def some_elements(self): def _create_element_in_extension_(self, raw_element): r""" - Create an element whose parent is chosen according to the input - ``raw_element``. + Create an element in an extension of this growth group which + is chosen according to the input ``raw_element``. INPUT: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 45cfbb084ea..092a8de45b0 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -344,8 +344,8 @@ def some_elements(self): def _create_element_in_extension_(self, element): r""" - Create an element whose parent is chosen according to the input - ``element``. + Create an element in an extension of this cartesian product of + growth groups which is chosen according to the input ``element``. INPUT: diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 6f0aa937b06..0e4d241867d 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1633,7 +1633,8 @@ def _create_element_(self, growth, coefficient): def _create_element_in_extension_(self, growth, coefficient): r""" - Create an element whose parent is chosen according to the input. + Create an element in an extension of this term monoid which + is chosen according to the input. INPUT: From 4cb775fbe20b1e44f5db2bef973f1763c80c6e35 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 11:51:43 +0200 Subject: [PATCH 1559/1872] Trac #19094/#19083 comment 60, 12: add doctest in _rpow_element to test parameter base --- src/sage/rings/asymptotic/growth_group.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ab5279d4b04..59f01529ed4 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2535,6 +2535,13 @@ def _rpow_element_(self, base): x sage: rp.parent() Growth Group x^ZZ + + :: + + sage: G = GrowthGroup('log(x)^SR') + sage: lx = G('log(x)') + sage: lx._rpow_element_(2) + x^(log(2)) """ var = str(self.parent()._var_) if not(var.startswith('log(') and self.exponent.is_one()): From 51f796c2470150834d6949e408e257469f18afbd Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 11:55:36 +0200 Subject: [PATCH 1560/1872] Trac #19094/#19083 comment 60, 12: document _rpow_element 2^x --- src/sage/rings/asymptotic/growth_group.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 59f01529ed4..be2ee8c8fb3 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2528,6 +2528,13 @@ def _rpow_element_(self, base): Traceback (most recent call last): ... ValueError: Variable %s is not a log of something. + + The previous example does not work since the result would not + live in a monomial growth group. When using :meth:`rpow`, this + case is handeled by the calling method :meth:`_rpow_`. + + :: + sage: G = GrowthGroup('log(x)^ZZ') sage: lx = G(raw_element=1); lx log(x) From 3b724240f9aba068d4495b4600c3f4a9190d5043 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 16 Oct 2015 12:35:21 +0200 Subject: [PATCH 1561/1872] trac #19390: Illustration of the dangers of nonsymetric functions in the graph constructor --- src/sage/graphs/graph.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index ef8fb39d882..f96bc5245ec 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -819,6 +819,21 @@ class Graph(GenericGraph): sage: Graph(g).edges() # optional - python_igraph [(0, 1, {'name': 'a', 'weight': 1}), (0, 2, {'name': 'b', 'weight': 3})] + + When defining an undirected graph from a function ``f``, it is *very* + important that ``f`` be symmetric. If it is not, anything can happen:: + + sage: f_sym = lambda x,y : abs(x-y) == 1 + sage: f_nonsym = lambda x,y : (x-y) == 1 + sage: G_sym = Graph([[4,6,1,5,3,7,2,0], f_sym]) + sage: G_sym.is_isomorphic(graphs.PathGraph(8)) + True + sage: G_nonsym = Graph([[4,6,1,5,3,7,2,0], f_nonsym]) + sage: G_nonsym.size() + 4 + sage: G_nonsym.is_isomorphic(G_sym) + False + By default, graphs are mutable and can thus not be used as a dictionary key:: From 2f110dbcba55c31032663e2b66a3d118abed3226 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 12:38:26 +0200 Subject: [PATCH 1562/1872] Trac #19094/#19083 comment 60, 13: simplify ExponentialGrowthElement._repr_ --- src/sage/rings/asymptotic/growth_group.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index be2ee8c8fb3..b89f9075d96 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3008,6 +3008,16 @@ def _repr_(self): sage: P((-1)^x) # indirect doctest (-1)^x + + :: + + sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup + sage: G = ExponentialGrowthGroup(ZZ['x'], 'y'); G + Growth Group ZZ[x]^y + sage: G('(1-x)^y') + (-x + 1)^y + sage: G('(1+x)^y') + (x + 1)^y """ from sage.rings.integer_ring import ZZ from misc import repr_op @@ -3015,10 +3025,7 @@ def _repr_(self): var = repr(self.parent()._var_) if self.base.is_one(): return '1' - elif not any(s in str(self.base) for s in '-/^'): - return str(self.base) + repr_op('', '^', var) - else: - return '(' + str(self.base) + ')' + repr_op('', '^', var) + return repr_op(str(self.base), '^', var) def _mul_(self, other): From 4c49d029e7a7998190c8d0c7409ebec79ece56af Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 12:41:42 +0200 Subject: [PATCH 1563/1872] Trac #19094/#19083 comment 60, 14: rewrite keyword arguments documentation of GrowthGroupFactory --- src/sage/rings/asymptotic/growth_group.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index b89f9075d96..4ab5ee3e685 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3480,9 +3480,10 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): - ``specification`` -- a string. - keyword arguments are passed on to the growth group - constructor. If not specified, then the argument + constructor. + If the keyword ``ignore_variables`` is not specified, then the ``ignore_variables=('e',)`` (to ignore ``e`` as a variable name) - is added. + is used. OUTPUT: From d2cc73a4aa79c5d27b888502026b44f90e751755 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 12:44:08 +0200 Subject: [PATCH 1564/1872] add forgotten "EXAMPLES::" line --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 ++ src/sage/rings/asymptotic/growth_group.py | 2 ++ src/sage/rings/asymptotic/growth_group_cartesian.py | 2 ++ src/sage/rings/asymptotic/term_monoid.py | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d683d196fe9..fd759470e0c 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2063,6 +2063,8 @@ def _create_element_in_extension_(self, term, old_parent=None): An element. + EXAMPLES:: + sage: A = AsymptoticRing('z^ZZ', ZZ) sage: term = next(A.an_element().summands.elements_topological()) sage: A._create_element_in_extension_(term, A) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 4ab5ee3e685..2c1dc272046 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1643,6 +1643,8 @@ def _create_element_in_extension_(self, raw_element): An element. + EXAMPLES:: + sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') sage: G._create_element_in_extension_(3).parent() diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 092a8de45b0..1432ce803a6 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -355,6 +355,8 @@ def _create_element_in_extension_(self, element): An element. + EXAMPLES:: + sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ * log(z)^ZZ') sage: z = G('z')[0] diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 0e4d241867d..0cd95178707 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1644,6 +1644,8 @@ def _create_element_in_extension_(self, growth, coefficient): An element. + EXAMPLES:: + sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: G = GrowthGroup('z^ZZ') From 787e775860ab07c3fd577355092369731bef53c1 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 4 Oct 2015 11:50:08 +0200 Subject: [PATCH 1565/1872] trac #19344: A (625, 468, 353, 342)-strongly regular graph --- src/sage/graphs/strongly_regular_db.pyx | 36 ++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index c41bee69738..1cd0bcb33ee 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1983,6 +1983,39 @@ def SRG_625_416_279_272(): M = Matrix(GF(5),[list(l) for l in x]) return strongly_regular_from_two_weight_code(LinearCode(M)) +def SRG_625_468_353_342(): + r""" + Return a `(625, 468, 353, 342)`-strongly regular graph. + + This graph is built from a two-weight code presented in [BJ03]_ (cf. Theorem + 4.1). + + .. SEEALSO:: + + :func:`strongly_regular_from_two_weight_code` -- build a strongly regular graph from + a two-weight code. + + EXAMPLE:: + + sage: from sage.graphs.strongly_regular_db import SRG_625_468_353_342 + sage: G = SRG_625_468_353_342() # long time + sage: G.is_strongly_regular(parameters=True) # long time + (625, 468, 353, 342) + + REFERENCE: + + .. [BJ03] I. Bouyukliev and S. Juriaan, + Some new results on optimal codes over `F_5`, + Designs, Codes and Cryptography 30, no. 1 (2003): 97-111, + http://www.moi.math.bas.bg/moiuser/~iliya/pdf_site/gf5srev.pdf + """ + x = ("111111111111111111111111111111000000000", + "111111222222333333444444000000111111000", + "223300133440112240112240133440123400110", + "402340414201142301132013234230044330401") + M = Matrix(GF(5),[list(l) for l in x]) + return strongly_regular_from_two_weight_code(LinearCode(M)) + def SRG_243_220_199_200(): r""" Return a `(243, 220, 199, 200)`-strongly regular graph. @@ -2582,8 +2615,9 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (512, 219, 106, 84): [SRG_512_219_106_84], (512, 73, 12, 10): [SRG_512_73_12_10], (560, 208, 72, 80): [SRG_560_208_72_80], - (625, 416, 279,272): [SRG_625_416_279_272], (625, 364, 213,210): [SRG_625_364_213_210], + (625, 416, 279,272): [SRG_625_416_279_272], + (625, 468, 353,342): [SRG_625_468_353_342], (729, 336, 153,156): [SRG_729_336_153_156], (729, 616, 523,506): [SRG_729_616_523_506], (729, 420, 243,240): [SRG_729_420_243_240], From 498dbad4ca50f6b4f6b87e2cd8d85543253c2f09 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 12:46:05 +0200 Subject: [PATCH 1566/1872] Trac #19094/#19083 comment 60, 15: add a doctest to GenericProduct._create_element_via_parent_ --- src/sage/rings/asymptotic/growth_group_cartesian.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 1432ce803a6..8f9dce9ea3f 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -365,6 +365,14 @@ def _create_element_in_extension_(self, element): Growth Group z^ZZ * log(z)^ZZ sage: G._create_element_in_extension_((z^(1/2), lz)).parent() Growth Group z^QQ * log(z)^ZZ + + :: + + sage: G._create_element_in_extension_((3, 3, 3)) + Traceback (most recent call last): + ... + ValueError: Cannot create (3, 3, 3) as a cartesian product like + Growth Group z^ZZ * log(z)^ZZ. """ factors = self.cartesian_factors() if len(element) != len(factors): From e8ad893715b0dfc8a3907a05382b0c1cba57b818 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 12:47:37 +0200 Subject: [PATCH 1567/1872] Trac #19094/#19083 comment 60, 16: delte misplaced statement in docstring --- src/sage/rings/asymptotic/growth_group_cartesian.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 8f9dce9ea3f..7e86897c9c3 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -886,9 +886,7 @@ def __pow__(self, exponent): INPUT: - - ``exponent`` -- a number. This can be anything that is a - valid right hand side of ``*`` with elements of the - parent's base. + - ``exponent`` -- a number. OUTPUT: From d3d2a63a63d2a89d84fcd42508f3b06eca5766df Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 13:20:09 +0200 Subject: [PATCH 1568/1872] Trac #19094/#19083 comment 64, 21: GenericTerm.log_term remove note box --- src/sage/rings/asymptotic/term_monoid.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 0cd95178707..b4374fae794 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -835,11 +835,6 @@ def log_term(self, base=None): A tuple of terms. - .. NOTE:: - - This method returns a tuple with the summands that come from - applying the rule `\log(x\cdot y) = \log(x) + \log(y)`. - .. NOTE:: This abstract method raises a From 0d2ca6cd4c30085ba2e77f68acc96d4aa54f9574 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 13:45:07 +0200 Subject: [PATCH 1569/1872] Trac #19094/#19083 comment 64, 22: doctest error inputs of __classcall__ --- src/sage/rings/asymptotic/term_monoid.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 9f06492c412..5029d065fe4 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1305,6 +1305,25 @@ def __classcall__(cls, growth_group, coefficient_ring, category=None): sage: from sage.rings.asymptotic.misc import underlying_class sage: underlying_class(T)(G, QQ) is T True + + :: + + sage: GenericTermMonoid(None, ZZ) # indirect doctest + Traceback (most recent call last): + ... + ValueError: No growth group specified. + sage: GenericTermMonoid(int, ZZ) # indirect doctest + Traceback (most recent call last): + ... + TypeError: is not a valid growth group. + sage: GenericTermMonoid(G, None) # indirect doctest + Traceback (most recent call last): + ... + ValueError: No coefficient ring specified. + sage: GenericTermMonoid(G, int) # indirect doctest + Traceback (most recent call last): + ... + TypeError: is not a valid coefficient ring. """ if growth_group is None: raise ValueError('No growth group specified.') From 310641e2f7c733e3f70d63e952f411e3c6e385f1 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 13:47:43 +0200 Subject: [PATCH 1570/1872] Trac #19094/#19083 comment 64, 23: extend doc of GenericTermMonoid._coerce_map_from_ --- src/sage/rings/asymptotic/term_monoid.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 5029d065fe4..03716459b5f 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1457,8 +1457,10 @@ def _coerce_map_from_(self, S): .. NOTE:: Another generic term monoid ``S`` coerces into this term - monoid if and only if the growth group of ``S`` coerces - into the growth group of this term monoid. + monoid if and only if both, the growth group of ``S`` coerces + into the growth group of this term monoid and the coefficient + ring of ``S`` coerces into the coefficient ring of this term + monoid. EXAMPLES:: From e458cd46931685c6a8034119e4981166995ee909 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 14:04:27 +0200 Subject: [PATCH 1571/1872] Trac #19094/#19083 comment 64, 25: add doctests to GenericTermMonoid._split_growth_and_coefficient_ --- src/sage/rings/asymptotic/term_monoid.py | 37 ++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 03716459b5f..4f58dbcb693 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1702,10 +1702,41 @@ def _split_growth_and_coefficient_(self, data): sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G_ZZ = GrowthGroup('x^ZZ') - sage: T_ZZ = TermMonoid('exact', G_ZZ, QQ) - sage: T_ZZ._split_growth_and_coefficient_('2*x^3') + sage: G = GrowthGroup('x^ZZ') + sage: T = TermMonoid('exact', G, QQ) + sage: T._split_growth_and_coefficient_('2*x^3') (x^3, 2) + + :: + + sage: T._split_growth_and_coefficient_('2.7 * x^3') + Traceback (most recent call last): + ... + ValueError: Factor 2.7 of 2.7 * x^3 is neither a coefficient + (in Rational Field) nor growth (in Growth Group x^ZZ). + + :: + + sage: G = GrowthGroup('QQ^x * x^ZZ * log(x)^ZZ') + sage: T = TermMonoid('exact', G, QQ) + sage: T._split_growth_and_coefficient_('3/4 * 2^x * log(x)') + (2^x*log(x), 3/4) + sage: T._split_growth_and_coefficient_('3 * x^2 * 4 * log(x) * x') + (x^3*log(x), 12) + sage: var('x') + x + sage: T._split_growth_and_coefficient_(log(x)^5 * x^2 * 4) + (x^2*log(x)^5, 4) + + :: + + sage: T = TermMonoid('exact', G, SR) + sage: T._split_growth_and_coefficient_(log(x)^5 * x^2 * 4) + (x^2*log(x)^5, 4) + sage: var('y') + y + sage: T._split_growth_and_coefficient_(2^x * y * 4) + (2^x, 4*y) """ factors = self._get_factors_(data) From d492447b7922c9d2a2fbd91f5f48cafff924499c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 14:28:32 +0200 Subject: [PATCH 1572/1872] Trac #19094/#19083 comment 64, 27: document assumption 0 = O(g) --- src/sage/rings/asymptotic/term_monoid.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 4f58dbcb693..b67de25d237 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -578,6 +578,12 @@ def _calculate_pow_test_zero_(self, exponent): ZeroDivisionError: Cannot take O(z) to exponent -1. > *previous* ZeroDivisionError: rational division by zero """ + # This assumes `0 = O(g)` for any `g` in the growth group, which + # is valid in the case of a variable going to `\infty`. + # Once non-standard asymptoptics are supported, this has to be + # rewritten. + # See also #19083, comment 64, 27. + zero = self.parent().coefficient_ring.zero() try: zero ** exponent From c6fdfc00720a5bcb35de2a7bb1cb23c177bcd1eb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 14:33:04 +0200 Subject: [PATCH 1573/1872] Trac #19094/#19083 comment 64, 27: add test in __pow__ to check errors --- src/sage/rings/asymptotic/term_monoid.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index b67de25d237..ab201e0aa89 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2006,6 +2006,11 @@ def __pow__(self, exponent): O(z^3) sage: t^(1/2) # indirect doctest O(z^(1/2)) + sage: t^(-1) # indirect doctest + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot take O(z) to exponent -1. + > *previous* ZeroDivisionError: rational division by zero """ return self._calculate_pow_test_zero_(exponent) From cacd890d2d00c7f7882805f5d9f97f01f2eb9824 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 14:36:21 +0200 Subject: [PATCH 1574/1872] Trac #19094/#19083 comment 64, 28: test error in OTermMonoid._create_element_ --- src/sage/rings/asymptotic/term_monoid.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index ab201e0aa89..1c5b26c2121 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2297,10 +2297,17 @@ def _create_element_(self, growth, coefficient): sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: from sage.rings.asymptotic.growth_group import GrowthGroup - sage: G_ZZ = GrowthGroup('x^ZZ') - sage: T_ZZ = TermMonoid('O', G_ZZ, QQ) - sage: T_ZZ(G_ZZ.gen()) # indirect doctest + sage: G = GrowthGroup('x^ZZ') + sage: T = TermMonoid('O', G, QQ) + sage: T(G.gen()) # indirect doctest O(x) + sage: T(G.gen(), SR.var('y')) # indirect doctest + Traceback (most recent call last): + ... + ValueError: Cannot create O(x) since given coefficient y + is not valid in O-Term Monoid x^ZZ with implicit coefficients in + Rational Field. + > *previous* TypeError: unable to convert y to a rational """ if coefficient is not None: try: From 8f57fa101e0749ee15f0db3a6577b14b70c0ab8d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 14:37:44 +0200 Subject: [PATCH 1575/1872] Trac #19083: Insert external link --- src/sage/rings/asymptotic/misc.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 7e6258be621..2abee723684 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -161,9 +161,10 @@ def split_str_by_op(string, op, strip_parentheses=True): - ``string`` -- a string. - - ``op`` -- a string. This is used by ``str.split``. Thus, if this - is ``None``, then any whitespace string is a separator and empty - strings are removed from the result. + - ``op`` -- a string. This is used by + :python:`str.split `. + Thus, if this is ``None``, then any whitespace string is a + separator and empty strings are removed from the result. - ``strip_parentheses`` -- (default: ``True``) a boolean. From 6c001634f4d1839bed8056ba69ca86bc2ca3489d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 14:38:13 +0200 Subject: [PATCH 1576/1872] Trac #19083: minor language issues --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- src/sage/rings/asymptotic/growth_group_cartesian.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index f4bfb35df49..fe776d59d65 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2525,7 +2525,7 @@ def _rpow_element_(self, base): .. NOTE:: - The parent of the result can be different to the parent + The parent of the result can be different from the parent of this element. A ``ValueError`` is raised if the calculation is not possible @@ -3494,7 +3494,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): - keyword arguments are passed on to the growth group constructor. - If the keyword ``ignore_variables`` is not specified, then the + If the keyword ``ignore_variables`` is not specified, then ``ignore_variables=('e',)`` (to ignore ``e`` as a variable name) is used. diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 1d50749f86f..97cbbfbdb5b 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1029,7 +1029,7 @@ def _rpow_element_(self, base): .. NOTE:: - The parent of the result can be different to the parent + The parent of the result can be different from the parent of this element. A ``ValueError`` is raised if the calculation is not possible From 51f699d5209bae5fb70201e1da0df0b0442ad40d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 14:58:00 +0200 Subject: [PATCH 1577/1872] Trac #19083: fix dead link by explicitly naming GenericGrowthElement --- src/sage/rings/asymptotic/growth_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index fe776d59d65..d02945a1c47 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2543,7 +2543,8 @@ def _rpow_element_(self, base): ValueError: Variable x is not a log of something. The previous example does not work since the result would not - live in a monomial growth group. When using :meth:`rpow`, this + live in a monomial growth group. When using + :meth:`~GenericGrowthElement.rpow`, this case is handeled by the calling method :meth:`_rpow_`. :: From 5219671880a3f0c143df93b074fe6796e19ed099 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 14:58:48 +0200 Subject: [PATCH 1578/1872] Trac #19094/#19083 comment 64, 29: fix broken link --- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 1c5b26c2121..4bff1fbdf6e 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2552,8 +2552,8 @@ def _mul_(self, other): def _calculate_pow_(self, exponent): r""" - Helper function for :meth:`__pow__` which calculates the power of this - element to the given ``exponent``. + Helper function for :meth:`~ExactTerm.__pow__` which calculates + the power of this element to the given ``exponent``. INPUT: From d4a447fb24f3546b8a5e52f71176ff57dc7ce3f8 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 15:00:41 +0200 Subject: [PATCH 1579/1872] Trac #19094/#19083 comment 64, 29: TermWithCoefficient._calculate_pow_: test ArithemticError --- src/sage/rings/asymptotic/term_monoid.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 4bff1fbdf6e..044322f22c9 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2575,6 +2575,20 @@ def _calculate_pow_(self, exponent): Term with coefficient 8 and growth z^3 sage: t._calculate_pow_(-2) Term with coefficient 1/4 and growth z^(-2) + + :: + + sage: T = TermWithCoefficientMonoid(G, CIF) + sage: T(G.an_element(), coefficient=CIF(RIF(-1,1), RIF(-1,1)))._calculate_pow_(I) + Traceback (most recent call last): + ... + ArithmeticError: Cannot take Term with coefficient 0.? + 0.?*I and + growth z to the exponent I in Generic Term Monoid z^ZZ with + (implicit) coefficients in Complex Interval Field with + 53 bits of precision since its coefficient 0.? + 0.?*I + cannot be taken to this exponent. + > *previous* ValueError: Can't take the argument of + interval strictly containing zero """ try: c = self.coefficient ** exponent From 086b62dd48188c07c87be1f7614af0384f81b616 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 15:09:25 +0200 Subject: [PATCH 1580/1872] Trac #19094/#19083 comment 64, 30: TermMonoidFactory: note block to refer to instance TermMonoid --- src/sage/rings/asymptotic/term_monoid.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 044322f22c9..4305e895879 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3354,6 +3354,10 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): - :class:`ExactTermMonoid`. + .. NOTE:: + + An instance of this factory is available as ``TermMonoid``. + INPUT: - ``term`` -- the kind of term that shall be created. Either a string From 76479520327e7ad98d2c976d87f9602ad9b889ac Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 15:09:44 +0200 Subject: [PATCH 1581/1872] write docstrings for the factory instances --- src/sage/rings/asymptotic/growth_group.py | 5 +++++ src/sage/rings/asymptotic/term_monoid.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index f4bfb35df49..dab166677a2 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3721,3 +3721,8 @@ def create_object(self, version, factors, **kwds): GrowthGroup = GrowthGroupFactory("GrowthGroup") +r""" +A factory for growth groups. +This is an instance of :class:`GrowthGroupFactory` whose documentation +provides more details. +""" diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 4305e895879..7c108a7cb5a 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3524,3 +3524,8 @@ def create_object(self, version, key, **kwds): TermMonoid = TermMonoidFactory("TermMonoid") +r""" +A factory for asymptotic term monoids. +This is an instance of :class:`TermMonoidFactory` whose documentation +provides more details. +""" From 65025ab68743a1dc6c30eb73b6db4e4283f49d4a Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 16 Oct 2015 15:15:43 +0200 Subject: [PATCH 1582/1872] Fix IntegerListsLex import --- src/sage/misc/mrange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 8bff4902c60..711059bb601 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -680,7 +680,7 @@ def cantor_product(*args, **kwds): TypeError: 'toto' is an invalid keyword argument for this function """ from itertools import count - from sage.combinat.integer_list import IntegerListsLex + from sage.combinat.integer_lists import IntegerListsLex m = len(args) # numer of factors lengths = [None] * m # None or length of factors From 7e4e823f847884a12a62f6b26b668c1c6f6e7b40 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 15:17:25 +0200 Subject: [PATCH 1583/1872] Trac #19094/#19083 comment 64, 30: more doctests in TermMonoidFactory --- src/sage/rings/asymptotic/term_monoid.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 7c108a7cb5a..2a43781b620 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3380,13 +3380,31 @@ class TermMonoidFactory(sage.structure.factory.UniqueFactory): sage: from sage.rings.asymptotic.growth_group import GrowthGroup sage: from sage.rings.asymptotic.term_monoid import TermMonoid sage: G = GrowthGroup('x^ZZ') - sage: OT = TermMonoid('O', G, QQ); OT + sage: TermMonoid('O', G, QQ) O-Term Monoid x^ZZ with implicit coefficients in Rational Field - sage: ET = TermMonoid('exact', G, ZZ); ET + sage: TermMonoid('exact', G, ZZ) Exact Term Monoid x^ZZ with coefficients in Integer Ring + :: + + sage: R = AsymptoticRing(growth_group=G, coefficient_ring=QQ) + sage: TermMonoid('exact', asymptotic_ring=R) + Exact Term Monoid x^ZZ with coefficients in Rational Field + sage: TermMonoid('O', asymptotic_ring=R) + O-Term Monoid x^ZZ with implicit coefficients in Rational Field + TESTS:: + sage: TermMonoid(TermMonoid('O', G, ZZ), asymptotic_ring=R) + O-Term Monoid x^ZZ with implicit coefficients in Rational Field + sage: TermMonoid(TermMonoid('exact', G, ZZ), asymptotic_ring=R) + Exact Term Monoid x^ZZ with coefficients in Rational Field + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: TermMonoid(GenericTermMonoid(G, ZZ), asymptotic_ring=R) + Generic Term Monoid x^ZZ with (implicit) coefficients in Rational Field + + :: + sage: TestSuite(TermMonoid('exact', GrowthGroup('x^ZZ'), QQ)).run(verbose=True) # long time running ._test_an_element() . . . pass running ._test_associativity() . . . pass From 728ccf927b638d3705d24a7b788b3fa8f91eff57 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 15:53:33 +0200 Subject: [PATCH 1584/1872] Trac #19094/#19083 comment 66, 30: document parameter convert --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index bb105a111e3..a6e761ad5b5 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -458,6 +458,10 @@ class AsymptoticExpansion(CommutativeAlgebraElement): - ``simplify`` -- a boolean (default: ``True``). It controls automatic simplification (absorption) of the asymptotic expansion. + - ``convert`` -- a boolean (default: ``True``). If set, then the + ``summands`` are converted to the asymptotic ring (the parent of this + expansion). If not, then the summands are taken as they are. + EXAMPLES: There are several ways to create asymptotic expansions; usually From a7f7faf78de998ccaf2fdbc7c3ca750f71abcec2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 15:53:48 +0200 Subject: [PATCH 1585/1872] Trac #19094/#19083 comment 66, 31: test parameter convert --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index a6e761ad5b5..f076351015c 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -625,6 +625,22 @@ def __init__(self, parent, summands, simplify=True, convert=True): | +-- no successors sage: R(lst, simplify=True) # indirect doctest 4*x^4 + O(x^3) + + :: + + sage: R. = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ) + sage: e = R(x^2 + O(x)) + sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticExpansion + sage: S = AsymptoticRing(growth_group='x^QQ', coefficient_ring=ZZ) + sage: for s in AsymptoticExpansion(S, e.summands).summands.elements_topological(): + ....: print s.parent() + O-Term Monoid x^QQ with implicit coefficients in Integer Ring + Exact Term Monoid x^QQ with coefficients in Integer Ring + sage: for s in AsymptoticExpansion(S, e.summands, + ....: convert=False).summands.elements_topological(): + ....: print s.parent() + O-Term Monoid x^QQ with implicit coefficients in Rational Field + Exact Term Monoid x^QQ with coefficients in Rational Field """ super(AsymptoticExpansion, self).__init__(parent=parent) From 7a27e687f4699e049b87208b56b06b288c00c7b0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 15:58:27 +0200 Subject: [PATCH 1586/1872] Trac #19094/#19083 comment 66, 31: Doctest error --- src/sage/rings/asymptotic/asymptotic_ring.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index f076351015c..6d423672e97 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -641,6 +641,17 @@ def __init__(self, parent, summands, simplify=True, convert=True): ....: print s.parent() O-Term Monoid x^QQ with implicit coefficients in Rational Field Exact Term Monoid x^QQ with coefficients in Rational Field + + :: + + sage: AsymptoticExpansion(S, R(1/2).summands) + Traceback (most recent call last): + ... + ValueError: Cannot include 1/2 with parent + Exact Term Monoid x^QQ with coefficients in Rational Field in + Asymptotic Ring over Integer Ring + > *previous* ValueError: 1/2 is not a coefficient in + Exact Term Monoid x^QQ with coefficients in Integer Ring. """ super(AsymptoticExpansion, self).__init__(parent=parent) From ad645aa2f0fac649cab675dde6764a9bdbab2a42 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 16:00:49 +0200 Subject: [PATCH 1587/1872] Trac #19094/#19083 comment 66, 32: change simplification check to "not exact term" --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 6d423672e97..0371ad51956 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1038,8 +1038,8 @@ def _mul_term_(self, term): sage: expr._mul_term_(t) O(x^3) """ - from term_monoid import OTerm - simplify = isinstance(term, OTerm) + from term_monoid import ExactTerm + simplify = not isinstance(term, ExactTerm) return self.parent()(self.summands.mapped(lambda element: term * element), simplify=simplify, convert=False) From d582c1345a788d5b8eba1b5d6e0734378f4559c4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 16:28:11 +0200 Subject: [PATCH 1588/1872] Trac #19094/#19083 comment 66, 29: rename coefficient to new_coefficent (_calculate_pow_) --- src/sage/rings/asymptotic/term_monoid.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 2a43781b620..65c03ffea21 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -595,7 +595,7 @@ def _calculate_pow_test_zero_(self, exponent): return self._calculate_pow_(exponent) - def _calculate_pow_(self, exponent, coefficient=None): + def _calculate_pow_(self, exponent, new_coefficient=None): r""" Helper function for :meth:`__pow__` which calculates the power of this element to the given ``exponent``. @@ -604,7 +604,7 @@ def _calculate_pow_(self, exponent, coefficient=None): - ``exponent`` -- an element. - - ``coefficient`` -- if not ``None`` this is passed on to the + - ``new_coefficient`` -- if not ``None`` this is passed on to the construction of the element (in particular, not taken to any power). OUTPUT: @@ -620,14 +620,14 @@ def _calculate_pow_(self, exponent, coefficient=None): Generic Term with growth z sage: t._calculate_pow_(3) Generic Term with growth z^3 - sage: t._calculate_pow_(3, coefficient=2) + sage: t._calculate_pow_(3, new_coefficient=2) Traceback (most recent call last): ... ValueError: Coefficient 2 is not 1, but Generic Term Monoid z^ZZ with (implicit) coefficients in Integer Ring does not support coefficients. sage: t._calculate_pow_(-2) Generic Term with growth z^(-2) - sage: t._calculate_pow_(-2, coefficient=2) + sage: t._calculate_pow_(-2, new_coefficient=2) Traceback (most recent call last): ... ValueError: Coefficient 2 is not 1, but Generic Term Monoid z^ZZ with @@ -640,7 +640,7 @@ def _calculate_pow_(self, exponent, coefficient=None): raise combine_exceptions( ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) - return self.parent()._create_element_in_extension_(g, coefficient) + return self.parent()._create_element_in_extension_(g, new_coefficient) def can_absorb(self, other): @@ -2598,7 +2598,7 @@ def _calculate_pow_(self, exponent): ArithmeticError('Cannot take %s to the exponent %s in %s since its ' 'coefficient %s cannot be taken to this exponent.' % (self, exponent, self.parent(), self.coefficient)), e) - return super(TermWithCoefficient, self)._calculate_pow_(exponent, coefficient=c) + return super(TermWithCoefficient, self)._calculate_pow_(exponent, new_coefficient=c) def _log_coefficient_(self, base=None): From 59db437cb3005db70d93db50419c285fd9a79b2b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 16:37:52 +0200 Subject: [PATCH 1589/1872] sort maximal elements in error string --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0371ad51956..dc663d3e2a7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1194,7 +1194,8 @@ def __invert__(self, precision=None): if len(max_elem) != 1: raise ValueError('Expansion %s cannot be inverted since there ' 'are several maximal elements %s.' % - (self, ', '.join(str(e) for e in max_elem))) + (self, ', '.join(str(e) for e in + sorted(max_elem, key=str)))) max_elem = max_elem[0] imax_elem = ~max_elem From 7ca2b7f050e1233fbcfc4c5966d1c6c74f4e59b7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 16:38:11 +0200 Subject: [PATCH 1590/1872] Trac #19094/#19083 comment 66, 33: test errors in __invert__ --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index dc663d3e2a7..24e7a0aa19e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1181,6 +1181,22 @@ def __invert__(self, precision=None): Asymptotic Ring over Rational Field sage: (a / 2).parent() Asymptotic Ring over Rational Field + + :: + + sage: ~A(0) + Traceback (most recent call last): + ... + ZeroDivisionError: Division by zero in 0. + + :: + + sage: B. = AsymptoticRing(growth_group='s^ZZ * t^ZZ', coefficient_ring=QQ) + sage: ~(s + t) + Traceback (most recent call last): + ... + ValueError: Expansion s + t cannot be inverted since there are + several maximal elements s, t. """ if not self.summands: raise ZeroDivisionError('Division by zero in %s.' % (self,)) From 12e8e52576df3167072fe2e29d14c396469b9013 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 16:40:45 +0200 Subject: [PATCH 1591/1872] Trac #19094/#19083 comment 66, 34: not tested in __pow__: refer to #19316 --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 24e7a0aa19e..0dda655c017 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1318,7 +1318,7 @@ def __pow__(self, exponent, precision=None): Asymptotic Ring over Rational Field sage: (x^(1/2) + O(x^0))^15 x^(15/2) + O(x^7) - sage: (y^2 + O(y))^(1/2) # not tested + sage: (y^2 + O(y))^(1/2) # not tested, see #19316 y + O(1) sage: (y^2 + O(y))^(-2) y^(-4) + O(y^(-5)) From 084565571642fd04b7ba1b667d700803881b2f8e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 17:02:31 +0200 Subject: [PATCH 1592/1872] Trac #19094/#19083 comment 66, 34: __pow__ add error tests --- src/sage/rings/asymptotic/asymptotic_ring.py | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0dda655c017..21ecf42e4c7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1357,6 +1357,27 @@ def __pow__(self, exponent, precision=None): sage: z^(1+1/z) z + log(z) + 1/2*z^(-1)*log(z)^2 + 1/6*z^(-2)*log(z)^3 + 1/24*z^(-3)*log(z)^4 + O(z^(-4)*log(z)^5) + + :: + + sage: B(0)^(-7) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot take 0 to the negative exponent -7. + sage: B(0)^SR.var('a') + Traceback (most recent call last): + ... + NotImplementedError: Taking 0 to the exponent a not implemented. + + :: + + sage: C. = AsymptoticRing(growth_group='s^QQ * t^QQ', coefficient_ring=QQ) + sage: (s+t)^s + Traceback (most recent call last): + ... + ValueError: Cannot take s + t to the exponent s. + > *previous* ValueError: log(s + t) cannot be constructed since + there are several maximal elements s, t. """ if not self.summands: if exponent == 0: From 3fe96bf9908e89dc2d9ec34029545a6ba6b3379c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 17:06:39 +0200 Subject: [PATCH 1593/1872] sort maximal elements in error string --- src/sage/rings/asymptotic/asymptotic_ring.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 21ecf42e4c7..40029fbd4f3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1529,7 +1529,8 @@ def log(self, base=None, precision=None): if len(max_elem) != 1: raise ValueError('log(%s) cannot be constructed since there ' 'are several maximal elements %s.' % - (self, ', '.join(str(e) for e in max_elem))) + (self, ', '.join(str(e) for e in + sorted(max_elem, key=str)))) max_elem = max_elem[0] imax_elem = ~max_elem From 5ca69eafd6d75a313c267ead52ee42985b2d91c6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 17:07:01 +0200 Subject: [PATCH 1594/1872] Trac #19094/#19083 comment 66, 35: doctest errors of log --- src/sage/rings/asymptotic/asymptotic_ring.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 40029fbd4f3..b3a094d9e8b 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1372,7 +1372,7 @@ def __pow__(self, exponent, precision=None): :: sage: C. = AsymptoticRing(growth_group='s^QQ * t^QQ', coefficient_ring=QQ) - sage: (s+t)^s + sage: (s + t)^s Traceback (most recent call last): ... ValueError: Cannot take s + t to the exponent s. @@ -1495,7 +1495,7 @@ def log(self, base=None, precision=None): EXAMPLES:: - sage: R. = AsymptoticRing('x^ZZ * log(x)^ZZ', QQ) + sage: R. = AsymptoticRing(growth_group='x^ZZ * log(x)^ZZ', coefficient_ring=QQ) sage: log(x) log(x) sage: log(x^2) @@ -1512,6 +1512,12 @@ def log(self, base=None, precision=None): ... ArithmeticError: Cannot compute log(0) in Asymptotic Ring over Rational Field. + sage: C. = AsymptoticRing(growth_group='s^ZZ * t^ZZ', coefficient_ring=QQ) + sage: log(s + t) + Traceback (most recent call last): + ... + ValueError: log(s + t) cannot be constructed since there are + several maximal elements s, t. """ P = self.parent() From 57eb7cc1f45a0f0ba02ab97bb414f109117f2828 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 17:11:21 +0200 Subject: [PATCH 1595/1872] Trac #19083: Mention "GrowthGroup" in docstring of "GrowthGroupFactory" --- src/sage/rings/asymptotic/growth_group.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 94f72abe9f1..03d12fc694d 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3503,6 +3503,10 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): An asymptotic growth group. + .. NOTE:: + + An instance of this factory is available as ``GrowthGroup``. + EXAMPLES:: sage: from sage.rings.asymptotic.growth_group import GrowthGroup From 0042756990b86f3b0ac536fe64d14c32fb2033a0 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 16 Oct 2015 17:12:24 +0200 Subject: [PATCH 1596/1872] Trac #19083: added doctest (comment 64.23) --- src/sage/rings/asymptotic/term_monoid.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 65c03ffea21..8caca1754e8 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1480,6 +1480,12 @@ def _coerce_map_from_(self, S): Generic Term Monoid x^QQ with (implicit) coefficients in Rational Field sage: T_QQ.has_coerce_map_from(T_ZZ) # indirect doctest True + sage: T_QQ_ZZ = GenericTermMonoid(G_QQ, ZZ); T_QQ_ZZ + Generic Term Monoid x^QQ with (implicit) coefficients in Integer Ring + sage: T_QQ.has_coerce_map_from(T_QQ_ZZ) + True + sage: T_QQ_ZZ.has_coerce_map_from(T_QQ) + False :: From cb55faa3d7774d9585097c2a87a243401e3cfc3a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 17:29:50 +0200 Subject: [PATCH 1597/1872] Trac #19094/#19083 comment 66, 35: improve speed of log --- src/sage/rings/asymptotic/asymptotic_ring.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b3a094d9e8b..24697cd60c7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1549,14 +1549,15 @@ def log(self, base=None, precision=None): one = new_self.parent().one() geom = one - new_self._mul_term_(imax_elem) + from sage.rings.integer_ring import ZZ expanding = True result = -geom geom_k = geom - k = one + k = ZZ(1) while expanding: - k += one + k += ZZ(1) geom_k *= geom - new_result = (result - geom_k / k).truncate(precision=precision) + new_result = (result - geom_k * ~k).truncate(precision=precision) if new_result.has_same_summands(result): expanding = False result = new_result From d925157d8d74df546f52ca187cfde27135e2d9ee Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 17:30:36 +0200 Subject: [PATCH 1598/1872] Trac #19094/#19083 comment 66, 36: rpow: decrease indention of ALGORITHM block --- src/sage/rings/asymptotic/asymptotic_ring.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 24697cd60c7..53a42aa85d6 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1624,18 +1624,18 @@ def rpow(self, base, precision=None): ALGORITHM: - The strategy for computing the exponential function is - as follows: + The strategy for computing the exponential function is + as follows: - - This asymptotic expansion is split into a part that - is in `o(1)` and the rest. + - This asymptotic expansion is split into a part that + is in `o(1)` and the rest. - - The part that is in `o(1)` is expanded according to - the series expansion of `\exp(t)` for `t \to 0`. + - The part that is in `o(1)` is expanded according to + the series expansion of `\exp(t)` for `t \to 0`. - - The remaining part of the expansion is taken exactly. - In particular, this means that the respective growth - elements have to be constructed. + - The remaining part of the expansion is taken exactly. + In particular, this means that the respective growth + elements have to be constructed. EXAMPLES:: From 375ff46221b7dcc101536774664b4bb935f99fba Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 16 Oct 2015 10:53:34 -0500 Subject: [PATCH 1599/1872] Fixing doctest failures and letting a few other rings know they are metric spaces. --- .../coercion_and_categories.rst | 2 +- src/doc/en/tutorial/tour_coercion.rst | 1 + src/doc/fr/tutorial/tour_coercion.rst | 1 + src/doc/pt/tutorial/tour_coercion.rst | 4 ++- src/sage/categories/bimodules.py | 14 +++++++--- src/sage/categories/category.py | 28 +++++++++++-------- src/sage/categories/category_types.py | 8 ++++-- src/sage/categories/homset.py | 18 ++++++------ src/sage/categories/lie_groups.py | 25 +++++++++-------- src/sage/categories/map.pyx | 8 ++++-- src/sage/categories/primer.py | 8 ++++-- src/sage/matrix/matrix_space.py | 8 ++++-- src/sage/modules/free_module.py | 14 +++++----- src/sage/modules/free_module_homspace.py | 8 +++--- src/sage/rings/complex_double.pyx | 15 +++++++++- src/sage/rings/complex_field.py | 2 +- src/sage/rings/integer_ring.pyx | 3 +- src/sage/rings/polynomial/polynomial_ring.py | 2 +- src/sage/rings/real_double.pyx | 15 +++++++++- src/sage/rings/ring.pyx | 9 ++++-- src/sage/structure/category_object.pyx | 3 +- src/sage/structure/parent.pyx | 4 ++- .../tensor/modules/finite_rank_free_module.py | 5 ++-- .../tests/french_book/domaines_doctest.py | 2 +- 24 files changed, 135 insertions(+), 72 deletions(-) diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 058b9f41f6b..b6f8e8bb015 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -878,7 +878,7 @@ The four axioms requested for coercions rational field is a homomorphism of euclidean domains:: sage: QQ.coerce_map_from(ZZ).category_for() - Category of euclidean domains + Join of Category of euclidean domains and Category of metric spaces .. end of output diff --git a/src/doc/en/tutorial/tour_coercion.rst b/src/doc/en/tutorial/tour_coercion.rst index 2bbb25d352b..7f94a0c84fd 100644 --- a/src/doc/en/tutorial/tour_coercion.rst +++ b/src/doc/en/tutorial/tour_coercion.rst @@ -118,6 +118,7 @@ implemented in Sage as well: sage: ZZ.category() Join of Category of euclidean domains and Category of infinite enumerated sets + and Category of metric spaces sage: ZZ.category().is_subcategory(Rings()) True sage: ZZ in Rings() diff --git a/src/doc/fr/tutorial/tour_coercion.rst b/src/doc/fr/tutorial/tour_coercion.rst index a032be7968c..395493ba3a6 100644 --- a/src/doc/fr/tutorial/tour_coercion.rst +++ b/src/doc/fr/tutorial/tour_coercion.rst @@ -119,6 +119,7 @@ par ailleurs les catégories en tant que telles : sage: ZZ.category() Join of Category of euclidean domains and Category of infinite enumerated sets + and Category of metric spaces sage: ZZ.category().is_subcategory(Rings()) True sage: ZZ in Rings() diff --git a/src/doc/pt/tutorial/tour_coercion.rst b/src/doc/pt/tutorial/tour_coercion.rst index 58ca4301876..569caee10fa 100644 --- a/src/doc/pt/tutorial/tour_coercion.rst +++ b/src/doc/pt/tutorial/tour_coercion.rst @@ -121,7 +121,9 @@ categorias matemáticas também são implementadas no Sage: sage: Rings() Category of rings sage: ZZ.category() - Join of Category of euclidean domains and Category of infinite enumerated sets + Join of Category of euclidean domains + and Category of infinite enumerated sets + and Category of metric spaces sage: ZZ.category().is_subcategory(Rings()) True diff --git a/src/sage/categories/bimodules.py b/src/sage/categories/bimodules.py index 7971135a4f3..f778479bbc8 100644 --- a/src/sage/categories/bimodules.py +++ b/src/sage/categories/bimodules.py @@ -70,15 +70,21 @@ def _make_named_class_key(self, name): EXAMPLES:: sage: Bimodules(QQ,ZZ)._make_named_class_key('parent_class') - (Category of quotient fields, - Join of Category of euclidean domains and Category of infinite enumerated sets) + (Join of Category of quotient fields and Category of metric spaces, + Join of Category of euclidean domains + and Category of infinite enumerated sets + and Category of metric spaces) + sage: Bimodules(Fields(), ZZ)._make_named_class_key('element_class') (Category of fields, - Join of Category of euclidean domains and Category of infinite enumerated sets) + Join of Category of euclidean domains + and Category of infinite enumerated sets + and Category of metric spaces) sage: Bimodules(QQ, Rings())._make_named_class_key('element_class') - (Category of quotient fields, Category of rings) + (Join of Category of quotient fields and Category of metric spaces, + Category of rings) sage: Bimodules(Fields(), Rings())._make_named_class_key('element_class') (Category of fields, Category of rings) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index a43973e47f9..9df89eb6a23 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -35,7 +35,7 @@ sage: V = VectorSpace(RationalField(), 3) sage: V.category() - Category of vector spaces with basis over quotient fields + Category of vector spaces with basis over (quotient fields and metric spaces) sage: G = SymmetricGroup(9) sage: G.category() Join of Category of finite permutation groups and Category of finite weyl groups @@ -323,7 +323,8 @@ class inheritance from ``C.parent_class``. sage: Algebras(GF(5)).parent_class is Algebras(GF(7)).parent_class True - sage: Coalgebras(QQ).parent_class is Coalgebras(FractionField(QQ['x'])).parent_class + sage: F = FractionField(ZZ['t']) + sage: Coalgebras(F).parent_class is Coalgebras(FractionField(F['x'])).parent_class True We now construct a parent in the usual way:: @@ -2755,9 +2756,9 @@ def _make_named_class(self, name, method_provider, cache = False, **options): Similarly for ``QQ`` and ``RR``:: sage: QQ.category() - Category of quotient fields + Join of Category of quotient fields and Category of metric spaces sage: RR.category() - Category of fields + Join of Category of fields and Category of complete metric spaces sage: Modules(QQ).parent_class is Modules(RR).parent_class False @@ -2818,14 +2819,17 @@ def _make_named_class_key(self, name): sage: Algebras(ZZ)._make_named_class_key("parent_class") Join of Category of euclidean domains - and Category of infinite enumerated sets + and Category of infinite enumerated sets + and Category of metric spaces The morphism class of a bimodule depends only on the category of the left and right base rings:: sage: Bimodules(QQ, ZZ)._make_named_class_key("morphism_class") - (Category of quotient fields, - Join of Category of euclidean domains and Category of infinite enumerated sets) + (Join of Category of quotient fields and Category of metric spaces, + Join of Category of euclidean domains + and Category of infinite enumerated sets + and Category of metric spaces) The element class of a join category depends only on the element class of its super categories:: @@ -2953,13 +2957,14 @@ def _make_named_class_key(self, name): sage: Modules(ZZ)._make_named_class_key('element_class') Join of Category of euclidean domains - and Category of infinite enumerated sets + and Category of infinite enumerated sets + and Category of metric spaces sage: Modules(QQ)._make_named_class_key('parent_class') - Category of quotient fields + Join of Category of quotient fields and Category of metric spaces sage: Schemes(Spec(ZZ))._make_named_class_key('parent_class') Category of schemes sage: ModularAbelianVarieties(QQ)._make_named_class_key('parent_class') - Category of quotient fields + Join of Category of quotient fields and Category of metric spaces """ return tuple(getattr(cat, name) for cat in self._super_categories) @@ -3005,7 +3010,8 @@ def _subcategory_hook_(self, category): EXAMPLE:: - sage: QQ['x'].category().is_subcategory(Category.join([Rings(), VectorSpaces(QuotientFields())])) # indirect doctest + sage: cat = Category.join([Rings(), VectorSpaces(QuotientFields().Metric())]) + sage: QQ['x'].category().is_subcategory(cat) # indirect doctest True """ return all(category.is_subcategory(X) for X in self._super_categories) diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index 21df7cb851e..08e65520807 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -193,13 +193,15 @@ def _make_named_class_key(self, name): EXAMPLES:: sage: Modules(ZZ)._make_named_class_key('element_class') - Join of Category of euclidean domains and Category of infinite enumerated sets + Join of Category of euclidean domains + and Category of infinite enumerated sets + and Category of metric spaces sage: Modules(QQ)._make_named_class_key('parent_class') - Category of quotient fields + Join of Category of quotient fields and Category of metric spaces sage: Schemes(Spec(ZZ))._make_named_class_key('parent_class') Category of schemes sage: ModularAbelianVarieties(QQ)._make_named_class_key('parent_class') - Category of quotient fields + Join of Category of quotient fields and Category of metric spaces sage: Algebras(Fields())._make_named_class_key('morphism_class') Category of fields """ diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index f73d29d3557..ec17a24468a 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -647,7 +647,7 @@ def __reduce__(self): (, (Vector space of dimension 2 over Rational Field, Vector space of dimension 3 over Rational Field, - Category of vector spaces with basis over quotient fields, + Category of vector spaces with basis over (quotient fields and metric spaces), False)) TESTS:: @@ -1164,18 +1164,18 @@ def reversed(self): sage: H = Hom(ZZ^2, ZZ^3); H Set of Morphisms from Ambient free module of rank 2 over - the principal ideal domain Integer Ring to Ambient free - module of rank 3 over the principal ideal domain Integer - Ring in Category of modules with basis over (euclidean - domains and infinite enumerated sets) + the principal ideal domain Integer Ring to Ambient free module + of rank 3 over the principal ideal domain Integer Ring + in Category of modules with basis over (euclidean domains and + infinite enumerated sets and metric spaces) sage: type(H) sage: H.reversed() Set of Morphisms from Ambient free module of rank 3 over - the principal ideal domain Integer Ring to Ambient free - module of rank 2 over the principal ideal domain Integer - Ring in Category of modules with basis over (euclidean - domains and infinite enumerated sets) + the principal ideal domain Integer Ring to Ambient free + module of rank 2 over the principal ideal domain Integer Ring + in Category of modules with basis over (euclidean domains and + infinite enumerated sets and metric spaces) sage: type(H.reversed()) """ diff --git a/src/sage/categories/lie_groups.py b/src/sage/categories/lie_groups.py index cbb6571977b..3883822f105 100644 --- a/src/sage/categories/lie_groups.py +++ b/src/sage/categories/lie_groups.py @@ -10,11 +10,11 @@ #from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method -from sage.categories.category_singleton import Category_singleton +from sage.categories.category_types import Category_over_base_ring from sage.categories.groups import Groups from sage.categories.manifolds import Manifolds -class LieGroups(Category_singleton): +class LieGroups(Category_over_base_ring): r""" The category of Lie groups. @@ -23,12 +23,12 @@ class LieGroups(Category_singleton): EXAMPLES:: sage: from sage.categories.lie_groups import LieGroups - sage: C = LieGroups(); C - Category of Lie groups + sage: C = LieGroups(QQ); C + Category of Lie groups over Rational Field TESTS:: - sage: TestSuite(C).run() + sage: TestSuite(C).run(skip="_test_category_over_bases") """ @cached_method def super_categories(self): @@ -36,10 +36,11 @@ def super_categories(self): EXAMPLES:: sage: from sage.categories.lie_groups import LieGroups - sage: LieGroups().super_categories() - [Category of topological groups, Category of smooth real manifolds] + sage: LieGroups(QQ).super_categories() + [Category of topological groups, + Category of smooth manifolds over Rational Field] """ - return [Groups().Topological(), Manifolds().Real().Smooth()] + return [Groups().Topological(), Manifolds(self.base()).Smooth()] def additional_structure(self): r""" @@ -54,7 +55,7 @@ def additional_structure(self): EXAMPLES:: sage: from sage.categories.lie_groups import LieGroups - sage: LieGroups().additional_structure() + sage: LieGroups(QQ).additional_structure() """ return None @@ -64,8 +65,8 @@ def _repr_object_names(self): EXAMPLES:: sage: from sage.categories.lie_groups import LieGroups - sage: LieGroups() # indirect doctest - Category of Lie groups + sage: LieGroups(QQ) # indirect doctest + Category of Lie groups over Rational Field """ - return "Lie groups" + return "Lie groups over {}".format(self.base_ring()) diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index 499b1b22486..00fc6ec3d61 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -628,9 +628,13 @@ cdef class Map(Element): sage: R. = QQ[] sage: f = R.hom([x+y, x-y], R) sage: f.category_for() - Join of Category of unique factorization domains and Category of commutative algebras over quotient fields + Join of Category of unique factorization domains + and Category of commutative algebras over (quotient fields and metric spaces) sage: f.category() - Category of endsets of unital magmas and right modules over quotient fields and left modules over quotient fields + Category of endsets of unital magmas + and right modules over (quotient fields and metric spaces) + and left modules over (quotient fields and metric spaces) + FIXME: find a better name for this method """ diff --git a/src/sage/categories/primer.py b/src/sage/categories/primer.py index b8c70db515d..5e32c54e985 100644 --- a/src/sage/categories/primer.py +++ b/src/sage/categories/primer.py @@ -348,9 +348,12 @@ sage: ZZ.category() Join of Category of euclidean domains and Category of infinite enumerated sets + and Category of metric spaces sage: ZZ.categories() - [Join of Category of euclidean domains and Category of infinite enumerated sets, + [Join of Category of euclidean domains + and Category of infinite enumerated sets + and Category of metric spaces, Category of euclidean domains, Category of principal ideal domains, Category of unique factorization domains, Category of gcd domains, Category of integral domains, Category of domains, @@ -360,7 +363,8 @@ Category of commutative magmas, Category of unital magmas, Category of magmas, Category of commutative additive groups, ..., Category of additive magmas, Category of infinite enumerated sets, Category of enumerated sets, - Category of infinite sets, Category of sets, + Category of infinite sets, Category of metric spaces, + Category of topological spaces, Category of sets, Category of sets with partial maps, Category of objects] diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 58569480464..6336b8e1c25 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -118,11 +118,13 @@ class MatrixSpace(UniqueRepresentation, parent_gens.ParentWithGens): sage: MatrixSpace(ZZ,10,5) Full MatrixSpace of 10 by 5 dense matrices over Integer Ring sage: MatrixSpace(ZZ,10,5).category() - Category of infinite modules over (euclidean domains and infinite enumerated sets) + Category of infinite modules over (euclidean domains + and infinite enumerated sets and metric spaces) sage: MatrixSpace(ZZ,10,10).category() - Category of infinite algebras over (euclidean domains and infinite enumerated sets) + Category of infinite algebras over (euclidean domains + and infinite enumerated sets and metric spaces) sage: MatrixSpace(QQ,10).category() - Category of infinite algebras over quotient fields + Category of infinite algebras over (quotient fields and metric spaces) TESTS:: diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 85db5e993d1..c4c73db54f0 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -686,14 +686,15 @@ def __init__(self, base_ring, rank, degree, sparse=False, Category of vector spaces with basis over (finite fields and subquotients of monoids and quotients of semigroups) sage: V = QQ^4; V.category() - Category of vector spaces with basis over quotient fields + Category of vector spaces with basis over (quotient fields and metric spaces) sage: V = GF(5)**20; V.category() Category of vector spaces with basis over (finite fields and subquotients of monoids and quotients of semigroups) sage: FreeModule(ZZ,3).category() - Category of modules with basis over (euclidean domains and infinite enumerated sets) + Category of modules with basis over (euclidean domains + and infinite enumerated sets and metric spaces) sage: (QQ^0).category() - Category of vector spaces with basis over quotient fields + Category of vector spaces with basis over (quotient fields and metric spaces) TESTS:: @@ -3067,10 +3068,9 @@ def _Hom_(self, Y, category): sage: type(H) sage: H - Set of Morphisms from Vector space of dimension 2 over - Rational Field to Ambient free module of rank 3 over the - principal ideal domain Integer Ring in Category of vector - spaces with basis over quotient fields + Set of Morphisms from Vector space of dimension 2 over Rational Field + to Ambient free module of rank 3 over the principal ideal domain Integer Ring + in Category of vector spaces with basis over (quotient fields and metric spaces) """ if Y.base_ring().is_field(): import vector_space_homspace diff --git a/src/sage/modules/free_module_homspace.py b/src/sage/modules/free_module_homspace.py index 5d674f304e9..4245f0cb578 100644 --- a/src/sage/modules/free_module_homspace.py +++ b/src/sage/modules/free_module_homspace.py @@ -28,10 +28,10 @@ sage: H = Hom(V3,V2) sage: H Set of Morphisms from Ambient free module of rank 3 over the - principal ideal domain Integer Ring to Ambient free module - of rank 2 over the principal ideal domain Integer Ring in - Category of modules with basis over (euclidean domains and - infinite enumerated sets) + principal ideal domain Integer Ring to Ambient free module of rank 2 + over the principal ideal domain Integer Ring in + Category of modules with basis over (euclidean domains + and infinite enumerated sets and metric spaces) sage: B = H.basis() sage: len(B) 6 diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 2dbd9b83612..7454a542240 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -151,7 +151,7 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): (-1.0, -1.0 + 1.2246...e-16*I, False) """ from sage.categories.fields import Fields - ParentWithGens.__init__(self, self, ('I',), normalize=False, category = Fields()) + ParentWithGens.__init__(self, self, ('I',), normalize=False, category=Fields().Metric().Complete()) self._populate_coercion_lists_() def __reduce__(self): @@ -199,6 +199,19 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): return 561162115 #return hash(self.str()) + def dist(self, a, b): + """ + Return the distance between ``a`` and ``b``. + + EXAMPLES:: + + sage: CDF.dist(3, 2) + 1.0 + sage: CDF.dist(-1, I) + 1.4142135623730951 + """ + return (self(a) - self(b)).abs() + def characteristic(self): """ Return the characteristic of the complex double field, which is 0. diff --git a/src/sage/rings/complex_field.py b/src/sage/rings/complex_field.py index 0f786b5571f..9f5765a2d0b 100644 --- a/src/sage/rings/complex_field.py +++ b/src/sage/rings/complex_field.py @@ -198,7 +198,7 @@ def __init__(self, prec=53): sage: C = ComplexField(200) sage: C.category() - Category of fields + Join of Category of fields and Category of complete metric spaces sage: TestSuite(C).run() """ self._prec = int(prec) diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index bbafd60a2a4..6fed18f4b0f 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -122,7 +122,8 @@ cdef class IntegerRing_class(PrincipalIdealDomain): False sage: Z.category() Join of Category of euclidean domains - and Category of infinite enumerated sets + and Category of infinite enumerated sets + and Category of metric spaces sage: Z(2^(2^5) + 1) 4294967297 diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index e0d2d4f4ff6..9c469c9eb46 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -268,7 +268,7 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ sage: category(ZZ['x']) Join of Category of unique factorization domains and Category of commutative algebras over - (euclidean domains and infinite enumerated sets) + (euclidean domains and infinite enumerated sets and metric spaces) sage: category(GF(7)['x']) Join of Category of euclidean domains and Category of commutative algebras over (finite fields and diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index e6ec3dfc30c..8211108ddd4 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -140,7 +140,7 @@ cdef class RealDoubleField_class(Field): sage: TestSuite(R).run() """ from sage.categories.fields import Fields - Field.__init__(self, self, category = Fields()) + Field.__init__(self, self, category=Fields().Metric().Complete()) self._populate_coercion_lists_(element_constructor=RealDoubleElement, init_no_parent=True, convert_method_name='_real_double_') @@ -236,6 +236,19 @@ cdef class RealDoubleField_class(Field): return 0 return cmp(type(self), type(x)) + def dist(self, a, b): + """ + Return the distance between ``a`` and ``b`` in ``self``. + + EXAMPLES:: + + sage: RDF.dist(5, 1/2) + 4.5 + sage: RDF.dist(-1, 1/2) + 1.5 + """ + return (self(a) - self(b)).abs() + def construction(self): r""" Returns the functorial construction of ``self``, namely, completion of diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 7d84ca3bab1..d3b779cbd6c 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -134,11 +134,14 @@ cdef class Ring(ParentWithGens): Test agaings another bug fixed in :trac:`9944`:: sage: QQ['x'].category() - Join of Category of euclidean domains and Category of commutative algebras over quotient fields + Join of Category of euclidean domains + and Category of commutative algebras over (quotient fields and metric spaces) sage: QQ['x','y'].category() - Join of Category of unique factorization domains and Category of commutative algebras over quotient fields + Join of Category of unique factorization domains + and Category of commutative algebras over (quotient fields and metric spaces) sage: PolynomialRing(MatrixSpace(QQ,2),'x').category() - Category of algebras over (algebras over quotient fields and infinite sets) + Category of algebras over (algebras over + (quotient fields and metric spaces) and infinite sets) sage: PolynomialRing(SteenrodAlgebra(2),'x').category() Category of algebras over graded hopf algebras with basis over Finite Field of size 2 diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index be78efcf49a..405ff0d9d4d 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -235,7 +235,8 @@ cdef class CategoryObject(sage_object.SageObject): sage: ZZ.categories() [Join of Category of euclidean domains - and Category of infinite enumerated sets, + and Category of infinite enumerated sets + and Category of metric spaces, Category of euclidean domains, Category of principal ideal domains, Category of unique factorization domains, diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 1936d2b69b9..fd20d2eaca9 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -805,6 +805,7 @@ cdef class Parent(category_object.CategoryObject): running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass running ._test_gcd_vs_xgcd() . . . pass + running ._test_metric() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_one() . . . pass running ._test_pickling() . . . pass @@ -875,6 +876,7 @@ cdef class Parent(category_object.CategoryObject): _test_eq _test_euclidean_degree _test_gcd_vs_xgcd + _test_metric _test_not_implemented_methods _test_one _test_pickling @@ -1117,7 +1119,7 @@ cdef class Parent(category_object.CategoryObject): it is a ring, from the point of view of categories:: sage: MS.category() - Category of infinite algebras over quotient fields + Category of infinite algebras over (quotient fields and metric spaces) sage: MS in Rings() True diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 8fbe8419514..a06ec2b2b47 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -243,7 +243,8 @@ class :class:`~sage.modules.free_module.FreeModule_generic` sage: M.category() Category of modules over Integer Ring sage: N.category() - Category of modules with basis over (euclidean domains and infinite enumerated sets) + Category of modules with basis over (euclidean domains + and infinite enumerated sets and metric spaces) In other words, the module created by ``FreeModule`` is actually `\ZZ^3`, while, in the absence of any distinguished basis, no *canonical* isomorphism @@ -367,7 +368,7 @@ class :class:`~sage.modules.free_module.FreeModule_generic` sage: V = VectorSpace(QQ,3) ; V Vector space of dimension 3 over Rational Field sage: V.category() - Category of vector spaces with basis over quotient fields + Category of vector spaces with basis over (quotient fields and metric spaces) sage: V is QQ^3 True sage: V.basis() diff --git a/src/sage/tests/french_book/domaines_doctest.py b/src/sage/tests/french_book/domaines_doctest.py index f8a15b85660..4628ffd4740 100644 --- a/src/sage/tests/french_book/domaines_doctest.py +++ b/src/sage/tests/french_book/domaines_doctest.py @@ -174,7 +174,7 @@ Sage example in ./domaines.tex, line 415:: sage: QQ.category() - Category of quotient fields + Join of Category of quotient fields and Category of metric spaces Sage example in ./domaines.tex, line 421:: From 2522bd0ad88237c6027bfa7475d33a640a17af3f Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 17:58:00 +0200 Subject: [PATCH 1600/1872] Trac #19094/#19083 comment 66, 36: add error test --- src/sage/rings/asymptotic/asymptotic_ring.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 53a42aa85d6..773e02204b1 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1642,6 +1642,15 @@ def rpow(self, base, precision=None): sage: A. = AsymptoticRing('x^ZZ', QQ) sage: (1/x).rpow('e', precision=5) 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + 1/24*x^(-4) + O(x^(-5)) + + TESTS:: + + sage: x.rpow(SR.var('y')) + Traceback (most recent call last): + ... + ArithmeticError: Cannot construct y^x in Growth Group x^ZZ + > *previous* TypeError: unsupported operand parent(s) for '*': + 'Growth Group x^ZZ' and 'Growth Group SR^x' """ if isinstance(base, AsymptoticExpansion): return base.__pow__(self, precision=precision) From 8cbacdfd2feea5207fc82e547a3f070a1448a1fe Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 18:03:37 +0200 Subject: [PATCH 1601/1872] Trac #19094/#19083 comment 66, 37: refer to #19424 in not tested doctest --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 773e02204b1..b601504ca67 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1863,7 +1863,7 @@ class AsymptoticRing(Algebra, UniqueRepresentation): ....: __eq__ = AR_class.Element.has_same_summands sage: A = AR(growth_group='z^QQ', coefficient_ring=QQ) sage: from itertools import islice - sage: TestSuite(A).run( # not tested # long time + sage: TestSuite(A).run( # not tested # long time # see #19424 ....: verbose=True, ....: elements=tuple(islice(A.some_elements(), 10)), ....: skip=('_test_some_elements', # to many elements From ec10395a9e92ea93255bcb181da98b3fbbad4e07 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 18:10:08 +0200 Subject: [PATCH 1602/1872] Trac #19094/#19083 comment 66, 39: extend description of old_parent (in AsymptoticRing._create_element_via_parent_) --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index b601504ca67..f1e7410fbec 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2162,7 +2162,9 @@ def _create_element_in_extension_(self, term, old_parent=None): - ``term`` -- the element data. - - ``old_parent`` -- the parent of ``term`` is compared to this parent. + - ``old_parent`` -- the parent of ``term`` is compared to this + parent. If both are the same or ``old_parent`` is ``None`, + then the result is an expansion in this (``self``) asymptotic ring. OUTPUT: From 36a48e4e19bd4d0afa6fc89b781e69e15d6a2f42 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 18:21:15 +0200 Subject: [PATCH 1603/1872] Trac #19094/#19083 comment 66, 39: _create_element_in_extension_ rewrite doctests and rename parameter to old_term_parent --- src/sage/rings/asymptotic/asymptotic_ring.py | 24 +++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index f1e7410fbec..3cc27e338e9 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2153,7 +2153,7 @@ def _create_empty_summands_(): merge=absorption) - def _create_element_in_extension_(self, term, old_parent=None): + def _create_element_in_extension_(self, term, old_term_parent=None): r""" Create an element in an extension of this asymptotic ring which is chosen according to the input. @@ -2162,7 +2162,7 @@ def _create_element_in_extension_(self, term, old_parent=None): - ``term`` -- the element data. - - ``old_parent`` -- the parent of ``term`` is compared to this + - ``old_term_parent`` -- the parent of ``term`` is compared to this parent. If both are the same or ``old_parent`` is ``None`, then the result is an expansion in this (``self``) asymptotic ring. @@ -2173,11 +2173,23 @@ def _create_element_in_extension_(self, term, old_parent=None): EXAMPLES:: sage: A = AsymptoticRing('z^ZZ', ZZ) - sage: term = next(A.an_element().summands.elements_topological()) - sage: A._create_element_in_extension_(term, A) - O(z) + sage: a = next(A.an_element().summands.elements_topological()) + sage: B = AsymptoticRing('z^QQ', QQ) + sage: b = next(B.an_element().summands.elements_topological()) + sage: c = A._create_element_in_extension_(a, a.parent()) + sage: next(c.summands.elements_topological()).parent() + O-Term Monoid z^ZZ with implicit coefficients in Integer Ring + sage: c = A._create_element_in_extension_(b, a.parent()) + sage: next(c.summands.elements_topological()).parent() + O-Term Monoid z^QQ with implicit coefficients in Rational Field + + TESTS:: + + sage: c = A._create_element_in_extension_(b, None) + sage: next(c.summands.elements_topological()).parent() + O-Term Monoid z^QQ with implicit coefficients in Rational Field """ - if old_parent is None or term.parent() is old_parent: + if old_term_parent is None or term.parent() is old_term_parent: parent = self else: # Insert an 'if' here once terms can have different From 38a597b1e531900e0c0c24fbb4c9129c43308b72 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 18:42:43 +0200 Subject: [PATCH 1604/1872] Trac #19094/#19083 comment 66, 40: remove outdated NOTE block --- src/sage/rings/asymptotic/asymptotic_ring.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 3cc27e338e9..9422d81b159 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2220,12 +2220,6 @@ def _element_constructor_(self, data, simplify=True, convert=True): An element of this asymptotic ring. - .. NOTE:: - - Either ``data`` or ``summands`` has to be given. If - ``summands`` is specified, then no positional argument - may be passed (except for ``int(0)``). - TESTS:: sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) From b9276719e7dc7ff183e35f0ba0517f29c5c4a4cb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 18:52:55 +0200 Subject: [PATCH 1605/1872] Trac #19094/#19083 comment 66, 40: complete doctests of AsymptoticRing._element_constructor_ --- src/sage/rings/asymptotic/asymptotic_ring.py | 37 ++++++++++++++------ 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 9422d81b159..56696767166 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2223,15 +2223,15 @@ def _element_constructor_(self, data, simplify=True, convert=True): TESTS:: sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ) - sage: AR(5) + sage: AR(5) # indirect doctest 5 - sage: AR(3*x^2) + sage: AR(3*x^2) # indirect doctest 3*x^2 sage: x = ZZ['x'].gen(); x.parent() Univariate Polynomial Ring in x over Integer Ring sage: AR(x) x - sage: y = ZZ['y'].gen(); AR(y) + sage: y = ZZ['y'].gen(); AR(y) # indirect doctest Traceback (most recent call last): ... ValueError: Polynomial y is not in @@ -2244,13 +2244,13 @@ def _element_constructor_(self, data, simplify=True, convert=True): sage: A = AsymptoticRing(growth_group='p^ZZ', coefficient_ring=QQ) sage: P.

= QQ[] - sage: A(p) + sage: A(p) # indirect doctest p - sage: A(p^11) + sage: A(p^11) # indirect doctest p^11 - sage: A(2*p^11) + sage: A(2*p^11) # indirect doctest 2*p^11 - sage: A(3*p^4 + 7/3*p - 8) + sage: A(3*p^4 + 7/3*p - 8) # indirect doctest 3*p^4 + 7/3*p - 8 :: @@ -2258,9 +2258,9 @@ def _element_constructor_(self, data, simplify=True, convert=True): sage: S = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=QQ) sage: var('x, y') (x, y) - sage: S(x + y) + sage: S(x + y) # indirect doctest x + y - sage: S(2*x - 4*x*y^6) + sage: S(2*x - 4*x*y^6) # indirect doctest -4*x*y^6 + 2*x :: @@ -2273,13 +2273,30 @@ def _element_constructor_(self, data, simplify=True, convert=True): sage: M = AsymptoticRing('m^ZZ', ZZ) sage: N = AsymptoticRing('n^ZZ', QQ) - sage: N(M.an_element()) + sage: N(M.an_element()) # indirect doctest Traceback (most recent call last): ... ValueError: Cannot include m^3 with parent Exact Term Monoid m^ZZ with coefficients in Integer Ring in Asymptotic Ring over Rational Field > *previous* ValueError: m^3 is not in Growth Group n^ZZ + + :: + + sage: M([1]) # indirect doctest + Traceback (most recent call last): + ... + TypeError: Not all list entries of [1] are asymptotic terms, + so cannot create an asymptotic expansion in + Asymptotic Ring over Integer Ring. + sage: M(SR.var('a') + 1) # indirect doctest + Traceback (most recent call last): + ... + ValueError: Symbolic expression a + 1 is not in + Asymptotic Ring over Integer Ring. + > *previous* ValueError: Cannot convert a to an exact summand + in an asymptotic expansion in + Asymptotic Ring over Integer Ring. """ from sage.data_structures.mutable_poset import MutablePoset if isinstance(data, MutablePoset): From 76246272e20ac2551b597ac2f56d73d5c2e912b0 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 19:10:22 +0200 Subject: [PATCH 1606/1872] Trac #19094/#19083 comment 66, 40: refer to trac tickets at O-Term from SR todo --- src/sage/rings/asymptotic/asymptotic_ring.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 56696767166..d3818004e62 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2345,6 +2345,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): summands = [] for summand in data.operands(): # TODO: check if summand is an O-Term here + # (see #19425, #19426) try: summands.append(self._create_exact_summand_(summand)) except ValueError as e: From 1ceba10f86bafc58471f0d8cff9707b5616ed784 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 19:15:34 +0200 Subject: [PATCH 1607/1872] Trac #19094/#19083 comment 66, 40: test conversion from multivariate polynomial ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d3818004e62..17059b930ae 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2269,6 +2269,22 @@ def _element_constructor_(self, data, simplify=True, convert=True): sage: 1/a a^(-1) + :: + + sage: P. = ZZ[] + sage: A(a + b) + a + b + sage: A(a + c) + Traceback (most recent call last): + ... + ValueError: Polynomial a + c is not in + Asymptotic Ring over Rational Field + > *previous* ValueError: Growth c is not in + Exact Term Monoid a^ZZ * b^ZZ with coefficients in Rational Field. + >> *previous* ValueError: c is not in Growth Group a^ZZ * b^ZZ. + >>... *previous* ValueError: c is not in any of the factors of + Growth Group a^ZZ * b^ZZ + :: sage: M = AsymptoticRing('m^ZZ', ZZ) From 80068372f79a2e804be5c864b51bac9a1c75498a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 19:30:25 +0200 Subject: [PATCH 1608/1872] Trac #19094/#19083 comment 66, 40: simplify test for empty data --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 17059b930ae..9643597810a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2339,7 +2339,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): return self.element_class(self, summands, simplify=simplify, convert=convert) - if not data or data == 0: + if not data: summands = AsymptoticRing._create_empty_summands_() return self.element_class(self, summands, simplify=simplify, convert=False) From 4e5af1142c3f01f021b815d11d0e9194b439f566 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 20:02:44 +0200 Subject: [PATCH 1609/1872] Trac #19094/#19083 comment 66, 36: delete ALGORITHM block --- src/sage/rings/asymptotic/asymptotic_ring.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 9643597810a..61c82ede143 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1622,21 +1622,6 @@ def rpow(self, base, precision=None): An asymptotic expansion. - ALGORITHM: - - The strategy for computing the exponential function is - as follows: - - - This asymptotic expansion is split into a part that - is in `o(1)` and the rest. - - - The part that is in `o(1)` is expanded according to - the series expansion of `\exp(t)` for `t \to 0`. - - - The remaining part of the expansion is taken exactly. - In particular, this means that the respective growth - elements have to be constructed. - EXAMPLES:: sage: A. = AsymptoticRing('x^ZZ', QQ) From cb083d4ae0f59aa5fe3a72a53b64a1c263e8da43 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 20:09:26 +0200 Subject: [PATCH 1610/1872] Trac #19094/#19083 comment 66, 41: delete _create_exact_summands_ since not needed --- src/sage/rings/asymptotic/asymptotic_ring.py | 51 +++----------------- 1 file changed, 7 insertions(+), 44 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 61c82ede143..8f0f5513b81 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2295,9 +2295,10 @@ def _element_constructor_(self, data, simplify=True, convert=True): ... ValueError: Symbolic expression a + 1 is not in Asymptotic Ring over Integer Ring. - > *previous* ValueError: Cannot convert a to an exact summand - in an asymptotic expansion in - Asymptotic Ring over Integer Ring. + > *previous* ValueError: a is not in + Exact Term Monoid m^ZZ with coefficients in Integer Ring. + >> *previous* ValueError: Factor a of a is neither a coefficient + (in Integer Ring) nor growth (in Growth Group m^ZZ). """ from sage.data_structures.mutable_poset import MutablePoset if isinstance(data, MutablePoset): @@ -2332,7 +2333,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): try: P = data.parent() except AttributeError: - return self._create_exact_summand_(data) + return self.create_summand('exact', data) from misc import combine_exceptions from sage.symbolic.ring import SR @@ -2348,7 +2349,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): # TODO: check if summand is an O-Term here # (see #19425, #19426) try: - summands.append(self._create_exact_summand_(summand)) + summands.append(self.create_summand('exact', summand)) except ValueError as e: raise combine_exceptions( ValueError('Symbolic expression %s is not in %s.' % @@ -2396,45 +2397,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): (data, self)), e) return result - return self._create_exact_summand_(data) - - - def _create_exact_summand_(self, data): - r""" - Create an exact summand. - - This helper method is used in the element constructor. - - INPUT: - - - ``data`` -- an element. - - OUTPUT: - - An asymptotic expansion. - - TESTS:: - - sage: A. = AsymptoticRing('a^ZZ', QQ) - sage: A._create_exact_summand_(38) - 38 - """ - try: - coefficient = self.coefficient_ring(data) - except (TypeError, ValueError): - pass - else: - return self.create_summand('exact', - growth=self.growth_group.one(), - coefficient=coefficient) - - try: - return self.create_summand('exact', data) - except (TypeError, ValueError): - pass - - raise ValueError('Cannot convert %s to an exact summand in an ' - 'asymptotic expansion in %s.' % (data, self)) + return self.create_summand('exact', data) def _coerce_map_from_(self, R): From cf228bb015a33cde43feb73e1443a25feb9e0a52 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 20:36:57 +0200 Subject: [PATCH 1611/1872] Trac #19094/#19083 comment 66, 42: make creating of exact summand with growth but without coefficient impossible --- src/sage/rings/asymptotic/asymptotic_ring.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 8f0f5513b81..d1e9df013b1 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2670,6 +2670,15 @@ def create_summand(self, type, data=None, **kwds): ... ValueError: Growth 42*x^2 is not in O-Term Monoid x^ZZ with implicit coefficients in Integer Ring. > *previous* ValueError: 42*x^2 is not in Growth Group x^ZZ. + + :: + + sage: AR. = AsymptoticRing('z^QQ', QQ) + sage: AR.create_summand('exact', growth='z^2') + Traceback (most recent call last): + ... + TypeError: Cannot create exact term: only 'growth' but + no 'coefficient' specified. """ from term_monoid import TermMonoid TM = TermMonoid(type, asymptotic_ring=self) @@ -2679,6 +2688,10 @@ def create_summand(self, type, data=None, **kwds): data = kwds.pop('growth') except KeyError: raise TypeError("Neither 'data' nor 'growth' are specified.") + if type == 'exact' and kwds.get('coefficient') is None: + raise TypeError("Cannot create exact term: only 'growth' " + "but no 'coefficient' specified.") + if type == 'exact' and kwds.get('coefficient') == 0: return self.zero() From a848139a35e95bfd67d9964fa7412743942de4a4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Fri, 16 Oct 2015 20:49:31 +0200 Subject: [PATCH 1612/1872] Trac #19094/#19083 comment 66, 42: create_summands: add doctests for interesting `data` --- src/sage/rings/asymptotic/asymptotic_ring.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index d1e9df013b1..95aaca2b4b4 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2662,9 +2662,24 @@ def create_summand(self, type, data=None, **kwds): O(x^2) sage: R.create_summand('exact', growth=x^456, coefficient=123) 123*x^456 + sage: R.create_summand('exact', data=12*x^13) + 12*x^13 TESTS:: + sage: R.create_summand('exact', data='12*x^13') + 12*x^13 + sage: R.create_summand('exact', data='x^13 * 12') + 12*x^13 + sage: R.create_summand('exact', data='x^13') + x^13 + sage: R.create_summand('exact', data='12') + 12 + sage: R.create_summand('exact', data=12) + 12 + + :: + sage: R.create_summand('O', growth=42*x^2, coefficient=1) Traceback (most recent call last): ... From 525d03837adb1ef1265d44314474f59421ed2363 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 16 Oct 2015 18:09:45 -0300 Subject: [PATCH 1613/1872] Trac 18411: Fix doctest in colored_permutations.py --- src/sage/combinat/colored_permutations.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 40e14878ce9..a72c776f539 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -6,6 +6,8 @@ Much of the colored permutations (and element) class can be generalized to `G \wr S_n` """ +import itertools + from sage.categories.groups import Groups from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups @@ -16,7 +18,6 @@ from sage.misc.misc_c import prod from sage.combinat.permutation import Permutations -from sage.combinat.cartesian_product import CartesianProduct from sage.matrix.constructor import diagonal_matrix from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.number_field.number_field import CyclotomicField @@ -460,9 +461,8 @@ def __iter__(self): [[1, 0], [2, 1]], [[1, 1], [2, 1]]] """ - C = CartesianProduct(*[self._C] * self._n) for p in self._P: - for c in C: + for c in itertools.product(self._C, repeat=self._n): yield self.element_class(self, c, p) def cardinality(self): @@ -983,10 +983,9 @@ def __iter__(self): [[1, 2], [1, -2], [-1, 2], [-1, -2], [2, 1], [2, -1], [-2, 1], [-2, -1]] """ - one = ZZ.one() - C = CartesianProduct(*[[one, -one]] * self._n) + pmone = [ZZ.one(), -ZZ.one()] for p in self._P: - for c in C: + for c in itertools.product(pmone, repeat=self._n): yield self.element_class(self, c, p) def _coerce_map_from_(self, C): From f8f5b93028708eebb745a1cc92f3b775a760108b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 16 Oct 2015 20:21:19 -0500 Subject: [PATCH 1614/1872] Fixing last remaining doctests. --- src/sage/algebras/clifford_algebra.py | 4 ++-- src/sage/categories/morphism.pyx | 5 ++++- src/sage/misc/functional.py | 2 +- src/sage/rings/rational_field.py | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index bb88f5e3bb4..ded7d322cf4 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -524,8 +524,8 @@ def __init__(self, Q, names, category=None): sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl = CliffordAlgebra(Q) sage: Cl.category() - Category of finite dimensional super algebras with basis - over (euclidean domains and infinite enumerated sets) + Category of finite dimensional super algebras with basis over + (euclidean domains and infinite enumerated sets and metric spaces) sage: TestSuite(Cl).run() TESTS: diff --git a/src/sage/categories/morphism.pyx b/src/sage/categories/morphism.pyx index a6c357407ba..a76d6ab4aa3 100644 --- a/src/sage/categories/morphism.pyx +++ b/src/sage/categories/morphism.pyx @@ -162,7 +162,10 @@ cdef class Morphism(Map): sage: R. = ZZ[] sage: f = R.hom([t**2]) sage: f.category() - Category of endsets of unital magmas and right modules over (euclidean domains and infinite enumerated sets) and left modules over (euclidean domains and infinite enumerated sets) + Category of endsets of unital magmas and right modules over + (euclidean domains and infinite enumerated sets and metric spaces) + and left modules over (euclidean domains + and infinite enumerated sets and metric spaces) sage: K = CyclotomicField(12) sage: L = CyclotomicField(132) diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 607cca30874..d83e2261e64 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -124,7 +124,7 @@ def category(x): sage: V = VectorSpace(QQ,3) sage: category(V) - Category of vector spaces with basis over quotient fields + Category of vector spaces with basis over (quotient fields and metric spaces) """ try: return x.category() diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 8b5794f9e92..aefba904c9d 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -154,7 +154,7 @@ def __init__(self): sage: Q.is_field() True sage: Q.category() - Category of quotient fields + Join of Category of quotient fields and Category of metric spaces sage: Q.zeta() -1 From de137d14c23ce6687d0066de76ab233cbce954dc Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 17 Oct 2015 07:15:44 +0200 Subject: [PATCH 1615/1872] Trac #19083: fix one ReSt error --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 95aaca2b4b4..002c233a5b4 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2148,7 +2148,7 @@ def _create_element_in_extension_(self, term, old_term_parent=None): - ``term`` -- the element data. - ``old_term_parent`` -- the parent of ``term`` is compared to this - parent. If both are the same or ``old_parent`` is ``None`, + parent. If both are the same or ``old_parent`` is ``None``, then the result is an expansion in this (``self``) asymptotic ring. OUTPUT: From f9fbccb030e9a665ce76b5bd8032be852b968753 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 17 Oct 2015 07:16:08 +0200 Subject: [PATCH 1616/1872] Trac #19083: expand description of parameter "convert" --- src/sage/rings/asymptotic/asymptotic_ring.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 002c233a5b4..3d1fed0c1d9 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -460,7 +460,9 @@ class AsymptoticExpansion(CommutativeAlgebraElement): - ``convert`` -- a boolean (default: ``True``). If set, then the ``summands`` are converted to the asymptotic ring (the parent of this - expansion). If not, then the summands are taken as they are. + expansion). If not, then the summands are taken as they are. In + that case, the caller must ensure that the parent of the terms is + set correctly. EXAMPLES: @@ -2198,8 +2200,11 @@ def _element_constructor_(self, data, simplify=True, convert=True): element is simplified (terms are absorbed) automatically. - ``convert`` -- (default: ``True``) passed on to the element - constructor. If set, then it is assured that the terms belong - to this asymptotic ring (by converting them if needed). + constructor. If set, then the ``summands`` are converted to + the asymptotic ring (the parent of this expansion). If not, + then the summands are taken as they are. In that case, the + caller must ensure that the parent of the terms is set + correctly. OUTPUT: From ec81de20addced6a723f51413c3ffb31eaf4bc13 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 16 Oct 2015 22:39:38 -0700 Subject: [PATCH 1617/1872] trac 6101: make morphisms inherit from 'Morphism' --- .../homology/algebraic_topological_model.py | 20 +- src/sage/homology/chain_complex_homspace.py | 10 +- src/sage/homology/chain_complex_morphism.py | 185 ++++++++----- src/sage/homology/chain_homotopy.py | 100 +++---- src/sage/homology/homology_morphism.py | 204 ++++++++++++-- .../homology_vector_space_with_basis.py | 14 +- src/sage/homology/simplicial_complex.py | 19 +- .../homology/simplicial_complex_homset.py | 51 ++-- .../homology/simplicial_complex_morphism.py | 259 ++++++++++-------- 9 files changed, 533 insertions(+), 329 deletions(-) diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index 1d4c40fd477..dd3cc3c304d 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -123,13 +123,11 @@ def algebraic_topological_model(K, base_ring=None): sage: M.dual().degree_of_differential() 1 sage: phi.dual() - Chain homotopy between - Chain complex morphism + Chain homotopy between: + Chain complex endomorphism of Chain complex with at most 3 nonzero terms over Rational Field + and Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field - To: Chain complex with at most 3 nonzero terms over Rational Field - and Chain complex morphism - From: Chain complex with at most 3 nonzero terms over Rational Field - To: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field In degree 0, the inclusion of the homology `M` into the chain complex `C` sends the homology generator to a single vertex:: @@ -393,13 +391,11 @@ def algebraic_topological_model_delta_complex(K, base_ring=None): sage: M.dual().degree_of_differential() 1 sage: phi.dual() - Chain homotopy between - Chain complex morphism - From: Chain complex with at most 3 nonzero terms over Rational Field - To: Chain complex with at most 3 nonzero terms over Rational Field - and Chain complex morphism + Chain homotopy between: + Chain complex endomorphism of Chain complex with at most 3 nonzero terms over Rational Field + and Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field - To: Chain complex with at most 3 nonzero terms over Rational Field + To: Chain complex with at most 3 nonzero terms over Rational Field In degree 0, the inclusion of the homology `M` into the chain complex `C` sends the homology generator to a single vertex:: diff --git a/src/sage/homology/chain_complex_homspace.py b/src/sage/homology/chain_complex_homspace.py index 5cd61825cb8..4bfc7e2da34 100644 --- a/src/sage/homology/chain_complex_homspace.py +++ b/src/sage/homology/chain_complex_homspace.py @@ -23,7 +23,7 @@ sage: i = H.identity() sage: x = i.associated_chain_complex_morphism(augmented=True) sage: x - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 4 nonzero terms over Integer Ring To: Chain complex with at most 4 nonzero terms over Integer Ring sage: x._matrix_dictionary @@ -64,13 +64,13 @@ sage: i = A.identity() sage: x = i.associated_chain_complex_morphism() sage: x - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring To: Chain complex with at most 3 nonzero terms over Integer Ring sage: y = x*4 sage: z = y*y sage: (y+z) - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring To: Chain complex with at most 3 nonzero terms over Integer Ring sage: f = x._matrix_dictionary @@ -99,7 +99,7 @@ #***************************************************************************** import sage.categories.homset -import sage.homology.chain_complex_morphism as chain_complex_morphism +from sage.homology.chain_complex_morphism import ChainComplexMorphism def is_ChainComplexHomspace(x): """ @@ -148,4 +148,4 @@ def __call__(self, f): True """ - return chain_complex_morphism.ChainComplexMorphism(f, self.domain(), self.codomain()) + return ChainComplexMorphism(f, self.domain(), self.codomain()) diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index 03a62ec89a7..5e79d25db3b 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -14,7 +14,6 @@ EXAMPLES:: - from sage.matrix.constructor import zero_matrix sage: S = simplicial_complexes.Sphere(1) sage: S Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} @@ -27,9 +26,7 @@ sage: G = Hom(C,C) sage: x = G(f) sage: x - Chain complex morphism - From: Chain complex with at most 2 nonzero terms over Integer Ring - To: Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex endomorphism of Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] @@ -54,9 +51,10 @@ # #***************************************************************************** -import sage.matrix.all as matrix -from sage.structure.sage_object import SageObject -from sage.rings.integer_ring import ZZ +from sage.matrix.constructor import block_diagonal_matrix, zero_matrix +from sage.categories.morphism import Morphism +from sage.categories.homset import Hom +from sage.categories.category_types import ChainComplexes def is_ChainComplexMorphism(x): """ @@ -73,7 +71,7 @@ def is_ChainComplexMorphism(x): sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() sage: x # indirect doctest - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 7 nonzero terms over Integer Ring To: Chain complex with at most 7 nonzero terms over Integer Ring sage: is_ChainComplexMorphism(x) @@ -81,7 +79,7 @@ def is_ChainComplexMorphism(x): """ return isinstance(x,ChainComplexMorphism) -class ChainComplexMorphism(SageObject): +class ChainComplexMorphism(Morphism): """ An element of this class is a morphism of chain complexes. """ @@ -91,7 +89,6 @@ def __init__(self, matrices, C, D, check=True): EXAMPLES:: - from sage.matrix.constructor import zero_matrix sage: S = simplicial_complexes.Sphere(1) sage: S Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} @@ -104,9 +101,7 @@ def __init__(self, matrices, C, D, check=True): sage: G = Hom(C,C) sage: x = G(f) sage: x - Chain complex morphism - From: Chain complex with at most 2 nonzero terms over Integer Ring - To: Chain complex with at most 2 nonzero terms over Integer Ring + Chain complex endomorphism of Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] @@ -120,7 +115,7 @@ def __init__(self, matrices, C, D, check=True): sage: Y = simplicial_complexes.Simplex(0) sage: g = Hom(X,Y)({0:0, 1:0}) sage: g.associated_chain_complex_morphism() - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 1 nonzero terms over Integer Ring @@ -133,7 +128,7 @@ def __init__(self, matrices, C, D, check=True): ... ValueError: matrix in degree 0 is not the right size sage: Hom(C,D)({0: matrix(2, 1, [1, 1])}) # 2x1 is right. - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Integer Ring To: Chain complex with at most 1 nonzero terms over Integer Ring """ @@ -156,9 +151,9 @@ def __init__(self, matrices, C, D, check=True): try: matrices[i] = initial_matrices.pop(i) except KeyError: - matrices[i] = matrix.zero_matrix(C.base_ring(), - D.differential(i).ncols(), - C.differential(i).ncols(), sparse=True) + matrices[i] = zero_matrix(C.base_ring(), + D.differential(i).ncols(), + C.differential(i).ncols(), sparse=True) if check: # All remaining matrices given must be 0x0. if not all(m.ncols() == m.nrows() == 0 for m in initial_matrices.values()): @@ -188,36 +183,7 @@ def __init__(self, matrices, C, D, check=True): # Use immutable matrices because they're hashable. m.set_immutable() self._matrix_dictionary[i] = m - self._domain = C - self._codomain = D - - def domain(self): - """ - The domain of this chain map - - EXAMPLES:: - - sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) - sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) - sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) - sage: f.domain() - Chain complex with at most 2 nonzero terms over Integer Ring - """ - return self._domain - - def codomain(self): - """ - The codomain of this chain map - - EXAMPLES:: - - sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) - sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) - sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) - sage: f.codomain() - Chain complex with at most 3 nonzero terms over Integer Ring - """ - return self._codomain + Morphism.__init__(self, Hom(C,D, ChainComplexes(C.base_ring()))) def in_degree(self, n): """ @@ -250,11 +216,44 @@ def in_degree(self, n): try: return self._matrix_dictionary[n] except KeyError: - from sage.matrix.constructor import zero_matrix rows = self.codomain().free_module_rank(n) cols = self.domain().free_module_rank(n) return zero_matrix(self.domain().base_ring(), rows, cols) + def to_matrix(self, deg=None): + """ + The matrix representing this chain map. + + If the degree ``deg`` is specified, return the matrix in that + degree; otherwise, return the (block) matrix for the whole + chain map. + + INPUTS: + + - ``deg`` -- (optional, default ``None``) the degree + + EXAMPLES:: + + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f.to_matrix(0) + [1] + sage: f.to_matrix() + [1|0|] + [-+-+] + [0|0|] + [-+-+] + [0|0|] + """ + if deg is not None: + return self.in_degree(deg) + row = 0 + col = 0 + blocks = [self._matrix_dictionary[n] + for n in sorted(self._matrix_dictionary.keys())] + return block_diagonal_matrix(blocks) + def dual(self): """ The dual chain map to this one. @@ -272,7 +271,7 @@ def dual(self): sage: f.in_degree(0) [1 1] sage: f.dual() - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Integer Ring To: Chain complex with at most 2 nonzero terms over Integer Ring sage: f.dual().in_degree(0) @@ -423,7 +422,7 @@ def __mul__(self,x): sage: f = ChainComplexMorphism({}, C0, C1) sage: g = ChainComplexMorphism({}, C1, C2) sage: g * f - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Integer Ring To: Chain complex with at most 1 nonzero terms over Integer Ring sage: f._matrix_dictionary @@ -495,7 +494,6 @@ def __sub__(self,x): [0 0 0 0] [0 0 0 0] [0 0 0 0]} - """ return self + (-x) @@ -510,7 +508,7 @@ def __eq__(self,x): sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() sage: x - Chain complex morphism + Chain complex morphism: From: Trivial chain complex over Integer Ring To: Trivial chain complex over Integer Ring sage: f = x._matrix_dictionary @@ -525,6 +523,64 @@ def __eq__(self,x): and self.domain() == x.domain() \ and self._matrix_dictionary == x._matrix_dictionary + def is_identity(self): + """ + True if this is the identity map. + + EXAMPLES:: + + sage: S = SimplicialComplex(is_mutable=False) + sage: H = Hom(S,S) + sage: i = H.identity() + sage: x = i.associated_chain_complex_morphism() + sage: x.is_identity() + True + """ + return self.to_matrix().is_one() + + def is_surjective(self): + """ + True if this map is surjective. + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: H = Hom(S1, S1) + sage: flip = H({0:0, 1:2, 2:1}) + sage: flip.associated_chain_complex_morphism().is_surjective() + True + + sage: pt = simplicial_complexes.Simplex(0) + sage: inclusion = Hom(pt, S1)({0:2}) + sage: inclusion.associated_chain_complex_morphism().is_surjective() + False + sage: inclusion.associated_chain_complex_morphism(cochain=True).is_surjective() + True + """ + m = self.to_matrix() + return m.rank() == m.nrows() + + def is_injective(self): + """ + True if this map is injective. + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: H = Hom(S1, S1) + sage: flip = H({0:0, 1:2, 2:1}) + sage: flip.associated_chain_complex_morphism().is_injective() + True + + sage: pt = simplicial_complexes.Simplex(0) + sage: inclusion = Hom(pt, S1)({0:2}) + sage: inclusion.associated_chain_complex_morphism().is_injective() + True + sage: inclusion.associated_chain_complex_morphism(cochain=True).is_injective() + False + """ + return self.to_matrix().right_nullity() == 0 + def __hash__(self): """ TESTS:: @@ -537,24 +593,13 @@ def __hash__(self): """ return hash(self.domain()) ^ hash(self.codomain()) ^ hash(tuple(self._matrix_dictionary.items())) - def _repr_(self): + def _repr_type(self): """ - Return the string representation of ``self``. - EXAMPLES:: - sage: S = SimplicialComplex(is_mutable=False) - sage: H = Hom(S,S) - sage: i = H.identity() - sage: x = i.associated_chain_complex_morphism() - sage: x - Chain complex morphism - From: Trivial chain complex over Integer Ring - To: Trivial chain complex over Integer Ring - sage: x._repr_() - 'Chain complex morphism\n From: Trivial chain complex over Integer Ring\n To: Trivial chain complex over Integer Ring' + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1)}) + sage: Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)})._repr_type() + 'Chain complex' """ - s = 'Chain complex morphism' - s += '\n From: {}'.format(self.domain()) - s += '\n To: {}'.format(self.codomain()) - return s + return "Chain complex" diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index 6f1bba15a5f..11350ec6c43 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -58,10 +58,13 @@ # http://www.gnu.org/licenses/ ######################################################################## -from sage.structure.sage_object import SageObject +from sage.categories.morphism import Morphism +from sage.categories.homset import Hom from sage.homology.chain_complex_morphism import ChainComplexMorphism -class ChainHomotopy(SageObject): +# In a perfect world, this would inherit from something like +# "TwoMorphism" rather than "Morphism"... +class ChainHomotopy(Morphism): r""" A chain homotopy. @@ -107,7 +110,7 @@ class ChainHomotopy(SageObject): and ``H._g``:: sage: H._f - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 2 nonzero terms over Integer Ring sage: H._f.in_degree(0) @@ -157,18 +160,18 @@ def __init__(self, matrices, f, g=None): ... ValueError: the chain maps are not compatible """ - domain = f._domain - codomain = f._codomain + domain = f.domain() + codomain = f.codomain() deg = domain.degree_of_differential() # Check that the chain complexes are compatible. This should # never arise, because first there should be errors in # constructing the chain maps. But just in case... - assert (domain.degree_of_differential() == - codomain.degree_of_differential()), 'the chain complexes are not compatible' - if g: + if domain.degree_of_differential() != codomain.degree_of_differential(): + raise ValueError('the chain complexes are not compatible') + if g is not None: # Check that the chain maps are compatible. - if not (domain == g._domain and codomain == - g._codomain): + if not (domain == g.domain() and codomain == + g.codomain()): raise ValueError('the chain maps are not compatible') # Check that the data define a chain homotopy. for i in domain.differential(): @@ -192,8 +195,6 @@ def __init__(self, matrices, f, g=None): elif i+deg in matrices: g_data[i] = f.in_degree(i) - matrices[i+deg] * domain.differential(i) g = ChainComplexMorphism(g_data, domain, codomain) - self._domain = domain - self._codomain = codomain self._matrix_dictionary = {} for i in matrices: m = matrices[i] @@ -202,6 +203,7 @@ def __init__(self, matrices, f, g=None): self._matrix_dictionary[i] = m self._f = f self._g = g + Morphism.__init__(self, Hom(domain, codomain)) def is_algebraic_gradient_vector_field(self): r""" @@ -237,9 +239,9 @@ def is_algebraic_gradient_vector_field(self): sage: H.is_algebraic_gradient_vector_field() False """ - if self._domain != self._codomain: + if self.domain() != self.codomain(): return False - deg = self._domain.degree_of_differential() + deg = self.domain().degree_of_differential() matrices = self._matrix_dictionary for i in matrices: if i-deg in matrices: @@ -272,14 +274,14 @@ def is_homology_gradient_vector_field(self): """ if not self.is_algebraic_gradient_vector_field(): return False - deg = self._domain.degree_of_differential() + deg = self.domain().degree_of_differential() matrices = self._matrix_dictionary for i in matrices: if i+deg in matrices: - diff_i = self._domain.differential(i) + diff_i = self.domain().differential(i) if diff_i * matrices[i+deg] * diff_i != diff_i: return False - if matrices[i] * self._domain.differential(i-deg) * matrices[i] != matrices[i]: + if matrices[i] * self.domain().differential(i-deg) * matrices[i] != matrices[i]: return False return True @@ -311,42 +313,10 @@ def in_degree(self, n): return self._matrix_dictionary[n] except KeyError: from sage.matrix.constructor import zero_matrix - deg = self._domain.degree_of_differential() - rows = self._codomain.free_module_rank(n-deg) - cols = self._domain.free_module_rank(n) - return zero_matrix(self._domain.base_ring(), rows, cols) - - def domain(self): - """ - The domain of this chain homotopy. - - EXAMPLES:: - - sage: from sage.homology.chain_homotopy import ChainHomotopy - sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 - sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 - sage: f = Hom(C, D)({}) - sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) - sage: H.domain() - Chain complex with at most 1 nonzero terms over Integer Ring - """ - return self._domain - - def codomain(self): - """ - The domain of this chain homotopy. - - EXAMPLES:: - - sage: from sage.homology.chain_homotopy import ChainHomotopy - sage: C = ChainComplex({1: matrix(ZZ, 0, 2)}) # one nonzero term in degree 1 - sage: D = ChainComplex({0: matrix(ZZ, 0, 1)}) # one nonzero term in degree 0 - sage: f = Hom(C, D)({}) - sage: H = ChainHomotopy({1: matrix(ZZ, 1, 2, (3,1))}, f, f) - sage: H.codomain() - Chain complex with at most 1 nonzero terms over Integer Ring - """ - return self._codomain + deg = self.domain().degree_of_differential() + rows = self.codomain().free_module_rank(n-deg) + cols = self.domain().free_module_rank(n) + return zero_matrix(self.domain().base_ring(), rows, cols) def dual(self): r""" @@ -372,7 +342,7 @@ def dual(self): [1] """ matrix_dict = self._matrix_dictionary - deg = self._domain.degree_of_differential() + deg = self.domain().degree_of_differential() matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} return ChainHomotopy(matrices, self._f.dual(), self._g.dual()) @@ -402,15 +372,15 @@ def _repr_(self): sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: g = Hom(C,D)({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: ChainHomotopy({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1)}, f, g) - Chain homotopy between - Chain complex morphism + Chain homotopy between: + Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 2 nonzero terms over Integer Ring - and Chain complex morphism + and Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 2 nonzero terms over Integer Ring """ - s = 'Chain homotopy between' + s = 'Chain homotopy between:' s += '\n {}'.format('\n '.join(self._f._repr_().split('\n'))) s += '\n and {}'.format('\n '.join(self._g._repr_().split('\n'))) return s @@ -490,11 +460,11 @@ def __init__(self, matrices, pi, iota): from sage.matrix.constructor import identity_matrix from chain_complex_morphism import ChainComplexMorphism - if not (pi._domain == iota._codomain - and pi._codomain == iota._domain): + if not (pi.domain() == iota.codomain() + and pi.codomain() == iota.domain()): raise ValueError('the chain maps are not composable') - C = pi._domain - D = pi._codomain + C = pi.domain() + D = pi.codomain() base_ring = C.base_ring() # Check that the composite 'pi iota' is 1. @@ -536,7 +506,7 @@ def pi(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.pi() - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field sage: phi.pi().in_degree(0) # Every vertex represents a homology class. @@ -560,7 +530,7 @@ def iota(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.iota() - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field @@ -594,7 +564,7 @@ def dual(self): sage: S2 = simplicial_complexes.Sphere(2) sage: phi, M = S2.algebraic_topological_model(QQ) sage: phi.iota() - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field diff --git a/src/sage/homology/homology_morphism.py b/src/sage/homology/homology_morphism.py index 2dd73fce323..c18cc78b1bf 100644 --- a/src/sage/homology/homology_morphism.py +++ b/src/sage/homology/homology_morphism.py @@ -27,11 +27,14 @@ # - associated_chain_complex_morphism # Once this is done, the code here ought to work without modification. -from sage.structure.sage_object import SageObject +from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis +from sage.categories.graded_modules_with_basis import GradedModulesWithBasis +from sage.categories.morphism import Morphism +from sage.categories.homset import Hom from sage.rings.rational_field import QQ -class InducedHomologyMorphism(SageObject): - """ +class InducedHomologyMorphism(Morphism): + r""" An element of this class is a morphism of (co)homology groups induced by a map of simplicial complexes. It requires working with field coefficients. @@ -48,7 +51,7 @@ class InducedHomologyMorphism(SageObject): This is not intended to be used directly by the user, but instead via the method - :meth:`simplicial_complex_morphism.SimplicialComplexMorphism.induced_homology_morphism`. + :meth:`~sage.homology.simplicial_complex_morphism.SimplicialComplexMorphism.induced_homology_morphism`. EXAMPLES:: @@ -56,11 +59,22 @@ class InducedHomologyMorphism(SageObject): sage: H = Hom(S1, S1) sage: f = H({0:0, 1:2, 2:1}) # f switches two vertices sage: f_star = f.induced_homology_morphism(QQ, cohomology=True) + sage: f_star + Graded algebra endomorphism of Cohomology ring of Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} over Rational Field + Defn: induced by: + Simplicial complex endomorphism of Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + Defn: 0 |--> 0 + 1 |--> 2 + 2 |--> 1 sage: f_star.to_matrix(1) [-1] + sage: f_star.to_matrix() + [ 1| 0] + [--+--] + [ 0|-1] sage: T = simplicial_complexes.Torus() - sage: y = T.homology_with_basis(1, QQ).basis()[1] + sage: y = T.homology_with_basis(QQ).basis()[(1,1)] sage: y.to_cycle() (0, 3) - (0, 6) + (3, 6) @@ -68,8 +82,13 @@ class InducedHomologyMorphism(SageObject): class in the torus, we can define a map `S^1 \to T` inducing an inclusion on `H_1`:: - sage: Hom(S1, T)({0:0, 1:3, 2: 6}) - Simplicial complex morphism {0: 0, 1: 3, 2: 6} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6) and 14 facets + sage: Hom(S1, T)({0:0, 1:3, 2:6}) + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + To: Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6) and 14 facets + Defn: 0 |--> 0 + 1 |--> 3 + 2 |--> 6 sage: g = Hom(S1, T)({0:0, 1:3, 2: 6}) sage: g_star = g.induced_homology_morphism(QQ) sage: g_star.to_matrix(0) @@ -77,6 +96,29 @@ class in the torus, we can define a map `S^1 \to T` inducing an sage: g_star.to_matrix(1) [0] [1] + sage: g_star.to_matrix() + [1|0] + [-+-] + [0|0] + [0|1] + [-+-] + [0|0] + + We can evaluate such a map on (co)homology classes:: + + sage: H = S1.homology_with_basis(QQ) + sage: a = H.basis()[(1,0)] + sage: g_star(a) + h_{1,1} + + sage: T = S1.product(S1, is_mutable=False) + sage: diag = Hom(S1,T).diagonal_morphism() + sage: b,c = list(T.cohomology_ring().basis(1)) + sage: diag_c = diag.induced_homology_morphism(cohomology=True) + sage: diag_c(b) + h^{1,0} + sage: diag_c(c) + h^{1,0} """ def __init__(self, map, base_ring=None, cohomology=False): """ @@ -123,6 +165,16 @@ def __init__(self, map, base_ring=None, cohomology=False): self._cohomology = cohomology self._map = map self._base_ring = base_ring + if cohomology: + domain = map.domain().cohomology_ring(base_ring=base_ring) + codomain = map.codomain().cohomology_ring(base_ring=base_ring) + Morphism.__init__(self, Hom(domain, codomain, + category=GradedAlgebrasWithBasis(base_ring))) + else: + domain = map.domain().homology_with_basis(base_ring=base_ring, cohomology=cohomology) + codomain = map.codomain().homology_with_basis(base_ring=base_ring, cohomology=cohomology) + Morphism.__init__(self, Hom(domain, codomain, + category=GradedModulesWithBasis(base_ring))) def base_ring(self): """ @@ -140,13 +192,17 @@ def base_ring(self): """ return self._base_ring - def to_matrix(self, deg): + def to_matrix(self, deg=None): """ - The matrix for this map in degree ``deg`` + The matrix for this map. + + If degree ``deg`` is specified, return the matrix just in that + degree; otherwise, return the block matrix representing the + entire map. INPUTS: - - ``deg`` -- integer + - ``deg`` -- (optional, default ``None``) the degree EXAMPLES:: @@ -158,6 +214,10 @@ def to_matrix(self, deg): sage: h = f.induced_homology_morphism(QQ) sage: h.to_matrix(1) [2] + sage: h.to_matrix() + [1|0] + [-+-] + [0|2] """ base_ring = self.base_ring() if self._cohomology: @@ -166,9 +226,20 @@ def to_matrix(self, deg): else: domain = self._map.domain() codomain = self._map.codomain() - phi_codomain, _ = codomain.algebraic_topological_model(base_ring) - phi_domain, _ = domain.algebraic_topological_model(base_ring) - return phi_codomain.pi().in_degree(deg) * self._map.associated_chain_complex_morphism(self.base_ring(), cochain=self._cohomology).in_degree(deg) * phi_domain.iota().in_degree(deg) + phi_codomain, H_codomain = codomain.algebraic_topological_model(base_ring) + phi_domain, H_domain = domain.algebraic_topological_model(base_ring) + mat = phi_codomain.pi().to_matrix(deg) * self._map.associated_chain_complex_morphism(self.base_ring(), cochain=self._cohomology).to_matrix(deg) * phi_domain.iota().to_matrix(deg) + if deg is None: + import numpy as np + betti_domain = [H_domain.free_module_rank(n) + for n in range(domain.dimension()+1)] + betti_codomain = [H_codomain.free_module_rank(n) + for n in range(codomain.dimension()+1)] + # Compute cumulative sums of Betti numbers to get subdivisions: + row_subdivs = list(np.cumsum(betti_codomain[:-1])) + col_subdivs = list(np.cumsum(betti_domain[:-1])) + mat.subdivide(row_subdivs, col_subdivs) + return mat def __call__(self, elt): """ @@ -187,24 +258,23 @@ def __call__(self, elt): sage: H = Hom(S1,S1) sage: g = H(f) sage: h = g.induced_homology_morphism(QQ) - sage: x = S1.homology_with_basis(1).basis()[0] + sage: x = S1.homology_with_basis().basis()[(1,0)] sage: x h_{1,0} sage: h(x) # indirect doctest -h_{1,0} """ - deg = elt.parent().degree() base_ring = self.base_ring() if self._cohomology: - codomain = self._map.domain().cohomology_with_basis(deg, base_ring) + codomain = self._map.domain().homology_with_basis(base_ring, cohomology=True) if elt.parent().complex() != self._map.codomain(): raise ValueError('element is not a cohomology class for the correct complex') else: - codomain = self._map.codomain().homology_with_basis(deg, base_ring) + codomain = self._map.codomain().homology_with_basis(base_ring) if elt.parent().complex() != self._map.domain(): raise ValueError('element is not a homology class for the correct complex') - return codomain.from_vector(self.to_matrix(deg) * elt.to_vector()) + return codomain.from_vector(self.to_matrix() * elt.to_vector()) def __eq__(self, other): """ @@ -244,18 +314,96 @@ def __eq__(self, other): dim = min(self._map.domain().dimension(), self._map.codomain().dimension()) return all(self.to_matrix(d) == other.to_matrix(d) for d in range(dim+1)) - def _repr_(self): + def is_identity(self): + """ + True if this is the identity map on (co)homology. + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: H = Hom(S1, S1) + sage: flip = H({0:0, 1:2, 2:1}) + sage: flip.induced_homology_morphism(QQ).is_identity() + False + sage: flip.induced_homology_morphism(GF(2)).is_identity() + True + sage: rotate = H({0:1, 1:2, 2:0}) + sage: rotate.induced_homology_morphism(QQ).is_identity() + True + """ + return self.to_matrix().is_one() + + def is_surjective(self): + """ + True if this map is surjective on (co)homology. + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: K = simplicial_complexes.Simplex(2) + sage: H = Hom(S1, K) + sage: f = H({0:0, 1:1, 2:2}) + sage: f.induced_homology_morphism().is_surjective() + True + sage: f.induced_homology_morphism(cohomology=True).is_surjective() + False + """ + m = self.to_matrix() + return m.rank() == m.nrows() + + def is_injective(self): """ - Return the string representation of ``self``. + True if this map is injective on (co)homology. EXAMPLES:: - sage: K = simplicial_complexes.Simplex(1) - sage: f = Hom(K,K).identity() - sage: f.induced_homology_morphism(QQ) - Homology morphism induced by Simplicial complex morphism {0: 0, 1: 1} from Simplicial complex with vertex set (0, 1) and facets {(0, 1)} to Simplicial complex with vertex set (0, 1) and facets {(0, 1)} - sage: f.induced_homology_morphism(QQ, cohomology=True) - Cohomology morphism induced by Simplicial complex morphism {0: 0, 1: 1} from Simplicial complex with vertex set (0, 1) and facets {(0, 1)} to Simplicial complex with vertex set (0, 1) and facets {(0, 1)} + sage: S1 = simplicial_complexes.Sphere(1) + sage: K = simplicial_complexes.Simplex(2) + sage: H = Hom(S1, K) + sage: f = H({0:0, 1:1, 2:2}) + sage: f.induced_homology_morphism().is_injective() + False + sage: f.induced_homology_morphism(cohomology=True).is_injective() + True + + sage: T = simplicial_complexes.Torus() + sage: g = Hom(S1, T)({0:0, 1:3, 2: 6}) + sage: g_star = g.induced_homology_morphism(QQ) + sage: g.is_injective() + True + """ + return self.to_matrix().right_nullity() == 0 + + def _repr_type(self): + """ + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: K = simplicial_complexes.Simplex(2) + sage: f = Hom(S1, K)({0: 0, 1:1, 2:2}) + sage: f.induced_homology_morphism()._repr_type() + 'Graded vector space' + sage: f.induced_homology_morphism(cohomology=True)._repr_type() + 'Graded algebra' + """ + return "Graded vector space" if not self._cohomology else "Graded algebra" + + def _repr_defn(self): + """ + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: K = simplicial_complexes.Simplex(2) + sage: f = Hom(S1, K)({0: 0, 1:1, 2:2}) + sage: print f.induced_homology_morphism()._repr_defn() + induced by: + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + To: Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)} + Defn: 0 |--> 0 + 1 |--> 1 + 2 |--> 2 """ - name = "Homology" if not self._cohomology else "Cohomology" - return "{} morphism induced by {}".format(name, self._map) + s = "induced by:" + s += '\n {}'.format('\n '.join(self._map._repr_().split('\n'))) + return s diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index bb67ea1f41b..15c42394f4c 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -242,24 +242,20 @@ def contraction(self): sage: H = simplicial_complexes.Simplex(2).homology_with_basis(QQ) sage: H.contraction() - Chain homotopy between - Chain complex morphism - From: Chain complex with at most 3 nonzero terms over Rational Field - To: Chain complex with at most 3 nonzero terms over Rational Field - and Chain complex morphism - From: Chain complex with at most 3 nonzero terms over Rational Field - To: Chain complex with at most 3 nonzero terms over Rational Field + Chain homotopy between: + Chain complex endomorphism of Chain complex with at most 3 nonzero terms over Rational Field + and Chain complex endomorphism of Chain complex with at most 3 nonzero terms over Rational Field From the chain contraction, one can also recover the maps `\pi` and `\iota`:: sage: phi = H.contraction() sage: phi.pi() - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 1 nonzero terms over Rational Field sage: phi.iota() - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field """ diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index 8b8bc58b6d3..7c1cdf2dfbd 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -158,7 +158,7 @@ from sage.misc.lazy_import import lazy_import from sage.homology.cell_complex import GenericCellComplex from sage.structure.sage_object import SageObject -from sage.structure.category_object import CategoryObject +from sage.structure.parent import Parent from sage.rings.integer import Integer from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.sets.set import Set @@ -735,7 +735,7 @@ def _latex_(self): """ return latex(self.__tuple) -class SimplicialComplex(CategoryObject, GenericCellComplex): +class SimplicialComplex(Parent, GenericCellComplex): r""" Define a simplicial complex. @@ -871,13 +871,13 @@ def __init__(self, sage: S == loads(dumps(S)) True - sage: TestSuite(S).run() - sage: TestSuite(S3).run() + sage: TestSuite(S).run(skip="_test_category") + sage: TestSuite(S3).run(skip="_test_category") """ if (maximal_faces is not None and from_characteristic_function is not None): raise ValueError("maximal_faces and from_characteristic_function cannot be both defined") - CategoryObject.__init__(self, category=SimplicialComplexes()) + Parent.__init__(self, category=SimplicialComplexes()) from sage.misc.misc import union C = None @@ -1031,7 +1031,7 @@ def __cmp__(self,right): sage: X == SimplicialComplex([[1,3]]) True """ - if set(self._facets) == set(right._facets): + if isinstance(right, SimplicialComplex) and set(self._facets) == set(right._facets): return 0 else: return -1 @@ -3332,7 +3332,12 @@ def _Hom_(self, other, category=None): sage: f = {0:0,1:1,2:3} sage: x = H(f) sage: x - Simplicial complex morphism {0: 0, 1: 1, 2: 3} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + To: Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Defn: 0 |--> 0 + 1 |--> 1 + 2 |--> 3 sage: S._Hom_(T, Objects()) Traceback (most recent call last): diff --git a/src/sage/homology/simplicial_complex_homset.py b/src/sage/homology/simplicial_complex_homset.py index 23c8596e53b..9874dfb4c5c 100644 --- a/src/sage/homology/simplicial_complex_homset.py +++ b/src/sage/homology/simplicial_complex_homset.py @@ -16,7 +16,12 @@ sage: f = {0:0,1:1,2:3} sage: x = H(f) sage: x - Simplicial complex morphism {0: 0, 1: 1, 2: 3} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + To: Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Defn: 0 |--> 0 + 1 |--> 1 + 2 |--> 3 sage: x.is_injective() True sage: x.is_surjective() @@ -55,7 +60,7 @@ #***************************************************************************** import sage.categories.homset -import sage.homology.simplicial_complex_morphism as simplicial_complex_morphism +from sage.homology.simplicial_complex_morphism import SimplicialComplexMorphism def is_SimplicialComplexHomset(x): """ @@ -90,9 +95,12 @@ def __call__(self, f): sage: H = Hom(S,T) sage: x = H(f) sage: x - Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 2, 4: 2} from Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets + To: Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Defn: [0, 1, 2, 3, 4] --> [0, 1, 2, 2, 2] """ - return simplicial_complex_morphism.SimplicialComplexMorphism(f,self.domain(),self.codomain()) + return SimplicialComplexMorphism(f,self.domain(),self.codomain()) def diagonal_morphism(self,rename_vertices=True): r""" @@ -104,18 +112,24 @@ def diagonal_morphism(self,rename_vertices=True): sage: H = Hom(S,S.product(S, is_mutable=False)) sage: d = H.diagonal_morphism() sage: d - Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2', 3: 'L3R3'} from - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} - to Simplicial complex with 16 vertices and 96 facets + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + To: Simplicial complex with 16 vertices and 96 facets + Defn: 0 |--> L0R0 + 1 |--> L1R1 + 2 |--> L2R2 + 3 |--> L3R3 sage: T = SimplicialComplex([[0], [1]], is_mutable=False) sage: U = T.product(T,rename_vertices = False, is_mutable=False) sage: G = Hom(T,U) sage: e = G.diagonal_morphism(rename_vertices = False) sage: e - Simplicial complex morphism {0: (0, 0), 1: (1, 1)} from - Simplicial complex with vertex set (0, 1) and facets {(0,), (1,)} - to Simplicial complex with 4 vertices and facets {((1, 1),), ((1, 0),), ((0, 0),), ((0, 1),)} + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1) and facets {(0,), (1,)} + To: Simplicial complex with 4 vertices and facets {((1, 1),), ((1, 0),), ((0, 0),), ((0, 1),)} + Defn: 0 |--> (0, 0) + 1 |--> (1, 1) """ if self._codomain == self._domain.product(self._domain,rename_vertices=rename_vertices): @@ -129,7 +143,7 @@ def diagonal_morphism(self,rename_vertices=True): else: for i in self._domain.vertices().set(): f[i] = (i,i) - return simplicial_complex_morphism.SimplicialComplexMorphism(f, self._domain,X) + return SimplicialComplexMorphism(f, self._domain,X) else: raise TypeError("Diagonal morphism is only defined for Hom(X,XxX).") @@ -148,15 +162,15 @@ def identity(self): sage: T = SimplicialComplex([[0,1]], is_mutable=False) sage: G = Hom(T,T) sage: G.identity() - Simplicial complex morphism {0: 0, 1: 1} from - Simplicial complex with vertex set (0, 1) and facets {(0, 1)} to - Simplicial complex with vertex set (0, 1) and facets {(0, 1)} + Simplicial complex endomorphism of Simplicial complex with vertex set (0, 1) and facets {(0, 1)} + Defn: 0 |--> 0 + 1 |--> 1 """ if self.is_endomorphism_set(): f = dict() for i in self._domain.vertices().set(): f[i]=i - return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,self._codomain) + return SimplicialComplexMorphism(f,self._domain,self._codomain) else: raise TypeError("Identity map is only defined for endomorphism sets.") @@ -171,7 +185,10 @@ def an_element(self): sage: H = Hom(S,T) sage: x = H.an_element() sage: x - Simplicial complex morphism {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0} from Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets to Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6) and 7 facets + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets + To: Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6) and 7 facets + Defn: [0, 1, 2, 3, 4, 5, 6, 7] --> [0, 0, 0, 0, 0, 0, 0, 0] """ X_vertices = self._domain.vertices().set() try: @@ -184,4 +201,4 @@ def an_element(self): f = dict() for x in X_vertices: f[x]=i - return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,self._codomain) + return SimplicialComplexMorphism(f,self._domain,self._codomain) diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py index 18853ec07a5..9bc33ea4acc 100644 --- a/src/sage/homology/simplicial_complex_morphism.py +++ b/src/sage/homology/simplicial_complex_morphism.py @@ -20,7 +20,10 @@ sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False) sage: H = Hom(S,S.product(S, is_mutable=False)) sage: H.diagonal_morphism() - Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2', 3: 'L3R3', 4: 'L4R4', 5: 'L5R5'} from Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (1, 5), (0, 2)} to Simplicial complex with 36 vertices and 18 facets + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (1, 5), (0, 2)} + To: Simplicial complex with 36 vertices and 18 facets + Defn: [0, 1, 2, 3, 4, 5] --> ['L0R0', 'L1R1', 'L2R2', 'L3R3', 'L4R4', 'L5R5'] sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False) sage: T = SimplicialComplex([[0,2],[1,3]], is_mutable=False) @@ -53,8 +56,13 @@ sage: i = H.identity() sage: j = i.fiber_product(i) sage: j - Simplicial complex morphism {'L1R1': 1, 'L3R3': 3, 'L2R2': 2, 'L0R0': 0} from Simplicial complex with 4 vertices and 4 facets to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} - + Simplicial complex morphism: + From: Simplicial complex with 4 vertices and 4 facets + To: Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Defn: L1R1 |--> 1 + L3R3 |--> 3 + L2R2 |--> 2 + L0R0 |--> 0 sage: S = simplicial_complexes.Sphere(2) sage: T = S.product(SimplicialComplex([[0,1]]), rename_vertices = False, is_mutable=False) sage: H = Hom(T,S) @@ -72,7 +80,10 @@ sage: y = G(g) sage: z = y.fiber_product(x) sage: z # this is the mapping path space - Simplicial complex morphism {'L2R(2, 0)': 2, 'L2R(2, 1)': 2, 'L0R(0, 0)': 0, 'L0R(0, 1)': 0, 'L1R(1, 0)': 1, 'L1R(1, 1)': 1} from Simplicial complex with 6 vertices and 6 facets to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Simplicial complex morphism: + From: Simplicial complex with 6 vertices and 6 facets + To: Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Defn: ['L2R(2, 0)', 'L2R(2, 1)', 'L0R(0, 0)', 'L0R(0, 1)', 'L1R(1, 0)', 'L1R(1, 1)'] --> [2, 2, 0, 0, 1, 1] """ #***************************************************************************** @@ -91,13 +102,15 @@ # #***************************************************************************** -import sage.homology.simplicial_complex as simplicial_complex -import sage.matrix.all as matrix -from sage.structure.sage_object import SageObject +from sage.homology.simplicial_complex import Simplex, SimplicialComplex +from sage.matrix.constructor import matrix, zero_matrix from sage.rings.integer_ring import ZZ from sage.homology.chain_complex_morphism import ChainComplexMorphism from sage.combinat.permutation import Permutation from sage.algebras.steenrod.steenrod_algebra_misc import convert_perm +from sage.categories.morphism import Morphism +from sage.categories.homset import Hom +from sage.categories.category_types import SimplicialComplexes def is_SimplicialComplexMorphism(x): """ @@ -116,7 +129,7 @@ def is_SimplicialComplexMorphism(x): """ return isinstance(x,SimplicialComplexMorphism) -class SimplicialComplexMorphism(SageObject): +class SimplicialComplexMorphism(Morphism): """ An element of this class is a morphism of simplicial complexes. """ @@ -143,7 +156,7 @@ def __init__(self,f,X,Y): sage: x.image() == y.image() False """ - if not isinstance(X,simplicial_complex.SimplicialComplex) or not isinstance(Y,simplicial_complex.SimplicialComplex): + if not isinstance(X,SimplicialComplex) or not isinstance(Y,SimplicialComplex): raise ValueError("X and Y must be SimplicialComplexes.") if not set(f.keys()) == X._vertex_set.set(): raise ValueError("f must be a dictionary from the vertex set of X to single values in the vertex set of Y.") @@ -155,12 +168,11 @@ def __init__(self,f,X,Y): fi = [] for j in tup: fi.append(f[j]) - v = simplicial_complex.Simplex(set(fi)) + v = Simplex(set(fi)) if not v in Y_faces[v.dimension()]: raise ValueError("f must be a dictionary from the vertices of X to the vertices of Y.") self._vertex_dictionary = f - self._domain = X - self._codomain = Y + Morphism.__init__(self, Hom(X,Y,SimplicialComplexes())) def __eq__(self,x): """ @@ -172,7 +184,11 @@ def __eq__(self,x): sage: H = Hom(S,S) sage: i = H.identity() sage: i - Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Simplicial complex endomorphism of Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Defn: 0 |--> 0 + 1 |--> 1 + 2 |--> 2 + 3 |--> 3 sage: f = {0:0,1:1,2:2,3:2} sage: j = H(f) sage: i==j @@ -187,9 +203,8 @@ def __eq__(self,x): sage: l = G(g) sage: k == l True - """ - if not isinstance(x,SimplicialComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._vertex_dictionary != x._vertex_dictionary: + if not isinstance(x,SimplicialComplexMorphism) or self.codomain() != x.codomain() or self.domain() != x.domain() or self._vertex_dictionary != x._vertex_dictionary: return False else: return True @@ -227,8 +242,8 @@ def __call__(self,x,orientation=False): sage: g(Simplex([0,1]), orientation=True) ((0, 1), -1) """ - dim = self._domain.dimension() - if not isinstance(x,simplicial_complex.Simplex) or x.dimension() > dim or not x in self._domain.faces()[x.dimension()]: + dim = self.domain().dimension() + if not isinstance(x,Simplex) or x.dimension() > dim or not x in self.domain().faces()[x.dimension()]: raise ValueError("x must be a simplex of the source of f") tup=x.tuple() fx=[] @@ -239,25 +254,42 @@ def __call__(self,x,orientation=False): oriented = Permutation(convert_perm(fx)).signature() else: oriented = 1 - return (simplicial_complex.Simplex(set(fx)), oriented) + return (Simplex(set(fx)), oriented) else: - return simplicial_complex.Simplex(set(fx)) + return Simplex(set(fx)) + + def _repr_type(self): + """ + EXAMPLES:: + + sage: S = simplicial_complexes.Sphere(1) + sage: T = simplicial_complexes.Sphere(2) + sage: H = Hom(S,T) + sage: f = {0:0,1:1,2:2} + sage: H(f)._repr_type() + 'Simplicial complex' + """ + return "Simplicial complex" - def _repr_(self): + def _repr_defn(self): """ - Return a string representation of ``self``. + If there are fewer than 5 vertices, print the image of each vertex + on a separate line. Otherwise, print the map as a single line. EXAMPLES:: - sage: S = simplicial_complexes.Sphere(2) - sage: H = Hom(S,S) - sage: i = H.identity() - sage: i - Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} - sage: i._repr_() - 'Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}' + sage: S = simplicial_complexes.Simplex(1) + sage: print Hom(S,S).identity()._repr_defn() + 0 |--> 0 + 1 |--> 1 + sage: T = simplicial_complexes.Torus() + sage: print Hom(T,T).identity()._repr_defn() + [0, 1, 2, 3, 4, 5, 6] --> [0, 1, 2, 3, 4, 5, 6] """ - return "Simplicial complex morphism " + str(self._vertex_dictionary) + " from " + self._domain._repr_() + " to " + self._codomain._repr_() + vd = self._vertex_dictionary + if len(vd) < 5: + return '\n'.join("{} |--> {}".format(v, vd[v]) for v in vd) + return "{} --> {}".format(vd.keys(), vd.values()) def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain=False): """ @@ -271,12 +303,17 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= sage: f = {0:0,1:1,2:2} sage: x = H(f) sage: x - Simplicial complex morphism {0: 0, 1: 1, 2: 2} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + To: Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + Defn: 0 |--> 0 + 1 |--> 1 + 2 |--> 2 sage: a = x.associated_chain_complex_morphism() sage: a - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring - To: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: a._matrix_dictionary {0: [0 0 0] [0 1 0] @@ -290,21 +327,21 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= [0 0 1], 2: []} sage: x.associated_chain_complex_morphism(augmented=True) - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring - To: Chain complex with at most 4 nonzero terms over Integer Ring + To: Chain complex with at most 4 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(cochain=True) - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Integer Ring - To: Chain complex with at most 2 nonzero terms over Integer Ring + To: Chain complex with at most 2 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(augmented=True,cochain=True) - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 4 nonzero terms over Integer Ring - To: Chain complex with at most 3 nonzero terms over Integer Ring + To: Chain complex with at most 3 nonzero terms over Integer Ring sage: x.associated_chain_complex_morphism(base_ring=GF(11)) - Chain complex morphism + Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Finite Field of size 11 - To: Chain complex with at most 3 nonzero terms over Finite Field of size 11 + To: Chain complex with at most 3 nonzero terms over Finite Field of size 11 Some simplicial maps which reverse the orientation of a few simplices:: @@ -325,20 +362,18 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= {0: [0 1] [1 0], 1: [-1]} """ - max_dim = max(self._domain.dimension(),self._codomain.dimension()) - min_dim = min(self._domain.dimension(),self._codomain.dimension()) + max_dim = max(self.domain().dimension(),self.codomain().dimension()) + min_dim = min(self.domain().dimension(),self.codomain().dimension()) matrices = {} if augmented is True: - m = matrix.Matrix(base_ring,1,1,1) + m = matrix(base_ring,1,1,1) if not cochain: matrices[-1] = m else: matrices[-1] = m.transpose() for dim in range(min_dim+1): -# X_faces = list(self._domain.faces()[dim]) -# Y_faces = list(self._codomain.faces()[dim]) - X_faces = list(self._domain.n_cells(dim)) - Y_faces = list(self._codomain.n_cells(dim)) + X_faces = list(self.domain().n_cells(dim)) + Y_faces = list(self.codomain().n_cells(dim)) num_faces_X = len(X_faces) num_faces_Y = len(Y_faces) mval = [0 for i in range(num_faces_X*num_faces_Y)] @@ -348,33 +383,33 @@ def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain= pass else: mval[X_faces.index(i)+(Y_faces.index(y)*num_faces_X)] = oriented - m = matrix.Matrix(base_ring,num_faces_Y,num_faces_X,mval,sparse=True) + m = matrix(base_ring,num_faces_Y,num_faces_X,mval,sparse=True) if not cochain: matrices[dim] = m else: matrices[dim] = m.transpose() for dim in range(min_dim+1,max_dim+1): try: - l1 = len(self._codomain.n_cells(dim)) + l1 = len(self.codomain().n_cells(dim)) except KeyError: l1 = 0 try: - l2 = len(self._domain.n_cells(dim)) + l2 = len(self.domain().n_cells(dim)) except KeyError: l2 = 0 - m = matrix.zero_matrix(base_ring,l1,l2,sparse=True) + m = zero_matrix(base_ring,l1,l2,sparse=True) if not cochain: matrices[dim] = m else: matrices[dim] = m.transpose() if not cochain: return ChainComplexMorphism(matrices,\ - self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\ - self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain)) + self.domain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\ + self.codomain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain)) else: return ChainComplexMorphism(matrices,\ - self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\ - self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain)) + self.codomain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\ + self.domain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain)) def image(self): """ @@ -418,41 +453,8 @@ def image(self): Simplicial complex with vertex set (0, 2) and facets {(0, 2)} """ - fa = [self(i) for i in self._domain.facets()] - return simplicial_complex.SimplicialComplex(fa, maximality_check=True) - - def domain(self): - """ - Returns the domain of the morphism. - - EXAMPLES:: - - sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False) - sage: T = SimplicialComplex([[0,1]], is_mutable=False) - sage: f = {0:0,1:1,2:0,3:1} - sage: H = Hom(S,T) - sage: x = H(f) - sage: x.domain() - Simplicial complex with vertex set (0, 1, 2, 3) and facets {(2, 3), (0, 1)} - """ - return self._domain - - def codomain(self): - """ - Returns the codomain of the morphism. - - EXAMPLES:: - - sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False) - sage: T = SimplicialComplex([[0,1]], is_mutable=False) - sage: f = {0:0,1:1,2:0,3:1} - sage: H = Hom(S,T) - sage: x = H(f) - sage: x.codomain() - Simplicial complex with vertex set (0, 1) and facets {(0, 1)} - - """ - return self._codomain + fa = [self(i) for i in self.domain().facets()] + return SimplicialComplex(fa, maximality_check=True) def is_surjective(self): """ @@ -479,7 +481,7 @@ def is_surjective(self): sage: x.is_surjective() True """ - return self._codomain == self.image() + return self.codomain() == self.image() def is_injective(self): """ @@ -502,7 +504,7 @@ def is_injective(self): True """ - v = [self._vertex_dictionary[i[0]] for i in self._domain.faces()[0]] + v = [self._vertex_dictionary[i[0]] for i in self.domain().faces()[0]] for i in v: if v.count(i) > 1: return False @@ -529,16 +531,21 @@ def is_identity(self): sage: f = {0:0,1:1,2:2,3:3} sage: x = H(f) sage: x - Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} + To: Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets + Defn: 0 |--> 0 + 1 |--> 1 + 2 |--> 2 + 3 |--> 3 sage: x.is_identity() False - """ - if self._domain != self._codomain: + if self.domain() != self.codomain(): return False else: f = dict() - for i in self._domain._vertex_set.set(): + for i in self.domain()._vertex_set.set(): f[i] = i if self._vertex_dictionary != f: return False @@ -565,28 +572,31 @@ def fiber_product(self, other, rename_vertices = True): sage: y = G(g) sage: z = x.fiber_product(y) sage: z - Simplicial complex morphism {'L1R2': 1, 'L1R1': 1, 'L2R0': 0, 'L0R0': 0} - from Simplicial complex with 4 vertices and facets - {('L2R0',), ('L1R1',), ('L0R0', 'L1R2')} to Simplicial complex - with vertex set (0, 1, 2) and facets {(2,), (0, 1)} + Simplicial complex morphism: + From: Simplicial complex with 4 vertices and facets {('L2R0',), ('L1R1',), ('L0R0', 'L1R2')} + To: Simplicial complex with vertex set (0, 1, 2) and facets {(2,), (0, 1)} + Defn: L1R2 |--> 1 + L1R1 |--> 1 + L2R0 |--> 0 + L0R0 |--> 0 """ - if self._codomain != other._codomain: + if self.codomain() != other.codomain(): raise ValueError("self and other must have the same codomain.") - X = self._domain.product(other._domain,rename_vertices = rename_vertices) + X = self.domain().product(other.domain(),rename_vertices = rename_vertices) v = [] f = dict() - eff1 = self._domain._vertex_set - eff2 = other._domain._vertex_set + eff1 = self.domain()._vertex_set + eff2 = other.domain()._vertex_set for i in eff1: for j in eff2: - if self(simplicial_complex.Simplex([i])) == other(simplicial_complex.Simplex([j])): + if self(Simplex([i])) == other(Simplex([j])): if rename_vertices: v.append("L"+str(i)+"R"+str(j)) f["L"+str(i)+"R"+str(j)] = self._vertex_dictionary[i] else: v.append((i,j)) f[(i,j)] = self._vertex_dictionary[i] - return SimplicialComplexMorphism(f, X.generated_subcomplex(v), self._codomain) + return SimplicialComplexMorphism(f, X.generated_subcomplex(v), self.codomain()) def mapping_torus(self): r""" @@ -622,21 +632,22 @@ def mapping_torus(self): ... ValueError: self must have the same domain and codomain. """ - if self._domain != self._codomain: + if self.domain() != self.codomain(): raise ValueError("self must have the same domain and codomain.") map_dict = self._vertex_dictionary - interval = simplicial_complex.SimplicialComplex([["I0","I1"],["I1","I2"]]) - product = interval.product(self._domain,False) + interval = SimplicialComplex([["I0","I1"],["I1","I2"]]) + product = interval.product(self.domain(),False) facets = list(product.maximal_faces()) - for facet in self._domain._facets: + for facet in self.domain()._facets: left = [ ("I0",v) for v in facet ] right = [ ("I2",map_dict[v]) for v in facet ] for i in range(facet.dimension()+1): facets.append(tuple(left[:i+1]+right[i:])) - return simplicial_complex.SimplicialComplex(facets) + return SimplicialComplex(facets) def induced_homology_morphism(self, base_ring=None, cohomology=False): - """The map in (co)homology induced by this map + """ + The map in (co)homology induced by this map INPUTS: @@ -653,22 +664,38 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): sage: diag = H.diagonal_morphism() sage: h = diag.induced_homology_morphism(QQ) sage: h - Homology morphism induced by Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2'} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with 9 vertices and 18 facets + Graded vector space morphism: + From: Homology module of Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} over Rational Field + To: Homology module of Simplicial complex with 9 vertices and 18 facets over Rational Field + Defn: induced by: + Simplicial complex morphism: + From: Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} + To: Simplicial complex with 9 vertices and 18 facets + Defn: 0 |--> L0R0 + 1 |--> L1R1 + 2 |--> L2R2 We can view the matrix form for the homomorphism:: - sage: h.to_matrix(0) + sage: h.to_matrix(0) # in degree 0 [1] - sage: h.to_matrix(1) + sage: h.to_matrix(1) # in degree 1 [ 2] [-1] + sage: h.to_matrix() # the entire homomorphism + [ 1| 0] + [--+--] + [ 0| 2] + [ 0|-1] + [--+--] + [ 0| 0] We can evaluate it on (co)homology classes:: sage: coh = diag.induced_homology_morphism(QQ, cohomology=True) sage: coh.to_matrix(1) [1 1] - sage: x,y = T.cohomology_with_basis(1, QQ).basis() + sage: x,y = list(T.cohomology_ring(QQ).basis(1)) sage: coh(x) h^{1,0} sage: coh(2*x+3*y) From 7338a050ea9f7c901bcf293afb6e2a033bf608e6 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 17 Oct 2015 08:15:56 +0200 Subject: [PATCH 1618/1872] Trac #19399: Add doctest --- src/sage/rings/asymptotic/growth_group.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 044b73fa25c..36e338d9f92 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2681,6 +2681,11 @@ def _determine_category_(category, base): Join of Category of commutative groups and Category of posets sage: MonomialGrowthGroup(ZZ, 'x', category=Monoids()).category() # indirect doctest Category of monoids + sage: W = Words([0, 1]) + sage: W.category() + Category of sets + sage: MonomialGrowthGroup(W, 'x').category() # indirect doctest + Join of Category of monoids and Category of posets """ if category is not None: return category From 41af76268e8bc96a6fcf23a2d0c70da58fc6df80 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 17 Oct 2015 03:37:53 -0300 Subject: [PATCH 1619/1872] Trac 18411: pass keywords in __call__ --- src/sage/categories/cartesian_product.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index 60b2c64ecfd..6cf5370c87c 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -123,7 +123,7 @@ def __init__(self): from sage.categories.sets_cat import Sets MultivariateConstructionFunctor.__init__(self, Sets(), Sets()) - def __call__(self, args): + def __call__(self, args, **kwds): r""" Functorial construction application. @@ -171,7 +171,7 @@ def __call__(self, args): from sage.sets.cartesian_product import CartesianProduct return CartesianProduct((), Sets().CartesianProducts()) - return super(CartesianProductFunctor, self).__call__(args) + return super(CartesianProductFunctor, self).__call__(args, **kwds) class CartesianProductsCategory(CovariantConstructionCategory): """ From 31ea7123356ca264e2630f22045662cb36a516d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 17 Oct 2015 08:59:16 +0200 Subject: [PATCH 1620/1872] trac #17560 fixing doc --- src/doc/en/reference/combinat/module_list.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 61c23512c0c..9ceefddddfd 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -169,7 +169,7 @@ Comprehensive Module list sage/combinat/posets/incidence_algebras sage/combinat/posets/lattices sage/combinat/posets/linear_extensions - sage/combinat/posets/mobius_algebra + sage/combinat/posets/moebius_algebra sage/combinat/posets/poset_examples sage/combinat/posets/posets sage/combinat/q_analogues From a0b5fbe3c7951729757e8ff285a686c3b08e9f38 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 11:49:33 +0200 Subject: [PATCH 1621/1872] remove parameter domain --- src/sage/rings/asymptotic/asymptotic_ring.py | 18 ++++++++----- src/sage/rings/asymptotic/growth_group.py | 24 +++++++++--------- .../asymptotic/growth_group_cartesian.py | 8 +++--- src/sage/rings/asymptotic/misc.py | 2 +- src/sage/rings/asymptotic/term_monoid.py | 25 +++++++------------ 5 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 84bc1816659..7aee014e6f3 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1835,31 +1835,37 @@ def substitute(self, rules=None, domain=None, **kwds): break else: domain = P + locals['_zero_'] = domain.zero() + locals['_one_'] = domain.one() try: - return self._substitute_(locals, domain) + return self._substitute_(locals) except TypeError as e: from misc import combine_exceptions + rules = '{' + ', '.join( + '%s: %s' % (k, v) + for k, v in sorted(locals.iteritems(), key=lambda k: str(k[0])) + if k[0] != '_') + '}' raise combine_exceptions( TypeError('Cannot apply the substitution rules %s at %s ' - 'in %s.' % (locals, self, self.parent())), e) + 'in %s.' % (rules, self, self.parent())), e) subs = substitute - def _substitute_(self, rules, domain): + def _substitute_(self, rules): if not self.summands: - return domain.zero() + return rules['_zero_'] from sage.symbolic.operators import add_vararg try: return add_vararg( - *tuple(s._substitute_(rules, domain) + *tuple(s._substitute_(rules) for s in self.summands.elements_topological())) except (ArithmeticError, NotImplementedError, TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) class AsymptoticRing(Algebra, UniqueRepresentation): diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 126d856c967..e7585e27c85 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -570,14 +570,14 @@ def extract_variable_names(s): return tuple(str(s) for s in SR(s).variables()) - def _substitute_(self, rules, domain): + def _substitute_(self, rules): from sage.misc.sage_eval import sage_eval try: return sage_eval(self.var_repr, locals=rules) except (ArithmeticError, NotImplementedError, TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) # The following function is used in the classes GenericGrowthElement and @@ -1325,9 +1325,9 @@ def factors(self): is_lt_one = _is_lt_one_ - def _substitute_(self, rules, domain): + def _substitute_(self, rules): if self.is_one(): - return domain.one() + return rules['_one_'] raise NotImplementedError('Cannot substitute in %s in the abstract ' 'base class %s.' % (self, self.parent())) @@ -2625,15 +2625,15 @@ def _le_(self, other): return self.exponent <= other.exponent - def _substitute_(self, rules, domain): + def _substitute_(self, rules): if self.is_one(): - return domain.one() + return rules['_one_'] try: - return self.parent()._var_._substitute_(rules, domain) ** self.exponent + return self.parent()._var_._substitute_(rules) ** self.exponent except (ArithmeticError, NotImplementedError, TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) class MonomialGrowthGroup(GenericGrowthGroup): @@ -3235,15 +3235,15 @@ def _le_(self, other): return bool(abs(self.base) <= abs(other.base)) - def _substitute_(self, rules, domain): + def _substitute_(self, rules): if self.is_one(): - return domain.one() + return rules['_one_'] try: - return self.base ** self.parent()._var_._substitute_(rules, domain) + return self.base ** self.parent()._var_._substitute_(rules) except (ArithmeticError, NotImplementedError, TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) class ExponentialGrowthGroup(GenericGrowthGroup): diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index ad586fcaef9..0e37a75c496 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1125,18 +1125,18 @@ def __invert__(self): tuple(~x for x in self.cartesian_factors())) - def _substitute_(self, rules, domain): + def _substitute_(self, rules): if self.is_one(): - return domain.one() + return rules['_one_'] from sage.symbolic.operators import mul_vararg try: return mul_vararg( - *tuple(x._substitute_(rules, domain) + *tuple(x._substitute_(rules) for x in self.cartesian_factors())) except (ArithmeticError, NotImplementedError, TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) CartesianProduct = CartesianProductGrowthGroups diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 537029c1cea..b7692f1d06e 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -340,7 +340,7 @@ def combine_exceptions(e, *f): return e -def substitute_raise_exception(self, e, rules, domain): +def substitute_raise_exception(self, e): raise combine_exceptions( TypeError('Cannot substitute in %s in %s.' % (self, self.parent())), e) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index fd17af64ac4..1923fc76aa7 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1250,7 +1250,7 @@ def _repr_(self): return 'Generic Term with growth ' + repr(self.growth) - def _substitute_(self, rules, domain): + def _substitute_(self, rules): raise NotImplementedError('Cannot substitute in %s in the abstract ' 'base class %s.' % (self, self.parent())) @@ -2251,13 +2251,13 @@ def rpow(self, base): (base, self, self.parent())) - def _substitute_(self, rules, domain): + def _substitute_(self, rules): try: - g = self.growth._substitute_(rules, domain) + g = self.growth._substitute_(rules) except (ArithmeticError, NotImplementedError, TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) try: return rules['O'](g) @@ -2271,18 +2271,11 @@ def _substitute_(self, rules, domain): elif isinstance(g.parent(), sage.symbolic.ring.SR): return g.Order() - elif domain is sage.symbolic.ring.SR: - try: - return domain(g).Order() - except (TypeError, ValueError) as e: - from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) - try: return sage.rings.big_oh.O(g) except (TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) class OTermMonoid(GenericTermMonoid): @@ -3320,13 +3313,13 @@ def rpow(self, base): return elem ** self.coefficient - def _substitute_(self, rules, domain): + def _substitute_(self, rules): try: - g = self.growth._substitute_(rules, domain) + g = self.growth._substitute_(rules) except (ArithmeticError, NotImplementedError, TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) c = self.coefficient @@ -3334,7 +3327,7 @@ def _substitute_(self, rules, domain): return c * g except (TypeError, ValueError) as e: from misc import substitute_raise_exception - substitute_raise_exception(self, e, rules, domain) + substitute_raise_exception(self, e) class ExactTermMonoid(TermWithCoefficientMonoid): From 461c314c31439b56b829bf7a439d781507bb6da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 17 Oct 2015 12:10:10 +0200 Subject: [PATCH 1622/1872] trac #17560 fixing doc again --- src/sage/combinat/posets/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/__init__.py b/src/sage/combinat/posets/__init__.py index b54cd07d799..61b51a2423d 100644 --- a/src/sage/combinat/posets/__init__.py +++ b/src/sage/combinat/posets/__init__.py @@ -17,7 +17,7 @@ - :ref:`sage.combinat.posets.cartesian_product` -- :ref:`sage.combinat.posets.mobius_algebra` +- :ref:`sage.combinat.posets.moebius_algebra` - :ref:`sage.combinat.tamari_lattices` - :ref:`sage.combinat.interval_posets` From 70bb79342126ece9987b218718d27b006dea8a6d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 15:22:33 +0200 Subject: [PATCH 1623/1872] substitute_raise_exception: rename self to element --- src/sage/rings/asymptotic/misc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index b7692f1d06e..b1622e773e6 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -340,10 +340,10 @@ def combine_exceptions(e, *f): return e -def substitute_raise_exception(self, e): +def substitute_raise_exception(element, e): raise combine_exceptions( - TypeError('Cannot substitute in %s in %s.' % - (self, self.parent())), e) + type(e)('Cannot substitute in %s in %s.' % + (element, element.parent())), e) def underlying_class(P): From 0fd249deb07fa94ab13799750647ec21ad745adb Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 15:22:45 +0200 Subject: [PATCH 1624/1872] substitute_raise_exception: write docstring and tests --- src/sage/rings/asymptotic/misc.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index b1622e773e6..8cdd5379809 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -341,6 +341,29 @@ def combine_exceptions(e, *f): def substitute_raise_exception(element, e): + r""" + Raise an error describing what went wrong with the substitution. + + INPUT: + + - ``element`` -- an element. + + - ``e`` -- an exception which is included in the raised error + message. + + OUTPUT: + + Raise an exception of the same type as ``e``. + + TESTS:: + + sage: from sage.rings.asymptotic.misc import substitute_raise_exception + sage: substitute_raise_exception(x, Exception('blub')) + Traceback (most recent call last): + ... + Exception: Cannot substitute in x in Symbolic Ring. + > *previous* Exception: blub + """ raise combine_exceptions( type(e)('Cannot substitute in %s in %s.' % (element, element.parent())), e) From 243a178d8ca653f7c247fe21e7cbb5a4a3a813b4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 15:24:01 +0200 Subject: [PATCH 1625/1872] _substitute_ in growth groups: rewrite exceptions --- src/sage/rings/asymptotic/growth_group.py | 13 +++---------- src/sage/rings/asymptotic/growth_group_cartesian.py | 3 +-- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index e7585e27c85..c96f3649e95 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -574,8 +574,7 @@ def _substitute_(self, rules): from sage.misc.sage_eval import sage_eval try: return sage_eval(self.var_repr, locals=rules) - except (ArithmeticError, NotImplementedError, - TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) @@ -1326,10 +1325,6 @@ def factors(self): def _substitute_(self, rules): - if self.is_one(): - return rules['_one_'] - raise NotImplementedError('Cannot substitute in %s in the abstract ' - 'base class %s.' % (self, self.parent())) class GenericGrowthGroup( @@ -2630,8 +2625,7 @@ def _substitute_(self, rules): return rules['_one_'] try: return self.parent()._var_._substitute_(rules) ** self.exponent - except (ArithmeticError, NotImplementedError, - TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) @@ -3240,8 +3234,7 @@ def _substitute_(self, rules): return rules['_one_'] try: return self.base ** self.parent()._var_._substitute_(rules) - except (ArithmeticError, NotImplementedError, - TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 0e37a75c496..a3d55fd173c 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1133,8 +1133,7 @@ def _substitute_(self, rules): return mul_vararg( *tuple(x._substitute_(rules) for x in self.cartesian_factors())) - except (ArithmeticError, NotImplementedError, - TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) From 17d0e2b8b6f1428ddde54b6e70fb7365e4f00961 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 15:24:25 +0200 Subject: [PATCH 1626/1872] docstrings and tests in _substitute_ of growth groups --- src/sage/rings/asymptotic/growth_group.py | 123 ++++++++++++++++++ .../asymptotic/growth_group_cartesian.py | 37 ++++++ 2 files changed, 160 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c96f3649e95..d46eff7a492 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -571,6 +571,41 @@ def extract_variable_names(s): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this variable. + + INPUT: + + - ``rules`` -- a dictionary. + + OUTPUT: + + An object. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import Variable + sage: Variable('x^2')._substitute_({'x': SR.var('z')}) + z^2 + sage: _.parent() + Symbolic Ring + + :: + + sage: Variable('1/x')._substitute_({'x': 'z'}) + Traceback (most recent call last): + ... + TypeError: Cannot substitute in 1/x in + . + > *previous* TypeError: unsupported operand parent(s) for '/': + 'Integer Ring' and '' + sage: Variable('1/x')._substitute_({'x': 0}) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot substitute in 1/x in + . + > *previous* ZeroDivisionError: rational division by zero + """ from sage.misc.sage_eval import sage_eval try: return sage_eval(self.var_repr, locals=rules) @@ -1325,6 +1360,33 @@ def factors(self): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this generic growth element. + + INPUT: + + - ``rules`` -- a dictionary. + + OUTPUT: + + An object. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: G = GenericGrowthGroup(ZZ) + sage: G(raw_element=42)._substitute_({}) + Traceback (most recent call last): + ... + TypeError: Cannot substitute in GenericGrowthElement(42) in + Growth Group Generic(ZZ). + > *previous* TypeError: Cannot substitute in the abstract base class + Growth Group Generic(ZZ). + """ + from misc import substitute_raise_exception + substitute_raise_exception(self, TypeError( + 'Cannot substitute in the abstract ' + 'base class %s.' % (self.parent(),))) class GenericGrowthGroup( @@ -2621,6 +2683,39 @@ def _le_(self, other): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this monomial growth element. + + INPUT: + + - ``rules`` -- a dictionary. + The neutral element of the group is replaced by the value + to key ``'_one_'``. + + OUTPUT: + + An object. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^ZZ') + sage: G(x^42)._substitute_({'x': SR.var('z')}) + z^42 + sage: _.parent() + Symbolic Ring + sage: G(x^42)._substitute_({'x': 2}) + 4398046511104 + sage: _.parent() + Integer Ring + sage: G(1 / x)._substitute_({'x': 0}) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot substitute in x^(-1) in Growth Group x^ZZ. + > *previous* ZeroDivisionError: rational division by zero + sage: G(1)._substitute_({'_one_': 'one'}) + 'one' + """ if self.is_one(): return rules['_one_'] try: @@ -3230,6 +3325,34 @@ def _le_(self, other): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this exponential growth element. + + INPUT: + + - ``rules`` -- a dictionary. + The neutral element of the group is replaced by the value + to key ``'_one_'``. + + OUTPUT: + + An object. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('QQ^x') + sage: G((1/2)^x)._substitute_({'x': SR.var('z')}) + (1/2)^z + sage: _.parent() + Symbolic Ring + sage: G((1/2)^x)._substitute_({'x': 2}) + 1/4 + sage: _.parent() + Rational Field + sage: G(1)._substitute_({'_one_': 'one'}) + 'one' + """ if self.is_one(): return rules['_one_'] try: diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index a3d55fd173c..f526797ec24 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1126,6 +1126,43 @@ def __invert__(self): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this + cartesian product growth element. + + INPUT: + + - ``rules`` -- a dictionary. + The neutral element of the group is replaced by the value + to key ``'_one_'``. + + OUTPUT: + + An object. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: G = GrowthGroup('x^QQ * log(x)^QQ') + sage: G(x^3 * log(x)^5)._substitute_({'x': SR.var('z')}) + z^3*log(z)^5 + sage: _.parent() + Symbolic Ring + sage: G(x^3 * log(x)^5)._substitute_({'x': 2.2}) # rel tol 1e-6 + 3.24458458945 + sage: _.parent() + Real Field with 53 bits of precision + sage: G(1 / x)._substitute_({'x': 0}) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot substitute in x^(-1) in + Growth Group x^QQ * log(x)^QQ. + > *previous* ZeroDivisionError: Cannot substitute in x^(-1) in + Growth Group x^QQ. + >> *previous* ZeroDivisionError: rational division by zero + sage: G(1)._substitute_({'_one_': 'one'}) + 'one' + """ if self.is_one(): return rules['_one_'] from sage.symbolic.operators import mul_vararg From d2a599f2003dcff423486b0d36b5659cd80e91ea Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 15:25:10 +0200 Subject: [PATCH 1627/1872] rewrite code of _substitute_ in term monoids --- src/sage/rings/asymptotic/term_monoid.py | 31 ++++++++++++++---------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 1923fc76aa7..cfb2977843f 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1251,8 +1251,10 @@ def _repr_(self): def _substitute_(self, rules): - raise NotImplementedError('Cannot substitute in %s in the abstract ' - 'base class %s.' % (self, self.parent())) + from misc import substitute_raise_exception + substitute_raise_exception(self, TypeError( + 'Cannot substitute in the abstract ' + 'base class %s.' % (self.parent(),))) class GenericTermMonoid(sage.structure.unique_representation.UniqueRepresentation, @@ -2254,8 +2256,7 @@ def rpow(self, base): def _substitute_(self, rules): try: g = self.growth._substitute_(rules) - except (ArithmeticError, NotImplementedError, - TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) @@ -2264,16 +2265,21 @@ def _substitute_(self, rules): except KeyError: pass - from asymptotic_ring import AsymptoticRing - if isinstance(g.parent(), AsymptoticRing): - return g.O() + try: + P = g.parent() + except AttributeError: + pass + else: + from asymptotic_ring import AsymptoticRing + if isinstance(P, AsymptoticRing): + return g.O() - elif isinstance(g.parent(), sage.symbolic.ring.SR): - return g.Order() + elif P is sage.symbolic.ring.SR: + return g.Order() try: return sage.rings.big_oh.O(g) - except (TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) @@ -3316,8 +3322,7 @@ def rpow(self, base): def _substitute_(self, rules): try: g = self.growth._substitute_(rules) - except (ArithmeticError, NotImplementedError, - TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) @@ -3325,7 +3330,7 @@ def _substitute_(self, rules): try: return c * g - except (TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) From 204e47c6eb3858f3977d29462d04781ba513022a Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 15:25:30 +0200 Subject: [PATCH 1628/1872] docstrings of _substitute_ in term monoids --- src/sage/rings/asymptotic/term_monoid.py | 109 +++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index cfb2977843f..e620bc5e096 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1251,6 +1251,32 @@ def _repr_(self): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this generic term. + + INPUT: + + - ``rules`` -- a dictionary. + + OUTPUT: + + Nothing since a + :python:`TypeError` + is raised. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import GenericTermMonoid + sage: t = GenericTermMonoid(GrowthGroup('x^ZZ'), ZZ).an_element() + sage: t._substitute_({}) + Traceback (most recent call last): + ... + TypeError: Cannot substitute in Generic Term with growth x in + Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring. + > *previous* TypeError: Cannot substitute in the abstract base class + Generic Term Monoid x^ZZ with (implicit) coefficients in Integer Ring. + """ from misc import substitute_raise_exception substitute_raise_exception(self, TypeError( 'Cannot substitute in the abstract ' @@ -2254,6 +2280,49 @@ def rpow(self, base): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this O-Term. + + INPUT: + + - ``rules`` -- a dictionary. + + OUTPUT: + + An object. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: T = TermMonoid('O', GrowthGroup('x^ZZ'), ZZ) + sage: t = T.an_element(); t + O(x) + sage: t._substitute_({'x': SR.var('z')}) + Order(z) + sage: t._substitute_({'x': SR.var('z'), 'O': function('Oh')}) + Oh(z) + sage: e = AsymptoticRing('x^ZZ', ZZ)('2*x'); e + 2*x + sage: t._substitute_({'x': e}) + O(x) + sage: T(1/x)._substitute_({'x': 0}) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot substitute in O(x^(-1)) in + O-Term Monoid x^ZZ with implicit coefficients in Integer Ring. + > *previous* ZeroDivisionError: Cannot substitute in x^(-1) in + Growth Group x^ZZ. + >> *previous* ZeroDivisionError: rational division by zero + sage: t._substitute_({'x': 3}) + O(3) + sage: t._substitute_({'x': 'null'}) + Traceback (most recent call last): + ... + ArithmeticError: Cannot substitute in O(x) in + O-Term Monoid x^ZZ with implicit coefficients in Integer Ring. + > *previous* ArithmeticError: O(null) not defined + """ try: g = self.growth._substitute_(rules) except (ArithmeticError, TypeError, ValueError) as e: @@ -3320,6 +3389,46 @@ def rpow(self, base): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this exact term. + + INPUT: + + - ``rules`` -- a dictionary. + + OUTPUT: + + An object. + + TESTS:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: from sage.rings.asymptotic.term_monoid import TermMonoid + sage: E = TermMonoid('exact', GrowthGroup('x^ZZ'), ZZ) + sage: e = E.an_element(); e + x + sage: e._substitute_({'x': SR.var('z')}) + z + sage: E(2/x)._substitute_({'x': 0}) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot substitute in 2*x^(-1) in + Exact Term Monoid x^ZZ with coefficients in Integer Ring. + > *previous* ZeroDivisionError: Cannot substitute in x^(-1) in + Growth Group x^ZZ. + >> *previous* ZeroDivisionError: rational division by zero + sage: (e*e)._substitute_({'x': 'something'}) + 'somethingsomething' + sage: E(1/x)._substitute_({'x': 'something'}) + '' + sage: E(1/x)._substitute_({'x': ZZ}) + Traceback (most recent call last): + ... + ValueError: Cannot substitute in x^(-1) in + Exact Term Monoid x^ZZ with coefficients in Integer Ring. + > *previous* ValueError: Cannot substitute in x^(-1) in Growth Group x^ZZ. + >> *previous* ValueError: rank (=-1) must be nonnegative + """ try: g = self.growth._substitute_(rules) except (ArithmeticError, TypeError, ValueError) as e: From 5cd22bf73ab7cf2340290d3390db4ba5cdc61b78 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 15:25:53 +0200 Subject: [PATCH 1629/1872] complete _substitute_ of asymptotic ring --- src/sage/rings/asymptotic/asymptotic_ring.py | 40 +++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 7aee014e6f3..f02f19f0061 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1855,6 +1855,43 @@ def substitute(self, rules=None, domain=None, **kwds): def _substitute_(self, rules): + r""" + Substitute the given ``rules`` in this asymptotic expansion. + + INPUT: + + - ``rules`` -- a dictionary. + The neutral element of the asymptotic ring is replaced by the value + to key ``'_zero_'``. + + OUTPUT: + + An object. + + TESTS:: + + sage: A. = AsymptoticRing(growth_group='z^QQ', coefficient_ring=QQ) + sage: z._substitute_({'z': SR.var('a')}) + a + sage: _.parent() + Symbolic Ring + sage: A(0)._substitute_({'_zero_': 'zero'}) + 'zero' + sage: (1/z)._substitute_({'z': 4}) + 1/4 + sage: _.parent() + Rational Field + sage: (1/z)._substitute_({'z': 0}) + Traceback (most recent call last): + ... + ZeroDivisionError: Cannot substitute in z^(-1) in + Asymptotic Ring over Rational Field. + > *previous* ZeroDivisionError: Cannot substitute in z^(-1) in + Exact Term Monoid z^QQ with coefficients in Rational Field. + >> *previous* ZeroDivisionError: Cannot substitute in z^(-1) in + Growth Group z^QQ. + >>... *previous* ZeroDivisionError: rational division by zero + """ if not self.summands: return rules['_zero_'] from sage.symbolic.operators import add_vararg @@ -1862,8 +1899,7 @@ def _substitute_(self, rules): return add_vararg( *tuple(s._substitute_(rules) for s in self.summands.elements_topological())) - except (ArithmeticError, NotImplementedError, - TypeError, ValueError) as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import substitute_raise_exception substitute_raise_exception(self, e) From 041a5d10259ca0ec083a313bd4ad1fe6cfb8d9c0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 17 Oct 2015 09:52:52 -0500 Subject: [PATCH 1630/1872] Adding p-adics to metric spaces and some cleanup. --- src/doc/en/reference/categories/index.rst | 10 ++++ src/sage/categories/metric_spaces.py | 53 ++++++++++++++++++++-- src/sage/rings/complex_double.pyx | 13 ------ src/sage/rings/complex_field.py | 13 ------ src/sage/rings/integer_ring.pyx | 13 ------ src/sage/rings/padics/local_generic.py | 1 + src/sage/rings/padics/padic_base_leaves.py | 12 +++-- src/sage/rings/padics/padic_generic.py | 1 + src/sage/rings/rational_field.py | 13 ------ src/sage/rings/real_double.pyx | 13 ------ src/sage/rings/real_mpfr.pyx | 13 ------ 11 files changed, 69 insertions(+), 86 deletions(-) diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index 518d9e6582f..34cf4165a73 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -56,6 +56,7 @@ Individual Categories sage/categories/coxeter_group_algebras sage/categories/coxeter_groups sage/categories/crystals + sage/categories/cw_complexes sage/categories/discrete_valuation sage/categories/distributive_magmas_and_additive_magmas sage/categories/division_rings @@ -98,6 +99,7 @@ Individual Categories sage/categories/graded_hopf_algebras_with_basis sage/categories/graded_modules sage/categories/graded_modules_with_basis + sage/categories/graphs sage/categories/group_algebras sage/categories/groupoid sage/categories/groups @@ -109,10 +111,13 @@ Individual Categories sage/categories/integral_domains sage/categories/lattice_posets sage/categories/left_modules + sage/categories/lie_groups sage/categories/magmas sage/categories/magmas_and_additive_magmas sage/categories/magmatic_algebras + sage/categories/manifolds sage/categories/matrix_algebras + sage/categories/metric_spaces sage/categories/modular_abelian_varieties sage/categories/modules sage/categories/modules_with_basis @@ -139,6 +144,8 @@ Individual Categories sage/categories/sets_cat sage/categories/sets_with_grading sage/categories/sets_with_partial_maps + sage/categories/simplicial_complexes + sage/categories/topological_spaces sage/categories/unique_factorization_domains sage/categories/unital_algebras sage/categories/vector_spaces @@ -187,6 +194,7 @@ Examples of parents using categories sage/categories/examples/commutative_additive_semigroups sage/categories/examples/coxeter_groups sage/categories/examples/crystals + sage/categories/examples/cw_complexes sage/categories/examples/facade_sets sage/categories/examples/finite_coxeter_groups sage/categories/examples/finite_dimensional_algebras_with_basis @@ -196,8 +204,10 @@ Examples of parents using categories sage/categories/examples/finite_weyl_groups sage/categories/examples/graded_connected_hopf_algebras_with_basis sage/categories/examples/graded_modules_with_basis + sage/categories/examples/graphs sage/categories/examples/hopf_algebras_with_basis sage/categories/examples/infinite_enumerated_sets + sage/categories/examples/manifolds sage/categories/examples/monoids sage/categories/examples/posets sage/categories/examples/semigroups_cython diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index ef2460ba3c6..d7147ede2df 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -81,6 +81,28 @@ class MetricSpaces(MetricSpacesCategory): - `d(a, b) = 0` if and only if `a = b`. A metric space is a set `S` with a distinguished metric. + + .. RUBRIC:: Implementation + + Objects in this category must implement either a ``dist`` on the parent + or the elements or ``metric`` on the parent; otherwise this will cause + an infinite recursion. + + .. TODO:: + + - Implement a general geodesics class. + - Implement a category for metric unital additive magmas and + move the generic distance `d(a, b) = |a - b|` there. + - Incorperate the length of a geodesic as part of the default + distance cycle. + + EXAMPLES:: + + sage: from sage.categories.metric_spaces import MetricSpaces + sage: C = MetricSpaces() + sage: C + Category of metric spaces + sage: TestSuite(C).run() """ def _repr_object_names(self): """ @@ -114,7 +136,7 @@ def _test_metric(self, **options): for a in S: for b in S: d = dist(a, b) - if a is not b: + if a != b: tester.assertGreater(d, 0) else: tester.assertEqual(d, 0) @@ -132,9 +154,8 @@ def metric(self): sage: m(p1, p2) 2.23230104635820 """ - return lambda a,b: self.dist(a, b) + return lambda a,b: a.dist(b) - @abstract_method def dist(self, a, b): """ Return the distance between ``a`` and ``b`` in ``self``. @@ -150,9 +171,35 @@ def dist(self, a, b): sage: PD = HyperbolicPlane().PD() sage: PD.dist(PD.get_point(0), PD.get_point(I/2)) arccosh(5/3) + + TESTS:: + + sage: RR.dist(-1, pi) + 4.14159265358979 + sage: RDF.dist(1, -1/2) + 1.5 + sage: CC.dist(3, 2) + 1.00000000000000 + sage: CC.dist(-1, I) + 1.41421356237310 + sage: CDF.dist(-1, I) + 1.4142135623730951 """ + return (self(a) - self(b)).abs() class ElementMethods: + def abs(self): + """ + Return the absolute value of ``self``. + + EXAMPLES:: + + sage: CC(I).abs() + 1.00000000000000 + """ + P = self.parent() + return P.metric()(self, P.zero()) + def dist(self, b): """ Return the distance between ``self`` and ``other``. diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 7101ee8da57..31c12bd710a 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -199,19 +199,6 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): return 561162115 #return hash(self.str()) - def dist(self, a, b): - """ - Return the distance between ``a`` and ``b``. - - EXAMPLES:: - - sage: CDF.dist(3, 2) - 1.0 - sage: CDF.dist(-1, I) - 1.4142135623730951 - """ - return (self(a) - self(b)).abs() - def characteristic(self): """ Return the characteristic of the complex double field, which is 0. diff --git a/src/sage/rings/complex_field.py b/src/sage/rings/complex_field.py index 9f5765a2d0b..991635b8e6a 100644 --- a/src/sage/rings/complex_field.py +++ b/src/sage/rings/complex_field.py @@ -745,16 +745,3 @@ def _factor_univariate_polynomial(self, f): from sage.structure.factorization import Factorization return Factorization([(R(g).monic(),e) for g,e in zip(*F)], f.leading_coefficient()) - def dist(self, a, b): - """ - Return the distance between ``a`` and ``b``. - - EXAMPLES:: - - sage: CC.dist(3, 2) - 1.00000000000000 - sage: CC.dist(-1, I) - 1.41421356237310 - """ - return self(a - b).abs() - diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 6fed18f4b0f..76adb61c7d6 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -1250,19 +1250,6 @@ cdef class IntegerRing_class(PrincipalIdealDomain): else: raise ValueError("no nth root of unity in integer ring") - def dist(self, a, b): - """ - Return the distance between ``a`` and ``b``. - - EXAMPLES:: - - sage: ZZ.dist(3, 2) - 1 - sage: ZZ.dist(-1, 1) - 2 - """ - return self(a - b).abs() - def parameter(self): r""" Return an integer of degree 1 for the Euclidean property of `\ZZ`, diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 48bdfb4f64c..8ee98a1b41d 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -55,6 +55,7 @@ def __init__(self, base, prec, names, element_class, category=None): category = CompleteDiscreteValuationFields() else: category = CompleteDiscreteValuationRings() + category = category.Metric().Complete() if default_category is not None: category = check_default_category(default_category, category) Parent.__init__(self, base, names=(names,), normalize=False, category=category, element_constructor=element_class) diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index a43eb7ef9af..55de7f5c625 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -231,7 +231,7 @@ def __init__(self, p, prec, print_mode, names): sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^3)]) sage: R = ZpCR(3, 2) - sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) + sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) # long time sage: R = ZpCR(next_prime(10^60)) sage: TestSuite(R).run() @@ -320,7 +320,7 @@ def __init__(self, p, prec, print_mode, names): sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^3)]) sage: R = ZpCA(3, 2) - sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) + sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) # long time sage: R = ZpCA(next_prime(10^60)) sage: TestSuite(R).run() @@ -411,7 +411,7 @@ def __init__(self, p, prec, print_mode, names): sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^3)]) sage: R = ZpFM(3, 2) - sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) + sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) # long time sage: R = ZpFM(next_prime(10^60)) sage: TestSuite(R).run() @@ -525,10 +525,12 @@ def __init__(self, p, prec, print_mode, names): sage: TestSuite(R).run(elements = [R.random_element() for i in range(2^10)], max_runs = 2^12) # long time sage: R = Qp(3, 1) - sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) + sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) # long time sage: R = Qp(3, 2) - sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^9)]) + sage: TestSuite(R).run(elements=[R.random_element() for i in range(3^9)], + ....: skip="_test_metric") # Skip because too long + sage: R._test_metric(elements=[R.random_element() for i in range(3^3)]) sage: R = Qp(next_prime(10^60)) sage: TestSuite(R).run() diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 1fba8833650..eed574f983d 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -56,6 +56,7 @@ def __init__(self, base, p, prec, print_mode, names, element_class, category=Non category = Fields() else: category = PrincipalIdealDomains() + category = category.Metric().Complete() LocalGeneric.__init__(self, base, prec, names, element_class, category) self._printer = pAdicPrinter(self, print_mode) diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index aefba904c9d..4a041a848bb 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -934,19 +934,6 @@ def algebraic_closure(self): from sage.rings.all import QQbar return QQbar - def dist(self, a, b): - """ - Return the distance between ``a`` and ``b``. - - EXAMPLES:: - - sage: QQ.dist(3, 2) - 1 - sage: QQ.dist(-1, 1/2) - 3/2 - """ - return self(a - b).abs() - def order(self): r""" Return the order of `\QQ` which is `\infty`. diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 8211108ddd4..a0a22c4e7d3 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -236,19 +236,6 @@ cdef class RealDoubleField_class(Field): return 0 return cmp(type(self), type(x)) - def dist(self, a, b): - """ - Return the distance between ``a`` and ``b`` in ``self``. - - EXAMPLES:: - - sage: RDF.dist(5, 1/2) - 4.5 - sage: RDF.dist(-1, 1/2) - 1.5 - """ - return (self(a) - self(b)).abs() - def construction(self): r""" Returns the functorial construction of ``self``, namely, completion of diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 415e9be2e44..3950c1bb96c 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -801,19 +801,6 @@ cdef class RealField_class(sage.rings.ring.Field): """ return self.complex_field() - def dist(self, a, b): - """ - Return the distance between ``a`` and ``b``. - - EXAMPLES:: - - sage: RR.dist(3, 2) - 1.00000000000000 - sage: RR.dist(-1, pi) - 4.14159265358979 - """ - return self(a - b).abs() - def ngens(self): """ Return the number of generators. From bfa0cdf3696eadd6c2307f96dd366916746d5366 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 17 Oct 2015 09:59:39 -0500 Subject: [PATCH 1631/1872] One last doc tweak. --- src/sage/categories/metric_spaces.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index d7147ede2df..79840337511 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -91,8 +91,8 @@ class MetricSpaces(MetricSpacesCategory): .. TODO:: - Implement a general geodesics class. - - Implement a category for metric unital additive magmas and - move the generic distance `d(a, b) = |a - b|` there. + - Implement a category for metric additive groups + and move the generic distance `d(a, b) = |a - b|` there. - Incorperate the length of a geodesic as part of the default distance cycle. From d13c3688328149c08f4efbbcee91a8fd2978d91a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 17 Oct 2015 10:12:00 -0500 Subject: [PATCH 1632/1872] Fixing doc of metric spaces. --- src/sage/categories/metric_spaces.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index 79840337511..89788f7e83c 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -1,5 +1,5 @@ r""" -Topological Spaces +Metric Spaces """ #***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw @@ -29,8 +29,8 @@ def default_super_categories(cls, category): INPUT: - - ``cls`` -- the class ``MetricSpaces`` - - ``category`` -- a category `Cat` + - ``cls`` -- the class ``MetricSpaces`` + - ``category`` -- a category `Cat` OUTPUT: From 9d3a6e396bde00555b19368b0d76a3e438fcfff7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 17:33:54 +0200 Subject: [PATCH 1633/1872] let __eq__ deal with noncomparable elements --- src/sage/rings/asymptotic/asymptotic_ring.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index f02f19f0061..144de521caa 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -758,10 +758,18 @@ def __eq__(self, other): sage: x == None False + + :: + + sage: x == 'x' + False """ if other is None: return False - return not bool(self - other) + try: + return not bool(self - other) + except (TypeError, ValueError): + return False def __ne__(self, other): From 5327238673a39f66f5fc6e51e46b859a5d42ec12 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 17:34:27 +0200 Subject: [PATCH 1634/1872] doctests: rewrite >>... to >...> --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 144de521caa..cb6068c7047 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1898,7 +1898,7 @@ def _substitute_(self, rules): Exact Term Monoid z^QQ with coefficients in Rational Field. >> *previous* ZeroDivisionError: Cannot substitute in z^(-1) in Growth Group z^QQ. - >>... *previous* ZeroDivisionError: rational division by zero + >...> *previous* ZeroDivisionError: rational division by zero """ if not self.summands: return rules['_zero_'] @@ -2420,7 +2420,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): > *previous* ValueError: Growth c is not in Exact Term Monoid a^ZZ * b^ZZ with coefficients in Rational Field. >> *previous* ValueError: c is not in Growth Group a^ZZ * b^ZZ. - >>... *previous* ValueError: c is not in any of the factors of + >...> *previous* ValueError: c is not in any of the factors of Growth Group a^ZZ * b^ZZ :: From ef4ebb185f2667261dcf41996af9ff98444d2726 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 17:35:41 +0200 Subject: [PATCH 1635/1872] rewrite main substitution method --- src/sage/rings/asymptotic/asymptotic_ring.py | 59 +++++++++++++------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index cb6068c7047..2336840a8d1 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1812,29 +1812,47 @@ def substitute(self, rules=None, domain=None, **kwds): sage: _.parent() Real Interval Field with 53 bits of precision """ + # check if nothing to do if not rules and not kwds: return self + # init and process keyword arguments gens = self.parent().gens() - locals = dict((str(g), g) for g in gens) + locals = kwds or dict() + # update with rules if isinstance(rules, dict): - locals.update(rules) + for k, v in rules.iteritems(): + if not isinstance(k, str) and k not in gens: + raise TypeError('Cannot substitute %s in %s ' + 'since it is neither an ' + 'asymptotic expansion ' + 'nor a string (but a %s).' % + (k, self, type(k))) + k = str(k) + if k in locals and locals[k] != v: + raise ValueError('Cannot substitute in %s: ' + 'duplicate key %s.' % (self, k)) + locals[k] = v elif rules is not None: raise TypeError('Substitution rules %s have to be a dictionary.' % (rules,)) - if kwds: - gens_str = tuple(str(g) for g in gens) - for k, v in kwds.iteritems(): - k = str(k) - if k not in gens_str: - raise ValueError('Cannot substitute %s by %s in %s ' - 'since it is not a generator of %s.' % - (k, v, self, self.parent())) - locals[k] = v - - if domain is None: + # fill up missing rules + for g in gens: + locals.setdefault(str(g), g) + + # check if all keys are generators + gens_str = tuple(str(g) for g in gens) + for k in locals: + if str(k) not in gens_str: + raise ValueError('Cannot substitute %s in %s ' + 'since it is not a generator of %s.' % + (k, self, self.parent())) + + # determine 0 and 1 + if domain is None and \ + ('_zero_' not in locals or '_one_' not in locals): P = self.parent() for g in gens: G = locals[str(g)].parent() @@ -1843,19 +1861,22 @@ def substitute(self, rules=None, domain=None, **kwds): break else: domain = P - locals['_zero_'] = domain.zero() - locals['_one_'] = domain.one() + locals.setdefault('_zero_', domain.zero()) + locals.setdefault('_one_', domain.one()) + # do the actual substitution try: return self._substitute_(locals) - except TypeError as e: + except (ArithmeticError, TypeError, ValueError) as e: from misc import combine_exceptions rules = '{' + ', '.join( '%s: %s' % (k, v) - for k, v in sorted(locals.iteritems(), key=lambda k: str(k[0])) - if k[0] != '_') + '}' + for k, v in sorted(locals.iteritems(), + key=lambda k: str(k[0])) + if not k.startswith('_') and + not any(k == str(g) and v is g for g in gens)) + '}' raise combine_exceptions( - TypeError('Cannot apply the substitution rules %s at %s ' + TypeError('Cannot apply the substitution rules %s on %s ' 'in %s.' % (rules, self, self.parent())), e) From 2f434d7237bff661589d4fe75bf323cb9020a766 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 17:36:02 +0200 Subject: [PATCH 1636/1872] write doc and many doctests for substitute --- src/sage/rings/asymptotic/asymptotic_ring.py | 99 ++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 2336840a8d1..524953bdfd9 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -1773,6 +1773,31 @@ def exp(self, precision=None): def substitute(self, rules=None, domain=None, **kwds): r""" + Substitute the given ``rules`` in this asymptotic expansion. + + INPUT: + + - ``rules`` -- a dictionary. + + - ``kwds`` -- keyword arguments will be added to the + substitution ``rules``. + + - ``domain`` -- (default: ``None``) a parent. The neutral + elements `0` and `1` (rules for the keys ``'_zero_'`` and + ``'_one_'``, see note box below) are taken out of this + domain. If ``None``, then this is determined automatically. + + OUTPUT: + + An object. + + .. NOTE:: + + The neutral element of the asymptotic ring is replaced by + the value to the key ``'_zero_'``; the neutral element of + the growth group is replaced by the value to the key + ``'_one_'``. + EXAMPLES:: sage: A. = AsymptoticRing(growth_group='(e^x)^QQ * x^ZZ * log(x)^ZZ', coefficient_ring=QQ, default_prec=5) @@ -1811,6 +1836,80 @@ def substitute(self, rules=None, domain=None, **kwds): 229.534211738584? sage: _.parent() Real Interval Field with 53 bits of precision + + .. SEEALSO:: + + :meth:`sage.symbolic.expression.Expression.subs` + + TESTS:: + + sage: x.subs({'y': -1}) + Traceback (most recent call last): + ... + ValueError: Cannot substitute y in x since it is not a generator of + Asymptotic Ring <(e^x)^QQ * x^ZZ * log(x)^ZZ> over Rational Field. + sage: B. = AsymptoticRing(growth_group='u^QQ * v^QQ * w^QQ', coefficient_ring=QQ) + sage: (1/u).subs({'u': 0}) + Traceback (most recent call last): + ... + TypeError: Cannot apply the substitution rules {u: 0} on u^(-1) in + Asymptotic Ring over Rational Field. + > *previous* ZeroDivisionError: Cannot substitute in u^(-1) in + Asymptotic Ring over Rational Field. + >> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in + Exact Term Monoid u^QQ * v^QQ * w^QQ with coefficients in Rational Field. + >...> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in + Growth Group u^QQ * v^QQ * w^QQ. + >...> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in + Growth Group u^QQ. + >...> *previous* ZeroDivisionError: rational division by zero + sage: (1/u).subs({'u': 0, 'v': SR.var('v')}) + Traceback (most recent call last): + ... + TypeError: Cannot apply the substitution rules {u: 0, v: v} on u^(-1) in + Asymptotic Ring over Rational Field. + > *previous* ZeroDivisionError: Cannot substitute in u^(-1) in + Asymptotic Ring over Rational Field. + >> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in + Exact Term Monoid u^QQ * v^QQ * w^QQ with coefficients in Rational Field. + >...> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in + Growth Group u^QQ * v^QQ * w^QQ. + >...> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in + Growth Group u^QQ. + >...> *previous* ZeroDivisionError: rational division by zero + + :: + + sage: u.subs({u: 0, 'v': SR.var('v')}) + 0 + sage: v.subs({u: 0, 'v': SR.var('v')}) + v + sage: _.parent() + Symbolic Ring + + :: + + sage: u.subs({SR.var('u'): -1}) + Traceback (most recent call last): + ... + TypeError: Cannot substitute u in u since it is neither an + asymptotic expansion nor a string + (but a ). + + :: + + sage: u.subs({u: 1, 'u': 1}) + 1 + sage: u.subs({u: 1}, u=1) + 1 + sage: u.subs({u: 1, 'u': 2}) + Traceback (most recent call last): + ... + ValueError: Cannot substitute in u: duplicate key u. + sage: u.subs({u: 1}, u=3) + Traceback (most recent call last): + ... + ValueError: Cannot substitute in u: duplicate key u. """ # check if nothing to do if not rules and not kwds: From ea5741f9a233c8a385a47e406cd436783206bc62 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 17 Oct 2015 18:22:45 +0200 Subject: [PATCH 1637/1872] Trac #18546: Add ARB as a dependency of sage --- build/make/deps | 1 + 1 file changed, 1 insertion(+) diff --git a/build/make/deps b/build/make/deps index 3d0fb935312..27f488d2d19 100644 --- a/build/make/deps +++ b/build/make/deps @@ -100,6 +100,7 @@ base: $(INST)/$(BZIP2) $(INST)/$(PATCH) $(INST)/$(PKGCONF) # Sage library (e.g. CYTHON, JINJA2), and on the other hand all # dependencies for Cython files (e.g. PARI, NTL, SAGE_MP_LIBRARY). sagelib: \ + $(INST)/$(ARB) \ $(INST)/$(ATLAS) \ $(INST)/$(CEPHES) \ $(INST)/$(CLIQUER) \ From e4f2a9db88c97fac89e0cd031579cc88b59dbeaa Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 17 Oct 2015 19:30:06 +0200 Subject: [PATCH 1638/1872] Trac #19305: simpler doctest --- src/sage/rings/asymptotic/growth_group.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index d46eff7a492..06901df58eb 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2704,8 +2704,8 @@ def _substitute_(self, rules): z^42 sage: _.parent() Symbolic Ring - sage: G(x^42)._substitute_({'x': 2}) - 4398046511104 + sage: G(x^3)._substitute_({'x': 2}) + 8 sage: _.parent() Integer Ring sage: G(1 / x)._substitute_({'x': 0}) From bb7c1046b3d7a7d4b18762028ee5230874582fcd Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 17 Oct 2015 19:30:30 +0200 Subject: [PATCH 1639/1872] Trac #19305: do not use variable "e" as it is special in asymptotics --- src/sage/rings/asymptotic/term_monoid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index e620bc5e096..fcf1ab2e802 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -2302,9 +2302,9 @@ def _substitute_(self, rules): Order(z) sage: t._substitute_({'x': SR.var('z'), 'O': function('Oh')}) Oh(z) - sage: e = AsymptoticRing('x^ZZ', ZZ)('2*x'); e + sage: u = AsymptoticRing('x^ZZ', ZZ)('2*x'); u 2*x - sage: t._substitute_({'x': e}) + sage: t._substitute_({'x': u}) O(x) sage: T(1/x)._substitute_({'x': 0}) Traceback (most recent call last): From 875542da5e016b418c99b275f1e1057489ecd565 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 20:57:54 +0200 Subject: [PATCH 1640/1872] write AsymptoticExpansion.symbolic_expression --- src/sage/rings/asymptotic/asymptotic_ring.py | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 524953bdfd9..770e9dd5978 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2032,6 +2032,38 @@ def _substitute_(self, rules): substitute_raise_exception(self, e) + def symbolic_expression(self): + r""" + Return this asymptotic expansion as a symbolic expression. + + OUTPUT: + + A symbolic expression. + + EXAMPLES:: + + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^QQ * log(y)^QQ * QQ^z * z^QQ', coefficient_ring=QQ) + sage: SR(A.an_element()) # indirect doctest + 1/8*(1/8)^z*x^3*y^(3/2)*z^(3/2)*log(y)^(3/2) + + Order((1/2)^z*x*sqrt(y)*sqrt(z)*sqrt(log(y))) + + TESTS:: + + sage: a = A.an_element(); a + 1/8*x^3*y^(3/2)*log(y)^(3/2)*(1/8)^z*z^(3/2) + + O(x*y^(1/2)*log(y)^(1/2)*(1/2)^z*z^(1/2)) + sage: a.symbolic_expression() + 1/8*(1/8)^z*x^3*y^(3/2)*z^(3/2)*log(y)^(3/2) + + Order((1/2)^z*x*sqrt(y)*sqrt(z)*sqrt(log(y))) + sage: _.parent() + Symbolic Ring + """ + from sage.symbolic.ring import SR + return self.substitute(dict((g, SR.var(str(g))) + for g in self.parent().gens()), + domain=SR) + + class AsymptoticRing(Algebra, UniqueRepresentation): r""" A ring consisting of :class:`asymptotic expansions `. From 5ac0feaa2faebd303bd3d4ed53ce40b60c22311c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 17 Oct 2015 20:58:23 +0200 Subject: [PATCH 1641/1872] extend SR._element_constructor_ to accept asymptotic expansions --- src/sage/symbolic/ring.pyx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index bdf639a1995..fdcf079a4ec 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -251,6 +251,22 @@ cdef class SymbolicRing(CommutativeRing): sage: bool(si == CC.0) True + Asymptotic expansions:: + + sage: A. = AsymptoticRing(growth_group='x^ZZ * y^QQ * log(y)^ZZ', coefficient_ring=ZZ) + doctest:...: FutureWarning: This class/method/function is + marked as experimental. + ... + See http://trac.sagemath.org/17601 for details. + sage: s = SR(3*x^5 * log(y) + 4*y^(3/7) + O(x*log(y))); s + 3*x^5*log(y) + 4*y^(3/7) + Order(x*log(y)) + sage: s.operator(), s.operands() + (, + [3*x^5*log(y), 4*y^(3/7), Order(x*log(y))]) + sage: t = s.operands()[0]; t + 3*x^5*log(y) + sage: t.operator(), t.operands() + (, [x^5, log(y), 3]) """ cdef GEx exp @@ -271,6 +287,7 @@ cdef class SymbolicRing(CommutativeRing): from sage.rings.infinity import (infinity, minus_infinity, unsigned_infinity) + from sage.rings.asymptotic.asymptotic_ring import AsymptoticExpansion if isinstance(x, (Integer, RealNumber, float, long, complex)): GEx_construct_pyobject(exp, x) @@ -282,6 +299,8 @@ cdef class SymbolicRing(CommutativeRing): return new_Expression_from_GEx(self, g_mInfinity) elif x is unsigned_infinity: return new_Expression_from_GEx(self, g_UnsignedInfinity) + elif isinstance(x, AsymptoticExpansion): + return x.symbolic_expression() elif isinstance(x, (RingElement, Matrix)): GEx_construct_pyobject(exp, x) else: From 5406172502891b43a78426ef76746dc8a73e264b Mon Sep 17 00:00:00 2001 From: "George H. Seelinger" Date: Sat, 17 Oct 2015 13:59:34 -0500 Subject: [PATCH 1642/1872] Added an assert statement and took into account the one element of the base ring. --- src/sage/combinat/diagram_algebras.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index e05983c8593..5814e551959 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1969,13 +1969,15 @@ def _element_constructor_(self, set_partition): def jucys_murphy(self, j): r""" - Return a generalized Jucys-Murphy elements for the Brauer algebra. - These are outlined in [Naz]_. + Return the ``j``-th generalized Jucys-Murphy element of ``self``. + These elements are simply the Jucys-Murphy elements of the symmetric + group algebra with an extra ``(z-1)/2`` term where ``z`` is the parameter + of the Brauer algebra. REFERENCES: .. [Naz] Maxim Nazarov, Young's Orthogonal Form for Brauer's Centralizer - Algebra. Journal of Algebra 182 (1996), 664--693. + Algebra. Journal of Algebra 182 (1996), 664--693. EXAMPLES: @@ -1984,10 +1986,15 @@ def jucys_murphy(self, j): sage: B.jucys_murphy(1) 1/2*z - 1/2 sage: B.jucys_murphy(3) - -B{{-3, -2}, {-1, 1}, {2, 3}} - B{{-3, -1}, {-2, 2}, {1, 3}} + B{{-3, 1}, {-2, 2}, {-1, 3}} + B{{-3, 2}, {-2, 3}, {-1, 1}} + (1/2*z-1/2)*B{{-3, 3}, {-2, 2}, {-1, 1}} - """ - B = self - return (B._q-1)/2 + sum(B([[i,-j],[j,-i]]) - B([[i,j],[-i,-j]]) for i in range(1,j)) + -B{{-3, -2}, {-1, 1}, {2, 3}} - B{{-3, -1}, {-2, 2}, {1, 3}} + + B{{-3, 1}, {-2, 2}, {-1, 3}} + B{{-3, 2}, {-2, 3}, {-1, 1}} + + (1/2*z-1/2)*B{{-3, 3}, {-2, 2}, {-1, 1}} + """ + assert j <= self.order(), "Jucys-Murphy index cannot be greater than the order of the algebra." + I = self._indices + one = self.base_ring().one() + return ((self._q-1)/2 + + sum(one*self([[i,-j],[j,-i]]) - one*self([[i,j],[-i,-j]]) for i in range(1,j))) class TemperleyLiebAlgebra(SubPartitionAlgebra): r""" From d34e7c3dfcda5b31ea4b5f1d112d843ae0d0e549 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Fri, 16 Oct 2015 12:10:04 -0700 Subject: [PATCH 1643/1872] trac 19016: add doctests to preserve coverage count --- src/sage/combinat/crystals/affine.py | 90 ++++++++++++++++++- src/sage/combinat/crystals/subcrystal.py | 57 +++++++++++- .../function_field/function_field_element.pyx | 18 ++++ src/sage/structure/element.pyx | 10 +++ 4 files changed, 170 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/crystals/affine.py b/src/sage/combinat/crystals/affine.py index 08b6f3e2b4d..b4f9ac8a6b9 100644 --- a/src/sage/combinat/crystals/affine.py +++ b/src/sage/combinat/crystals/affine.py @@ -473,27 +473,109 @@ def __eq__(self, other): sage: K = crystals.KirillovReshetikhin(['A',2,1],1,1) sage: b = K(rows=[[1]]) sage: c = K(rows=[[2]]) - sage: cc + False + sage: b>b + False + sage: c>b + True + """ return parent(self) is parent(other) and self.value > other.value + def __le__(self, other): + """" + EXAMPLES:: + + sage: K = crystals.KirillovReshetikhin(['A',2,1],1,1) + sage: b = K(rows=[[1]]) + sage: c = K(rows=[[2]]) + sage: b<=c + True + sage: b<=b + True + sage: c<=b + False + """ return parent(self) is parent(other) and self.value <= other.value + def __ge__(self, other): + """" + EXAMPLES:: + + sage: K = crystals.KirillovReshetikhin(['A',2,1],1,1) + sage: b = K(rows=[[1]]) + sage: c = K(rows=[[2]]) + sage: c>=b + True + sage: b>=b + True + sage: b>=c + False + """ return parent(self) is parent(other) and self.value >= other.value def __cmp__(self, other): + """" + EXAMPLES:: + + sage: K = crystals.KirillovReshetikhin(['A',2,1],1,1) + sage: b = K(rows=[[1]]) + sage: c = K(rows=[[2]]) + sage: cmp(b,c) + -1 + sage: cmp(b,1) + -1 + sage: cmp(b,b) + 0 + """ if parent(self) is parent(other): return cmp(self.value, other.value) else: diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index ccacb83dfb5..c7731e9f0b1 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -288,7 +288,7 @@ class Element(ElementWrapper): """ def __eq__(self, other): """ - Check less than. + Check sorting EXAMPLES:: @@ -309,15 +309,70 @@ def __eq__(self, other): [[-1, -1]](2)] """ return parent(self) is parent(other) and self.value == other.value + def __ne__(self, other): + """ + TESTS:: + + sage: A = crystals.KirillovReshetikhin(['C',2,1], 1,2).affinization() + sage: S = A.subcrystal(max_depth=2) + sage: ([(i,j) for i in range(len(S)) for j in range(len(S)) if S[i]!=S[j]] + ....: == [(i,j) for i in range(len(S)) for j in range(len(S)) if + ....: S[i].value!=S[j].value]) + True + """ return parent(self) is not parent(other) or self.value != other.value + def __lt__(self, other): + """ + TESTS:: + + sage: A = crystals.KirillovReshetikhin(['C',2,1], 1,2).affinization() + sage: S = A.subcrystal(max_depth=2) + sage: ([(i,j) for i in range(len(S)) for j in range(len(S)) if S[i]S[j]] + ....: == [(i,j) for i in range(len(S)) for j in range(len(S)) if + ....: S[i].value>S[j].value]) + True + """ return parent(self) is parent(other) and self.value > other.value + def __ge__(self, other): + """ + TESTS:: + + sage: A = crystals.KirillovReshetikhin(['C',2,1], 1,2).affinization() + sage: S = A.subcrystal(max_depth=2) + sage: ([(i,j) for i in range(len(S)) for j in range(len(S)) if S[i]>=S[j]] + ....: == [(i,j) for i in range(len(S)) for j in range(len(S)) if + ....: S[i].value>=S[j].value]) + True + """ return parent(self) is parent(other) and self.value >= other.value def __cmp__(self, other): diff --git a/src/sage/rings/function_field/function_field_element.pyx b/src/sage/rings/function_field/function_field_element.pyx index b2dc3230839..6ec309b8436 100644 --- a/src/sage/rings/function_field/function_field_element.pyx +++ b/src/sage/rings/function_field/function_field_element.pyx @@ -362,6 +362,14 @@ cdef class FunctionFieldElement_polymod(FunctionFieldElement): return not not self._x def __hash__(self): + """ + TESTS:: + + sage: K. = FunctionField(QQ); R. = K[] + sage: L. = K.extension(y^2 - x*y + 4*x^3) + sage: len({hash(y^i+x^j) for i in [-2..2] for j in [-2..2]}) == 25 + True + """ return hash(self._x) cpdef int _cmp_(self, Element other) except -2: @@ -567,6 +575,16 @@ cdef class FunctionFieldElement_rational(FunctionFieldElement): return not not self._x def __hash__(self): + """ + TESTS: + + It would be nice if the following would produce a list of + 15 distinct hashes. + + sage: K. = FunctionField(QQ) + sage: len({hash(t^i+t^j) for i in [-2..2] for j in [i..2]}) + 10 + """ return hash(self._x) cpdef int _cmp_(self, Element other) except -2: diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index ad72a1cf532..a76e61926ec 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -962,6 +962,16 @@ cdef class Element(SageObject): raise def _cache_key(self): + """ + Provide a hashable key for an element if it is not hashable + + EXAMPLES:: + + sage: a=sage.structure.element.Element(ZZ) + sage: a._cache_key() + (Integer Ring, 'Generic element of a structure') + """ + return(self.parent(),str(self)) cdef _richcmp(self, other, int op): From feaa7a01b4db03b6ac25f758efb57f5590735c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 17 Oct 2015 22:17:12 +0200 Subject: [PATCH 1644/1872] trac 6322 better double optional condition on magma and gap --- .../explicit_methods_in_number_theory/nf_galois_groups.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 530c26f614d..4756963f818 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 @@ -89,7 +89,7 @@ groups in the GAP transitive groups database. :: sage: K. = NumberField(x^3 - 2) - sage: K.galois_group(type="gap", algorithm='magma') # optional - magma # optional - database_gap + sage: K.galois_group(type="gap", algorithm='magma') # optional - magma database_gap Galois group Transitive group number 2 of degree 3 of the Number Field in a with defining polynomial x^3 - 2 From 9613ee37a939b0a2b5fda54696f91dafc225a65a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 17 Oct 2015 16:06:17 -0500 Subject: [PATCH 1645/1872] Tweaks to the JM code and fixing a doctest. --- src/sage/combinat/diagram_algebras.py | 38 +++++++++++++++++---------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 5814e551959..b4f977d86c0 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1970,31 +1970,41 @@ def _element_constructor_(self, set_partition): def jucys_murphy(self, j): r""" Return the ``j``-th generalized Jucys-Murphy element of ``self``. - These elements are simply the Jucys-Murphy elements of the symmetric - group algebra with an extra ``(z-1)/2`` term where ``z`` is the parameter + + The `j`-th Jucys-Murphy element of a Brauer algebra is simply + the `j`-th Jucys-Murphy element of the symmetric group algebra + with an extra `(z-1)/2` term, where ``z`` is the parameter of the Brauer algebra. REFERENCES: - .. [Naz] Maxim Nazarov, Young's Orthogonal Form for Brauer's Centralizer - Algebra. Journal of Algebra 182 (1996), 664--693. + .. [Naz96] Maxim Nazarov, Young's Orthogonal Form for Brauer's + Centralizer Algebra. Journal of Algebra 182 (1996), 664--693. - EXAMPLES: + EXAMPLES:: sage: z = var('z') sage: B = BrauerAlgebra(3,z) sage: B.jucys_murphy(1) - 1/2*z - 1/2 + (1/2*z-1/2)*B{{-3, 3}, {-2, 2}, {-1, 1}} sage: B.jucys_murphy(3) -B{{-3, -2}, {-1, 1}, {2, 3}} - B{{-3, -1}, {-2, 2}, {1, 3}} - + B{{-3, 1}, {-2, 2}, {-1, 3}} + B{{-3, 2}, {-2, 3}, {-1, 1}} - + (1/2*z-1/2)*B{{-3, 3}, {-2, 2}, {-1, 1}} - """ - assert j <= self.order(), "Jucys-Murphy index cannot be greater than the order of the algebra." - I = self._indices - one = self.base_ring().one() - return ((self._q-1)/2 - + sum(one*self([[i,-j],[j,-i]]) - one*self([[i,j],[-i,-j]]) for i in range(1,j))) + + B{{-3, 1}, {-2, 2}, {-1, 3}} + B{{-3, 2}, {-2, 3}, {-1, 1}} + + (1/2*z-1/2)*B{{-3, 3}, {-2, 2}, {-1, 1}} + """ + if j < 1: + raise ValueError("Jucys-Murphy index must be positive") + k = self.order() + if j > k: + raise ValueError("Jucys-Murphy index cannot be greater than the order of the algebra") + I = lambda x: self._indices(to_Brauer_partition(x, k=k)) + R = self.base_ring() + one = R.one() + d = {self.one_basis(): R( (self._q-1) / 2 )} + for i in range(1,j): + d[I([[i,-j],[j,-i]])] = one + d[I([[i,j],[-i,-j]])] = -one + return self._from_dict(d, remove_zeros=True) class TemperleyLiebAlgebra(SubPartitionAlgebra): r""" From 953e0a6489a3eca48b13b1e91ece798c51a6fe5c Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 17 Oct 2015 15:37:01 -0700 Subject: [PATCH 1646/1872] trac 6101: add _an_element_, etc., to SimplicialComplex --- src/sage/homology/simplicial_complex.py | 55 ++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index 8d00cd63d93..1a27c75015e 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -872,8 +872,8 @@ def __init__(self, sage: S == loads(dumps(S)) True - sage: TestSuite(S).run(skip="_test_category") - sage: TestSuite(S3).run(skip="_test_category") + sage: TestSuite(S).run() + sage: TestSuite(S3).run() """ if (maximal_faces is not None and from_characteristic_function is not None): @@ -1077,6 +1077,57 @@ def vertices(self): """ return self._vertex_set + def _an_element_(self): + """ + The first facet of this complex. + + EXAMPLES:: + + sage: SimplicialComplex()._an_element_() + () + sage: simplicial_complexes.Sphere(3)._an_element_() + (1, 2, 3, 4) + """ + return self.facets()[0] + + def __contains__(self, x): + """ + True if ``x`` is a simplex which is contained in this complex. + + EXAMPLES:: + + sage: K = SimplicialComplex([(0,1,2), (0,2,3)]) + sage: Simplex((0,2)) in K + True + sage: Simplex((1,3)) in K + False + sage: 0 in K # not a simplex + False + """ + if not isinstance(x, Simplex): + return False + dim = x.dimension() + return x in self.n_faces(dim) + + def __call__(self, simplex): + """ + If ``simplex`` is a simplex in this complex, return it. + Otherwise, raise a ``ValueError``. + + EXAMPLE:: + + sage: K = SimplicialComplex([(0,1,2), (0,2,3)]) + sage: K(Simplex((1,2))) + (1, 2) + sage: K(Simplex((0,1,3))) + Traceback (most recent call last): + ... + ValueError: the simplex is not in this complex + """ + if simplex not in self: + raise ValueError('the simplex is not in this complex') + return simplex + def maximal_faces(self): """ The maximal faces (a.k.a. facets) of this simplicial complex. From fcf799ce33270401e9dce7bfcf4f383dbcedc49d Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Sat, 17 Oct 2015 19:55:45 -0700 Subject: [PATCH 1647/1872] tract 19016: some further doctest fixes --- src/sage/combinat/crystals/subcrystal.py | 9 +++++++++ src/sage/rings/function_field/function_field_element.pyx | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index c7731e9f0b1..6d3ecee636d 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -376,6 +376,15 @@ def __ge__(self, other): return parent(self) is parent(other) and self.value >= other.value def __cmp__(self, other): + """ + TESTS:: + + sage: A = crystals.KirillovReshetikhin(['C',2,1], 1,2).affinization() + sage: S = A.subcrystal(max_depth=2) + sage: ([(i,j,cmp(S[i],S[j])) for i in range(len(S)) for j in range(len(S))] + ....: == [(i,j,cmp(S[i].value,S[j].value)) for i in range(len(S)) for j in range(len(S))]) + True + """ if parent(self) is parent(other): return cmp(self.value, other.value) else: diff --git a/src/sage/rings/function_field/function_field_element.pyx b/src/sage/rings/function_field/function_field_element.pyx index 6ec309b8436..580bd5fa283 100644 --- a/src/sage/rings/function_field/function_field_element.pyx +++ b/src/sage/rings/function_field/function_field_element.pyx @@ -579,7 +579,7 @@ cdef class FunctionFieldElement_rational(FunctionFieldElement): TESTS: It would be nice if the following would produce a list of - 15 distinct hashes. + 15 distinct hashes:: sage: K. = FunctionField(QQ) sage: len({hash(t^i+t^j) for i in [-2..2] for j in [i..2]}) From 81c442e3c47b964e604c0314fc15bfe5ef5a0506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 18 Oct 2015 15:02:45 +0200 Subject: [PATCH 1648/1872] some hidden doc problems in underscore methods --- src/sage/lfunctions/zero_sums.pyx | 3 +- src/sage/quadratic_forms/genera/genus.py | 206 ++++++++++------------- src/sage/rings/continued_fraction.py | 4 +- 3 files changed, 95 insertions(+), 118 deletions(-) diff --git a/src/sage/lfunctions/zero_sums.pyx b/src/sage/lfunctions/zero_sums.pyx index e35bf038bad..6c4535c3d9c 100644 --- a/src/sage/lfunctions/zero_sums.pyx +++ b/src/sage/lfunctions/zero_sums.pyx @@ -1552,7 +1552,8 @@ cdef class LFunctionZeroSum_EllipticCurve(LFunctionZeroSum_abstract): specified by max_Delta. This computation can be run on curves with very large conductor (so long as the conductor is known or quickly computable) when Delta is not too large (see below). - Uses Bober's rank bounding method as described in [Bob-13]. + + Uses Bober's rank bounding method as described in [Bob-13]_. INPUT: diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 60f2f8f7c74..1f978f0f1ad 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -17,24 +17,23 @@ from sage.rings.integer import Integer from sage.rings.finite_rings.constructor import FiniteField + def Genus(A): - """ - Given a nonsingular symmetric matrix A, return the genus of A. + r""" + Given a nonsingular symmetric matrix `A`, return the genus of `A`. INPUT: - - A -- a symmetric matrix with coefficients in ZZ + - `A` -- a symmetric matrix with coefficients in `\ZZ` OUTPUT: - A GenusSymbol_global_ring object, encoding the Conway-Sloane - genus symbol of the quadratic form whose Gram matrix is A. + A ``GenusSymbol_global_ring`` object, encoding the Conway-Sloane + genus symbol of the quadratic form whose Gram matrix is `A`. EXAMPLES:: - sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring sage: from sage.quadratic_forms.genera.genus import Genus - sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: Genus(A) Genus of [1 1] @@ -43,7 +42,6 @@ def Genus(A): return GenusSymbol_global_ring(A) - def LocalGenusSymbol(A,p): """ Given a nonsingular symmetric matrix A, return the local symbol of A at the prime p. @@ -55,8 +53,8 @@ def LocalGenusSymbol(A,p): OUTPUT: - A Genus_Symbol_p_adic_ring object, encoding the Conway-Sloane - genus symbol at p of the quadratic form whose Gram matrix is A. + A Genus_Symbol_p_adic_ring object, encoding the Conway-Sloane + genus symbol at p of the quadratic form whose Gram matrix is A. EXAMPLES:: @@ -91,7 +89,7 @@ def is_GlobalGenus(G): OUTPUT: - boolean + boolean EXAMPLES:: @@ -144,7 +142,7 @@ def is_2_adic_genus(genus_symbol_quintuple_list): OUTPUT: - boolean + boolean EXAMPLES:: @@ -209,7 +207,7 @@ def canonical_2_adic_compartments(genus_symbol_quintuple_list): OUTPUT: - a list of lists of integers. + a list of lists of integers. EXAMPLES:: @@ -283,7 +281,7 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): OUTPUT: - a list of lists of distinct integers. + a list of lists of distinct integers. EXAMPLES:: @@ -325,12 +323,13 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): sage: canonical_2_adic_trains(G2.symbol_tuple_list()) [] - NOTES: + .. NOTE:: See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples. - TO DO: - - Add a non-trivial example in the doctest here! + .. TODO:: + + Add a non-trivial example in the doctest here! """ ## Recompute compartments if none are passed. if compartments is None: @@ -384,7 +383,7 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): OUTPUT: - a list of lists of distinct integers. + a list of lists of distinct integers. EXAMPLES:: @@ -415,12 +414,13 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): sage: canonical_2_adic_reduction(G2.symbol_tuple_list()) [[0, 2, -1, 0, 0]] - NOTES: + .. NOTE:: See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples. - TO DO: - - Add an example where sign walking occurs! + .. TODO:: + + Add an example where sign walking occurs! """ canonical_symbol = genus_symbol_quintuple_list # Canonical determinants: @@ -469,7 +469,7 @@ def basis_complement(B): OUTPUT: - a rectangular matrix over a field + a rectangular matrix over a field EXAMPLES:: @@ -515,7 +515,7 @@ def signature_pair_of_matrix(A): OUTPUT: - a pair (tuple) of integers. + a pair (tuple) of integers. EXAMPLES:: @@ -564,7 +564,10 @@ def p_adic_symbol(A, p, val): val = valuation of the maximal elementary divisor of A needed to obtain enough precision calculation is modulo p to the val+3 - TODO: Some description of the definition of the genus symbol. + + .. TODO:: + + Some description of the definition of the genus symbol. INPUT: @@ -574,7 +577,7 @@ def p_adic_symbol(A, p, val): OUTPUT: - a list of lists of integers + a list of lists of integers EXAMPLES:: @@ -638,7 +641,7 @@ def is_even_matrix(A): OUTPUT: - a pair of the form (boolean, integer) + a pair of the form (boolean, integer) EXAMPLES:: @@ -671,8 +674,8 @@ def split_odd(A): OUTPUT: - a pair (u, B) consisting of an odd integer u and an odd - integral symmetric matrix B. + a pair (u, B) consisting of an odd integer u and an odd + integral symmetric matrix B. EXAMPLES:: @@ -764,7 +767,7 @@ def trace_diag_mod_8(A): OUTPUT: - an integer + an integer EXAMPLES:: @@ -816,7 +819,7 @@ def two_adic_symbol(A, val): OUTPUT: - a list of lists of integers (representing a Conway-Sloane 2-adic symbol) + a list of lists of integers (representing a Conway-Sloane 2-adic symbol) EXAMPLES:: @@ -890,29 +893,6 @@ def two_adic_symbol(A, val): return [ [s[0]+m0] + s[1:] for s in sym + two_adic_symbol(A, val) ] - - - -## Removed because it was unused and undocumented! -# -#def is_trivial_symbol(p, sym): -# """ -# """ -# if len(sym) != 1: -# return False -# if sym[0] != 0 or sym[2] != 1: -# return False -# if p != 2: -# return True -# return sym[3] == 1 and sym[1] % 8 == sym[4] - - - - - - - - class Genus_Symbol_p_adic_ring(object): """ Local genus symbol over a p-adic ring. @@ -924,19 +904,19 @@ def __init__(self, prime, symbol, check = True): The genus symbol of a component p^m*A for odd prime = p is of the form (m,n,d), where - m = valuation of the component - n = rank of A - d = det(A) in {1,u} for normalized quadratic non-residue u. + - m = valuation of the component + - n = rank of A + - d = det(A) in {1,u} for normalized quadratic non-residue u. The genus symbol of a component 2^m*A is of the form (m,n,s,d,o), where - m = valuation of the component - n = rank of A - d = det(A) in {1,3,5,7} - s = 0 (or 1) if even (or odd) - o = oddity of A (= 0 if s = 0) in Z/8Z - = the trace of the diagonalization of A + - m = valuation of the component + - n = rank of A + - d = det(A) in {1,3,5,7} + - s = 0 (or 1) if even (or odd) + - o = oddity of A (= 0 if s = 0) in Z/8Z + = the trace of the diagonalization of A The genus symbol is a list of such symbols (ordered by m) for each of the Jordan blocks A_1,...,A_t. @@ -949,7 +929,6 @@ def __init__(self, prime, symbol, check = True): doubling conventions straight throughout! This is especially noticeable in the determinant and excess methods!! - INPUT: - prime -- a prime integer > 0 @@ -958,7 +937,7 @@ def __init__(self, prime, symbol, check = True): OUTPUT: - None + None EXAMPLES:: @@ -992,31 +971,29 @@ def __init__(self, prime, symbol, check = True): self._canonical_symbol = None def __repr__(self): - """ + r""" Gives a string representation for the p-adic genus symbol INPUT: - None + None OUTPUT: - a string + a string EXAMPLES:: sage: from sage.quadratic_forms.genera.genus import two_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring - sage: A = diagonal_matrix(ZZ, [1,2,3,4]) sage: s2 = two_adic_symbol(A, 2); s2 [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]] sage: G = Genus_Symbol_p_adic_ring(2, s2) sage: G.__repr__() 'Genus symbol at 2 : [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]]' - """ - return "Genus symbol at %s : %s"%(self._prime, self._symbol) + return "Genus symbol at %s : %s" % (self._prime, self._symbol) def __eq__(self, other): @@ -1025,11 +1002,11 @@ def __eq__(self, other): INPUT: - a Genus_Symbol_p_adic_ring object + a Genus_Symbol_p_adic_ring object OUTPUT: - boolean + boolean EXAMPLES:: @@ -1064,11 +1041,13 @@ def __ne__(self, other): INPUT: - a Genus_Symbol_p_adic_ring object + a ``Genus_Symbol_p_adic_ring`` object OUTPUT: - boolean + boolean + + EXAMPLES:: sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring @@ -1109,11 +1088,11 @@ def canonical_symbol(self): INPUT: - None + None OUTPUT: - a list of lists of integers + a list of lists of integers EXAMPLES:: @@ -1156,13 +1135,13 @@ def canonical_symbol(self): sage: G3.canonical_symbol() [[0, 3, 1], [1, 1, -1]] + .. NOTE:: - NOTES: + See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples. - See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples. + .. TODO:: - TO DO: - - Add an example where sign walking occurs! + Add an example where sign walking occurs! """ symbol = self._symbol if self._prime == 2: @@ -1180,11 +1159,11 @@ def symbol_tuple_list(self): INPUT: - None + None OUTPUT: - list of lists of integers + list of lists of integers EXAMPLES:: @@ -1220,11 +1199,11 @@ def number_of_blocks(self): INPUT: - None + None OUTPUT: - integer >= 0 + integer >= 0 EXAMPLES:: @@ -1258,11 +1237,11 @@ def determinant(self): INPUT: - None + None OUTPUT: - an integer + an integer EXAMPLES:: @@ -1291,16 +1270,17 @@ def rank(self): """ Returns the dimension of a quadratic form associated to this genus symbol. - TO DO: DELETE THIS METHOD IN FAVOR OF THE dimension() METHOD BELOW! + .. TODO:: + DELETE THIS METHOD IN FAVOR OF THE dimension() METHOD BELOW! INPUT: - None + None OUTPUT: - an integer >= 0 + an integer >= 0 EXAMPLES:: @@ -1324,18 +1304,17 @@ def rank(self): """ return sum([ s[1] for s in self._symbol ]) - def dimension(self): """ Returns the dimension of a quadratic form associated to this genus symbol. INPUT: - None + None OUTPUT: - an integer >= 0 + an integer >= 0 EXAMPLES:: @@ -1372,15 +1351,15 @@ def excess(self): REFERENCE: - Conway and Sloane Book, 3rd edition, pp 370-371. + Conway and Sloane Book, 3rd edition, pp 370-371. INPUT: - None + None OUTPUT: - an integer + an integer EXAMPLES:: @@ -1448,11 +1427,11 @@ def trains(self): INPUT: - None + None OUTPUT: - a list of integers >= 0 + a list of integers >= 0 EXAMPLES:: @@ -1483,11 +1462,11 @@ def compartments(self): INPUT: - None + None OUTPUT: - a list of integers >= 0 + a list of integers >= 0 EXAMPLES:: @@ -1534,7 +1513,7 @@ def __init__(self, A, max_elem_divisors=None): OUTPUT: - None + None EXAMPLES:: @@ -1565,29 +1544,26 @@ def __init__(self, A, max_elem_divisors=None): def __repr__(self): - """ + r""" Returns a string representing the global genus symbol. INPUT: - None + None OUTPUT: - a string + a string EXAMPLES:: sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring - sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: GS = GenusSymbol_global_ring(A) sage: GS.__repr__() 'Genus of [2 0 0 0]\n[0 4 0 0]\n[0 0 6 0]\n[0 0 0 8]' - """ - return "Genus of %s"%self._representative - + return "Genus of %s" % self._representative def __eq__(self, other): @@ -1596,11 +1572,11 @@ def __eq__(self, other): INPUT: - a GenusSymbol_global_ring object + a ``GenusSymbol_global_ring`` object OUTPUT: - boolean + boolean EXAMPLES:: @@ -1642,11 +1618,11 @@ def __ne__(self, other): INPUT: - a GenusSymbol_global_ring object + a ``GenusSymbol_global_ring`` object OUTPUT: - boolean + boolean EXAMPLES:: @@ -1681,11 +1657,11 @@ def signature_pair_of_matrix(self): INPUT: - None + None OUTPUT: - a pair of integers (p, n) each >= 0 + a pair of integers (p, n) each >= 0 EXAMPLES:: @@ -1709,11 +1685,11 @@ def determinant(self): INPUT: - None + None OUTPUT: - an integer + an integer EXAMPLES:: diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index 13f17a7c667..3c50c17e610 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -589,7 +589,7 @@ def _mpfr_(self, R): sage: cf.n(digits=11) 8.9371541378 - TESTS:: + TESTS: We check that the rounding works as expected, at least in the rational case:: @@ -1471,7 +1471,7 @@ def _rational_(self): return self.numerator(n-1) / self.denominator(n-1) def _latex_(self): - """ + r""" EXAMPLES:: sage: a = continued_fraction(-17/389) From 323af475b8853045ac21b35b79e9b2b6cca89dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 18 Oct 2015 15:20:43 +0200 Subject: [PATCH 1649/1872] hidden doc problems in arithgroup --- .../modular/arithgroup/arithgroup_element.pyx | 10 +-- .../modular/arithgroup/congroup_gammaH.py | 68 ++++++++++++------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/sage/modular/arithgroup/arithgroup_element.pyx b/src/sage/modular/arithgroup/arithgroup_element.pyx index 3402a75d254..46021d08082 100644 --- a/src/sage/modular/arithgroup/arithgroup_element.pyx +++ b/src/sage/modular/arithgroup/arithgroup_element.pyx @@ -137,19 +137,19 @@ cdef class ArithmeticSubgroupElement(MultiplicativeGroupElement): yield self.__x[1,1] def __repr__(self): - """ - Return the string representation of self. + r""" + Return the string representation of ``self``. EXAMPLES:: sage: Gamma1(5)([6,1,5,1]).__repr__() '[6 1]\n[5 1]' """ - return "%s"%self.__x + return "%s" % self.__x def _latex_(self): - """ - Return latex representation of self. + r""" + Return latex representation of ``self``. EXAMPLES:: diff --git a/src/sage/modular/arithgroup/congroup_gammaH.py b/src/sage/modular/arithgroup/congroup_gammaH.py index 09487983532..388e48eec28 100644 --- a/src/sage/modular/arithgroup/congroup_gammaH.py +++ b/src/sage/modular/arithgroup/congroup_gammaH.py @@ -109,9 +109,11 @@ def _normalize_H(H, level): Normalize representatives for a given subgroup H of the units modulo level. - NOTE: This function does *not* make any attempt to find a minimal - set of generators for H. It simply normalizes the inputs for use - in hashing. + .. NOTE:: + + This function does *not* make any attempt to find a minimal + set of generators for H. It simply normalizes the inputs for use + in hashing. EXAMPLES:: @@ -137,8 +139,8 @@ def _normalize_H(H, level): H.remove(1) return H -class GammaH_class(CongruenceSubgroup): +class GammaH_class(CongruenceSubgroup): r""" The congruence subgroup `\Gamma_H(N)` for some subgroup `H \trianglelefteq (\ZZ / N\ZZ)^\times`, which is the subgroup of `{\rm @@ -147,7 +149,7 @@ class GammaH_class(CongruenceSubgroup): TESTS: - We test calculation of various invariants of the group: :: + We test calculation of various invariants of the group:: sage: GammaH(33,[2]).projective_index() 96 @@ -164,7 +166,7 @@ class GammaH_class(CongruenceSubgroup): sage: Gamma1(23).genus() 12 - We calculate the dimensions of some modular forms spaces: :: + We calculate the dimensions of some modular forms spaces:: sage: GammaH(33,[2]).dimension_cusp_forms(2) 5 @@ -175,7 +177,7 @@ class GammaH_class(CongruenceSubgroup): sage: GammaH(32079, [21676]).dimension_cusp_forms(20) 180266112 - We can sometimes show that there are no weight 1 cusp forms: :: + We can sometimes show that there are no weight 1 cusp forms:: sage: GammaH(20, [9]).dimension_cusp_forms(1) 0 @@ -183,8 +185,9 @@ class GammaH_class(CongruenceSubgroup): def __init__(self, level, H, Hlist=None): r""" - The congruence subgroup `\Gamma_H(N)`. The subgroup H - must be input as a list. + The congruence subgroup `\Gamma_H(N)`. + + The subgroup `H` must be given as a list. EXAMPLES:: @@ -483,13 +486,16 @@ def _coset_reduction_data_first_coord(G): of the reduction step (the first coordinate). INPUT: - G -- a congruence subgroup Gamma_0(N), Gamma_1(N), or Gamma_H(N). + + G -- a congruence subgroup Gamma_0(N), Gamma_1(N), or Gamma_H(N). OUTPUT: - A list v such that - v[u] = (min(u*h: h in H), - gcd(u,N) , - an h such that h*u = min(u*h: h in H)). + + A list v such that + + v[u] = (min(u*h: h in H), + gcd(u,N) , + an h such that h*u = min(u*h: h in H)). EXAMPLES:: @@ -558,11 +564,13 @@ def _coset_reduction_data_second_coord(G): of the reduction step (the second coordinate). INPUT: - self + + self OUTPUT: - a dictionary v with keys the divisors of N such that v[d] - is the subgroup {h in H : h = 1 (mod N/d)}. + + a dictionary v with keys the divisors of N such that v[d] + is the subgroup {h in H : h = 1 (mod N/d)}. EXAMPLES:: @@ -624,19 +632,24 @@ def _reduce_coset(self, uu, vv): Compute a canonical form for a given Manin symbol. INPUT: + Two integers (uu,vv) that define an element of `(Z/NZ)^2`. - uu -- an integer - vv -- an integer + + - uu -- an integer + - vv -- an integer OUTPUT: - pair of integers that are equivalent to (uu,vv). - NOTE: We do *not* require that gcd(uu,vv,N) = 1. If the gcd is - not 1, we return (0,0). + pair of integers that are equivalent to (uu,vv). + + .. NOTE:: + + We do *not* require that gcd(uu,vv,N) = 1. If the gcd is + not 1, we return (0,0). EXAMPLES: - An example at level 9.:: + An example at level 9:: sage: G = GammaH(9,[7]); G Congruence Subgroup Gamma_H(9) with H generated by [7] @@ -735,6 +748,7 @@ def reduce_cusp(self, c): def _reduce_cusp(self, c): r""" Compute a minimal representative for the given cusp c. + Returns a pair (c', t), where c' is the minimal representative for the given cusp, and t is either 1 or -1, as explained below. Largely for internal use. @@ -745,9 +759,13 @@ def _reduce_cusp(self, c): Two cusps `u1/v1` and `u2/v2` are equivalent modulo `\Gamma_H(N)` if and only if - `v1 = h*v2 (mod N)` and `u1 = h^(-1)*u2 (mod gcd(v1,N))` + + - `v1 = h*v2 (mod N)` and `u1 = h^(-1)*u2 (mod gcd(v1,N))` + or - `v1 = -h*v2 (mod N)` and `u1 = -h^(-1)*u2 (mod gcd(v1,N))` + + - `v1 = -h*v2 (mod N)` and `u1 = -h^(-1)*u2 (mod gcd(v1,N))` + for some `h \in H`. Then t is 1 or -1 as c and c' fall into the first or second case, respectively. From 188832bf8db965f824f8b4c19feb5bd51a733957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 18 Oct 2015 15:28:45 +0200 Subject: [PATCH 1650/1872] hidden doc problem in modsym --- src/sage/modular/modsym/ambient.py | 18 +++++++----------- src/sage/modular/modsym/manin_symbol.pyx | 14 +++++++------- src/sage/modular/modsym/modular_symbols.py | 2 +- src/sage/modular/modsym/p1list.pyx | 4 ++-- src/sage/modular/modsym/space.py | 9 +++++---- 5 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 5ef072af57a..62937b5dc52 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -531,7 +531,7 @@ def _action_on_modular_symbols(self, g): INPUT: - ``g`` (list) -- `g=[a,b,c,d]` where `a,b,c,d` are integers + `g` (list) -- `g=[a,b,c,d]` where `a,b,c,d` are integers defining a `2\times2` integer matrix. OUTPUT: @@ -539,10 +539,10 @@ def _action_on_modular_symbols(self, g): (matrix) The matrix of the action of `g` on this Modular Symbol space, with respect to the standard basis. - .. note:: + .. NOTE:: - Use _matrix_of_operator_on_modular_symbols for more general - operators. + Use ``_matrix_of_operator_on_modular_symbols`` for more general + operators. EXAMPLES:: @@ -2898,19 +2898,15 @@ def boundary_space(self): def _hecke_image_of_ith_basis_vector(self, n, i): """ Return `T_n(e_i)`, where `e_i` is the - `i`th basis vector of this ambient space. + `i` th basis vector of this ambient space. INPUT: - - - ``n`` - an integer which should be prime. - + - ``n`` -- an integer which should be prime. OUTPUT: - - - ``modular symbol`` - element of this ambient space - + - ``modular symbol`` -- element of this ambient space EXAMPLES:: diff --git a/src/sage/modular/modsym/manin_symbol.pyx b/src/sage/modular/modsym/manin_symbol.pyx index 6e4e6351c8b..d4da00430ad 100644 --- a/src/sage/modular/modsym/manin_symbol.pyx +++ b/src/sage/modular/modsym/manin_symbol.pyx @@ -436,13 +436,13 @@ def _print_polypart(i, j): EXAMPLES:: - sage: from sage.modular.modsym.manin_symbol import _print_polypart - sage: _print_polypart(2,3) - 'X^2*Y^3' - sage: _print_polypart(2,0) - 'X^2' - sage: _print_polypart(0,1) - 'Y' + sage: from sage.modular.modsym.manin_symbol import _print_polypart + sage: _print_polypart(2,3) + 'X^2*Y^3' + sage: _print_polypart(2,0) + 'X^2' + sage: _print_polypart(0,1) + 'Y' """ if i > 1: xpart = "X^%s"%i diff --git a/src/sage/modular/modsym/modular_symbols.py b/src/sage/modular/modsym/modular_symbols.py index b13170bf0b4..96aec36e734 100644 --- a/src/sage/modular/modsym/modular_symbols.py +++ b/src/sage/modular/modsym/modular_symbols.py @@ -117,7 +117,7 @@ def __getitem__(self, j): return [self.__alpha, self.__beta][j] def _latex_(self): - """ + r""" Return Latex representation of this modular symbol. EXAMPLES:: diff --git a/src/sage/modular/modsym/p1list.pyx b/src/sage/modular/modsym/p1list.pyx index 1ab36b2a6b5..20acee773f0 100644 --- a/src/sage/modular/modsym/p1list.pyx +++ b/src/sage/modular/modsym/p1list.pyx @@ -764,8 +764,8 @@ cdef class P1List: return sage.modular.modsym.p1list._make_p1list, (self.__N, ) def __getitem__(self, n): - """ - Standard indexing/slicing function for the class P1List. + r""" + Standard indexing/slicing function for the class ``P1List``. EXAMPLES:: diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index 7bf69c3fa9d..b1a844a79e4 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -2318,15 +2318,16 @@ def _matrix_of_galois_action(self, t, P): INPUT: - - `t` -- integer - - `P` -- list of cusps + - `t` -- integer - EXAMPLES:: + - `P` -- list of cusps + + EXAMPLES: We compute the matrix of the element of the Galois group associated to 5 and 31 for level 32. In the first case the Galois action is trivial, and in the second it is - nontrivial.:: + nontrivial. :: sage: M = ModularSymbols(32) sage: P = [c for c in Gamma0(32).cusps() if not c.is_infinity()] From 6bc8a178025ea85403a8dbdcd5413f52cd7ccea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 18 Oct 2015 15:34:03 +0200 Subject: [PATCH 1651/1872] one more problem in modsym --- src/sage/modular/modsym/ambient.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 62937b5dc52..781eaf9342d 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -2787,7 +2787,7 @@ def _cuspidal_new_submodule_dimension_formula(self): r""" Return the dimension of the new cuspidal subspace, via the formula. - EXAMPLES: + EXAMPLES:: sage: M = ModularSymbols(100,2) sage: M._cuspidal_new_submodule_dimension_formula() From 92c23d04f2595b16680dca273708d2dc13ff874e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 18 Oct 2015 15:37:48 +0200 Subject: [PATCH 1652/1872] another problem in ambient.py --- src/sage/modular/modsym/ambient.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 781eaf9342d..d59a2e6475e 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -810,7 +810,7 @@ def modular_symbol_sum(self, x, check=True): The sum `\sum_{i=0}^{k-2} a_i [ i, \alpha, \beta ]` as an element of this modular symbol space. - EXAMPLES: + EXAMPLES:: sage: M = ModularSymbols(11,4) sage: R.=QQ[] @@ -3096,7 +3096,7 @@ def _cuspidal_new_submodule_dimension_formula(self): r""" Return the dimension of the new cuspidal subspace, via the formula. - EXAMPLES: + EXAMPLES:: sage: M = ModularSymbols(Gamma1(22),2) sage: M._cuspidal_new_submodule_dimension_formula() @@ -3803,16 +3803,13 @@ def _hecke_images(self, i, v): INPUT: + - ``i`` -- nonnegative integer - - ``i`` - nonnegative integer - - - ``v`` - a list of positive integer - + - ``v`` -- a list of positive integer OUTPUT: - - - ``matrix`` - whose rows are the Hecke images + - ``matrix`` -- whose rows are the Hecke images EXAMPLES:: @@ -3825,8 +3822,6 @@ def _hecke_images(self, i, v): [ 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0] [ 0 1 0 2 0 -1 1 1 0 0 0 0 0 0 0] [ 0 1 1 -1 -1 0 -1 1 1 0 1 2 0 -2 2] - - """ if self.weight() != 2: raise NotImplementedError("hecke images only implemented when the weight is 2") From 82c27990ede27ce86a70b6ee1056fcfd336c4138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Mon, 19 Oct 2015 00:09:01 +0300 Subject: [PATCH 1653/1872] Docstrings for functions comparing two element. --- src/sage/combinat/posets/posets.py | 139 ++++++++++++++--------------- 1 file changed, 69 insertions(+), 70 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index bd2afa2c60c..c7efac7f3fa 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -17,24 +17,24 @@ List of Poset methods --------------------- -**Comparing & intervals** +**Comparing & relations** .. csv-table:: :class: contentstable :widths: 30, 70 :delim: | - :meth:`~FinitePoset.is_greater_than` | Return ``True`` if `x` is greater than but not equal to `y` in the poset, and ``False`` otherwise. - :meth:`~FinitePoset.is_gequal` | Return ``True`` if `x` is greater than or equal to `y` in the poset, and ``False`` otherwise. - :meth:`~FinitePoset.is_less_than` | Return ``True`` if `x` is less than but not equal to `y` in the poset, and ``False`` otherwise. - :meth:`~FinitePoset.is_lequal` | Return ``True`` if `x` is less than or equal to `y` in the poset, and ``False`` otherwise. - :meth:`~FinitePoset.compare_elements` | Compares `x` and `y` in the poset. - :meth:`~FinitePoset.closed_interval` | Return a list of the elements `z` such that `x \le z \le y`. - :meth:`~FinitePoset.open_interval` | Return a list of the elements `z` such that `x < z < y`. - :meth:`~FinitePoset.intervals` | Return a list of all intervals of the poset. - :meth:`~FinitePoset.intervals_iterator` | Return an iterator for all the intervals of the poset. - :meth:`~FinitePoset.order_filter` | Return the order filter generated by a list of elements. - :meth:`~FinitePoset.order_ideal` | Return the order ideal generated by a list of elements. + :meth:`~FinitePoset.is_greater_than` | Return ``True`` if `x` is strictly greater than `y` in the poset. + :meth:`~FinitePoset.is_gequal` | Return ``True`` if `x` is greater than or equal to `y` in the poset. + :meth:`~FinitePoset.is_less_than` | Return ``True`` if `x` is strictly less than `y` in the poset. + :meth:`~FinitePoset.is_lequal` | Return ``True`` if `x` is less than or equal to `y` in the poset. + :meth:`~FinitePoset.compare_elements` | Compare two element the poset. + :meth:`~FinitePoset.closed_interval` | Return the list of elements in a closed interval of the poset. + :meth:`~FinitePoset.open_interval` | Return the list of elements in an open interval of the poset. + :meth:`~FinitePoset.relations` | Return the list of relations in the poset. + :meth:`~FinitePoset.relations_iterator` | Return an iterator over the relations in the poset. + :meth:`~FinitePoset.order_filter` | Return the upper set generated by elements. + :meth:`~FinitePoset.order_ideal` | Return the lower set generated by elements. **Covering** @@ -2058,49 +2058,51 @@ def is_incomparable_chain_free(self, m, n = None): def is_lequal(self, x, y): """ - Returns ``True`` if `x` is less than or equal to `y` in the poset, and + Return ``True`` if `x` is less than or equal to `y` in the poset, and ``False`` otherwise. EXAMPLES:: - sage: Q = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) - sage: x,y,z = Q(0),Q(1),Q(4) - sage: Q.is_lequal(x,y) - False - sage: Q.is_lequal(y,x) - False - sage: Q.is_lequal(x,z) - True - sage: Q.is_lequal(y,z) + sage: P = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) + sage: P.is_lequal(2, 4) True - sage: Q.is_lequal(z,z) + sage: P.is_lequal(2, 2) True + sage: P.is_lequal(0, 1) + False + sage: P.is_lequal(3, 2) + False + + .. SEEALSO:: :meth:`is_less_than`, :meth:`is_gequal`. """ i = self._element_to_vertex(x) j = self._element_to_vertex(y) - return (i == j or self._hasse_diagram.is_lequal(i, j)) + return (self._hasse_diagram.is_lequal(i, j)) le = is_lequal def is_less_than(self, x, y): """ - Returns ``True`` if `x` is less than but not equal to `y` in the poset, + Return ``True`` if `x` is less than but not equal to `y` in the poset, and ``False`` otherwise. EXAMPLES:: - sage: Q = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) - sage: x,y,z = Q(0),Q(1),Q(4) - sage: Q.is_less_than(x,y) + sage: P = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) + sage: P.is_less_than(1, 3) + True + sage: P.is_less_than(0, 1) False - sage: Q.is_less_than(y,x) + sage: P.is_less_than(2, 2) False - sage: Q.is_less_than(x,z) - True - sage: Q.is_less_than(y,z) - True - sage: Q.is_less_than(z,z) + + For non-facade posets also ``<`` works:: + + sage: P = Poset({3: [1, 2]}, facade=False) + sage: P(1) < P(2) False + + .. SEEALSO:: :meth:`is_lequal`, :meth:`is_greater_than`. """ i = self._element_to_vertex(x) j = self._element_to_vertex(y) @@ -2110,53 +2112,51 @@ def is_less_than(self, x, y): def is_gequal(self, x, y): """ - Returns ``True`` if `x` is greater than or equal to `y` in the poset, + Return ``True`` if `x` is greater than or equal to `y` in the poset, and ``False`` otherwise. EXAMPLES:: - sage: Q = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) - sage: x,y,z = Q(0),Q(1),Q(4) - sage: Q.is_gequal(x,y) - False - sage: Q.is_gequal(y,x) - False - sage: Q.is_gequal(x,z) - False - sage: Q.is_gequal(z,x) - True - sage: Q.is_gequal(z,y) + sage: P = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) + sage: P.is_gequal(3, 1) True - sage: Q.is_gequal(z,z) + sage: P.is_gequal(2, 2) True + sage: P.is_gequal(0, 1) + False + + .. SEEALSO:: :meth:`is_greater_than`, :meth:`is_lequal`. """ i = self._element_to_vertex(x) j = self._element_to_vertex(y) - return (i == j or self._hasse_diagram.is_lequal(j, i)) + return (self._hasse_diagram.is_lequal(j, i)) ge = is_gequal def is_greater_than(self, x, y): """ - Returns ``True`` if `x` is greater than but not equal to `y` in the + Return ``True`` if `x` is greater than but not equal to `y` in the poset, and ``False`` otherwise. EXAMPLES:: - sage: Q = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) - sage: x,y,z = Q(0),Q(1),Q(4) - sage: Q.is_greater_than(x,y) + sage: P = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) + sage: P.is_greater_than(3, 1) + True + sage: P.is_greater_than(1, 2) False - sage: Q.is_greater_than(y,x) + sage: P.is_greater_than(3, 3) False - sage: Q.is_greater_than(x,z) + sage: P.is_greater_than(0, 1) False - sage: Q.is_greater_than(z,x) - True - sage: Q.is_greater_than(z,y) + + For non-facade posets also ``>`` works:: + + sage: P = Poset({3: [1, 2]}, facade=False) + sage: P(2) > P(3) True - sage: Q.is_greater_than(z,z) - False + + .. SEEALSO:: :meth:`is_gequal`, :meth:`is_less_than`. """ i = self._element_to_vertex(x) j = self._element_to_vertex(y) @@ -2168,23 +2168,22 @@ def compare_elements(self, x, y): r""" Compare `x` and `y` in the poset. - If ``x`` = ``y``, then ``0`` is returned; - if ``x`` < ``y``, then ``-1`` is returned; - if ``x`` > ``y``, then ``1`` is returned; - and if ``x`` and ``y`` are not comparable, - then ``None`` is returned. + - If `x < y`, return ``-1``. + - If `x = y`, return ``0``. + - If `x > y`, return ``1``. + - If `x` and `y` are not comparable, return ``None``. EXAMPLES:: - sage: P = Poset([[1,2],[4],[3],[4],[]]) - sage: P.compare_elements(0,0) + sage: P = Poset([[1, 2], [4], [3], [4], []]) + sage: P.compare_elements(0, 0) 0 - sage: P.compare_elements(0,4) + sage: P.compare_elements(0, 4) -1 - sage: P.compare_elements(4,0) + sage: P.compare_elements(4, 0) 1 - sage: P.compare_elements(1,2) - + sage: P.compare_elements(1, 2) is None + True """ i, j = map(self._element_to_vertex, (x, y)) if i == j: From 9dcc412a4416aa7b8fad962b1d0f974f7460922a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Mon, 19 Oct 2015 00:17:00 +0300 Subject: [PATCH 1654/1872] A typo in the index. --- src/sage/combinat/posets/posets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index c7efac7f3fa..871e4396068 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -70,7 +70,7 @@ :meth:`~FinitePoset.is_connected` | Return ``True`` if the poset is connected, and ``False`` otherwise. :meth:`~FinitePoset.is_graded` | Return whether this poset is graded. :meth:`~FinitePoset.is_ranked` | Return whether this poset is ranked. - :meth:`~FinitePoset.is_ranked` | Return ``True`` if the poset is rank symmetric. + :meth:`~FinitePoset.is_rank_symmetric` | Return ``True`` if the poset is rank symmetric. :meth:`~FinitePoset.is_incomparable_chain_free` | Return whether the poset is `(m+n)`-free. :meth:`~FinitePoset.is_slender` | Return whether the poset ``self`` is slender or not. :meth:`~FinitePoset.is_join_semilattice` | Return ``True`` is the poset has a join operation, and False otherwise. From aea0eff7c7f5bce8ebf9d218a0df6c2c0575bd0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Mon, 19 Oct 2015 13:58:30 +0300 Subject: [PATCH 1655/1872] More polishing to docstrings. --- src/sage/combinat/posets/posets.py | 178 ++++++++++++++++++----------- 1 file changed, 111 insertions(+), 67 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 871e4396068..6537cd45e2c 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -17,22 +17,22 @@ List of Poset methods --------------------- -**Comparing & relations** +**Comparing, intervals and relations** .. csv-table:: :class: contentstable :widths: 30, 70 :delim: | - :meth:`~FinitePoset.is_greater_than` | Return ``True`` if `x` is strictly greater than `y` in the poset. - :meth:`~FinitePoset.is_gequal` | Return ``True`` if `x` is greater than or equal to `y` in the poset. :meth:`~FinitePoset.is_less_than` | Return ``True`` if `x` is strictly less than `y` in the poset. + :meth:`~FinitePoset.is_greater_than` | Return ``True`` if `x` is strictly greater than `y` in the poset. :meth:`~FinitePoset.is_lequal` | Return ``True`` if `x` is less than or equal to `y` in the poset. - :meth:`~FinitePoset.compare_elements` | Compare two element the poset. + :meth:`~FinitePoset.is_gequal` | Return ``True`` if `x` is greater than or equal to `y` in the poset. + :meth:`~FinitePoset.compare_elements` | Compare two element of the poset. :meth:`~FinitePoset.closed_interval` | Return the list of elements in a closed interval of the poset. :meth:`~FinitePoset.open_interval` | Return the list of elements in an open interval of the poset. :meth:`~FinitePoset.relations` | Return the list of relations in the poset. - :meth:`~FinitePoset.relations_iterator` | Return an iterator over the relations in the poset. + :meth:`~FinitePoset.relations_iterator` | Return an iterator over relations in the poset. :meth:`~FinitePoset.order_filter` | Return the upper set generated by elements. :meth:`~FinitePoset.order_ideal` | Return the lower set generated by elements. @@ -1820,52 +1820,54 @@ def cover_relations_iterator(self): def relations(self): r""" - Returns a list of all relations of the poset. + Return the list of all relations of the poset. - A relation is a pair of elements `x` and `y` such that `x\leq y` - in ``self``. + A relation is a pair of elements `x` and `y` such that `x \leq y` + in the poset. - Relations are also often called intervals. The number of - intervals is the dimension of the incidence algebra. + The number of relations is the dimension of the incidence + algebra. OUTPUT: A list of pairs (each pair is a list), where the first element of the pair is less than or equal to the second element. - Pairs are produced in a rough sort of lexicographic order, - where earlier elements are from lower levels of the poset. - .. SEEALSO:: :meth:`relations_number`, :meth:`relations_iterator` EXAMPLES:: - sage: Q = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) - sage: Q.relations() + sage: P = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) + sage: P.relations() [[1, 1], [1, 2], [1, 3], [1, 4], [0, 0], [0, 2], [0, 3], [0, 4], [2, 2], [2, 3], [2, 4], [3, 3], [3, 4], [4, 4]] + TESTS:: + + sage: P = Poset() # Test empty poset + sage: P.relations() + [] + AUTHOR: - Rob Beezer (2011-05-04) """ return list(self.relations_iterator()) + intervals = deprecated_function_alias(19360, relations) + def relations_iterator(self, strict=False): r""" - Returns an iterator for all the relations of the poset. - - A relation is a pair of elements `x` and `y` such that `x\leq y` - in ``self``. + Return an iterator for all the relations of the poset. - Relations are also often called intervals. The number of - intervals is the dimension of the incidence algebra. + A relation is a pair of elements `x` and `y` such that `x \leq y` + in the poset. INPUT: - - ``strict`` -- boolean (default ``False``) if ``True``, returns + - ``strict`` -- a boolean (default ``False``) if ``True``, returns an iterator over relations `x < y`, excluding all relations `x \leq x`. @@ -1876,25 +1878,21 @@ def relations_iterator(self, strict=False): .. SEEALSO:: - :meth:`relations_number`, :meth:`relations`, - :meth:`maximal_chains`, :meth:`chains` + :meth:`relations_number`, :meth:`relations`. EXAMPLES:: - sage: Q = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) - sage: type(Q.relations_iterator()) + sage: P = Poset({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) + sage: it = P.relations_iterator() + sage: type(it) - sage: [z for z in Q.relations_iterator()] - [[1, 1], [1, 2], [1, 3], [1, 4], [0, 0], [0, 2], [0, 3], - [0, 4], [2, 2], [2, 3], [2, 4], [3, 3], [3, 4], [4, 4]] + sage: it.next(), it.next() + ([1, 1], [1, 2]) sage: P = posets.PentagonPoset() sage: list(P.relations_iterator(strict=True)) [[0, 1], [0, 2], [0, 4], [0, 3], [1, 4], [2, 3], [2, 4], [3, 4]] - sage: len(list(P.relations_iterator())) - 13 - AUTHOR: - Rob Beezer (2011-05-04) @@ -1911,6 +1909,8 @@ def relations_iterator(self, strict=False): for j in hd.breadth_first_search(i): yield [elements[i], elements[j]] + intervals_iterator = deprecated_function_alias(19360, relations_iterator) + def relations_number(self): """ Return the number of relations in the poset. @@ -1942,10 +1942,8 @@ def relations_number(self): """ return sum(1 for x in self.relations_iterator()) - # three useful aliases - intervals = relations + # Maybe this should also be deprecated. intervals_number = relations_number - intervals_iterator = relations_iterator def is_incomparable_chain_free(self, m, n = None): r""" @@ -4288,17 +4286,31 @@ def random_order_ideal(self, direction='down'): def order_filter(self,elements): """ - Returns the order filter generated by the elements of an + Return the order filter generated by the elements of an iterable ``elements``. `I` is an order filter if, for any `x` in `I` and `y` such that - `y \ge x`, then `y` is in `I`. + `y \ge x`, then `y` is in `I`. This is also called upper set or + upset. EXAMPLES:: - sage: B = Posets.BooleanLattice(4) - sage: B.order_filter([3,8]) - [3, 7, 8, 9, 10, 11, 12, 13, 14, 15] + sage: P = Poset((divisors(1000), attrcall("divides"))) + sage: P.order_filter([20, 25]) + [20, 40, 25, 50, 100, 200, 125, 250, 500, 1000] + + .. SEEALSO:: + + :meth:`order_ideal`, :meth:`~sage.categories.posets.Posets.ParentMethods.principal_order_filter`. + + TESTS:: + + sage: P = Poset() # Test empty poset + sage: P.order_filter([]) + [] + sage: C = Posets.ChainPoset(5) + sage: C.order_filter([]) + [] """ vertices = sorted(map(self._element_to_vertex,elements)) of = self._hasse_diagram.order_filter(vertices) @@ -4306,19 +4318,31 @@ def order_filter(self,elements): def order_ideal(self,elements): """ - Returns the order ideal generated by the elements of an + Return the order ideal generated by the elements of an iterable ``elements``. `I` is an order ideal if, for any `x` in `I` and `y` such that - `y \le x`, then `y` is in `I`. + `y \le x`, then `y` is in `I`. This is also called lower set or + downset. EXAMPLES:: - sage: B = Posets.BooleanLattice(4) - sage: B.order_ideal([7,10]) - [0, 1, 2, 3, 4, 5, 6, 7, 8, 10] - sage: B.order_ideal(iter(range(4, 9))) - [0, 1, 2, 3, 4, 5, 6, 7, 8] + sage: P = Poset((divisors(1000), attrcall("divides"))) + sage: P.order_ideal([20, 25]) + [1, 2, 4, 5, 10, 20, 25] + + .. SEEALSO:: + + :meth:`order_filter`, :meth:`~sage.categories.posets.Posets.ParentMethods.principal_order_ideal`. + + TESTS:: + + sage: P = Poset() # Test empty poset + sage: P.order_ideal([]) + [] + sage: C = Posets.ChainPoset(5) + sage: C.order_ideal([]) + [] """ vertices = [self._element_to_vertex(_) for _ in elements] oi = self._hasse_diagram.order_ideal(vertices) @@ -4355,38 +4379,58 @@ def interval(self, x, y): def closed_interval(self, x, y): """ - Return a list of the elements `z` such that `x \le z \le y`. + Return the list of elements `z` such that `x \le z \le y` in the poset. EXAMPLES:: - sage: uc = [[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]] - sage: dag = DiGraph(dict(zip(range(len(uc)),uc))) - sage: P = Poset(dag) - sage: I = set(map(P,[2,5,6,4,7])) - sage: I == set(P.closed_interval(2,7)) - True + sage: P = Poset((divisors(1000), attrcall("divides"))) + sage: P.closed_interval(2, 100) + [2, 4, 10, 20, 50, 100] + + .. SEEALSO:: + + :meth:`open_interval` + + TESTS:: + + sage: C = Posets.ChainPoset(10) + sage: C.closed_interval(3, 3) + [3] + sage: C.closed_interval(8, 5) + [] + sage: A = Posets.AntichainPoset(10) + sage: A.closed_interval(3, 7) + [] """ - return self.interval(x,y) + return [self._vertex_to_element(_) for _ in self._hasse_diagram.interval( + self._element_to_vertex(x),self._element_to_vertex(y))] def open_interval(self, x, y): """ - Return a list of the elements `z` such that `x < z < y`. + Return the list of elements `z` such that `x < z < y` in the poset. EXAMPLES:: - sage: uc = [[1,3,2],[4],[4,5,6],[6],[7],[7],[7],[]] - sage: dag = DiGraph(dict(zip(range(len(uc)),uc))) - sage: P = Poset(dag) - sage: I = set(map(P,[5,6,4])) - sage: I == set(P.open_interval(2,7)) - True + sage: P = Poset((divisors(1000), attrcall("divides"))) + sage: P.open_interval(2, 100) + [4, 10, 20, 50] - :: + .. SEEALSO:: - sage: dg = DiGraph({"a":["b","c"], "b":["d"], "c":["d"]}) - sage: P = Poset(dg, facade = False) - sage: P.open_interval("a","d") - [b, c] + :meth:`closed_interval` + + TESTS:: + + sage: C = Posets.ChainPoset(10) + sage: C.open_interval(3, 3) + [] + sage: C.open_interval(3, 4) + [] + sage: C.open_interval(7, 3) + [] + sage: A = Posets.AntichainPoset(10) + sage: A.open_interval(3, 7) + [] """ return [self._vertex_to_element(_) for _ in self._hasse_diagram.open_interval( self._element_to_vertex(x),self._element_to_vertex(y))] From 3cc556da45d5540a3cfb7536777102548ba5edca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Mon, 19 Oct 2015 16:58:55 +0300 Subject: [PATCH 1656/1872] Change one .intervals() to .relations(). --- src/sage/combinat/posets/incidence_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/incidence_algebras.py b/src/sage/combinat/posets/incidence_algebras.py index 51525c96168..c9bde6b2a93 100644 --- a/src/sage/combinat/posets/incidence_algebras.py +++ b/src/sage/combinat/posets/incidence_algebras.py @@ -69,7 +69,7 @@ def __init__(self, R, P, prefix='I'): if P in FiniteEnumeratedSets(): cat = cat.FiniteDimensional() self._poset = P - CombinatorialFreeModule.__init__(self, R, map(tuple, P.intervals()), + CombinatorialFreeModule.__init__(self, R, map(tuple, P.relations()), prefix=prefix, category=cat) def _repr_term(self, A): From f6fdd7ddad7fdbef37e7632d628f432891e76acc Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 19 Oct 2015 11:36:38 -0500 Subject: [PATCH 1657/1872] Some last little bit of cleanup. --- src/sage/categories/manifolds.py | 6 ++---- src/sage/categories/metric_spaces.py | 3 +-- src/sage/categories/topological_spaces.py | 2 -- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index 972ca4cedfe..4a6433b95ec 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -10,8 +10,6 @@ from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method -from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.lazy_import import LazyImport from sage.categories.category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.sets_cat import Sets @@ -67,8 +65,8 @@ def additional_structure(self): Return ``None``. Indeed, the category of manifolds defines no new - structure: a morphism of metric spaces between manifolds - is a manifold morphism. + structure: a morphism of topological spaces between + manifolds is a manifold morphism. .. SEEALSO:: :meth:`Category.additional_structure` diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index 89788f7e83c..c22ef8008db 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -8,7 +8,6 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.categories.category import Category from sage.categories.category_with_axiom import CategoryWithAxiom @@ -47,7 +46,7 @@ def default_super_categories(cls, category): Consider ``category=Groups()``. Then, a group `G` with a metric is simultaneously a topological group by itself, and a - topogological space:: + metric space:: sage: Groups().Metric().super_categories() [Category of topological groups, Category of metric spaces] diff --git a/src/sage/categories/topological_spaces.py b/src/sage/categories/topological_spaces.py index f279509fb5b..41f98e0decc 100644 --- a/src/sage/categories/topological_spaces.py +++ b/src/sage/categories/topological_spaces.py @@ -9,8 +9,6 @@ #****************************************************************************** from sage.misc.cachefunc import cached_method -from sage.misc.lazy_attribute import lazy_class_attribute -from sage.categories.category import Category from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory from sage.categories.sets_cat import Sets From 55ae3f23a027b4decd37ddc9d3d96a1aec00d15c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 19:54:55 +0200 Subject: [PATCH 1658/1872] function transform_category --- src/sage/rings/asymptotic/misc.py | 125 ++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index e69fdd4d9e4..b1d49bf63b4 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -529,3 +529,128 @@ def log_string(element, base=None): """ basestr = ', base=' + str(base) if base else '' return 'log(%s%s)' % (element, basestr) + + +def transform_category(category, + subcategory_mapping, axiom_mapping, + initial_category=None): + r""" + Transform ``category`` to a new category according to the given + mappings. + + INPUT: + + - ``category`` -- a category. + + - ``subcategory_mapping`` -- a list (or other iterable) of triples + ``(from, to, mandatory)``, where + + - ``from`` and ``to`` are categories and + - ``mandatory`` is a boolean. + + - ``axiom_mapping`` -- a list (or other iterable) of triples + ``(from, to, mandatory)``, where + + - ``from`` and ``to`` are strings describing axioms and + - ``mandatory`` is a boolean. + + OUTPUT: + + A category. + + .. NOTE:: + + Consider a subcategory mapping ``(from, to, mandatory)``. If + ``category`` is a subcategory of ``from``, then the + returned category will be a subcategory of ``to``. Otherwise and + if ``mandatory`` is set, then an error is raised. + + Consider an axiom mapping ``(from, to, mandatory)``. If + ``category`` is has axiom ``from``, then the + returned category will have axiom ``to``. Otherwise and + if ``mandatory`` is set, then an error is raised. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.misc import transform_category + sage: from sage.categories.additive_semigroups import AdditiveSemigroups + sage: from sage.categories.additive_monoids import AdditiveMonoids + sage: from sage.categories.additive_groups import AdditiveGroups + sage: S = [ + ....: (Sets(), Sets(), True), + ....: (Posets(), Posets(), False), + ....: (AdditiveMagmas(), Magmas(), False)] + sage: A = [ + ....: ('AdditiveAssociative', 'Associative', False), + ....: ('AdditiveUnital', 'Unital', False), + ....: ('AdditiveInverse', 'Inverse', False), + ....: ('AdditiveCommutative', 'Commutative', False)] + sage: transform_category(Objects(), S, A) + Traceback (most recent call last): + ... + ValueError: Category of objects is not + a subcategory of Category of sets. + sage: transform_category(Sets(), S, A) + Category of sets + sage: transform_category(Posets(), S, A) + Category of posets + sage: transform_category(AdditiveSemigroups(), S, A) + Category of semigroups + sage: transform_category(AdditiveMonoids(), S, A) + Category of monoids + sage: transform_category(AdditiveGroups(), S, A) + Category of groups + sage: transform_category(AdditiveGroups().AdditiveCommutative(), S, A) + Category of commutative groups + + :: + + sage: transform_category(AdditiveGroups().AdditiveCommutative(), S, A, + ....: initial_category=Posets()) + Join of Category of commutative groups + and Category of posets + + :: + + sage: transform_category(ZZ.category(), S, A) + Category of commutative groups + sage: transform_category(QQ.category(), S, A) + Category of commutative groups + sage: transform_category(SR.category(), S, A) + Category of commutative groups + sage: transform_category(Fields(), S, A) + Category of commutative groups + sage: transform_category(ZZ['t'].category(), S, A) + Category of commutative groups + + :: + + sage: A[-1] = ('Commutative', 'AdditiveCommutative', True) + sage: transform_category(Groups(), S, A) + Traceback (most recent call last): + ... + ValueError: Category of groups does not have + axiom Commutative. + """ + if initial_category is None: + from sage.categories.objects import Objects + result = Objects() + else: + result = initial_category + + for A, B, mandatory in subcategory_mapping: + if category.is_subcategory(A): + result &= B + elif mandatory: + raise ValueError('%s is not a subcategory of %s.' % + (category, A)) + + axioms = category.axioms() + for A, B, mandatory in axiom_mapping: + if A in axioms: + result = result._with_axiom(B) + elif mandatory: + raise ValueError('%s does not have axiom %s.' % + (category, A)) + + return result From 2b331ed2ed0f59eb6650db5bb8ccb0fa6eb45500 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 19:56:34 +0200 Subject: [PATCH 1659/1872] use new transform_category in classcall to determine the category --- src/sage/rings/asymptotic/growth_group.py | 79 +++++++++++++++++++++-- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 19ea74e9aad..accfe0e2a84 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1357,6 +1357,19 @@ class GenericGrowthGroup( Element = GenericGrowthElement + # set everything up to determine category + from sage.categories.sets_cat import Sets + from sage.categories.posets import Posets + from sage.categories.magmas import Magmas + from sage.categories.additive_magmas import AdditiveMagmas + + _determine_category_subcategory_mapping_ = [ + (Sets(), Sets(), True), + (Posets(), Posets(), False)] + + _determine_category_axiom_mapping_ = [] + + @staticmethod def __classcall__(cls, base, var=None, category=None, ignore_variables=None): r""" @@ -1395,7 +1408,25 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): elif not isinstance(var, Variable): var = Variable(var, ignore=ignore_variables) - category = cls._determine_category_(category, base) + from sage.categories.posets import Posets + if category is None: + # The following block can be removed once #19269 is fixed. + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ + from sage.rings.polynomial.polynomial_ring import is_PolynomialRing + if base is ZZ or base is QQ or \ + is_PolynomialRing(base) and \ + (base.base_ring() is ZZ or base.base_ring() is QQ): + initial_category = Posets() + else: + initial_category = None + + from misc import transform_category + category = transform_category( + base.category(), + cls._determine_category_subcategory_mapping_, + cls._determine_category_axiom_mapping_, + initial_category=initial_category) return super(GenericGrowthGroup, cls).__classcall__( cls, base, var, category) @@ -1426,7 +1457,7 @@ def _determine_category_(category, base): sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup sage: GenericGrowthGroup(ZZ, 'x').category() # indirect doctest - Join of Category of monoids and Category of posets + Category of posets sage: GenericGrowthGroup(ZZ, 'x', category=Groups()).category() # indirect doctest Category of groups """ @@ -1448,7 +1479,7 @@ def __init__(self, base, var, category): sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup sage: GenericGrowthGroup(ZZ).category() - Join of Category of monoids and Category of posets + Category of posets :: @@ -2713,6 +2744,24 @@ class MonomialGrowthGroup(GenericGrowthGroup): Element = MonomialGrowthElement + # set everything up to determine category + from sage.categories.sets_cat import Sets + from sage.categories.posets import Posets + from sage.categories.magmas import Magmas + from sage.categories.additive_magmas import AdditiveMagmas + + _determine_category_subcategory_mapping_ = [ + (Sets(), Sets(), True), + (Posets(), Posets(), False), + (AdditiveMagmas(), Magmas(), False)] + + _determine_category_axiom_mapping_ = [ + ('AdditiveAssociative', 'Associative', False), + ('AdditiveUnital', 'Unital', False), + ('AdditiveInverse', 'Inverse', False), + ('AdditiveCommutative', 'Commutative', False)] + + @staticmethod def _determine_category_(category, base): r""" @@ -2745,7 +2794,7 @@ def _determine_category_(category, base): sage: W.category() Category of sets sage: MonomialGrowthGroup(W, 'x').category() # indirect doctest - Join of Category of monoids and Category of posets + Category of sets """ if category is not None: return category @@ -3360,6 +3409,26 @@ class ExponentialGrowthGroup(GenericGrowthGroup): Element = ExponentialGrowthElement + # set everything up to determine category + from sage.categories.sets_cat import Sets + from sage.categories.posets import Posets + from sage.categories.magmas import Magmas + from sage.categories.groups import Groups + from sage.categories.division_rings import DivisionRings + + _determine_category_subcategory_mapping_ = [ + (Sets(), Sets(), True), + (Posets(), Posets(), False), + (Magmas(), Magmas(), False), + (DivisionRings(), Groups(), False)] + + _determine_category_axiom_mapping_ = [ + ('Associative', 'Associative', False), + ('Unital', 'Unital', False), + ('Inverse', 'Inverse', False), + ('Commutative', 'Commutative', False)] + + @staticmethod def _determine_category_(category, base): r""" @@ -3385,7 +3454,7 @@ def _determine_category_(category, base): sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup sage: ExponentialGrowthGroup(ZZ, 'x').category() # indirect doctest - Join of Category of monoids and Category of posets + Join of Category of commutative monoids and Category of posets sage: ExponentialGrowthGroup(QQ, 'x').category() # indirect doctest Join of Category of commutative groups and Category of posets sage: ExponentialGrowthGroup(ZZ, 'x', category=Groups()).category() # indirect doctest From fbcec57ad74924fc76984af1dca24c6e05f69a1b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 20:00:20 +0200 Subject: [PATCH 1660/1872] delete _determine_category_ methods and move doctests to __classcall__ --- src/sage/rings/asymptotic/growth_group.py | 172 +++++----------------- 1 file changed, 33 insertions(+), 139 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index accfe0e2a84..033060a7a8a 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1399,6 +1399,39 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): sage: L2 = MonomialGrowthGroup(QQ, 'log(x)') sage: L1 is L2 True + + Test determining of the category (GenericGrowthGroup):: + + sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup + sage: GenericGrowthGroup(ZZ, 'x').category() # indirect doctest + Category of posets + sage: GenericGrowthGroup(ZZ, 'x', category=Groups()).category() # indirect doctest + Category of groups + + Test determining of the category (MonomialGrowthGroup):: + + sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup + sage: MonomialGrowthGroup(ZZ, 'x').category() # indirect doctest + Join of Category of commutative groups and Category of posets + sage: MonomialGrowthGroup(ZZ, 'x', category=Monoids()).category() # indirect doctest + Category of monoids + sage: W = Words([0, 1]) + sage: W.category() + Category of sets + sage: MonomialGrowthGroup(W, 'x').category() # indirect doctest + Category of sets + + Test determining of the category (ExponentialGrowthGroup):: + + sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup + sage: ExponentialGrowthGroup(ZZ, 'x').category() # indirect doctest + Join of Category of commutative monoids and Category of posets + sage: ExponentialGrowthGroup(QQ, 'x').category() # indirect doctest + Join of Category of commutative groups and Category of posets + sage: ExponentialGrowthGroup(ZZ, 'x', category=Groups()).category() # indirect doctest + Category of groups + sage: ExponentialGrowthGroup(QQ, 'x', category=Monoids()).category() # indirect doctest + Category of monoids """ if not isinstance(base, sage.structure.parent.Parent): raise TypeError('%s is not a valid base.' % (base,)) @@ -1432,44 +1465,6 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): cls, base, var, category) - @staticmethod - def _determine_category_(category, base): - r""" - Return the category of this generic growth group. - - INPUT: - - - ``category`` -- a category or ``None``. - - - ``base`` -- the parent. - - OUTPUT: - - A category. - - .. NOTE:: - - If the input category is not ``None``, then this category - is returned. Otherwise the join category of monoids and posets - is returned. - - TESTS:: - - sage: from sage.rings.asymptotic.growth_group import GenericGrowthGroup - sage: GenericGrowthGroup(ZZ, 'x').category() # indirect doctest - Category of posets - sage: GenericGrowthGroup(ZZ, 'x', category=Groups()).category() # indirect doctest - Category of groups - """ - if category is not None: - return category - - from sage.categories.monoids import Monoids - from sage.categories.posets import Posets - - return Monoids() & Posets() - - @sage.misc.superseded.experimental(trac_number=17601) def __init__(self, base, var, category): r""" @@ -2762,57 +2757,6 @@ class MonomialGrowthGroup(GenericGrowthGroup): ('AdditiveCommutative', 'Commutative', False)] - @staticmethod - def _determine_category_(category, base): - r""" - Return the category of this monomial growth group. - - INPUT: - - - ``category`` -- a category or ``None``. - - - ``base`` -- the parent. - - OUTPUT: - - A category. - - .. NOTE:: - - If the input category is not ``None``, then this category - is returned. Otherwise the category is determined from - the given base. - - TESTS:: - - sage: from sage.rings.asymptotic.growth_group import MonomialGrowthGroup - sage: MonomialGrowthGroup(ZZ, 'x').category() # indirect doctest - Join of Category of commutative groups and Category of posets - sage: MonomialGrowthGroup(ZZ, 'x', category=Monoids()).category() # indirect doctest - Category of monoids - sage: W = Words([0, 1]) - sage: W.category() - Category of sets - sage: MonomialGrowthGroup(W, 'x').category() # indirect doctest - Category of sets - """ - if category is not None: - return category - - from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups - from sage.categories.groups import Groups - from sage.categories.monoids import Monoids - from sage.categories.posets import Posets - - C = base.category() - if C.is_subcategory(CommutativeAdditiveGroups()): - category = Groups().Commutative() - else: - category = Monoids() - - return category & Posets() - - def _repr_short_(self): r""" A short representation string of this monomial growth group. @@ -3429,56 +3373,6 @@ class ExponentialGrowthGroup(GenericGrowthGroup): ('Commutative', 'Commutative', False)] - @staticmethod - def _determine_category_(category, base): - r""" - Return the category of this exponential growth group. - - INPUT: - - - ``category`` -- a category or ``None``. - - - ``base`` -- the parent. - - OUTPUT: - - A category. - - .. NOTE:: - - If the input category is not ``None``, then this category - is returned. Otherwise the category is determined from - the given base. - - TESTS:: - - sage: from sage.rings.asymptotic.growth_group import ExponentialGrowthGroup - sage: ExponentialGrowthGroup(ZZ, 'x').category() # indirect doctest - Join of Category of commutative monoids and Category of posets - sage: ExponentialGrowthGroup(QQ, 'x').category() # indirect doctest - Join of Category of commutative groups and Category of posets - sage: ExponentialGrowthGroup(ZZ, 'x', category=Groups()).category() # indirect doctest - Category of groups - sage: ExponentialGrowthGroup(QQ, 'x', category=Monoids()).category() # indirect doctest - Category of monoids - """ - if category is not None: - return category - - from sage.categories.fields import Fields - from sage.categories.groups import Groups - from sage.categories.monoids import Monoids - from sage.categories.posets import Posets - - C = base.category() - if C.is_subcategory(Fields()) or C.is_subcategory(Groups().Commutative()): - category = Groups().Commutative() - else: - category = Monoids() - - return category & Posets() - - def _repr_short_(self): r""" A short representation string of this exponential growth group. From 5fa9df874837162afba6446fb3e8553616d2d5e6 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 20:03:27 +0200 Subject: [PATCH 1661/1872] add one blank for consistency --- src/sage/rings/asymptotic/growth_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 033060a7a8a..a5fe4b99f1f 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1418,7 +1418,7 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): sage: W = Words([0, 1]) sage: W.category() Category of sets - sage: MonomialGrowthGroup(W, 'x').category() # indirect doctest + sage: MonomialGrowthGroup(W, 'x').category() # indirect doctest Category of sets Test determining of the category (ExponentialGrowthGroup):: From 09eeb38e95b54000a303f4777643e644d5e90e3e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 20:20:57 +0200 Subject: [PATCH 1662/1872] implement some_elements of exponential growth group This has to be done since we have to skip a possible element 0 --- src/sage/rings/asymptotic/growth_group.py | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index a5fe4b99f1f..689e7fb78fb 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3505,6 +3505,31 @@ def _convert_(self, data): return self.base().one() + def some_elements(self): + r""" + Return some elements of this exponential growth group. + + See :class:`TestSuite` for a typical use case. + + INPUT: + + Nothing. + + OUTPUT: + + An iterator. + + EXAMPLES:: + + sage: from sage.rings.asymptotic.growth_group import GrowthGroup + sage: tuple(GrowthGroup('QQ^z').some_elements()) + ((1/2)^z, (-1/2)^z, 2^z, (-2)^z, 1, (-1)^z, + 42^z, (2/3)^z, (-2/3)^z, (3/2)^z, (-3/2)^z, ...) + """ + return iter(self.element_class(self, e) + for e in self.base().some_elements() if e != 0) + + def gens(self): r""" Return a tuple of all generators of this exponential growth From 3d3c96a75dcec49bc74f97f3f7e470d2bbabb401 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 20:21:10 +0200 Subject: [PATCH 1663/1872] fix doctests: inverse is now tested --- src/sage/rings/asymptotic/growth_group.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 689e7fb78fb..44d10d90890 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -3721,6 +3721,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): running ._test_elements_eq_transitive() . . . pass running ._test_elements_neq() . . . pass running ._test_eq() . . . pass + running ._test_inverse() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_one() . . . pass running ._test_pickling() . . . pass @@ -3746,6 +3747,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): running ._test_elements_eq_transitive() . . . pass running ._test_elements_neq() . . . pass running ._test_eq() . . . pass + running ._test_inverse() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_one() . . . pass running ._test_pickling() . . . pass @@ -3771,6 +3773,7 @@ class GrowthGroupFactory(sage.structure.factory.UniqueFactory): running ._test_elements_eq_transitive() . . . pass running ._test_elements_neq() . . . pass running ._test_eq() . . . pass + running ._test_inverse() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_one() . . . pass running ._test_pickling() . . . pass From 3dc986d64c61aca5c1ed3562ae9125012e811e57 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 20:23:01 +0200 Subject: [PATCH 1664/1872] fix doctest some_elements in cartesian product --- src/sage/rings/asymptotic/growth_group_cartesian.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 6cf2c514d28..dfc6c202a1a 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -332,12 +332,12 @@ def some_elements(self): x^(-1/2)*log(x)*(-1/2)^y, x^2*log(x)^(-1)*2^y, x^(-2)*log(x)^2*(-2)^y, - log(x)^(-2)*0^y, - x*log(x)^3, - x^(-1)*log(x)^(-3)*(-1)^y, - x^42*log(x)^4*42^y, - x^(2/3)*log(x)^(-4)*(2/3)^y, - x^(-2/3)*log(x)^5*(-2/3)^y) + log(x)^(-2), + x*log(x)^3*(-1)^y, + x^(-1)*log(x)^(-3)*42^y, + x^42*log(x)^4*(2/3)^y, + x^(2/3)*log(x)^(-4)*(-2/3)^y, + x^(-2/3)*log(x)^5*(3/2)^y) """ from itertools import izip return iter( From 6a6efc41e89adc6d16a8e9c4f348b4ab2e076099 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 20:44:39 +0200 Subject: [PATCH 1665/1872] introduce parameter R in .symbolic_expression --- src/sage/rings/asymptotic/asymptotic_ring.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 770e9dd5978..38c05eb7677 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2032,10 +2032,16 @@ def _substitute_(self, rules): substitute_raise_exception(self, e) - def symbolic_expression(self): + def symbolic_expression(self, R=None): r""" Return this asymptotic expansion as a symbolic expression. + INPUT: + + - ``R`` -- (a subring of) the symbolic ring or ``None``. + The output is will be an element of ``R``. If ``None``, + then the symbolic ring is used. + OUTPUT: A symbolic expression. @@ -2058,10 +2064,14 @@ def symbolic_expression(self): sage: _.parent() Symbolic Ring """ - from sage.symbolic.ring import SR - return self.substitute(dict((g, SR.var(str(g))) + if R is None: + from sage.symbolic.ring import SR + R = SR + + return self.substitute(dict((g, R.var(str(g))) for g in self.parent().gens()), - domain=SR) + domain=R) + class AsymptoticRing(Algebra, UniqueRepresentation): From f39b94226944f107bb11b91483949406be75ecd5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 20:44:54 +0200 Subject: [PATCH 1666/1872] simplify SR._element_constructor --- src/sage/rings/asymptotic/asymptotic_ring.py | 2 ++ src/sage/symbolic/ring.pyx | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 38c05eb7677..8f988d8fbed 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2073,6 +2073,8 @@ def symbolic_expression(self, R=None): domain=R) + _symbolic_ = symbolic_expression # will be used by SR._element_constructor_ + class AsymptoticRing(Algebra, UniqueRepresentation): r""" diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 67c72e5a8fb..a7c4bb57f4f 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -299,7 +299,6 @@ cdef class SymbolicRing(CommutativeRing): from sage.rings.infinity import (infinity, minus_infinity, unsigned_infinity) - from sage.rings.asymptotic.asymptotic_ring import AsymptoticExpansion from sage.structure.factorization import Factorization if isinstance(x, (Integer, RealNumber, float, long, complex)): @@ -312,8 +311,6 @@ cdef class SymbolicRing(CommutativeRing): return new_Expression_from_GEx(self, g_mInfinity) elif x is unsigned_infinity: return new_Expression_from_GEx(self, g_UnsignedInfinity) - elif isinstance(x, AsymptoticExpansion): - return x.symbolic_expression() elif isinstance(x, (RingElement, Matrix)): GEx_construct_pyobject(exp, x) elif isinstance(x, Factorization): From 5c3cba330f79abf2864651d38e4545e1246ac9ad Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 21:17:20 +0200 Subject: [PATCH 1667/1872] fix checks whether parent is SR to check if instance of SymbolicRing --- src/sage/rings/asymptotic/asymptotic_ring.py | 4 ++-- src/sage/rings/asymptotic/growth_group.py | 12 ++++++------ src/sage/rings/asymptotic/term_monoid.py | 8 +++++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 8f988d8fbed..21b4eb71809 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2653,12 +2653,12 @@ def _element_constructor_(self, data, simplify=True, convert=True): return self.create_summand('exact', data) from misc import combine_exceptions - from sage.symbolic.ring import SR + from sage.symbolic.ring import SymbolicRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring_generic import is_MPolynomialRing from sage.rings.power_series_ring import is_PowerSeriesRing - if P is SR: + if isinstance(P, SymbolicRing): from sage.symbolic.operators import add_vararg if data.operator() == add_vararg: summands = [] diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index d46eff7a492..b8d453817da 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -2910,13 +2910,13 @@ def _convert_(self, data): from sage.symbolic.ring import SR return self._convert_(SR(data)) - from sage.symbolic.ring import SR + from sage.symbolic.ring import SymbolicRing from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from sage.rings.polynomial.multi_polynomial_ring_generic import \ MPolynomialRing_generic from sage.rings.power_series_ring import PowerSeriesRing_generic import operator - if P is SR: + if isinstance(P, SymbolicRing): if data.operator() == operator.pow: base, exponent = data.operands() if str(base) == var: @@ -3504,17 +3504,17 @@ def _convert_(self, data): else: return # end of parsing - from sage.symbolic.ring import SR + from sage.symbolic.ring import SymbolicRing import operator from sage.symbolic.operators import mul_vararg - if P is SR: + if isinstance(P, SymbolicRing): op = data.operator() if op == operator.pow: base, exponent = data.operands() if str(exponent) == var: return base elif exponent.operator() == mul_vararg: - return base ** (exponent / SR(var)) + return base ** (exponent / P(var)) elif isinstance(op, sage.functions.log.Function_exp): from sage.functions.log import exp base = exp(1) @@ -3522,7 +3522,7 @@ def _convert_(self, data): if str(exponent) == var: return base elif exponent.operator() == mul_vararg: - return base ** (exponent / SR(var)) + return base ** (exponent / P(var)) def gens(self): diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index e620bc5e096..9e0c6280830 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1843,8 +1843,8 @@ def _get_factors_(self, data): except AttributeError: return (data,) - from sage.symbolic.ring import SR - if P is SR: + from sage.symbolic.ring import SymbolicRing + if isinstance(P, SymbolicRing): from sage.symbolic.operators import mul_vararg if data.operator() == mul_vararg: return tuple(data.operands()) @@ -2340,10 +2340,12 @@ def _substitute_(self, rules): pass else: from asymptotic_ring import AsymptoticRing + from sage.symbolic.ring import SymbolicRing + if isinstance(P, AsymptoticRing): return g.O() - elif P is sage.symbolic.ring.SR: + elif isinstance(P, SymbolicRing): return g.Order() try: From ee5293298a509cb15da000f87ba25adb75f4f63d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 19 Oct 2015 21:17:43 +0200 Subject: [PATCH 1668/1872] fixup and doctest of parameter R in .symbolic_expression --- src/sage/rings/asymptotic/asymptotic_ring.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 21b4eb71809..e32557767d7 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2063,12 +2063,21 @@ def symbolic_expression(self, R=None): Order((1/2)^z*x*sqrt(y)*sqrt(z)*sqrt(log(y))) sage: _.parent() Symbolic Ring + + :: + + sage: from sage.symbolic.ring import SymbolicRing + sage: class MySymbolicRing(SymbolicRing): + ....: pass + sage: mySR = MySymbolicRing() + sage: a.symbolic_expression(mySR).parent() is mySR + True """ if R is None: from sage.symbolic.ring import SR R = SR - return self.substitute(dict((g, R.var(str(g))) + return self.substitute(dict((g, R(R.var(str(g)))) for g in self.parent().gens()), domain=R) From aeb120cf3cbdad3e74607619a9ef49542aee0161 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 19 Oct 2015 21:01:03 -0300 Subject: [PATCH 1669/1872] Trac 19016: review #1 --- src/sage/combinat/colored_permutations.py | 12 ++++++++++++ .../function_field/function_field_element.pyx | 4 ++-- src/sage/rings/ideal.py | 16 ---------------- src/sage/rings/polynomial/laurent_polynomial.pyx | 2 +- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 40e14878ce9..eaf5de808e4 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -42,6 +42,18 @@ def __init__(self, parent, colors, perm): self._perm = perm MultiplicativeGroupElement.__init__(self, parent=parent) + def __hash__(self): + r""" + TESTS:: + + sage: C = ColoredPermutations(4, 3) + sage: s1,s2,t = C.gens() + sage: hash(s1), hash(s2), hash(t) + (2666658751600856334, 3639282354432100950, 3639281107336048003) # 64-bit + (-1973744370, 88459862, -1467077245) # 32-bit + """ + return hash(self._perm) ^ hash(self._colors) + def _repr_(self): """ Return a string representation of ``self``. diff --git a/src/sage/rings/function_field/function_field_element.pyx b/src/sage/rings/function_field/function_field_element.pyx index 580bd5fa283..2ecaabd469d 100644 --- a/src/sage/rings/function_field/function_field_element.pyx +++ b/src/sage/rings/function_field/function_field_element.pyx @@ -578,8 +578,8 @@ cdef class FunctionFieldElement_rational(FunctionFieldElement): """ TESTS: - It would be nice if the following would produce a list of - 15 distinct hashes:: + It would be nice if the following would produce a list of + 15 distinct hashes:: sage: K. = FunctionField(QQ) sage: len({hash(t^i+t^j) for i in [-2..2] for j in [i..2]}) diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 0b9f6297e03..36932590f97 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -318,22 +318,6 @@ def __repr__(self): """ return "Ideal %s of %s"%(self._repr_short(), self.ring()) - def __hash__(self): - r""" - Very stupid constant hash function! - - TESTS:: - - sage: R = ZZ - sage: I = ZZ*2 - sage: J = ZZ*(-2) - sage: hash(I) - 0 - sage: hash(J) - 0 - """ - return 0 - def __cmp__(self, other): """ Compares the generators of two ideals. diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 0ef044296ef..dfd8d4cd692 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1352,7 +1352,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): -2021162459040316190 # 64-bit -1148451614 # 32-bit """ - return hash(self._poly) + return hash(self._poly) ^ hash(self._mon) cdef _new_c(self): """ From e1aca778523496285eef6b12a7ae264b3edf3b7e Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 20 Oct 2015 10:16:03 +0200 Subject: [PATCH 1670/1872] SR.symbol: set parent correctly (inheritance) --- src/sage/symbolic/ring.pyx | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 439d02de32c..239097c6be2 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -586,6 +586,24 @@ cdef class SymbolicRing(CommutativeRing): sage: n = var('n', domain='integer') sage: solve([n^2 == 3],n) [] + + TESTS: + + Test that the parent is set correctly (inheritance):: + + sage: from sage.symbolic.ring import SymbolicRing + sage: class MySymbolicRing(SymbolicRing): + ....: def _repr_(self): + ....: return 'My Symbolic Ring' + sage: MySR = MySymbolicRing() + sage: MySR.symbol('x').parent() + My Symbolic Ring + sage: MySR.var('x').parent() # indirect doctest + My Symbolic Ring + sage: MySR.var('blub').parent() # indirect doctest + My Symbolic Ring + sage: MySR.an_element().parent() + My Symbolic Ring """ cdef GSymbol symb cdef Expression e @@ -597,7 +615,7 @@ cdef class SymbolicRing(CommutativeRing): if e is not None: if domain is None: if latex_name is None: - return e + return self(e) # get symbol symb = ex_to_symbol(e._gobj) @@ -609,12 +627,12 @@ cdef class SymbolicRing(CommutativeRing): if domain is not None: send_sage_domain_to_maxima(e, domain) - return e + return self(e) else: # initialize a new symbol # Construct expression e = Expression.__new__(Expression) - e._parent = SR + e._parent = self if name is None: # Check if we need a temporary anonymous new symbol symb = ginac_new_symbol() From ff914dc988541148b4f10a3434dd688fc5ff7e75 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 20 Oct 2015 07:02:41 -0500 Subject: [PATCH 1671/1872] Implementing John's suggestions. --- .../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 da1a8701a89..b4378371526 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -951,7 +951,7 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): @cached_method def is_commutative(self): """ - Return if ``self`` is a commutative algebra. + Return whether ``self`` is a commutative algebra. EXAMPLES:: @@ -963,6 +963,10 @@ def is_commutative(self): True """ B = list(self.basis()) + try: # See if 1 is a basis element, if so, remove it + B.remove(self.one()) + except ValueError: + pass return all(b*bp == bp*b for i,b in enumerate(B) for bp in B[i+1:]) class ElementMethods: From b6c565763a2df99471bb6b574f60d15450b44c2e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 20 Oct 2015 08:36:39 -0500 Subject: [PATCH 1672/1872] Add a warning about the abuse of Parent in simplicial complex. --- src/sage/homology/simplicial_complex.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index 1a27c75015e..98c5ab48003 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -837,7 +837,15 @@ class SimplicialComplex(Parent, GenericCellComplex): True sage: SimplicialComplex(S, is_immutable=False).is_mutable() True - """ + + .. WARNING:: + + Simplicial complexes are not proper parents as they do + not possess element classes. In particular, parents are assumed + to be hashable (and hence immutable) by the coercion framework. + However this is close enough to being a parent with elements + being the faces of ``self`` that we currently allow this abuse. + """ def __init__(self, maximal_faces=None, From a206df8bea523ed25f1201c96b948406d06e351f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 20 Oct 2015 16:17:21 +0200 Subject: [PATCH 1673/1872] restore broken cluster quiver interact --- .../cluster_algebra_quiver/cluster_seed.py | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index ad41db77a43..75dbfee3925 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -975,6 +975,7 @@ def interact(self, fig_size=1, circular=True): from sage.plot.plot import EMBEDDED_MODE from sagenb.notebook.interact import interact, selector from sage.misc.all import html,latex + from sage.repl.rich_output.pretty_print import pretty_print if not EMBEDDED_MODE: return "The interactive mode only runs in the Sage notebook." @@ -986,13 +987,19 @@ def interact(self, fig_size=1, circular=True): ssm = [True] ssl = [True] @interact - def player(k=selector(values=range(self._n),nrows = 1,label='Mutate at: '), show_seq=("Mutation sequence:", True), show_vars=("Cluster variables:", True), show_matrix=("B-Matrix:", True), show_lastmutation=("Show last mutation:", True) ): - ft,ss,sv,sm,sl = sft.pop(), sss.pop(), ssv.pop(), ssm.pop(), ssl.pop() + def player(k=selector(values=range(self._n), nrows = 1, + label='Mutate at: '), + show_seq=("Mutation sequence:", True), + show_vars=("Cluster variables:", True), + show_matrix=("B-Matrix:", True), + show_lastmutation=("Show last mutation:", True)): + ft, ss, sv, sm, sl = sft.pop(), sss.pop(), ssv.pop(), ssm.pop(), ssl.pop() if ft: self.show(fig_size=fig_size, circular=circular) elif show_seq is not ss or show_vars is not sv or show_matrix is not sm or show_lastmutation is not sl: if seq and show_lastmutation: - self.show(fig_size=fig_size, circular=circular, mark=seq[len(seq)-1]) + self.show(fig_size=fig_size, circular=circular, + mark=seq[len(seq) - 1]) else: self.show(fig_size=fig_size, circular=circular ) else: @@ -1001,32 +1008,27 @@ def player(k=selector(values=range(self._n),nrows = 1,label='Mutate at: '), show if not show_lastmutation: self.show(fig_size=fig_size, circular=circular) else: - self.show(fig_size=fig_size, circular=circular,mark=k) + self.show(fig_size=fig_size, circular=circular, mark=k) sft.append(False) sss.append(show_seq) ssv.append(show_vars) ssm.append(show_matrix) ssl.append(show_lastmutation) - if show_seq: html( "Mutation sequence: $" + str( [ seq[i] for i in xrange(len(seq)) ] ).strip('[]') + "$" ) + if show_seq: + pretty_print(html("Mutation sequence: $" + str( [ seq[i] for i in xrange(len(seq)) ] ).strip('[]') + "$")) if show_vars: - html( "Cluster variables:" ) + pretty_print(html("Cluster variables:")) table = "$\\begin{align*}\n" for i in xrange(self._n): - table += "\tv_{%s} &= "%i + latex( self._cluster[i] ) + "\\\\ \\\\\n" + table += "\tv_{%s} &= " % i + latex(self.cluster_variable(i)) + "\\\\ \\\\\n" table += "\\end{align*}$" - html( "$ $" ) - html( table ) - html( "$ $" ) + pretty_print(html("$ $")) + pretty_print(html(table)) + pretty_print(html("$ $")) if show_matrix: - html( "B-Matrix:" ) - m = self._M - #m = matrix(range(1,self._n+1),sparse=True).stack(m) - m = latex(m) - m = m.split('(')[1].split('\\right')[0] - html( "$ $" ) - html( "$\\begin{align*} " + m + "\\end{align*}$" ) - #html( "$" + m + "$" ) - html( "$ $" ) + pretty_print(html("B-Matrix:")) + pretty_print(html(self._M)) + pretty_print(html("$ $")) def save_image(self, filename, circular=False, mark=None, save_pos=False): r""" @@ -1265,7 +1267,7 @@ def cluster(self): else: raise ValueError('Clusters not being tracked') elif self._cluster is None: - self._cluster = [ self.cluster_variable(k) for k in range(self._n) ] + self._cluster = [self.cluster_variable(k) for k in range(self._n)] return copy(self._cluster) def _f_mutate( self, k): @@ -2438,16 +2440,15 @@ def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2,return_o sage: S.mutation_sequence([0,1,0,1],return_output='var') [(x1 + 1)/x0, (x0 + x1 + 1)/(x0*x1), (x0 + 1)/x1, x0] """ - - seed = ClusterSeed( self ) + seed = ClusterSeed(self) new_clust_var = [] seed_sequence = [] for v in sequence: - seed = seed.mutate(v,inplace=False) - new_clust_var.append( seed.cluster()[v]) - seed_sequence.append( seed ) + seed = seed.mutate(v, inplace=False) + new_clust_var.append(seed.cluster()[v]) + seed_sequence.append(seed) if show_sequence: self.quiver().mutation_sequence2(sequence=sequence, show_sequence=True, fig_size=fig_size ) @@ -2729,7 +2730,8 @@ def exchangeable_part(self): seed.track_mutations(self._track_mut) if self._use_fpolys: self.cluster() - seed._cluster = [ self._cluster[k].subs(eval_dict) for k in xrange(self._n) ] + seed._cluster = [self._cluster[k].subs(eval_dict) + for k in xrange(self._n)] seed._mutation_type = self._mutation_type return seed @@ -2963,7 +2965,8 @@ def set_cluster( self, cluster, force=False ): if not force: # if already have f_polynomials, using set_cluster might yield data inconsistent with them. print("Warning: using set_cluster at this point could lead to inconsistent seed data.") else: - self._cluster = [ FractionField(self._R)(x) for x in cluster ][0:self._n] + self._cluster = [FractionField(self._R)(x) + for x in cluster][0:self._n] self._is_principal = None else: print("Warning: clusters not being tracked so this command is ignored.") From 01b2b3c873d06d5e18ac64c8646b65c7adec8c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 20 Oct 2015 16:43:07 +0200 Subject: [PATCH 1674/1872] trac #19440 trying to fix the hash for cluster quivers and cluster seeds --- .../cluster_algebra_quiver/cluster_seed.py | 38 ++++++++++++++++--- .../combinat/cluster_algebra_quiver/quiver.py | 20 +++++++++- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index ad41db77a43..8aa4cc2dc17 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -213,6 +213,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user # Copy the following attributes from data self._M = copy( data._M ) + self._M.set_immutable() self._B = copy( data._B ) self._n = data._n self._m = data._m @@ -269,6 +270,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user quiver = ClusterQuiver( data ) self._M = copy(quiver._M) # B-tilde exchange matrix + self._M.set_immutable() self._n = quiver._n self._m = quiver._m self._B = copy(self._M[:self._n,:self._n]) # Square Part of the B_matrix @@ -397,6 +399,7 @@ def use_c_vectors(self, use=True, bot_is_c=False, force=False): self._C = copy(self._M[self._m:(self._n+self._m),:self._n]) self._BC = copy(self._M) self._M = self._M[:self._m:self._n] + self._M.set_immutable() self._bot_is_c = False def use_g_vectors(self, use=True, force=False): @@ -858,6 +861,26 @@ def __eq__(self, other): d_vec = self.d_matrix() == other.d_matrix() return g_vec and c_vec and d_vec and clusters and ExMat + def __hash__(self): + """ + Return a hash of ``self``. + + EXAMPLES:: + + sage: Q = ClusterSeed(['A',5]) + sage: hash(Q) # indirect doctest + 16 + """ + mat_hash = self._M.__hash__() + if self._use_fpolys: + return mat_hash ** self.cluster().__hash__() + elif self._use_g_vec: + return mat_hash ** self.g_matrix().__hash__() + elif self._use_c_vec: + return mat_hash ** self.c_matrix().__hash__() + elif self._use_d_vec: + return mat_hash ** self.d_matrix().__hash__() + def _repr_(self): r""" Returns the description of ``self``. @@ -1077,7 +1100,7 @@ def b_matrix(self): [ 0 0 0 1] [ 0 0 -2 0] """ - return copy( self._M ) + return copy(self._M) def ground_field(self): r""" @@ -2359,6 +2382,7 @@ def mutate(self, sequence, inplace=True): seed._BC.mutate(k) seed._M = copy(seed._BC[:n+m,:n]) + self._M.set_immutable() if seed._use_c_vec: seed._C = seed._BC[n+m:2*n+m,:n+m] @@ -3050,15 +3074,19 @@ def reset_coefficients( self ): [ 0 1 0] [ 0 0 1] """ - n,m = self._n, self._m + n, m = self._n, self._m if not n == m: - raise ValueError("The numbers of cluster variables and of frozen variables do not coincide.") + raise ValueError("The numbers of cluster variables " + "and of frozen variables do not coincide.") + newM = copy(self._M) for i in xrange(m): for j in xrange(n): if i == j: - self._M[i+n,j] = 1 + newM[i + n, j] = 1 else: - self._M[i+n,j] = 0 + newM[i + n, j] = 0 + self._M = newM + self._M.set_immutable() self._quiver = None self._is_principal = None diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index be2cbbba0d6..0d7aef7236b 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -251,6 +251,7 @@ def __init__( self, data, frozen=None ): print 'The input data is a quiver, therefore the additional parameter frozen is ignored.' self._M = copy(data._M) + self._M.set_immutable() self._n = data._n self._m = data._m self._digraph = copy( data._digraph ) @@ -266,6 +267,7 @@ def __init__( self, data, frozen=None ): print 'The input data is a matrix, therefore the additional parameter frozen is ignored.' self._M = copy(data).sparse_matrix() + self._M.set_immutable() self._n = n = self._M.ncols() self._m = m = self._M.nrows() - self._n self._digraph = _matrix_to_digraph( self._M ) @@ -330,6 +332,7 @@ def __init__( self, data, frozen=None ): self._digraph = dg self._vertex_dictionary = {} self._M = M + self._M.set_immutable() if n+m == 0: self._description = 'Quiver without vertices' elif n+m == 1: @@ -364,6 +367,18 @@ def __eq__(self, other): """ return isinstance(other, ClusterQuiver) and self._M == other._M + def __hash__(self): + """ + Return a hash of ``self``. + + EXAMPLES:: + + sage: Q = ClusterQuiver(['A',5]) + sage: hash(Q) # indirect doctest + 16 + """ + return self._M.__hash__() + def _repr_(self): """ Returns the description of ``self``. @@ -701,7 +716,7 @@ def b_matrix(self): [ 0 0 0 1] [ 0 0 -2 0] """ - return copy( self._M ) + return copy(self._M) def digraph(self): """ @@ -1277,6 +1292,7 @@ def mutate(self, data, inplace=True): M = _edge_list_to_matrix( dg.edge_iterator(), n, m ) if inplace: self._M = M + self._M.set_immutable() self._digraph = dg else: Q = ClusterQuiver( M ) @@ -1387,6 +1403,7 @@ def reorient( self, data ): dg_new.add_edge( edge[1],edge[0],edge[2] ) self._digraph = dg_new self._M = _edge_list_to_matrix( dg_new.edges(), self._n, self._m ) + self._M.set_immutable() self._mutation_type = None elif all( type(edge) in [list,tuple] and len(edge)==2 for edge in data ): edges = self._digraph.edges(labels=False) @@ -1396,6 +1413,7 @@ def reorient( self, data ): self._digraph.delete_edge(edge[1],edge[0]) self._digraph.add_edge(edge[0],edge[1],label) self._M = _edge_list_to_matrix( self._digraph.edges(), self._n, self._m ) + self._M.set_immutable() self._mutation_type = None else: raise ValueError('The order is no total order on the vertices of the quiver or a list of edges to be oriented.') From c1cf361e83c117521c832a10f1d6248f264972d8 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Tue, 20 Oct 2015 08:51:09 -0700 Subject: [PATCH 1675/1872] trac 19016: fix laurent_polynomial hash doctest --- src/sage/rings/polynomial/laurent_polynomial.pyx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index dfd8d4cd692..b5ed30643a6 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1341,16 +1341,14 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): def __hash__(self): r""" - TESTS:: + TESTS: + + Test that the hash is non-constant (the hash does not need to be + deterministic so we leave some slack for collisions):: sage: L. = LaurentPolynomialRing(QQ) - sage: f = L({(-1,-1):1}) - sage: hash(f) - 1 - sage: f = L({(1,1):1}) - sage: hash(f) - -2021162459040316190 # 64-bit - -1148451614 # 32-bit + sage: len({hash(w^i*z^j) for i in [-2..2] for j in [-2..2]}) > 20 + True """ return hash(self._poly) ^ hash(self._mon) From 704edce505ced902c389492fe9e20dbb3de0c50c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 20 Oct 2015 20:43:07 +0200 Subject: [PATCH 1676/1872] trac #19440 another try for the hash --- .../combinat/cluster_algebra_quiver/cluster_seed.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 8aa4cc2dc17..24c5fc8776f 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -869,17 +869,17 @@ def __hash__(self): sage: Q = ClusterSeed(['A',5]) sage: hash(Q) # indirect doctest - 16 + -5649412990944896369 """ - mat_hash = self._M.__hash__() + # mat_hash = self._M.__hash__() if self._use_fpolys: - return mat_hash ** self.cluster().__hash__() + return tuple(self.cluster()).__hash__() elif self._use_g_vec: - return mat_hash ** self.g_matrix().__hash__() + return self.g_matrix().__hash__() elif self._use_c_vec: - return mat_hash ** self.c_matrix().__hash__() + return self.c_matrix().__hash__() elif self._use_d_vec: - return mat_hash ** self.d_matrix().__hash__() + return self.d_matrix().__hash__() def _repr_(self): r""" From 4b2f2bb78df9837b0a400f7b2dc38d4e1f3ad190 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Wed, 21 Oct 2015 11:22:08 +0900 Subject: [PATCH 1677/1872] =?UTF-8?q?Making=20latex.rst=20pass=20the=20doc?= =?UTF-8?q?test=20by:=201)=20magic=20comment=20word=20=E2=80=9Crandom?= =?UTF-8?q?=E2=80=9D=20recovered=20on=20the=20top=20of=20the=20line;=202)?= =?UTF-8?q?=20A=20misplaced/duplicated=20\\usepackage{tikz}=20strings=20re?= =?UTF-8?q?moved.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/ja/tutorial/latex.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/doc/ja/tutorial/latex.rst b/src/doc/ja/tutorial/latex.rst index 7002e3127fa..7eb10a5272b 100644 --- a/src/doc/ja/tutorial/latex.rst +++ b/src/doc/ja/tutorial/latex.rst @@ -361,14 +361,12 @@ LaTeX表式とLatexエンジンの生成するdvi形式にdvipngが扱えないs グラフは ``tikzpicture`` 環境で取り込まれるから,文字列 ``tikzpicture`` を ``mathjax avoid list`` に入れておくとよい. そうしてからワークシートで ``view(graphs.CompleteGraph(4))`` を実行するとpdflatexがPDFファイルを生成し,ついで ``convert`` ユーティリティが抽出したPNG画像がワークシートの出力セルに挿入されることになる. ノートブック上でグラフをLaTeXにグラフを処理させるために必要なコマンド操作を以下に示す. - - :: sage: from sage.graphs.graph_latex import setup_latex_preamble sage: setup_latex_preamble() - sage: latex.extra_preamble() # システムで運用されているTeXの種類に依存 - '\\usepackage{foo-bar-unchecked}\\usepackage{tikz}\n\\usepackage{tkz-graph}\n\\usepackage{tkz-berge}\n\\usetikzlibrary{arrows,shapes}' + sage: latex.extra_preamble() # random - システムで運用されているTeXに依存 + '\\usepackage{tikz}\n\\usepackage{tkz-graph}\n\\usepackage{tkz-berge}\n' sage: latex.engine('pdflatex') sage: latex.add_to_mathjax_avoid_list('tikzpicture') sage: latex.mathjax_avoid_list() From 519a75ed555ddc2bea1be0bec29f7ca75f8950dc Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Wed, 21 Oct 2015 14:07:05 +0900 Subject: [PATCH 1678/1872] =?UTF-8?q?Recovering=20mssing=20lines=20and=20t?= =?UTF-8?q?he=20=E2=80=9Crandom=E2=80=9D=20comment=20keywords=20(programmi?= =?UTF-8?q?ng.rst)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/ja/tutorial/programming.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst index 47eb291b69a..7895d7bdb20 100644 --- a/src/doc/ja/tutorial/programming.rst +++ b/src/doc/ja/tutorial/programming.rst @@ -462,8 +462,10 @@ Pythonには集合(set)型が組込まれている. :: sage: X = set([1,19,'a']); Y = set([1,1,1, 2/3]) - sage: X + sage: X # random sort order {1, 19, 'a'} + sage: X == set(['a', 1, 1, 19]) + True sage: Y {2/3, 1} sage: 'a' in X @@ -480,8 +482,10 @@ Pythonには集合(set)型が組込まれている. :: sage: X = Set([1,19,'a']); Y = Set([1,1,1, 2/3]) - sage: X + sage: X # random sort order {'a', 1, 19} + sage: X == Set(['a', 1, 1, 19]) + True sage: Y {1, 2/3} sage: X.intersection(Y) From 4626cc13efc233cd0545b253815babbf3df5ecec Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Wed, 21 Oct 2015 09:34:19 +0200 Subject: [PATCH 1679/1872] document initial_category --- src/sage/rings/asymptotic/misc.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index b1d49bf63b4..29c3656b47b 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -554,6 +554,14 @@ def transform_category(category, - ``from`` and ``to`` are strings describing axioms and - ``mandatory`` is a boolean. + - ``initial_category`` -- (default: ``None``) a category. When + transforming the given category, this ``initial_category`` is + used as a starting point of the result. This means the resulting + category will be a subcategory of ``initial_category``. + If ``initial_category`` is ``None``, then the + :class:`category of objects ` + is used. + OUTPUT: A category. From be4fa45234bb933ca3b9bfce4cf1a2da61e14e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 21 Oct 2015 10:12:51 +0200 Subject: [PATCH 1680/1872] trac #19440 hash for 32 and 64-bit --- src/sage/combinat/cluster_algebra_quiver/cluster_seed.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 24c5fc8776f..46f12eadbf7 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -869,7 +869,8 @@ def __hash__(self): sage: Q = ClusterSeed(['A',5]) sage: hash(Q) # indirect doctest - -5649412990944896369 + -5649412990944896369 # 64-bit + 222337679 # 32-bit """ # mat_hash = self._M.__hash__() if self._use_fpolys: From 3152b5c3e970c906f48c9bf1cf001aee4c2583f6 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Wed, 21 Oct 2015 20:52:45 +0200 Subject: [PATCH 1681/1872] Updated Sage version to 6.10.beta1 --- 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 9d90d562953..4f9f6ab9cf8 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Sage version 6.10.beta0, released 2015-10-15 +Sage version 6.10.beta1, released 2015-10-21 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 0c170545927..45719e0ee55 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=3e0d10789b34d6f890e1575c2a06894a90e4807e -md5=020a9b7f31e61b57056969b6816455f1 -cksum=2662451870 +sha1=35bf9f2f9f36a2027fb78b0e32e967c60d9e9605 +md5=2d76276badfea4dd5bf52b5589d3af87 +cksum=3537008558 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 52bd8e43afb..9289ddcee34 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -120 +121 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index 4a95ae46233..6a94ac82e24 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath Version 6.10.beta0, Release Date: 2015-10-15 │ +│ SageMath Version 6.10.beta1, Release Date: 2015-10-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 b8eaf7940b3..f18d20a0ade 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.10.beta0' -SAGE_RELEASE_DATE='2015-10-15' +SAGE_VERSION='6.10.beta1' +SAGE_RELEASE_DATE='2015-10-21' diff --git a/src/sage/version.py b/src/sage/version.py index 13ac1cb1b05..8ed36a37275 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.10.beta0' -date = '2015-10-15' +version = '6.10.beta1' +date = '2015-10-21' From c5a7eee39d4c6dce006d1f6f8fd7a23383d540b7 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 14 Oct 2015 17:16:42 -0700 Subject: [PATCH 1682/1872] trac #19418: skew-Hadamard matrices and related srg's --- src/sage/combinat/matrices/hadamard_matrix.py | 301 +++++++++++++++++- src/sage/graphs/generators/families.py | 92 ++++++ src/sage/graphs/graph_generators.py | 6 + src/sage/graphs/strongly_regular_db.pyx | 110 ++++++- 4 files changed, 493 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 3d827f93233..3ccb9b0f8c3 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -77,23 +77,41 @@ def normalise_hadamard(H): H.rescale_row(i, -1) return H -def hadamard_matrix_paleyI(n): +def hadamard_matrix_paleyI(n, normalize=True): """ Implements the Paley type I construction. The Paley type I case corresponds to the case `p \cong 3 \mod{4}` for a prime `p` (see [Hora]_). + INPUT: + + - ``n`` -- the matrix size + + - ``normalize`` (boolean) -- whether to normalize the result. + EXAMPLES: - We note that this method returns a normalised Hadamard matrix :: + We note that this method by default returns a normalised Hadamard matrix :: - sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(4) # random + sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI + sage: hadamard_matrix_paleyI(4) # random [ 1 1 1 1] [ 1 -1 1 -1] [ 1 -1 -1 1] [ 1 1 -1 -1] + Otherwise, it returns a skew Hadamard matrix `H`, i.e. `H=S+I`, with + `S=-S^\top` :: + + sage: M=hadamard_matrix_paleyI(4, normalize=False); M # random + [ 1 1 1 1] + [ 1 -1 1 -1] + [ 1 -1 -1 1] + [ 1 1 -1 -1] + sage: S=M-identity_matrix(4); -S==S.T + True + TESTS:: sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI @@ -102,6 +120,9 @@ def hadamard_matrix_paleyI(n): sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True) ....: for n in test_cases) True + sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n,normalize=False),verbose=True) + ....: for n in test_cases) + True """ p = n - 1 if not(is_prime_power(p) and (p % 4 == 3)): @@ -115,10 +136,12 @@ def hadamard_matrix_paleyI(n): for x in K_list] for y in K_list]) for i in range(n): - H[0,i] = 1 - H[i,i] = -1 H[i,0] = -1 - H = normalise_hadamard(H) + H[0,i] = 1 + if normalize: + for i in range(n): + H[i,i] = -1 + H = normalise_hadamard(H) return H def hadamard_matrix_paleyII(n): @@ -189,7 +212,7 @@ def hadamard_matrix_paleyII(n): return normalise_hadamard(H) -def is_hadamard_matrix(M, normalized=False, verbose=False): +def is_hadamard_matrix(M, normalized=False, verbose=False, skew=False): r""" Test if `M` is a hadamard matrix. @@ -200,6 +223,9 @@ def is_hadamard_matrix(M, normalized=False, verbose=False): - ``normalized`` (boolean) -- whether to test if ``M`` is a normalized Hadamard matrix, i.e. has its first row/column filled with +1. + - ``skew`` (boolean) -- whether to test if ``M`` is a skew + Hadamard matrix, i.e. `M=S+I` for `-S=S^\top`, and `I` the identity matrix. + - ``verbose`` (boolean) -- whether to be verbose when the matrix is not Hadamard. @@ -253,6 +279,13 @@ def is_hadamard_matrix(M, normalized=False, verbose=False): print "The matrix is not normalized" return False + if skew: + S = M - I(n) + if -S != S.T: + if verbose: + print "The matrix is not skew" + return False + return True from sage.matrix.constructor import matrix_method @@ -588,7 +621,7 @@ def true(): return M -def _helper_payley_matrix(n): +def _helper_payley_matrix(n, zero_position=1): r""" Return the marix constructed in Lemma 1.19 page 291 of [SWW72]_. @@ -626,11 +659,16 @@ def _helper_payley_matrix(n): K_pairs = set(frozenset([x,-x]) for x in K) K_pairs.discard(frozenset([0])) K_list = [None]*n + if zero_position: + zero_position=n//2 + shift=0 + else: + shift=1 + for i,(x,y) in enumerate(K_pairs): - K_list[i] = x + K_list[i+shift] = x K_list[-i-1] = y - K_list[n//2] = K(0) - + K_list[zero_position] = K(0) M = matrix(n,[[2*((x-y).is_square())-1 for x in K_list] for y in K_list]) @@ -681,7 +719,7 @@ def rshcd_from_close_prime_powers(n): REFERENCE: - .. [GS14] J.M. Goethals, and J. J. Seidel, + .. [GS14] J. M. Goethals, and J. J. Seidel, Strongly regular graphs derived from combinatorial designs, Canadian Journal of Mathematics 22(1970), 597-614, http://dx.doi.org/10.4153/CJM-1970-067-9 @@ -709,3 +747,242 @@ def rshcd_from_close_prime_powers(n): assert len(set(map(sum,HH))) == 1 assert HH**2 == n**2*I(n**2) return HH + +def _circulant_matrix(v): + r""" + Return the circulant matrix specified by its 1st row `v` + + A circulant `n \times n` matrix specified by the 1st row `v=(v_0...v_{n-1})` is + the matrix $(c_{ij})_{0 \leq i,j\leq n-1}$ where $c_{ij}=v_{j-i \mod b}$. + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import _circulant_matrix + sage: v=[1,2,3,4,8] + sage: _circulant_matrix(v) + [1 2 3 4 8] + [8 1 2 3 4] + [4 8 1 2 3] + [3 4 8 1 2] + [2 3 4 8 1] + """ + from sage.rings.finite_rings.integer_mod import mod + n = len(v) + return matrix(n, n, lambda i, j: v[mod(j-i,n)]) + +def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): + r""" + Williamson-Goethals-Seidel construction of a skew Hadamard matrix + + Given `n\times n` (anti)circulant (or matrices `A`, `B`, `C`, `D` with 1,-1 entries, + and satisfying `A+A^\top = 2I`, `AA^\top + BB^\top + CC^\top + DD^\top = 4nI`, + one can construct a skew Hadamard matrix of order `4n`, cf. [GS70s]_. + Matrices for `n=36` and `52` are given in [GS70s]_. Matrices for `n=92` are given + in [Wall71]_. + + INPUT: + + - ``a`` -- 1,-1 list specifying the 1st row of `A` + + - ``b`` -- 1,-1 list specifying the 1st row of `B` + + - ``d`` -- 1,-1 list specifying the 1st row of `C` + + - ``c`` -- 1,-1 list specifying the 1st row of `D` + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import williamson_goethals_seidel_skew_hadamard_matrix as WGS + sage: a=[ 1, 1, 1, -1, 1, -1, 1, -1, -1] + sage: b=[ 1, -1, 1, 1, -1, -1, 1, 1, -1] + sage: c=[-1, -1]+[1]*6+[-1] + sage: d=[ 1, 1, 1, -1, 1, 1, -1, 1, 1] + sage: M=WGS(a,b,c,d,check=True) + + REFERENCES: + + .. [GS70s] J.M. Goethals and J. J. Seidel, + A skew Hadamard matrix of order 36, + J. Aust. Math. Soc. 11(1970), 343-344 + .. [Wall71] J. Wallis, + A skew-Hadamard matrix of order 92, + Bull. Aust. Math. Soc. 5(1971), 203-204 + .. [KoSt08] C. Koukouvinos, S. Stylianou + On skew-Hadamard matrices, + Discrete Math. 308(2008) 2723-2731 + + + """ + from sage.combinat.matrices.hadamard_matrix import _circulant_matrix + n = len(a) + R = matrix(ZZ, n, n, lambda i,j: 1 if i+j==n-1 else 0) + A,B,C,D=map(_circulant_matrix, [a,b,c,d]) + if check: + assert A*A.T+B*B.T+C*C.T+D*D.T==4*n*I(n) + assert A+A.T==2*I(n) + + M = block_matrix([[ A, B*R, C*R, D*R], + [-B*R, A, -D.T*R, C.T*R], + [-C*R, D.T*R, A, -B.T*R], + [-D*R, -C.T*R, B.T*R, A]]) + if check: + assert is_hadamard_matrix(M, normalized=False, skew=True) + return M + +def _GS_skew_hadamard(n, existence=False, check=True): + from sage.combinat.matrices.hadamard_matrix import\ + williamson_goethals_seidel_skew_hadamard_matrix as WGS + def pmtoZ(s): + return map(lambda x: 1 if x=='+' else -1, s) + + if existence: + return n in [36, 52, 92] + + if n==36: + a=[ 1, 1, 1, -1, 1, -1, 1, -1, -1] + b=[ 1, -1, 1, 1, -1, -1, 1, 1, -1] + c=[-1, -1]+[1]*6+[-1] + d=[ 1, 1, 1, -1, 1, 1, -1, 1, 1] + return WGS(a,b,c,d, check=check) + if n==52: + a=pmtoZ('++++-++--+---') + b=pmtoZ('-+-++----++-+') + c=pmtoZ('--+-+++++-+++') + return WGS(a,b,c,c, check=check) + if n==92: + a = [1,-1,-1,-1,-1,-1,-1,-1, 1, 1,-1, 1,-1, 1,-1,-1, 1, 1, 1, 1, 1, 1, 1] + b = [1, 1,-1,-1, 1,-1,-1, 1, 1, 1, 1,-1,-1, 1, 1, 1, 1,-1,-1, 1,-1,-1, 1] + c = [1, 1,-1,-1,-1, 1,-1, 1,-1, 1,-1, 1, 1,-1, 1,-1, 1,-1, 1,-1,-1,-1, 1] + d = [1,-1,-1,-1,-1, 1,-1,-1, 1,-1,-1, 1, 1,-1,-1, 1,-1,-1, 1,-1,-1,-1,-1] + return WGS(a,b,c,d, check=check) + return None + +_skew_had_cache={} + +def skew_hadamard_matrix(n,existence=False, check=True): + r""" + Tries to construct a skew Hadamard matrix + + A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix + and `-S=S^\top`. + + INPUT: + + - ``n`` (integer) -- dimension of the matrix + + - ``existence`` (boolean) -- whether to build the matrix or merely query if + a construction is available in Sage. When set to ``True``, the function + returns: + + - ``True`` -- meaning that Sage knows how to build the matrix + + - ``Unknown`` -- meaning that Sage does not know how to build the + matrix, but that the design may exist (see :mod:`sage.misc.unknown`). + + - ``False`` -- meaning that the matrix does not exist. + + - ``check`` (boolean) -- whether to check that output is correct before + returning it. As this is expected to be useless (but we are cautious + guys), you may want to disable it whenever you want speed. Set to ``True`` + by default. + + EXAMPLES:: + + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix + sage: skew_hadamard_matrix(12).det() + 2985984 + sage: 12^6 + 2985984 + sage: skew_hadamard_matrix(1) + [1] + sage: skew_hadamard_matrix(2) + [ 1 1] + [-1 1] + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix + sage: skew_hadamard_matrix(10,existence=True) + False + sage: skew_hadamard_matrix(12,existence=True) + True + sage: skew_hadamard_matrix(784,existence=True) # long time + True + sage: skew_hadamard_matrix(10) + Traceback (most recent call last): + ... + ValueError: A skew Hadamard matrix of order 10 does not exist + sage: skew_hadamard_matrix(36) + 36 x 36 dense matrix over Integer Ring... + sage: skew_hadamard_matrix(52) + 52 x 52 dense matrix over Integer Ring... + sage: skew_hadamard_matrix(92) + 92 x 92 dense matrix over Integer Ring... + sage: skew_hadamard_matrix(100) + Traceback (most recent call last): + ... + ValueError: A skew Hadamard matrix of order 100 is not yet implemented. + sage: skew_hadamard_matrix(100,existence=True) + Unknown + """ + def true(): + _skew_had_cache[n]=True + return True + M = None + if existence and n in _skew_had_cache: + return True + if not(n % 4 == 0) and (n > 2): + if existence: + return False + raise ValueError("A skew Hadamard matrix of order %s does not exist" % n) + if n == 2: + if existence: + return true() + M = matrix([[1, 1], [-1, 1]]) + elif n == 1: + if existence: + return true() + M = matrix([1]) + elif is_prime_power(n - 1) and ((n - 1) % 4 == 3): + if existence: + return true() + M = hadamard_matrix_paleyI(n, normalize=False) + + elif n % 8 == 0: + if skew_hadamard_matrix(n//2,existence=True, check=False): + if existence: + return true() + H = skew_hadamard_matrix(n//2,check=False) + M = block_matrix([[H,H], [-H.T,H.T]]) + + else: # try Williamson construction + for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n + n1 = n//d + if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\ + and skew_hadamard_matrix(n1,existence=True, check=False): + if existence: + return true() + H = skew_hadamard_matrix(n1, check=False)-I(n1) + U = matrix(ZZ, d, lambda i, j: -1 if i==j==0 else\ + 1 if i==j==1 or (i>1 and j-1==d-i)\ + else 0) + A = block_matrix([[matrix([0]), matrix(ZZ,1,n1-1,[1]*(n1-1))], + [ matrix(ZZ,n1-1,1,[-1]*(n1-1)), + _helper_payley_matrix(n1-1,zero_position=0)]])+I(n1) + M = A.tensor_product(I(n1))+(U*A).tensor_product(H) + break + if M is None: # try Williamson-Goethals-Seidel construction + if _GS_skew_hadamard(n, existence=True): + if existence: + return true() + M = _GS_skew_hadamard(n) + + if M is None: + if existence: + return Unknown + raise ValueError("A skew Hadamard matrix of order %s is not yet implemented." % n) + + if check: + assert is_hadamard_matrix(M, normalized=False, skew=True) + _skew_had_cache[n]=True + return M diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index c48916e73b9..dbd8318447b 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -1595,6 +1595,98 @@ def PaleyGraph(q): loops=False, name = "Paley graph with parameter %d"%q) return g +def PasechnikGraph(n): + """ + Pseudo-`OA(2n-1,4n-1)`-graph from a skew Hadamard matrix of order `4n` + + A strongly regular graph with parameters of the orthogonal array graph + :func:`OrthogonalArrayBlockGraph + `, also + known as pseudo Latin squares graph `L_{2n-1}(4n-1)`, constructed from a + skew Hadamard matrix of order `4n` following [Pa92]_. + + EXAMPLES:: + + sage: from sage.graphs.generators.families import PasechnikGraph + sage: PasechnikGraph(4).is_strongly_regular(parameters=True) + (225, 98, 43, 42) + sage: PasechnikGraph(9).is_strongly_regular(parameters=True) # long time + (1225, 578, 273, 272) + + REFERENCES: + + .. [Pa92] D. V. Pasechnik, + Skew-symmetric association schemes with two classes and strongly + regular graphs of type `L_{2n-1}(4n- 1)`, + Acta Applicandaie Math. 29(1992), 129-138 + """ + from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix + from sage.matrix.constructor import identity_matrix, matrix, diagonal_matrix + H = skew_hadamard_matrix(4*n) + dd = diagonal_matrix(H[0]) + H = dd*H*dd + M = H[1:].T[1:] - identity_matrix(4*n-1) + G = Graph(M.tensor_product(M.T), format='seidel_adjacency_matrix') + G.relabel() + G.name("Pasechnik Graph_" + str((n))) + return G + +def Pseudo_L_2n_4n_m_1(n): + """ + Pseudo-`OA(2n,4n-1)`-graph from a skew Hadamard matrix of order `4n` + + A strongly regular graph with parameters of the orthogonal array graph + :func:`OrthogonalArrayBlockGraph + `, also + known as pseudo Latin squares graph `L_{2n}(4n-1)`, constructed from a + skew Hadamard matrix of order `4n` due to Goethals and Seidel, see [BvL84]_. + + EXAMPLES:: + + sage: from sage.graphs.generators.families import Pseudo_L_2n_4n_m_1 + sage: Pseudo_L_2n_4n_m_1(4).is_strongly_regular(parameters=True) + (225, 112, 55, 56) + sage: Pseudo_L_2n_4n_m_1(9).is_strongly_regular(parameters=True) # long time + (1225, 612, 305, 306) + + """ + from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix + from sage.matrix.constructor import identity_matrix, matrix, diagonal_matrix + idm = identity_matrix(4*n-1) + e = matrix([1]*(4*n-1)) + H = skew_hadamard_matrix(4*n) + dd = diagonal_matrix(H[0]) + H = dd*H*dd + M = H[1:].T[1:] - idm + s = M.tensor_product(M.T) - idm.tensor_product(e.T*e - idm) + G = Graph(s, format='seidel_adjacency_matrix') + G.relabel() + G.name("skewhad^2_" + str((n))) + return G + +def switch_skewhad_pow2(n): + """ + a strongly regular graph in Seidel switching class of `Pseudo_L_{2n}(4n-1)` + + A strongly regular graph in the + :meth:`Seidel switching ` class of + func:`Pseudo_L_{2n}(4n-1) + ` + + EXAMPLES:: + + sage: from sage.graphs.generators.families import switch_skewhad_pow2 + sage: switch_skewhad_pow2(4).is_strongly_regular(parameters=True) + (226, 105, 48, 49) + + """ + from sage.graphs.generators.families import Pseudo_L_2n_4n_m_1 + G = Pseudo_L_2n_4n_m_1(n).complement() + G.add_vertex((4*n-1)**2) + G.seidel_switching(range((4*n-1)*(2*n-1))) + G.name("switch skewhad^2+*_" + str((n))) + return G + def HanoiTowerGraph(pegs, disks, labels=True, positions=True): r""" Returns the graph whose vertices are the states of the diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 477400f23b3..f43aa7f0b3b 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -216,12 +216,15 @@ def __append_to_doc(methods): "NStarGraph", "OddGraph", "PaleyGraph", + "PasechnikGraph", "petersen_family", "planar_graphs", + "Pseudo_L_2n_4n_m_1", "quadrangulations", "RingedTree", "SierpinskiGasketGraph", "strongly_regular_graph", + "switch_skewhad_pow2", "trees", "triangulations", "WheelGraph"]) @@ -1989,10 +1992,13 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None NStarGraph = staticmethod(sage.graphs.generators.families.NStarGraph) OddGraph = staticmethod(sage.graphs.generators.families.OddGraph) PaleyGraph = staticmethod(sage.graphs.generators.families.PaleyGraph) + PasechnikGraph = staticmethod(sage.graphs.generators.families.PasechnikGraph) petersen_family = staticmethod(sage.graphs.generators.families.petersen_family) + Pseudo_L_2n_4n_m_1 = staticmethod(sage.graphs.generators.families.Pseudo_L_2n_4n_m_1) RingedTree = staticmethod(sage.graphs.generators.families.RingedTree) SierpinskiGasketGraph = staticmethod(sage.graphs.generators.families.SierpinskiGasketGraph) strongly_regular_graph = staticmethod(sage.graphs.strongly_regular_db.strongly_regular_graph) + switch_skewhad_pow2 = staticmethod(sage.graphs.generators.families.switch_skewhad_pow2) trees = staticmethod(sage.graphs.generators.families.trees) WheelGraph = staticmethod(sage.graphs.generators.families.WheelGraph) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 638d6a74fb7..acb10dd30e5 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -90,7 +90,17 @@ def is_paley(int v,int k,int l,int mu): @cached_function def is_orthogonal_array_block_graph(int v,int k,int l,int mu): r""" - Test whether some Orthogonal Array graph is `(v,k,\lambda,\mu)`-strongly regular. + Test whether some (pseudo)Orthogonal Array graph is `(v,k,\lambda,\mu)`-strongly regular. + + We know how to construct graphs with parameters of an Orthogonal Array (`OA(m,n)`), + also known as Latin squares graphs `L_m(n)`, in several cases where no orthogonal + array is known, or even in some cases for which they are known not to exist. + + Such graphs are usually called pseudo-Latin squares graphs. Namely, Sage + can construct a graph with parameters of an `OA(m,n)`-graph whenever there + exists a skew-Hadamard matrix of order `n+1`, and `m=(n+1)/2` or `m=(n-1)/2`. + The construction in the former case is due to Goethals-Seidel [BvL84]_, and in the + latter case due to Pasechnik [Pa92]_. INPUT: @@ -110,11 +120,24 @@ def is_orthogonal_array_block_graph(int v,int k,int l,int mu): OA(5,8): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 35, 18, 20) + sage: t=is_orthogonal_array_block_graph(225,98,43,42); t + (..., 4) + sage: g = t[0](*t[1:]); g + Pasechnik Graph_4: Graph on 225 vertices + sage: g.is_strongly_regular(parameters=True) + (225, 98, 43, 42) + sage: t=is_orthogonal_array_block_graph(225,112,55,56); t + (..., 4) + sage: g = t[0](*t[1:]); g + skewhad^2_4: Graph on 225 vertices + sage: g.is_strongly_regular(parameters=True) + (225, 112, 55, 56) sage: t = is_orthogonal_array_block_graph(5,5,5,5); t """ # notations from # http://www.win.tue.nl/~aeb/graphs/OA.html + from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix if not is_square(v): return n = int(sqrt(v)) @@ -128,6 +151,15 @@ def is_orthogonal_array_block_graph(int v,int k,int l,int mu): from sage.graphs.generators.intersection import OrthogonalArrayBlockGraph return (lambda m,n : OrthogonalArrayBlockGraph(m, n), m,n) + elif n>2 and skew_hadamard_matrix(n+1, existence=True): + if m==(n+1)/2: + from sage.graphs.generators.families import Pseudo_L_2n_4n_m_1 as G + elif m==(n-1)/2: + from sage.graphs.generators.families import PasechnikGraph as G + else: + return + return (G, (n+1)/4) + @cached_function def is_johnson(int v,int k,int l,int mu): r""" @@ -1283,6 +1315,52 @@ def is_taylor_twograph_srg(int v,int k,int l,int mu): return (TaylorTwographSRG, q) return +def is_switch_skewhad(int v, int k, int l, int mu): + r""" + Test whether some `switch skewhad^2+*` is `(v,k,\lambda,\mu)`-strongly regular. + + The `switch skewhad^2+*` graphs appear on `Andries Brouwer's database + `__ and are built by + adding an isolated vertex to the complement of + :func:`~sage.graphs.graph_generators.GraphGenerators.Pseudo_L_2n_4n_m_1`, + and a :meth:`Seidel switching ` a set of disjoint + `n`-cocliques. + + INPUT: + + - ``v,k,l,mu`` (integers) + + OUTPUT: + + A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if the + parameters match, and ``None`` otherwise. + + EXAMPLES:: + + sage: graphs.strongly_regular_graph(226, 105, 48, 49) + switch skewhad^2+*_4: Graph on 226 vertices + + TESTS:: + + sage: from sage.graphs.strongly_regular_db import is_switch_skewhad + sage: t = is_switch_skewhad(5,5,5,5); t + + """ + from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix + from sage.graphs.generators.families import switch_skewhad_pow2 + cdef int n + r,s = eigenvalues(v,k,l,mu) + if r is None: + return + if r.switch_OA_srg at ..., 14, 29) """ - from sage.combinat.designs.orthogonal_arrays import orthogonal_array - cdef int n_2_p_1 = v cdef int n = floor(sqrt(n_2_p_1-1)) @@ -1370,6 +1446,31 @@ cdef eigenvalues(int v,int k,int l,int mu): return [(-b+sqrt(D))/2.0, (-b-sqrt(D))/2.0] + +cdef _L_g_n_params(int v,int k, int l,int mu): + r""" + Check whether (v,k,l,mu)-strongly regular graph has parameters of an `L_g(n)` s.r.g. + + Also known as pseudo-OA(n,g) case, i.e. s.r.g. with parameters of an OA(n,g)-graph. + Return g and n, if they exist. See Sect. 9.1 of [BH12]_ for details. + + INPUT: + + - ``v,k,l,mu`` (integers) + + """ + cdef int g, n + r,s = eigenvalues(v,k,l,mu) + if r is None: + return + if r < s: + r, s = s, r + g = -s + n = r+g + if v==n**2 and k==g*(n-1) and l==(g-1)*(g-2)+n-2 and mu==g*(g-1): + return [g, n] + return + def _H_3_cayley_graph(L): r""" return the `L`-Cayley graph of the group `H_3` from Prop. 12 in [JK03]_. @@ -2970,7 +3071,8 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint is_twograph_descendant_of_srg, is_taylor_twograph_srg, is_switch_OA_srg, - is_polhill] + is_polhill, + is_switch_skewhad] # Going through all test functions, for the set of parameters and its # complement. From 7effc544d159a7249900499484a1d81244ddc364 Mon Sep 17 00:00:00 2001 From: Takeo Sakai Date: Thu, 22 Oct 2015 10:16:29 +0900 Subject: [PATCH 1683/1872] Updating doctest on the categories and correct a typo, both in tour_coercion.rst --- src/doc/ja/tutorial/tour_coercion.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/ja/tutorial/tour_coercion.rst b/src/doc/ja/tutorial/tour_coercion.rst index 464807040a5..81e7625c7f9 100644 --- a/src/doc/ja/tutorial/tour_coercion.rst +++ b/src/doc/ja/tutorial/tour_coercion.rst @@ -88,7 +88,7 @@ Sageでは元が属する構造物のことを「ペアレント構造」(parent sage: isinstance(ZZ, Ring) True -代数学では,同じ種類の代数構造を共有する物を,いわゆる「圏」(cagegory)と呼ばれるものに集約して扱う. +代数学では,同じ種類の代数構造を共有する物を,いわゆる「圏」(category)と呼ばれるものに集約して扱う. Sageのクラス階層と圏の階層構造にはそれなりに類似が見られないでもない. しかし,Pythonクラスについては圏との類似はあまり強調すべきものでもなさそうだ. いずれにせよ,数学的な意味における圏はSageでも実装されている: @@ -99,7 +99,9 @@ Sageのクラス階層と圏の階層構造にはそれなりに類似が見ら sage: Rings() Category of rings sage: ZZ.category() - Join of Category of euclidean domains and Category of infinite enumerated sets + Join of Category of euclidean domains + and Category of infinite enumerated sets + and Category of metric spaces sage: ZZ.category().is_subcategory(Rings()) True sage: ZZ in Rings() From 7ab7b370464104034fa8128324afa2faeefa4431 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 22 Oct 2015 12:39:58 +0200 Subject: [PATCH 1684/1872] Trac #19453: FiniteStateMachine.transposition(): multi-letter input not handeled correctly --- src/sage/combinat/finite_state_machine.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index d79c83937d0..945ee294fb5 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -8429,6 +8429,26 @@ def transposition(self): sage: aut.transposition().initial_states() ['1', '2'] + :: + + sage: A = Automaton([(0, 1, [1, 0])], + ....: initial_states=[0], + ....: final_states=[1]) + sage: A([1, 0]) + True + sage: A.transposition()([0, 1]) + True + + :: + + sage: T = Transducer([(0, 1, [1, 0], [1, 0])], + ....: initial_states=[0], + ....: final_states=[1]) + sage: T([1, 0]) + [1, 0] + sage: T.transposition()([0, 1]) + [1, 0] + TESTS: @@ -8456,7 +8476,7 @@ def transposition(self): for transition in self.iter_transitions(): transposition.add_transition( transition.to_state.label(), transition.from_state.label(), - transition.word_in, transition.word_out) + list(reversed(transition.word_in)), transition.word_out) for initial in self.iter_initial_states(): state = transposition.state(initial.label()) From 3a75d03a6bac01d19ae4d262db476a9a6fb400cc Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 22 Oct 2015 12:47:53 +0200 Subject: [PATCH 1685/1872] Trac #19453: also transpose output --- src/sage/combinat/finite_state_machine.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 945ee294fb5..0cc06f96736 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -8402,14 +8402,15 @@ def projection(self, what='input'): return new - def transposition(self): + def transposition(self, reverse_output_labels=True): """ Returns a new finite state machine, where all transitions of the input finite state machine are reversed. INPUT: - Nothing. + - ``reverse_output_labels`` -- a boolean (default: ``True``): whether to reverse + output labels. OUTPUT: @@ -8447,6 +8448,8 @@ def transposition(self): sage: T([1, 0]) [1, 0] sage: T.transposition()([0, 1]) + [0, 1] + sage: T.transposition(reverse_output_labels=False)([0, 1]) [1, 0] @@ -8468,6 +8471,11 @@ def transposition(self): """ from copy import deepcopy + if reverse_output_labels: + rewrite_output = lambda word: list(reversed(word)) + else: + rewrite_output = lambda word: word + transposition = self.empty_copy() for state in self.iter_states(): @@ -8476,7 +8484,8 @@ def transposition(self): for transition in self.iter_transitions(): transposition.add_transition( transition.to_state.label(), transition.from_state.label(), - list(reversed(transition.word_in)), transition.word_out) + list(reversed(transition.word_in)), + rewrite_output(transition.word_out)) for initial in self.iter_initial_states(): state = transposition.state(initial.label()) From 8e42c26965ae7548e39561a23f2b45bdfeb77ca8 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 22 Oct 2015 13:35:44 +0200 Subject: [PATCH 1686/1872] Removed deprecation warnings and lazy imported everything --- src/sage/coding/all.py | 90 +++++++----------------- src/sage/coding/channel_constructions.py | 11 +-- src/sage/coding/code_constructions.py | 17 ----- src/sage/coding/encoder.py | 3 +- 4 files changed, 34 insertions(+), 87 deletions(-) diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 5895ac96efc..56c05cee834 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -1,65 +1,26 @@ from sage.misc.lazy_import import lazy_import -from code_constructions import (permutation_action, walsh_matrix,cyclotomic_cosets) - -from sage.misc.superseded import deprecated_callable_import -deprecated_callable_import(15445, - 'sage.coding.code_constructions', - globals(), - locals(), - ["BinaryGolayCode", - "BCHCode", - "CyclicCode", - "CyclicCodeFromGeneratingPolynomial", - "CyclicCodeFromCheckPolynomial", - "DuadicCodeEvenPair", - "DuadicCodeOddPair", - "ExtendedBinaryGolayCode", - "ExtendedQuadraticResidueCode", - "ExtendedTernaryGolayCode", - "HammingCode", - "LinearCodeFromCheckMatrix", - "QuadraticResidueCode", - "QuadraticResidueCodeEvenPair", - "QuadraticResidueCodeOddPair", - "RandomLinearCode", - "ReedSolomonCode", - "TernaryGolayCode", - "ToricCode", - "TrivialCode", - "WalshCode"], - ("This method soon will not be available in that " - "way anymore. To use it, you can now call it by " - "typing codes.%(name)s")) - -deprecated_callable_import(15445, - 'sage.coding.guava', - globals(), - locals(), - ["BinaryReedMullerCode", - "QuasiQuadraticResidueCode", - "RandomLinearCodeGuava"], - ("This method soon will not be available in that " - "way anymore. To use it, you can now call it by " - "typing codes.%(name)s")) - -from code_bounds import (codesize_upper_bound, - dimension_upper_bound, - volume_hamming, - gilbert_lower_bound, - plotkin_upper_bound, - griesmer_upper_bound, - elias_upper_bound, - hamming_upper_bound, - singleton_upper_bound, - gv_info_rate, - entropy, - gv_bound_asymp, - hamming_bound_asymp, - singleton_bound_asymp, - plotkin_bound_asymp, - elias_bound_asymp, - mrrw1_bound_asymp) +lazy_import("sage.coding.code_constructions", ["permutation_action",\ + "walsh_matrix",\ + "cyclotomic_cosets"]) + +lazy_import("sage.coding.code_bounds", ["codesize_upper_bound",\ + "dimension_upper_bound",\ + "volume_hamming",\ + "gilbert_lower_bound",\ + "plotkin_upper_bound",\ + "griesmer_upper_bound",\ + "elias_upper_bound",\ + "hamming_upper_bound",\ + "singleton_upper_bound",\ + "gv_info_rate",\ + "entropy",\ + "gv_bound_asymp",\ + "hamming_bound_asymp",\ + "singleton_bound_asymp",\ + "plotkin_bound_asymp",\ + "elias_bound_asymp",\ + "mrrw1_bound_asymp"]) lazy_import("sage.coding.linear_code", ["LinearCode",\ "LinearCodeFromVectorSpace",\ @@ -68,11 +29,10 @@ "bounds_minimum_distance", "self_orthogonal_binary_codes"]) -from sd_codes import self_dual_codes_binary -lazy_import("sage.coding.delsarte_bounds", - ["Krawtchouk", "delsarte_bound_hamming_space", "delsarte_bound_additive_hamming_space"]) +lazy_import("sage.coding.delsarte_bounds", ["Krawtchouk",\ + "delsarte_bound_hamming_space",\ + "delsarte_bound_additive_hamming_space"]) +lazy_import("sage.coding.sd_codes", "self_dual_codes_binary") 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 2a6a14f1120..a49147640ef 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -62,7 +62,8 @@ def random_error_vector(n, F, error_positions): EXAMPLES:: - sage: sage.coding.channel_constructions.random_error_vector(5, GF(2), [1,3]) + sage: from sage.coding.channel_constructions import random_error_vector + sage: random_error_vector(5, GF(2), [1,3]) (0, 1, 0, 1, 0) """ vect = [F.zero()]*n @@ -90,12 +91,13 @@ def format_interval(t): TESTS:: + sage: from sage.coding.channel_constructions import format_interval sage: t = (5, 5) - sage: sage.coding.channel_constructions.format_interval(t) + sage: format_interval(t) '5' sage: t = (2, 10) - sage: sage.coding.channel_constructions.format_interval(t) + sage: format_interval(t) 'between 2 and 10' """ @@ -142,7 +144,8 @@ def __init__(self, input_space, output_space): We first create a new Channel subclass:: - sage: class ChannelExample(sage.coding.channel_constructions.Channel): + sage: from sage.coding.channel_constructions import Channel + sage: class ChannelExample(Channel): ....: def __init__(self, input_space, output_space): ....: super(ChannelExample, self).__init__(input_space, output_space) diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index 17a243df93f..34270dfd17b 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -978,15 +978,6 @@ def HammingCode(r,F): 3 sage: C = codes.HammingCode(3,GF(4,'a')); C Linear code of length 21, dimension 18 over Finite Field in a of size 2^2 - - While the ``codes`` object now gathers all code constructors, - ``HammingCode`` is still available in the global namespace:: - - sage: HammingCode(3,GF(2)) - doctest:...: DeprecationWarning: This method soon will not be available in that way anymore. To use it, you can now call it by typing codes.HammingCode - See http://trac.sagemath.org/15445 for details. - Linear code of length 7, dimension 4 over Finite Field of size 2 - """ q = F.order() n = (q**r-1)/(q-1) @@ -1295,14 +1286,6 @@ def ReedSolomonCode(n,k,F,pts = None): sage: C.minimum_distance() 3 - While the ``codes`` object now gathers all code constructors, - ``ReedSolomonCode`` is still available in the global namespace:: - - sage: ReedSolomonCode(6,4,GF(7)) - doctest:...: DeprecationWarning: This method soon will not be available in that way anymore. To use it, you can now call it by typing codes.ReedSolomonCode - See http://trac.sagemath.org/15445 for details. - Linear code of length 6, dimension 4 over Finite Field of size 7 - REFERENCES: - [W] http://en.wikipedia.org/wiki/Reed-Solomon diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index d5051e7ccfe..d9833623243 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -70,7 +70,8 @@ def __init__(self, code): We first create a new :class:`Encoder` subclass:: - sage: class EncoderExample(sage.coding.encoder.Encoder): + sage: from sage.coding.encoder import Encoder + sage: class EncoderExample(Encoder): ....: def __init__(self, code): ....: super(EncoderExample, self).__init__(code) From f13f5c236c2cdf29fffe42ffa9df07eed3a4543f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 22 Oct 2015 16:45:22 +0200 Subject: [PATCH 1687/1872] Trac #19454: methods determine_input_alphabet and determine_output_alphabet --- src/sage/combinat/finite_state_machine.py | 127 +++++++++++++++++++--- 1 file changed, 110 insertions(+), 17 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index d79c83937d0..5b8b14adde5 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -86,7 +86,9 @@ :meth:`~FiniteStateMachine.delete_transition` | Delete a transition :meth:`~FiniteStateMachine.remove_epsilon_transitions` | Remove epsilon transitions (not implemented) :meth:`~FiniteStateMachine.split_transitions` | Split transitions with input words of length ``> 1`` - :meth:`~FiniteStateMachine.determine_alphabets` | Determines input and output alphabets + :meth:`~FiniteStateMachine.determine_alphabets` | Determine input and output alphabets + :meth:`~FiniteStateMachine.determine_input_alphabet` | Determine input alphabet + :meth:`~FiniteStateMachine.determine_output_alphabet` | Determine output alphabet :meth:`~FiniteStateMachine.construct_final_word_out` | Construct final output by implicitly reading trailing letters; cf. :meth:`~FiniteStateMachine.with_final_word_out` @@ -5126,27 +5128,27 @@ def default_function(transitions): len(relabeledFSM.states()), dictionary) - def determine_alphabets(self, reset=True): + def determine_input_alphabet(self, reset=True): """ - Determines the input and output alphabet according to the - transitions in self. + Determine the input alphabet according to the transitions + of this finite state machine. INPUT: - - ``reset`` -- If reset is ``True``, then the existing input - and output alphabets are erased, otherwise new letters are - appended to the existing alphabets. + - ``reset`` -- a boolean (default: ``True``). If ``True``, then + the existing input alphabet is erased, otherwise new letters are + appended to the existing alphabet. OUTPUT: Nothing. - After this operation the input alphabet and the output - alphabet of self are a list of letters. + After this operation the input alphabet of this finite state machine + is a list of letters. .. TODO:: - At the moment, the letters of the alphabets need to be hashable. + At the moment, the letters of the alphabet need to be hashable. EXAMPLES:: @@ -5154,32 +5156,123 @@ def determine_alphabets(self, reset=True): ....: (2, 2, 1, 1), (2, 2, 0, 0)], ....: final_states=[1], ....: determine_alphabets=False) - sage: T.state(1).final_word_out = [1, 4] sage: (T.input_alphabet, T.output_alphabet) (None, None) - sage: T.determine_alphabets() + sage: T.determine_input_alphabet() sage: (T.input_alphabet, T.output_alphabet) - ([0, 1, 2], [0, 1, 4]) - """ + ([0, 1, 2], None) + + .. SEEALSO:: + :meth:`determine_output_alphabet` + :meth:`determine_alphabets` + """ if reset: ain = set() - aout = set() else: ain = set(self.input_alphabet) - aout = set(self.output_alphabet) for t in self.iter_transitions(): for letter in t.word_in: ain.add(letter) + self.input_alphabet = list(ain) + + + def determine_output_alphabet(self, reset=True): + """ + Determine the output alphabet according to the transitions + of this finite state machine. + + INPUT: + + - ``reset`` -- a boolean (default: ``True``). If ``True``, then + the existing output alphabet is erased, otherwise new letters are + appended to the existing alphabet. + + OUTPUT: + + Nothing. + + After this operation the output alphabet of this finite state machine + is a list of letters. + + .. TODO:: + + At the moment, the letters of the alphabet need to be hashable. + + EXAMPLES:: + + sage: T = Transducer([(1, 1, 1, 0), (1, 2, 2, 1), + ....: (2, 2, 1, 1), (2, 2, 0, 0)], + ....: final_states=[1], + ....: determine_alphabets=False) + sage: T.state(1).final_word_out = [1, 4] + sage: (T.input_alphabet, T.output_alphabet) + (None, None) + sage: T.determine_output_alphabet() + sage: (T.input_alphabet, T.output_alphabet) + (None, [0, 1, 4]) + + .. SEEALSO:: + :meth:`determine_input_alphabet` + :meth:`determine_alphabets` + """ + if reset: + aout = set() + else: + aout = set(self.output_alphabet) + + for t in self.iter_transitions(): for letter in t.word_out: aout.add(letter) for s in self.iter_final_states(): for letter in s.final_word_out: aout.add(letter) - self.input_alphabet = list(ain) self.output_alphabet = list(aout) + def determine_alphabets(self, reset=True): + """ + Determine the input and output alphabet according to the + transitions in this finite state machine. + + INPUT: + + - ``reset`` -- If reset is ``True``, then the existing input + and output alphabets are erased, otherwise new letters are + appended to the existing alphabets. + + OUTPUT: + + Nothing. + + After this operation the input alphabet and the output + alphabet of this finite state machine are a list of letters. + + .. TODO:: + + At the moment, the letters of the alphabets need to be hashable. + + EXAMPLES:: + + sage: T = Transducer([(1, 1, 1, 0), (1, 2, 2, 1), + ....: (2, 2, 1, 1), (2, 2, 0, 0)], + ....: final_states=[1], + ....: determine_alphabets=False) + sage: T.state(1).final_word_out = [1, 4] + sage: (T.input_alphabet, T.output_alphabet) + (None, None) + sage: T.determine_alphabets() + sage: (T.input_alphabet, T.output_alphabet) + ([0, 1, 2], [0, 1, 4]) + + .. SEEALSO:: + :meth:`determine_input_alphabet` + :meth:`determine_output_alphabet` + """ + self.determine_input_alphabet(reset) + self.determine_output_alphabet(reset) + + #************************************************************************* # get states and transitions #************************************************************************* From cc8a7e60b0ba3e5ab41bc216436026683250216c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 22 Oct 2015 16:46:10 +0200 Subject: [PATCH 1688/1872] Trac #19454: Modify behavior of determine_alphabets in constructor --- src/sage/combinat/finite_state_machine.py | 45 +++++++++++++++++++---- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 5b8b14adde5..72f20eef9e2 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -2973,6 +2973,38 @@ class FiniteStateMachine(sage.structure.sage_object.SageObject): ValueError: with_final_word_out cannot be specified when copying another finite state machine. + :trac:`19454` rewrote automatic detection of the alphabets:: + + sage: def transition_function(state, letter): + ....: return (0, 3 + letter) + sage: T1 = Transducer(transition_function, + ....: input_alphabet=[0, 1], + ....: initial_states=[0], + ....: final_states=[0]) + sage: T1.output_alphabet + [3, 4] + sage: T2 = Transducer([(0, 0, 0, 3), (0, 0, 0, 4)], + ....: initial_states=[0], + ....: final_states=[0]) + sage: T2.output_alphabet + [3, 4] + sage: T = Transducer([(0, 0, 1, 2)]) + sage: (T.input_alphabet, T.output_alphabet) + ([1], [2]) + sage: T = Transducer([(0, 0, 1, 2)], determine_alphabets=False) + sage: (T.input_alphabet, T.output_alphabet) + (None, None) + sage: T = Transducer([(0, 0, 1, 2)], input_alphabet=[0, 1]) + sage: (T.input_alphabet, T.output_alphabet) + ([0, 1], [2]) + sage: T = Transducer([(0, 0, 1, 2)], output_alphabet=[2, 3]) + sage: (T.input_alphabet, T.output_alphabet) + ([1], [2, 3]) + sage: T = Transducer([(0, 0, 1, 2)], input_alphabet=[0, 1], + ....: output_alphabet=[2, 3]) + sage: (T.input_alphabet, T.output_alphabet) + ([0, 1], [2, 3]) + .. automethod:: __call__ """ @@ -3142,9 +3174,6 @@ def __init__(self, self.add_transition(L) else: raise TypeError('Wrong input data for transition.') - if determine_alphabets is None and input_alphabet is None \ - and output_alphabet is None: - determine_alphabets = True elif hasattr(data, '__iter__'): # data is a something that is iterable, # items are transitions @@ -3157,15 +3186,17 @@ def __init__(self, self.add_transition(transition) else: raise TypeError('Wrong input data for transition.') - if determine_alphabets is None and input_alphabet is None \ - and output_alphabet is None: - determine_alphabets = True elif hasattr(data, '__call__'): self.add_from_transition_function(data) else: raise TypeError('Cannot decide what to do with data.') - if determine_alphabets: + if determine_alphabets is None and data is not None: + if input_alphabet is None: + self.determine_input_alphabet() + if output_alphabet is None: + self.determine_output_alphabet() + elif determine_alphabets: self.determine_alphabets() if with_final_word_out is not None: From 97f5b9d5a03bf61eb3ed53f936d6279e4fd4025f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 22 Oct 2015 17:32:01 +0200 Subject: [PATCH 1689/1872] Trac #19455: Implement FiniteStateMachine.coaccessible_components --- src/sage/combinat/finite_state_machine.py | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index d79c83937d0..9e264bbd57f 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -49,6 +49,7 @@ :meth:`~FiniteStateMachine.predecessors` | List of predecessors of a state :meth:`~FiniteStateMachine.induced_sub_finite_state_machine` | Induced sub-machine :meth:`~FiniteStateMachine.accessible_components` | Accessible components + :meth:`~FiniteStateMachine.coaccessible_components` | Coaccessible components :meth:`~FiniteStateMachine.final_components` | Final components (connected components which cannot be left again) @@ -7050,6 +7051,47 @@ def accessible(from_state, read): return result + def coaccessible_components(self): + r""" + Return the sub-machine induced by the coaccessible states of this + finite state machine. + + OUTPUT: + + A finite state machine of the same type as this finite state + machine. + + EXAMPLES:: + + sage: A = automata.ContainsWord([1, 1], + ....: input_alphabet=[0, 1]).complement().minimization().relabeled() + sage: A.transitions() + [Transition from 0 to 0: 0|-, + Transition from 0 to 0: 1|-, + Transition from 1 to 1: 0|-, + Transition from 1 to 2: 1|-, + Transition from 2 to 1: 0|-, + Transition from 2 to 0: 1|-] + sage: A.initial_states() + [1] + sage: A.final_states() + [1, 2] + sage: C = A.coaccessible_components() + sage: C.transitions() + [Transition from 1 to 1: 0|-, + Transition from 1 to 2: 1|-, + Transition from 2 to 1: 0|-] + + .. SEEALSO:: + :meth:`accessible_components`, + :meth:`induced_sub_finite_state_machine` + """ + DG = self.digraph().reverse() + coaccessible_states = DG.breadth_first_search( + [_.label() for _ in self.iter_final_states()]) + return self.induced_sub_finite_state_machine( + [self.state(_) for _ in coaccessible_states]) + # ************************************************************************* # creating new finite state machines # ************************************************************************* From c43b63a7181245275af01e4a803fd71549950b86 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 22 Oct 2015 17:32:38 +0200 Subject: [PATCH 1690/1872] Trac #19455: Minor fixes and link in docstring to accessible_components --- src/sage/combinat/finite_state_machine.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 9e264bbd57f..bf9728339d5 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -6989,7 +6989,7 @@ def epsilon_successors(self, state): def accessible_components(self): """ - Returns a new finite state machine with the accessible states + Return a new finite state machine with the accessible states of self and all transitions between those states. INPUT: @@ -7019,6 +7019,9 @@ def accessible_components(self): sage: F.accessible_components() Automaton with 1 state + .. SEEALSO:: + :meth:`coaccessible_components` + TESTS: Check whether input of length > 1 works:: From 4d22b1d5ff6fa0e677428d8f9362fc0eb16cc53d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 22 Oct 2015 17:32:57 +0200 Subject: [PATCH 1691/1872] Trac #19455: Simplify old docstring using coaccessible_components --- src/sage/combinat/finite_state_machine.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index bf9728339d5..136ed6211d0 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -11070,13 +11070,7 @@ def determinisation(self): sage: A = Automaton([(0, 1, 1), (0, 2, [1, 1]), (0, 3, [1, 1, 1]), ....: (1, 0, -1), (2, 0, -2), (3, 0, -3)], ....: initial_states=[0], final_states=[0, 1, 2, 3]) - sage: B = A.determinisation().relabeled() - sage: all(t.to_state.label() == 2 for t in - ....: B.state(2).transitions) - True - sage: B.state(2).is_final - False - sage: B.delete_state(2) # this is a sink + sage: B = A.determinisation().relabeled().coaccessible_components() sage: sorted(B.transitions()) [Transition from 0 to 1: 1|-, Transition from 1 to 0: -1|-, From 81cc8e491d6ff10a8117bc8216bee7d74886d033 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 22 Oct 2015 10:42:38 -0500 Subject: [PATCH 1692/1872] Fixing _Hom_ for highest weight crystals. --- src/sage/categories/highest_weight_crystals.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index 25b64b2e993..bdc8f1db5df 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -428,11 +428,24 @@ def _Hom_(self, Y, category=None, **options): to The crystal of tableaux of type ['A', 2] and shape(s) [[2, 1]] sage: type(H) + + TESTS: + + Check that we fallback first to trying a crystal homset + :trac:``:: + + sage: Binf = crystals.infinity.Tableaux(['A',2]) + sage: Bi = crystals.elementary.Elementary(Binf.cartan_type(), 1) + sage: tens = Bi.tensor(Binf) + sage: Hom(Binf, tens) + Set of Crystal Morphisms from ... """ if category is None: category = self.category() elif not category.is_subcategory(HighestWeightCrystals()): - raise TypeError("{} is not a subcategory of HighestWeightCrystals()".format(category)) + if not category.is_subcategory(Crystals()): + raise TypeError("{} is not a subcategory of Crystals()".format(category)) + return CrystalHomset(self, Y, category=category, **options) if Y not in Crystals(): raise TypeError("{} is not a crystal".format(Y)) return HighestWeightCrystalHomset(self, Y, category=category, **options) From 1cadb057ee7193dbb2ef8f09272a6174973c5aee Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 22 Oct 2015 10:45:14 -0500 Subject: [PATCH 1693/1872] Added ticket number... --- 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 bdc8f1db5df..4ed6665ec1d 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -432,7 +432,7 @@ def _Hom_(self, Y, category=None, **options): TESTS: Check that we fallback first to trying a crystal homset - :trac:``:: + (:trac:`19458`):: sage: Binf = crystals.infinity.Tableaux(['A',2]) sage: Bi = crystals.elementary.Elementary(Binf.cartan_type(), 1) From 444ed2d651625a4c88a8714de4976c2199ea3302 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 22 Oct 2015 10:51:04 -0500 Subject: [PATCH 1694/1872] A better fix to take advantage of the HW crystal property of the domain. --- src/sage/categories/highest_weight_crystals.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index 4ed6665ec1d..d2b99a7cbbc 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -442,10 +442,8 @@ def _Hom_(self, Y, category=None, **options): """ if category is None: category = self.category() - elif not category.is_subcategory(HighestWeightCrystals()): - if not category.is_subcategory(Crystals()): - raise TypeError("{} is not a subcategory of Crystals()".format(category)) - return CrystalHomset(self, Y, category=category, **options) + elif not category.is_subcategory(Crystals()): + raise TypeError("{} is not a subcategory of Crystals()".format(category)) if Y not in Crystals(): raise TypeError("{} is not a crystal".format(Y)) return HighestWeightCrystalHomset(self, Y, category=category, **options) From 3aa4bf2781f8ddb4a98316d252d0bc7a695f0c0a Mon Sep 17 00:00:00 2001 From: Stefan Witzel Date: Thu, 22 Oct 2015 19:10:03 +0200 Subject: [PATCH 1695/1872] Fix containment. Containment testing catches TypeError, ValueError, ZeroDivisionError. However, casting a Laurent series to a power series (when it isn't one) raises an ArithmeticError. This commit adds ArithmeticError to the list to make the following code work: L. = LaurentSeriesRing(GF(2)) R. = PolynomialRing(L) O = L.power_series_ring() S. = PolynomialRing(O) t**(-1)*x*y in S --- src/sage/structure/parent.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 8223d88a7ec..aed29a3ce93 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1305,7 +1305,7 @@ cdef class Parent(category_object.CategoryObject): # comparisons. return True return False - except (TypeError, ValueError, ZeroDivisionError): + except (TypeError, ValueError, ZeroDivisionError, ArithmeticError): return False cpdef coerce(self, x): From 697e2fbbf1473c45cfd1c047c9d8f7e760b11c2c Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 22 Oct 2015 20:45:38 +0200 Subject: [PATCH 1696/1872] Trac #19460: Implement FiniteStateMachine.number_of_words --- src/sage/combinat/finite_state_machine.py | 80 +++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index d79c83937d0..62deeef324c 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -110,6 +110,7 @@ :meth:`Automaton.is_equivalent` | Checks for equivalent automata :meth:`~FiniteStateMachine.is_Markov_chain` | Checks for a Markov chain :meth:`~FiniteStateMachine.is_monochromatic` | Checks whether the colors of all states are equal + :meth:`~FiniteStateMachine.number_of_words` | Determine the number of successful paths :meth:`~FiniteStateMachine.asymptotic_moments` | Main terms of expectation and variance of sums of labels :meth:`~FiniteStateMachine.moments_waiting_time` | Moments of the waiting time for first true output :meth:`~FiniteStateMachine.epsilon_successors` | Epsilon successors of a state @@ -9731,6 +9732,85 @@ def predecessors(self, state, valid_input=None): return(done) + def number_of_words(self, variable=sage.symbolic.ring.SR.var('n')): + r""" + Return the number of successful input words of given length. + + INPUT: + + - ``variable`` -- a symbol denoting the length of the words, + by default `n`. + + OUTPUT: + + A symbolic expression. + + EXAMPLES:: + + sage: NAFpm = Automaton([(0, 0, 0), (0, 1, 1), (0, 1, -1), (1, 0, 0)], + ....: initial_states=[0], + ....: final_states=[0, 1]) + sage: N = NAFpm.number_of_words(); N + 4/3*2^n - 1/3*(-1)^n + sage: all(len(list(NAFpm.language(_))) + ....: - len(list(NAFpm.language(_-1))) == N.subs(n=_) + ....: for _ in range(1, 6)) + True + sage: NAFp = Automaton([(0, 0, 0), (0, 1, 1), (1, 0, 0)], + ....: initial_states=[0], + ....: final_states=[0, 1]) + sage: N = NAFp.number_of_words(); N + 1.170820393249937?*1.618033988749895?^n + - 0.1708203932499369?*(-0.618033988749895?)^n + sage: all(len(list(NAFp.language(_))) + ....: - len(list(NAFp.language(_-1))) == N.subs(n=_) + ....: for _ in range(1, 6)) + True + + TESTS:: + + sage: A = Automaton([(0, 0, 0), (0, 1, 0)], + ....: initial_states=[0]) + sage: A.number_of_words() + Traceback (most recent call last): + ... + NotImplementedError: Finite State Machine must be deterministic. + """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + from sage.rings.arith import falling_factorial + from sage.rings.integer_ring import ZZ + from sage.rings.qqbar import QQbar + from sage.symbolic.ring import SR + + def jordan_block_power(block, exponent): + eigenvalue = SR(block[0, 0]) + return matrix(block.nrows(), + block.nrows(), + lambda i, j: eigenvalue**(exponent-(j-i))* + falling_factorial(exponent, j-i)/ZZ(j-i).factorial() + if j>= i else 0) + + def matrix_power(A, exponent): + J, T = A.jordan_form(QQbar, transformation=True) + assert T*J*T.inverse() == A + Jpower = matrix.block_diagonal( + [jordan_block_power(J.subdivision(j, j), exponent) + for j in range(len(J.subdivisions()[0])+1) ]) + P = Jpower.parent() + result = P(T)*Jpower*P(T).inverse() + assert all(result.subs(n=_) == A**_ for _ in range(5)) + return result + + if not self.is_deterministic(): + raise NotImplementedError("Finite State Machine must be deterministic.") + + left = vector(ZZ(s.is_initial) for s in self.iter_states()) + right = vector(ZZ(s.is_final) for s in self.iter_states()) + A = self.adjacency_matrix(entry=lambda t: 1) + return left*matrix_power(A, variable)*right + + def asymptotic_moments(self, variable=sage.symbolic.ring.SR.var('n')): r""" Returns the main terms of expectation and variance of the sum From 68a8208d9def8674dfe9711495f171b98349dbdc Mon Sep 17 00:00:00 2001 From: Ben Salisbury Date: Thu, 22 Oct 2015 16:59:54 -0400 Subject: [PATCH 1697/1872] fixed documentation errors and merged with develop --- src/sage/combinat/rigged_configurations/kr_tableaux.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/rigged_configurations/kr_tableaux.py b/src/sage/combinat/rigged_configurations/kr_tableaux.py index 5b2d43de0c1..15d6484ed6b 100644 --- a/src/sage/combinat/rigged_configurations/kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/kr_tableaux.py @@ -493,7 +493,7 @@ def s(self): @cached_method def kirillov_reshetikhin_crystal(self): """ - Return the corresponding KR crystal in the + Return the corresponding KR crystal in the :func:`Kashiwara-Nakashima model `. @@ -1711,7 +1711,7 @@ def f(self, i): def epsilon(self, i): r""" - Compute `\epsilon_i` of ``self``. + Compute `\varepsilon_i` of ``self``. .. TODO:: @@ -1734,7 +1734,7 @@ def epsilon(self, i): def phi(self, i): r""" - Compute `\phi_i` of ``self``. + Compute `\varphi_i` of ``self``. .. TODO:: From 55ab2c76e89a439db48fffb66b46cacd7854cd8f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 23 Oct 2015 09:16:27 +0200 Subject: [PATCH 1698/1872] Trac #19460: add another doctest --- src/sage/combinat/finite_state_machine.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 62deeef324c..d44b4105055 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9767,6 +9767,26 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n')): ....: for _ in range(1, 6)) True + The adjacency matrix of the following example is a Jordan matrix of size 3 to + the eigenvalue 4:: + + sage: J3 = Automaton([(0, 1, -1), (1, 2, -1)], + ....: initial_states=[0], + ....: final_states=[0, 1, 2]) + sage: for i in range(3): + ....: for j in range(4): + ....: new_transition = J3.add_transition(i, i, j) + sage: J3.adjacency_matrix(entry=lambda t: 1) + [4 1 0] + [0 4 1] + [0 0 4] + sage: N = J3.number_of_words(); N + 1/2*4^(n - 2)*(n - 1)*n + 4^(n - 1)*n + 4^n + sage: all(len(list(J3.language(_))) + ....: - len(list(J3.language(_-1))) == N.subs(n=_) + ....: for _ in range(1, 6)) + True + TESTS:: sage: A = Automaton([(0, 0, 0), (0, 1, 0)], From dadb126bd845b50e72643d59eb569834b24bf38e Mon Sep 17 00:00:00 2001 From: David Lucas Date: Fri, 23 Oct 2015 13:27:30 +0200 Subject: [PATCH 1699/1872] Removed lazy import for self_dual_codes_binary --- src/sage/coding/all.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 56c05cee834..105e7505def 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -33,6 +33,7 @@ "delsarte_bound_hamming_space",\ "delsarte_bound_additive_hamming_space"]) -lazy_import("sage.coding.sd_codes", "self_dual_codes_binary") +from sd_codes import self_dual_codes_binary +#lazy_import("sage.coding.sd_codes", "self_dual_codes_binary") lazy_import('sage.coding', 'codes_catalog', 'codes') lazy_import('sage.coding', 'channels_catalog', 'channels') From 7272942710a80866935ba073fe0e8697d7a3f137 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 23 Oct 2015 14:20:39 +0200 Subject: [PATCH 1700/1872] trac #19462: LinearCode.is_projective --- src/sage/coding/linear_code.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index f39e6e6d77c..69cf818c907 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1608,6 +1608,39 @@ def divisor(self): if len(S)>1: return GCD(S0) return 1 + def is_projective(self): + r""" + Test whether the code is projective. + + A linear code `C` over a a ring `R` is called *projective* when its dual + `Cd` has minimum weight `\geq 3`, i.e. when no two coordinate positions + of `C` are linearly independent (cf. definition 3 from [BS11] or 9.8.1 + from [BH12]). + + EXAMPLE:: + + sage: C = codes.BinaryGolayCode() + sage: C.is_projective() + True + sage: C.dual_code().minimum_distance() + 8 + + REFERENCE: + + .. [BS11] E, Byrne and A. Sneyd, + On the Parameters of Codes with Two Homogeneous Weights. + WCC 2011-Workshop on coding and cryptography, pp. 81-90. 2011. + https://hal.inria.fr/inria-00607341/document + """ + M = self.generator_matrix().transpose() + R = self.base_ring() + RM = [[row*r for r in R] for row in M] + for row in RM: + for x in row: + x.set_immutable() + RM = map(frozenset,RM) + return len(RM) == M.nrows() + def dual_code(self): r""" This computes the dual code `Cd` of the code `C`, From 5d188d4a0beb0022ad072068932222c6e23920ad Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 23 Oct 2015 09:55:12 -0500 Subject: [PATCH 1701/1872] Fixing pdf build. --- src/sage/combinat/root_system/coxeter_matrix.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 856fbb17e00..7344c72e159 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -1,5 +1,5 @@ """ -Coxeter matrices +Coxeter Matrices """ #***************************************************************************** # Copyright (C) 2007 Mike Hansen , @@ -46,7 +46,7 @@ class CoxeterMatrix(CoxeterType): .. MATH:: b_{ij} = \begin{cases} - m_{ij} & m_{ij} < 0 (\text{i.e.,} m_{ij} = \infty), + m_{ij} & m_{ij} < 0\ (\text{i.e., } m_{ij} = \infty), \\ -\cos\left( \frac{\pi}{m_{ij}} \right) & \text{otherwise}. \end{cases} From 4a8d9701a24ab0437ff4e8fbf517bb47443ef425 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 23 Oct 2015 20:34:57 +0200 Subject: [PATCH 1702/1872] trac #19462: Typo --- src/sage/coding/linear_code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 69cf818c907..f5b96faaee0 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1627,7 +1627,7 @@ def is_projective(self): REFERENCE: - .. [BS11] E, Byrne and A. Sneyd, + .. [BS11] E. Byrne and A. Sneyd, On the Parameters of Codes with Two Homogeneous Weights. WCC 2011-Workshop on coding and cryptography, pp. 81-90. 2011. https://hal.inria.fr/inria-00607341/document From 017089a65dc9ef2087762007590d43cde1832240 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 23 Oct 2015 23:12:56 +0200 Subject: [PATCH 1703/1872] trac #19462: Bugfix+doctest --- src/sage/coding/linear_code.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index f5b96faaee0..671fe1ce1f4 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1625,6 +1625,12 @@ def is_projective(self): sage: C.dual_code().minimum_distance() 8 + A non-projective code:: + + sage: C = codes.LinearCode(matrix(GF(2),[[1,0,1],[1,1,1]])) + sage: C.is_projective() + False + REFERENCE: .. [BS11] E. Byrne and A. Sneyd, @@ -1638,7 +1644,7 @@ def is_projective(self): for row in RM: for x in row: x.set_immutable() - RM = map(frozenset,RM) + RM = set(map(frozenset,RM)) return len(RM) == M.nrows() def dual_code(self): From 47d566defc92bb3ac9e7f7c8f4ac3e03965416dd Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 23 Oct 2015 18:36:14 -0300 Subject: [PATCH 1704/1872] Trac 19461: optimized code for fields --- src/sage/coding/linear_code.py | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 671fe1ce1f4..48e6c72e19e 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -216,6 +216,7 @@ import sage.modules.free_module as fm import sage.modules.module as module from sage.categories.modules import Modules +from sage.categories.fields import Fields from copy import copy from sage.interfaces.all import gap from sage.rings.finite_rings.constructor import FiniteField as GF @@ -1640,12 +1641,33 @@ def is_projective(self): """ M = self.generator_matrix().transpose() R = self.base_ring() - RM = [[row*r for r in R] for row in M] - for row in RM: - for x in row: - x.set_immutable() - RM = set(map(frozenset,RM)) - return len(RM) == M.nrows() + + if R in Fields(): + def projectivize(row): + if not row.is_zero(): + for i in range(len(row)): + if row[i]: + break + row = ~(row[i]) * row + row.set_immutable() + return row + else: + def projectivize(row): + orbit = set() + for r in R: + rrow = row*r + rrow.set_immutable() + orbit.add(rrow) + return frozenset(orbit) + + rows = set() + for row in M.rows(): + row = projectivize(row) + if row in rows: + return False + rows.add(row) + + return True def dual_code(self): r""" From 03f759a5326645822fc56e0156487bcf4238fde0 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 24 Oct 2015 07:31:34 +0200 Subject: [PATCH 1705/1872] trac #19462: Enforce the unwritten assumption --- src/sage/coding/linear_code.py | 38 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 48e6c72e19e..269e822cd0e 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -834,9 +834,18 @@ def __init__(self, base_field, length, default_encoder_name): Traceback (most recent call last): ... ValueError: You must set a valid encoder as default encoder for this code, by completing __init__.py + + A ring instead of a field:: + + sage: codes.LinearCode(IntegerModRing(4),matrix.ones(4)) + Traceback (most recent call last): + ... + ValueError: 'generator_matrix' must be defined on a field (not a ring) """ if not isinstance(length, (int, Integer)): raise ValueError("length must be a Python int or a Sage Integer") + if not base_field.is_field(): + raise ValueError("'base_field' must be a field (and {} is not one)".format(base_field)) self._length = Integer(length) if not default_encoder_name in self._registered_encoders: raise ValueError("You must set a valid encoder as default encoder for this code, by completing __init__.py") @@ -846,7 +855,6 @@ def __init__(self, base_field, length, default_encoder_name): 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 _latex_(self): """ Return a latex representation of ``self``. @@ -1642,23 +1650,14 @@ def is_projective(self): M = self.generator_matrix().transpose() R = self.base_ring() - if R in Fields(): - def projectivize(row): - if not row.is_zero(): - for i in range(len(row)): - if row[i]: - break - row = ~(row[i]) * row - row.set_immutable() - return row - else: - def projectivize(row): - orbit = set() - for r in R: - rrow = row*r - rrow.set_immutable() - orbit.add(rrow) - return frozenset(orbit) + def projectivize(row): + if not row.is_zero(): + for i in range(len(row)): + if row[i]: + break + row = ~(row[i]) * row + row.set_immutable() + return row rows = set() for row in M.rows(): @@ -3677,6 +3676,9 @@ def __init__(self, generator_matrix, d=None): ValueError: this linear code contains no non-zero vector """ base_ring = generator_matrix.base_ring() + if not base_ring.is_field(): + raise ValueError("'generator_matrix' must be defined on a field (not a 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 From 55bf4e470e93cf365bc37b1c1053bc24a8cf7f80 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sat, 24 Oct 2015 12:13:43 +0200 Subject: [PATCH 1706/1872] Fix continued fractions -> RR for negative numbers --- src/sage/rings/continued_fraction.py | 79 +++++++++++----------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index 3c50c17e610..fd86a4f6ebb 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -533,12 +533,8 @@ def __cmp__(self, other): def _mpfr_(self, R): r""" - Return a numerical approximation of ``self`` in the real mpfr ring ``R``. - - The output result is accurate: when the rounding mode of - ``R`` is 'RNDN' then the result is the nearest binary number of ``R`` to - ``self``. The other rounding mode are 'RNDD' (toward +infinity), 'RNDU' - (toward -infinity) and 'RNDZ' (toward zero). + Return a correctly-rounded numerical approximation of ``self`` + in the real mpfr ring ``R``. EXAMPLES:: @@ -591,41 +587,36 @@ def _mpfr_(self, R): TESTS: - We check that the rounding works as expected, at least in the rational - case:: + Check that the rounding works as expected (at least in the + rational case):: - sage: for _ in xrange(100): - ....: a = QQ.random_element(num_bound=1<<64) + sage: fields = [] + sage: for prec in [17, 24, 53, 128, 256]: + ....: for rnd in ['RNDN', 'RNDD', 'RNDU', 'RNDZ']: + ....: fields.append(RealField(prec=prec, rnd=rnd)) + sage: for n in range(3000): # long time + ....: a = QQ.random_element(num_bound=2^(n%100)) ....: cf = continued_fraction(a) - ....: for prec in 17,24,53,128,256: - ....: for rnd in 'RNDN','RNDD','RNDU','RNDZ': - ....: R = RealField(prec=prec, rnd=rnd) - ....: assert R(cf) == R(a) + ....: for R in fields: + ....: assert R(cf) == R(a) """ # 1. integer case if self.quotient(1) is Infinity: return R(self.quotient(0)) - # 2. negative numbers - # TODO: it is possible to deal with negative values. The only problem is - # that we need to find the good value for N (which involves - # self.quotient(k) for k=0,1,2) + rnd = R.rounding_mode() + + # 2. negative numbers: reduce to the positive case if self.quotient(0) < 0: - rnd = R.rounding_mode() - if rnd == 'RNDN' or rnd == 'RNDZ': - return -R(-self) - elif rnd == 'RNDD': - r = R(-self) - s,m,e = r.sign_mantissa_exponent() - if e < 0: - return -(R(m+1) >> (-e)) - return -(R(m+1) << e) - else: - r = R(-self) - s,m,e = r.sign_mantissa_exponent() - if e < 0: - return -(R(m-1) >> (-e)) - return -(R(m-1) << e) + sgn = -1 + self = -self + # Adjust rounding for change in sign + if rnd == 'RNDD': + rnd = 'RNDA' + elif rnd == 'RNDU': + rnd = 'RNDZ' + else: + sgn = 1 # 3. positive non integer if self.quotient(0) == 0: # 0 <= self < 1 @@ -655,8 +646,8 @@ def _mpfr_(self, R): assert m_odd.nbits() == R.prec() or m_even.nbits() == R.prec() - if m_even == m_odd: # no need to worry (we have a decimal number) - return R(m_even) >> N + if m_even == m_odd: # no need to worry (we have an exact number) + return R(sgn * m_even) >> N # check ordering # m_even/2^N <= p_even/q_even <= self <= p_odd/q_odd <= m_odd/2^N @@ -665,30 +656,24 @@ def _mpfr_(self, R): assert p_even / q_even <= p_odd / q_odd assert p_odd / q_odd <= m_odd / (ZZ_1 << N) - rnd = R.rounding_mode() if rnd == 'RNDN': # round to the nearest # in order to find the nearest approximation we possibly need to # augment our precision on convergents. while True: assert not(p_odd << (N+1) <= (2*m_odd-1) * q_odd) or not(p_even << (N+1) >= (2*m_even+1) * q_even) if p_odd << (N+1) <= (2*m_odd-1) * q_odd: - return R(m_even) >> N + return R(sgn * m_even) >> N if p_even << (N+1) >= (2*m_even+1) * q_even: - return R(m_odd) >> N + return R(sgn * m_odd) >> N k += 1 p_even = self.numerator(2*k) p_odd = self.numerator(2*k+1) q_even = self.denominator(2*k) q_odd = self.denominator(2*k+1) - elif rnd == 'RNDU': # round up (toward +infinity) - return R(m_odd) >> N - elif rnd == 'RNDD': # round down (toward -infinity) - return R(m_even) >> N - elif rnd == 'RNDZ': # round toward zero - if m_even.sign() == 1: - return R(m_even) >> N - else: - return R(m_odd) >> N + elif rnd == 'RNDU' or rnd == 'RNDA': # round up + return R(sgn * m_odd) >> N + elif rnd == 'RNDD' or rnd == 'RNDZ': # round down + return R(sgn * m_even) >> N else: raise ValueError("%s unknown rounding mode" % rnd) From d87a21253be535a01d9b03ac1db6a24257b5089a Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sat, 24 Oct 2015 12:51:00 +0200 Subject: [PATCH 1707/1872] Update to git-2.6.2 --- build/pkgs/git/checksums.ini | 6 +++--- build/pkgs/git/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/git/checksums.ini b/build/pkgs/git/checksums.ini index 88657651061..3a6e9681738 100644 --- a/build/pkgs/git/checksums.ini +++ b/build/pkgs/git/checksums.ini @@ -1,4 +1,4 @@ tarball=git-VERSION.tar.gz -sha1=150efeb9c016cb8d3e768a408f3f407d18d69661 -md5=edf994cf34cd3354dadcdfa6b4292335 -cksum=995320395 +sha1=ff32a94936309ca3f0e3d56e479e7510a3c1c925 +md5=da293290da69f45a86a311ad3cd43dc8 +cksum=2025246710 diff --git a/build/pkgs/git/package-version.txt b/build/pkgs/git/package-version.txt index 276cbf9e285..097a15a2af3 100644 --- a/build/pkgs/git/package-version.txt +++ b/build/pkgs/git/package-version.txt @@ -1 +1 @@ -2.3.0 +2.6.2 From e7c62eab7b7e49a4dae2d66e8d3394bb6f09ac18 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Sat, 24 Oct 2015 15:53:44 +0200 Subject: [PATCH 1708/1872] 19450: qepcad-B.1.69 fails to install --- build/pkgs/qepcad/spkg-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/qepcad/spkg-install b/build/pkgs/qepcad/spkg-install index 1f7566b703c..6da4a409be9 100755 --- a/build/pkgs/qepcad/spkg-install +++ b/build/pkgs/qepcad/spkg-install @@ -33,7 +33,7 @@ saclib="$SAGE_LOCAL/lib/saclib" export saclib qe=$(pwd -P) export qe -$MAKE opt +$MAKE -j1 opt if [ $? -ne 0 ]; then echo >&2 "Error building qepcad." From 913a0c14f45142e5f80579c58147174daa18f27b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 24 Oct 2015 12:29:16 -0500 Subject: [PATCH 1709/1872] Fixing doctest/tab issues from merge. --- src/sage/misc/functional.py | 2 +- src/sage/modules/free_module.py | 10 +++++----- src/sage/tensor/modules/finite_rank_free_module.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index d106f65d494..5920e8e9c7b 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -125,7 +125,7 @@ def category(x): sage: V = VectorSpace(QQ,3) sage: category(V) Category of finite dimensional vector spaces with basis over - (quotient fields and metric spaces) + (quotient fields and metric spaces) """ try: return x.category() diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index ab004a9409e..ef19b53f0e5 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -687,18 +687,18 @@ def __init__(self, base_ring, rank, degree, sparse=False, (finite fields and subquotients of monoids and quotients of semigroups) sage: V = QQ^4; V.category() Category of finite dimensional vector spaces with basis over - (quotient fields and metric spaces) + (quotient fields and metric spaces) sage: V = GF(5)**20; V.category() Category of finite dimensional vector spaces with basis over (finite fields and subquotients of monoids - and quotients of semigroups) + and quotients of semigroups) sage: FreeModule(ZZ,3).category() Category of finite dimensional modules with basis over (euclidean domains and infinite enumerated sets - and metric spaces) + and metric spaces) sage: (QQ^0).category() Category of finite dimensional vector spaces with basis - over quotient fields + over (quotient fields and metric spaces) TESTS:: @@ -3075,7 +3075,7 @@ def _Hom_(self, Y, category): Set of Morphisms from Vector space of dimension 2 over Rational Field to Ambient free module of rank 3 over the principal ideal domain Integer Ring in Category of finite dimensional vector spaces with basis over - (quotient fields and metric spaces) + (quotient fields and metric spaces) """ if Y.base_ring().is_field(): import vector_space_homspace diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 1176bd2a8bd..15a1fea98e2 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -369,7 +369,7 @@ class :class:`~sage.modules.free_module.FreeModule_generic` Vector space of dimension 3 over Rational Field sage: V.category() Category of finite dimensional vector spaces with basis - over (quotient fields and metric spaces) + over (quotient fields and metric spaces) sage: V is QQ^3 True sage: V.basis() From 4b8767f4a13612b2ae60e04c43bb2f0c64f32ae4 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 24 Oct 2015 21:21:49 +0200 Subject: [PATCH 1710/1872] small changes in docstring (blank lines, comma, stop) --- src/sage/combinat/finite_state_machine.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 72f20eef9e2..314855ceb47 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -5194,8 +5194,9 @@ def determine_input_alphabet(self, reset=True): ([0, 1, 2], None) .. SEEALSO:: - :meth:`determine_output_alphabet` - :meth:`determine_alphabets` + + :meth:`determine_output_alphabet`, + :meth:`determine_alphabets`. """ if reset: ain = set() @@ -5244,8 +5245,9 @@ def determine_output_alphabet(self, reset=True): (None, [0, 1, 4]) .. SEEALSO:: - :meth:`determine_input_alphabet` - :meth:`determine_alphabets` + + :meth:`determine_input_alphabet`, + :meth:`determine_alphabets`. """ if reset: aout = set() @@ -5297,8 +5299,9 @@ def determine_alphabets(self, reset=True): ([0, 1, 2], [0, 1, 4]) .. SEEALSO:: - :meth:`determine_input_alphabet` - :meth:`determine_output_alphabet` + + :meth:`determine_input_alphabet`, + :meth:`determine_output_alphabet`. """ self.determine_input_alphabet(reset) self.determine_output_alphabet(reset) From 500628b8fa311267c900ec34126762e5d029d038 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 24 Oct 2015 15:32:07 -0500 Subject: [PATCH 1711/1872] Made KR crystals robust against python int's. --- src/sage/combinat/crystals/kirillov_reshetikhin.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index 7475bd6d9c0..6e5d34913ca 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -3040,13 +3040,21 @@ def classical_decomposition(self): sage: K = crystals.KirillovReshetikhin(['D',4,1],3,2) sage: K.classical_decomposition() The crystal of tableaux of type ['D', 4] and shape(s) [[1, 1, 1, -1]] + + TESTS: + + Check that this is robust against python ints:: + + sage: K = crystals.KirillovReshetikhin(['D',4,1], 4, int(1)) + sage: K.classical_crystal + The crystal of tableaux of type ['D', 4] and shape(s) [[1/2, 1/2, 1/2, 1/2]] """ C = self.cartan_type().classical() - s = self.s() + s = QQ(self.s()) if self.r() == C.n: - c = [s/2]*C.n + c = [s/QQ(2)]*C.n else: - c = [s/2]*(C.n-1)+[-s/2] + c = [s/QQ(2)]*(C.n-1)+[-s/QQ(2)] return CrystalOfTableaux(C, shape = c) def dynkin_diagram_automorphism(self, i): From b26bd8a5373e07a89ab5e72b66018599f4db17fb Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 24 Oct 2015 22:57:10 +0200 Subject: [PATCH 1712/1872] Minor improvements --- .../finite_dimensional_algebra_element.py | 7 ++- src/sage/algebras/jordan_algebra.py | 4 +- .../algebras/steenrod/steenrod_algebra.py | 4 +- src/sage/algebras/weyl_algebra.py | 11 ++-- src/sage/categories/enumerated_sets.py | 62 +++++++++---------- 5 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py index 21e8ce2e954..c17d4be8f4c 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py @@ -136,13 +136,16 @@ def matrix(self): def monomial_coefficients(self, copy=True): """ - Return a dictionary whose keys are indices of basis in + Return a dictionary whose keys are indices of basis elements in the support of ``self`` and whose values are the corresponding coefficients. INPUT: - - ``copy`` -- ignored + - ``copy`` -- (default: ``True``) if ``self`` is internally + represented by a dictionary ``d``, then make a copy of ``d``; + if ``False``, then this can cause undesired behavior by + mutating ``d`` EXAMPLES:: diff --git a/src/sage/algebras/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index eabcc3463ca..0f024e61113 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -558,7 +558,7 @@ def _rmul_(self, other): def monomial_coefficients(self, copy=True): """ - Return a dictionary whose keys are indices of basis in + Return a dictionary whose keys are indices of basis elements in the support of ``self`` and whose values are the corresponding coefficients. @@ -961,7 +961,7 @@ def _rmul_(self, other): def monomial_coefficients(self, copy=True): """ - Return a dictionary whose keys are indices of basis in + Return a dictionary whose keys are indices of basis elements in the support of ``self`` and whose values are the corresponding coefficients. diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index e934d8d3308..e98c6d2474e 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -1569,12 +1569,12 @@ def counit_on_basis(self, t): def _milnor_on_basis(self, t): r""" - Convert the tuple t in the current basis to an element in the + Convert the tuple ``t`` in the current basis to an element in the Milnor basis. INPUT: - - t - tuple, representing basis element in the current basis. + - ``t`` - tuple, representing basis element in the current basis. OUTPUT: element of the Steenrod algebra with the Milnor basis diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index e60c72402bc..5fc6edbc113 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -405,7 +405,8 @@ def _lmul_(self, other): def monomial_coefficients(self, copy=True): """ Return a dictionary which has the basis keys in the support - of ``self`` and their corresponding coefficients as values. + of ``self`` as keys and their corresponding coefficients + as values. INPUT: @@ -767,10 +768,12 @@ def basis(self): """ n = self._n from sage.combinat.integer_lists.nn import IntegerListsNN - I = IntegerListsNN(length=n*2) + from sage.categories.cartesian_product import cartesian_product + I = IntegerListsNN(length=n, element_constructor=tuple) + J = cartesian_product([I, I]) one = self.base_ring().one() - f = lambda x: self.element_class(self, {(tuple(x[:n]),tuple(x[n:])): one}) - return Family(I, f, name="basis map") + f = lambda x: self.element_class(self, {(x[0], x[1]): one}) + return Family(J, f, name="basis map") @cached_method def algebra_generators(self): diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 1cbe3103953..398264af692 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -23,7 +23,7 @@ class EnumeratedSets(Category_singleton): together with a canonical enumeration of its elements; conceptually, this is very similar to an immutable list. The main difference lies in the names and the return type of the methods, - and of course the fact that the list of element is not supposed to + and of course the fact that the list of elements is not supposed to be expanded in memory. Whenever possible one should use one of the two sub-categories :class:`FiniteEnumeratedSets` or :class:`InfiniteEnumeratedSets`. @@ -39,7 +39,7 @@ class EnumeratedSets(Category_singleton): - ``S.cardinality()``: the number of elements of the set. This is the equivalent for ``len`` on a list except that the return value is specified to be a Sage :class:`Integer` or - ``infinity``, instead of a Python ``int``; + ``infinity``, instead of a Python ``int``. - ``iter(S)``: an iterator for the elements of the set; @@ -48,15 +48,15 @@ class EnumeratedSets(Category_singleton): predictably too large to be expanded in memory. - ``S.unrank(n)``: the ``n-th`` element of the set when ``n`` is a sage - ``Integer``. This is the equivanlent for ``l[n]`` on a list. + ``Integer``. This is the equivalent for ``l[n]`` on a list. - ``S.rank(e)``: the position of the element ``e`` in the set; This is equivalent to ``l.index(e)`` for a list except that the return value is specified to be a Sage :class:`Integer`, - instead of a Python ``int``; + instead of a Python ``int``. - ``S.first()``: the first object of the set; it is equivalent to - ``S.unrank(0)``; + ``S.unrank(0)``. - ``S.next(e)``: the object of the set which follows ``e``; It is equivalent to ``S.unrank(S.rank(e)+1)``. @@ -148,12 +148,12 @@ def __iter__(self): An iterator for the enumerated set. ``iter(self)`` allows the combinatorial class to be treated as an - iterable. This if the default implementation from the category - ``EnumeratedSets()`` it just goes through the iterator of the set + iterable. This is the default implementation from the category + ``EnumeratedSets()``; it just goes through the iterator of the set to count the number of objects. By decreasing order of priority, the second column of the - following array shows which methods is used to define + following array shows which method is used to define ``__iter__``, when the methods of the first column are overloaded: +------------------------+---------------------------------+ @@ -166,53 +166,53 @@ def __iter__(self): | ``list` | ``_iterator_from_next`` | +------------------------+---------------------------------+ - If non of these are provided raise a ``NotImplementedError`` + If none of these are provided, raise a ``NotImplementedError``. EXAMPLES:: We start with an example where nothing is implemented:: sage: class broken(UniqueRepresentation, Parent): - ... def __init__(self): - ... Parent.__init__(self, category = EnumeratedSets()) - ... + ....: def __init__(self): + ....: Parent.__init__(self, category = EnumeratedSets()) + ....: sage: it = iter(broken()); [next(it), next(it), next(it)] Traceback (most recent call last): ... NotImplementedError: iterator called but not implemented - Here is what happends when ``first`` and ``next`` are implemeted:: + Here is what happens when ``first`` and ``next`` are implemented:: sage: class set_first_next(UniqueRepresentation, Parent): - ... def __init__(self): - ... Parent.__init__(self, category = EnumeratedSets()) - ... def first(self): - ... return 0 - ... def next(self, elt): - ... return elt+1 - ... + ....: def __init__(self): + ....: Parent.__init__(self, category = EnumeratedSets()) + ....: def first(self): + ....: return 0 + ....: def next(self, elt): + ....: return elt+1 + ....: sage: it = iter(set_first_next()); [next(it), next(it), next(it)] [0, 1, 2] Let us try with ``unrank``:: sage: class set_unrank(UniqueRepresentation, Parent): - ... def __init__(self): - ... Parent.__init__(self, category = EnumeratedSets()) - ... def unrank(self, i): - ... return i + 5 - ... + ....: def __init__(self): + ....: Parent.__init__(self, category = EnumeratedSets()) + ....: def unrank(self, i): + ....: return i + 5 + ....: sage: it = iter(set_unrank()); [next(it), next(it), next(it)] [5, 6, 7] Let us finally try with ``list``:: sage: class set_list(UniqueRepresentation, Parent): - ... def __init__(self): - ... Parent.__init__(self, category = EnumeratedSets()) - ... def list(self): - ... return [5, 6, 7] - ... + ....: def __init__(self): + ....: Parent.__init__(self, category = EnumeratedSets()) + ....: def list(self): + ....: return [5, 6, 7] + ....: sage: it = iter(set_list()); [next(it), next(it), next(it)] [5, 6, 7] @@ -257,7 +257,7 @@ def is_empty(self): def list(self): """ - Return an error since the cardinality of self is not known. + Return an error since the cardinality of ``self`` is not known. EXAMPLES:: From b32e479bffac439f3cfb561027dfebc871d01528 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 24 Oct 2015 23:29:35 +0200 Subject: [PATCH 1713/1872] further changes (mostly doc) --- src/sage/algebras/weyl_algebra.py | 18 ++++++++++++++++-- src/sage/categories/algebras_with_basis.py | 11 ++++++++++- .../finite_dimensional_modules_with_basis.py | 11 +++++++---- src/sage/categories/modules_with_basis.py | 8 ++++++-- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 5fc6edbc113..c8ed19e72aa 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -433,6 +433,8 @@ def __iter__(self): """ Return an iterator of ``self``. + This is the iterator of ``self.list()``. + EXAMPLES:: sage: W. = DifferentialWeylAlgebra(QQ) @@ -448,6 +450,11 @@ def list(self): """ Return ``self`` as a list. + This list consists of pairs `(m, c)`, where `m` is a pair of + tuples indexing a basis element of ``self``, and `c` is the + coordinate of ``self`` corresponding to this basis element. + (Only nonzero coordinates are shown.) + EXAMPLES:: sage: W. = DifferentialWeylAlgebra(QQ) @@ -765,12 +772,19 @@ def basis(self): sage: [next(it) for i in range(20)] [1, x, y, dx, dy, x^2, x*y, x*dx, x*dy, y^2, y*dx, y*dy, dx^2, dx*dy, dy^2, x^3, x^2*y, x^2*dx, x^2*dy, x*y^2] + sage: dx, dy = W.differentials() + sage: (dx*x).monomials() + [1, x*dx] + sage: B[(x*y).monomials()[0]] + x*y + sage: sorted((dx*x).monomial_coefficients().items()) + [(((0, 0), (0, 0)), 1), (((1, 0), (1, 0)), 1)] """ n = self._n from sage.combinat.integer_lists.nn import IntegerListsNN from sage.categories.cartesian_product import cartesian_product - I = IntegerListsNN(length=n, element_constructor=tuple) - J = cartesian_product([I, I]) + I = IntegerListsNN(length=2*n) + J = I.map(lambda u : (tuple(u[:n]), tuple(u[n:]))) one = self.base_ring().one() f = lambda x: self.element_class(self, {(x[0], x[1]): one}) return Family(J, f, name="basis map") diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index 786d4a7cb87..ee0ad3865ae 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -209,6 +209,14 @@ def __invert__(self): inversed this way. It is correct though for graded connected algebras with basis. + .. WARNING:: + + This might produce a result which does not belong to + the parent of ``self``, yet believes to do so. For + instance, inverting 2 times the unity will produce 1/2 + times the unity, even if 1/2 is not in the base ring. + Handle with care. + EXAMPLES:: sage: C = AlgebrasWithBasis(QQ).example() @@ -234,7 +242,8 @@ def __invert__(self): class CartesianProducts(CartesianProductsCategory): """ - The category of algebras with basis, constructed as cartesian products of algebras with basis + The category of algebras with basis, constructed as cartesian + products of algebras with basis. Note: this construction give the direct products of algebras with basis. See comment in :class:`Algebras.CartesianProducts diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 72b94186759..5dccfac10ee 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -269,19 +269,22 @@ def dense_coefficient_list(self, order=None): """ Return a list of *all* coefficients of ``self``. + By default, this list is ordered in the same way as the + indexing set of the basis of the parent of ``self``. + INPUT: - ``order`` -- (optional) an ordering of the basis indexing set EXAMPLES:: - sage: v = vector([0, -1, -2]) + sage: v = vector([0, -1, -3]) sage: v.dense_coefficient_list() - [0, -1, -2] + [0, -1, -3] sage: v.dense_coefficient_list([2,1,0]) - [-2, -1, 0] + [-3, -1, 0] sage: sorted(v.coefficients()) - [-2, -1] + [-3, -1] """ if order is None: try: diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 43e55d108ba..28548de670e 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -194,9 +194,13 @@ def is_abelian(self): Graded = LazyImport('sage.categories.graded_modules_with_basis', 'GradedModulesWithBasis') Super = LazyImport('sage.categories.super_modules_with_basis', 'SuperModulesWithBasis') + # To implement a module_with_basis you need to implement the + # following methods: + # - On the parent class, either basis() or an _indices attribute and + # monomial(). + # - On the element class, monomial_coefficients(). + class ParentMethods: - # To implement a module_with_basis you need to implement either - # basis() or an _indices attribute and monomial(). @cached_method def basis(self): """ From dbb5789a5daf6bd54a4b315ecb8fa77f20a848c6 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 24 Oct 2015 23:53:49 +0200 Subject: [PATCH 1714/1872] Further fixes --- src/sage/algebras/iwahori_hecke_algebra.py | 4 +- src/sage/algebras/weyl_algebra.py | 2 +- src/sage/categories/algebras_with_basis.py | 1 + .../categories/hopf_algebras_with_basis.py | 1 + src/sage/categories/modules_with_basis.py | 156 +++++++++++++----- src/sage/combinat/free_module.py | 9 +- src/sage/geometry/linear_expression.py | 23 +-- src/sage/modules/free_module.py | 24 +-- src/sage/modules/free_module_element.pyx | 25 ++- 9 files changed, 175 insertions(+), 70 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 3bd17b63960..90fb74a604f 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -457,7 +457,7 @@ def __init__(self, W, q1, q2, base_ring): sage: R. = QQ[] sage: H = IwahoriHeckeAlgebra("A2", q1, q2=q2, base_ring=Frac(R)) - sage: TestSuite(H).run() + sage: TestSuite(H.a_realization()).run() """ self._W = W self._cartan_type = W.cartan_type() @@ -1954,7 +1954,7 @@ def __init__(self, W): EXAMPLES:: sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard("A2") - sage: TestSuite(H).run() + sage: TestSuite(H.a_realization()).run() """ self._W = W self._cartan_type = W.cartan_type() diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index c8ed19e72aa..f6707a9b053 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -775,7 +775,7 @@ def basis(self): sage: dx, dy = W.differentials() sage: (dx*x).monomials() [1, x*dx] - sage: B[(x*y).monomials()[0]] + sage: B[(x*y).support()[0]] x*y sage: sorted((dx*x).monomial_coefficients().items()) [(((0, 0), (0, 0)), 1), (((1, 0), (1, 0)), 1)] diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index ee0ad3865ae..710263e3915 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -81,6 +81,7 @@ class AlgebrasWithBasis(CategoryWithAxiom_over_base_ring): running ._test_elements_eq_transitive() . . . pass running ._test_elements_neq() . . . pass running ._test_eq() . . . pass + running ._test_keytype() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_one() . . . pass running ._test_pickling() . . . pass diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index fb01c14d369..1ebefe17b6f 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -90,6 +90,7 @@ class HopfAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): running ._test_elements_eq_transitive() . . . pass running ._test_elements_neq() . . . pass running ._test_eq() . . . pass + running ._test_keytype() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_one() . . . pass running ._test_pickling() . . . pass diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 28548de670e..19334d53087 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -161,7 +161,7 @@ def _call_(self, x): Vector space of dimension 3 over Rational Field If ``x`` itself is not a module with basis, but there is a - canonical one associated to it, the later is returned:: + canonical one associated to it, the latter is returned:: sage: CQ(AbelianVariety(Gamma0(37))) # indirect doctest Vector space of dimension 4 over Rational Field @@ -244,8 +244,9 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, - ``on_basis`` -- a function `f` from `I` to `Y` - ``diagonal`` -- a function `d` from `I` to `R` - ``function`` -- a function `f` from `X` to `Y` - - ``matrix`` -- a matrix of size `\dim X \times \dim Y` - or `\dim Y \times \dim X` + - ``matrix`` -- a matrix of size `\dim Y \times \dim X` + (if the keyword ``side`` is set to ``'left'``) or + `\dim Y \times \dim X` (if this keyword is ``'right'``) Further options include: @@ -787,6 +788,36 @@ def tensor(*parents): """ return parents[0].__class__.Tensor(parents, category = tensor.category_from_parents(parents)) + def cardinality(self): + """ + Return the cardinality of ``self``. + + EXAMPLES:: + + sage: S = SymmetricGroupAlgebra(QQ, 4) + sage: S.cardinality() + +Infinity + sage: S = SymmetricGroupAlgebra(GF(2), 4) # not tested -- MRO bug :trac:`15475` + sage: S.cardinality() # not tested -- MRO bug :trac:`15475` + 16777216 + sage: S.cardinality().factor() # not tested -- MRO bug :trac:`15475` + 2^24 + + sage: E. = ExteriorAlgebra(QQ) + sage: E.cardinality() + +Infinity + sage: E. = ExteriorAlgebra(GF(3)) + sage: E.cardinality() + 81 + + sage: s = SymmetricFunctions(GF(2)).s() + sage: s.cardinality() + +Infinity + """ + if self.dimension() == Infinity: + return Infinity + return self.base_ring().cardinality() ** self.dimension() + def monomial(self, i): """ Return the basis element indexed by ``i``. @@ -816,19 +847,21 @@ def _sum_of_monomials(self, indices): sage: F._sum_of_monomials(['a', 'b']) B['a'] + B['b'] """ - # TODO: optimize by calling directly _from_dict if we - # know that all indices are distinct as sum_of_terms; - # otherwise, maybe call dict_addition directly + # This is the generic implementation. When implementing a + # concrete instance of a module with basis, you probably want + # to override it with something faster. return self.sum(self.monomial(index) for index in indices) @lazy_attribute def sum_of_monomials(self): """ - Return the sum of the corresponding basis elements. + Return the sum of the basis elements with indices in + ``indices``. INPUT: - - ``indices`` -- an list (or iterable) of indices of basis elements + - ``indices`` -- an list (or iterable) of indices of basis + elements EXAMPLES:: @@ -844,7 +877,7 @@ def sum_of_monomials(self): sage: F.sum_of_monomials A map to Free module generated by {'a', 'b', 'c'} over Rational Field """ - # domain = sets of self.combinatorial_class(), + # domain = iterables of basis indices of self. return PoorManMap(self._sum_of_monomials, codomain = self) def monomial_or_zero_if_none(self, i): @@ -870,6 +903,10 @@ def term(self, index, coeff=None): - ``index`` -- the index of a basis element - ``coeff`` -- an element of the coefficient ring (default: one) + OUTPUT: + + ``coeff * B[index]``, where ``B`` is the basis of ``self``. + EXAMPLES:: sage: m = matrix([[0,1],[1,1]]) @@ -891,6 +928,11 @@ def sum_of_terms(self, terms): - ``terms`` -- a list (or iterable) of pairs ``(index, coeff)`` + OUTPUT: + + Sum of ``coeff * B[index]`` over all ``(index, coeff)`` in + ``terms``, where ``B`` is the basis of ``self``. + EXAMPLES:: sage: m = matrix([[0,1],[1,1]]) @@ -914,8 +956,8 @@ def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): ``coeff`` in ``self.base_ring()`` - ``factor_on_left`` -- (optional) if ``True``, the coefficients - are multiplied from the left if ``False``, the coefficients are - multiplied from the right + are multiplied from the left; if ``False``, the coefficients + are multiplied from the right EXAMPLES:: @@ -940,16 +982,15 @@ def _apply_module_morphism(self, x, on_basis, codomain=False): - ``x`` -- a element of ``self`` - - ``on_basis`` -- a function that takes in a combinatorial - object indexing a basis element and returns an element of the - codomain + - ``on_basis`` -- a function that takes in an object indexing + a basis element and returns an element of the codomain - - ``codomain`` -- (optional) the codomain of the morphism, otherwise - it is computed using :func:`on_basis` + - ``codomain`` -- (optional) the codomain of the morphism (by + default, it is computed using :func:`on_basis`) If ``codomain`` is not specified, then the function tries to compute the codomain of the module morphism by finding the image - of one of the elements in the support, hence :func:`on_basis` + of one of the elements in the support; hence :func:`on_basis` should return an element whose parent is the codomain. EXAMPLES:: @@ -991,22 +1032,21 @@ def _apply_module_morphism(self, x, on_basis, codomain=False): codomain = on_basis(key).parent() except Exception: raise ValueError('codomain could not be determined') - mc = x.monomial_coefficients(copy=False) + if hasattr( codomain, 'linear_combination' ): + mc = x.monomial_coefficients(copy=False) return codomain.linear_combination( (on_basis(key), coeff) for key, coeff in mc.iteritems() ) else: return_sum = codomain.zero() for key, coeff in x._monomial_coefficients.iteritems(): - return_sum += coeff * on_basis( key ) + return_sum += coeff * on_basis(key) return return_sum def _apply_module_endomorphism(self, x, on_basis): """ - This takes in a function from the basis elements to the elements of - self and applies it linearly to a. Note that - _apply_module_endomorphism does not require multiplication on - self to be defined. + This takes in a function ``on_basis`` from the basis indices + to the elements of ``self``, and applies it linearly to ``x``. EXAMPLES:: @@ -1015,7 +1055,28 @@ def _apply_module_endomorphism(self, x, on_basis): sage: s._apply_module_endomorphism( s([2,1]) + s([1,1,1]), f) 2*s[2, 1] + 2*s[3] """ - return self.linear_combination( ( on_basis( key ), coeff ) for key, coeff in x._monomial_coefficients.iteritems() ) + return self.linear_combination( ( on_basis(key), coeff ) + for key, coeff in + x._monomial_coefficients.iteritems() ) + + def _test_keytype(self, **options): + """ + Check that the keys returned by + ``self.element_class.monomial_coefficients()`` are of the + same type as the keys of ``self.basis()``. + + See also: :class:`TestSuite`. + + EXAMPLES:: + + sage: ZZ._test_characteristic() + """ + tester = self._tester(**options) + xs = self.some_elements() + B = self.basis() + for x in xs: + t = [(B[key], coeff) for key, coeff in x.monomial_coefficients().iteritems()] + assert self.linear_combination(t) == x class ElementMethods: # TODO: Define the appropriate element methods here (instead of in @@ -1032,9 +1093,9 @@ class ElementMethods: @abstract_method def monomial_coefficients(self, copy=True): """ - Return a dictionary whose keys are indices of basis in - the support of ``self`` and whose values are the corresponding - coefficients. + Return a dictionary whose keys are indices of basis elements + in the support of ``self`` and whose values are the + corresponding coefficients. INPUT: @@ -1097,9 +1158,19 @@ def __getitem__(self, m): def coefficient(self, m): """ - Return the coefficient of ``m`` in ``self`` and raises an error + Return the coefficient of ``m`` in ``self`` and raise an error if ``m`` is not in the basis indexing set. + INPUT: + + - ``m`` -- a basis index of the parent of ``self`` + + OUTPUT: + + The ``B[m]``-coordinate of ``self`` with respect to the basis + ``B``. Here, ``B`` denotes the given basis of the parent of + ``self``. + EXAMPLES:: sage: s = CombinatorialFreeModule(QQ, Partitions()) @@ -1119,7 +1190,7 @@ def coefficient(self, m): ... AssertionError: [2, 1] should be an element of Partitions - Test that coefficient also works for those parents that do + Test that ``coefficient`` also works for those parents that do not yet have an element_class:: sage: G = DihedralGroup(3) @@ -1168,8 +1239,8 @@ def is_zero(self): def __len__(self): """ - Return the number of basis elements of self with nonzero - coefficients. + Return the number of basis elements whose coefficients in + ``self`` are nonzero. EXAMPLES:: @@ -1192,8 +1263,8 @@ def __len__(self): def length(self): """ - Return the number of basis elements of self with nonzero - coefficients. + Return the number of basis elements whose coefficients in + ``self`` are nonzero. EXAMPLES:: @@ -1214,9 +1285,11 @@ def length(self): def support(self): """ - Return a list of the combinatorial objects indexing the basis - elements of ``self`` which non-zero coefficients (in an - arbitrary order). + Return a list of the objects indexing the basis of + ``self.parent()`` whose corresponding coefficients of + ``self`` are non-zero. + + This method returns these objects in an arbitrary order. EXAMPLES:: @@ -1242,6 +1315,10 @@ def monomials(self): Return a list of the monomials of ``self`` (in an arbitrary order). + The monomials of an element `a` are defined to be the basis + elements whose corresponding coefficients of `a` are + non-zero. + EXAMPLES:: sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) @@ -1254,12 +1331,12 @@ def monomials(self): [] """ P = self.parent() - one = P.base_ring().one() return [P.monomial(key) for key in self.support()] def terms(self): """ - Return a list of the terms of ``self`` (in an arbitrary order). + Return a list of the (non-zero) terms of ``self`` (in an + arbitrary order). .. SEEALSO:: :meth:`monomials` @@ -1298,6 +1375,9 @@ def coefficients(self, sort=True): sage: f = B['a'] - 3*B['c'] sage: f.coefficients() [1, -3] + sage: f = B['c'] - 3*B['a'] + sage: f.coefficients() + [-3, 1] :: diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 4c0dbebe007..b5f7a3d29b1 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -556,7 +556,7 @@ def _vector_(self, new_base_ring=None): INPUT: - - ``new_base_ring`` -- a ring (default: None) + - ``new_base_ring`` -- a ring (default: ``None``) OUTPUT: a dense :func:`FreeModule` vector @@ -597,8 +597,8 @@ def _vector_(self, new_base_ring=None): sage: a == QS3.from_vector(a.to_vector()) True - If ''new_base_ring'' is specified, then a vector over - ''new_base_ring'' is returned:: + If ``new_base_ring`` is specified, then a vector over + ``new_base_ring`` is returned:: sage: a._vector_(RDF) (2.0, 0.0, 0.0, 0.0, 0.0, 4.0) @@ -629,7 +629,8 @@ def _vector_(self, new_base_ring=None): def _acted_upon_(self, scalar, self_on_left=False): """ - Return the action of ``scalar`` on ``self``. + Return the action of ``scalar`` (an element of the base ring) on + ``self``. EXAMPLES:: diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index b1863336e45..febb8838840 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -2,8 +2,8 @@ Linear Expressions A linear expression is just a linear polynomial in some (fixed) -variables. This class only implements linear expressions for others to -use. +variables (allowing a nonzero constant term). This class only implements +linear expressions for others to use. EXAMPLES:: @@ -12,6 +12,8 @@ Module of linear expressions in variables x, y, z over Rational Field sage: x + 2*y + 3*z + 4 x + 2*y + 3*z + 4 + sage: L(4) + 0*x + 0*y + 0*z + 4 You can also pass coefficients and a constant term to construct linear expressions:: @@ -23,7 +25,7 @@ sage: L([4, 1, 2, 3]) # note: constant is first in single-tuple notation x + 2*y + 3*z + 4 -The linear expressions are a module under the base ring, so you can +The linear expressions are a module over the base ring, so you can add them and multiply them with scalars:: sage: m = x + 2*y + 3*z + 4 @@ -91,9 +93,9 @@ def __init__(self, parent, coefficients, constant, check=True): self._const = constant if check: if self._coeffs.parent() is not self.parent().ambient_module(): - raise ValueError("cofficients are not in the ambient module") + raise ValueError("coefficients are not in the ambient module") if not self._coeffs.is_immutable(): - raise ValueError("cofficients are not immutable") + raise ValueError("coefficients are not immutable") if self._const.parent() is not self.parent().base_ring(): raise ValueError("the constant is not in the base ring") @@ -165,7 +167,7 @@ def coefficients(self): def monomial_coefficients(self, copy=True): """ - Return a dictionary whose keys are indices of basis in + Return a dictionary whose keys are indices of basis elements in the support of ``self`` and whose values are the corresponding coefficients. @@ -178,12 +180,13 @@ def monomial_coefficients(self, copy=True): sage: from sage.geometry.linear_expression import LinearExpressionModule sage: L. = LinearExpressionModule(QQ) sage: linear = L([1, 2, 3], 4) - sage: linear.monomial_coefficients() - {0: 1, 1: 2, 2: 3, 'b': 4} + sage: sorted(linear.monomial_coefficients().items() + ((0, 1), (1, 2), (2, 3), ('b', 4)} """ zero = self.parent().base_ring().zero() d = {i: v for i,v in enumerate(self._coeffs) if v != zero} - d['b'] = self._const + if self._const != zero: + d['b'] = self._const return d def _repr_vector(self, variable='x'): @@ -538,7 +541,7 @@ def ngens(self): @cached_method def gens(self): """ - Return the generators. + Return the generators of ``self``. OUTPUT: diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index ef19b53f0e5..c688167722d 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -654,7 +654,8 @@ class FreeModule_generic(Module): def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, category=None): """ - Create the free module of given rank over the given base_ring. + Create the free module of given rank ``rank`` over the given base + ring ``base_ring``. INPUT: @@ -672,10 +673,11 @@ def __init__(self, base_ring, rank, degree, sparse=False, - ``category`` -- category (default: None) If ``base_ring`` is a field, then the default category is the - category of vector spaces over that field; otherwise it is the - category of free modules over that ring. In addition, the - category is intersected with the category of finite enumerated - sets if the ring is finite or the rank is 0. + category of finite-dimensional vector spaces over that field; + otherwise it is the category of finite-dimensional free modules + over that ring. In addition, the category is intersected with the + category of finite enumerated sets if the ring is finite or the + rank is 0. EXAMPLES:: @@ -908,7 +910,7 @@ def _an_element_(self): def _element_constructor_(self, x, coerce=True, copy=True, check=True): r""" - Create an element of this free module from x. + Create an element of this free module from ``x``. The ``coerce`` and ``copy`` arguments are passed on to the underlying element constructor. If @@ -973,7 +975,7 @@ def _element_constructor_(self, x, coerce=True, copy=True, check=True): def is_submodule(self, other): """ - Return True if self is a submodule of other. + Return ``True`` if ``self`` is a submodule of ``other``. EXAMPLES:: @@ -1007,11 +1009,9 @@ def is_submodule(self, other): sage: M.is_submodule(N) True - Since basis() is not implemented in general, submodule testing does - not work for all PID's. However, trivial cases are already used - (and useful) for coercion, e.g. - - :: + Since :meth:`basis` is not implemented in general, submodule + testing does not work for all PID's. However, trivial cases are + already used (and useful) for coercion, e.g. :: sage: QQ(1/2) * vector(ZZ['x']['y'],[1,2,3,4]) (1/2, 1, 3/2, 2) diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index a514f642902..6a63c1f3427 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -2079,9 +2079,16 @@ cdef class FreeModuleElement(Vector): # abstract base class """ Return dictionary of nonzero entries of ``self``. + More precisely, this returns a dictionary whose keys are indices + of basis elements in the support of ``self`` and whose values are + the corresponding coefficients. + INPUT: - - ``copy`` -- bool (default: ``True``) + - ``copy`` -- (default: ``True``) if ``self`` is internally + represented by a dictionary ``d``, then make a copy of ``d``; + if ``False``, then this can cause undesired behavior by + mutating ``d`` OUTPUT: @@ -2092,8 +2099,11 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: v = vector([0,0,0,0,1/2,0,3/14]) sage: v.dict() {4: 1/2, 6: 3/14} + sage: sorted(v.support()) + [4, 6] - In some cases when copy=False, we get back a dangerous reference:: + In some cases, when ``copy=False``, we get back a dangerous + reference:: sage: v = vector({0:5, 2:3/7}, sparse=True) sage: v.dict(copy=False) @@ -4838,9 +4848,16 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): """ Return dictionary of nonzero entries of ``self``. + More precisely, this returns a dictionary whose keys are indices + of basis elements in the support of ``self`` and whose values are + the corresponding coefficients. + INPUT: - - ``copy`` -- bool (default: ``True``) + - ``copy`` -- (default: ``True``) if ``self`` is internally + represented by a dictionary ``d``, then make a copy of ``d``; + if ``False``, then this can cause undesired behavior by + mutating ``d`` OUTPUT: @@ -4851,6 +4868,8 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): sage: v = vector([0,0,0,0,1/2,0,3/14], sparse=True) sage: v.dict() {4: 1/2, 6: 3/14} + sage: sorted(v.support()) + [4, 6] """ if copy: return dict(self._entries) From e2fb14a393beb5e40519df8cf7ae06b077a398b0 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 25 Oct 2015 01:46:17 +0200 Subject: [PATCH 1715/1872] remove _test_keytype since submodules of free modules are currently failing it --- src/sage/algebras/iwahori_hecke_algebra.py | 4 ++-- src/sage/categories/algebras_with_basis.py | 1 - .../categories/hopf_algebras_with_basis.py | 1 - src/sage/categories/modules_with_basis.py | 19 ------------------- 4 files changed, 2 insertions(+), 23 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 90fb74a604f..3bd17b63960 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -457,7 +457,7 @@ def __init__(self, W, q1, q2, base_ring): sage: R. = QQ[] sage: H = IwahoriHeckeAlgebra("A2", q1, q2=q2, base_ring=Frac(R)) - sage: TestSuite(H.a_realization()).run() + sage: TestSuite(H).run() """ self._W = W self._cartan_type = W.cartan_type() @@ -1954,7 +1954,7 @@ def __init__(self, W): EXAMPLES:: sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard("A2") - sage: TestSuite(H.a_realization()).run() + sage: TestSuite(H).run() """ self._W = W self._cartan_type = W.cartan_type() diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index 710263e3915..ee0ad3865ae 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -81,7 +81,6 @@ class AlgebrasWithBasis(CategoryWithAxiom_over_base_ring): running ._test_elements_eq_transitive() . . . pass running ._test_elements_neq() . . . pass running ._test_eq() . . . pass - running ._test_keytype() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_one() . . . pass running ._test_pickling() . . . pass diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index 1ebefe17b6f..fb01c14d369 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -90,7 +90,6 @@ class HopfAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): running ._test_elements_eq_transitive() . . . pass running ._test_elements_neq() . . . pass running ._test_eq() . . . pass - running ._test_keytype() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_one() . . . pass running ._test_pickling() . . . pass diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 19334d53087..21e98a51ded 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1059,25 +1059,6 @@ def _apply_module_endomorphism(self, x, on_basis): for key, coeff in x._monomial_coefficients.iteritems() ) - def _test_keytype(self, **options): - """ - Check that the keys returned by - ``self.element_class.monomial_coefficients()`` are of the - same type as the keys of ``self.basis()``. - - See also: :class:`TestSuite`. - - EXAMPLES:: - - sage: ZZ._test_characteristic() - """ - tester = self._tester(**options) - xs = self.some_elements() - B = self.basis() - for x in xs: - t = [(B[key], coeff) for key, coeff in x.monomial_coefficients().iteritems()] - assert self.linear_combination(t) == x - class ElementMethods: # TODO: Define the appropriate element methods here (instead of in # subclasses). These methods should be consistent with those on From fc7e50975777e4f50e0c345cfdb0cf42f12740c5 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 25 Oct 2015 08:37:06 +0100 Subject: [PATCH 1716/1872] trac #19462: ring->field --- src/sage/coding/linear_code.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 269e822cd0e..3e02363662b 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1621,10 +1621,10 @@ def is_projective(self): r""" Test whether the code is projective. - A linear code `C` over a a ring `R` is called *projective* when its dual - `Cd` has minimum weight `\geq 3`, i.e. when no two coordinate positions - of `C` are linearly independent (cf. definition 3 from [BS11] or 9.8.1 - from [BH12]). + A linear code `C` over a field is called *projective* when its dual `Cd` + has minimum weight `\geq 3`, i.e. when no two coordinate positions of + `C` are linearly independent (cf. definition 3 from [BS11] or 9.8.1 from + [BH12]). EXAMPLE:: @@ -1648,7 +1648,7 @@ def is_projective(self): https://hal.inria.fr/inria-00607341/document """ M = self.generator_matrix().transpose() - R = self.base_ring() + R = self.base_field() def projectivize(row): if not row.is_zero(): From 38351ac2691d8c3c374207a037bfafc8bc674a67 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 25 Oct 2015 15:01:40 +0100 Subject: [PATCH 1717/1872] Less fragile git interface doctests --- src/sage/dev/git_interface.py | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/sage/dev/git_interface.py b/src/sage/dev/git_interface.py index 8f8148987b9..3cebbe75805 100644 --- a/src/sage/dev/git_interface.py +++ b/src/sage/dev/git_interface.py @@ -211,16 +211,7 @@ def _execute(self, cmd, *args, **kwds): sage: git._execute('status',foo=True) # --foo is not a valid parameter Traceback (most recent call last): ... - GitError: git returned with non-zero exit code (129) for - "git -c user.email=doc@test.test -c user.name=doctest status --foo". - output to stderr: error: unknown option `foo' - usage: git status [options] [--] ... - - -v, --verbose be verbose - -s, --short show status concisely - -b, --branch show branch information - --porcelain machine-readable output - ... + GitError: git returned with non-zero exit code ... """ exit_code, stdout, stderr, cmd = self._run_git(cmd, args, kwds) if exit_code: @@ -251,16 +242,7 @@ def _execute_silent(self, cmd, *args, **kwds): sage: git._execute_silent('status',foo=True) # --foo is not a valid parameter Traceback (most recent call last): ... - GitError: git returned with non-zero exit code (129) for - "git -c user.email=doc@test.test -c user.name=doctest status --foo". - output to stderr: error: unknown option `foo' - usage: git status [options] [--] ... - - -v, --verbose be verbose - -s, --short show status concisely - -b, --branch show branch information - --porcelain machine-readable output - ... + GitError: git returned with non-zero exit code ... """ exit_code, stdout, stderr, cmd = self._run_git(cmd, args, kwds) if exit_code: @@ -546,9 +528,7 @@ def get_state(self): sage: git._execute_supersilent('rebase', 'branch2') Traceback (most recent call last): ... - GitError: git returned with non-zero exit code (1) for - "git -c user.email=doc@test.test -c user.name=doctest rebase branch2". - ... + GitError: git returned with non-zero exit code ... sage: git.get_state() ('rebase',) sage: git.super_silent.rebase(abort=True) From 96004dfa8a3368fe4f2fe122268744d9f6e4bf79 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 25 Oct 2015 09:26:46 -0500 Subject: [PATCH 1718/1872] Darij... --- src/sage/geometry/linear_expression.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index febb8838840..d52f0ddb04e 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -180,8 +180,8 @@ def monomial_coefficients(self, copy=True): sage: from sage.geometry.linear_expression import LinearExpressionModule sage: L. = LinearExpressionModule(QQ) sage: linear = L([1, 2, 3], 4) - sage: sorted(linear.monomial_coefficients().items() - ((0, 1), (1, 2), (2, 3), ('b', 4)} + sage: sorted(linear.monomial_coefficients().items()) + [(0, 1), (1, 2), (2, 3), ('b', 4)] """ zero = self.parent().base_ring().zero() d = {i: v for i,v in enumerate(self._coeffs) if v != zero} From b8094cb4e3c8fc23816c74c3b27a4226cb7ce86c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 25 Oct 2015 11:14:35 -0500 Subject: [PATCH 1719/1872] Doing some things with the new constructor for robustness (and why I asked for it). --- src/sage/categories/regular_crystals.py | 7 +++---- src/sage/combinat/partition.py | 10 ++++------ .../rigged_configurations/bij_abstract_class.py | 2 +- src/sage/combinat/rigged_configurations/bij_type_D.py | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index 9fa8085633b..69230c68ba6 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -453,8 +453,7 @@ def wt_zero(x): if checker(y): edges.append([x, y, i]) from sage.graphs.all import DiGraph - G = DiGraph(edges) - G.add_vertices(X) + G = DiGraph([X, edges], format="vertices_and_edges", immutable=True) if have_dot2tex(): G.set_latex_options(format="dot2tex", edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring) @@ -874,8 +873,8 @@ def dual_equivalence_class(self, index_set=None): if y not in visited: todo.add(y) from sage.graphs.graph import Graph - G = Graph(edges, multiedges=True) - G.add_vertices(visited) + G = Graph([visited, edges], format="vertices_and_edges", + immutable=True, multiedges=True) if have_dot2tex(): G.set_latex_options(format="dot2tex", edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index ea7bbb65773..2a9b05a9482 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -4635,14 +4635,12 @@ def coloring(i): if directed: from sage.graphs.digraph import DiGraph - G = DiGraph(edges, multiedges=True) - G.add_vertices(T) # Add isolated vertices - self._DDEG = G.copy(immutable=True) + self._DDEG = DiGraph([T, edges], format="vertices_and_edges", + immutable=True, multiedges=True) else: from sage.graphs.graph import Graph - G = Graph(edges, multiedges=True) - G.add_vertices(T) # Add isolated vertices - self._DEG = G.copy(immutable=True) + self._DEG = Graph([T, edges], format="vertices_and_edges", + immutable=True, multiedges=True) return self.dual_equivalence_graph(directed, coloring) ############## diff --git a/src/sage/combinat/rigged_configurations/bij_abstract_class.py b/src/sage/combinat/rigged_configurations/bij_abstract_class.py index cb745eb36a8..8a12d5ce409 100644 --- a/src/sage/combinat/rigged_configurations/bij_abstract_class.py +++ b/src/sage/combinat/rigged_configurations/bij_abstract_class.py @@ -432,7 +432,7 @@ def run(self, verbose=False, build_graph=False): self._graph.pop(0) # Remove the dummy at the start from sage.graphs.digraph import DiGraph from sage.graphs.dot2tex_utils import have_dot2tex - self._graph = DiGraph(self._graph) + self._graph = DiGraph(self._graph, format="list_of_edges") if have_dot2tex(): self._graph.set_latex_options(format="dot2tex", edge_labels=True) diff --git a/src/sage/combinat/rigged_configurations/bij_type_D.py b/src/sage/combinat/rigged_configurations/bij_type_D.py index a191ed3e0df..5b660866e24 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D.py @@ -542,7 +542,7 @@ def run(self, verbose=False, build_graph=False): self._graph.pop(0) # Remove the dummy at the start from sage.graphs.digraph import DiGraph from sage.graphs.dot2tex_utils import have_dot2tex - self._graph = DiGraph(self._graph) + self._graph = DiGraph(self._graph, format="list_of_edges") if have_dot2tex(): self._graph.set_latex_options(format="dot2tex", edge_labels=True) From d94f997e5d8082d80cf07067cab8ae13d67fe866 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 25 Oct 2015 12:50:48 -0500 Subject: [PATCH 1720/1872] Some last compatibility issues with modules with basis (hopefully). --- src/sage/categories/modules_with_basis.py | 9 +++++---- src/sage/modules/with_basis/morphism.py | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 21e98a51ded..aa4dc15e85c 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1039,7 +1039,8 @@ def _apply_module_morphism(self, x, on_basis, codomain=False): for key, coeff in mc.iteritems() ) else: return_sum = codomain.zero() - for key, coeff in x._monomial_coefficients.iteritems(): + mc = x.monomial_coefficients(copy=False) + for key, coeff in mc.iteritems(): return_sum += coeff * on_basis(key) return return_sum @@ -1055,9 +1056,9 @@ def _apply_module_endomorphism(self, x, on_basis): sage: s._apply_module_endomorphism( s([2,1]) + s([1,1,1]), f) 2*s[2, 1] + 2*s[3] """ - return self.linear_combination( ( on_basis(key), coeff ) - for key, coeff in - x._monomial_coefficients.iteritems() ) + mc = x.monomial_coefficients(copy=False) + return self.linear_combination( (on_basis(key), coeff) + for key, coeff in mc.iteritems() ) class ElementMethods: # TODO: Define the appropriate element methods here (instead of in diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 4fb91391cc0..17f1d211f2f 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -380,10 +380,11 @@ def __call__(self, *args): x = args[self._position] assert(x.parent() is self.domain()) + mc = x.monomial_coefficients(copy=False) if self._is_module_with_basis_over_same_base_ring: - return self.codomain().linear_combination( (self._on_basis(*(before+(index,)+after)), coeff ) for (index, coeff) in args[self._position] ) + return self.codomain().linear_combination( (self._on_basis(*(before+(index,)+after)), coeff ) for (index, coeff) in mc.iteritems() ) else: - return sum(( coeff * self._on_basis(*(before+(index,)+after)) for (index, coeff) in args[self._position]), self._zero) + return sum(( coeff * self._on_basis(*(before+(index,)+after)) for (index, coeff) in mc.iteritems() ), self._zero) # As per the specs of Map, we should in fact implement _call_. # However we currently need to abuse Map.__call__ (which strict From 1b88d3fec4bfc544875c2aae4879eb4684ddd3f5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 25 Oct 2015 15:35:33 -0500 Subject: [PATCH 1721/1872] Changing indices for Weyl algebras. --- src/sage/algebras/weyl_algebra.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index f6707a9b053..af3f004c2aa 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -783,11 +783,11 @@ def basis(self): n = self._n from sage.combinat.integer_lists.nn import IntegerListsNN from sage.categories.cartesian_product import cartesian_product - I = IntegerListsNN(length=2*n) - J = I.map(lambda u : (tuple(u[:n]), tuple(u[n:]))) + elt_map = lambda u : (tuple(u[:n]), tuple(u[n:])) + I = IntegerListsNN(length=2*n, element_constructor=elt_map) one = self.base_ring().one() f = lambda x: self.element_class(self, {(x[0], x[1]): one}) - return Family(J, f, name="basis map") + return Family(I, f, name="basis map") @cached_method def algebra_generators(self): From 299fbb32269c30f61f1814e70806b28de1a0e57a Mon Sep 17 00:00:00 2001 From: Stefan Witzel Date: Mon, 26 Oct 2015 14:38:14 +0100 Subject: [PATCH 1722/1872] Alternate fix to containment. Undid the last change: Parent.__contains__() does not catch ArithmeticError any more. Instead LaurentSeries.power_series() now throws TypeError rather than ArithmeticError if it is not a power series. --- src/sage/rings/laurent_series_ring_element.pyx | 13 +++++++++++-- src/sage/structure/parent.pyx | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 3f58a281bd6..0c5c2803eeb 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -1231,10 +1231,19 @@ cdef class LaurentSeries(AlgebraElement): sage: f.power_series() Traceback (most recent call last): ... - ArithmeticError: self is a not a power series + TypeError: self is a not a power series + + TESTS: + + sage: L. = LaurentSeriesRing(GF(2)) + sage: R. = PolynomialRing(L) + sage: O = L.power_series_ring() + sage: S. = PolynomialRing(O) + sage: t**(-1)*x*y in S + False """ if self.__n < 0: - raise ArithmeticError, "self is a not a power series" + raise TypeError, "self is a not a power series" u = self.__u t = u.parent().gen() return t**(self.__n) * u diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index aed29a3ce93..8223d88a7ec 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1305,7 +1305,7 @@ cdef class Parent(category_object.CategoryObject): # comparisons. return True return False - except (TypeError, ValueError, ZeroDivisionError, ArithmeticError): + except (TypeError, ValueError, ZeroDivisionError): return False cpdef coerce(self, x): From 8e690e2a13b8c266f0d6a46c7c9b01a01aa48933 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 26 Oct 2015 09:37:13 -0500 Subject: [PATCH 1723/1872] Some hacks and FIXMEs. --- src/sage/combinat/sf/sf.py | 9 ++++++++- src/sage/combinat/sf/sfa.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 50261f61c96..895aad981c7 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -21,7 +21,9 @@ #***************************************************************************** from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.categories.all import Rings, GradedHopfAlgebras +from sage.categories.rings import Rings +from sage.categories.graded_hopf_algebras import GradedHopfAlgebras +from sage.categories.fields import Fields from sage.combinat.partition import Partitions from sage.combinat.free_module import CombinatorialFreeModule from sage.rings.rational_field import QQ @@ -831,6 +833,11 @@ def __init__(self, R): """ assert(R in Rings()) + # FIXME: We just automatically check that the base ring is a field to + # prevent category refinement during construction of the category, + # thus preventing the MRO issues noted in #15536, #15475 (and likely others). + # Thus fix the MRO/category-refinement issue and remove the line below. + R in Fields() self._base = R # Won't be needed when CategoryObject won't override anymore base_ring Parent.__init__(self, category = GradedHopfAlgebras(R).WithRealizations()) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index d03fedff474..abaeb313c80 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -382,9 +382,13 @@ def super_categories(self): sage: Sym = SymmetricFunctions(QQ) sage: bases = SymmetricFunctionsBases(Sym) sage: bases.super_categories() - [Category of commutative hopf algebras with basis over Rational Field, - Category of realizations of Symmetric Functions over Rational Field] + [Category of realizations of Symmetric Functions over Rational Field, + Category of commutative hopf algebras with basis over Rational Field, + Join of Category of realizations of hopf algebras over Rational Field + and Category of graded algebras over Rational Field] """ + # FIXME: The last one should also be commutative, but this triggers a + # KeyError when doing the C3 algorithm!!! cat = HopfAlgebras(self.base().base_ring()) return [self.base().Realizations(), cat.Commutative().WithBasis(), @@ -1315,7 +1319,6 @@ def super_categories(self): sage: bases.super_categories() [Category of bases of Symmetric Functions over Rational Field, Join of Category of hopf algebras with basis over Rational Field - and Category of realizations of hopf algebras over Rational Field and Category of filtered algebras with basis over Rational Field and Category of commutative algebras over Rational Field] """ @@ -1361,11 +1364,8 @@ def super_categories(self): sage: Sym = SymmetricFunctions(QQ) sage: bases = GradedSymmetricFunctionsBases(Sym) sage: bases.super_categories() - [Join of Category of hopf algebras with basis over Rational Field - and Category of realizations of hopf algebras over Rational Field - and Category of graded algebras over Rational Field - and Category of commutative algebras over Rational Field, - Category of filtered bases of Symmetric Functions over Rational Field] + [Category of filtered bases of Symmetric Functions over Rational Field, + Category of commutative graded hopf algebras with basis over Rational Field] """ cat = HopfAlgebras(self.base().base_ring()).Commutative().WithBasis().Graded() return [FilteredSymmetricFunctionsBases(self.base()), cat] From 24d7616c04340a622e62c6fee32105b4b051ef3d Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 26 Oct 2015 18:48:06 +0100 Subject: [PATCH 1724/1872] Use proper relative path for mathjax --- build/pkgs/notebook/package-version.txt | 2 +- .../patches/jupyter_notebook_config.py | 2 +- build/pkgs/notebook/patches/mathjax.patch | 73 +++++++++++++++++++ build/pkgs/notebook/spkg-install | 14 +++- 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 build/pkgs/notebook/patches/mathjax.patch diff --git a/build/pkgs/notebook/package-version.txt b/build/pkgs/notebook/package-version.txt index 61d8a2af785..f0cd2d909bb 100644 --- a/build/pkgs/notebook/package-version.txt +++ b/build/pkgs/notebook/package-version.txt @@ -1 +1 @@ -4.0.4.p1 +4.0.4.p2 diff --git a/build/pkgs/notebook/patches/jupyter_notebook_config.py b/build/pkgs/notebook/patches/jupyter_notebook_config.py index 3bf63a1649a..99c7801b76c 100644 --- a/build/pkgs/notebook/patches/jupyter_notebook_config.py +++ b/build/pkgs/notebook/patches/jupyter_notebook_config.py @@ -4,4 +4,4 @@ # needs to have the mathjax_url set to wherever your distribution # installs mathjax. -c.NotebookApp.mathjax_url = '../nbextensions/mathjax/MathJax.js' +c.NotebookApp.mathjax_url = 'nbextensions/mathjax/MathJax.js' diff --git a/build/pkgs/notebook/patches/mathjax.patch b/build/pkgs/notebook/patches/mathjax.patch new file mode 100644 index 00000000000..1237afef049 --- /dev/null +++ b/build/pkgs/notebook/patches/mathjax.patch @@ -0,0 +1,73 @@ +commit 17b364389182e667d64db93db2dcecc84dada8f9 +Author: Jeroen Demeyer +Date: Mon Oct 26 18:29:42 2015 +0100 + + Interpret mathjax_url relative to base_url + +diff --git a/notebook/base/handlers.py b/notebook/base/handlers.py +index 30b1223..127a6ba 100644 +--- a/notebook/base/handlers.py ++++ b/notebook/base/handlers.py +@@ -32,7 +32,7 @@ from ipython_genutils.path import filefind + from ipython_genutils.py3compat import string_types + + import notebook +-from notebook.utils import is_hidden, url_path_join, url_escape ++from notebook.utils import is_hidden, url_path_join, url_is_absolute, url_escape + from notebook.services.security import csp_report_uri + + #----------------------------------------------------------------------------- +@@ -155,7 +155,10 @@ class IPythonHandler(AuthenticatedHandler): + + @property + def mathjax_url(self): +- return self.settings.get('mathjax_url', '') ++ url = self.settings.get('mathjax_url', '') ++ if not url or url_is_absolute(url): ++ return url ++ return url_path_join(self.base_url, url) + + @property + def base_url(self): +diff --git a/notebook/notebookapp.py b/notebook/notebookapp.py +index bfbe467..c74e4eb 100644 +--- a/notebook/notebookapp.py ++++ b/notebook/notebookapp.py +@@ -658,9 +658,7 @@ class NotebookApp(JupyterApp): + def _mathjax_url_default(self): + if not self.enable_mathjax: + return u'' +- static_url_prefix = self.tornado_settings.get("static_url_prefix", +- url_path_join(self.base_url, "static") +- ) ++ static_url_prefix = self.tornado_settings.get("static_url_prefix", "static") + return url_path_join(static_url_prefix, 'components', 'MathJax', 'MathJax.js') + + def _mathjax_url_changed(self, name, old, new): +diff --git a/notebook/utils.py b/notebook/utils.py +index 9ba424c..ee9c6ac 100644 +--- a/notebook/utils.py ++++ b/notebook/utils.py +@@ -13,9 +13,10 @@ import sys + from distutils.version import LooseVersion + + try: +- from urllib.parse import quote, unquote ++ from urllib.parse import quote, unquote, urlparse + except ImportError: + from urllib import quote, unquote ++ from urlparse import urlparse + + from ipython_genutils import py3compat + +@@ -39,6 +40,10 @@ def url_path_join(*pieces): + if result == '//': result = '/' + return result + ++def url_is_absolute(url): ++ """Determine whether a given URL is absolute""" ++ return urlparse(url).path.startswith("/") ++ + def path2url(path): + """Convert a local file path to a URL""" + pieces = [ quote(p) for p in path.split(os.sep) ] diff --git a/build/pkgs/notebook/spkg-install b/build/pkgs/notebook/spkg-install index 10759a4d973..a42c3ed659d 100755 --- a/build/pkgs/notebook/spkg-install +++ b/build/pkgs/notebook/spkg-install @@ -1,6 +1,18 @@ #!/usr/bin/env bash -cd src && python setup.py install +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 + echo >&2 "Error applying '$patch'" + exit 1 + fi +done + + +python setup.py install # Install the Jupyter notebook configuration ETC_JUPYTER="$SAGE_ETC"/jupyter From 4943cda8c49a4336284861b9beb92bf731954d7e Mon Sep 17 00:00:00 2001 From: Stefan Witzel Date: Tue, 27 Oct 2015 09:45:44 +0100 Subject: [PATCH 1725/1872] Changed power series example to match reality. The fact that LaurentSeries.power_series() raises a TypeError rather than an ArithmeticError is now reflected in the example of PowerSeriesRing_generic._element_constructor_(). The TypeError is raised in the argument form TypeError("error"). --- src/sage/rings/laurent_series_ring_element.pyx | 2 +- src/sage/rings/power_series_ring.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 0c5c2803eeb..61f34798050 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -1243,7 +1243,7 @@ cdef class LaurentSeries(AlgebraElement): False """ if self.__n < 0: - raise TypeError, "self is a not a power series" + raise TypeError("self is a not a power series") u = self.__u t = u.parent().gen() return t**(self.__n) * u diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index ff081f23dd4..d24ec2c935d 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -720,7 +720,7 @@ def _element_constructor_(self, f, prec=infinity, check=True): sage: P(1/q) Traceback (most recent call last): ... - ArithmeticError: self is a not a power series + TypeError: self is a not a power series It is checked that the precision is non-negative (see :trac:`19409`):: From fb6299eec28a317a64bfc38b8474c816d06cdc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 27 Oct 2015 10:52:39 +0200 Subject: [PATCH 1726/1872] Removed a test for having attribute _hasse_diagram. --- src/sage/combinat/posets/posets.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 61365be62aa..d1012915fdc 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5922,8 +5922,6 @@ def is_induced_subposet(self, other): sage: P.is_induced_subposet(Poset()) False """ - if not hasattr(other, 'hasse_diagram'): - raise TypeError('the input is not a finite poset') if not self._is_facade or not other._is_facade: raise TypeError('the function is not defined on non-facade posets') # TODO: When we have decided if From ade22b1abf6842fac14a3c61da43189d1b0279d4 Mon Sep 17 00:00:00 2001 From: Marco Mancini Date: Tue, 27 Oct 2015 11:09:06 +0100 Subject: [PATCH 1727/1872] Created Singleton class Parallelism more generic. Persist problem with doc and tests --- src/sage/parallel/parallelism.py | 268 ++++++++++++++++++ src/sage/tensor/modules/all.py | 1 - src/sage/tensor/modules/comp.py | 58 ++-- src/sage/tensor/modules/parallel_utilities.py | 194 ------------- 4 files changed, 297 insertions(+), 224 deletions(-) create mode 100644 src/sage/parallel/parallelism.py delete mode 100644 src/sage/tensor/modules/parallel_utilities.py diff --git a/src/sage/parallel/parallelism.py b/src/sage/parallel/parallelism.py new file mode 100644 index 00000000000..f2b90c9312c --- /dev/null +++ b/src/sage/parallel/parallelism.py @@ -0,0 +1,268 @@ +r""" +Parallelization utilities + +This module defines + +- the singleton class :class:`Parallelism` to gather the information + relative to the parallelization (basically the number of processes to be used) +- the global functions :func:`set_nproc_tensor` and :func:`get_nproc_tensor` to be used in + a Sage session for managing the number of processes involved in the + parallelization. + +Some examples of parallelization are provided in the documentation +of :meth:`sage.tensor.modules.comp.Components.contract`. + +AUTHORS: + +- Marco Mancini, Eric Gourgoulhon, Michal Bejger (2015): initial version + +""" + +#****************************************************************************** +# Copyright (C) 2015 Marco Mancini +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.structure.sage_object import SageObject +from sage.misc.fast_methods import Singleton +from sage.parallel.ncpus import ncpus +from sage.rings.integer import Integer + +class Parallelism(Singleton, SageObject): + r""" + Singleton class for managing the number of processes used in parallel + computations involved in tensor algebra. + + EXAMPLES:: + + sage: from sage.parallel.parallelism import Parallelism + sage: Parallelism().get('tensor') + 1 + sage: Parallelism().set('tensor',4) + sage: Parallelism().get('tensor') + 4 + sage: Parallelism().set('tensor',1) + sage: Parallelism().get('tensor') + 1 + + """ + def __init__(self): + r""" + Only a single instance of this class is created (singleton model) + + TEST:: + + sage: from sage.parallel.parallelism import Parallelism + sage: TP = Parallelism() + sage: TP + Number of cpu used = 1 + + Test of the singleton character:: + + sage: Parallelism() is TP + True + + The test suite is passed:: + + sage: TestSuite(TP).run() + + """ + self._default = None + self._nproc = {'tensor' : 1} + + + def _repr_(self): + r""" + String representation of the object. + + TEST:: + + sage: from sage.parallel.parallelism import Parallelism + sage: Parallelism()._repr_() + 'Number of cpu used = 1' + + """ + return str(self._nproc) + + def set(self, field, nproc=None): + r""" + Set the number of processes to be launched in parallel + computations regarding some specific field in sage + + INPUT: + - + + - ``field`` -- specify the part of sage for which set the + number of processes for parallel computations. + + - ``nproc`` -- (defaut: ``None``) number of processes; if ``None``, the + number of processes will be set to the maximum of cores found on the + computer. + + EXAMPLES: + + The default is a single processor (no parallelization):: + + sage: from sage.parallel.parallelism import Parallelism + sage: Parallelism() + Number of cpu used = 1 + + Asking for parallelization on 4 cores in tensor algebra:: + + sage: Parallelism().set('tensor',4) + sage: Parallelism() + Number of cpu used = 4 + + Using all the cores available on the computer:: + + sage: Parallelism().set('tensor') + sage: Parallelism() # random + Number of cpu used = 8 + + Switching off the parallelization:: + + sage: Parallelism().set('tensor',1) + sage: Parallelism() + Number of cpu used = 1 + + """ + if field not in self._nproc : + raise KeyError( + """entry for field {0} is not implemented in the Parallelism""".format(field) + ) + if nproc is not None : + if not isinstance(nproc,(int,Integer)): + raise TypeError("nproc must be integer") + + if nproc is None: + if self._default is None: + self._nproc[field] = ncpus() + else: + self._nproc[field] = self._default + else: + self._nproc[field] = nproc + + def get(self,field): + r""" + Get the number of processes which wiil be used in parallel + computations regarding some specific field in sage + + INPUT: + - + + - ``field`` -- specify the part of sage for which get the + number of processes for parallel computations. + + EXAMPLES: + + The default is a single processor (no parallelization):: + + sage: from sage.parallel.parallelism import Parallelism + sage: Parallelism().get('tensor') + 1 + + Asking for parallelization on 4 cores:: + + sage: Parallelism().set('tensor',4) + sage: Parallelism().get('tensor') + 4 + + """ + if field not in self._nproc : + raise KeyError("""entry for field {} does not correspond + is not implemented in the Parallelism""".format(field)) + + return self._nproc[field] + + + def get_all(self): + r""" + Get the number of processes which wiil be used in parallel + computations in any field in sage + + INPUT: + - + + EXAMPLES: + + sage: from sage.parallel.parallelism import Parallelism + sage: Parallelism().get_all() + { + 'tensor': 1 + } + + Asking for parallelization on 4 cores:: + + sage: Parallelism().set('tensor',4) + sage: Parallelism().get_all() + { + 'tensor': 4 + } + + """ + return self._nproc + + + def set_default(self, nproc=None): + r""" + Set the default number of processes to be launched in parallel + computations for all fields in sage + + INPUT: + - + + - ``nproc`` -- (defaut: ``None``) default number of processes; if ``None``, the + number of processes will be set to the maximum of cores found on the + computer. + + EXAMPLES: + + The default is a single processor (no parallelization):: + + sage: from sage.parallel.parallelism import Parallelism + sage: Parallelism() + + Asking for parallelization on 4 cores for all fields:: + + sage: Parallelism().set_default(4) + sage: Parallelism() + Number of cpu used = 4 + + Using all the cores available on the computer:: + + sage: Parallelism().set_default('tensor') + sage: Parallelism() # random + Number of cpu used = 8 + + """ + if nproc is not None : + if not isinstance(nproc,(int,Integer)): + raise TypeError("nproc must be integer") + + self._default = nproc + + def get_default(self): + r""" + Get the default number of processes to be launched in parallel + computations for all fields in sage + + INPUT: + - + + EXAMPLES: + + The default is a single processor (no parallelization):: + + sage: from sage.parallel.parallelism import Parallelism + sage: Parallelism() + sage: Parallelism().get_default('tensor') + 1 + + + """ + return self._default + diff --git a/src/sage/tensor/modules/all.py b/src/sage/tensor/modules/all.py index 0501792b752..a6d8750ae90 100644 --- a/src/sage/tensor/modules/all.py +++ b/src/sage/tensor/modules/all.py @@ -1,2 +1 @@ from finite_rank_free_module import FiniteRankFreeModule -from parallel_utilities import set_nproc_tensor, get_nproc_tensor diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 0816a5a7cba..2f2b78c660b 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -251,7 +251,7 @@ class :class:`~sage.tensor.differential_form_element.DifferentialForm`) from sage.structure.sage_object import SageObject from sage.rings.integer import Integer from sage.parallel.all import parallel -from sage.tensor.modules.parallel_utilities import TensorParallelCompute +from sage.parallel.parallelism import Parallelism from operator import itemgetter import time @@ -1285,7 +1285,7 @@ def __add__(self, other): Parallel computation:: - sage: set_nproc_tensor(2); get_nproc_tensor() + sage: Parallelism().set('tensor',2); Parallelism().get('tensor') 2 sage: s = a.__add__(b) ; s 1-index components w.r.t. [1, 2, 3] @@ -1293,7 +1293,7 @@ def __add__(self, other): [5, 5, 3] sage: s == a+b True - sage: set_nproc_tensor(1) + sage: Parallelism().set('tensor',2) """ if other == 0: @@ -1314,10 +1314,10 @@ def __add__(self, other): "same starting index") - if TensorParallelCompute()._use_paral : + if Parallelism().get('tensor') != 1 : # parallel sum result = self._new_instance() - nproc = TensorParallelCompute()._nproc + nproc = Parallelism().get('tensor') lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in other._comp.iteritems()] @@ -1401,7 +1401,7 @@ def __sub__(self, other): Parallel computation:: - sage: set_nproc_tensor(2); get_nproc_tensor() + sage: Parallelism().set('tensor',2); Parallelism().get('tensor') 2 sage: s = a.__sub__(b) ; s 1-index components w.r.t. [1, 2, 3] @@ -1409,7 +1409,7 @@ def __sub__(self, other): [-3, -5, -9] sage: s == a - b True - sage: set_nproc_tensor(1) + sage: Parallelism().set('tensor',1) """ if other == 0: @@ -1474,7 +1474,7 @@ def __mul__(self, other): True Parallel computation:: - sage: set_nproc_tensor(2); get_nproc_tensor() + sage: Parallelism().set('tensor',2); Parallelism().get('tensor') 2 sage: s = a.__mul__(b) ; s 2-indices components w.r.t. [1, 2, 3] @@ -1484,7 +1484,7 @@ def __mul__(self, other): [-12 -15 -18] sage: s == a*b True - sage: set_nproc_tensor(1); get_nproc_tensor() + sage: Parallelism().set('tensor',1); Parallelism().get('tensor') 1 """ @@ -1522,8 +1522,8 @@ def __mul__(self, other): # So we use a loop specific to the current case and return the # result: - if TensorParallelCompute()._use_paral : - nproc = TensorParallelCompute()._nproc + if Parallelism().get('tensor') != 1 : + nproc = Parallelism().get('tensor') lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind in result.non_redundant_index_generator()] @@ -1552,8 +1552,8 @@ def paral_mul(a,local_list_ind): result = Components(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter) - if TensorParallelCompute()._use_paral : - nproc = TensorParallelCompute()._nproc + if Parallelism().get('tensor') != 1 : + nproc = Parallelism().get('tensor') lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in self._comp.iteritems()] @@ -1775,7 +1775,7 @@ def contract(self, *args): Parallel computation:: - sage: set_nproc_tensor(2); get_nproc_tensor() + sage: Parallelism().set('tensor',2); Parallelism().get('tensor') 2 sage: s = a.contract(0, b, 0) ; s 1-index components w.r.t. [ @@ -1787,7 +1787,7 @@ def contract(self, *args): [28, 32, 36] sage: s = a.contract(0, b, 1) ; s[:] [12, 24, 36] - sage: set_nproc_tensor(1) + sage: Parallelism().set('tensor',1) Contraction on 2 indices:: @@ -1812,7 +1812,7 @@ def contract(self, *args): Parallel computation:: - sage: set_nproc_tensor(2); get_nproc_tensor() + sage: Parallelism().set('tensor',2); Parallelism().get('tensor') 2 sage: c = a*b ; c 3-indices components w.r.t. [ @@ -1828,7 +1828,7 @@ def contract(self, *args): ] sage: s[:] [-285, 570, 855] - sage: set_nproc_tensor(1) + sage: Parallelism().set('tensor',1) Consistency check with :meth:`trace`:: @@ -1892,11 +1892,11 @@ def contract(self, *args): res = 0 - if TensorParallelCompute()._use_paral: + if Parallelism().get('tensor') != 1: # parallel contraction to scalar # parallel multiplication - @parallel(p_iter='multiprocessing',ncpus=TensorParallelCompute()._nproc) + @parallel(p_iter='multiprocessing',ncpus=Parallelism().get('tensor')) def compprod(a,b): return a*b @@ -2026,9 +2026,9 @@ def compprod(a,b): start_index=self._sindex) shift_o = self._nid - ncontr - if TensorParallelCompute()._use_paral: + if Parallelism().get('tensor') != 1: # parallel computation - nproc = TensorParallelCompute()._nproc + nproc = Parallelism().get('tensor') lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in res.non_redundant_index_generator()] ind_step = max(1,int(len(ind_list)/nproc/2)) @@ -3225,7 +3225,7 @@ def __mul__(self, other): True Parallel computation:: - sage: set_nproc_tensor(2); get_nproc_tensor() + sage: Parallelism().set('tensor',2); Parallelism().get('tensor') 2 sage: s = a.__mul__(b) ; s 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) @@ -3243,7 +3243,7 @@ def __mul__(self, other): True sage: s == a*c True - sage: set_nproc_tensor(1); get_nproc_tensor() + sage: Parallelism().set('tensor',1); Parallelism().get('tensor') 1 """ @@ -3271,8 +3271,8 @@ def __mul__(self, other): self._sindex, self._output_formatter, sym, antisym) - if TensorParallelCompute()._use_paral : - nproc = TensorParallelCompute()._nproc + if Parallelism().get('tensor') != 1 : + nproc = Parallelism().get('tensor') lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in self._comp.iteritems()] @@ -4549,7 +4549,7 @@ def __add__(self, other): Parallel computation:: - sage: set_nproc_tensor(2); get_nproc_tensor() + sage: Parallelism().set('tensor',2); Parallelism().get('tensor') 2 sage: s = a.__add__(c) ; s # the symmetry is lost 2-indices components w.r.t. (1, 2, 3) @@ -4559,7 +4559,7 @@ def __add__(self, other): [-7 5 0] sage: s == a + c True - sage: set_nproc_tensor(1) + sage: Parallelism().set('tensor',1) """ @@ -4579,10 +4579,10 @@ def __add__(self, other): raise ValueError("the two sets of components do not have the " + "same starting index") - if TensorParallelCompute()._use_paral : + if Parallelism().get('tensor') != 1 : # parallel sum result = self._new_instance() - nproc = TensorParallelCompute()._nproc + nproc = Parallelism().get('tensor') lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ ind for ind, ocomp in other._comp.iteritems()] diff --git a/src/sage/tensor/modules/parallel_utilities.py b/src/sage/tensor/modules/parallel_utilities.py deleted file mode 100644 index fa7310333da..00000000000 --- a/src/sage/tensor/modules/parallel_utilities.py +++ /dev/null @@ -1,194 +0,0 @@ -r""" -Parallelization utilities - -This module defines - -- the singleton class :class:`TensorParallelCompute` to gather the information - relative to the parallelization of tensor algebra (basically the number of - processes to be used) -- the global functions :func:`set_nproc_tensor` and :func:`get_nproc_tensor` to be used in - a Sage session for managing the number of processes involved in the - parallelization. - -Some examples of parallelization are provided in the documentation -of :meth:`sage.tensor.modules.comp.Components.contract`. - -AUTHORS: - -- Marco Mancini, Eric Gourgoulhon, Michal Bejger (2015): initial version - -""" - -#****************************************************************************** -# Copyright (C) 2015 Marco Mancini -# -# Distributed under the terms of the GNU General Public License (GPL) -# as published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#****************************************************************************** - -from sage.structure.sage_object import SageObject -from sage.misc.fast_methods import Singleton -from sage.parallel.ncpus import ncpus - - -class TensorParallelCompute(Singleton, SageObject): - r""" - Singleton class for managing the number of processes used in parallel - computations involved in tensor algebra. - - EXAMPLES:: - - sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute - sage: TensorParallelCompute() - Number of cpu used = 1 - sage: TensorParallelCompute().set(4) - sage: TensorParallelCompute() - Number of cpu used = 4 - sage: TensorParallelCompute().set(1) - sage: TensorParallelCompute() - Number of cpu used = 1 - - """ - def __init__(self): - r""" - Only a single instance of this class is created (singleton model) - - TEST:: - - sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute - sage: TP = TensorParallelCompute() - sage: TP - Number of cpu used = 1 - - Test of the singleton character:: - - sage: TensorParallelCompute() is TP - True - - The test suite is passed:: - - sage: TestSuite(TP).run() - - """ - self._nproc = 1 - self._use_paral = False - - def _repr_(self): - r""" - String representation of the object. - - TEST:: - - sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute - sage: TensorParallelCompute()._repr_() - 'Number of cpu used = 1' - - """ - return "Number of cpu used = {}".format(self._nproc) - - def set(self, nproc=None): - r""" - Set the number of processes to be launched in parallel - computations - - INPUT: - - - ``nproc`` -- (defaut: ``None``) number of processes; if ``None``, the - number of processes will be set to the maximum of cores found on the - computer. - - EXAMPLES: - - The default is a single processor (no parallelization):: - - sage: from sage.tensor.modules.parallel_utilities import TensorParallelCompute - sage: TensorParallelCompute() - Number of cpu used = 1 - - Asking for parallelization on 4 cores:: - - sage: TensorParallelCompute().set(4) - sage: TensorParallelCompute() - Number of cpu used = 4 - - Using all the cores available on the computer:: - - sage: TensorParallelCompute().set() - sage: TensorParallelCompute() # random - Number of cpu used = 8 - - Switching off the parallelization:: - - sage: TensorParallelCompute().set(1) - sage: TensorParallelCompute() - Number of cpu used = 1 - - """ - self._nproc = ncpus() if nproc is None else nproc - self._use_paral = True if self._nproc!=1 else False - - -def set_nproc_tensor(nproc=None): - r""" - Set the number of processes for parallelizing computations - relative to tensor algebra. - - INPUT: - - - ``nproc`` -- (defaut: ``None``) number of processes; if ``None``, the - number of processes will be set to the maximum of cores found on the - computer. - - EXAMPLES: - - The default is a single processor (no parallelization):: - - sage: get_nproc_tensor() - 1 - - Asking for parallelization on 4 cores:: - - sage: set_nproc_tensor(4) - sage: get_nproc_tensor() - 4 - - Using all the cores available on the computer:: - - sage: set_nproc_tensor() - sage: get_nproc_tensor() # random - 8 - - Switching off the parallelization:: - - sage: set_nproc_tensor(1) - sage: get_nproc_tensor() - 1 - - See :meth:`sage.tensor.modules.comp.Components.contract` for a concrete - example of use. - - """ - TensorParallelCompute().set(nproc) - -def get_nproc_tensor(): - r""" - Return the number of processes used in parallelized tensorial - computations. - - EXAMPLES: - - The default is a single processor (no parallelization):: - - sage: get_nproc_tensor() - 1 - - Asking for parallelization on 4 cores:: - - sage: set_nproc_tensor(4) - sage: get_nproc_tensor() - 4 - - """ - return TensorParallelCompute()._nproc From 4228920f2068230956e4171a78fc57ed81339375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 27 Oct 2015 12:12:08 +0200 Subject: [PATCH 1728/1872] Better error reporting. --- src/sage/combinat/posets/posets.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index d1012915fdc..822e6e3bd54 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -3495,7 +3495,7 @@ def dilworth_decomposition(self): union of chains. According to Dilworth's theorem, the number of chains is equal to - `\alpha` (the posets' width). + `\alpha` (the posets' width). EXAMPLES:: @@ -5921,8 +5921,16 @@ def is_induced_subposet(self, other): True sage: P.is_induced_subposet(Poset()) False + + Bad input:: + + sage: Poset().is_induced_subposet('junk') + Traceback (most recent call last): + ... + AttributeError: 'str' object has no attribute 'subposet' """ - if not self._is_facade or not other._is_facade: + if (not self._is_facade or + (isinstance(other, FinitePoset) and not other._is_facade)): raise TypeError('the function is not defined on non-facade posets') # TODO: When we have decided if # Poset({'x':[42]}) == LatticePoset({'x':[42]}) From 579aed862ea02a060a82e6b03ab7cd068a15f76e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 27 Oct 2015 11:12:49 +0100 Subject: [PATCH 1729/1872] trac #19483: Update bliss --- build/pkgs/bliss/SPKG.txt | 2 +- build/pkgs/bliss/checksums.ini | 8 ++++---- build/pkgs/bliss/package-version.txt | 2 +- build/pkgs/bliss/patches/digraph_heuristic.patch | 10 ---------- 4 files changed, 6 insertions(+), 16 deletions(-) delete mode 100644 build/pkgs/bliss/patches/digraph_heuristic.patch diff --git a/build/pkgs/bliss/SPKG.txt b/build/pkgs/bliss/SPKG.txt index 73bd34d5183..84b97f0f8fc 100644 --- a/build/pkgs/bliss/SPKG.txt +++ b/build/pkgs/bliss/SPKG.txt @@ -7,7 +7,7 @@ forms of graphs. == License == -GPL +LGPL == Upstream Contact == diff --git a/build/pkgs/bliss/checksums.ini b/build/pkgs/bliss/checksums.ini index 740953e6b30..7fc59156c20 100644 --- a/build/pkgs/bliss/checksums.ini +++ b/build/pkgs/bliss/checksums.ini @@ -1,4 +1,4 @@ -tarball=bliss-VERSION.tar.bz2 -sha1=500796365fdf142dcfb34f979d678ffa456f1431 -md5=4e57118f9acad9a80baaefd93f967bdf -cksum=662785944 +tarball=bliss-VERSION.tar.gz +sha1=46322da1a03750e199e156d8967d88b89ebad5de +md5=b936d5d54b618a77ed59dfeeced3fa58 +cksum=76340303 diff --git a/build/pkgs/bliss/package-version.txt b/build/pkgs/bliss/package-version.txt index 615e437dd31..6ab5ccfd03e 100644 --- a/build/pkgs/bliss/package-version.txt +++ b/build/pkgs/bliss/package-version.txt @@ -1 +1 @@ -0.72.p1 +0.73 diff --git a/build/pkgs/bliss/patches/digraph_heuristic.patch b/build/pkgs/bliss/patches/digraph_heuristic.patch deleted file mode 100644 index 6e61458f424..00000000000 --- a/build/pkgs/bliss/patches/digraph_heuristic.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- 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) - { - vertices.resize(nof_vertices); -+ sh = shs_f; - } - - From c7db8222972eed2cdab455beaae3c50f4e45afe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Tue, 27 Oct 2015 13:38:34 +0200 Subject: [PATCH 1730/1872] Added an INPUT section to docstring. --- src/sage/combinat/posets/posets.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 822e6e3bd54..40ffc5f98b7 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5894,6 +5894,10 @@ def is_induced_subposet(self, other): Note that "induced" here has somewhat different meaning compared to that of graphs. + INPUT: + + - ``other``, a poset. + .. NOTE:: This method does not check whether the poset is a From 2148f20bedec3f4c7bac7f056bf5065b13f3ba8d Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 26 Oct 2015 22:16:09 -0400 Subject: [PATCH 1731/1872] Trac #19485: make legends more legible. The default "legend options" are empty, but this defaults everywhere to a gray legend with black text. This is difficult to read, especially when the result is printed (journal, thesis, etc.) or projected (as in a presentation). This commit changes the default background color for legends to 'white'. A drop shadow is added to ensure that the legend stands out amongst the plot. Some doctests and examples have been updated to make sense considering the new defaults. --- src/sage/plot/graphics.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index d5c68742c62..c401885f7d7 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -299,7 +299,7 @@ def set_legend_options(self, **kwds): - ``borderaxespad`` - (default: None) float, length between the axes and the legend - - ``back_color`` - (default: (0.9, 0.9, 0.9)) This parameter can be a string + - ``back_color`` - (default: 'white') This parameter can be a string denoting a color or an RGB tuple. The string can be a color name as in ('red', 'green', 'yellow', ...) or a floating point number like '0.8' which gets expanded to (0.8, 0.8, 0.8). The @@ -360,7 +360,7 @@ def set_legend_options(self, **kwds): - ``font_size`` - (default: 'medium') string, one of 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large' or an absolute font size (e.g. 12) - - ``shadow`` - (default: False) boolean - draw a shadow behind the legend + - ``shadow`` - (default: True) boolean - draw a shadow behind the legend - ``fancybox`` - (default: False) a boolean. If True, draws a frame with a round fancybox. @@ -377,11 +377,11 @@ def set_legend_options(self, **kwds): sage: p.set_legend_options() {} - We build a legend with a shadow:: + We build a legend without a shadow:: - sage: p.set_legend_options(shadow=True) + sage: p.set_legend_options(shadow=False) sage: p.set_legend_options()['shadow'] - True + False To set the legend position to the center of the plot, all these methods are roughly equivalent:: @@ -1067,11 +1067,11 @@ def __add__(self, other): sage: p1 = plot(x, x, 0, 1) sage: p2 = p1 - sage: p1.set_legend_options(back_color = 'white') - sage: p2.set_legend_options(shadow = True) + sage: p1.set_legend_options(back_color = 'black') + sage: p2.set_legend_options(shadow = False) sage: p3 = p1 + p2 sage: p3._legend_opts - {'back_color': 'white', 'shadow': True} + {'back_color': 'black', 'shadow': False} If the same legend option is specified more than once, the latter takes precedence:: @@ -1320,7 +1320,7 @@ def _set_scale(self, figure, scale=None, base=None): typeset='default') @suboptions('legend', - back_color=(0.9, 0.9, 0.9), borderpad=0.6, + back_color='white', borderpad=0.6, borderaxespad=None, columnspacing=None, fancybox=False, font_family='sans-serif', @@ -1329,7 +1329,7 @@ def _set_scale(self, figure, scale=None, base=None): handlelength=0.05, handletextpad=0.5, labelspacing=0.02, loc='best', markerscale=0.6, ncol=1, numpoints=2, - shadow=False, title=None) + shadow=True, title=None) def show(self, filename=None, linkmode=False, **kwds): r""" Show this graphics image immediately. @@ -2688,7 +2688,7 @@ def matplotlib(self, filename=None, weight = lopts.pop('font_weight', 'medium'), variant = lopts.pop('font_variant', 'normal') ) - color = lopts.pop('back_color', (0.9, 0.9, 0.9)) + color = lopts.pop('back_color', 'white') leg = subplot.legend(prop=prop, **lopts) if leg is None: sage.misc.misc.warn("legend requested but no items are labeled") @@ -3059,7 +3059,7 @@ def save_image(self, filename=None, *args, **kwds): # filename argument is written explicitly so that it can be used as a # positional one, which is a very likely usage for this function. @suboptions('legend', - back_color=(0.9, 0.9, 0.9), borderpad=0.6, + back_color='white', borderpad=0.6, borderaxespad=None, columnspacing=None, fancybox=False, font_family='sans-serif', @@ -3068,7 +3068,7 @@ def save_image(self, filename=None, *args, **kwds): handlelength=0.05, handletextpad=0.5, labelspacing=0.02, loc='best', markerscale=0.6, ncol=1, numpoints=2, - shadow=False, title=None) + shadow=True, title=None) def save(self, filename=None, **kwds): r""" Save the graphics to an image file. From 8184b387caa77679b05608b4fb68eeed314d732f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 27 Oct 2015 09:04:38 -0500 Subject: [PATCH 1732/1872] Better category detection and cardinality for subcrystals; fixing alcove path weight. --- src/sage/combinat/crystals/alcove_path.py | 29 ++++++++++++++----- src/sage/combinat/crystals/subcrystal.py | 19 +++++++++++- src/sage/combinat/crystals/virtual_crystal.py | 12 ++++++++ 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index b8cacdf58c2..1e73f182842 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -714,23 +714,33 @@ def epsilon(self, i): def weight(self): """ - Returns the weight of self. + Return the weight of ``self``. EXAMPLES:: sage: C = crystals.AlcovePaths(['A',2],[2,0]) sage: for i in C: i.weight() - 2*Lambda[1] - Lambda[2] - Lambda[1] - Lambda[2] - -2*Lambda[1] + 2*Lambda[2] - -Lambda[1] - -2*Lambda[2] + (0, 2, 0) + (0, 0, 1) + (0, 1, -1) + (0, -2, 2) + (0, -1, 0) + (0, 0, -2) sage: B = crystals.AlcovePaths(['A',2,1],[1,0,0]) sage: p = B.module_generators[0].f_string([0,1,2]) sage: p.weight() Lambda[0] - delta + + TESTS: + + Check that crystal morphisms work (:trac:`19481`):: + + sage: C1 = crystals.AlcovePaths(['A',2],[1,0]) + sage: C2 = crystals.AlcovePaths(['A',2],[2,0]) + sage: phi = C1.crystal_morphism(C2.module_generators, scaling_factors={1:2, 2:2}) + sage: [phi(x) for x in C1] + [(), ((alpha[1], 0),), ((alpha[1], 0), (alpha[1] + alpha[2], 0))] """ root_space = self.parent().R.root_space() weight = -self.parent().weight @@ -738,7 +748,10 @@ def weight(self): root = root_space(i.root) weight = -i.height*root + weight.reflection(root) - return -weight + WLR = self.parent().weight_lattice_realization() + B = WLR.basis() + return WLR._from_dict({i: Integer(c) for i,c in -weight}, + remove_zeros=False) #def __repr__(self): #return str(self.integer_sequence()) diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index 341c3540231..206a4f9d053 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -127,6 +127,8 @@ def __classcall_private__(cls, ambient, contained=None, generators=None, generators = ambient.module_generators category = Crystals().or_subcategory(category) + if ambient in FiniteCrystals() or isinstance(contained, frozenset): + category = category.Finite() if virtualization is not None: if scaling_factors is None: @@ -250,6 +252,18 @@ def cardinality(self): sage: S = B.subcrystal(max_depth=4) sage: S.cardinality() 22 + + TESTS: + + Check that :trac:`19481` is fixed:: + + sage: from sage.combinat.crystals.virtual_crystal import VirtualCrystal + sage: A = crystals.infinity.Tableaux(['A',3]) + sage: V = VirtualCrystal(A, {1:(1,3), 2:(2,)}, {1:1, 2:2}, cartan_type=['C',2]) + sage: V.cardinality() + Traceback (most recent call last): + ... + NotImplementedError: unknown cardinality """ if self._cardinality is not None: return self._cardinality @@ -261,7 +275,10 @@ def cardinality(self): except AttributeError: if self in FiniteCrystals(): return Integer(len(self.list())) - card = super(Subcrystal, self).cardinality() + try: + card = super(Subcrystal, self).cardinality() + except AttributeError: + raise NotImplementedError("unknown cardinality") if card == infinity: self._cardinality = card return card diff --git a/src/sage/combinat/crystals/virtual_crystal.py b/src/sage/combinat/crystals/virtual_crystal.py index eef6051c311..9f72c2f4291 100644 --- a/src/sage/combinat/crystals/virtual_crystal.py +++ b/src/sage/combinat/crystals/virtual_crystal.py @@ -168,6 +168,16 @@ def __classcall_private__(cls, ambient, virtualization, scaling_factors, sage: V2 = psi2.image() sage: V1 is V2 True + + TESTS: + + Check that :trac:`19481` is fixed:: + + sage: from sage.combinat.crystals.virtual_crystal import VirtualCrystal + sage: A = crystals.Tableaux(['A',3], shape=[2,1,1]) + sage: V = VirtualCrystal(A, {1:(1,3), 2:(2,)}, {1:1, 2:2}, cartan_type=['C',2]) + sage: V.category() + Category of finite crystals """ if cartan_type is None: cartan_type = ambient.cartan_type() @@ -181,6 +191,8 @@ def __classcall_private__(cls, ambient, virtualization, scaling_factors, scaling_factors = Family(scaling_factors) category = Crystals().or_subcategory(category) + if ambient in FiniteCrystals() or isinstance(contained, frozenset): + category = category.Finite() return super(Subcrystal, cls).__classcall__(cls, ambient, virtualization, scaling_factors, contained, tuple(generators), cartan_type, From 2a602c4e2743f6c0269c62b167289b54f935011b Mon Sep 17 00:00:00 2001 From: Stefan Witzel Date: Tue, 27 Oct 2015 17:35:13 +0100 Subject: [PATCH 1733/1872] Added ticket number to doctest. --- src/sage/rings/laurent_series_ring_element.pyx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 61f34798050..c1faec2ac3e 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -1235,6 +1235,9 @@ cdef class LaurentSeries(AlgebraElement): TESTS: + Check whether a polynomial over a Laurent series ring is contained in the + polynomial ring over the power series ring (see :trac:`19459`): + sage: L. = LaurentSeriesRing(GF(2)) sage: R. = PolynomialRing(L) sage: O = L.power_series_ring() From 596bfc5438145eedfdb4c7084469c741562491ee Mon Sep 17 00:00:00 2001 From: Stefan Witzel Date: Tue, 27 Oct 2015 20:04:34 +0100 Subject: [PATCH 1734/1872] Fixed typo. --- src/sage/rings/laurent_series_ring_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index c1faec2ac3e..6aae7daae9f 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -1246,7 +1246,7 @@ cdef class LaurentSeries(AlgebraElement): False """ if self.__n < 0: - raise TypeError("self is a not a power series") + raise TypeError("self is not a power series") u = self.__u t = u.parent().gen() return t**(self.__n) * u From c296cd32ad25b84fa718a92fb9abdb95eca76960 Mon Sep 17 00:00:00 2001 From: Stefan Witzel Date: Tue, 27 Oct 2015 21:09:03 +0100 Subject: [PATCH 1735/1872] Adjusted the doctest again. --- src/sage/rings/power_series_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index d24ec2c935d..3dc1e66c7a7 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -720,7 +720,7 @@ def _element_constructor_(self, f, prec=infinity, check=True): sage: P(1/q) Traceback (most recent call last): ... - TypeError: self is a not a power series + TypeError: self is not a power series It is checked that the precision is non-negative (see :trac:`19409`):: From 4e64db3784a823a5d9912024c41f0f53e423ad09 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Tue, 27 Oct 2015 22:30:10 +0100 Subject: [PATCH 1736/1872] Fix doctests and documentation issues in class Parallelism --- .../reference/tensor_free_modules/index.rst | 2 - src/sage/parallel/all.py | 3 +- src/sage/parallel/parallelism.py | 332 +++++++++++------- src/sage/tensor/modules/comp.py | 2 +- 4 files changed, 213 insertions(+), 126 deletions(-) diff --git a/src/doc/en/reference/tensor_free_modules/index.rst b/src/doc/en/reference/tensor_free_modules/index.rst index bfb08f9522b..89f81db9f25 100644 --- a/src/doc/en/reference/tensor_free_modules/index.rst +++ b/src/doc/en/reference/tensor_free_modules/index.rst @@ -25,6 +25,4 @@ a self-consistent subset that can be used independently of SageManifolds. sage/tensor/modules/format_utilities - sage/tensor/modules/parallel_utilities - .. include:: ../footer.txt diff --git a/src/sage/parallel/all.py b/src/sage/parallel/all.py index edc5dfae64d..d8e39f55441 100644 --- a/src/sage/parallel/all.py +++ b/src/sage/parallel/all.py @@ -1,2 +1,3 @@ from decorate import parallel, fork - +from sage.misc.lazy_import import lazy_import +lazy_import('sage.parallel.parallelism', 'Parallelism') diff --git a/src/sage/parallel/parallelism.py b/src/sage/parallel/parallelism.py index f2b90c9312c..1db79530996 100644 --- a/src/sage/parallel/parallelism.py +++ b/src/sage/parallel/parallelism.py @@ -1,16 +1,12 @@ r""" Parallelization utilities -This module defines +This module defines the singleton class :class:`Parallelism` to gather the +information relative to parallelization of computations in some specific topics +(basically the number of processes to be used). -- the singleton class :class:`Parallelism` to gather the information - relative to the parallelization (basically the number of processes to be used) -- the global functions :func:`set_nproc_tensor` and :func:`get_nproc_tensor` to be used in - a Sage session for managing the number of processes involved in the - parallelization. - -Some examples of parallelization are provided in the documentation -of :meth:`sage.tensor.modules.comp.Components.contract`. +Some examples of use are provided in the documentation of +:meth:`sage.tensor.modules.comp.Components.contract`. AUTHORS: @@ -35,45 +31,78 @@ class Parallelism(Singleton, SageObject): r""" Singleton class for managing the number of processes used in parallel - computations involved in tensor algebra. + computations involved in various fields. - EXAMPLES:: + EXAMPLES: - sage: from sage.parallel.parallelism import Parallelism - sage: Parallelism().get('tensor') - 1 - sage: Parallelism().set('tensor',4) + The number of processes is initialized to 1 (no parallelization) for + each field (only tensor computations are implemented at the moment):: + + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 1 + + Using 4 processes to parallelize tensor computations:: + + sage: Parallelism().set('tensor', nproc=4) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 4 sage: Parallelism().get('tensor') 4 - sage: Parallelism().set('tensor',1) - sage: Parallelism().get('tensor') - 1 + + Using 6 processes to parallelize all types of computations:: + + sage: Parallelism().set(nproc=6) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 6 + + Using all the cores available on the computer to parallelize tensor + computations:: + + sage: Parallelism().set('tensor') + sage: Parallelism() # random (depends on the computer) + Number of processes for parallelization: + - tensor computations: 8 + + Using all the cores available on the computer to parallelize all types + of computations:: + + sage: Parallelism().set() + sage: Parallelism() # random (depends on the computer) + Number of processes for parallelization: + - tensor computations: 8 + + Switching off all parallelizations:: + + sage: Parallelism().set(nproc=1) """ def __init__(self): r""" - Only a single instance of this class is created (singleton model) + Construct the single instance of class Parallelism (singleton model). TEST:: - sage: from sage.parallel.parallelism import Parallelism - sage: TP = Parallelism() - sage: TP - Number of cpu used = 1 + sage: par = Parallelism() + sage: par + Number of processes for parallelization: + - tensor computations: 1 Test of the singleton character:: - sage: Parallelism() is TP + sage: Parallelism() is par True The test suite is passed:: - sage: TestSuite(TP).run() + sage: TestSuite(par).run() """ - self._default = None - self._nproc = {'tensor' : 1} - + self._default = ncpus() # default number of proc. used in parallelizations + self._nproc = {'tensor' : 1} # dict. of number of processes to be used + # (keys: computational field) def _repr_(self): r""" @@ -81,127 +110,185 @@ def _repr_(self): TEST:: - sage: from sage.parallel.parallelism import Parallelism sage: Parallelism()._repr_() - 'Number of cpu used = 1' + 'Number of processes for parallelization:\n - tensor computations: 1' """ - return str(self._nproc) + resu = "Number of processes for parallelization:\n" + for field in sorted(self._nproc): + resu += " - {} computations: {}\n".format(field, self._nproc[field]) + return resu[:-1] - def set(self, field, nproc=None): + def reset(self): r""" - Set the number of processes to be launched in parallel - computations regarding some specific field in sage + Put the singleton object ``Parallelism()`` in the same state as just + after its creation. - INPUT: - - + EXAMPLE: - - ``field`` -- specify the part of sage for which set the - number of processes for parallel computations. + State of ``Parallelism()`` just after its creation:: - - ``nproc`` -- (defaut: ``None``) number of processes; if ``None``, the - number of processes will be set to the maximum of cores found on the - computer. + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 1 + sage: Parallelism().get_default() # random (depends on the computer) + 8 + + Changing some values:: + + sage: Parallelism().set_default(6) + sage: Parallelism().set() + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 6 + sage: Parallelism().get_default() + 6 + + Back to the initial state:: + + sage: Parallelism().reset() + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 1 + sage: Parallelism().get_default() # random (depends on the computer) + 8 + + """ + self._default = ncpus() + for field in self._nproc: + self._nproc[field] = 1 + + def set(self, field=None, nproc=None): + r""" + Set the number of processes to be launched for parallel computations + regarding some specific field. + + INPUT: + + - ``field`` -- (defaut: ``None``) string specifying the computational + field for which the number of parallel processes is to be set; if + ``None``, all fields are considered + - ``nproc`` -- (defaut: ``None``) number of processes to be used for + parallelization; if ``None``, the number of processes will be set to + the default value, which, unless redefined by :meth:`set_default`, + is the total number of cores found on the computer. EXAMPLES: The default is a single processor (no parallelization):: - sage: from sage.parallel.parallelism import Parallelism sage: Parallelism() - Number of cpu used = 1 + Number of processes for parallelization: + - tensor computations: 1 Asking for parallelization on 4 cores in tensor algebra:: - sage: Parallelism().set('tensor',4) + sage: Parallelism().set('tensor', nproc=4) sage: Parallelism() - Number of cpu used = 4 + Number of processes for parallelization: + - tensor computations: 4 Using all the cores available on the computer:: sage: Parallelism().set('tensor') - sage: Parallelism() # random - Number of cpu used = 8 + sage: Parallelism() # random (depends on the computer) + Number of processes for parallelization: + - tensor computations: 8 + + Using 6 cores in all parallelizations:: + + sage: Parallelism().set(nproc=6) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 6 + + Using all the cores available on the computer in all parallelizations:: + + sage: Parallelism().set() + sage: Parallelism() # random (depends on the computer) + Number of processes for parallelization: + - tensor computations: 8 Switching off the parallelization:: - sage: Parallelism().set('tensor',1) + sage: Parallelism().set('tensor', nproc=1) sage: Parallelism() - Number of cpu used = 1 + Number of processes for parallelization: + - tensor computations: 1 """ - if field not in self._nproc : - raise KeyError( - """entry for field {0} is not implemented in the Parallelism""".format(field) - ) - if nproc is not None : - if not isinstance(nproc,(int,Integer)): - raise TypeError("nproc must be integer") - - if nproc is None: - if self._default is None: - self._nproc[field] = ncpus() - else: - self._nproc[field] = self._default + if field is None: + for fi in self._nproc: + self.set(field=fi, nproc=nproc) else: - self._nproc[field] = nproc + if field not in self._nproc : + raise KeyError( + """entry for field {0} is not implemented in the Parallelism""".format(field) + ) + if nproc is None: + self._nproc[field] = self._default + else: + if not isinstance(nproc,(int,Integer)): + raise TypeError("nproc must be integer") + self._nproc[field] = nproc - def get(self,field): + def get(self, field): r""" - Get the number of processes which wiil be used in parallel - computations regarding some specific field in sage + Get the number of processes which will be used in parallel computations + regarding some specific field. INPUT: - - - - ``field`` -- specify the part of sage for which get the - number of processes for parallel computations. + - ``field`` -- string specifying the part of Sage involved in + parallel computations + + OUTPUT: + + - number of processes used in parallelization of computations in the + domain ``field`` EXAMPLES: - The default is a single processor (no parallelization):: + The default is a single proces (no parallelization):: - sage: from sage.parallel.parallelism import Parallelism + sage: Parallelism().reset() sage: Parallelism().get('tensor') 1 - Asking for parallelization on 4 cores:: - - sage: Parallelism().set('tensor',4) + Asking for parallelization on 4 cores:: + + sage: Parallelism().set('tensor', nproc=4) sage: Parallelism().get('tensor') 4 """ - if field not in self._nproc : - raise KeyError("""entry for field {} does not correspond - is not implemented in the Parallelism""".format(field)) - + if field not in self._nproc: + raise KeyError("entry for field {} is not ".format(field) + + "implemented in Parallelism()") return self._nproc[field] def get_all(self): r""" - Get the number of processes which wiil be used in parallel - computations in any field in sage + Get the number of processes which will be used in parallel + computations in all fields - INPUT: - - + OUTPUT: - EXAMPLES: + - dictionary of the number of processes, with the computational fields + as keys - sage: from sage.parallel.parallelism import Parallelism + EXAMPLES:: + + sage: Parallelism().reset() sage: Parallelism().get_all() - { - 'tensor': 1 - } + {'tensor': 1} + + Asking for parallelization on 4 cores:: - Asking for parallelization on 4 cores:: - - sage: Parallelism().set('tensor',4) + sage: Parallelism().set(nproc=4) sage: Parallelism().get_all() - { - 'tensor': 4 - } + {'tensor': 4} """ return self._nproc @@ -210,59 +297,60 @@ def get_all(self): def set_default(self, nproc=None): r""" Set the default number of processes to be launched in parallel - computations for all fields in sage + computations. INPUT: - - - - ``nproc`` -- (defaut: ``None``) default number of processes; if ``None``, the - number of processes will be set to the maximum of cores found on the - computer. + - ``nproc`` -- (defaut: ``None``) default number of processes; + if ``None``, the number of processes will be set to the total number + of cores found on the computer. EXAMPLES: - The default is a single processor (no parallelization):: + The default number of process for parallelization is the total number + of cores found on the computer:: - sage: from sage.parallel.parallelism import Parallelism - sage: Parallelism() + sage: Parallelism().get_default() # random (depends on the computer) + 8 - Asking for parallelization on 4 cores for all fields:: + Changing it thanks to ``set_default``:: - sage: Parallelism().set_default(4) - sage: Parallelism() - Number of cpu used = 4 + sage: Parallelism().set_default(nproc=4) + sage: Parallelism().get_default() + 4 - Using all the cores available on the computer:: + Setting it back to the total number of cores available on the computer:: - sage: Parallelism().set_default('tensor') - sage: Parallelism() # random - Number of cpu used = 8 + sage: Parallelism().set_default() + sage: Parallelism().get_default() # random (depends on the computer) + 8 """ - if nproc is not None : + if nproc is None: + self._default = ncpus() + else: if not isinstance(nproc,(int,Integer)): raise TypeError("nproc must be integer") - - self._default = nproc + self._default = nproc def get_default(self): r""" Get the default number of processes to be launched in parallel - computations for all fields in sage - - INPUT: - - + computations. EXAMPLES: - The default is a single processor (no parallelization):: + The default number of process for parallelization is the total number + of cores found on the computer:: - sage: from sage.parallel.parallelism import Parallelism - sage: Parallelism() - sage: Parallelism().get_default('tensor') - 1 + sage: Parallelism().get_default() # random (depends on the computer) + 8 + + It can be changed via :meth:`set_default`:: + sage: Parallelism().set_default(nproc=4) + sage: Parallelism().get_default() + 4 """ return self._default - diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 2f2b78c660b..70db188f3b7 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -250,7 +250,7 @@ class :class:`~sage.tensor.differential_form_element.DifferentialForm`) from sage.structure.sage_object import SageObject from sage.rings.integer import Integer -from sage.parallel.all import parallel +from sage.parallel.decorate import parallel from sage.parallel.parallelism import Parallelism from operator import itemgetter import time From 77d6017c3ddcb930703ca04da9ae24935e55a03e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 27 Oct 2015 17:22:16 -0500 Subject: [PATCH 1737/1872] Fixing Ryser algorithm. --- src/sage/combinat/integer_vector.py | 187 ++++++++++------------------ 1 file changed, 67 insertions(+), 120 deletions(-) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index d068828f1df..9be40a5e6e8 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -114,86 +114,6 @@ def is_gale_ryser(r,s): # same number of 1s domination return len(rstar) <= len(s2) and sum(r2) == sum(s2) and rstar.dominates(s) -def _slider01(A, t, k, p1, p2, fixedcols=[]): - r""" - Assumes `A` is a `(0,1)`-matrix. For each of the - `t` rows with highest row sums, this function - returns a matrix `B` which is the same as `A` except that it - has slid `t` of the `1` in each of these rows of `A` - over towards the `k`-th column. Care must be taken when the - last leading 1 is in column >=k. It avoids those in columns - listed in fixedcols. - - This is a 'private' function for use in gale_ryser_theorem. - - INPUT: - - - ``A`` -- an `m\times n` (0,1) matrix - - ``t``, ``k`` -- integers satisfying `0 < t < m`, `0 < k < n` - - ``fixedcols`` -- those columns (if any) whose entries - aren't permitted to slide - - OUTPUT: - - An `m\times n` (0,1) matrix, which is the same as `A` except - that it has exactly one `1` in `A` slid over to the `k`-th - column. - - EXAMPLES:: - - sage: from sage.combinat.integer_vector import _slider01 - sage: A = matrix([[1,1,1,0],[1,1,1,0],[1,0,0,0],[1,0,0,0]]) - sage: A - [1 1 1 0] - [1 1 1 0] - [1 0 0 0] - [1 0 0 0] - sage: _slider01(A, 1, 3, [3,3,1,1], [3,3,1,1]) - [1 1 0 1] - [1 1 1 0] - [1 0 0 0] - [1 0 0 0] - sage: _slider01(A, 3, 3, [3,3,1,1], [3,3,1,1]) - [1 1 0 1] - [1 0 1 1] - [0 0 0 1] - [1 0 0 0] - - """ - # we assume that the rows of A are arranged so that - # there row sums are decreasing as you go from the - # top row to the bottom row - import copy - from sage.matrix.constructor import matrix - m = len(A.rows()) - rs = [sum(x) for x in A.rows()] - n = len(A.columns()) - cs = [sum(x) for x in A.columns()] - B = [copy.deepcopy(list(A.row(j))) for j in range(m)] - c = 0 # initializing counter - for ii in range(m): - rw = copy.deepcopy(B[ii]) # to make mutable - # now we want to move the rightmost left 1 to the k-th column - fixedcols = [l for l in range(n) if p2[l]==sum(matrix(B).column(l))] - JJ = range(n) - JJ.reverse() - for jj in JJ: - if t==sum(matrix(B).column(k)): - break - if jj=t: next - j=n-1 - else: - next - if c>=t: - break - return matrix(B) - def gale_ryser_theorem(p1, p2, algorithm="gale"): r""" Returns the binary matrix given by the Gale-Ryser theorem. @@ -234,8 +154,8 @@ def gale_ryser_theorem(p1, p2, algorithm="gale"): Ryser's Algorithm: - (Ryser [Ryser63]_): The construction of an `m\times n` matrix `A=A_{r,s}`, - due to Ryser, is described as follows. The + (Ryser [Ryser63]_): The construction of an `m\times n` matrix + `A=A_{r,s}`, due to Ryser, is described as follows. The construction works if and only if have `s\preceq r^*`. * Construct the `m\times n` matrix `B` from `r` by defining @@ -255,6 +175,8 @@ def gale_ryser_theorem(p1, p2, algorithm="gale"): with a wrong sum in the step below. * Proceed inductively to construct columns `n-1`, ..., `2`, `1`. + Note: when performing the induction on step `k`, we consider + the row sums of the first `k` columns. * Set `A = B`. Return `A`. @@ -282,10 +204,10 @@ def gale_ryser_theorem(p1, p2, algorithm="gale"): sage: p1 = [3,3,1,1] sage: p2 = [3,3,1,1] sage: gale_ryser_theorem(p1, p2, algorithm = "ryser") - [1 1 0 1] [1 1 1 0] - [0 1 0 0] + [1 1 0 1] [1 0 0 0] + [0 1 0 0] sage: p1 = [4,2,2] sage: p2 = [3,3,1,1] sage: gale_ryser_theorem(p1, p2, algorithm = "ryser") @@ -311,19 +233,19 @@ def gale_ryser_theorem(p1, p2, algorithm="gale"): sage: from sage.combinat.integer_vector import gale_ryser_theorem sage: gale_ryser_theorem([3,3,0,1,1,0], [3,1,3,1,0], algorithm = "ryser") - [1 0 1 1 0] [1 1 1 0 0] + [1 0 1 1 0] [0 0 0 0 0] - [0 0 1 0 0] [1 0 0 0 0] + [0 0 1 0 0] [0 0 0 0 0] sage: p1 = [3,1,1,1,1]; p2 = [3,2,2,0] sage: gale_ryser_theorem(p1, p2, algorithm = "ryser") [1 1 1 0] - [0 0 1 0] - [0 1 0 0] [1 0 0 0] [1 0 0 0] + [0 1 0 0] + [0 0 1 0] TESTS: @@ -334,20 +256,20 @@ def gale_ryser_theorem(p1, p2, algorithm="gale"): checked for correctness.:: sage: def test_algorithm(algorithm, low = 10, high = 50): - ... n,m = randint(low,high), randint(low,high) - ... g = graphs.RandomBipartite(n, m, .3) - ... s1 = sorted(g.degree([(0,i) for i in range(n)]), reverse = True) - ... s2 = sorted(g.degree([(1,i) for i in range(m)]), reverse = True) - ... m = gale_ryser_theorem(s1, s2, algorithm = algorithm) - ... ss1 = sorted(map(lambda x : sum(x) , m.rows()), reverse = True) - ... ss2 = sorted(map(lambda x : sum(x) , m.columns()), reverse = True) - ... if ((ss1 != s1) or (ss2 != s2)): - ... print "Algorithm %s failed with this input:" % algorithm - ... print s1, s2 - - sage: for algorithm in ["gale", "ryser"]: # long time - ... for i in range(50): # long time - ... test_algorithm(algorithm, 3, 10) # long time + ....: n,m = randint(low,high), randint(low,high) + ....: g = graphs.RandomBipartite(n, m, .3) + ....: s1 = sorted(g.degree([(0,i) for i in range(n)]), reverse = True) + ....: s2 = sorted(g.degree([(1,i) for i in range(m)]), reverse = True) + ....: m = gale_ryser_theorem(s1, s2, algorithm = algorithm) + ....: ss1 = sorted(map(lambda x : sum(x) , m.rows()), reverse = True) + ....: ss2 = sorted(map(lambda x : sum(x) , m.columns()), reverse = True) + ....: if ((ss1 != s1) or (ss2 != s2)): + ....: print "Algorithm %s failed with this input:" % algorithm + ....: print s1, s2 + + sage: for algorithm in ["gale", "ryser"]: # long time + ....: for i in range(50): # long time + ....: test_algorithm(algorithm, 3, 10) # long time Null matrix:: @@ -359,14 +281,28 @@ def gale_ryser_theorem(p1, p2, algorithm="gale"): [0 0 0 0] [0 0 0 0] [0 0 0 0] - + + Check that :trac:`16638` is fixed:: + + sage: tests = [([4, 3, 3, 2, 1, 1, 1, 1, 0], [6, 5, 1, 1, 1, 1, 1]), + ....: ([4, 4, 3, 3, 1, 1, 0], [5, 5, 2, 2, 1, 1]), + ....: ([4, 4, 3, 2, 1, 1], [5, 5, 1, 1, 1, 1, 1, 0, 0]), + ....: ([3, 3, 3, 3, 2, 1, 1, 1, 0], [7, 6, 2, 1, 1, 0]), + ....: ([3, 3, 3, 1, 1, 0], [4, 4, 1, 1, 1])] + sage: for s1, s2 in tests: + ....: m = gale_ryser_theorem(s1, s2, algorithm="ryser") + ....: ss1 = sorted(map(lambda x : sum(x) , m.rows()), reverse = True) + ....: ss2 = sorted(map(lambda x : sum(x) , m.columns()), reverse = True) + ....: if ((ss1 != s1) or (ss2 != s2)): + ....: print("Error in Ryser algorithm") + ....: print(s1, s2) REFERENCES: .. [Ryser63] H. J. Ryser, Combinatorial Mathematics, - Carus Monographs, MAA, 1963. + Carus Monographs, MAA, 1963. .. [Gale57] D. Gale, A theorem on flows in networks, Pacific J. Math. - 7(1957)1073-1082. + 7(1957)1073-1082. """ from sage.combinat.partition import Partition from sage.matrix.constructor import matrix @@ -380,28 +316,39 @@ def gale_ryser_theorem(p1, p2, algorithm="gale"): # Sorts the sequences if they are not, and remembers the permutation # applied tmp = sorted(enumerate(p1), reverse=True, key=lambda x:x[1]) - r = [x[1] for x in tmp if x[1]>0] + r = [x[1] for x in tmp] r_permutation = [x-1 for x in Permutation([x[0]+1 for x in tmp]).inverse()] m = len(r) tmp = sorted(enumerate(p2), reverse=True, key=lambda x:x[1]) - s = [x[1] for x in tmp if x[1]>0] + s = [x[1] for x in tmp] s_permutation = [x-1 for x in Permutation([x[0]+1 for x in tmp]).inverse()] n = len(s) - A0 = matrix([[1]*r[j]+[0]*(n-r[j]) for j in range(m)]) - - for k in range(1,n+1): - goodcols = [i for i in range(n) if s[i]==sum(A0.column(i))] - if sum(A0.column(n-k)) != s[n-k]: - A0 = _slider01(A0,s[n-k],n-k, p1, p2, goodcols) - - # If we need to add empty rows/columns - if len(p1)!=m: - A0 = A0.stack(matrix([[0]*n]*(len(p1)-m))) - - if len(p2)!=n: - A0 = A0.transpose().stack(matrix([[0]*len(p1)]*(len(p2)-n))).transpose() + # This is the partition equivalent to the sliding algorithm + cols = [] + for t in reversed(s): + c = [0] * m + i = 0 + while t: + k = i + 1 + while k < m and r[i] == r[k]: + k += 1 + if t >= k - i: # == number rows of the same length + for j in range(i, k): + r[j] -= 1 + c[j] = 1 + t -= k - i + else: # Remove the t last rows of that length + for j in range(k-t, k): + r[j] -= 1 + c[j] = 1 + t = 0 + i = k + cols.append(c) + + # We added columns to the back instead of the front + A0 = matrix(list(reversed(cols))).transpose() # Applying the permutations to get a matrix satisfying the # order given by the input From 81012bc59c29eea8162bcec1ecc21cafa9d1d826 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 27 Oct 2015 20:32:48 -0300 Subject: [PATCH 1738/1872] Trac 19016: add hash value for asymptotic ring elt --- src/sage/rings/asymptotic/asymptotic_ring.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index e32557767d7..a2bacd54ade 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -704,6 +704,26 @@ def summands(self): return self._summands_ + def __hash__(self): + r""" + A hash value for this element. + + .. WARNING:: + + This hash value uses the string representation and might not be + always right. + + TESTS:: + + sage: R_log = AsymptoticRing(growth_group='log(x)^QQ', coefficient_ring=QQ) + sage: lx = R_log(log(SR.var('x'))) + sage: elt = (O(lx) + lx^3)^4 + sage: hash(elt) # random + -4395085054568712393 + """ + return hash(str(self)) + + def __nonzero__(self): r""" Return whether this asymptotic expansion is not identically zero. From c7b4f0e0210e6cbad4bcfd62ce3093239f071ff3 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 27 Oct 2015 20:58:53 -0300 Subject: [PATCH 1739/1872] Trac 19016: more robust doctest (see #19488) --- src/sage/combinat/crystals/affine.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/crystals/affine.py b/src/sage/combinat/crystals/affine.py index b4f9ac8a6b9..0efe7f39be3 100644 --- a/src/sage/combinat/crystals/affine.py +++ b/src/sage/combinat/crystals/affine.py @@ -571,15 +571,15 @@ def __cmp__(self, other): sage: c = K(rows=[[2]]) sage: cmp(b,c) -1 - sage: cmp(b,1) - -1 sage: cmp(b,b) 0 - """ - if parent(self) is parent(other): - return cmp(self.value, other.value) - else: - return cmp(parent(self), parent(other)) + + If the parent are different, it uses comparison of the parents:: + + sage: cmp(b,1) == cmp(b.parent(), ZZ) + True + """ + return cmp(parent(self), parent(other)) or cmp(self.value, other.value) AffineCrystalFromClassical.Element = AffineCrystalFromClassicalElement From b0332975733cdda87b65707273fc42975ba96020 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Wed, 28 Oct 2015 07:31:35 +0100 Subject: [PATCH 1740/1872] Improvements in the documentation of class Parallelism --- src/doc/en/reference/parallel/index.rst | 1 + src/sage/parallel/parallelism.py | 50 ++++---- src/sage/tensor/modules/comp.py | 151 +++++++++++++----------- 3 files changed, 108 insertions(+), 94 deletions(-) diff --git a/src/doc/en/reference/parallel/index.rst b/src/doc/en/reference/parallel/index.rst index a24820055aa..fe2fecd9703 100644 --- a/src/doc/en/reference/parallel/index.rst +++ b/src/doc/en/reference/parallel/index.rst @@ -8,6 +8,7 @@ Parallel Computing sage/parallel/reference sage/parallel/use_fork sage/parallel/multiprocessing_sage + sage/parallel/parallelism sage/parallel/ncpus .. SEEALSO:: diff --git a/src/sage/parallel/parallelism.py b/src/sage/parallel/parallelism.py index 1db79530996..b852527500d 100644 --- a/src/sage/parallel/parallelism.py +++ b/src/sage/parallel/parallelism.py @@ -1,9 +1,9 @@ r""" -Parallelization utilities +Parallelization control -This module defines the singleton class :class:`Parallelism` to gather the -information relative to parallelization of computations in some specific topics -(basically the number of processes to be used). +This module defines the singleton class :class:`Parallelism` to govern the +parallelization of computations in some specific topics. It allows the user to +set the number of processes to be used for parallelization. Some examples of use are provided in the documentation of :meth:`sage.tensor.modules.comp.Components.contract`. @@ -121,8 +121,8 @@ def _repr_(self): def reset(self): r""" - Put the singleton object ``Parallelism()`` in the same state as just - after its creation. + Put the singleton object ``Parallelism()`` in the same state as + immediately after its creation. EXAMPLE: @@ -165,10 +165,10 @@ def set(self, field=None, nproc=None): INPUT: - - ``field`` -- (defaut: ``None``) string specifying the computational + - ``field`` -- (default: ``None``) string specifying the computational field for which the number of parallel processes is to be set; if ``None``, all fields are considered - - ``nproc`` -- (defaut: ``None``) number of processes to be used for + - ``nproc`` -- (default: ``None``) number of processes to be used for parallelization; if ``None``, the number of processes will be set to the default value, which, unless redefined by :meth:`set_default`, is the total number of cores found on the computer. @@ -211,7 +211,7 @@ def set(self, field=None, nproc=None): Switching off the parallelization:: - sage: Parallelism().set('tensor', nproc=1) + sage: Parallelism().set(nproc=1) sage: Parallelism() Number of processes for parallelization: - tensor computations: 1 @@ -222,20 +222,19 @@ def set(self, field=None, nproc=None): self.set(field=fi, nproc=nproc) else: if field not in self._nproc : - raise KeyError( - """entry for field {0} is not implemented in the Parallelism""".format(field) - ) + raise KeyError("entry for field {} is not ".format(field) + + "implemented in Parallelism") if nproc is None: self._nproc[field] = self._default else: - if not isinstance(nproc,(int,Integer)): + if not isinstance(nproc, (int,Integer)): raise TypeError("nproc must be integer") self._nproc[field] = nproc def get(self, field): r""" - Get the number of processes which will be used in parallel computations - regarding some specific field. + Return the number of processes which will be used in parallel + computations regarding some specific field. INPUT: @@ -244,12 +243,12 @@ def get(self, field): OUTPUT: - - number of processes used in parallelization of computations in the - domain ``field`` + - number of processes used in parallelization of computations + pertaining to ``field`` EXAMPLES: - The default is a single proces (no parallelization):: + The default is a single process (no parallelization):: sage: Parallelism().reset() sage: Parallelism().get('tensor') @@ -270,7 +269,7 @@ def get(self, field): def get_all(self): r""" - Get the number of processes which will be used in parallel + Return the number of processes which will be used in parallel computations in all fields OUTPUT: @@ -301,14 +300,14 @@ def set_default(self, nproc=None): INPUT: - - ``nproc`` -- (defaut: ``None``) default number of processes; + - ``nproc`` -- (default: ``None``) default number of processes; if ``None``, the number of processes will be set to the total number of cores found on the computer. EXAMPLES: - The default number of process for parallelization is the total number - of cores found on the computer:: + A priori the default number of process for parallelization is the + total number of cores found on the computer:: sage: Parallelism().get_default() # random (depends on the computer) 8 @@ -335,14 +334,15 @@ def set_default(self, nproc=None): def get_default(self): r""" - Get the default number of processes to be launched in parallel + Return the default number of processes to be launched in parallel computations. EXAMPLES: - The default number of process for parallelization is the total number - of cores found on the computer:: + A priori, the default number of process for parallelization is the + total number of cores found on the computer:: + sage: Parallelism().reset() sage: Parallelism().get_default() # random (depends on the computer) 8 diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 70db188f3b7..06527217d2d 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1285,15 +1285,17 @@ def __add__(self, other): Parallel computation:: - sage: Parallelism().set('tensor',2); Parallelism().get('tensor') - 2 - sage: s = a.__add__(b) ; s + sage: Parallelism().set('tensor', nproc=2) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 2 + sage: s_par = a.__add__(b) ; s_par 1-index components w.r.t. [1, 2, 3] - sage: s[:] + sage: s_par[:] [5, 5, 3] - sage: s == a+b + sage: s_par == s True - sage: Parallelism().set('tensor',2) + sage: Parallelism().set('tensor', nproc=1) # switch off parallelization """ if other == 0: @@ -1401,15 +1403,17 @@ def __sub__(self, other): Parallel computation:: - sage: Parallelism().set('tensor',2); Parallelism().get('tensor') - 2 - sage: s = a.__sub__(b) ; s + sage: Parallelism().set('tensor', nproc=2) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 2 + sage: s_par = a.__sub__(b) ; s_par 1-index components w.r.t. [1, 2, 3] - sage: s[:] + sage: s_par[:] [-3, -5, -9] - sage: s == a - b + sage: s_par == s True - sage: Parallelism().set('tensor',1) + sage: Parallelism().set('tensor', nproc=1) # switch off parallelization """ if other == 0: @@ -1474,18 +1478,20 @@ def __mul__(self, other): True Parallel computation:: - sage: Parallelism().set('tensor',2); Parallelism().get('tensor') - 2 - sage: s = a.__mul__(b) ; s + + sage: Parallelism().set('tensor', nproc=2) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 2 + sage: s_par = a.__mul__(b) ; s_par 2-indices components w.r.t. [1, 2, 3] - sage: s[:] + sage: s_par[:] [ 4 5 6] [ 0 0 0] [-12 -15 -18] - sage: s == a*b + sage: s_par == s True - sage: Parallelism().set('tensor',1); Parallelism().get('tensor') - 1 + sage: Parallelism().set('tensor', nproc=1) # switch off parallelization """ if not isinstance(other, Components): @@ -1758,37 +1764,43 @@ def contract(self, *args): sage: a[:] = (-1, 2, 3) sage: b = Components(QQ, V.basis(), 2) sage: b[:] = [[1,2,3], [4,5,6], [7,8,9]] - sage: s = a.contract(0, b, 0) ; s + sage: s0 = a.contract(0, b, 0) ; s0 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] - sage: s[:] - [28, 32, 36] - sage: [sum(a[j]*b[j,i] for j in range(3)) for i in range(3)] # check + sage: s0[:] [28, 32, 36] - sage: s = a.contract(0, b, 1) ; s[:] - [12, 24, 36] - sage: [sum(a[j]*b[i,j] for j in range(3)) for i in range(3)] # check + sage: s0[:] == [sum(a[j]*b[j,i] for j in range(3)) for i in range(3)] # check + True + sage: s1 = a.contract(0, b, 1) ; s1[:] [12, 24, 36] + sage: s1[:] == [sum(a[j]*b[i,j] for j in range(3)) for i in range(3)] # check + True - Parallel computation:: + Parallel computations (see + :class:`~sage.parallel.parallelism.Parallelism`):: - sage: Parallelism().set('tensor',2); Parallelism().get('tensor') - 2 - sage: s = a.contract(0, b, 0) ; s + sage: Parallelism().set('tensor', nproc=2) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 2 + sage: s0_par = a.contract(0, b, 0) ; s0_par 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] - sage: s[:] + sage: s0_par[:] [28, 32, 36] - sage: s = a.contract(0, b, 1) ; s[:] + sage: s0_par == s0 + True + sage: s1_par = a.contract(0, b, 1) ; s1_par[:] [12, 24, 36] - sage: Parallelism().set('tensor',1) - + sage: s1_par == s1 + True + sage: Parallelism().set('tensor', nproc = 1) # switch off parallelization Contraction on 2 indices:: @@ -1812,24 +1824,26 @@ def contract(self, *args): Parallel computation:: - sage: Parallelism().set('tensor',2); Parallelism().get('tensor') - 2 - sage: c = a*b ; c + sage: Parallelism().set('tensor', nproc=2) + sage: c_par = a*b ; c_par 3-indices components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] - sage: s = c.contract(1,2, b, 0,1) ; s + sage: c_par == c + True + sage: s_par = c_par.contract(1,2, b, 0,1) ; s_par 1-index components w.r.t. [ (1, 0, 0), (0, 1, 0), (0, 0, 1) ] - sage: s[:] + sage: s_par[:] [-285, 570, 855] - sage: Parallelism().set('tensor',1) - + sage: s_par == s + True + sage: Parallelism().set('tensor', nproc=1) # switch off parallelization Consistency check with :meth:`trace`:: @@ -3205,46 +3219,44 @@ def __mul__(self, other): sage: a[0,1], a[1,2] = 4, 5 sage: b = CompWithSym(ZZ, [1,2,3], 2, sym=(0,1)) sage: b[0,1], b[2,2] = 2, -3 - sage: s = a.__mul__(b) ; s + sage: s1 = a.__mul__(b) ; s1 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) - sage: s[1,0,0,1] + sage: s1[1,0,0,1] 8 - sage: s[1,0,0,1] == a[1,0] * b[0,1] + sage: s1[1,0,0,1] == a[1,0] * b[0,1] True - sage: s == a*b + sage: s1 == a*b True sage: c = CompWithSym(ZZ, [1,2,3], 2, antisym=(0,1)) sage: c[0,1], c[0,2] = 3, 7 - sage: s = a.__mul__(c) ; s + sage: s2 = a.__mul__(c) ; s2 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3) - sage: s[1,0,2,0] + sage: s2[1,0,2,0] -28 - sage: s[1,0,2,0] == a[1,0] * c[2,0] + sage: s2[1,0,2,0] == a[1,0] * c[2,0] True - sage: s == a*c + sage: s2 == a*c True Parallel computation:: - sage: Parallelism().set('tensor',2); Parallelism().get('tensor') - 2 - sage: s = a.__mul__(b) ; s + + sage: Parallelism().set('tensor', nproc=2) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 2 + sage: s1_par = a.__mul__(b) ; s1_par 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) - sage: s[1,0,0,1] + sage: s1_par[1,0,0,1] 8 - sage: s[1,0,0,1] == a[1,0] * b[0,1] - True - sage: s == a*b + sage: s1_par == s1 True - sage: s = a.__mul__(c) ; s + sage: s2_par = a.__mul__(c) ; s2_par 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3) - sage: s[1,0,2,0] + sage: s2_par[1,0,2,0] -28 - sage: s[1,0,2,0] == a[1,0] * c[2,0] + sage: s2_par == s2 True - sage: s == a*c - True - sage: Parallelism().set('tensor',1); Parallelism().get('tensor') - 1 + sage: Parallelism().set('tensor', nproc=1) # switch off parallelization """ if not isinstance(other, Components): @@ -4549,18 +4561,19 @@ def __add__(self, other): Parallel computation:: - sage: Parallelism().set('tensor',2); Parallelism().get('tensor') - 2 - sage: s = a.__add__(c) ; s # the symmetry is lost + sage: Parallelism().set('tensor', nproc=2) + sage: Parallelism() + Number of processes for parallelization: + - tensor computations: 2 + sage: s_par = a.__add__(c) ; s_par 2-indices components w.r.t. (1, 2, 3) sage: s[:] [ 0 7 7] [ 1 0 5] [-7 5 0] - sage: s == a + c + sage: s_par == s True - sage: Parallelism().set('tensor',1) - + sage: Parallelism().set('tensor', nproc=1) # switch off parallelization """ if other == 0: From ea80cfd6f3e3e9f61d8d64a560d22428a9509dd7 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 28 Oct 2015 09:14:31 +0100 Subject: [PATCH 1741/1872] trac #19483: Bugfix --- build/pkgs/bliss/spkg-install | 2 +- src/sage/graphs/bliss.pyx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/pkgs/bliss/spkg-install b/build/pkgs/bliss/spkg-install index e3f9c7cb15a..746526d99b8 100755 --- a/build/pkgs/bliss/spkg-install +++ b/build/pkgs/bliss/spkg-install @@ -18,7 +18,7 @@ for patch in ../patches/*.patch; do done -$MAKE && mv libbliss.a "$SAGE_LOCAL/lib" && mv *.hh "$SAGE_LOCAL/include" +$MAKE && cp libbliss.a "$SAGE_LOCAL/lib" && cp *.hh "$SAGE_LOCAL/include" if [ $? -ne 0 ]; then echo "An error occurred whilst building bliss" diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 6c64a57cc7c..a0b69588b5e 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -311,3 +311,4 @@ def canonical_form(G, partition=None, return_graph=False, certify=False): return sorted(edges),relabel return sorted(edges) + From 4786d52f04c7201d932c7c776a6e1d58169bc463 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 21 Oct 2015 00:59:22 +0200 Subject: [PATCH 1742/1872] Rerun configure if package metadata changed --- Makefile | 2 +- src/doc/en/developer/packaging.rst | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Makefile b/Makefile index a7df7e96cb9..cd3f75f365c 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ build: all-build # If configure was run before, rerun it with the old arguments. # Otherwise, run configure with argument $PREREQ_OPTIONS. -build/make/Makefile: configure +build/make/Makefile: configure build/pkgs/*/* rm -f config.log mkdir -p logs/pkgs ln -s logs/pkgs/config.log config.log diff --git a/src/doc/en/developer/packaging.rst b/src/doc/en/developer/packaging.rst index 1dfa4eea6a2..ac8fc766b58 100644 --- a/src/doc/en/developer/packaging.rst +++ b/src/doc/en/developer/packaging.rst @@ -397,16 +397,6 @@ Sage (``FoO-1.3.tar.gz`` in the example of section in the ``SAGE_ROOT/upstream/`` directory and run ``sage --fix-pkg-checksums`` if you have not done that yet. -In order to update ``build/make/Makefile``, which contains the rules -to build all packages, you need to run the following command from -``SAGE_ROOT``:: - - [user@localhost]$ ./configure - -You need to re-run ``./configure`` whenever you change any package -metadata: if you add or remove a package or if you change the version, -type or dependencies of a package. - Now you can install the package using:: [user@localhost]$ sage -i package_name From 6752cf18c9e4e0f70c041ecf971d17009915a4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 28 Oct 2015 10:43:12 +0100 Subject: [PATCH 1743/1872] trac : adding the q-Bernoulli polynomials of Carlitz --- src/sage/combinat/q_bernoulli.pyx | 71 +++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/q_bernoulli.pyx b/src/sage/combinat/q_bernoulli.pyx index 299d252d33d..d803e779952 100644 --- a/src/sage/combinat/q_bernoulli.pyx +++ b/src/sage/combinat/q_bernoulli.pyx @@ -1,15 +1,15 @@ """ -`q`-Bernoulli Numbers +`q`-Bernoulli Numbers and Polynomials """ - from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.polynomial.polynomial_ring import polygen from sage.misc.cachefunc import cached_function + @cached_function -def q_bernoulli(m,p=None): +def q_bernoulli(m, p=None): r""" - Computes Carlitz's `q`-analogue of the Bernoulli numbers + Compute Carlitz's `q`-analogue of the Bernoulli numbers. For every nonnegative integer `m`, the `q`-Bernoulli number `\beta_m` is a rational function of the indeterminate `q` whose @@ -36,7 +36,7 @@ def q_bernoulli(m,p=None): -1/(q + 1) sage: q_bernoulli(2) q/(q^3 + 2*q^2 + 2*q + 1) - sage: all(q_bernoulli(i)(q=1)==bernoulli(i) for i in range(12)) + sage: all(q_bernoulli(i)(q=1) == bernoulli(i) for i in range(12)) True One can evaluate the rational function by giving a second argument:: @@ -62,10 +62,63 @@ def q_bernoulli(m,p=None): if m < 0: raise ValueError("the argument must be a nonnegative integer.") cdef int i - q = PolynomialRing(ZZ,'q').gen() - result = (q-1)**(1-m)*sum((-1)**(m-i)*m.binomial(i)*(i+1)/(q**(i+1)-1) - for i in range(m+1)) + q = polygen(ZZ, 'q') + result = (q-1)**(1-m) * sum((-1)**(m-i)*m.binomial(i)*(i+1)/(q**(i+1)-1) + for i in range(m + 1)) if p is None: return result else: return result(q=p) + + +@cached_function +def q_bernoulli_polynomial(m): + r""" + Compute Carlitz's `q`-analogue of the Bernoulli polynomials. + + For every nonnegative integer `m`, the `q`-Bernoulli polynomial + is a polynomial in one variable `x` with coefficients in `\QQ(q)` whose + value at `q=1` is the usual Bernoulli polynomial `B_m(x)`. + + This function returns a slight modification of the original + Carlitz `q`-Bernoulli polynomials. + + INPUT: + + - `m` -- a nonnegative integer + + OUTPUT: + + A polynomial in one variable `x`. + + EXAMPLES:: + + sage: from sage.combinat.q_bernoulli import q_bernoulli_polynomial, q_bernoulli + sage: q_bernoulli_polynomial(0) + 1 + sage: q_bernoulli_polynomial(1) + (2/(q + 1))*x - 1/(q + 1) + sage: x = q_bernoulli_polynomial(1).parent().gen() + sage: all(q_bernoulli_polynomial(i)(q=1)==bernoulli_polynomial(x,i) for i in range(12)) + True + sage: all(q_bernoulli_polynomial(i)(x=0)==q_bernoulli(i) for i in range(12)) + True + + The function does not accept negative arguments:: + + sage: q_bernoulli_polynomial(-1) + Traceback (most recent call last): + ... + ValueError: the argument must be a nonnegative integer. + + REFERENCES: [Ca1948]_, [Ca1954]_ + """ + m = ZZ(m) + if m < 0: + raise ValueError("the argument must be a nonnegative integer.") + cdef int i + q = polygen(ZZ, 'q') + x = polygen(q.parent(), 'x') + z = 1 + (q - 1) * x + return sum(m.binomial(i) * x ** (m - i) * z ** i * q_bernoulli(i) + for i in range(m + 1)) From 21d1d70c1da23187c7d230dd950c45980d13cae6 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Wed, 28 Oct 2015 11:19:46 +0100 Subject: [PATCH 1744/1872] Minor modification in the doctests of parallel computation in class Components --- src/sage/tensor/modules/comp.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 06527217d2d..36738219c88 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1286,9 +1286,8 @@ def __add__(self, other): Parallel computation:: sage: Parallelism().set('tensor', nproc=2) - sage: Parallelism() - Number of processes for parallelization: - - tensor computations: 2 + sage: Parallelism().get('tensor') + 2 sage: s_par = a.__add__(b) ; s_par 1-index components w.r.t. [1, 2, 3] sage: s_par[:] @@ -1404,9 +1403,8 @@ def __sub__(self, other): Parallel computation:: sage: Parallelism().set('tensor', nproc=2) - sage: Parallelism() - Number of processes for parallelization: - - tensor computations: 2 + sage: Parallelism().get('tensor') + 2 sage: s_par = a.__sub__(b) ; s_par 1-index components w.r.t. [1, 2, 3] sage: s_par[:] @@ -1480,9 +1478,8 @@ def __mul__(self, other): Parallel computation:: sage: Parallelism().set('tensor', nproc=2) - sage: Parallelism() - Number of processes for parallelization: - - tensor computations: 2 + sage: Parallelism().get('tensor') + 2 sage: s_par = a.__mul__(b) ; s_par 2-indices components w.r.t. [1, 2, 3] sage: s_par[:] @@ -1783,9 +1780,8 @@ def contract(self, *args): :class:`~sage.parallel.parallelism.Parallelism`):: sage: Parallelism().set('tensor', nproc=2) - sage: Parallelism() - Number of processes for parallelization: - - tensor computations: 2 + sage: Parallelism().get('tensor') + 2 sage: s0_par = a.contract(0, b, 0) ; s0_par 1-index components w.r.t. [ (1, 0, 0), @@ -3241,9 +3237,8 @@ def __mul__(self, other): Parallel computation:: sage: Parallelism().set('tensor', nproc=2) - sage: Parallelism() - Number of processes for parallelization: - - tensor computations: 2 + sage: Parallelism().get('tensor') + 2 sage: s1_par = a.__mul__(b) ; s1_par 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) sage: s1_par[1,0,0,1] @@ -4562,9 +4557,8 @@ def __add__(self, other): Parallel computation:: sage: Parallelism().set('tensor', nproc=2) - sage: Parallelism() - Number of processes for parallelization: - - tensor computations: 2 + sage: Parallelism().get('tensor') + 2 sage: s_par = a.__add__(c) ; s_par 2-indices components w.r.t. (1, 2, 3) sage: s[:] From 21b42975eb17072d7bcf2479048ccdd10f5bdf1c Mon Sep 17 00:00:00 2001 From: Stefan Witzel Date: Wed, 28 Oct 2015 12:16:12 +0100 Subject: [PATCH 1745/1872] Adjusted another doctest. --- src/sage/rings/laurent_series_ring_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 6aae7daae9f..77ac755c16e 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -1231,7 +1231,7 @@ cdef class LaurentSeries(AlgebraElement): sage: f.power_series() Traceback (most recent call last): ... - TypeError: self is a not a power series + TypeError: self is not a power series TESTS: From 0a5e36f94b6527ecb77ac0e93d1e60b8e511b6bc Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 28 Oct 2015 11:59:30 +0000 Subject: [PATCH 1746/1872] adding missing docs and tests, part I --- src/sage/combinat/matrices/hadamard_matrix.py | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 3ccb9b0f8c3..9bcfc8ed4f3 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -114,8 +114,7 @@ def hadamard_matrix_paleyI(n, normalize=True): TESTS:: - sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI - sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyI, is_hadamard_matrix) sage: test_cases = [x+1 for x in range(100) if is_prime_power(x) and x%4==3] sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True) ....: for n in test_cases) @@ -181,8 +180,7 @@ def hadamard_matrix_paleyII(n): TESTS:: - sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyII - sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix + sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyII, is_hadamard_matrix) sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1] sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True) ....: for n in test_cases) @@ -212,7 +210,7 @@ def hadamard_matrix_paleyII(n): return normalise_hadamard(H) -def is_hadamard_matrix(M, normalized=False, verbose=False, skew=False): +def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): r""" Test if `M` is a hadamard matrix. @@ -232,7 +230,12 @@ def is_hadamard_matrix(M, normalized=False, verbose=False, skew=False): EXAMPLE:: sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix - sage: is_hadamard_matrix(matrix.hadamard(12)) + sage: h = matrix.hadamard(12) + sage: is_hadamard_matrix(h) + True + sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix + sage: h=skew_hadamard_matrix(12) + sage: is_hadamard_matrix(h, skew=True) True sage: h = matrix.hadamard(12) sage: h[0,0] = 2 @@ -246,7 +249,20 @@ def is_hadamard_matrix(M, normalized=False, verbose=False, skew=False): The matrix is not normalized False + TESTS:: + sage: from sage.combinat.matrices.hadamard_matrix import (is_hadamard_matrix, skew_hadamard_matrix) + sage: h = matrix.hadamard(12) + sage: is_hadamard_matrix(h, skew=True) + False + sage: is_hadamard_matrix(h, skew=True, verbose=True) + The matrix is not skew + False + sage: h=skew_hadamard_matrix(12) + sage: is_hadamard_matrix(h, skew=True, verbose=True) + True + sage: is_hadamard_matrix(h, skew=False, verbose=True) + True """ n = M.ncols() if n != M.nrows(): @@ -280,12 +296,12 @@ def is_hadamard_matrix(M, normalized=False, verbose=False, skew=False): return False if skew: - S = M - I(n) - if -S != S.T: - if verbose: - print "The matrix is not skew" - return False - + for i in xrange(n-1): + for j in xrange(i+1, n): + if M[i,j] != -M[j,i]: + if verbose: + print "The matrix is not skew" + return False return True from sage.matrix.constructor import matrix_method @@ -621,7 +637,7 @@ def true(): return M -def _helper_payley_matrix(n, zero_position=1): +def _helper_payley_matrix(n, zero_position=True): r""" Return the marix constructed in Lemma 1.19 page 291 of [SWW72]_. @@ -637,6 +653,9 @@ def _helper_payley_matrix(n, zero_position=1): - ``n`` -- a prime power + - ``zero_position`` -- is true (default), place 0 of ``F_n`` in the middle, otherwise + place it first. + .. SEEALSO:: :func:`rshcd_from_close_prime_powers` @@ -650,6 +669,10 @@ def _helper_payley_matrix(n, zero_position=1): [-1 1 0 1 -1] [-1 -1 1 0 1] [ 1 -1 -1 1 0] + sage: _helper_payley_matrix(3) + [ 0 -1 1] + [ 1 0 -1] + [-1 1 0] """ from sage.rings.finite_rings.constructor import FiniteField as GF K = GF(n,conway=True,prefix='x') @@ -830,6 +853,21 @@ def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): return M def _GS_skew_hadamard(n, existence=False, check=True): + r""" + Data for Williamson-Goethals-Seidel construction of skew Hadamard matrices + + Here we keep the data for this construction. + Namely, it needs 4 circulant matrices with extra properties, as described in + :func:`sage.combinat.matrices.hadamard_matrix.williamson_goethals_seidel_skew_hadamard_matrix` + + INPUT: + + - ``n`` -- the order of the matrix + + - ``existence`` -- if true (default), only check that we can do the construction + + - ``check`` -- if true (default), check the result. + """ from sage.combinat.matrices.hadamard_matrix import\ williamson_goethals_seidel_skew_hadamard_matrix as WGS def pmtoZ(s): From c284eda90adb73aa4e0a36e0d6467fb76c779654 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 28 Oct 2015 12:36:14 +0000 Subject: [PATCH 1747/1872] moved circulant to matrix. --- src/sage/combinat/matrices/hadamard_matrix.py | 25 +--------- src/sage/matrix/constructor.py | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 9bcfc8ed4f3..b5e87ec2393 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -771,28 +771,6 @@ def rshcd_from_close_prime_powers(n): assert HH**2 == n**2*I(n**2) return HH -def _circulant_matrix(v): - r""" - Return the circulant matrix specified by its 1st row `v` - - A circulant `n \times n` matrix specified by the 1st row `v=(v_0...v_{n-1})` is - the matrix $(c_{ij})_{0 \leq i,j\leq n-1}$ where $c_{ij}=v_{j-i \mod b}$. - - EXAMPLES:: - - sage: from sage.combinat.matrices.hadamard_matrix import _circulant_matrix - sage: v=[1,2,3,4,8] - sage: _circulant_matrix(v) - [1 2 3 4 8] - [8 1 2 3 4] - [4 8 1 2 3] - [3 4 8 1 2] - [2 3 4 8 1] - """ - from sage.rings.finite_rings.integer_mod import mod - n = len(v) - return matrix(n, n, lambda i, j: v[mod(j-i,n)]) - def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): r""" Williamson-Goethals-Seidel construction of a skew Hadamard matrix @@ -836,10 +814,9 @@ def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): """ - from sage.combinat.matrices.hadamard_matrix import _circulant_matrix n = len(a) R = matrix(ZZ, n, n, lambda i,j: 1 if i+j==n-1 else 0) - A,B,C,D=map(_circulant_matrix, [a,b,c,d]) + A,B,C,D=map(matrix.circulant, [a,b,c,d]) if check: assert A*A.T+B*B.T+C*C.T+D*D.T==4*n*I(n) assert A+A.T==2*I(n) diff --git a/src/sage/matrix/constructor.py b/src/sage/matrix/constructor.py index 3f108e1beed..e6efed88099 100644 --- a/src/sage/matrix/constructor.py +++ b/src/sage/matrix/constructor.py @@ -2158,6 +2158,52 @@ def elementary_matrix(arg0, arg1=None, **kwds): else: return elem.transpose() +@matrix_method +def circulant(v, sparse=False): + r""" + Return the circulant matrix specified by its 1st row `v` + + A circulant `n \times n` matrix specified by the 1st row `v=(v_0...v_{n-1})` is + the matrix $(c_{ij})_{0 \leq i,j\leq n-1}$ where $c_{ij}=v_{j-i \mod b}$. + If the input (a vector) is sparse, return a sparse matrix. + Else, by default, if the data is a plain list, return a dense matrix. + + INPUT: + + - ``v`` -- a list or a vector of values + + - ``sparse`` -- if ``v`` is a vector, the output sparsity is determined by the + sparsity of ``v``. Else, by default, it is dense; otherwise, if ``sparse`` is + set to ``True``, it will be sparse. + + EXAMPLES:: + + sage: v=[1,2,3,4,8] + sage: matrix.circulant(v) + [1 2 3 4 8] + [8 1 2 3 4] + [4 8 1 2 3] + [3 4 8 1 2] + [2 3 4 8 1] + sage: matrix.circulant(vector(GF(3),[0,1,-1],sparse=True)) + [0 1 2] + [2 0 1] + [1 2 0] + + TESTS:: + + sage: m = matrix.circulant(vector(GF(3),[0,1,-1],sparse=True)) + sage: m.is_sparse() + True + """ + try: + sparse = v.is_sparse() + except: + pass + n = len(v) + return matrix(n, n, lambda i, j: v[(j-i)%n], sparse=sparse) + + def _determine_block_matrix_grid(sub_matrices): r""" For internal use. This tries to determine the dimensions From 727ac938b282c541f489d273c2a3cf7bbc96fc2e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 27 Oct 2015 14:00:59 +0100 Subject: [PATCH 1748/1872] trac #19484: sage-unzip --- src/bin/sage-unzip | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100755 src/bin/sage-unzip diff --git a/src/bin/sage-unzip b/src/bin/sage-unzip new file mode 100755 index 00000000000..ca0fdf834a8 --- /dev/null +++ b/src/bin/sage-unzip @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# +# This file is a replacement for the 'unzip' command. +# +# We obtain its main feature (extraction) through the 'zipfile' python module. + +import argparse + +parser = argparse.ArgumentParser(description='Extract the contents of a .zip archive') +parser.add_argument('filename', help="the .zip archive", type=argparse.FileType('r')) +parser.add_argument('-d',help='An optional directory to which to extract files. Set to "." by default.',action='store',default='.') + +args = parser.parse_args() +from zipfile import ZipFile +ZipFile(args.filename).extractall(args.d) From 6f5488747fe670975c27d262711b6561fda7c548 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 28 Oct 2015 14:15:27 +0000 Subject: [PATCH 1749/1872] function renaming, documenting, and doctesting, and removing extra if renamed Pseudo_L_2n_4n_m_1, and removed the renamed from the graph catalog renamed witch_skewhad_pow2, and removed the renamed from the graph catalog removed PasechnikGraph from the catalog renamed _L_g_n_params, made it cpdef'd, and added tests for it, and used it to simplify is_orthogonal_array_block_graph replaced an if M==None: with else:. --- src/sage/combinat/matrices/hadamard_matrix.py | 8 ++--- src/sage/graphs/generators/families.py | 28 +++++++-------- src/sage/graphs/graph_generators.py | 6 ---- src/sage/graphs/strongly_regular_db.pyx | 35 +++++++++++-------- 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index b5e87ec2393..de65ea75836 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -992,10 +992,10 @@ def true(): return true() M = _GS_skew_hadamard(n) - if M is None: - if existence: - return Unknown - raise ValueError("A skew Hadamard matrix of order %s is not yet implemented." % n) + else: + if existence: + return Unknown + raise ValueError("A skew Hadamard matrix of order %s is not yet implemented." % n) if check: assert is_hadamard_matrix(M, normalized=False, skew=True) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index dbd8318447b..8496b431d1f 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -1631,7 +1631,7 @@ def PasechnikGraph(n): G.name("Pasechnik Graph_" + str((n))) return G -def Pseudo_L_2n_4n_m_1(n): +def SquaredSkewHadamardMatrixGraph(n): """ Pseudo-`OA(2n,4n-1)`-graph from a skew Hadamard matrix of order `4n` @@ -1639,14 +1639,14 @@ def Pseudo_L_2n_4n_m_1(n): :func:`OrthogonalArrayBlockGraph `, also known as pseudo Latin squares graph `L_{2n}(4n-1)`, constructed from a - skew Hadamard matrix of order `4n` due to Goethals and Seidel, see [BvL84]_. + skew Hadamard matrix of order `4n`, due to Goethals and Seidel, see [BvL84]_. EXAMPLES:: - sage: from sage.graphs.generators.families import Pseudo_L_2n_4n_m_1 - sage: Pseudo_L_2n_4n_m_1(4).is_strongly_regular(parameters=True) + sage: from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph + sage: SquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True) (225, 112, 55, 56) - sage: Pseudo_L_2n_4n_m_1(9).is_strongly_regular(parameters=True) # long time + sage: SquaredSkewHadamardMatrixGraph(9).is_strongly_regular(parameters=True) # long time (1225, 612, 305, 306) """ @@ -1664,24 +1664,24 @@ def Pseudo_L_2n_4n_m_1(n): G.name("skewhad^2_" + str((n))) return G -def switch_skewhad_pow2(n): +def SwitchedSquaredSkewHadamardMatrixGraph(n): """ - a strongly regular graph in Seidel switching class of `Pseudo_L_{2n}(4n-1)` + a strongly regular graph in Seidel switching class of `SquaredSkewHadamardMatrixGraph` A strongly regular graph in the - :meth:`Seidel switching ` class of - func:`Pseudo_L_{2n}(4n-1) - ` + :meth:`Seidel switching ` class of the dijoint union of + a 1-vertex graph and func:`Pseudo-L_{2n}(4n-1) + ` EXAMPLES:: - sage: from sage.graphs.generators.families import switch_skewhad_pow2 - sage: switch_skewhad_pow2(4).is_strongly_regular(parameters=True) + sage: from sage.graphs.generators.families import SwitchedSquaredSkewHadamardMatrixGraph + sage: SwitchedSquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True) (226, 105, 48, 49) """ - from sage.graphs.generators.families import Pseudo_L_2n_4n_m_1 - G = Pseudo_L_2n_4n_m_1(n).complement() + from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph + G = SquaredSkewHadamardMatrixGraph(n).complement() G.add_vertex((4*n-1)**2) G.seidel_switching(range((4*n-1)*(2*n-1))) G.name("switch skewhad^2+*_" + str((n))) diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index f43aa7f0b3b..477400f23b3 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -216,15 +216,12 @@ def __append_to_doc(methods): "NStarGraph", "OddGraph", "PaleyGraph", - "PasechnikGraph", "petersen_family", "planar_graphs", - "Pseudo_L_2n_4n_m_1", "quadrangulations", "RingedTree", "SierpinskiGasketGraph", "strongly_regular_graph", - "switch_skewhad_pow2", "trees", "triangulations", "WheelGraph"]) @@ -1992,13 +1989,10 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None NStarGraph = staticmethod(sage.graphs.generators.families.NStarGraph) OddGraph = staticmethod(sage.graphs.generators.families.OddGraph) PaleyGraph = staticmethod(sage.graphs.generators.families.PaleyGraph) - PasechnikGraph = staticmethod(sage.graphs.generators.families.PasechnikGraph) petersen_family = staticmethod(sage.graphs.generators.families.petersen_family) - Pseudo_L_2n_4n_m_1 = staticmethod(sage.graphs.generators.families.Pseudo_L_2n_4n_m_1) RingedTree = staticmethod(sage.graphs.generators.families.RingedTree) SierpinskiGasketGraph = staticmethod(sage.graphs.generators.families.SierpinskiGasketGraph) strongly_regular_graph = staticmethod(sage.graphs.strongly_regular_db.strongly_regular_graph) - switch_skewhad_pow2 = staticmethod(sage.graphs.generators.families.switch_skewhad_pow2) trees = staticmethod(sage.graphs.generators.families.trees) WheelGraph = staticmethod(sage.graphs.generators.families.WheelGraph) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index acb10dd30e5..bdbd007240c 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -138,14 +138,9 @@ def is_orthogonal_array_block_graph(int v,int k,int l,int mu): # notations from # http://www.win.tue.nl/~aeb/graphs/OA.html from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix - if not is_square(v): - return - n = int(sqrt(v)) - if k % (n-1): - return - m = k//(n-1) - if (l != (m-1)*(m-2)+n-2 or - mu != m*(m-1)): + try: + m, n = latin_squares_graph_parameters(v,k,l,mu) + except: return if orthogonal_array(m,n,existence=True): from sage.graphs.generators.intersection import OrthogonalArrayBlockGraph @@ -153,7 +148,7 @@ def is_orthogonal_array_block_graph(int v,int k,int l,int mu): elif n>2 and skew_hadamard_matrix(n+1, existence=True): if m==(n+1)/2: - from sage.graphs.generators.families import Pseudo_L_2n_4n_m_1 as G + from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph as G elif m==(n-1)/2: from sage.graphs.generators.families import PasechnikGraph as G else: @@ -1322,7 +1317,7 @@ def is_switch_skewhad(int v, int k, int l, int mu): The `switch skewhad^2+*` graphs appear on `Andries Brouwer's database `__ and are built by adding an isolated vertex to the complement of - :func:`~sage.graphs.graph_generators.GraphGenerators.Pseudo_L_2n_4n_m_1`, + :func:`~sage.graphs.graph_generators.GraphGenerators.SquaredSkewHadamardMatrixGraph`, and a :meth:`Seidel switching ` a set of disjoint `n`-cocliques. @@ -1347,7 +1342,7 @@ def is_switch_skewhad(int v, int k, int l, int mu): """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix - from sage.graphs.generators.families import switch_skewhad_pow2 + from sage.graphs.generators.families import SwitchedSquaredSkewHadamardMatrixGraph cdef int n r,s = eigenvalues(v,k,l,mu) if r is None: @@ -1359,7 +1354,7 @@ def is_switch_skewhad(int v, int k, int l, int mu): v == (4*n-1)**2 + 1 and \ k == (4*n-1)*(2*n-1) and \ skew_hadamard_matrix(4*n, existence=True): - return (switch_skewhad_pow2, n) + return (SwitchedSquaredSkewHadamardMatrixGraph, n) def is_switch_OA_srg(int v, int k, int l, int mu): r""" @@ -1447,7 +1442,7 @@ cdef eigenvalues(int v,int k,int l,int mu): (-b-sqrt(D))/2.0] -cdef _L_g_n_params(int v,int k, int l,int mu): +cpdef latin_squares_graph_parameters(int v,int k, int l,int mu): r""" Check whether (v,k,l,mu)-strongly regular graph has parameters of an `L_g(n)` s.r.g. @@ -1456,8 +1451,18 @@ cdef _L_g_n_params(int v,int k, int l,int mu): INPUT: - - ``v,k,l,mu`` (integers) + - ``v,k,l,mu`` -- (integers) parameters of the graph + + OUTPUT: + + - ``(g, n)`` -- parameters of an `L_g(n)` graph, or `None` + + TESTS:: + sage: from sage.graphs.strongly_regular_db import latin_squares_graph_parameters + sage: latin_squares_graph_parameters(9,4,1,2) + (2, 3) + sage: latin_squares_graph_parameters(5,4,1,2) """ cdef int g, n r,s = eigenvalues(v,k,l,mu) @@ -1468,7 +1473,7 @@ cdef _L_g_n_params(int v,int k, int l,int mu): g = -s n = r+g if v==n**2 and k==g*(n-1) and l==(g-1)*(g-2)+n-2 and mu==g*(g-1): - return [g, n] + return g, n return def _H_3_cayley_graph(L): From 6b80f002f5e13f9d165e7ffc41fb984110d6c36a Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 28 Oct 2015 15:49:24 +0000 Subject: [PATCH 1750/1872] added AttributeError to check for in except: --- src/sage/matrix/constructor.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/constructor.py b/src/sage/matrix/constructor.py index e6efed88099..b42d8e0280f 100644 --- a/src/sage/matrix/constructor.py +++ b/src/sage/matrix/constructor.py @@ -2195,10 +2195,14 @@ def circulant(v, sparse=False): sage: m = matrix.circulant(vector(GF(3),[0,1,-1],sparse=True)) sage: m.is_sparse() True + sage: m = matrix.circulant(vector(GF(3),[0,1,-1],sparse=False)) + sage: m.is_sparse() + False """ + from exceptions import AttributeError try: sparse = v.is_sparse() - except: + except AttributeError: pass n = len(v) return matrix(n, n, lambda i, j: v[(j-i)%n], sparse=sparse) From 135c0ea946a630afcba946056ef691c50b315d24 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 28 Oct 2015 16:08:42 +0000 Subject: [PATCH 1751/1872] for a skew Hadamard matrix, check that the diagonal entries are all 1 --- src/sage/combinat/matrices/hadamard_matrix.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index de65ea75836..2e45b6ba25b 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -263,6 +263,12 @@ def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): True sage: is_hadamard_matrix(h, skew=False, verbose=True) True + sage: h=-h + sage: is_hadamard_matrix(h, skew=True, verbose=True) + The matrix is not skew - diagonal entries must be all 1 + False + sage: is_hadamard_matrix(h, skew=False, verbose=True) + True """ n = M.ncols() if n != M.nrows(): @@ -302,6 +308,11 @@ def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): if verbose: print "The matrix is not skew" return False + for i in xrange(n): + if M[i,i] != 1: + if verbose: + print "The matrix is not skew - diagonal entries must be all 1" + return False return True from sage.matrix.constructor import matrix_method From c04916b8e3924ff6da6066185cee62148ecf20c8 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 28 Oct 2015 09:28:24 -0700 Subject: [PATCH 1752/1872] return skew-normalized Hadamard mats by default --- src/sage/combinat/matrices/hadamard_matrix.py | 11 +++++++++-- src/sage/graphs/generators/families.py | 8 ++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 2e45b6ba25b..06cc3c1a4b7 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -885,7 +885,7 @@ def pmtoZ(s): _skew_had_cache={} -def skew_hadamard_matrix(n,existence=False, check=True): +def skew_hadamard_matrix(n,existence=False, skew_normalize=True, check=True): r""" Tries to construct a skew Hadamard matrix @@ -907,6 +907,9 @@ def skew_hadamard_matrix(n,existence=False, check=True): - ``False`` -- meaning that the matrix does not exist. + - ``skew_normalize`` (boolean) -- whether to make the 1st row all-one, and + adjust the 1st column accordingly. Set to ``True`` by default. + - ``check`` (boolean) -- whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` @@ -940,6 +943,8 @@ def skew_hadamard_matrix(n,existence=False, check=True): ValueError: A skew Hadamard matrix of order 10 does not exist sage: skew_hadamard_matrix(36) 36 x 36 dense matrix over Integer Ring... + sage: skew_hadamard_matrix(36)==skew_hadamard_matrix(36,skew_normalize=False) + False sage: skew_hadamard_matrix(52) 52 x 52 dense matrix over Integer Ring... sage: skew_hadamard_matrix(92) @@ -1007,7 +1012,9 @@ def true(): if existence: return Unknown raise ValueError("A skew Hadamard matrix of order %s is not yet implemented." % n) - + if skew_normalize: + dd = diagonal_matrix(M[0]) + M = dd*M*dd if check: assert is_hadamard_matrix(M, normalized=False, skew=True) _skew_had_cache[n]=True diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 8496b431d1f..43c86e82923 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -1621,10 +1621,8 @@ def PasechnikGraph(n): Acta Applicandaie Math. 29(1992), 129-138 """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix - from sage.matrix.constructor import identity_matrix, matrix, diagonal_matrix + from sage.matrix.constructor import identity_matrix, matrix H = skew_hadamard_matrix(4*n) - dd = diagonal_matrix(H[0]) - H = dd*H*dd M = H[1:].T[1:] - identity_matrix(4*n-1) G = Graph(M.tensor_product(M.T), format='seidel_adjacency_matrix') G.relabel() @@ -1651,12 +1649,10 @@ def SquaredSkewHadamardMatrixGraph(n): """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix - from sage.matrix.constructor import identity_matrix, matrix, diagonal_matrix + from sage.matrix.constructor import identity_matrix, matrix idm = identity_matrix(4*n-1) e = matrix([1]*(4*n-1)) H = skew_hadamard_matrix(4*n) - dd = diagonal_matrix(H[0]) - H = dd*H*dd M = H[1:].T[1:] - idm s = M.tensor_product(M.T) - idm.tensor_product(e.T*e - idm) G = Graph(s, format='seidel_adjacency_matrix') From 535e1096291f0c2fdc34b5b28cf5f6728ed76fa1 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 28 Oct 2015 21:56:51 +0000 Subject: [PATCH 1753/1872] putting reference in the right file turns out that one can refer to [blah]_ if [blah] is in super-directory, but not in sub-directory... --- src/sage/graphs/generators/families.py | 7 ------- src/sage/graphs/strongly_regular_db.pyx | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 43c86e82923..b058bc4f64a 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -1612,13 +1612,6 @@ def PasechnikGraph(n): (225, 98, 43, 42) sage: PasechnikGraph(9).is_strongly_regular(parameters=True) # long time (1225, 578, 273, 272) - - REFERENCES: - - .. [Pa92] D. V. Pasechnik, - Skew-symmetric association schemes with two classes and strongly - regular graphs of type `L_{2n-1}(4n- 1)`, - Acta Applicandaie Math. 29(1992), 129-138 """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix from sage.matrix.constructor import identity_matrix, matrix diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index bdbd007240c..9899fcb965b 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -134,6 +134,13 @@ def is_orthogonal_array_block_graph(int v,int k,int l,int mu): (225, 112, 55, 56) sage: t = is_orthogonal_array_block_graph(5,5,5,5); t + + REFERENCE: + + .. [Pa92] D. V. Pasechnik, + Skew-symmetric association schemes with two classes and strongly + regular graphs of type `L_{2n-1}(4n- 1)`, + Acta Applicandaie Math. 29(1992), 129-138 """ # notations from # http://www.win.tue.nl/~aeb/graphs/OA.html From 8a972ca553d93eaa81c9f8e49112c2e44606f6e4 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Thu, 29 Oct 2015 00:18:18 +0100 Subject: [PATCH 1754/1872] Updated Sage version to 6.10.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 4f9f6ab9cf8..feb64723094 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Sage version 6.10.beta1, released 2015-10-21 +Sage version 6.10.beta2, released 2015-10-28 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 45719e0ee55..c6a3fac1146 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=35bf9f2f9f36a2027fb78b0e32e967c60d9e9605 -md5=2d76276badfea4dd5bf52b5589d3af87 -cksum=3537008558 +sha1=d7f2ecde69b59bec3887fd0ba1f4e2784394fd6b +md5=fa6127892f72b56b96a592fcec729f25 +cksum=1455899060 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 9289ddcee34..9f54fe3133b 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -121 +122 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index 6a94ac82e24..f2a44eff412 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath Version 6.10.beta1, Release Date: 2015-10-21 │ +│ SageMath Version 6.10.beta2, Release Date: 2015-10-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 f18d20a0ade..9330d0a3dbb 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.10.beta1' -SAGE_RELEASE_DATE='2015-10-21' +SAGE_VERSION='6.10.beta2' +SAGE_RELEASE_DATE='2015-10-28' diff --git a/src/sage/version.py b/src/sage/version.py index 8ed36a37275..6de652178fb 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.10.beta1' -date = '2015-10-21' +version = '6.10.beta2' +date = '2015-10-28' From 635a994510bf2b93c441bf857bd408ba29ce18ee Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 26 Oct 2015 11:26:47 +0100 Subject: [PATCH 1755/1872] Trac #19496: Remove problematic "assert" If one of the eigenvalues vanishes, inserting small values of n will lead to ZeroDivision. Thus remove the "assert". --- src/sage/combinat/finite_state_machine.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index d44b4105055..fd4c1b7a3d2 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9813,13 +9813,11 @@ def jordan_block_power(block, exponent): def matrix_power(A, exponent): J, T = A.jordan_form(QQbar, transformation=True) - assert T*J*T.inverse() == A Jpower = matrix.block_diagonal( [jordan_block_power(J.subdivision(j, j), exponent) for j in range(len(J.subdivisions()[0])+1) ]) P = Jpower.parent() result = P(T)*Jpower*P(T).inverse() - assert all(result.subs(n=_) == A**_ for _ in range(5)) return result if not self.is_deterministic(): From 01763fd38506f8721560fa29e60227e5081db08b Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 29 Oct 2015 10:03:23 +0000 Subject: [PATCH 1756/1872] remove #random from paleyI/II and fix the test --- src/sage/combinat/matrices/hadamard_matrix.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 06cc3c1a4b7..3d716301b1c 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -95,7 +95,7 @@ def hadamard_matrix_paleyI(n, normalize=True): We note that this method by default returns a normalised Hadamard matrix :: sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI - sage: hadamard_matrix_paleyI(4) # random + sage: hadamard_matrix_paleyI(4) [ 1 1 1 1] [ 1 -1 1 -1] [ 1 -1 -1 1] @@ -104,11 +104,11 @@ def hadamard_matrix_paleyI(n, normalize=True): Otherwise, it returns a skew Hadamard matrix `H`, i.e. `H=S+I`, with `S=-S^\top` :: - sage: M=hadamard_matrix_paleyI(4, normalize=False); M # random + sage: M=hadamard_matrix_paleyI(4, normalize=False); M [ 1 1 1 1] - [ 1 -1 1 -1] - [ 1 -1 -1 1] - [ 1 1 -1 -1] + [-1 1 1 -1] + [-1 -1 1 1] + [-1 1 -1 1] sage: S=M-identity_matrix(4); -S==S.T True @@ -159,7 +159,7 @@ def hadamard_matrix_paleyII(n): We note that the method returns a normalised Hadamard matrix :: - sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12) # random + sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12) [ 1 1| 1 1| 1 1| 1 1| 1 1| 1 1] [ 1 -1|-1 1|-1 1|-1 1|-1 1|-1 1] [-----+-----+-----+-----+-----+-----] From fd56bbb74a7d64324d9e10d2cfd3ae38185b8944 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 29 Oct 2015 13:49:46 +0000 Subject: [PATCH 1757/1872] Mathon's graphs on 784 vertices --- .../graphs/generators/classical_geometries.py | 38 ++++++++++ src/sage/graphs/strongly_regular_db.pyx | 71 +++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 33ebf67da74..5d28644e93e 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -1102,3 +1102,41 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, G = IncidenceStructure(L).dual().intersection_graph() G.name('T2*(O,'+str(q)+'); GQ'+str((q-1,q+1))) return G + +def EllipticLinesProjectivePlaneScheme(k): + r""" + Pseudo-cyclic association scheme for action of `O(3,2^k)` on elliptic lines + + The group `O(3,2^k)` acts naturally on the `q(q-1)/2` lines of `PG(2,2^k)` + skew to the conic preseerved by it, see Sect. 12.7.B of [BCN89]_ and Sect. 6.D + in [BvL84]_. Compute the orbitals of this action and return them. + + INPUT: + + - ``k`` (integer) -- the exponent of 2 to get the field size + + TESTS:: + + sage: from sage.graphs.generators.classical_geometries import EllipticLinesProjectivePlaneScheme + sage: EllipticLinesProjectivePlaneScheme(2) + [ + [1 0 0 0 0 0] [0 1 1 1 1 0] [0 0 0 0 0 1] + [0 1 0 0 0 0] [1 0 1 1 0 1] [0 0 0 0 1 0] + [0 0 1 0 0 0] [1 1 0 0 1 1] [0 0 0 1 0 0] + [0 0 0 1 0 0] [1 1 0 0 1 1] [0 0 1 0 0 0] + [0 0 0 0 1 0] [1 0 1 1 0 1] [0 1 0 0 0 0] + [0 0 0 0 0 1], [0 1 1 1 1 0], [1 0 0 0 0 0] + ] + """ + from sage.libs.gap.libgap import libgap + from sage.matrix.constructor import matrix + from itertools import product + q = 2**k + g0 = libgap.GeneralOrthogonalGroup(3,q) # invariant form x0^2+x1*x2 + g = libgap.Group(libgap.List(g0.GeneratorsOfGroup(),libgap.TransposedMat)) + W = libgap.FullRowSpace(libgap.GF(q), 3) + l=sum(libgap.Elements(libgap.Basis(W))) + gp = libgap.Action(g,libgap.Orbit(g,l,libgap.OnLines),libgap.OnLines) + orbitals = gp.Orbits(list(product(gp.Orbit(1),gp.Orbit(1))),libgap.OnTuples) + mats = map(lambda o: map(lambda x: (int(x[0])-1,int(x[1])-1), o), orbitals) + return map(lambda x: matrix(q*(q-1)/2, lambda i,j: 1 if (i,j) in x else 0), mats) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 4132a81183b..308d668624e 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1757,6 +1757,74 @@ def strongly_regular_from_two_weight_code(L): G.relabel() return G +def mathon_pseudocylcic_merging_graph(M, t): + r""" + Mathon's merging of classes in a pseudo-cyclic 3-class association scheme + + Construct strongly regular graphs from p.97 of [BvL84]_. + + INPUT: + + - ``M`` -- the list of matrices in a pseudo-cyclic 3-class association scheme. + The identity matrix must be the first entry. + + - ``t`` (integer) -- the number of the graph, from 0 to 2. + + TESTS:: + + sage: from sage.graphs.strongly_regular_db import mathon_pseudocylcic_merging_graph + sage: from sage.graphs.generators.classical_geometries import EllipticLinesProjectivePlaneScheme as ES + sage: G = mathon_pseudocylcic_merging_graph(ES(3), 0) # long time + sage: sage: G.is_strongly_regular(parameters=True) # long time + (784, 243, 82, 72) + sage: G = mathon_pseudocylcic_merging_graph(ES(3), 1) # long time + sage: sage: G.is_strongly_regular(parameters=True) # long time + (784, 270, 98, 90) + sage: G = mathon_pseudocylcic_merging_graph(ES(3), 2) # long time + sage: sage: G.is_strongly_regular(parameters=True) # long time + (784, 297, 116, 110) + sage: G = mathon_pseudocylcic_merging_graph(ES(2), 2) + Traceback (most recent call last): + ... + AssertionError... + sage: M = ES(3) + sage: M = [M[1],M[0],M[2],M[3]] + sage: G = mathon_pseudocylcic_merging_graph(M, 2) + Traceback (most recent call last): + ... + AssertionError... + """ + from sage.graphs.graph import Graph + from sage.matrix.constructor import identity_matrix + assert (len(M) == 4) + assert (M[0]==identity_matrix(M[0].nrows())) + A = sum(map(lambda x: x.tensor_product(x), M[1:])) + if t > 0: + A += sum(map(lambda x: x.tensor_product(M[0]), M[1:])) + if t > 1: + A += sum(map(lambda x: M[0].tensor_product(x), M[1:])) + return Graph(A) + +def mathon_graph_on_784_vertices(t): + r""" + return one of Mathon's graphs on 784 vertices + + INPUT: + + - ``t`` (integer) -- the number of the graph, from 0 to 2. + + EXAMPLE:: + + sage: from sage.graphs.strongly_regular_db import mathon_graph_on_784_vertices + sage: G = mathon_graph_on_784_vertices(0) + sage: G.is_strongly_regular(parameters=True) + (784, 243, 82, 72) + """ + from sage.graphs.generators.classical_geometries import \ + EllipticLinesProjectivePlaneScheme as ES + + return mathon_pseudocylcic_merging_graph(ES(3), t) + def SRG_256_187_138_132(): r""" Return a `(256, 187, 138, 132)`-strongly regular graph. @@ -2786,6 +2854,9 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (729, 560, 433,420): [SRG_729_560_433_420], (729, 476, 313,306): [SRG_729_476_313_306], (729, 532, 391,380): [SRG_729_532_391_380], + (784, 243, 82, 72): [mathon_graph_on_784_vertices, 0], + (784, 270, 98, 90): [mathon_graph_on_784_vertices, 1], + (784, 297, 116, 110):[mathon_graph_on_784_vertices, 2], (1024,825, 668,650): [SRG_1024_825_668_650], (1782,416, 100, 96): [SuzukiGraph], } From 9110eaf58841002bdb280be8468ba7563c78d46d Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 29 Oct 2015 15:53:09 +0100 Subject: [PATCH 1758/1872] Removed deprecated cyclotomic_cosets --- src/sage/coding/code_constructions.py | 42 --------------------------- 1 file changed, 42 deletions(-) diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index 34270dfd17b..6b464d6ed1d 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -164,48 +164,6 @@ ############### utility functions ################ -def cyclotomic_cosets(q, n, t = None): - r""" - This method is deprecated. - - See the documentation in - :func:`~sage.categories.rings.Rings.Finite.ParentMethods.cyclotomic_cosets`. - - INPUT: q,n,t positive integers (or t=None) Some type-checking of - inputs is performed. - - OUTPUT: q-cyclotomic cosets mod n (or, if t is not None, the q-cyclotomic - coset mod n containing t) - - EXAMPLES:: - - sage: cyclotomic_cosets(2,11) - doctest:...: DeprecationWarning: cyclotomic_cosets(q,n,t) is deprecated. - Use Zmod(n).cyclotomic_cosets(q) or Zmod(n).cyclotomic_cosets(q,[t]) - instead. Be careful that this method returns elements of Zmod(n). - See http://trac.sagemath.org/16464 for details. - [[0], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]] - - sage: Zmod(11).cyclotomic_cosets(2) - [[0], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]] - - sage: cyclotomic_cosets(5,11) - [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] - sage: cyclotomic_cosets(5,11,3) - [1, 3, 4, 5, 9] - """ - from sage.misc.superseded import deprecation - deprecation(16464, """cyclotomic_cosets(q,n,t) is deprecated. Use - Zmod(n).cyclotomic_cosets(q) or - Zmod(n).cyclotomic_cosets(q,[t]) instead. Be careful - that this method returns elements of Zmod(n).""") - - from sage.rings.finite_rings.integer_mod_ring import Zmod - if t is None: - return [[x.lift() for x in cos] for cos in Zmod(n).cyclotomic_cosets(q)] - else: - return [x.lift() for x in Zmod(n).cyclotomic_cosets(q,[t])[0]] - def is_a_splitting(S1, S2, n, return_automorphism=False): """ Check wether ``(S1,S2)`` is a splitting of `\ZZ/n\ZZ`. From bc6ecf9dd1596562e824a9fd02840d4ea7ce7874 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 29 Oct 2015 16:00:54 +0100 Subject: [PATCH 1759/1872] New catalog for bounds. Some changes in all.py, fixed doctests. --- src/doc/en/reference/coding/index.rst | 1 + .../en/thematic_tutorials/coding_theory.rst | 14 ++-- src/sage/coding/all.py | 59 ++++++++-------- src/sage/coding/bounds_catalog.py | 35 ++++++++++ src/sage/coding/code_bounds.py | 68 +++++++++---------- src/sage/coding/codes_catalog.py | 1 + 6 files changed, 110 insertions(+), 68 deletions(-) create mode 100644 src/sage/coding/bounds_catalog.py diff --git a/src/doc/en/reference/coding/index.rst b/src/doc/en/reference/coding/index.rst index 6311e17f696..a96991cd80d 100644 --- a/src/doc/en/reference/coding/index.rst +++ b/src/doc/en/reference/coding/index.rst @@ -15,6 +15,7 @@ Coding Theory sage/coding/code_constructions sage/coding/guava sage/coding/sd_codes + sage/coding/bounds_catalog sage/coding/code_bounds sage/coding/codecan/codecan sage/coding/codecan/autgroup_can_label diff --git a/src/doc/en/thematic_tutorials/coding_theory.rst b/src/doc/en/thematic_tutorials/coding_theory.rst index 1a436882330..dc37743a4c5 100644 --- a/src/doc/en/thematic_tutorials/coding_theory.rst +++ b/src/doc/en/thematic_tutorials/coding_theory.rst @@ -792,7 +792,7 @@ Regarding bounds on coding theory parameters, this module implements: :: - sage: dimension_upper_bound(10, 3, 2) + sage: codes.bounds.dimension_upper_bound(10, 3, 2) 6 This was established in the example above. @@ -942,17 +942,17 @@ Here are all the bounds together: :: - sage: f1 = lambda x: gv_bound_asymp(x,2) + sage: f1 = lambda x: codes.bounds.gv_bound_asymp(x,2) sage: P1 = plot(f1,0,1/2,linestyle=":") - sage: f2 = lambda x: plotkin_bound_asymp(x,2) + sage: f2 = lambda x: codes.bounds.plotkin_bound_asymp(x,2) sage: P2 = plot(f2,0,1/2,linestyle="--") - sage: f3 = lambda x: elias_bound_asymp(x,2) + sage: f3 = lambda x: codes.bounds.elias_bound_asymp(x,2) sage: P3 = plot(f3,0,1/2,rgbcolor=(1,0,0)) - sage: f4 = lambda x: singleton_bound_asymp(x,2) + sage: f4 = lambda x: codes.bounds.singleton_bound_asymp(x,2) sage: P4 = plot(f4,0,1/2,linestyle="-.") - sage: f5 = lambda x: mrrw1_bound_asymp(x,2) + sage: f5 = lambda x: codes.bounds.mrrw1_bound_asymp(x,2) sage: P5 = plot(f5,0,1/2,linestyle="steps") - sage: f6 = lambda x: hamming_bound_asymp(x,2) + sage: f6 = lambda x: codes.bounds.hamming_bound_asymp(x,2) sage: P6 = plot(f6,0,1/2,rgbcolor=(0,1,0)) sage: show(P1+P2+P3+P4+P5+P6) diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 105e7505def..a8a96e35429 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -1,39 +1,44 @@ from sage.misc.lazy_import import lazy_import -lazy_import("sage.coding.code_constructions", ["permutation_action",\ - "walsh_matrix",\ - "cyclotomic_cosets"]) +lazy_import("sage.coding.code_constructions", ["permutation_action", + "walsh_matrix"]) -lazy_import("sage.coding.code_bounds", ["codesize_upper_bound",\ - "dimension_upper_bound",\ - "volume_hamming",\ - "gilbert_lower_bound",\ - "plotkin_upper_bound",\ - "griesmer_upper_bound",\ - "elias_upper_bound",\ - "hamming_upper_bound",\ - "singleton_upper_bound",\ - "gv_info_rate",\ - "entropy",\ - "gv_bound_asymp",\ - "hamming_bound_asymp",\ - "singleton_bound_asymp",\ - "plotkin_bound_asymp",\ - "elias_bound_asymp",\ - "mrrw1_bound_asymp"]) +from sage.misc.superseded import deprecated_callable_import +deprecated_callable_import(19315, + "sage.coding.code_bounds", + globals(), + locals(), + ["codesize_upper_bound", + "dimension_upper_bound", + "volume_hamming", + "gilbert_lower_bound", + "plotkin_upper_bound", + "griesmer_upper_bound", + "elias_upper_bound", + "hamming_upper_bound", + "singleton_upper_bound", + "gv_info_rate", + "entropy", + "gv_bound_asymp", + "hamming_bound_asymp", + "singleton_bound_asymp", + "plotkin_bound_asymp", + "elias_bound_asymp", + "mrrw1_bound_asymp"], + ("This method soon will not be available in that way." + "Please call codes.bounds.%(name)s instead")) -lazy_import("sage.coding.linear_code", ["LinearCode",\ - "LinearCodeFromVectorSpace",\ - "best_known_linear_code",\ - "best_known_linear_code_www",\ +lazy_import("sage.coding.linear_code", ["LinearCode", + "LinearCodeFromVectorSpace", + "best_known_linear_code", + "best_known_linear_code_www", "bounds_minimum_distance", "self_orthogonal_binary_codes"]) -lazy_import("sage.coding.delsarte_bounds", ["Krawtchouk",\ - "delsarte_bound_hamming_space",\ +lazy_import("sage.coding.delsarte_bounds", ["Krawtchouk", + "delsarte_bound_hamming_space", "delsarte_bound_additive_hamming_space"]) from sd_codes import self_dual_codes_binary -#lazy_import("sage.coding.sd_codes", "self_dual_codes_binary") lazy_import('sage.coding', 'codes_catalog', 'codes') lazy_import('sage.coding', 'channels_catalog', 'channels') diff --git a/src/sage/coding/bounds_catalog.py b/src/sage/coding/bounds_catalog.py new file mode 100644 index 00000000000..aca2e2448f3 --- /dev/null +++ b/src/sage/coding/bounds_catalog.py @@ -0,0 +1,35 @@ +r""" +Index of bounds + +The ``codes.bounds`` object may be used to access the bounds that Sage can compute. + +{INDEX_OF_FUNCTIONS} + +.. NOTE:: + + To import these names into the global namespace, use: + + sage: from sage.coding.bounds_catalog import * +""" +from sage.misc.lazy_import import lazy_import as _lazy_import +_lazy_import("sage.coding.code_bounds", ["codesize_upper_bound", + "dimension_upper_bound", + "volume_hamming", + "gilbert_lower_bound", + "plotkin_upper_bound", + "griesmer_upper_bound", + "elias_upper_bound", + "hamming_upper_bound", + "singleton_upper_bound", + "gv_info_rate", + "entropy", + "gv_bound_asymp", + "hamming_bound_asymp", + "singleton_bound_asymp", + "plotkin_bound_asymp", + "elias_bound_asymp", + "mrrw1_bound_asymp"]) + +from sage.misc.rest_index_of_methods import gen_rest_table_index as _gen_rest_table_index +import sys as _sys +__doc__ = __doc__.format(INDEX_OF_FUNCTIONS=_gen_rest_table_index(_sys.modules[__name__], only_local_functions=False)) diff --git a/src/sage/coding/code_bounds.py b/src/sage/coding/code_bounds.py index 3ecc60e23a4..0a9a16e3335 100644 --- a/src/sage/coding/code_bounds.py +++ b/src/sage/coding/code_bounds.py @@ -217,17 +217,17 @@ def codesize_upper_bound(n,d,q,algorithm=None): EXAMPLES:: - sage: codesize_upper_bound(10,3,2) + sage: codes.bounds.codesize_upper_bound(10,3,2) 93 - sage: codesize_upper_bound(24,8,2,algorithm="LP") + sage: codes.bounds.codesize_upper_bound(24,8,2,algorithm="LP") 4096 - sage: codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.codesize_upper_bound(10,3,2,algorithm="gap") # optional - gap_packages (Guava package) 85 - sage: codesize_upper_bound(11,3,4,algorithm=None) + sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm=None) 123361 - sage: codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="gap") # optional - gap_packages (Guava package) 123361 - sage: codesize_upper_bound(11,3,4,algorithm="LP") + sage: codes.bounds.codesize_upper_bound(11,3,4,algorithm="LP") 109226 """ @@ -254,11 +254,11 @@ def dimension_upper_bound(n,d,q,algorithm=None): EXAMPLES:: - sage: dimension_upper_bound(10,3,2) + sage: codes.bounds.dimension_upper_bound(10,3,2) 6 - sage: dimension_upper_bound(30,15,4) + sage: codes.bounds.dimension_upper_bound(30,15,4) 13 - sage: dimension_upper_bound(30,15,4,algorithm="LP") + sage: codes.bounds.dimension_upper_bound(30,15,4,algorithm="LP") 12 """ @@ -277,7 +277,7 @@ def volume_hamming(n,q,r): EXAMPLES:: - sage: volume_hamming(10,2,3) + sage: codes.bounds.volume_hamming(10,2,3) 176 """ ans=sum([factorial(n)/(factorial(i)*factorial(n-i))*(q-1)**i for i in range(r+1)]) @@ -290,7 +290,7 @@ def gilbert_lower_bound(n,q,d): EXAMPLES:: - sage: gilbert_lower_bound(10,2,3) + sage: codes.bounds.gilbert_lower_bound(10,2,3) 128/7 """ ans=q**n/volume_hamming(n,q,d-1) @@ -306,9 +306,9 @@ def plotkin_upper_bound(n,q,d, algorithm=None): EXAMPLES:: - sage: plotkin_upper_bound(10,2,3) + sage: codes.bounds.plotkin_upper_bound(10,2,3) 192 - sage: plotkin_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.plotkin_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 192 """ if algorithm=="gap": @@ -338,9 +338,9 @@ def griesmer_upper_bound(n,q,d,algorithm=None): EXAMPLES:: - sage: griesmer_upper_bound(10,2,3) + sage: codes.bounds.griesmer_upper_bound(10,2,3) 128 - sage: griesmer_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.griesmer_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 128 """ if algorithm=="gap": @@ -373,9 +373,9 @@ def elias_upper_bound(n,q,d,algorithm=None): EXAMPLES:: - sage: elias_upper_bound(10,2,3) + sage: codes.bounds.elias_upper_bound(10,2,3) 232 - sage: elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) + sage: codes.bounds.elias_upper_bound(10,2,3,algorithm="gap") # optional - gap_packages (Guava package) 232 """ @@ -425,7 +425,7 @@ def hamming_upper_bound(n,q,d): EXAMPLES:: - sage: hamming_upper_bound(10,2,3) + sage: codes.bounds.hamming_upper_bound(10,2,3) 93 """ return int((q**n)/(volume_hamming(n, q, int((d-1)/2)))) @@ -452,7 +452,7 @@ def singleton_upper_bound(n,q,d): EXAMPLES:: - sage: singleton_upper_bound(10,2,3) + sage: codes.bounds.singleton_upper_bound(10,2,3) 256 """ return q**(n - d + 1) @@ -464,7 +464,7 @@ def gv_info_rate(n,delta,q): EXAMPLES:: - sage: RDF(gv_info_rate(100,1/4,3)) # abs tol 1e-15 + sage: RDF(codes.bounds.gv_info_rate(100,1/4,3)) # abs tol 1e-15 0.36704992608261894 """ q = ZZ(q) @@ -484,20 +484,20 @@ def entropy(x, q=2): EXAMPLES:: - sage: entropy(0, 2) + sage: codes.bounds.entropy(0, 2) 0 - sage: entropy(1/5,4) + sage: codes.bounds.entropy(1/5,4) 1/5*log(3)/log(4) - 4/5*log(4/5)/log(4) - 1/5*log(1/5)/log(4) - sage: entropy(1, 3) + sage: codes.bounds.entropy(1, 3) log(2)/log(3) Check that values not within the limits are properly handled:: - sage: entropy(1.1, 2) + sage: codes.bounds.entropy(1.1, 2) Traceback (most recent call last): ... ValueError: The entropy function is defined only for x in the interval [0, 1] - sage: entropy(1, 1) + sage: codes.bounds.entropy(1, 1) Traceback (most recent call last): ... ValueError: The value q must be an integer greater than 1 @@ -571,9 +571,9 @@ def gv_bound_asymp(delta,q): EXAMPLES:: - sage: RDF(gv_bound_asymp(1/4,2)) + sage: RDF(codes.bounds.gv_bound_asymp(1/4,2)) 0.18872187554086... - sage: f = lambda x: gv_bound_asymp(x,2) + sage: f = lambda x: codes.bounds.gv_bound_asymp(x,2) sage: plot(f,0,1) Graphics object consisting of 1 graphics primitive """ @@ -586,9 +586,9 @@ def hamming_bound_asymp(delta,q): EXAMPLES:: - sage: RDF(hamming_bound_asymp(1/4,2)) + sage: RDF(codes.bounds.hamming_bound_asymp(1/4,2)) 0.456435556800... - sage: f = lambda x: hamming_bound_asymp(x,2) + sage: f = lambda x: codes.bounds.hamming_bound_asymp(x,2) sage: plot(f,0,1) Graphics object consisting of 1 graphics primitive """ @@ -600,9 +600,9 @@ def singleton_bound_asymp(delta,q): EXAMPLES:: - sage: singleton_bound_asymp(1/4,2) + sage: codes.bounds.singleton_bound_asymp(1/4,2) 3/4 - sage: f = lambda x: singleton_bound_asymp(x,2) + sage: f = lambda x: codes.bounds.singleton_bound_asymp(x,2) sage: plot(f,0,1) Graphics object consisting of 1 graphics primitive """ @@ -615,7 +615,7 @@ def plotkin_bound_asymp(delta,q): EXAMPLES:: - sage: plotkin_bound_asymp(1/4,2) + sage: codes.bounds.plotkin_bound_asymp(1/4,2) 1/2 """ r = 1-1/q @@ -628,7 +628,7 @@ def elias_bound_asymp(delta,q): EXAMPLES:: - sage: elias_bound_asymp(1/4,2) + sage: codes.bounds.elias_bound_asymp(1/4,2) 0.39912396330... """ r = 1-1/q @@ -641,7 +641,7 @@ def mrrw1_bound_asymp(delta,q): EXAMPLES:: - sage: mrrw1_bound_asymp(1/4,2) # abs tol 4e-16 + sage: codes.bounds.mrrw1_bound_asymp(1/4,2) # abs tol 4e-16 0.3545789026652697 """ return RDF(entropy((q-1-delta*(q-2)-2*sqrt((q-1)*delta*(1-delta)))/q,q)) diff --git a/src/sage/coding/codes_catalog.py b/src/sage/coding/codes_catalog.py index 9af7b3a908c..03bbdbec4ca 100644 --- a/src/sage/coding/codes_catalog.py +++ b/src/sage/coding/codes_catalog.py @@ -31,6 +31,7 @@ from guava import BinaryReedMullerCode, QuasiQuadraticResidueCode, RandomLinearCodeGuava import encoders_catalog as encoders +import bounds_catalog as bounds from sage.misc.rest_index_of_methods import gen_rest_table_index as _gen_rest_table_index import sys as _sys __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=_gen_rest_table_index(_sys.modules[__name__], only_local_functions=False)) From 2497282901353b174fc8d290be0532c3874d4952 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 29 Oct 2015 15:08:23 +0100 Subject: [PATCH 1760/1872] Improve comparison framework --- src/sage/numerical/linear_functions.pyx | 42 +++--- src/sage/numerical/linear_tensor_element.pyx | 2 +- src/sage/rings/integer.pyx | 29 ++-- .../rings/padics/padic_generic_element.pyx | 14 -- src/sage/rings/polynomial/pbori.pyx | 62 ++++++--- src/sage/structure/coerce.pyx | 100 +++++++++++--- src/sage/structure/element.pxd | 3 +- src/sage/structure/element.pyx | 126 +++++------------- 8 files changed, 199 insertions(+), 179 deletions(-) diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index 2e88237077b..5b7e5107e94 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -291,12 +291,12 @@ cdef class LinearFunctionsParent_class(Parent): - ``free_module`` -- vector space or matrix space over the same base ring. - + OUTPUT: Instance of :class:`sage.numerical.linear_tensor.LinearTensorParent_class`. - + EXAMPLES:: sage: LF = MixedIntegerLinearProgram().linear_functions_parent() @@ -703,7 +703,7 @@ cdef class LinearFunction(ModuleElement): [x_0 0 ] [0 x_0] sage: tf.parent() - Tensor product of Full MatrixSpace of 2 by 2 dense matrices over + Tensor product of Full MatrixSpace of 2 by 2 dense matrices over Rational Field and Linear functions over Rational Field """ R = self.base_ring() @@ -841,7 +841,7 @@ cdef class LinearFunction(ModuleElement): """ return (left-right).is_zero() - cdef _richcmp(left, right, int op): + def __richcmp__(left, right, int op): """ Create an inequality or equality object. @@ -898,8 +898,8 @@ cdef class LinearFunction(ModuleElement): 1 <= x_0 sage: 1 >= x[0] x_0 <= 1 - """ - LF = left.parent() + """ + LF = (left)._parent LC = LinearConstraintsParent(LF) equality = (op == Py_EQ) cdef LinearConstraint left_constraint = LC(left, equality=equality) @@ -928,10 +928,10 @@ cdef class LinearFunction(ModuleElement): sage: d = {} sage: d[f] = 3 """ - # see _cmp_() if you want to change the hash function + # see __cmp__() if you want to change the hash function return hash_by_id( self) - cpdef int _cmp_(left, Element right) except -2: + def __cmp__(left, right): """ Implement comparison of two linear functions. @@ -1238,9 +1238,7 @@ cdef class LinearConstraint(Element): """ Evil hack to allow chained constraints - Python translates ``x < y < z`` into: - - .. code-block:: python + Python translates ``x < y < z`` into:: temp = x <= y # calls x.__richcmp__(y) if temp: # calls temp.__nonzero__() @@ -1475,7 +1473,7 @@ cdef class LinearConstraint(Element): self._chained_comparator_hack_part2() return True - cdef _richcmp(py_left, py_right, int op): + def __richcmp__(py_left, py_right, int op): """ Chain (in)equalities @@ -1488,14 +1486,18 @@ cdef class LinearConstraint(Element): sage: b[0] <= 1 <= b[1] <= 2 <= b[2] <= 3 x_0 <= 1 <= x_1 <= 2 <= x_2 <= 3 """ - # print 'richcmp', py_left, ', ', py_right - LC = py_left.parent() - if not is_LinearConstraint(py_right): - py_right = LC(py_right, equality=py_left.is_equation()) - elif py_right.parent() is not LC: - py_right = LC(py_right.constraints, equality=py_left.is_equation()) - cdef LinearConstraint right = py_right - cdef LinearConstraint left = py_left._chained_comparator_hack_part1(right) + cdef LinearConstraint left = py_left + LC = left._parent + cdef LinearConstraint right + try: + right = py_right + except TypeError: + right = LC(py_right, equality=left.is_equation()) + + if right._parent is not LC: + right = LC(right.constraints, equality=left.is_equation()) + + left = left._chained_comparator_hack_part1(right) if op == Py_LT: raise ValueError("strict < is not allowed, use <= instead.") elif op == Py_EQ: diff --git a/src/sage/numerical/linear_tensor_element.pyx b/src/sage/numerical/linear_tensor_element.pyx index 30ad818bc04..617d56035bc 100644 --- a/src/sage/numerical/linear_tensor_element.pyx +++ b/src/sage/numerical/linear_tensor_element.pyx @@ -355,7 +355,7 @@ cdef class LinearTensor(ModuleElement): result[key] = b * coeff return self.parent()(result) - cdef _richcmp(left, right, int op): + def __richcmp__(left, right, int op): """ Create an inequality or equality object. diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 35a6db4810b..baac12b40b9 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -149,7 +149,8 @@ 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 +from sage.structure.element cimport (Element, EuclideanDomainElement, + parent_c, coercion_model) include "sage/ext/python_debug.pxi" from sage.libs.pari.paridecl cimport * from sage.rings.rational cimport Rational @@ -169,7 +170,7 @@ 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 +from sage.structure.element import coerce_binop cdef extern from *: int unlikely(int) nogil # Defined by Cython @@ -888,30 +889,30 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if isinstance(left, Integer): if isinstance(right, Integer): c = mpz_cmp((left).value, (right).value) - elif PyInt_CheckExact(right): + elif isinstance(right, int): c = mpz_cmp_si((left).value, PyInt_AS_LONG(right)) - elif PyLong_CheckExact(right): + elif isinstance(right, long): mpz_set_pylong(mpz_tmp, right) c = mpz_cmp((left).value, mpz_tmp) - elif PyFloat_CheckExact(right): + elif isinstance(right, float): d = PyFloat_AsDouble(right) if isnan(d): return op == 3 c = mpz_cmp_d((left).value, d) else: - return (left)._richcmp(right, op) - - else: # right is an Integer - if PyInt_CheckExact(left): + return coercion_model.richcmp(left, right, op) + else: # right is an Integer and left is not + if isinstance(left, int): c = -mpz_cmp_si((right).value, PyInt_AS_LONG(left)) - elif PyLong_CheckExact(left): + if isinstance(left, long): mpz_set_pylong(mpz_tmp, left) c = mpz_cmp(mpz_tmp, (right).value) - elif PyFloat_CheckExact(left): + if isinstance(left, float): d = PyFloat_AsDouble(left) if isnan(d): return op == 3 c = -mpz_cmp_d((right).value, d) else: - return (left)._richcmp(right, op) + return coercion_model.richcmp(left, right, op) + return rich_to_bool_sgn(op, c) cpdef int _cmp_(left, sage.structure.element.Element right) except -2: @@ -2984,7 +2985,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): mpz_fdiv_qr(q.value, r.value, self.value, (other).value) else: - left, right = canonical_coercion(self, other) + left, right = coercion_model.canonical_coercion(self, other) return left.quo_rem(right) return q, r @@ -6112,7 +6113,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 1 """ if not isinstance(n, Integer) and not isinstance(n, int): - left, right = canonical_coercion(self, n) + left, right = coercion_model.canonical_coercion(self, n) return left.gcd(right) cdef Integer m = as_Integer(n) cdef Integer g = PY_NEW(Integer) diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 1a334b28f17..17e5871309f 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -30,8 +30,6 @@ AUTHORS: include "sage/ext/interrupt.pxi" include "sage/ext/stdsage.pxi" -import sys - cimport sage.rings.padics.local_generic_element from sage.libs.gmp.mpz cimport mpz_set_si from sage.rings.padics.local_generic_element cimport LocalGenericElement @@ -44,18 +42,6 @@ from sage.structure.element import coerce_binop cdef long maxordp = (1L << (sizeof(long) * 8 - 2)) - 1 cdef class pAdicGenericElement(LocalGenericElement): - def __richcmp__(left, right, int op): - """ - Comparison. - - EXAMPLES:: - - sage: R = Zp(5); a = R(5, 6); b = R(5 + 5^6, 8) - sage: a == b #indirect doctest - True - """ - return (left)._richcmp(right, op) - cpdef int _cmp_(left, Element right) except -2: """ First compare valuations, then compare normalized diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index ab92d9dd498..8d2275d2e29 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -206,6 +206,7 @@ from sage.rings.ideal import FieldIdeal from sage.structure.element cimport Element from sage.structure.element cimport RingElement from sage.structure.element cimport ModuleElement +from sage.structure.element cimport have_same_parent_c, coercion_model from sage.structure.parent cimport Parent from sage.structure.sequence import Sequence @@ -3075,6 +3076,45 @@ cdef class BooleanPolynomial(MPolynomial): return self._pbpoly.is_equal(right._pbpoly) def __richcmp__(left, right, int op): + """ + Optimized comparison function, checking for boolean ``False`` + in one of the arguments. + + EXAMPLES:: + + sage: P. = BooleanPolynomialRing() + sage: P.zero() == True + False + sage: P(0) != True + True + sage: P(False) == False + True + sage: P() != False + False + sage: x == True + False + sage: x != True + True + sage: x == False + False + sage: x != False + True + """ + cdef bint bl, br + + if (op == Py_EQ) or (op == Py_NE): + bl = not not left + br = not not right + if not bl or not br: + return (br or bl) == (op == Py_NE) + + # Copy from Element.__richcmp__ + if have_same_parent_c(left, right): + return (left)._richcmp_(right, op) + else: + return coercion_model.richcmp(left, right, op) + + cpdef int _cmp_(left, Element right) except -2: """ Compare left and right and return -1, 0, 1 for ``less than``, ``equal``, and ``greater than`` respectively. @@ -3098,27 +3138,11 @@ cdef class BooleanPolynomial(MPolynomial): :: - sage: P(0) == 0 + sage: P(True) == True True + sage: cmp(P(0), 0) + 0 """ - cdef bint bl = bool(left) - cdef bint br = bool(right) - - if op == Py_EQ: - if not bl or not br: - return (not br and not bl) - - elif op == Py_NE: - if not bl or not br: - return not (not br and not bl) - - #boilerplate from sage.structure.element - return (left)._richcmp(right, op) - - cpdef int _cmp_(left, Element right) except -2: - - - cdef int res from itertools import izip for lm, rm in izip(left, right): diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 338c12dd192..e22f3a120a3 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -64,16 +64,19 @@ For more information on how to specify coercions, conversions, and actions, see the documentation for Parent. """ - #***************************************************************************** # Copyright (C) 2007 Robert Bradshaw # -# Distributed under the terms of the GNU General Public License (GPL) -# +# 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.object cimport (PyObject, PyTypeObject, + PyObject_CallObject, PyObject_RichCompare) +from cpython.weakref cimport PyWeakref_GET_OBJECT, PyWeakref_NewRef from libc.string cimport strncmp cdef add, sub, mul, div, truediv, iadd, isub, imul, idiv @@ -81,24 +84,20 @@ import operator cdef dict operator_dict = operator.__dict__ from operator import add, sub, mul, div, truediv, iadd, isub, imul, idiv -from cpython.weakref cimport PyWeakref_GET_OBJECT, PyWeakref_NewRef - -from sage_object cimport SageObject +from .sage_object cimport SageObject, rich_to_bool +from .parent cimport Set_PythonType +from .element cimport arith_error_message, parent_c +from .coerce_actions import LeftModuleAction, RightModuleAction, IntegerMulAction +from .coerce_exceptions import CoercionException from sage.categories.map cimport Map -import sage.categories.morphism from sage.categories.morphism import IdentityMorphism -from sage.categories.action import InverseAction, PrecomposedAction -from parent cimport Set_PythonType -from coerce_exceptions import CoercionException -from element cimport arith_error_message, parent_c - -import sys, traceback - -from coerce_actions import LeftModuleAction, RightModuleAction, IntegerMulAction +from sage.categories.action cimport InverseAction, PrecomposedAction from sage.misc.lazy_import import LazyImport parent = LazyImport('sage.structure.all', 'parent', deprecation=17533) +import traceback + cpdef py_scalar_parent(py_type): """ @@ -278,7 +277,7 @@ cdef bint is_Integer(x): global _Integer if _Integer is None: from sage.rings.integer import Integer as _Integer - return type(x) is _Integer or type(x) is int + return type(x) is _Integer cdef class CoercionModel_cache_maps(CoercionModel): """ @@ -1117,6 +1116,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): sage: canonical_coercion(vector([1, 2, 3]), 0) ((1, 2, 3), (0, 0, 0)) + sage: canonical_coercion(GF(5)(0), float(0)) + (0, 0) """ xp = parent_c(x) yp = parent_c(y) @@ -1199,13 +1200,13 @@ cdef class CoercionModel_cache_maps(CoercionModel): return self.canonical_coercion(x, y) # Allow coercion of 0 even if no coercion from Z - if is_Integer(x) and not x and type(yp) is not type: + if (x_numeric or is_Integer(x)) and not x and type(yp) is not type: try: return yp(0), y except Exception: self._record_exception() - if is_Integer(y) and not y and type(xp) is not type: + if (y_numeric or is_Integer(y)) and not y and type(xp) is not type: try: return x, xp(0) except Exception: @@ -1753,6 +1754,67 @@ cdef class CoercionModel_cache_maps(CoercionModel): return None + cpdef richcmp(self, x, y, int op): + """ + Given two arbitrary objects ``x`` and ``y``, coerce them to + a common parent and compare them using rich comparison operator + ``op``. + + EXAMPLES:: + + sage: from sage.structure.element import get_coercion_model + sage: from sage.structure.sage_object import op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE + sage: richcmp = get_coercion_model().richcmp + sage: richcmp(None, None, op_EQ) + True + sage: richcmp(None, 1, op_LT) + True + sage: richcmp("hello", None, op_LE) + False + sage: richcmp(-1, 1, op_GE) + False + sage: richcmp(int(1), float(2), op_GE) + False + + If there is no coercion, compare types:: + + sage: x = QQ.one(); y = GF(2).one() + sage: richcmp(x, y, op_EQ) + False + sage: richcmp(x, y, op_NE) + True + sage: richcmp(x, y, op_LT if cmp(type(x), type(y)) == -1 else op_GT) + True + """ + # Some very special cases + if x is None or x is Ellipsis: + return rich_to_bool(op, 0 if x is y else -1) + if y is None or y is Ellipsis: + return rich_to_bool(op, 0 if x is y else 1) + + # Coerce to a common parent + try: + x, y = self.canonical_coercion(x, y) + except (TypeError, NotImplementedError): + pass + else: + return PyObject_RichCompare(x, y, op) + + # Comparing with coercion didn't work, try something else. + + # If types are not equal: compare types + cdef int c = cmp(type(x), type(y)) + if c: + return rich_to_bool(op, c) + + # Final attempt: compare by id() + if (x) >= (y): + # It cannot happen that x is y, since they don't + # have the same parent. + return rich_to_bool(op, 1) + else: + return rich_to_bool(op, -1) + def _coercion_error(self, x, x_map, x_elt, y, y_map, y_elt): """ This function is only called when someone has incorrectly implemented diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index 66e6047cb52..47b0903e391 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -37,8 +37,6 @@ cdef class Element(SageObject): cdef Parent _parent cpdef _richcmp_(left, Element right, int op) cpdef int _cmp_(left, Element right) except -2 - cdef _richcmp(self, right, int op) - cdef int _cmp(self, right) except -2 cdef _set_parent_c(self, Parent parent) cpdef base_extend(self, R) @@ -147,6 +145,7 @@ cdef class Matrix(ModuleElement): cdef class CoercionModel: cpdef canonical_coercion(self, x, y) cpdef bin_op(self, x, y, op) + cpdef richcmp(self, x, y, int op) cdef CoercionModel coercion_model diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index a76e61926ec..c4d883ddda7 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -886,7 +886,7 @@ cdef class Element(SageObject): """ return not self - cdef int _cmp(self, other) except -2: + def __cmp__(self, other): """ Compare ``left`` and ``right`` using the coercion framework. @@ -895,8 +895,8 @@ cdef class Element(SageObject): EXAMPLES: - We create an ``Element`` class where we define ``__cmp__`` - and ``_richcmp_`` and check that comparison works:: + We create an ``Element`` class where we define ``_richcmp_`` + and check that comparison works:: sage: cython(''' ....: from sage.structure.sage_object cimport rich_to_bool @@ -905,8 +905,6 @@ cdef class Element(SageObject): ....: cdef float x ....: def __init__(self, float v): ....: self.x = v - ....: def __cmp__(self, other): - ....: return (self)._cmp(other) ....: cpdef _richcmp_(self, Element other, int op): ....: cdef float x1 = (self).x ....: cdef float x2 = (other).x @@ -971,89 +969,8 @@ cdef class Element(SageObject): sage: a._cache_key() (Integer Ring, 'Generic element of a structure') """ - return(self.parent(),str(self)) - cdef _richcmp(self, other, int op): - """ - Compare ``self`` and ``other`` using the coercion framework, - comparing according to the comparison operator ``op``. - - This method exists only because of historical reasons: before - :trac:`18329`, the ``__richcmp__`` method would not be - inherited if ``__hash__`` was defined. Eventually, we should - completely replace ``_richcmp`` by ``__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). - 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. - # The explicit cast other tells Cython to omit the - # check isinstance(other, Element) when calling _richcmp_ - return self._richcmp_(other, 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) - except (TypeError, NotImplementedError): - pass - else: - 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)) - - # 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) - #################################################################### # In a Cython or a Python class, you must define either _cmp_ # (if your subclass is totally ordered), _richcmp_ (if your subclass @@ -1068,11 +985,33 @@ cdef class Element(SageObject): # 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) + def __richcmp__(self, other, int op): + """ + Compare ``self`` and ``other`` using the coercion framework, + comparing according to the comparison operator ``op``. - def __cmp__(left, right): - return (left)._cmp(right) + Normally, a class will not redefine ``__richcmp__`` but rely on + this ``Element.__richcmp__`` method which uses coercion if + needed to compare elements. After coercion (or if no coercion + is needed), ``_richcmp_`` is called. + + If a class wants to implement rich comparison without coercion, + then ``__richcmp__`` should be defined. + 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 + ``coercion_model.richcmp()`` for the remaining cases. + This is done for example in :class:`Integer`. + """ + if have_same_parent_c(self, other): + # Same parents, in particular self and other must both be + # an instance of Element. The explicit casts below make + # Cython generate optimized code for this call. + return (self)._richcmp_(other, op) + else: + return coercion_model.richcmp(self, other, op) cpdef _richcmp_(left, Element right, int op): r""" @@ -3359,6 +3298,7 @@ def coerce_cmp(x,y): if c == 0: c = -1 return c + # We define this base class here to avoid circular cimports. cdef class CoercionModel: """ @@ -3374,9 +3314,15 @@ cdef class CoercionModel: return op(x,y) raise TypeError(arith_error_message(x,y,op)) + cpdef richcmp(self, x, y, int op): + x, y = self.canonical_coercion(x, y) + return PyObject_RichCompare(x, y, op) + + import coerce cdef CoercionModel coercion_model = coerce.CoercionModel_cache_maps() + def get_coercion_model(): """ Return the global coercion model. From 6c7e85187a0d695ef3856b83d08eaaa0520f1fc0 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 29 Oct 2015 21:06:33 +0000 Subject: [PATCH 1761/1872] typos fixed --- src/sage/graphs/generators/classical_geometries.py | 2 +- src/sage/graphs/strongly_regular_db.pyx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 5d28644e93e..8712696007c 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -1108,7 +1108,7 @@ def EllipticLinesProjectivePlaneScheme(k): Pseudo-cyclic association scheme for action of `O(3,2^k)` on elliptic lines The group `O(3,2^k)` acts naturally on the `q(q-1)/2` lines of `PG(2,2^k)` - skew to the conic preseerved by it, see Sect. 12.7.B of [BCN89]_ and Sect. 6.D + skew to the conic preserved by it, see Sect. 12.7.B of [BCN89]_ and Sect. 6.D in [BvL84]_. Compute the orbitals of this action and return them. INPUT: diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 308d668624e..4e3f79319f0 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1775,13 +1775,13 @@ def mathon_pseudocylcic_merging_graph(M, t): sage: from sage.graphs.strongly_regular_db import mathon_pseudocylcic_merging_graph sage: from sage.graphs.generators.classical_geometries import EllipticLinesProjectivePlaneScheme as ES sage: G = mathon_pseudocylcic_merging_graph(ES(3), 0) # long time - sage: sage: G.is_strongly_regular(parameters=True) # long time + sage: G.is_strongly_regular(parameters=True) # long time (784, 243, 82, 72) sage: G = mathon_pseudocylcic_merging_graph(ES(3), 1) # long time - sage: sage: G.is_strongly_regular(parameters=True) # long time + sage: G.is_strongly_regular(parameters=True) # long time (784, 270, 98, 90) sage: G = mathon_pseudocylcic_merging_graph(ES(3), 2) # long time - sage: sage: G.is_strongly_regular(parameters=True) # long time + sage: G.is_strongly_regular(parameters=True) # long time (784, 297, 116, 110) sage: G = mathon_pseudocylcic_merging_graph(ES(2), 2) Traceback (most recent call last): From fd7894aa1f32d08c0836d506f33e883d870a9bfc Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 29 Oct 2015 22:43:02 +0000 Subject: [PATCH 1762/1872] check that skew_normalize worked --- src/sage/combinat/matrices/hadamard_matrix.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 3d716301b1c..277837eaf8d 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -1017,5 +1017,7 @@ def true(): M = dd*M*dd if check: assert is_hadamard_matrix(M, normalized=False, skew=True) + if skew_normalize: + assert M[0]==[1]*n _skew_had_cache[n]=True return M From 3503d6218c68b2d1f8e08ffe832daeb0c4b393d4 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 29 Oct 2015 22:53:31 +0000 Subject: [PATCH 1763/1872] rest of fixes for hadamard_matrix.py removed some unneeded imports in tests, renamed _GS_... and a matrix row is a vector(), not a list() removed unneeded check=False removed a silly # long time fixed docs and a test for _helper_... doctests for GS_...smallcases() --- src/sage/combinat/matrices/hadamard_matrix.py | 84 +++++++++++++------ 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 277837eaf8d..fef0bda0d34 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -114,7 +114,7 @@ def hadamard_matrix_paleyI(n, normalize=True): TESTS:: - sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyI, is_hadamard_matrix) + sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix sage: test_cases = [x+1 for x in range(100) if is_prime_power(x) and x%4==3] sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True) ....: for n in test_cases) @@ -251,7 +251,6 @@ def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): TESTS:: - sage: from sage.combinat.matrices.hadamard_matrix import (is_hadamard_matrix, skew_hadamard_matrix) sage: h = matrix.hadamard(12) sage: is_hadamard_matrix(h, skew=True) False @@ -333,7 +332,7 @@ def hadamard_matrix(n,existence=False, check=True): - ``True`` -- meaning that Sage knows how to build the matrix - ``Unknown`` -- meaning that Sage does not know how to build the - matrix, but that the design may exist (see :mod:`sage.misc.unknown`). + matrix, although the matrix may exist (see :mod:`sage.misc.unknown`). - ``False`` -- meaning that the matrix does not exist. @@ -654,18 +653,19 @@ def _helper_payley_matrix(n, zero_position=True): This function return a `n^2` matrix `M` whose rows/columns are indexed by the element of a finite field on `n` elements `x_1,...,x_n`. The value - `M_{i,j}` is equal to `\chi(x_i-x_j)`. Note that `n` must be an odd prime power. + `M_{i,j}` is equal to `\chi(x_i-x_j)`. - The elements `x_1,...,x_n` are ordered in such a way that the matrix is - symmetric with respect to its second diagonal. The matrix is symmetric if - n==4k+1, and skew-symmetric if n=4k-1. + The elements `x_1,...,x_n` are ordered in such a way that the matrix + (respectively, its submatrix obtained by removing first row and first column in the case + ``zero_position=False``) is symmetric with respect to its second diagonal. + The matrix is symmetric if `n=4k+1`, and skew-symmetric otherwise. INPUT: - - ``n`` -- a prime power + - ``n`` -- an odd prime power. - - ``zero_position`` -- is true (default), place 0 of ``F_n`` in the middle, otherwise - place it first. + - ``zero_position`` -- if it is true (default), place 0 of ``F_n`` in the middle, + otherwise place it first. .. SEEALSO:: @@ -680,10 +680,33 @@ def _helper_payley_matrix(n, zero_position=True): [-1 1 0 1 -1] [-1 -1 1 0 1] [ 1 -1 -1 1 0] - sage: _helper_payley_matrix(3) - [ 0 -1 1] - [ 1 0 -1] - [-1 1 0] + + TESTS:: + + sage: _helper_payley_matrix(11,zero_position=True) + [ 0 -1 1 -1 -1 -1 1 1 1 -1 1] + [ 1 0 -1 -1 1 -1 1 -1 1 1 -1] + [-1 1 0 1 -1 -1 -1 -1 1 1 1] + [ 1 1 -1 0 1 -1 -1 1 -1 -1 1] + [ 1 -1 1 -1 0 1 -1 -1 -1 1 1] + [ 1 1 1 1 -1 0 1 -1 -1 -1 -1] + [-1 -1 1 1 1 -1 0 1 -1 1 -1] + [-1 1 1 -1 1 1 -1 0 1 -1 -1] + [-1 -1 -1 1 1 1 1 -1 0 -1 1] + [ 1 -1 -1 1 -1 1 -1 1 1 0 -1] + [-1 1 -1 -1 -1 1 1 1 -1 1 0] + sage: _helper_payley_matrix(11,zero_position=False) + [ 0 1 1 1 1 -1 1 -1 -1 -1 -1] + [-1 0 -1 1 -1 -1 1 1 1 -1 1] + [-1 1 0 -1 -1 1 1 -1 1 1 -1] + [-1 -1 1 0 1 -1 -1 -1 1 1 1] + [-1 1 1 -1 0 1 -1 1 -1 -1 1] + [ 1 1 -1 1 -1 0 -1 -1 -1 1 1] + [-1 -1 -1 1 1 1 0 1 -1 1 -1] + [ 1 -1 1 1 -1 1 -1 0 1 -1 -1] + [ 1 -1 -1 -1 1 1 1 -1 0 -1 1] + [ 1 1 -1 -1 1 -1 -1 1 1 0 -1] + [ 1 -1 1 -1 -1 -1 1 1 -1 1 0] """ from sage.rings.finite_rings.constructor import FiniteField as GF K = GF(n,conway=True,prefix='x') @@ -786,11 +809,9 @@ def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): r""" Williamson-Goethals-Seidel construction of a skew Hadamard matrix - Given `n\times n` (anti)circulant (or matrices `A`, `B`, `C`, `D` with 1,-1 entries, + Given `n\times n` (anti)circulant matrices `A`, `B`, `C`, `D` with 1,-1 entries, and satisfying `A+A^\top = 2I`, `AA^\top + BB^\top + CC^\top + DD^\top = 4nI`, one can construct a skew Hadamard matrix of order `4n`, cf. [GS70s]_. - Matrices for `n=36` and `52` are given in [GS70s]_. Matrices for `n=92` are given - in [Wall71]_. INPUT: @@ -840,13 +861,15 @@ def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): assert is_hadamard_matrix(M, normalized=False, skew=True) return M -def _GS_skew_hadamard(n, existence=False, check=True): +def GS_skew_hadamard_smallcases(n, existence=False, check=True): r""" Data for Williamson-Goethals-Seidel construction of skew Hadamard matrices Here we keep the data for this construction. Namely, it needs 4 circulant matrices with extra properties, as described in :func:`sage.combinat.matrices.hadamard_matrix.williamson_goethals_seidel_skew_hadamard_matrix` + Matrices for `n=36` and `52` are given in [GS70s]_. Matrices for `n=92` are given + in [Wall71]_. INPUT: @@ -855,6 +878,17 @@ def _GS_skew_hadamard(n, existence=False, check=True): - ``existence`` -- if true (default), only check that we can do the construction - ``check`` -- if true (default), check the result. + + TESTS:: + + sage: from sage.combinat.matrices.hadamard_matrix import GS_skew_hadamard_smallcases + sage: GS_skew_hadamard_smallcases(36) + 36 x 36 dense matrix over Integer Ring... + sage: GS_skew_hadamard_smallcases(52) + 52 x 52 dense matrix over Integer Ring... + sage: GS_skew_hadamard_smallcases(92) + 92 x 92 dense matrix over Integer Ring... + sage: GS_skew_hadamard_smallcases(100) """ from sage.combinat.matrices.hadamard_matrix import\ williamson_goethals_seidel_skew_hadamard_matrix as WGS @@ -930,12 +964,11 @@ def skew_hadamard_matrix(n,existence=False, skew_normalize=True, check=True): TESTS:: - sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix sage: skew_hadamard_matrix(10,existence=True) False sage: skew_hadamard_matrix(12,existence=True) True - sage: skew_hadamard_matrix(784,existence=True) # long time + sage: skew_hadamard_matrix(784,existence=True) True sage: skew_hadamard_matrix(10) Traceback (most recent call last): @@ -980,7 +1013,7 @@ def true(): M = hadamard_matrix_paleyI(n, normalize=False) elif n % 8 == 0: - if skew_hadamard_matrix(n//2,existence=True, check=False): + if skew_hadamard_matrix(n//2,existence=True): if existence: return true() H = skew_hadamard_matrix(n//2,check=False) @@ -990,7 +1023,7 @@ def true(): for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n n1 = n//d if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\ - and skew_hadamard_matrix(n1,existence=True, check=False): + and skew_hadamard_matrix(n1,existence=True): if existence: return true() H = skew_hadamard_matrix(n1, check=False)-I(n1) @@ -1003,10 +1036,10 @@ def true(): M = A.tensor_product(I(n1))+(U*A).tensor_product(H) break if M is None: # try Williamson-Goethals-Seidel construction - if _GS_skew_hadamard(n, existence=True): + if GS_skew_hadamard_smallcases(n, existence=True): if existence: return true() - M = _GS_skew_hadamard(n) + M = GS_skew_hadamard_smallcases(n) else: if existence: @@ -1018,6 +1051,7 @@ def true(): if check: assert is_hadamard_matrix(M, normalized=False, skew=True) if skew_normalize: - assert M[0]==[1]*n + from sage.modules.free_module_element import vector + assert M[0]==vector([1]*n) _skew_had_cache[n]=True return M From 595f7e9f55f9566a315394df4f998a56e3dfab40 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 30 Oct 2015 10:25:34 +0000 Subject: [PATCH 1764/1872] added graphs to graphs., and doc(test)s additions and fixes --- src/sage/graphs/generators/families.py | 32 +++++++++++++++----------- src/sage/graphs/graph_generators.py | 6 +++++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index b058bc4f64a..6da2065be84 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -1597,7 +1597,7 @@ def PaleyGraph(q): def PasechnikGraph(n): """ - Pseudo-`OA(2n-1,4n-1)`-graph from a skew Hadamard matrix of order `4n` + Pasechnik strongly regular graph on `(4n-1)^2` vertices A strongly regular graph with parameters of the orthogonal array graph :func:`OrthogonalArrayBlockGraph @@ -1607,10 +1607,9 @@ def PasechnikGraph(n): EXAMPLES:: - sage: from sage.graphs.generators.families import PasechnikGraph - sage: PasechnikGraph(4).is_strongly_regular(parameters=True) + sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) (225, 98, 43, 42) - sage: PasechnikGraph(9).is_strongly_regular(parameters=True) # long time + sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True) # long time (1225, 578, 273, 272) """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix @@ -1634,10 +1633,9 @@ def SquaredSkewHadamardMatrixGraph(n): EXAMPLES:: - sage: from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph - sage: SquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True) + sage: graphs.SquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True) (225, 112, 55, 56) - sage: SquaredSkewHadamardMatrixGraph(9).is_strongly_regular(parameters=True) # long time + sage: graphs.SquaredSkewHadamardMatrixGraph(9).is_strongly_regular(parameters=True) # long time (1225, 612, 305, 306) """ @@ -1655,19 +1653,27 @@ def SquaredSkewHadamardMatrixGraph(n): def SwitchedSquaredSkewHadamardMatrixGraph(n): """ - a strongly regular graph in Seidel switching class of `SquaredSkewHadamardMatrixGraph` + A strongly regular graph in Seidel switching class of `SquaredSkewHadamardMatrixGraph` A strongly regular graph in the - :meth:`Seidel switching ` class of the dijoint union of - a 1-vertex graph and func:`Pseudo-L_{2n}(4n-1) + :meth:`Seidel switching ` class of the disjoint union of + a 1-vertex graph and the one produced by :func:`Pseudo-L_{2n}(4n-1) ` + In this case, the other possible parameter set of a strongly regular graph in the + Seidel switching class of the latter graph (see [BH12]_) coincides with the set + of parameters of the complement of the graph returned by this function. + EXAMPLES:: - sage: from sage.graphs.generators.families import SwitchedSquaredSkewHadamardMatrixGraph - sage: SwitchedSquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True) + sage: g=graphs.SwitchedSquaredSkewHadamardMatrixGraph(4) + sage: g.is_strongly_regular(parameters=True) (226, 105, 48, 49) - + sage: from sage.combinat.designs.twographs import twograph_descendant + sage: twograph_descendant(g,0).is_strongly_regular(parameters=True) + (225, 112, 55, 56) + sage: twograph_descendant(g.complement(),0).is_strongly_regular(parameters=True) + (225, 112, 55, 56) """ from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph G = SquaredSkewHadamardMatrixGraph(n).complement() diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 477400f23b3..6180af9abe1 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -216,11 +216,14 @@ def __append_to_doc(methods): "NStarGraph", "OddGraph", "PaleyGraph", + "PasechnikGraph", "petersen_family", "planar_graphs", "quadrangulations", "RingedTree", "SierpinskiGasketGraph", + "SquaredSkewHadamardMatrixGraph", + "SwitchedSquaredSkewHadamardMatrixGraph", "strongly_regular_graph", "trees", "triangulations", @@ -1989,9 +1992,12 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None NStarGraph = staticmethod(sage.graphs.generators.families.NStarGraph) OddGraph = staticmethod(sage.graphs.generators.families.OddGraph) PaleyGraph = staticmethod(sage.graphs.generators.families.PaleyGraph) + PasechnikGraph = staticmethod(sage.graphs.generators.families.PasechnikGraph) petersen_family = staticmethod(sage.graphs.generators.families.petersen_family) RingedTree = staticmethod(sage.graphs.generators.families.RingedTree) SierpinskiGasketGraph = staticmethod(sage.graphs.generators.families.SierpinskiGasketGraph) + SquaredSkewHadamardMatrixGraph = staticmethod(sage.graphs.generators.families.SquaredSkewHadamardMatrixGraph) + SwitchedSquaredSkewHadamardMatrixGraph = staticmethod(sage.graphs.generators.families.SwitchedSquaredSkewHadamardMatrixGraph) strongly_regular_graph = staticmethod(sage.graphs.strongly_regular_db.strongly_regular_graph) trees = staticmethod(sage.graphs.generators.families.trees) WheelGraph = staticmethod(sage.graphs.generators.families.WheelGraph) From 035274fcdd548a4e4256cc9e08102a22a750d704 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 30 Oct 2015 12:51:38 +0000 Subject: [PATCH 1765/1872] reshuffling and renaming and moar tests and removing Schlaefli graph, as it's a GQ(2,4)... --- .../graphs/generators/classical_geometries.py | 38 --------- src/sage/graphs/generators/families.py | 50 ++++++++++++ src/sage/graphs/generators/smallgraphs.py | 70 +++++++++++++++++ src/sage/graphs/graph_generators.py | 4 + src/sage/graphs/strongly_regular_db.pyx | 77 +------------------ 5 files changed, 128 insertions(+), 111 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 8712696007c..33ebf67da74 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -1102,41 +1102,3 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, G = IncidenceStructure(L).dual().intersection_graph() G.name('T2*(O,'+str(q)+'); GQ'+str((q-1,q+1))) return G - -def EllipticLinesProjectivePlaneScheme(k): - r""" - Pseudo-cyclic association scheme for action of `O(3,2^k)` on elliptic lines - - The group `O(3,2^k)` acts naturally on the `q(q-1)/2` lines of `PG(2,2^k)` - skew to the conic preserved by it, see Sect. 12.7.B of [BCN89]_ and Sect. 6.D - in [BvL84]_. Compute the orbitals of this action and return them. - - INPUT: - - - ``k`` (integer) -- the exponent of 2 to get the field size - - TESTS:: - - sage: from sage.graphs.generators.classical_geometries import EllipticLinesProjectivePlaneScheme - sage: EllipticLinesProjectivePlaneScheme(2) - [ - [1 0 0 0 0 0] [0 1 1 1 1 0] [0 0 0 0 0 1] - [0 1 0 0 0 0] [1 0 1 1 0 1] [0 0 0 0 1 0] - [0 0 1 0 0 0] [1 1 0 0 1 1] [0 0 0 1 0 0] - [0 0 0 1 0 0] [1 1 0 0 1 1] [0 0 1 0 0 0] - [0 0 0 0 1 0] [1 0 1 1 0 1] [0 1 0 0 0 0] - [0 0 0 0 0 1], [0 1 1 1 1 0], [1 0 0 0 0 0] - ] - """ - from sage.libs.gap.libgap import libgap - from sage.matrix.constructor import matrix - from itertools import product - q = 2**k - g0 = libgap.GeneralOrthogonalGroup(3,q) # invariant form x0^2+x1*x2 - g = libgap.Group(libgap.List(g0.GeneratorsOfGroup(),libgap.TransposedMat)) - W = libgap.FullRowSpace(libgap.GF(q), 3) - l=sum(libgap.Elements(libgap.Basis(W))) - gp = libgap.Action(g,libgap.Orbit(g,l,libgap.OnLines),libgap.OnLines) - orbitals = gp.Orbits(list(product(gp.Orbit(1),gp.Orbit(1))),libgap.OnTuples) - mats = map(lambda o: map(lambda x: (int(x[0])-1,int(x[1])-1), o), orbitals) - return map(lambda x: matrix(q*(q-1)/2, lambda i,j: 1 if (i,j) in x else 0), mats) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index c48916e73b9..dcec9d6160e 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2333,3 +2333,53 @@ def RingedTree(k, vertex_labels = True): g.relabel(vertices) return g + + + +def MathonPseudocyclicMergingGraph(M, t): + r""" + Mathon's merging of classes in a pseudo-cyclic 3-class association scheme + + Construct strongly regular graphs from p.97 of [BvL84]_. + + INPUT: + + - ``M`` -- the list of matrices in a pseudo-cyclic 3-class association scheme. + The identity matrix must be the first entry. + + - ``t`` (integer) -- the number of the graph, from 0 to 2. + + TESTS:: + + sage: from sage.graphs.generators.families import MathonPseudocyclicMergingGraph as mer + sage: from sage.graphs.generators.smallgraphs import _EllipticLinesProjectivePlaneScheme as ES + sage: G = mer(ES(3), 0) # long time + sage: G.is_strongly_regular(parameters=True) # long time + (784, 243, 82, 72) + sage: G = mer(ES(3), 1) # long time + sage: G.is_strongly_regular(parameters=True) # long time + (784, 270, 98, 90) + sage: G = mer(ES(3), 2) # long time + sage: G.is_strongly_regular(parameters=True) # long time + (784, 297, 116, 110) + sage: G = mer(ES(2), 2) + Traceback (most recent call last): + ... + AssertionError... + sage: M = ES(3) + sage: M = [M[1],M[0],M[2],M[3]] + sage: G = mer(M, 2) + Traceback (most recent call last): + ... + AssertionError... + """ + from sage.graphs.graph import Graph + from sage.matrix.constructor import identity_matrix + assert (len(M) == 4) + assert (M[0]==identity_matrix(M[0].nrows())) + A = sum(map(lambda x: x.tensor_product(x), M[1:])) + if t > 0: + A += sum(map(lambda x: x.tensor_product(M[0]), M[1:])) + if t > 1: + A += sum(map(lambda x: M[0].tensor_product(x), M[1:])) + return Graph(A) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index b6bcebb66be..6abc98956fb 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -4753,3 +4753,73 @@ def WienerArayaGraph(): g.get_pos().pop(0) g.relabel() return g + +def _EllipticLinesProjectivePlaneScheme(k): + r""" + Pseudo-cyclic association scheme for action of `O(3,2^k)` on elliptic lines + + The group `O(3,2^k)` acts naturally on the `q(q-1)/2` lines of `PG(2,2^k)` + skew to the conic preserved by it, see Sect. 12.7.B of [BCN89]_ and Sect. 6.D + in [BvL84]_. Compute the orbitals of this action and return them. + + This is a helper for :func:`sage.graphs.generators.smallgraphs.MathonStronglyRegularGraph`. + + INPUT: + + - ``k`` (integer) -- the exponent of 2 to get the field size + + TESTS:: + + sage: from sage.graphs.generators.smallgraphs import _EllipticLinesProjectivePlaneScheme + sage: _EllipticLinesProjectivePlaneScheme(2) + [ + [1 0 0 0 0 0] [0 1 1 1 1 0] [0 0 0 0 0 1] + [0 1 0 0 0 0] [1 0 1 1 0 1] [0 0 0 0 1 0] + [0 0 1 0 0 0] [1 1 0 0 1 1] [0 0 0 1 0 0] + [0 0 0 1 0 0] [1 1 0 0 1 1] [0 0 1 0 0 0] + [0 0 0 0 1 0] [1 0 1 1 0 1] [0 1 0 0 0 0] + [0 0 0 0 0 1], [0 1 1 1 1 0], [1 0 0 0 0 0] + ] + """ + from sage.libs.gap.libgap import libgap + from sage.matrix.constructor import matrix + from itertools import product + q = 2**k + g0 = libgap.GeneralOrthogonalGroup(3,q) # invariant form x0^2+x1*x2 + g = libgap.Group(libgap.List(g0.GeneratorsOfGroup(),libgap.TransposedMat)) + W = libgap.FullRowSpace(libgap.GF(q), 3) + l=sum(libgap.Elements(libgap.Basis(W))) + gp = libgap.Action(g,libgap.Orbit(g,l,libgap.OnLines),libgap.OnLines) + orbitals = gp.Orbits(list(product(gp.Orbit(1),gp.Orbit(1))),libgap.OnTuples) + mats = map(lambda o: map(lambda x: (int(x[0])-1,int(x[1])-1), o), orbitals) + return map(lambda x: matrix(q*(q-1)/2, lambda i,j: 1 if (i,j) in x else 0), mats) + + +def MathonStronglyRegularGraph(t): + r""" + return one of Mathon's graphs on 784 vertices + + INPUT: + + - ``t`` (integer) -- the number of the graph, from 0 to 2. + + EXAMPLE:: + + sage: from sage.graphs.generators.smallgraphs import MathonStronglyRegularGraph + sage: G = MathonStronglyRegularGraph(0) # long time + sage: G.is_strongly_regular(parameters=True) # long time + (784, 243, 82, 72) + + TESTS:: + + sage: G = graphs.MathonStronglyRegularGraph(1) # long time + sage: G.is_strongly_regular(parameters=True) # long time + (784, 270, 98, 90) + sage: G = graphs.MathonStronglyRegularGraph(2) # long time + sage: G.is_strongly_regular(parameters=True) # long time + (784, 297, 116, 110) + + """ + from sage.graphs.generators.families import MathonPseudocyclicMergingGraph + ES = _EllipticLinesProjectivePlaneScheme(3) + return MathonPseudocyclicMergingGraph(ES, t) diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 477400f23b3..e87dc7557a2 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -136,6 +136,7 @@ def __append_to_doc(methods): "LivingstoneGraph", "M22Graph", "MarkstroemGraph", + "MathonStronglyRegularGraph", "McGeeGraph", "McLaughlinGraph", "MeredithGraph", @@ -210,6 +211,7 @@ def __append_to_doc(methods): "KneserGraph", "LCFGraph", "line_graph_forbidden_subgraphs", + "MathonPseudocyclicMergingGraph", "MycielskiGraph", "MycielskiStep", "NKStarGraph", @@ -1920,6 +1922,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None LivingstoneGraph = staticmethod(sage.graphs.generators.smallgraphs.LivingstoneGraph) M22Graph = staticmethod(sage.graphs.generators.smallgraphs.M22Graph) MarkstroemGraph = staticmethod(sage.graphs.generators.smallgraphs.MarkstroemGraph) + MathonStronglyRegularGraph = staticmethod(sage.graphs.generators.smallgraphs.MathonStronglyRegularGraph) McGeeGraph = staticmethod(sage.graphs.generators.smallgraphs.McGeeGraph) McLaughlinGraph = staticmethod(sage.graphs.generators.smallgraphs.McLaughlinGraph) MeredithGraph = staticmethod(sage.graphs.generators.smallgraphs.MeredithGraph) @@ -1983,6 +1986,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None KneserGraph = staticmethod(sage.graphs.generators.families.KneserGraph) LCFGraph = staticmethod(sage.graphs.generators.families.LCFGraph) line_graph_forbidden_subgraphs = staticmethod(sage.graphs.generators.families.line_graph_forbidden_subgraphs) + MathonPseudocyclicMergingGraph = staticmethod(sage.graphs.generators.families.MathonPseudocyclicMergingGraph) MycielskiGraph = staticmethod(sage.graphs.generators.families.MycielskiGraph) MycielskiStep = staticmethod(sage.graphs.generators.families.MycielskiStep) NKStarGraph = staticmethod(sage.graphs.generators.families.NKStarGraph) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 4e3f79319f0..8a39cd91512 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -41,9 +41,9 @@ from sage.graphs.generators.smallgraphs import CameronGraph from sage.graphs.generators.smallgraphs import M22Graph from sage.graphs.generators.smallgraphs import SimsGewirtzGraph from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph -from sage.graphs.generators.smallgraphs import SchlaefliGraph from sage.graphs.generators.smallgraphs import HigmanSimsGraph from sage.graphs.generators.smallgraphs import LocalMcLaughlinGraph +from sage.graphs.generators.smallgraphs import MathonStronglyRegularGraph from sage.graphs.generators.smallgraphs import SuzukiGraph from sage.graphs.graph import Graph from libc.math cimport sqrt, floor @@ -1757,74 +1757,6 @@ def strongly_regular_from_two_weight_code(L): G.relabel() return G -def mathon_pseudocylcic_merging_graph(M, t): - r""" - Mathon's merging of classes in a pseudo-cyclic 3-class association scheme - - Construct strongly regular graphs from p.97 of [BvL84]_. - - INPUT: - - - ``M`` -- the list of matrices in a pseudo-cyclic 3-class association scheme. - The identity matrix must be the first entry. - - - ``t`` (integer) -- the number of the graph, from 0 to 2. - - TESTS:: - - sage: from sage.graphs.strongly_regular_db import mathon_pseudocylcic_merging_graph - sage: from sage.graphs.generators.classical_geometries import EllipticLinesProjectivePlaneScheme as ES - sage: G = mathon_pseudocylcic_merging_graph(ES(3), 0) # long time - sage: G.is_strongly_regular(parameters=True) # long time - (784, 243, 82, 72) - sage: G = mathon_pseudocylcic_merging_graph(ES(3), 1) # long time - sage: G.is_strongly_regular(parameters=True) # long time - (784, 270, 98, 90) - sage: G = mathon_pseudocylcic_merging_graph(ES(3), 2) # long time - sage: G.is_strongly_regular(parameters=True) # long time - (784, 297, 116, 110) - sage: G = mathon_pseudocylcic_merging_graph(ES(2), 2) - Traceback (most recent call last): - ... - AssertionError... - sage: M = ES(3) - sage: M = [M[1],M[0],M[2],M[3]] - sage: G = mathon_pseudocylcic_merging_graph(M, 2) - Traceback (most recent call last): - ... - AssertionError... - """ - from sage.graphs.graph import Graph - from sage.matrix.constructor import identity_matrix - assert (len(M) == 4) - assert (M[0]==identity_matrix(M[0].nrows())) - A = sum(map(lambda x: x.tensor_product(x), M[1:])) - if t > 0: - A += sum(map(lambda x: x.tensor_product(M[0]), M[1:])) - if t > 1: - A += sum(map(lambda x: M[0].tensor_product(x), M[1:])) - return Graph(A) - -def mathon_graph_on_784_vertices(t): - r""" - return one of Mathon's graphs on 784 vertices - - INPUT: - - - ``t`` (integer) -- the number of the graph, from 0 to 2. - - EXAMPLE:: - - sage: from sage.graphs.strongly_regular_db import mathon_graph_on_784_vertices - sage: G = mathon_graph_on_784_vertices(0) - sage: G.is_strongly_regular(parameters=True) - (784, 243, 82, 72) - """ - from sage.graphs.generators.classical_geometries import \ - EllipticLinesProjectivePlaneScheme as ES - - return mathon_pseudocylcic_merging_graph(ES(3), t) - def SRG_256_187_138_132(): r""" Return a `(256, 187, 138, 132)`-strongly regular graph. @@ -2805,7 +2737,6 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint return G constructions = { - ( 27, 16, 10, 8): [SchlaefliGraph], ( 36, 14, 4, 6): [Graph,('c~rLDEOcKTPO`U`HOIj@MWFLQFAaRIT`HIWqPsQQJ'+ 'DXGLqYM@gRLAWLdkEW@RQYQIErcgesClhKefC_ygSGkZ`OyHETdK[?lWStCapVgKK')], ( 50, 7, 0, 1): [HoffmanSingletonGraph], @@ -2854,9 +2785,9 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint (729, 560, 433,420): [SRG_729_560_433_420], (729, 476, 313,306): [SRG_729_476_313_306], (729, 532, 391,380): [SRG_729_532_391_380], - (784, 243, 82, 72): [mathon_graph_on_784_vertices, 0], - (784, 270, 98, 90): [mathon_graph_on_784_vertices, 1], - (784, 297, 116, 110):[mathon_graph_on_784_vertices, 2], + (784, 243, 82, 72): [MathonStronglyRegularGraph, 0], + (784, 270, 98, 90): [MathonStronglyRegularGraph, 1], + (784, 297, 116, 110):[MathonStronglyRegularGraph, 2], (1024,825, 668,650): [SRG_1024_825_668_650], (1782,416, 100, 96): [SuzukiGraph], } From 0a850a571e50290bdb91c3e26bff7c2a8d240b04 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 30 Oct 2015 15:09:10 -0700 Subject: [PATCH 1766/1872] trac 19505: git a la xkcd --- src/doc/en/developer/manual_git.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/en/developer/manual_git.rst b/src/doc/en/developer/manual_git.rst index ae31a1dd327..a0849457d54 100644 --- a/src/doc/en/developer/manual_git.rst +++ b/src/doc/en/developer/manual_git.rst @@ -12,6 +12,8 @@ If you want to contribute using git only, you are at the right place. This chapter will tell you how to do so, assuming some basic familiarity with git. In particular, you should have read :ref:`chapter-walkthrough` first. +Randall Munroe has provided a `basic overview `_. + We assume that you have a copy of the Sage git repository, for example by running:: From b91038179691d452ffa6a6ef24b9269e3db99b2a Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 31 Oct 2015 06:23:54 +0100 Subject: [PATCH 1767/1872] Trac #19496: Add doctest with eigenvalue 0 --- src/sage/combinat/finite_state_machine.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index fd4c1b7a3d2..6784e3bd1bd 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9787,6 +9787,14 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n')): ....: for _ in range(1, 6)) True + Here is an automaton without cycles, so with eigenvalue `0`. :: + + sage: A = Automaton([(j, j+1, 0) for j in range(3)], + ....: initial_states=[0], + ....: final_states=range(3)) + sage: A.number_of_words() + 1/2*0^(n - 2)*(n - 1)*n + 0^(n - 1)*n + 0^n + TESTS:: sage: A = Automaton([(0, 0, 0), (0, 1, 0)], From 4b34dafe88e8751f0d7651799a6a842f9e13bfd6 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 31 Oct 2015 06:26:10 +0100 Subject: [PATCH 1768/1872] Trac #19496: new parameter base_ring --- src/sage/combinat/finite_state_machine.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 6784e3bd1bd..f38d6ded61d 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9732,7 +9732,8 @@ def predecessors(self, state, valid_input=None): return(done) - def number_of_words(self, variable=sage.symbolic.ring.SR.var('n')): + def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), + base_ring=sage.rings.qqbar.QQbar): r""" Return the number of successful input words of given length. @@ -9741,6 +9742,9 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n')): - ``variable`` -- a symbol denoting the length of the words, by default `n`. + - ``base_ring`` -- Ring (default: ``QQbar``) in which to + compute the eigenvalues. + OUTPUT: A symbolic expression. @@ -9808,7 +9812,6 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n')): from sage.modules.free_module_element import vector from sage.rings.arith import falling_factorial from sage.rings.integer_ring import ZZ - from sage.rings.qqbar import QQbar from sage.symbolic.ring import SR def jordan_block_power(block, exponent): @@ -9820,7 +9823,7 @@ def jordan_block_power(block, exponent): if j>= i else 0) def matrix_power(A, exponent): - J, T = A.jordan_form(QQbar, transformation=True) + J, T = A.jordan_form(base_ring, transformation=True) Jpower = matrix.block_diagonal( [jordan_block_power(J.subdivision(j, j), exponent) for j in range(len(J.subdivisions()[0])+1) ]) From fa62208739d011d9df193485d2524d3e48bbbf29 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 31 Oct 2015 06:38:24 +0100 Subject: [PATCH 1769/1872] Trac #19496: solve linear system instead of computing inverses It is more efficient to solve the linear system T*x = right than computing T.inverse()*right. However, this means that we no longer compute the matrix power explicitly. --- src/sage/combinat/finite_state_machine.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index f38d6ded61d..d8800680cfb 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9822,22 +9822,19 @@ def jordan_block_power(block, exponent): falling_factorial(exponent, j-i)/ZZ(j-i).factorial() if j>= i else 0) - def matrix_power(A, exponent): - J, T = A.jordan_form(base_ring, transformation=True) - Jpower = matrix.block_diagonal( - [jordan_block_power(J.subdivision(j, j), exponent) - for j in range(len(J.subdivisions()[0])+1) ]) - P = Jpower.parent() - result = P(T)*Jpower*P(T).inverse() - return result - if not self.is_deterministic(): raise NotImplementedError("Finite State Machine must be deterministic.") left = vector(ZZ(s.is_initial) for s in self.iter_states()) right = vector(ZZ(s.is_final) for s in self.iter_states()) A = self.adjacency_matrix(entry=lambda t: 1) - return left*matrix_power(A, variable)*right + J, T = A.jordan_form(base_ring, transformation=True) + Jpower = matrix.block_diagonal( + [jordan_block_power(J.subdivision(j, j), variable) + for j in range(len(J.subdivisions()[0])+1) ]) + T_inv_right = T.solve_right(right).change_ring(SR) + left_T = (left*T).change_ring(SR) + return left_T*Jpower*T_inv_right def asymptotic_moments(self, variable=sage.symbolic.ring.SR.var('n')): From 6e8f5d1fe1fadde6b9b78d11b5165a123d712d91 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 31 Oct 2015 07:02:20 +0100 Subject: [PATCH 1770/1872] Trac #19496: wrap long lines in the documentation --- src/sage/combinat/finite_state_machine.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index d8800680cfb..8fc0b370a62 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9751,9 +9751,10 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), EXAMPLES:: - sage: NAFpm = Automaton([(0, 0, 0), (0, 1, 1), (0, 1, -1), (1, 0, 0)], - ....: initial_states=[0], - ....: final_states=[0, 1]) + sage: NAFpm = Automaton([(0, 0, 0), (0, 1, 1), + ....: (0, 1, -1), (1, 0, 0)], + ....: initial_states=[0], + ....: final_states=[0, 1]) sage: N = NAFpm.number_of_words(); N 4/3*2^n - 1/3*(-1)^n sage: all(len(list(NAFpm.language(_))) @@ -9771,8 +9772,8 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), ....: for _ in range(1, 6)) True - The adjacency matrix of the following example is a Jordan matrix of size 3 to - the eigenvalue 4:: + The adjacency matrix of the following example is a Jordan + matrix of size 3 to the eigenvalue 4:: sage: J3 = Automaton([(0, 1, -1), (1, 2, -1)], ....: initial_states=[0], From d46a680e7f1029bfbb9c28bb3f420444a41cb8ac Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Sat, 31 Oct 2015 07:02:45 +0100 Subject: [PATCH 1771/1872] Trac #19496: additional doctests and explanations --- src/sage/combinat/finite_state_machine.py | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 8fc0b370a62..35f22ccd812 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9761,6 +9761,11 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), ....: - len(list(NAFpm.language(_-1))) == N.subs(n=_) ....: for _ in range(1, 6)) True + + An example with non-rational eigenvalues. By default, + eigenvalues are elements of the + :mod:`field of algebraic numbers `. :: + sage: NAFp = Automaton([(0, 0, 0), (0, 1, 1), (1, 0, 0)], ....: initial_states=[0], ....: final_states=[0, 1]) @@ -9772,6 +9777,35 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), ....: for _ in range(1, 6)) True + We specify a suitable ``base_ring`` to obtain a radical + expression. To do so, we first compute the characteristic + polynomial and then construct a number field generated by its + roots. :: + + sage: M = NAFp.adjacency_matrix(entry=lambda t:1) + sage: M.characteristic_polynomial() + x^2 - x - 1 + sage: R. = NumberField(x^2-x-1, embedding=1.6) + sage: N = NAFp.number_of_words(base_ring=R); N + 1/10*(1/2*sqrt(5) + 1/2)^n*(3*sqrt(5) + 5) + - 1/10*(-1/2*sqrt(5) + 1/2)^n*(3*sqrt(5) - 5) + sage: all(len(list(NAFp.language(_))) + ....: - len(list(NAFp.language(_-1))) == N.subs(n=_) + ....: for _ in range(1, 6)) + True + + In this special case, we might also use the constant + :class:`golden_ratio `:: + + sage: R. = NumberField(x^2-x-1, embedding=golden_ratio) + sage: N = NAFp.number_of_words(base_ring=R); N + 1/5*(3*golden_ratio + 1)*golden_ratio^n + - 1/5*(3*golden_ratio - 4)*(-golden_ratio + 1)^n + sage: all(len(list(NAFp.language(_))) + ....: - len(list(NAFp.language(_-1))) == N.subs(n=_) + ....: for _ in range(1, 6)) + True + The adjacency matrix of the following example is a Jordan matrix of size 3 to the eigenvalue 4:: From 06fd9b4212d1a64448df1cbb39ba53b72865c3d1 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sat, 31 Oct 2015 11:21:28 +0000 Subject: [PATCH 1772/1872] fix the bug, and add docs --- src/sage/combinat/matrices/hadamard_matrix.py | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index fef0bda0d34..48191b9ec69 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -924,7 +924,8 @@ def skew_hadamard_matrix(n,existence=False, skew_normalize=True, check=True): Tries to construct a skew Hadamard matrix A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix - and `-S=S^\top`. + and `-S=S^\top`. Currently constructions from Section 14.1 of [Ha83]_ and few + more exotic ones are implemented. INPUT: @@ -982,12 +983,21 @@ def skew_hadamard_matrix(n,existence=False, skew_normalize=True, check=True): 52 x 52 dense matrix over Integer Ring... sage: skew_hadamard_matrix(92) 92 x 92 dense matrix over Integer Ring... + sage: skew_hadamard_matrix(816) # long time + 816 x 816 dense matrix over Integer Ring... sage: skew_hadamard_matrix(100) Traceback (most recent call last): ... ValueError: A skew Hadamard matrix of order 100 is not yet implemented. sage: skew_hadamard_matrix(100,existence=True) Unknown + + REFERENCES: + + .. [Ha83] M. Hall, + Combinatorial Theory, + 2nd edition, + Wiley, 1983 """ def true(): _skew_had_cache[n]=True @@ -1013,13 +1023,13 @@ def true(): M = hadamard_matrix_paleyI(n, normalize=False) elif n % 8 == 0: - if skew_hadamard_matrix(n//2,existence=True): + if skew_hadamard_matrix(n//2,existence=True): # (Lemma 14.1.6 in [Ha83]_) if existence: return true() H = skew_hadamard_matrix(n//2,check=False) M = block_matrix([[H,H], [-H.T,H.T]]) - else: # try Williamson construction + else: # try Williamson construction (Lemma 14.1.5 in [Ha83]_) for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n n1 = n//d if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\ @@ -1030,9 +1040,9 @@ def true(): U = matrix(ZZ, d, lambda i, j: -1 if i==j==0 else\ 1 if i==j==1 or (i>1 and j-1==d-i)\ else 0) - A = block_matrix([[matrix([0]), matrix(ZZ,1,n1-1,[1]*(n1-1))], - [ matrix(ZZ,n1-1,1,[-1]*(n1-1)), - _helper_payley_matrix(n1-1,zero_position=0)]])+I(n1) + A = block_matrix([[matrix([0]), matrix(ZZ,1,d-1,[1]*(d-1))], + [ matrix(ZZ,d-1,1,[-1]*(d-1)), + _helper_payley_matrix(d-1,zero_position=0)]])+I(d) M = A.tensor_product(I(n1))+(U*A).tensor_product(H) break if M is None: # try Williamson-Goethals-Seidel construction From 779fa74360a44a28c416b4062fda42e9037356be Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 31 Oct 2015 10:41:12 -0400 Subject: [PATCH 1773/1872] change variable _ to s; use srange instead of range in doctests --- src/sage/combinat/finite_state_machine.py | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 35f22ccd812..9dbb0065f62 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9757,9 +9757,9 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), ....: final_states=[0, 1]) sage: N = NAFpm.number_of_words(); N 4/3*2^n - 1/3*(-1)^n - sage: all(len(list(NAFpm.language(_))) - ....: - len(list(NAFpm.language(_-1))) == N.subs(n=_) - ....: for _ in range(1, 6)) + sage: all(len(list(NAFpm.language(s))) + ....: - len(list(NAFpm.language(s-1))) == N.subs(n=s) + ....: for s in srange(1, 6)) True An example with non-rational eigenvalues. By default, @@ -9772,9 +9772,9 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), sage: N = NAFp.number_of_words(); N 1.170820393249937?*1.618033988749895?^n - 0.1708203932499369?*(-0.618033988749895?)^n - sage: all(len(list(NAFp.language(_))) - ....: - len(list(NAFp.language(_-1))) == N.subs(n=_) - ....: for _ in range(1, 6)) + sage: all(len(list(NAFp.language(s))) + ....: - len(list(NAFp.language(s-1))) == N.subs(n=s) + ....: for s in srange(1, 6)) True We specify a suitable ``base_ring`` to obtain a radical @@ -9789,9 +9789,9 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), sage: N = NAFp.number_of_words(base_ring=R); N 1/10*(1/2*sqrt(5) + 1/2)^n*(3*sqrt(5) + 5) - 1/10*(-1/2*sqrt(5) + 1/2)^n*(3*sqrt(5) - 5) - sage: all(len(list(NAFp.language(_))) - ....: - len(list(NAFp.language(_-1))) == N.subs(n=_) - ....: for _ in range(1, 6)) + sage: all(len(list(NAFp.language(s))) + ....: - len(list(NAFp.language(s-1))) == N.subs(n=s) + ....: for s in srange(1, 6)) True In this special case, we might also use the constant @@ -9801,9 +9801,9 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), sage: N = NAFp.number_of_words(base_ring=R); N 1/5*(3*golden_ratio + 1)*golden_ratio^n - 1/5*(3*golden_ratio - 4)*(-golden_ratio + 1)^n - sage: all(len(list(NAFp.language(_))) - ....: - len(list(NAFp.language(_-1))) == N.subs(n=_) - ....: for _ in range(1, 6)) + sage: all(len(list(NAFp.language(s))) + ....: - len(list(NAFp.language(s-1))) == N.subs(n=s) + ....: for s in srange(1, 6)) True The adjacency matrix of the following example is a Jordan @@ -9821,9 +9821,9 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), [0 0 4] sage: N = J3.number_of_words(); N 1/2*4^(n - 2)*(n - 1)*n + 4^(n - 1)*n + 4^n - sage: all(len(list(J3.language(_))) - ....: - len(list(J3.language(_-1))) == N.subs(n=_) - ....: for _ in range(1, 6)) + sage: all(len(list(J3.language(s))) + ....: - len(list(J3.language(s-1))) == N.subs(n=s) + ....: for s in range(1, 6)) True Here is an automaton without cycles, so with eigenvalue `0`. :: From b846713be8605d6588cc3f2c9cdbf4feb41ed357 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 31 Oct 2015 10:41:35 -0400 Subject: [PATCH 1774/1872] PEP8ify --- src/sage/combinat/finite_state_machine.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 9dbb0065f62..0ff740021a2 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -9782,7 +9782,7 @@ def number_of_words(self, variable=sage.symbolic.ring.SR.var('n'), polynomial and then construct a number field generated by its roots. :: - sage: M = NAFp.adjacency_matrix(entry=lambda t:1) + sage: M = NAFp.adjacency_matrix(entry=lambda t: 1) sage: M.characteristic_polynomial() x^2 - x - 1 sage: R. = NumberField(x^2-x-1, embedding=1.6) @@ -9853,9 +9853,9 @@ def jordan_block_power(block, exponent): eigenvalue = SR(block[0, 0]) return matrix(block.nrows(), block.nrows(), - lambda i, j: eigenvalue**(exponent-(j-i))* - falling_factorial(exponent, j-i)/ZZ(j-i).factorial() - if j>= i else 0) + lambda i, j: eigenvalue**(exponent-(j-i)) * + falling_factorial(exponent, j-i) / ZZ(j-i).factorial() + if j >= i else 0) if not self.is_deterministic(): raise NotImplementedError("Finite State Machine must be deterministic.") @@ -9866,10 +9866,10 @@ def jordan_block_power(block, exponent): J, T = A.jordan_form(base_ring, transformation=True) Jpower = matrix.block_diagonal( [jordan_block_power(J.subdivision(j, j), variable) - for j in range(len(J.subdivisions()[0])+1) ]) + for j in range(len(J.subdivisions()[0]) + 1)]) T_inv_right = T.solve_right(right).change_ring(SR) - left_T = (left*T).change_ring(SR) - return left_T*Jpower*T_inv_right + left_T = (left * T).change_ring(SR) + return left_T * Jpower * T_inv_right def asymptotic_moments(self, variable=sage.symbolic.ring.SR.var('n')): From 75a48608242e992a5c00a633dde7c421e7e9b12d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 31 Oct 2015 09:58:22 -0500 Subject: [PATCH 1775/1872] Add special case for ja docs in pdf builder. --- src/doc/common/builder.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/doc/common/builder.py b/src/doc/common/builder.py index 851b7ee83ad..60b7e76b7d0 100755 --- a/src/doc/common/builder.py +++ b/src/doc/common/builder.py @@ -214,7 +214,8 @@ def pdf(self): """ Builds the PDF files for this document. This is done by first (re)-building the LaTeX output, going into that LaTeX - directory, and running 'make all-pdf' there. + directory, and running 'make all-pdf' (or for the special case of + the ja docs, 'all-pdf-ja(ex,to run platex)' there. EXAMPLES:: @@ -225,9 +226,18 @@ def pdf(self): self.latex() tex_dir = self._output_dir('latex') pdf_dir = self._output_dir('pdf') - if subprocess.call("cd '%s' && $MAKE all-pdf && mv -f *.pdf '%s'"%(tex_dir, pdf_dir), shell=True): - raise RuntimeError("failed to run $MAKE all-pdf in %s"%tex_dir) - + make_target = "cd '%s' && $MAKE all-pdf && mv -f *.pdf '%s'" + error_message = "failed to run $MAKE all-pdf in %s" + MB_LANG = {'ja':'all-pdf-ja'} # language name : the modified target + + # Replace the command for languages that require special processing + if self.lang in MB_LANG: + command = MB_LANG[self.lang] + make_target = make_target.replace('all-pdf', command) + error_message = error_message.replace('all-pdf', command) + + if subprocess.call(make_target%(tex_dir, pdf_dir), shell=True): + raise RuntimeError(error_message%tex_dir) logger.warning("Build finished. The built documents can be found in %s", pdf_dir) def clean(self, *args): From 019ac7badbabf9f1881bd84588673414940a006f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 31 Oct 2015 10:04:23 -0500 Subject: [PATCH 1776/1872] An alternative proposal for #19188 not using replace. --- src/doc/common/builder.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/common/builder.py b/src/doc/common/builder.py index 60b7e76b7d0..6787e22e9cc 100755 --- a/src/doc/common/builder.py +++ b/src/doc/common/builder.py @@ -226,18 +226,18 @@ def pdf(self): self.latex() tex_dir = self._output_dir('latex') pdf_dir = self._output_dir('pdf') - make_target = "cd '%s' && $MAKE all-pdf && mv -f *.pdf '%s'" - error_message = "failed to run $MAKE all-pdf in %s" - MB_LANG = {'ja':'all-pdf-ja'} # language name : the modified target + make_target = "cd '%s' && $MAKE %s && mv -f *.pdf '%s'" + error_message = "failed to run $MAKE %s in %s" + MB_LANG = {'ja': 'all-pdf-ja'} # language name : the modified target # Replace the command for languages that require special processing if self.lang in MB_LANG: command = MB_LANG[self.lang] - make_target = make_target.replace('all-pdf', command) - error_message = error_message.replace('all-pdf', command) + else: + command = 'all-pdf' - if subprocess.call(make_target%(tex_dir, pdf_dir), shell=True): - raise RuntimeError(error_message%tex_dir) + if subprocess.call(make_target%(tex_dir, command, pdf_dir), shell=True): + raise RuntimeError(error_message%(command, tex_dir)) logger.warning("Build finished. The built documents can be found in %s", pdf_dir) def clean(self, *args): From 9dd11b272861e5e7c50c04d44364452d71359b8d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 31 Oct 2015 10:19:30 -0500 Subject: [PATCH 1777/1872] Fixing is_unitary for FiniteDimensionalAlgebra. --- .../finite_dimensional_algebra.py | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 4c842d11d4d..0d0964c5a89 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -461,25 +461,32 @@ def is_unitary(self): sage: D.is_unitary() False - .. NOTE:: - - If a finite-dimensional algebra over a field admits a left identity, - then this is the unique left identity, and it is also a - right identity. + sage: E = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0],[1,0]]), Matrix([[0,1],[0,1]])]) + sage: E.is_unitary() + False """ - k = self.base_ring() n = self.degree() - # B is obtained by concatenating the elements of - # self.table(), and v by concatenating the rows of - # the n times n identity matrix. - B = reduce(lambda x, y: x.augment(y), - self.table(), Matrix(k, n, 0)) - v = vector(Matrix.identity(k, n).list()) - try: - self._one = B.solve_left(v) + k = self.base_ring() + if n == 0: + self._one = vector(k, []) return True + B1 = reduce(lambda x, y: x.augment(y), + self._table, Matrix(k, n, 0)) + B2 = reduce(lambda x, y: x.augment(y), + self.left_table(), Matrix(k, n, 0)) + # This is the vector obtained by concatenating the rows of the + # n times n identity matrix: + kone = k.one() + kzero = k.zero() + v = vector(k, (n - 1) * ([kone] + n * [kzero]) + [kone]) + try: + sol1 = B1.solve_left(v) + sol2 = B2.solve_left(v) except ValueError: return False + assert sol1 == sol2 + self._one = sol1 + return True def is_zero(self): """ From cc371284d78e98ecad623893bcf0ea84ceeaa861 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Tue, 27 Oct 2015 13:02:04 -0400 Subject: [PATCH 1778/1872] is_unitary method fixed --- .../finite_dimensional_algebra.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 0d0964c5a89..405407be3b6 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -307,7 +307,7 @@ def __cmp__(self, other): def base_extend(self, F): """ - Return ``self`` base changed to ``F``. + Return ``self`` base changed to the field ``F``. EXAMPLES:: @@ -350,9 +350,9 @@ def ideal(self, gens=None, given_by_matrix=False): - ``gens`` -- (default: None) - either an element of ``A`` or a list of elements of ``A``, given as vectors, matrices, or - FiniteDimensionalAlgebraElements. If ``given_by_matrix`` is ``True``, then - ``gens`` should instead be a matrix whose rows form a basis - of an ideal of ``A``. + FiniteDimensionalAlgebraElements. If ``given_by_matrix`` is + ``True``, then ``gens`` should instead be a matrix whose rows + form a basis of an ideal of ``A``. - ``given_by_matrix`` -- boolean (default: ``False``) - if ``True``, no checking is done @@ -443,6 +443,11 @@ def is_unitary(self): Return ``True`` if ``self`` has a two-sided multiplicative identity element. + .. WARNING:: + + This uses linear algebra; thus expect wrong results when + the base ring is not a field. + EXAMPLES:: sage: A = FiniteDimensionalAlgebra(QQ, []) From 58d506884e51b65406fc0ff861f0e1d7f1e48d33 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 27 Oct 2015 15:35:02 -0500 Subject: [PATCH 1779/1872] Adding UniqueRepresentation behavior. --- .../finite_dimensional_algebra.py | 146 ++++++++++++++---- .../finite_dimensional_algebra_ideal.py | 2 +- 2 files changed, 117 insertions(+), 31 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 405407be3b6..a4fac6463e0 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -18,17 +18,18 @@ from sage.rings.integer_ring import ZZ -from sage.categories.all import FiniteDimensionalAlgebrasWithBasis +from sage.categories.magmatic_algebras import MagmaticAlgebras from sage.matrix.constructor import Matrix from sage.matrix.matrix import is_Matrix from sage.modules.free_module_element import vector from sage.rings.ring import Algebra +from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method from functools import reduce -class FiniteDimensionalAlgebra(Algebra): +class FiniteDimensionalAlgebra(Algebra, UniqueRepresentation): """ Create a finite-dimensional `k`-algebra from a multiplication table. @@ -64,6 +65,66 @@ class FiniteDimensionalAlgebra(Algebra): sage: B Finite-dimensional algebra of degree 3 over Rational Field """ + @staticmethod + def __classcall_private__(cls, k, table, names='e', assume_associative=False, + category=None): + """ + Normalize input. + + EXAMPLES:: + + sage: table = [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])] + sage: A1 = FiniteDimensionalAlgebra(GF(3), table) + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, names='e') + sage: A3 = FiniteDimensionalAlgebra(GF(3), table, names=['e0', 'e1']) + sage: A1 is A2 and A2 is A3 + True + + TESTS: + + Uniqueness is not perfectly enforces across all categories:: + + sage: table = [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])] + sage: cat = Algebras(GF(3)).FiniteDimensional().WithBasis() + sage: A1 = FiniteDimensionalAlgebra(GF(3), table) + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, category=cat) + sage: A1 == A2 + True + sage: A1 is A2 + False + sage: hash(A1) == hash(A2) + True + """ + n = len(table) + table = [b.base_extend(k) for b in table] + for b in table: + b.set_immutable() + table = tuple(table) + if not all([is_Matrix(b) and b.dimensions() == (n, n) for b in table]): + raise ValueError("input is not a multiplication table") + + cat = MagmaticAlgebras(k).FiniteDimensional().WithBasis() + cat = cat.or_subcategory(category) + if assume_associative: + cat = cat.Associative() + + # TODO: Change once normalize_names is a static method or a function + #names = CategoryObject.normalize_names(n, names) + # TODO: ...and remove this + if isinstance(names, str): + if ',' in names: + names = names.split(',') + elif n != 1: + names = [names + str(i) for i in range(n)] + else: + names = [names] + names = tuple(names) + if len(names) != n: + # This is the same type of error that normalize_names throws - TCS + raise IndexError("the number of names must equal the number of generators") + + return super(FiniteDimensionalAlgebra, cls).__classcall__(cls, k, table, + names, assume_associative, cat) def __init__(self, k, table, names='e', assume_associative=False, category=None): """ @@ -99,14 +160,9 @@ def __init__(self, k, table, names='e', assume_associative=False, category=None) sage: E.gens() (e,) """ - n = len(table) - self._table = [b.base_extend(k) for b in table] - if not all([is_Matrix(b) and b.dimensions() == (n, n) for b in table]): - raise ValueError("input is not a multiplication table") + self._table = table self._assume_associative = assume_associative # No further validity checks necessary! - if category is None: - category = FiniteDimensionalAlgebrasWithBasis(k) Algebra.__init__(self, base_ring=k, names=names, category=category) def _repr_(self): @@ -172,7 +228,8 @@ def _Hom_(self, B, category): sage: A._Hom_(B, A.category()) Set of Homomorphisms from Finite-dimensional algebra of degree 1 over Rational Field to Finite-dimensional algebra of degree 2 over Rational Field """ - if category.is_subcategory(FiniteDimensionalAlgebrasWithBasis(self.base_ring())): + cat = MagmaticAlgebras(self.base_ring()).FiniteDimensional().WithBasis() + if category.is_subcategory(cat): from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_morphism import FiniteDimensionalAlgebraHomset return FiniteDimensionalAlgebraHomset(self, B, category=category) return super(FiniteDimensionalAlgebra, self)._Hom_(B, category) @@ -257,10 +314,10 @@ def table(self): sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) sage: A.table() - [ + ( [1 0] [0 1] [0 1], [0 0] - ] + ) """ return self._table @@ -273,37 +330,66 @@ def left_table(self): EXAMPLES:: sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1],[-1,0]])]) - sage: B.left_table() - [ + sage: T = B.left_table(); T + ( [1 0] [ 0 1] [0 1], [-1 0] - ] + ) + + We check immutability:: + + sage: T[0] = "vandalized by h4xx0r" + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + sage: T[1][0] = [13, 37] + Traceback (most recent call last): + ... + ValueError: matrix is immutable; please change a copy instead + (i.e., use copy(M) to change a copy of M). """ B = self.table() n = self.degree() - return [Matrix([B[j][i] for j in xrange(n)]) for i in xrange(n)] + table = [Matrix([B[j][i] for j in xrange(n)]) for i in xrange(n)] + for b in table: + b.set_immutable() + return tuple(table) - def __cmp__(self, other): + def __eq__(self, other): """ - Compare ``self`` to ``other``. + Check equality of ``self`` to ``other``. EXAMPLES:: sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) - sage: cmp(A, A) - 0 - sage: cmp(B, B) - 0 - sage: cmp(A, B) - 1 + sage: A == A + True + sage: B == B + True + sage: A == B + False """ - if not isinstance(other, FiniteDimensionalAlgebra): - return cmp(type(self), type(other)) - if self.base_ring() == other.base_ring(): - return cmp(self.table(), other.table()) - else: - return 1 + return (isinstance(other, FiniteDimensionalAlgebra) + and self.base_ring() == other.base_ring() + and self.table() == other.table()) + + def __ne__(self, other): + """ + Check if ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) + sage: A != A + False + sage: B != B + False + sage: A != B + True + """ + return not self.__eq__(other) def base_extend(self, F): """ @@ -316,7 +402,7 @@ def base_extend(self, F): sage: C.base_extend(k) Finite-dimensional algebra of degree 1 over Finite Field in y of size 2^2 """ - # Base extension of the multiplication table is done by __init__. + # Base extension of the multiplication table is done by __classcall_private__. return FiniteDimensionalAlgebra(F, self.table()) def cardinality(self): diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py index 4361661657c..07fe4bd9e04 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py @@ -84,7 +84,7 @@ def __eq__(self, other): sage: A2 = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) sage: A is A2 - False + True sage: A == A2 True sage: I2 = A.ideal(A([1,1])) From 9a20a1e9474f925a3406a434ee62541b3dd2df51 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 31 Oct 2015 14:09:16 -0500 Subject: [PATCH 1780/1872] Adding random marker in ascii. --- src/doc/ja/tutorial/programming.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst index 7895d7bdb20..750856b3bd8 100644 --- a/src/doc/ja/tutorial/programming.rst +++ b/src/doc/ja/tutorial/programming.rst @@ -638,7 +638,7 @@ Sageに付属している関数 ``kronecker`` は,PARIのCライブラリを sage: 2 < CC(3.1,1) True - sage: 5 < VectorSpace(QQ,3) # 出力は一定しない。 + sage: 5 < VectorSpace(QQ,3) # random 出力は一定しない。 False 記号を含む不等号の判定には ``bool`` 関数を用いる: From 284efb7752c8a71ca6800c0b268b50d0d754896f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 31 Oct 2015 21:03:54 +0100 Subject: [PATCH 1781/1872] trac #19490, change in Value Error, import PolynomialRing and more doc --- src/sage/combinat/q_bernoulli.pyx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/q_bernoulli.pyx b/src/sage/combinat/q_bernoulli.pyx index d803e779952..998e74c6513 100644 --- a/src/sage/combinat/q_bernoulli.pyx +++ b/src/sage/combinat/q_bernoulli.pyx @@ -2,7 +2,7 @@ `q`-Bernoulli Numbers and Polynomials """ from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.cachefunc import cached_function @@ -50,7 +50,7 @@ def q_bernoulli(m, p=None): sage: q_bernoulli(-1) Traceback (most recent call last): ... - ValueError: the argument must be a nonnegative integer. + ValueError: the argument must be a nonnegative integer REFERENCES: @@ -60,11 +60,11 @@ def q_bernoulli(m, p=None): """ m = ZZ(m) if m < 0: - raise ValueError("the argument must be a nonnegative integer.") + raise ValueError("the argument must be a nonnegative integer") cdef int i - q = polygen(ZZ, 'q') - result = (q-1)**(1-m) * sum((-1)**(m-i)*m.binomial(i)*(i+1)/(q**(i+1)-1) - for i in range(m + 1)) + q = PolynomialRing(ZZ, 'q').gen() + result = (q - 1)**(1-m) * sum((-1)**(m-i)*m.binomial(i)*(i+1)/(q**(i+1)-1) + for i in range(m + 1)) if p is None: return result else: @@ -80,8 +80,10 @@ def q_bernoulli_polynomial(m): is a polynomial in one variable `x` with coefficients in `\QQ(q)` whose value at `q=1` is the usual Bernoulli polynomial `B_m(x)`. - This function returns a slight modification of the original - Carlitz `q`-Bernoulli polynomials. + The original `q`-Bernoulli polynomials introduced by Carlitz were + polynomials in `q^y` with coefficients in `\QQ(q)`. This function returns + these polynomials but expressed in the variable `x=(q^y-1)/(q-1)`. This + allows to let `q=1` to recover the classical Bernoulli polynomials. INPUT: @@ -109,16 +111,16 @@ def q_bernoulli_polynomial(m): sage: q_bernoulli_polynomial(-1) Traceback (most recent call last): ... - ValueError: the argument must be a nonnegative integer. + ValueError: the argument must be a nonnegative integer REFERENCES: [Ca1948]_, [Ca1954]_ """ m = ZZ(m) if m < 0: - raise ValueError("the argument must be a nonnegative integer.") + raise ValueError("the argument must be a nonnegative integer") cdef int i - q = polygen(ZZ, 'q') - x = polygen(q.parent(), 'x') + q = PolynomialRing(ZZ, 'q').gen() + x = PolynomialRing(q.parent(), 'x').gen() z = 1 + (q - 1) * x return sum(m.binomial(i) * x ** (m - i) * z ** i * q_bernoulli(i) for i in range(m + 1)) From c50c78df2b1a236b32b42f5f3bf83d5f9d3b8015 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sat, 31 Oct 2015 22:32:30 +0000 Subject: [PATCH 1782/1872] fixing circulant's behaviour --- src/sage/matrix/constructor.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/sage/matrix/constructor.py b/src/sage/matrix/constructor.py index b42d8e0280f..445ef41abb7 100644 --- a/src/sage/matrix/constructor.py +++ b/src/sage/matrix/constructor.py @@ -2159,22 +2159,21 @@ def elementary_matrix(arg0, arg1=None, **kwds): return elem.transpose() @matrix_method -def circulant(v, sparse=False): +def circulant(v, sparse=None): r""" Return the circulant matrix specified by its 1st row `v` A circulant `n \times n` matrix specified by the 1st row `v=(v_0...v_{n-1})` is - the matrix $(c_{ij})_{0 \leq i,j\leq n-1}$ where $c_{ij}=v_{j-i \mod b}$. - If the input (a vector) is sparse, return a sparse matrix. - Else, by default, if the data is a plain list, return a dense matrix. + the matrix $(c_{ij})_{0 \leq i,j\leq n-1}$, where $c_{ij}=v_{j-i \mod b}$. INPUT: - ``v`` -- a list or a vector of values - - ``sparse`` -- if ``v`` is a vector, the output sparsity is determined by the - sparsity of ``v``. Else, by default, it is dense; otherwise, if ``sparse`` is - set to ``True``, it will be sparse. + - ``sparse`` -- ``None`` by default; if ``sparse`` is set to ``True``, the output + will be sparse. Respectively, setting it to ``False`` produces dense output. + If ``sparse`` is not set, and if ``v`` is a vector, the output sparsity is determined + by the sparsity of ``v``; else, the output will be dense. EXAMPLES:: @@ -2185,25 +2184,29 @@ def circulant(v, sparse=False): [4 8 1 2 3] [3 4 8 1 2] [2 3 4 8 1] - sage: matrix.circulant(vector(GF(3),[0,1,-1],sparse=True)) + sage: m = matrix.circulant(vector(GF(3),[0,1,-1],sparse=True)); m [0 1 2] [2 0 1] [1 2 0] + sage: m.is_sparse() + True TESTS:: - sage: m = matrix.circulant(vector(GF(3),[0,1,-1],sparse=True)) - sage: m.is_sparse() - True sage: m = matrix.circulant(vector(GF(3),[0,1,-1],sparse=False)) sage: m.is_sparse() False + sage: matrix.circulant([0,1,-1]).is_sparse() + False + sage: matrix.circulant([0,1,-1], sparse=True).is_sparse() + True """ from exceptions import AttributeError - try: - sparse = v.is_sparse() - except AttributeError: - pass + if sparse==None: + try: + sparse = v.is_sparse() + except AttributeError: + sparse = False n = len(v) return matrix(n, n, lambda i, j: v[(j-i)%n], sparse=sparse) From 366feaedc2e28d1fc8d03380970883f644abd5de Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 1 Nov 2015 00:35:43 +0100 Subject: [PATCH 1783/1872] non-associative doctests --- .../finite_dimensional_algebra.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 0d0964c5a89..667bae76f48 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -464,6 +464,14 @@ def is_unitary(self): sage: E = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0],[1,0]]), Matrix([[0,1],[0,1]])]) sage: E.is_unitary() False + + sage: F = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,1], [0,0,0], [1,0,0]])]) + sage: F.is_unitary() + True + + sage: G = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [1,0,0]])]) + sage: G.is_unitary() # Unique right identity, but no left identity. + False """ n = self.degree() k = self.base_ring() @@ -524,6 +532,16 @@ def one(self): Traceback (most recent call last): ... TypeError: algebra is not unitary + + sage: D = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,1], [0,0,0], [1,0,0]])]) + sage: D.one() + e0 + + sage: E = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [1,0,0]])]) + sage: E.one() + Traceback (most recent call last): + ... + TypeError: algebra is not unitary """ if not self.is_unitary(): raise TypeError("algebra is not unitary") From 5de123aba252a6e81bd947f986ff730552179cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 1 Nov 2015 09:31:47 +0100 Subject: [PATCH 1784/1872] move the associahedra to the polytopes catalogue --- src/sage/combinat/root_system/all.py | 1 - .../combinat/root_system/associahedron.py | 74 +++++++++---------- src/sage/geometry/polyhedron/library.py | 7 ++ 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py index 91e894eee4c..a4a4ecc0c33 100644 --- a/src/sage/combinat/root_system/all.py +++ b/src/sage/combinat/root_system/all.py @@ -2,7 +2,6 @@ Root system features that are imported by default in the interpreter namespace """ from sage.misc.lazy_import import lazy_import -lazy_import('sage.combinat.root_system.associahedron', 'Associahedron') from cartan_type import CartanType from dynkin_diagram import DynkinDiagram diff --git a/src/sage/combinat/root_system/associahedron.py b/src/sage/combinat/root_system/associahedron.py index b007d82c7b8..cb244efac75 100644 --- a/src/sage/combinat/root_system/associahedron.py +++ b/src/sage/combinat/root_system/associahedron.py @@ -1,7 +1,7 @@ r""" Associahedron -.. todo:: +.. TODO:: - fix adjacency matrix - edit graph method to get proper vertex labellings @@ -40,13 +40,13 @@ def Associahedron(cartan_type): The associahedron of type `A_n` is one way to realize the classical associahedron as defined in :wikipedia:`Associahedron` - A polytopal realization of the associahedron can be found in [CFZ]. The - implementation is based on [CFZ, Theorem 1.5, Remark 1.6, and Corollary - 1.9.]. + A polytopal realization of the associahedron can be found in [CFZ]_. The + implementation is based on [CFZ]_, Theorem 1.5, Remark 1.6, and Corollary + 1.9. EXAMPLES:: - sage: Asso = Associahedron(['A',2]); Asso + sage: Asso = polytopes.associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: sorted(Asso.Hrepresentation(), key=repr) [An inequality (-1, 0) x + 1 >= 0, @@ -58,24 +58,24 @@ def Associahedron(cartan_type): (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, 0), A vertex at (0, -1)) - sage: Associahedron(['B',2]) + sage: polytopes.associahedron(['B',2]) Generalized associahedron of type ['B', 2] with 6 vertices - The two pictures of [CFZ] can be recovered with:: + The two pictures of [CFZ]_ can be recovered with:: - sage: Asso = Associahedron(['A',3]); Asso + sage: Asso = polytopes.associahedron(['A',3]); Asso Generalized associahedron of type ['A', 3] with 14 vertices sage: Asso.plot() Graphics3d Object - sage: Asso = Associahedron(['B',3]); Asso + sage: Asso = polytopes.associahedron(['B',3]); Asso Generalized associahedron of type ['B', 3] with 20 vertices sage: Asso.plot() Graphics3d Object TESTS:: - sage: sorted(Associahedron(['A',3]).vertices()) + sage: sorted(polytopes.associahedron(['A',3]).vertices()) [A vertex at (-3/2, 0, -1/2), A vertex at (-3/2, 0, 3/2), A vertex at (-3/2, 1, -3/2), A vertex at (-3/2, 2, -3/2), A vertex at (-3/2, 2, 3/2), A vertex at (-1/2, -1, -1/2), @@ -84,7 +84,7 @@ def Associahedron(cartan_type): A vertex at (3/2, -2, 3/2), A vertex at (3/2, 0, -3/2), A vertex at (3/2, 2, -3/2), A vertex at (3/2, 2, 3/2)] - sage: sorted(Associahedron(['B',3]).vertices()) + sage: sorted(polytopes.associahedron(['B',3]).vertices()) [A vertex at (-3, 0, 0), A vertex at (-3, 0, 3), A vertex at (-3, 2, -2), A vertex at (-3, 4, -3), A vertex at (-3, 5, -3), A vertex at (-3, 5, 3), @@ -96,24 +96,21 @@ def Associahedron(cartan_type): A vertex at (3, -3, 0), A vertex at (3, 3, -3), A vertex at (3, 5, -3), A vertex at (3, 5, 3)] - sage: Associahedron(['A',4]).f_vector() + sage: polytopes.associahedron(['A',4]).f_vector() (1, 42, 84, 56, 14, 1) - sage: Associahedron(['B',4]).f_vector() + sage: polytopes.associahedron(['B',4]).f_vector() (1, 70, 140, 90, 20, 1) REFERENCES: - - [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of - generalized associahedra, arXiv:0202004. + .. [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of + generalized associahedra, arXiv:0202004. """ - cartan_type = CartanType( cartan_type ) + cartan_type = CartanType(cartan_type) parent = Associahedra(QQ, cartan_type.rank()) return parent(cartan_type) - - - class Associahedron_class(Polyhedron_QQ_ppl): r""" The Python class of an associahedron @@ -123,55 +120,53 @@ class Associahedron_class(Polyhedron_QQ_ppl): TESTS:: - sage: Asso = Associahedron(['A',2]); Asso + sage: Asso = polytopes.associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: TestSuite(Asso).run() """ def _repr_(self): r""" - Returns a string representation of self. + Return a string representation of ``self``. EXAMPLES:: - sage: Associahedron(['A',3])._repr_() + sage: polytopes.associahedron(['A',3])._repr_() "Generalized associahedron of type ['A', 3] with 14 vertices" """ - return 'Generalized associahedron of type %s with %s vertices'\ - %(self._cartan_type,self.n_vertices()) + msg = 'Generalized associahedron of type {} with {} vertices' + return msg.format(self._cartan_type, self.n_vertices()) def cartan_type(self): r""" - Returns the Cartan type + Return the Cartan type of ``self``. EXAMPLES:: - sage: Associahedron(['A',3]).cartan_type() + sage: polytopes.associahedron(['A',3]).cartan_type() ['A', 3] """ return self._cartan_type def vertices_in_root_space(self): r""" - Returns the vertices of ``self`` as elements in the root space + Return the vertices of ``self`` as elements in the root space. EXAMPLES:: - sage: Asso = Associahedron(['A',2]) + sage: Asso = polytopes.associahedron(['A',2]) sage: Asso.vertices() (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, 0), A vertex at (0, -1)) sage: Asso.vertices_in_root_space() - (alpha[1] - alpha[2], alpha[1] + alpha[2], -alpha[1] + alpha[2], -alpha[1], -alpha[2]) + (alpha[1] - alpha[2], alpha[1] + alpha[2], -alpha[1] + alpha[2], + -alpha[1], -alpha[2]) """ root_space = self._cartan_type.root_system().root_space() - return tuple( root_space.from_vector(vector(V)) for V in self.vertex_generator() ) - - - - + return tuple(root_space.from_vector(vector(V)) + for V in self.vertex_generator()) class Associahedra(Polyhedra_QQ_ppl): @@ -216,20 +211,19 @@ def _element_constructor_(self, cartan_type, **kwds): sage: parent._element_constructor_(['A',2]) Generalized associahedron of type ['A', 2] with 5 vertices """ - cartan_type = CartanType( cartan_type ) + cartan_type = CartanType(cartan_type) if not cartan_type.is_finite(): raise ValueError("the Cartan type must be finite") root_space = cartan_type.root_system().root_space() # TODO: generalize this as a method of root lattice realization - rhocheck = sum( beta.associated_coroot() for beta in root_space.positive_roots() )/2 + rhocheck = sum(beta.associated_coroot() + for beta in root_space.positive_roots()) / 2 I = root_space.index_set() inequalities = [] for orbit in root_space.almost_positive_roots_decomposition(): c = rhocheck.coefficient(orbit[0].leading_support()) for beta in orbit: - inequalities.append( [c] + [ beta.coefficient(i) for i in I ] ) - associahedron = super(Associahedra, self)._element_constructor_(None, [inequalities,[]]) + inequalities.append([c] + [beta.coefficient(i) for i in I]) + associahedron = super(Associahedra, self)._element_constructor_(None, [inequalities, []]) associahedron._cartan_type = cartan_type return associahedron - - diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index b1368de04bc..9d4e1094369 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -15,6 +15,7 @@ :delim: | :meth:`~sage.geometry.polyhedron.library.Polytopes.Birkhoff_polytope` + :meth:`~sage.geometry.polyhedron.library.Polytopes.associahedron` :meth:`~sage.geometry.polyhedron.library.Polytopes.buckyball` :meth:`~sage.geometry.polyhedron.library.Polytopes.cross_polytope` :meth:`~sage.geometry.polyhedron.library.Polytopes.cube` @@ -1114,4 +1115,10 @@ def parallelotope(self, generators): 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) + # -------------------------------------------------------- + # imports from other files + # -------------------------------------------------------- + import sage.combinat.root_system.associahedron + associahedron = staticmethod(sage.combinat.root_system.associahedron.Associahedron) + polytopes = Polytopes() From 7ba2730c5392d6745c87152fdf8dea526f211ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 1 Nov 2015 10:05:47 +0100 Subject: [PATCH 1785/1872] clean-up of doc of associahedra --- src/sage/combinat/root_system/associahedron.py | 17 ++++++----------- .../root_system/root_lattice_realizations.py | 14 +++----------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/sage/combinat/root_system/associahedron.py b/src/sage/combinat/root_system/associahedron.py index cb244efac75..466f4a34685 100644 --- a/src/sage/combinat/root_system/associahedron.py +++ b/src/sage/combinat/root_system/associahedron.py @@ -28,9 +28,7 @@ def Associahedron(cartan_type): r""" - Construct an associahedron - - An Associahedron + Construct an associahedron. The generalized associahedron is a polytopal complex with vertices in one-to-one correspondence with clusters in the cluster complex, and with @@ -38,9 +36,9 @@ def Associahedron(cartan_type): intersect in codimension 1. The associahedron of type `A_n` is one way to realize the classical - associahedron as defined in :wikipedia:`Associahedron` + associahedron as defined in the :wikipedia:`Associahedron`. - A polytopal realization of the associahedron can be found in [CFZ]_. The + A polytopal realization of the associahedron can be found in [CFZ]_. The implementation is based on [CFZ]_, Theorem 1.5, Remark 1.6, and Corollary 1.9. @@ -48,12 +46,14 @@ def Associahedron(cartan_type): sage: Asso = polytopes.associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices + sage: sorted(Asso.Hrepresentation(), key=repr) [An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (1, 1) x + 1 >= 0] + sage: Asso.Vrepresentation() (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, 0), A vertex at (0, -1)) @@ -61,7 +61,7 @@ def Associahedron(cartan_type): sage: polytopes.associahedron(['B',2]) Generalized associahedron of type ['B', 2] with 6 vertices - The two pictures of [CFZ]_ can be recovered with:: + The two pictures of [CFZ]_ can be recovered with:: sage: Asso = polytopes.associahedron(['A',3]); Asso Generalized associahedron of type ['A', 3] with 14 vertices @@ -100,11 +100,6 @@ def Associahedron(cartan_type): (1, 42, 84, 56, 14, 1) sage: polytopes.associahedron(['B',4]).f_vector() (1, 70, 140, 90, 20, 1) - - REFERENCES: - - .. [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of - generalized associahedra, arXiv:0202004. """ cartan_type = CartanType(cartan_type) parent = Associahedra(QQ, cartan_type.rank()) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 3df1e443fef..06f549760a6 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -1709,7 +1709,8 @@ def tau_epsilon_operator_on_almost_positive_roots(self, J): REFERENCES: - .. [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of generalized associahedra + .. [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of + generalized associahedra, :arxiv:`math/0202004`. """ W = self.weyl_group() t = W.from_reduced_word(J) @@ -1745,7 +1746,7 @@ def tau_plus_minus(self): EXAMPLES: - We explore the example of [CFZ1]_ Eq.(1.3):: + We explore the example of [CFZ]_ Eq.(1.3):: sage: S = RootSystem(['A',2]).root_lattice() sage: taup, taum = S.tau_plus_minus() @@ -1755,10 +1756,6 @@ def tau_plus_minus(self): alpha[1] + alpha[2] , alpha[2] , alpha[1] -alpha[2] , -alpha[2] , alpha[2] alpha[2] , alpha[1] + alpha[2] , -alpha[2] - - REFERENCES: - - .. [CFZ1] Chapoton, Fomin, Zelevinsky - Polytopal realizations of generalized associahedra """ ct = self.cartan_type() L,R = ct.index_set_bipartition() @@ -1790,11 +1787,6 @@ def almost_positive_roots_decomposition(self): [-alpha[2], alpha[2], alpha[1] + alpha[2] + alpha[3] + alpha[4], alpha[1] + 2*alpha[2] + alpha[3] + alpha[4]], [-alpha[3], alpha[3], alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[4]], [-alpha[4], alpha[4], alpha[2] + alpha[4], alpha[1] + alpha[2] + alpha[3]]] - - REFERENCES: - - .. [CFZ2] Chapoton, Fomin, Zelevinsky - Polytopal realizations of - generalized associahedra """ # TODO: this should use a generic function for computing # orbits under the action of a group: From d82bb5277c5fb2715ba3fb679b4329a5a150a667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 1 Nov 2015 12:23:32 +0100 Subject: [PATCH 1786/1872] tra #19509 fixing staticmethod import --- src/sage/geometry/polyhedron/library.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 9d4e1094369..e498d34f803 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -68,6 +68,7 @@ from constructor import Polyhedron from sage.graphs.digraph import DiGraph +from sage.combinat.root_system.associahedron import Associahedron def zero_sum_projection(d): r""" @@ -149,8 +150,6 @@ class Polytopes(): polytopes. """ - flow_polytope = staticmethod(DiGraph.flow_polytope) - def regular_polygon(self, n, exact=True, base_ring=None): """ Return a regular polygon with `n` vertices. @@ -1118,7 +1117,8 @@ def parallelotope(self, generators): # -------------------------------------------------------- # imports from other files # -------------------------------------------------------- - import sage.combinat.root_system.associahedron - associahedron = staticmethod(sage.combinat.root_system.associahedron.Associahedron) + associahedron = staticmethod(Associahedron) + + flow_polytope = staticmethod(DiGraph.flow_polytope) polytopes = Polytopes() From 3a42a1c4ecd2a8572de4b5c1a4e0a985745814f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 1 Nov 2015 17:29:56 +0100 Subject: [PATCH 1787/1872] trac #19490 reviewer's comments --- src/sage/combinat/q_bernoulli.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/q_bernoulli.pyx b/src/sage/combinat/q_bernoulli.pyx index 998e74c6513..6f899a4cf1e 100644 --- a/src/sage/combinat/q_bernoulli.pyx +++ b/src/sage/combinat/q_bernoulli.pyx @@ -119,8 +119,9 @@ def q_bernoulli_polynomial(m): if m < 0: raise ValueError("the argument must be a nonnegative integer") cdef int i - q = PolynomialRing(ZZ, 'q').gen() - x = PolynomialRing(q.parent(), 'x').gen() + R = PolynomialRing(ZZ, 'q') + q = R.gen() + x = PolynomialRing(R, 'x').gen() z = 1 + (q - 1) * x return sum(m.binomial(i) * x ** (m - i) * z ** i * q_bernoulli(i) for i in range(m + 1)) From d8d3eda712c9b8eba85fed818ef385e56ddb16b3 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Sun, 1 Nov 2015 20:07:07 -0500 Subject: [PATCH 1788/1872] additions to NCSF/QSym/Sym/NCSym/NCSymD to ensure that MRO errors are not triggered --- src/sage/combinat/ncsf_qsym/ncsf.py | 6 +++++- src/sage/combinat/ncsf_qsym/qsym.py | 7 +++++-- src/sage/combinat/ncsym/dual.py | 6 ++++++ src/sage/combinat/ncsym/ncsym.py | 6 ++++++ src/sage/combinat/sf/sf.py | 12 +++++------- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/ncsf_qsym/ncsf.py b/src/sage/combinat/ncsf_qsym/ncsf.py index d6ba56f6478..15422a928e7 100644 --- a/src/sage/combinat/ncsf_qsym/ncsf.py +++ b/src/sage/combinat/ncsf_qsym/ncsf.py @@ -32,6 +32,7 @@ from sage.functions.other import factorial from sage.categories.realizations import Category_realization_of_parent from sage.categories.rings import Rings +from sage.categories.fields import Fields from sage.categories.graded_hopf_algebras import GradedHopfAlgebras from sage.combinat.composition import Compositions from sage.combinat.free_module import CombinatorialFreeModule @@ -401,9 +402,12 @@ def __init__(self, R): r""" TESTS:: + sage: NCSF1 = NonCommutativeSymmetricFunctions(FiniteField(23)) + sage: NCSF2 = NonCommutativeSymmetricFunctions(Integers(23)) sage: TestSuite(NonCommutativeSymmetricFunctions(QQ)).run() """ - assert(R in Rings()) + # change the line below to assert(R in Rings()) once MRO issues from #15536, #15475 are resolved + assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R self._base = R # Won't be needed once CategoryObject won't override base_ring Parent.__init__(self, category = GradedHopfAlgebras(R).WithRealizations()) diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index 26568000798..2434430c93e 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -65,8 +65,8 @@ from sage.misc.bindable_class import BindableClass from sage.categories.graded_hopf_algebras import GradedHopfAlgebras -from sage.categories.all import CommutativeRings from sage.categories.rings import Rings +from sage.categories.fields import Fields from sage.categories.realizations import Category_realization_of_parent from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -529,9 +529,12 @@ def __init__(self, R): sage: QuasiSymmetricFunctions(QQ) Quasisymmetric functions over the Rational Field + sage: QSym1 = QuasiSymmetricFunctions(FiniteField(23)) + sage: QSym2 = QuasiSymmetricFunctions(Integers(23)) sage: TestSuite(QuasiSymmetricFunctions(QQ)).run() """ - assert R in Rings() + # change the line below to assert(R in Rings()) once MRO issues from #15536, #15475 are resolved + assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R self._base = R # Won't be needed once CategoryObject won't override base_ring category = GradedHopfAlgebras(R) # TODO: .Commutative() self._category = category diff --git a/src/sage/combinat/ncsym/dual.py b/src/sage/combinat/ncsym/dual.py index 3a01c975a1a..11f6a79be99 100644 --- a/src/sage/combinat/ncsym/dual.py +++ b/src/sage/combinat/ncsym/dual.py @@ -17,6 +17,8 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.graded_hopf_algebras import GradedHopfAlgebras +from sage.categories.rings import Rings +from sage.categories.fields import Fields from sage.combinat.ncsym.bases import NCSymDualBases, NCSymBasis_abstract from sage.combinat.partition import Partition @@ -39,8 +41,12 @@ def __init__(self, R): EXAMPLES:: + sage: NCSymD1 = SymmetricFunctionsNonCommutingVariablesDual(FiniteField(23)) + sage: NCSymD2 = SymmetricFunctionsNonCommutingVariablesDual(Integers(23)) sage: TestSuite(SymmetricFunctionsNonCommutingVariables(QQ).dual()).run() """ + # change the line below to assert(R in Rings()) once MRO issues from #15536, #15475 are resolved + assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R self._base = R # Won't be needed once CategoryObject won't override base_ring category = GradedHopfAlgebras(R) # TODO: .Commutative() Parent.__init__(self, category=category.WithRealizations()) diff --git a/src/sage/combinat/ncsym/ncsym.py b/src/sage/combinat/ncsym/ncsym.py index 27a63cc7921..6cdd45766b1 100644 --- a/src/sage/combinat/ncsym/ncsym.py +++ b/src/sage/combinat/ncsym/ncsym.py @@ -18,6 +18,8 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.graded_hopf_algebras import GradedHopfAlgebras +from sage.categories.rings import Rings +from sage.categories.fields import Fields from sage.functions.other import factorial from sage.combinat.free_module import CombinatorialFreeModule @@ -282,8 +284,12 @@ def __init__(self, R): EXAMPLES:: + sage: NCSym1 = SymmetricFunctionsNonCommutingVariables(FiniteField(23)) + sage: NCSym2 = SymmetricFunctionsNonCommutingVariables(Integers(23)) sage: TestSuite(SymmetricFunctionsNonCommutingVariables(QQ)).run() """ + # change the line below to assert(R in Rings()) once MRO issues from #15536, #15475 are resolved + assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R self._base = R # Won't be needed once CategoryObject won't override base_ring category = GradedHopfAlgebras(R) # TODO: .Commutative() Parent.__init__(self, category = category.WithRealizations()) diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 895aad981c7..22d587d6611 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -21,9 +21,9 @@ #***************************************************************************** from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.categories.rings import Rings from sage.categories.graded_hopf_algebras import GradedHopfAlgebras from sage.categories.fields import Fields +from sage.categories.rings import Rings from sage.combinat.partition import Partitions from sage.combinat.free_module import CombinatorialFreeModule from sage.rings.rational_field import QQ @@ -829,15 +829,13 @@ def __init__(self, R): TESTS:: + sage: Sym1 = SymmetricFunctions(FiniteField(23)) + sage: Sym2 = SymmetricFunctions(Integers(23)) sage: TestSuite(Sym).run() """ - assert(R in Rings()) - # FIXME: We just automatically check that the base ring is a field to - # prevent category refinement during construction of the category, - # thus preventing the MRO issues noted in #15536, #15475 (and likely others). - # Thus fix the MRO/category-refinement issue and remove the line below. - R in Fields() + # change the line below to assert(R in Rings()) once MRO issues from #15536, #15475 are resolved + assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R self._base = R # Won't be needed when CategoryObject won't override anymore base_ring Parent.__init__(self, category = GradedHopfAlgebras(R).WithRealizations()) From 5b492f37fd2918dcc66e16ff446f5b30fe1bb9a4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 1 Nov 2015 20:32:12 -0600 Subject: [PATCH 1789/1872] Fixing non-ascii character. --- src/sage/combinat/sf/symplectic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index ea623769305..2fcd5c09d12 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -61,7 +61,7 @@ class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): .. [KoikeTerada1987] K. Koike, I. Terada, *Young-diagrammatic methods for the representation theory of the classical groups of type Bn, Cn, Dn*. - J. Algebra 107 (1987), no. 2, 466–511. + J. Algebra 107 (1987), no. 2, 466-511. .. [ShimozonoZabrocki2006] Mark Shimozono and Mike Zabrocki. *Deformed universal characters for classical and affine algebras*. From 84f5917bbf3ffa4d7fc04b1abe2220e8871060b9 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Mon, 2 Nov 2015 08:04:07 -0500 Subject: [PATCH 1790/1872] use the default implementation of antipode and counit, remove specifications of category in morphisms --- src/sage/combinat/sf/character.py | 49 ++++++++----------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 13e36e9b168..e1c1b83ad4b 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -30,7 +30,6 @@ from sage.combinat.sf.sfa import SymmetricFunctionAlgebra_generic as SFA_generic from sage.misc.cachefunc import cached_method from sage.categories.homset import Hom -from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.morphism import SetMorphism from sage.combinat.partition import Partition from sage.rings.arith import divisors, moebius @@ -116,33 +115,6 @@ def _other_to_self(self, sexpr): sexpr -= sexpr.coefficient(mup) * self._self_to_other_on_basis(mup) return out - def counit(self, x): - r""" - Return the counit of ``x`` in ``self``. - - EXAMPLES:: - - sage: ht = SymmetricFunctions(QQ).ht() - sage: ht.an_element() - 2*ht[] + 2*ht[1] + 3*ht[2] - sage: ht.counit(ht.an_element()) - 2 - """ - return self._other.counit(self._other(x)) - - def antipode(self, x): - r""" - Return the antipode of ``x`` in ``self``. - - EXAMPLES:: - - sage: ht = SymmetricFunctions(QQ).ht() - sage: ht.an_element() - 2*ht[] + 2*ht[1] + 3*ht[2] - sage: ht.antipode(ht.an_element()) - 2*ht[] + ht[1] + 3*ht[1, 1] - 3*ht[2] - """ - return self( self._other.antipode(self._other(x)) ) class character_basis(generic_character): r""" @@ -215,11 +187,9 @@ def __init__(self, Sym, other_basis, bname, pfix): """ SFA_generic.__init__(self, Sym, basis_name=bname, prefix=pfix, graded=False) self._other = other_basis - categ = HopfAlgebrasWithBasis(self.base_ring()).Graded() self.module_morphism(self._self_to_other_on_basis, - codomain=self._other, - category=categ).register_as_coercion() - self.register_coercion(SetMorphism(Hom(self._other, self, categ), + codomain=self._other).register_as_coercion() + self.register_coercion(SetMorphism(Hom(self._other, self), self._other_to_self)) @cached_method @@ -306,6 +276,15 @@ class irreducible_character_basis(generic_character): st[1] + st[1, 1] + st[2] + st[2, 1] + st[3] sage: s[4,2].kronecker_product(s[5,1]) s[3, 2, 1] + s[3, 3] + s[4, 1, 1] + s[4, 2] + s[5, 1] + sage: st[1,1,1].counit() + -1 + sage: all(sum(c*st(la)*st(mu).antipode() for + ....: ((la,mu),c) in st(ga).coproduct())==st(st(ga).counit()) + ....: for ga in Partitions(3)) + True + + TESTS:: + sage: TestSuite(st).run() """ def __init__(self, Sym, pfix): @@ -335,12 +314,10 @@ def __init__(self, Sym, pfix): self._other = Sym.Schur() self._p = Sym.powersum() - categ = HopfAlgebrasWithBasis(self.base_ring()).Graded() self.module_morphism(self._self_to_power_on_basis, - codomain=Sym.powersum(), - category=categ).register_as_coercion() + codomain=Sym.powersum()).register_as_coercion() from sage.categories.morphism import SetMorphism - self.register_coercion(SetMorphism(Hom(self._other, self, categ), + self.register_coercion(SetMorphism(Hom(self._other, self), self._other_to_self)) def _b_power_k(self, k): From 9ac89ae33b6ee825c1a4179709c759406764d315 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 2 Nov 2015 13:24:24 +0100 Subject: [PATCH 1791/1872] Move pynac_symbol_registry to cdef attribute SR.symbols --- src/sage/calculus/calculus.py | 11 +++++++---- src/sage/symbolic/callable.py | 4 +++- src/sage/symbolic/expression.pyx | 10 ++++++---- src/sage/symbolic/ring.pxd | 7 +++++++ src/sage/symbolic/ring.pyx | 26 ++++++++++---------------- 5 files changed, 33 insertions(+), 25 deletions(-) create mode 100644 src/sage/symbolic/ring.pxd diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index c895e9cb135..72c96362200 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1960,7 +1960,6 @@ def maxima_options(**kwds): # _find_var() and _find_func() functions below without extra arguments. _augmented_syms = {} -from sage.symbolic.ring import pynac_symbol_registry def _find_var(name): """ @@ -1976,13 +1975,17 @@ def _find_var(name): I """ try: - res = _augmented_syms.get(name) - if res is None: - return pynac_symbol_registry[name] + res = _augmented_syms[name] + except KeyError: + pass + else: # _augmented_syms might contain entries pointing to functions if # previous computations polluted the maxima workspace if not isinstance(res, Function): return res + + try: + return SR.symbols[name] except KeyError: pass diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index e64659eac01..e1900971143 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -61,7 +61,8 @@ SyntaxError: can't assign to function call """ -from sage.symbolic.ring import SymbolicRing, SR, ParentWithBase +from sage.structure.parent_base import ParentWithBase +from sage.symbolic.ring import SymbolicRing, SR from sage.categories.pushout import ConstructionFunctor ######################################################################################### @@ -283,6 +284,7 @@ def __init__(self, arguments): self._arguments = arguments ParentWithBase.__init__(self, SR) self._populate_coercion_lists_(coerce_list=[SR]) + self.symbols = SR.symbols # Use the same list of symbols as SR def __hash__(self): """ diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 3809dc83610..a962be91946 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -11492,14 +11492,16 @@ cdef class Expression(CommutativeRingElement): ValueError: Expression cos(x)*sin(x) contains no y terms - TESTS:: + TESTS: - sage: var('x,y') # check that the pynac registry is not polluted + Check that the symbols registry is not polluted:: + + sage: var('x,y') (x, y) - sage: psr = copy(sage.symbolic.ring.pynac_symbol_registry) + sage: psr = copy(SR.symbols) sage: (x^6*y^5).implicit_derivative(y, x, 3) -792/125*y/x^3 + 12/25*(15*x^4*y^5 + 28*x^3*y^5)/(x^6*y^4) - 36/125*(20*x^5*y^4 + 43*x^4*y^4)/(x^7*y^3) - sage: psr == sage.symbolic.ring.pynac_symbol_registry + sage: psr == SR.symbols True """ from sage.symbolic.ring import SR diff --git a/src/sage/symbolic/ring.pxd b/src/sage/symbolic/ring.pxd new file mode 100644 index 00000000000..3f029346bba --- /dev/null +++ b/src/sage/symbolic/ring.pxd @@ -0,0 +1,7 @@ +from sage.symbolic.expression cimport Expression +from sage.rings.ring cimport CommutativeRing + +cdef class SymbolicRing(CommutativeRing): + cdef public dict symbols + + cpdef Expression symbol(self, name=*, latex_name=*, domain=*) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 239097c6be2..8341f2edae9 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -13,10 +13,6 @@ The symbolic ring # http://www.gnu.org/licenses/ #***************************************************************************** -################################################################# -# Initialize the library -################################################################# - from ginac cimport * from sage.rings.integer cimport Integer @@ -27,14 +23,11 @@ from sage.symbolic.expression cimport Expression, new_Expression_from_GEx, new_E from sage.libs.pari.pari_instance import PariInstance from sage.misc.latex import latex_variable_name 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, ZZ -pynac_symbol_registry = {} cdef class SymbolicRing(CommutativeRing): """ @@ -51,6 +44,7 @@ cdef class SymbolicRing(CommutativeRing): """ CommutativeRing.__init__(self, self) self._populate_coercion_lists_(convert_method_name='_symbolic_') + self.symbols = {} def __reduce__(self): """ @@ -501,7 +495,7 @@ cdef class SymbolicRing(CommutativeRing): sage: SR._an_element_() some_variable """ - return self.var('some_variable') + return self.symbol('some_variable') def is_field(self, proof = True): """ @@ -555,7 +549,7 @@ cdef class SymbolicRing(CommutativeRing): from sage.symbolic.constants import pi return self(pi) - cpdef symbol(self, name=None, latex_name=None, domain=None): + cpdef Expression symbol(self, name=None, latex_name=None, domain=None): """ EXAMPLES:: @@ -609,13 +603,13 @@ cdef class SymbolicRing(CommutativeRing): cdef Expression e # check if there is already a symbol with same name - e = pynac_symbol_registry.get(name) + e = self.symbols.get(name) # fast path to get an already existing variable if e is not None: if domain is None: if latex_name is None: - return self(e) + return e # get symbol symb = ex_to_symbol(e._gobj) @@ -627,7 +621,7 @@ cdef class SymbolicRing(CommutativeRing): if domain is not None: send_sage_domain_to_maxima(e, domain) - return self(e) + return e else: # initialize a new symbol # Construct expression @@ -646,7 +640,7 @@ cdef class SymbolicRing(CommutativeRing): else: ginac_domain = domain_complex symb = ginac_symbol(name, latex_name, ginac_domain) - pynac_symbol_registry[name] = e + self.symbols[name] = e GEx_construct_symbol(&e._gobj, symb) if domain is not None: @@ -654,7 +648,7 @@ cdef class SymbolicRing(CommutativeRing): return e - cpdef var(self, name, latex_name=None, domain=None): + def var(self, name, latex_name=None, domain=None): """ Return the symbolic variable defined by x as an element of the symbolic ring. @@ -1043,8 +1037,8 @@ def var(name, **kwds): TESTS: - These examples test that variables can only be made from - valid identifiers. See Trac 7496 (and 9724) for details:: + These examples test that variables can only be made from valid + identifiers. See :trac:`7496` (and :trac:`9724`) for details:: sage: var(' ') Traceback (most recent call last): From 0069c10a8f1540db42c38952150407864a45a828 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 2 Nov 2015 11:01:27 -0500 Subject: [PATCH 1792/1872] documenting magmatism --- .../finite_dimensional_algebra.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index a4fac6463e0..920d9123c9b 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -46,7 +46,10 @@ class FiniteDimensionalAlgebra(Algebra, UniqueRepresentation): ``True``, then methods requiring associativity assume this without checking - - ``category`` -- (default: ``FiniteDimensionalAlgebrasWithBasis(k)``) + - ``category`` -- (default: + ``MagmaticAlgebras(k).FiniteDimensional().WithBasis()`` + when ``assume_associative`` is ``False``, else + ``Algebras(k).FiniteDimensional().WithBasis()``) the category to which this algebra belongs The list ``table`` must have the following form: there exists a @@ -64,6 +67,14 @@ class FiniteDimensionalAlgebra(Algebra, UniqueRepresentation): sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B Finite-dimensional algebra of degree 3 over Rational Field + + TESTS:: + + sage: A.category() + Category of finite dimensional magmatic algebras with basis over Finite Field of size 3 + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])], assume_associative=True) + sage: A.category() + Category of finite dimensional associative algebras with basis over Finite Field of size 3 """ @staticmethod def __classcall_private__(cls, k, table, names='e', assume_associative=False, From b2d0194f7e0f42b6c250c2d9b10896c4f8e8aaca Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 2 Nov 2015 13:09:11 -0500 Subject: [PATCH 1793/1872] a couple more fixes --- .../finite_dimensional_algebra.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 920d9123c9b..1294f783661 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -63,6 +63,7 @@ class FiniteDimensionalAlgebra(Algebra, UniqueRepresentation): sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) sage: A Finite-dimensional algebra of degree 2 over Finite Field of size 3 + sage: TestSuite(A).run() sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B @@ -110,9 +111,9 @@ def __classcall_private__(cls, k, table, names='e', assume_associative=False, table = [b.base_extend(k) for b in table] for b in table: b.set_immutable() + if not (is_Matrix(b) and b.dimensions() == (n, n)): + raise ValueError("input is not a multiplication table") table = tuple(table) - if not all([is_Matrix(b) and b.dimensions() == (n, n) for b in table]): - raise ValueError("input is not a multiplication table") cat = MagmaticAlgebras(k).FiniteDimensional().WithBasis() cat = cat.or_subcategory(category) @@ -306,7 +307,8 @@ def __iter__(self): def _ideal_class_(self, n=0): """ - Return the ideal class of ``self``. + Return the ideal class of ``self`` (that is, the class that + all ideals of ``self`` inherit from). EXAMPLES:: From e772c76a06e90d7d5b7649b4c546e428e8ab2a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Mon, 2 Nov 2015 23:37:09 +0100 Subject: [PATCH 1794/1872] Add parameter immutable to functions to_simple, to_directed and to_undirected --- src/sage/graphs/digraph.py | 22 +++++++++++++++++----- src/sage/graphs/generic_graph.py | 10 +++++++--- src/sage/graphs/graph.py | 22 +++++++++++++++++----- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 3abc113977f..ef062c44889 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -1071,20 +1071,26 @@ def is_directed_acyclic(self, certificate = False): """ return self._backend.is_directed_acyclic(certificate = certificate) - def to_directed(self): + def to_directed(self, immutable=None): """ Since the graph is already directed, simply returns a copy of itself. + INPUT: + + - ``immutable`` (boolean) -- whether to create a mutable/immutable + copy. ``immutable=None`` (default) means that the graph and its copy + will behave the same way. + EXAMPLES:: sage: DiGraph({0:[1,2,3],4:[5,1]}).to_directed() Digraph on 6 vertices """ - return self.copy() + return self.copy(immutable=immutable) def to_undirected(self, implementation='c_graph', data_structure=None, - sparse=None): + sparse=None, immutable=None): """ Returns an undirected version of the graph. Every directed edge becomes an edge. @@ -1099,6 +1105,10 @@ def to_undirected(self, implementation='c_graph', data_structure=None, ``data_structure="sparse"``, and ``sparse=False`` is an alias for ``data_structure="dense"``. + - ``immutable`` (boolean) -- whether to create a mutable/immutable + graph. ``immutable=None`` (default) means that the graph and its + undirected version will behave the same way. + EXAMPLES:: sage: D = DiGraph({0:[1,2],1:[0]}) @@ -1130,6 +1140,8 @@ def to_undirected(self, implementation='c_graph', data_structure=None, data_structure = "sparse" else: data_structure = "static_sparse" + if immutable is None: + immutable = (data_structure == "static_sparse") from sage.graphs.all import Graph G = Graph(name = self.name(), pos = self._pos, @@ -1145,8 +1157,8 @@ def to_undirected(self, implementation='c_graph', data_structure=None, G._embedding = copy(self._embedding) G._weighted = self._weighted - if data_structure == "static_sparse": - G=G.copy(data_structure=data_structure) + if immutable: + G=G.copy(data_structure="static_sparse") return G diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 84938f5c7eb..f625ed33958 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16353,7 +16353,7 @@ def complement(self): return G.copy(immutable=True) return G - def to_simple(self, to_undirected=True, keep_label='any'): + def to_simple(self, to_undirected=True, keep_label='any', immutable=None): """ Returns a simple version of itself. @@ -16370,6 +16370,10 @@ def to_simple(self, to_undirected=True, keep_label='any'): kept: any label (``'any'``), the smallest label (``'min'``), or the largest (``'max'``). + - ``immutable`` (boolean) -- whether to create a mutable/immutable + copy. ``immutable=None`` (default) means that the graph and its copy + will behave the same way. + EXAMPLES:: sage: G = DiGraph(loops=True,multiedges=True,sparse=True) @@ -16391,9 +16395,9 @@ def to_simple(self, to_undirected=True, keep_label='any'): [(2, 3, 2), (3, 2, None)] """ if to_undirected: - g=self.to_undirected() + g=self.to_undirected(immutable=immutable) else: - g=copy(self) + g=self.copy(immutable=immutable) g.allow_loops(False) g.allow_multiple_edges(False, keep_label=keep_label) return g diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 56282c0c86e..bf687559da2 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4831,7 +4831,7 @@ def centrality_degree(self, v=None): ### Constructors def to_directed(self, implementation='c_graph', data_structure=None, - sparse=None): + sparse=None, immutable=None): """ Returns a directed version of the graph. A single edge becomes two edges, one in each direction. @@ -4846,6 +4846,10 @@ def to_directed(self, implementation='c_graph', data_structure=None, ``data_structure="sparse"``, and ``sparse=False`` is an alias for ``data_structure="dense"``. + - ``immutable`` (boolean) -- whether to create a mutable/immutable + digraph. ``immutable=None`` (default) means that the graph and its + directed version will behave the same way. + EXAMPLES:: sage: graphs.PetersenGraph().to_directed() @@ -4878,6 +4882,8 @@ def to_directed(self, implementation='c_graph', data_structure=None, data_structure = "sparse" else: data_structure = "static_sparse" + if immutable is None: + immutable = (data_structure == "static_sparse") from sage.graphs.all import DiGraph D = DiGraph(name = self.name(), pos = self._pos, @@ -4895,22 +4901,28 @@ def to_directed(self, implementation='c_graph', data_structure=None, D._embedding = copy(self._embedding) D._weighted = self._weighted - if data_structure == "static_sparse": - D = D.copy(data_structure=data_structure) + if immutable: + D = D.copy(data_structure="static_sparse") return D - def to_undirected(self): + def to_undirected(self, immutable=None): """ Since the graph is already undirected, simply returns a copy of itself. + INPUT: + + - ``immutable`` (boolean) -- whether to create a mutable/immutable + copy. ``immutable=None`` (default) means that the graph and its copy + will behave the same way. + EXAMPLES:: sage: graphs.PetersenGraph().to_undirected() Petersen graph: Graph on 10 vertices """ - return self.copy() + return self.copy(immutable=immutable) def join(self, other, verbose_relabel=None, labels="pairs"): """ From b7497ff83b919219025c7a611d162a4f19815486 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 2 Nov 2015 16:54:35 -0600 Subject: [PATCH 1795/1872] Removing the equality checks and some other little fixes. --- .../finite_dimensional_algebra.py | 83 ++++++++----------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 1294f783661..319d20315f3 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -29,7 +29,7 @@ from functools import reduce -class FiniteDimensionalAlgebra(Algebra, UniqueRepresentation): +class FiniteDimensionalAlgebra(UniqueRepresentation, Algebra): """ Create a finite-dimensional `k`-algebra from a multiplication table. @@ -44,12 +44,10 @@ class FiniteDimensionalAlgebra(Algebra, UniqueRepresentation): - ``assume_associative`` -- (default: ``False``) boolean; if ``True``, then methods requiring associativity assume this - without checking + without checking and sets the category as ``category.Associative()`` - ``category`` -- (default: - ``MagmaticAlgebras(k).FiniteDimensional().WithBasis()`` - when ``assume_associative`` is ``False``, else - ``Algebras(k).FiniteDimensional().WithBasis()``) + ``MagmaticAlgebras(k).FiniteDimensional().WithBasis()``) the category to which this algebra belongs The list ``table`` must have the following form: there exists a @@ -83,7 +81,7 @@ def __classcall_private__(cls, k, table, names='e', assume_associative=False, """ Normalize input. - EXAMPLES:: + TESTS:: sage: table = [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])] sage: A1 = FiniteDimensionalAlgebra(GF(3), table) @@ -92,19 +90,40 @@ def __classcall_private__(cls, k, table, names='e', assume_associative=False, sage: A1 is A2 and A2 is A3 True - TESTS: + The ``assume_associative`` keyword is built into the category:: - Uniqueness is not perfectly enforces across all categories:: + sage: from sage.categories.magmatic_algebras import MagmaticAlgebras + sage: cat = MagmaticAlgebras(GF(3)).FiniteDimensional().WithBasis() + sage: A1 = FiniteDimensionalAlgebra(GF(3), table, category=cat.Associative()) + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, assume_associative=True) + sage: A1 is A2 + True + + Uniqueness depends on the category:: - sage: table = [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])] sage: cat = Algebras(GF(3)).FiniteDimensional().WithBasis() sage: A1 = FiniteDimensionalAlgebra(GF(3), table) sage: A2 = FiniteDimensionalAlgebra(GF(3), table, category=cat) sage: A1 == A2 - True + False sage: A1 is A2 False - sage: hash(A1) == hash(A2) + + Checking that equality is still as expected:: + + sage: A = FiniteDimensionalAlgebra(GF(3), table) + sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) + sage: A == A + True + sage: B == B + True + sage: A == B + False + sage: A != A + False + sage: B != B + False + sage: A != B True """ n = len(table) @@ -136,9 +155,9 @@ def __classcall_private__(cls, k, table, names='e', assume_associative=False, raise IndexError("the number of names must equal the number of generators") return super(FiniteDimensionalAlgebra, cls).__classcall__(cls, k, table, - names, assume_associative, cat) + names, category=cat) - def __init__(self, k, table, names='e', assume_associative=False, category=None): + def __init__(self, k, table, names='e', category=None): """ TESTS:: @@ -173,7 +192,7 @@ def __init__(self, k, table, names='e', assume_associative=False, category=None) (e,) """ self._table = table - self._assume_associative = assume_associative + self._assume_associative = "Associative" in category.axioms() # No further validity checks necessary! Algebra.__init__(self, base_ring=k, names=names, category=category) @@ -368,42 +387,6 @@ def left_table(self): b.set_immutable() return tuple(table) - def __eq__(self, other): - """ - Check equality of ``self`` to ``other``. - - EXAMPLES:: - - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) - sage: A == A - True - sage: B == B - True - sage: A == B - False - """ - return (isinstance(other, FiniteDimensionalAlgebra) - and self.base_ring() == other.base_ring() - and self.table() == other.table()) - - def __ne__(self, other): - """ - Check if ``self`` is not equal to ``other``. - - EXAMPLES:: - - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) - sage: A != A - False - sage: B != B - False - sage: A != B - True - """ - return not self.__eq__(other) - def base_extend(self, F): """ Return ``self`` base changed to the field ``F``. From 2f351bb5dae66a0353bb90e80645449879210710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Mon, 2 Nov 2015 23:59:45 +0100 Subject: [PATCH 1796/1872] Fix is_cut_edge to make a copy of an immutable graph --- src/sage/graphs/generic_graph.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index f625ed33958..a88613be824 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -5237,17 +5237,22 @@ def is_cut_edge(self, u, v=None, label=None): if len([(uu,vv) for uu,vv,ll in self.edges_incident(u) if uu == v or vv == v]) > 1: return False - self.delete_edge(u,v,label) - if self.is_directed(): + if getattr(self, '_immutable', False): + G = copy(self) + else: + G = self + G.delete_edge(u,v,label) + if G.is_directed(): # (u,v) is a cut-edge if u is not in the connected # component containing v of self-(u,v) - sol = not u in self.connected_component_containing_vertex(v) + sol = not u in G.connected_component_containing_vertex(v) else: # (u,v) is a cut-edge if there is no path from u to v in # self-(u,v) - sol = not self.distance(u,v) < self.order() + sol = not G.distance(u,v) < G.order() - self.add_edge(u,v,label) + if not getattr(self, '_immutable', False): + G.add_edge(u,v,label) return sol From 9c1870a754a700da9bd3d4a35b7eac764255d4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Tue, 3 Nov 2015 00:51:13 +0100 Subject: [PATCH 1797/1872] Add parameter immutable to subgraph and helper function, fix steiner_tree --- src/sage/graphs/generic_graph.py | 41 +++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index a88613be824..d6701f6b78c 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -5465,7 +5465,7 @@ def steiner_tree(self,vertices, weighted = False, solver = None, verbose = 0): if not weighted: gg = g.subgraph(vertices) if gg.is_connected(): - st = g.subgraph(edges = gg.min_spanning_tree()) + st = g.subgraph(edges = gg.min_spanning_tree(), immutable=False) st.delete_vertices([v for v in g if st.degree(v) == 0]) return st @@ -5517,7 +5517,8 @@ def steiner_tree(self,vertices, weighted = False, solver = None, verbose = 0): edges = p.get_values(edges) - st = g.subgraph(edges=[e for e in g.edges(labels = False) if edges[R(e)] == 1]) + st = g.subgraph(edges=[e for e in g.edges(labels = False) if edges[R(e)] == 1], + immutable=False) st.delete_vertices([v for v in g if st.degree(v) == 0]) return st @@ -11083,7 +11084,8 @@ def is_regular(self, k = None): ### Substructures def subgraph(self, vertices=None, edges=None, inplace=False, - vertex_property=None, edge_property=None, algorithm=None): + vertex_property=None, edge_property=None, algorithm=None, + immutable=None): """ Returns the subgraph containing the given vertices and edges. @@ -11124,6 +11126,10 @@ def subgraph(self, vertices=None, edges=None, inplace=False, edges. If not specified, then the algorithm is chosen based on the number of vertices in the subgraph. + - ``immutable`` (boolean) -- whether to create a mutable/immutable + subgraph. ``immutable=None`` (default) means that the graph and its + subgraph will behave the same way. + EXAMPLES:: @@ -11244,12 +11250,14 @@ def subgraph(self, vertices=None, edges=None, inplace=False, if inplace or len(vertices)>0.05*self.order() or algorithm=="delete": return self._subgraph_by_deleting(vertices=vertices, edges=edges, inplace=inplace, - edge_property=edge_property) + edge_property=edge_property, + immutable=immutable) else: return self._subgraph_by_adding(vertices=vertices, edges=edges, - edge_property=edge_property) + edge_property=edge_property, + immutable=immutable) - def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None): + def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, immutable=None): """ Returns the subgraph containing the given vertices and edges. The edges also satisfy the edge_property, if it is not None. @@ -11271,6 +11279,10 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None): to be a function on edges, which is intersected with the edges specified, if any are. + - ``immutable`` (boolean) -- whether to create a mutable/immutable + subgraph. ``immutable=None`` (default) means that the graph and its + subgraph will behave the same way. + EXAMPLES:: @@ -11381,10 +11393,15 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None): value = dict([(v, getattr(self, attr).get(v, None)) for v in G]) setattr(G, attr,value) + if immutable is None: + immutable = getattr(self, '_immutable', False) + if immutable: + G = G.copy(immutable=True) + return G def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, - edge_property=None): + edge_property=None, immutable=None): """ Returns the subgraph containing the given vertices and edges. The edges also satisfy the edge_property, if it is not None. @@ -11410,6 +11427,10 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, delete the extra vertices and edges from the current graph. This will modify the graph. + - ``immutable`` (boolean) -- whether to create a mutable/immutable + subgraph. ``immutable=None`` (default) means that the graph and its + subgraph will behave the same way. + EXAMPLES:: @@ -11531,8 +11552,10 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, G.delete_edges(edges_to_delete) if not inplace: - if getattr(self, '_immutable', False): - return G.copy(immutable=True) + if immutable is None: + immutable = getattr(self, '_immutable', False) + if immutable: + G = G.copy(immutable=True) return G def subgraph_search(self, G, induced=False): From 6a6c1f1c474a92d4c2cd7db4db29189f9244b4b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Tue, 3 Nov 2015 00:56:58 +0100 Subject: [PATCH 1798/1872] Fix to_simple to first make a mutable copy --- src/sage/graphs/generic_graph.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index d6701f6b78c..c7a8db07631 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16423,11 +16423,15 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): [(2, 3, 2), (3, 2, None)] """ if to_undirected: - g=self.to_undirected(immutable=immutable) + g=self.to_undirected(immutable=False) else: - g=self.copy(immutable=immutable) + g=self.copy(immutable=False) g.allow_loops(False) g.allow_multiple_edges(False, keep_label=keep_label) + if immutable is None: + immutable = getattr(self, '_immutable', False) + if immutable: + g = g.copy(immutable=True) return g def disjoint_union(self, other, verbose_relabel=None, labels="pairs"): From 03f63e7ca45fb26969f5259b3987bd27358c74f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Tue, 3 Nov 2015 01:25:50 +0100 Subject: [PATCH 1799/1872] Use mutable copies when graph modifying may occur --- src/sage/graphs/generic_graph.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index c7a8db07631..754ebac2601 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -4239,7 +4239,7 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, # A local copy of self from sage.graphs.planarity import is_planar - graph = self.to_undirected() + graph = self.to_undirected(immutable=False) if hasattr(graph, '_embedding'): del(graph._embedding) @@ -4357,7 +4357,7 @@ def layout_planar(self, set_embedding=False, on_embedding=None, external_face=No """ from sage.graphs.schnyder import _triangulate, _normal_label, _realizer, _compute_coordinates - G = self.to_undirected() + G = self.to_undirected(immutable=False) try: G._embedding = self._embedding except AttributeError: @@ -4626,7 +4626,7 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal if not self.is_connected(): raise TypeError("Graph must be connected to use Euler's Formula to compute minimal genus.") - G = self.to_simple() + G = self.to_simple(immutable=False) verts = G.order() edges = G.size() @@ -8169,7 +8169,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False,ver """ self._scream_if_not_simple(allow_loops=True) from sage.numerical.mip import MixedIntegerLinearProgram - g=self + g=copy(self) p=MixedIntegerLinearProgram(maximization=True, solver = solver) # Adding the intensity if not present @@ -8358,7 +8358,7 @@ def _build_flow_graph(self, flow, integer): g.set_edge_label(u,v, int(round(l))) # returning a graph with the same embedding, the corresponding name, etc ... - h = self.subgraph(edges=[]) + h = self.subgraph(edges=[], immutable=False) h.delete_vertices([v for v in self if (v not in g) or g.degree(v)==0]) h.add_edges(g.edges()) @@ -12386,7 +12386,7 @@ def is_interval(self, certificate = False): # As we will be deleting vertices ... g = copy(self) - for cc in self.connected_components_subgraphs(): + for cc in g.connected_components_subgraphs(): # We pick a perfect elimination order for every connected # component. We will then iteratively take the last vertex From df80be003e837c1bcb05edfcbfc167e1ada2d592 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Tue, 3 Nov 2015 01:55:38 +0100 Subject: [PATCH 1800/1872] and more --- .../finite_dimensional_algebra.py | 3 ++- .../finite_dimensional_algebra_element.py | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 319d20315f3..0905d97a869 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -44,7 +44,8 @@ class FiniteDimensionalAlgebra(UniqueRepresentation, Algebra): - ``assume_associative`` -- (default: ``False``) boolean; if ``True``, then methods requiring associativity assume this - without checking and sets the category as ``category.Associative()`` + without checking, and the category is set to + ``category.Associative()`` - ``category`` -- (default: ``MagmaticAlgebras(k).FiniteDimensional().WithBasis()``) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py index c17d4be8f4c..2b633114115 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.py @@ -366,6 +366,9 @@ def is_invertible(self): Return ``True`` if ``self`` has a two-sided multiplicative inverse. + This assumes that the algebra to which ``self`` belongs is + associative. + .. NOTE:: If an element of a unitary finite-dimensional algebra over a field @@ -388,6 +391,9 @@ def _inverse(self): The two-sided inverse of ``self``, if it exists; otherwise this is ``None``. + This assumes that the algebra to which ``self`` belongs is + associative. + EXAMPLES:: sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) @@ -413,11 +419,14 @@ def inverse(self): Return the two-sided multiplicative inverse of ``self``, if it exists. + This assumes that the algebra to which ``self`` belongs is + associative. + .. NOTE:: - If an element of a unitary finite-dimensional algebra over a field - admits a left inverse, then this is the unique left - inverse, and it is also a right inverse. + If an element of a finite-dimensional unitary associative + algebra over a field admits a left inverse, then this is the + unique left inverse, and it is also a right inverse. EXAMPLES:: From 97d0c13d737251f3b0e9b200ed20bb47bfc54e25 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Mon, 2 Nov 2015 22:44:25 -0500 Subject: [PATCH 1801/1872] remove a few references to choose_nk, move functions in choose_nk.py to combination.py --- src/sage/combinat/choose_nk.py | 107 +++------------------ src/sage/combinat/combination.py | 135 ++++++++++++++++++++++++++- src/sage/combinat/enumerated_sets.py | 1 - src/sage/combinat/subset.py | 12 +-- 4 files changed, 155 insertions(+), 100 deletions(-) diff --git a/src/sage/combinat/choose_nk.py b/src/sage/combinat/choose_nk.py index 7e5da370c1d..2b0420f483e 100644 --- a/src/sage/combinat/choose_nk.py +++ b/src/sage/combinat/choose_nk.py @@ -1,30 +1,6 @@ -""" -Deprecated combinations +# the following functions have been moved to sage.combinat.combination +import sage.combinat.combination as combination -AUTHORS: - -- Mike Hansen (2007): initial implementation - -- Vincent Delecroix (2014): deprecation -""" -#***************************************************************************** -# Copyright (C) 2007 Mike Hansen , -# -# 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.rings.arith import binomial - -#TODO: the following functions are used sage.combinat.combination and -# sage.combinat.subset. It might be good to move them somewhere else. def rank(comb, n, check=True): """ Return the rank of ``comb`` in the subsets of ``range(n)`` of size ``k`` @@ -37,6 +13,8 @@ def rank(comb, n, check=True): sage: import sage.combinat.choose_nk as choose_nk sage: choose_nk.rank((), 3) + doctest:1: DeprecationWarning: choose_nk.rank is deprecated and will be removed. Use combination.rank instead + See http://trac.sagemath.org/18674 for details. 0 sage: choose_nk.rank((0,), 3) 0 @@ -67,55 +45,14 @@ def rank(comb, n, check=True): sage: choose_nk.rank([0,1,2], 3) 0 """ - k = len(comb) - if check: - if k > n: - raise ValueError("len(comb) must be <= n") - comb = [int(_) for _ in comb] - for i in xrange(k - 1): - if comb[i + 1] <= comb[i]: - raise ValueError("comb must be a subword of (0,1,...,n)") - - #Generate the combinadic from the - #combination - - #w = [n-1-comb[i] for i in xrange(k)] - - #Calculate the integer that is the dual of - #the lexicographic index of the combination - r = k - t = 0 - for i in range(k): - t += binomial(n - 1 - comb[i], r) - r -= 1 - - return binomial(n,k)-t-1 - - - -def _comb_largest(a,b,x): - """ - Returns the largest w < a such that binomial(w,b) <= x. - - EXAMPLES:: - - sage: from sage.combinat.choose_nk import _comb_largest - sage: _comb_largest(6,3,10) - 5 - sage: _comb_largest(6,3,5) - 4 - """ - w = a - 1 - - while binomial(w,b) > x: - w -= 1 - - return w + from sage.misc.superseded import deprecation + deprecation(18674, "choose_nk.rank is deprecated and will be removed. Use combination.rank instead") + return combination.rank(comb, n, check) def from_rank(r, n, k): - """ - Returns the combination of rank r in the subsets of range(n) of - size k when listed in lexicographic order. + r""" + Returns the combination of rank ``r`` in the subsets of ``range(n)`` of + size ``k`` when listed in lexicographic order. The algorithm used is based on combinadics and James McCaffrey's MSDN article. See: http://en.wikipedia.org/wiki/Combinadic @@ -124,6 +61,8 @@ def from_rank(r, n, k): sage: import sage.combinat.choose_nk as choose_nk sage: choose_nk.from_rank(0,3,0) + doctest:1: DeprecationWarning: choose_nk.from_rank is deprecated and will be removed. Use combination.from_rank instead + See http://trac.sagemath.org/18674 for details. () sage: choose_nk.from_rank(0,3,1) (0,) @@ -140,23 +79,7 @@ def from_rank(r, n, k): sage: choose_nk.from_rank(0,3,3) (0, 1, 2) """ - if k < 0: - raise ValueError("k must be > 0") - if k > n: - raise ValueError("k must be <= n") - - a = n - b = k - x = binomial(n, k) - 1 - r # x is the 'dual' of m - comb = [None] * k - - for i in xrange(k): - comb[i] = _comb_largest(a, b, x) - x = x - binomial(comb[i], b) - a = comb[i] - b = b - 1 - - for i in xrange(k): - comb[i] = (n - 1) - comb[i] + from sage.misc.superseded import deprecation + deprecation(18674, "choose_nk.from_rank is deprecated and will be removed. Use combination.from_rank instead") + return combination.from_rank(r, n, k) - return tuple(comb) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index e72bce63ae7..9b1680f2302 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -27,7 +27,6 @@ from sage.rings.all import ZZ, Integer from sage.rings.arith import binomial from combinat import CombinatorialClass -from choose_nk import rank, from_rank from integer_vector import IntegerVectors from sage.misc.misc import uniq @@ -466,6 +465,140 @@ def rank(self, x): return rank(x, len(self.mset)) +def rank(comb, n, check=True): + """ + Return the rank of ``comb`` in the subsets of ``range(n)`` of size ``k`` + where ``k`` is the length of ``comb``. + + The algorithm used is based on combinadics and James McCaffrey's + MSDN article. See: :wikipedia:`Combinadic`. + + EXAMPLES:: + + sage: import sage.combinat.combination as combination + sage: combination.rank((), 3) + 0 + sage: combination.rank((0,), 3) + 0 + sage: combination.rank((1,), 3) + 1 + sage: combination.rank((2,), 3) + 2 + sage: combination.rank((0,1), 3) + 0 + sage: combination.rank((0,2), 3) + 1 + sage: combination.rank((1,2), 3) + 2 + sage: combination.rank((0,1,2), 3) + 0 + + sage: combination.rank((0,1,2,3), 3) + Traceback (most recent call last): + ... + ValueError: len(comb) must be <= n + sage: combination.rank((0,0), 2) + Traceback (most recent call last): + ... + ValueError: comb must be a subword of (0,1,...,n) + + sage: combination.rank([1,2], 3) + 2 + sage: combination.rank([0,1,2], 3) + 0 + """ + k = len(comb) + if check: + if k > n: + raise ValueError("len(comb) must be <= n") + comb = [int(_) for _ in comb] + for i in xrange(k - 1): + if comb[i + 1] <= comb[i]: + raise ValueError("comb must be a subword of (0,1,...,n)") + + #Generate the combinadic from the + #combination + + #w = [n-1-comb[i] for i in xrange(k)] + + #Calculate the integer that is the dual of + #the lexicographic index of the combination + r = k + t = 0 + for i in range(k): + t += binomial(n - 1 - comb[i], r) + r -= 1 + + return binomial(n,k)-t-1 + +def _comb_largest(a,b,x): + r""" + Returns the largest `w < a` such that `binomial(w,b) <= x`. + + EXAMPLES:: + + sage: from sage.combinat.combination import _comb_largest + sage: _comb_largest(6,3,10) + 5 + sage: _comb_largest(6,3,5) + 4 + """ + w = a - 1 + + while binomial(w,b) > x: + w -= 1 + + return w + +def from_rank(r, n, k): + r""" + Returns the combination of rank ``r`` in the subsets of + ``range(n)`` of size ``k`` when listed in lexicographic order. + + The algorithm used is based on combinadics and James McCaffrey's + MSDN article. See: :wikipedia:`Combinadic` + + EXAMPLES:: + + sage: import sage.combinat.combination as combination + sage: combination.from_rank(0,3,0) + () + sage: combination.from_rank(0,3,1) + (0,) + sage: combination.from_rank(1,3,1) + (1,) + sage: combination.from_rank(2,3,1) + (2,) + sage: combination.from_rank(0,3,2) + (0, 1) + sage: combination.from_rank(1,3,2) + (0, 2) + sage: combination.from_rank(2,3,2) + (1, 2) + sage: combination.from_rank(0,3,3) + (0, 1, 2) + """ + if k < 0: + raise ValueError("k must be > 0") + if k > n: + raise ValueError("k must be <= n") + + a = n + b = k + x = binomial(n, k) - 1 - r # x is the 'dual' of m + comb = [None] * k + + for i in xrange(k): + comb[i] = _comb_largest(a, b, x) + x = x - binomial(comb[i], b) + a = comb[i] + b = b - 1 + + for i in xrange(k): + comb[i] = (n - 1) - comb[i] + + return tuple(comb) + ########################################################## # Deprecations diff --git a/src/sage/combinat/enumerated_sets.py b/src/sage/combinat/enumerated_sets.py index 291e861e286..7aeb4054a15 100644 --- a/src/sage/combinat/enumerated_sets.py +++ b/src/sage/combinat/enumerated_sets.py @@ -130,7 +130,6 @@ ------------------------- - :ref:`sage.combinat.permutation_nk` -- :ref:`sage.combinat.choose_nk` - :ref:`sage.combinat.multichoose_nk` - :ref:`sage.combinat.gray_codes` diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index 39aff81e561..7e7cb32b201 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -41,7 +41,7 @@ from sage.rings.arith import binomial from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer -import choose_nk +import combination ZZ_0 = ZZ.zero() @@ -438,7 +438,7 @@ def rank(self, sub): n = self._s.cardinality() r = sum(binomial(n,i) for i in xrange(len(index_list))) - return r + choose_nk.rank(index_list,n) + return r + combination.rank(index_list,n) def unrank(self, r): """ @@ -467,7 +467,7 @@ def unrank(self, r): r -= bin k += 1 bin = binomial(n,k) - return self.element_class([self._s.unrank(i) for i in choose_nk.from_rank(r, n, k)]) + return self.element_class([self._s.unrank(i) for i in combination.from_rank(r, n, k)]) def __call__(self, el): r""" @@ -769,7 +769,7 @@ def rank(self, sub): raise ValueError("{} is not a subset of length {} of {}".format( sub, self._k, self._s)) - return choose_nk.rank(index_list, n) + return combination.rank(index_list, n) def unrank(self, r): """ @@ -792,7 +792,7 @@ def unrank(self, r): if self._k > n or r >= self.cardinality() or r < 0: raise IndexError("index out of range") else: - return self.element_class([lset[i] for i in choose_nk.from_rank(r, n, self._k)]) + return self.element_class([lset[i] for i in combination.from_rank(r, n, self._k)]) def an_element(self): """ @@ -1346,7 +1346,7 @@ def unrank(self, r): r -= binom k += 1 binom = binomial(n,k) - C = choose_nk.from_rank(r, n, k) + C = combination.from_rank(r, n, k) return self.element_class(sorted([self._s.unrank(i) for i in C])) def _an_element_(self): From bca35ddbb8d6518535b43e32ec34514fcd0ab8c8 Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Mon, 2 Nov 2015 23:48:12 -0500 Subject: [PATCH 1802/1872] 19512: is_morphism implementation --- .../schemes/product_projective/morphism.py | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/sage/schemes/product_projective/morphism.py b/src/sage/schemes/product_projective/morphism.py index 6e30ba6afea..c5f90f7121c 100644 --- a/src/sage/schemes/product_projective/morphism.py +++ b/src/sage/schemes/product_projective/morphism.py @@ -20,6 +20,7 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.categories.homset import Hom from sage.schemes.generic.morphism import SchemeMorphism_polynomial @@ -164,3 +165,58 @@ def __call__(self, P, check = True): Q = P[0]._coords + P[1]._coords newP = [f(Q) for f in self.defining_polynomials()] return(A.point(newP, check)) + + def is_morphism(self): + r""" + Returns ``True`` if ``self`` is a morphism of products of projective spaces. This is determined by checking + that the coordinates of ``self`` corresponding to each component space have no common zeros. + + OUTPUT: + + - Boolean + + EXAMPLES:: + + sage: Z. = ProductProjectiveSpaces([1,2],QQ) + sage: H = Hom(Z,Z) + sage: f = H([a^2,b^2,x*z-y*z,x^2-y^2,z^2]) + sage: f.is_morphism() + False + + :: + + sage: Z. = ProductProjectiveSpaces([2,2],CC) + sage: H = Hom(Z,Z) + sage: f = H([a^3-a*b*c,b^3,c^3,x^2,x^2+y^2,CC.0*z^2]) + sage: f.is_morphism() + True + """ + Z = self.domain().ambient_space() + counter = 0 + for t in range(Z.num_components()): + M = Z.dimension_relative_components()[t] + 1 + R = Z._components[t].coordinate_ring() + F = [self._polys[k] for k in range(counter,M+counter)] + H = Hom(Z.coordinate_ring(),R) + l = [] + for i in range(0,len(Z.coordinate_ring().gens())): + if i in range(counter, M+counter): + l.append(R.gens()[i-counter]) + else: + l.append(R(0)) + phi = H(l) + F = [phi(f) for f in F] + + defpolys = list(Z._components[t].defining_polynomials()) + if R.base_ring().is_field(): + F.extend(defpolys) + J = R.ideal(F) + else: + S = PolynomialRing(R.base_ring().fraction_field(), R.gens(), R.ngens()) + L = [S(f) for f in F] + [S(f) for f in defpolys] + J = S.ideal(L) + if J.dimension() > 0: + return False + counter = counter + M + + return True \ No newline at end of file From 68c34ab4f5e824c8aea07dfff3e74f6dec40e397 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 2 Nov 2015 23:06:27 -0600 Subject: [PATCH 1803/1872] Trying to get the right phrasing. --- .../finite_dimensional_algebra.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 0905d97a869..b4bd83fa997 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -43,9 +43,8 @@ class FiniteDimensionalAlgebra(UniqueRepresentation, Algebra): elements - ``assume_associative`` -- (default: ``False``) boolean; if - ``True``, then methods requiring associativity assume this - without checking, and the category is set to - ``category.Associative()`` + ``True``, then the category is set to ``category.Associative()`` + and methods requiring associativity assume this - ``category`` -- (default: ``MagmaticAlgebras(k).FiniteDimensional().WithBasis()``) From 039e8f93f312c0445d8f9bd1cf0c7b8c9670d933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Tue, 3 Nov 2015 10:28:26 +0100 Subject: [PATCH 1804/1872] Add parameter immutable to functions union, disjoint_union and join --- src/sage/graphs/generic_graph.py | 26 ++++++++++++++++++++------ src/sage/graphs/graph.py | 14 ++++++++++++-- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 754ebac2601..daacfdf5597 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16434,7 +16434,8 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): g = g.copy(immutable=True) return g - def disjoint_union(self, other, verbose_relabel=None, labels="pairs"): + def disjoint_union(self, other, verbose_relabel=None, labels="pairs", + immutable=None): """ Return the disjoint union of self and other. @@ -16448,6 +16449,10 @@ def disjoint_union(self, other, verbose_relabel=None, labels="pairs"): the result. If set to 'integers', the elements of the result will be relabeled with consecutive integers. + - ``immutable`` (boolean) -- whether to create a mutable/immutable + disjoint union. ``immutable=None`` (default) means that the graphs + and their disjoint union will behave the same way. + .. SEEALSO:: * :meth:`~sage.graphs.generic_graph.GenericGraph.union` @@ -16498,16 +16503,16 @@ def disjoint_union(self, other, verbose_relabel=None, labels="pairs"): r_self[v] = i; i += 1 for v in other: r_other[v] = i; i += 1 - G = self.relabel(r_self, inplace=False).union(other.relabel(r_other, inplace=False)) + G = self.relabel(r_self, inplace=False).union(other.relabel(r_other, inplace=False), immutable=immutable) else: r_self = dict([[v,(0,v)] for v in self]) r_other = dict([[v,(1,v)] for v in other]) - G = self.relabel(r_self, inplace=False).union(other.relabel(r_other, inplace=False)) + G = self.relabel(r_self, inplace=False).union(other.relabel(r_other, inplace=False), immutable=immutable) G._name = '%s disjoint_union %s'%(self.name(), other.name()) return G - def union(self, other): + def union(self, other, immutable=None): """ Returns the union of self and other. @@ -16517,7 +16522,14 @@ def union(self, other): If one of the two graphs allows loops (or multiple edges), the resulting graph will allow loops (or multiple edges). - If both graphs are immutable, the resulting graph is immutable. + If both graphs are immutable, the resulting graph is immutable, unless + requested otherwise. + + INPUT: + + - ``immutable`` (boolean) -- whether to create a mutable/immutable + union. ``immutable=None`` (default) means that the graphs and their + union will behave the same way. .. SEEALSO:: @@ -16574,7 +16586,9 @@ def union(self, other): G.add_edges(self.edges()) G.add_edges(other.edges()) - if getattr(self, "_immutable", False) and getattr(other, "_immutable", False): + if immutable is None: + immutable = getattr(self, "_immutable", False) and getattr(other, "_immutable", False) + if immutable: G = G.copy(immutable=True) return G diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index bf687559da2..cb7f3a3de8f 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4924,7 +4924,7 @@ def to_undirected(self, immutable=None): """ return self.copy(immutable=immutable) - def join(self, other, verbose_relabel=None, labels="pairs"): + def join(self, other, verbose_relabel=None, labels="pairs", immutable=None): """ Returns the join of ``self`` and ``other``. @@ -4938,6 +4938,10 @@ def join(self, other, verbose_relabel=None, labels="pairs"): the result. If set to 'integers', the elements of the result will be relabeled with consecutive integers. + - ``immutable`` (boolean) -- whether to create a mutable/immutable + join. ``immutable=None`` (default) means that the graphs and their + join will behave the same way. + .. SEEALSO:: * :meth:`~sage.graphs.generic_graph.GenericGraph.union` @@ -4981,7 +4985,7 @@ def join(self, other, verbose_relabel=None, labels="pairs"): if verbose_relabel is False: labels="integers" - G = self.disjoint_union(other, labels=labels) + G = self.disjoint_union(other, labels=labels, immutable=False) if labels=="integers": G.add_edges((u,v) for u in range(self.order()) for v in range(self.order(), self.order()+other.order())) @@ -4990,6 +4994,12 @@ def join(self, other, verbose_relabel=None, labels="pairs"): for v in other.vertices()) G.name('%s join %s'%(self.name(), other.name())) + + if immutable is None: + immutable = getattr(self, "_immutable", False) and getattr(other, "_immutable", False) + if immutable: + G = G.copy(immutable=True) + return G From cccfb2bc0f82458eaf33d401adafc78c48922140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Tue, 3 Nov 2015 10:52:19 +0100 Subject: [PATCH 1805/1872] Use mutable copies and subgraphs when they might be modified --- src/sage/graphs/graph.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index cb7f3a3de8f..0704bdf0cb4 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1919,7 +1919,11 @@ def _recursive_spanning_trees(G,forest): forest = Graph([]) forest.add_vertices(self.vertices()) forest.add_edges(self.bridges()) - return _recursive_spanning_trees(self, forest) + if getattr(self, "_immutable", False): + G = copy(self) + else: + G = self + return _recursive_spanning_trees(G, forest) else: return [] @@ -5069,7 +5073,7 @@ def seidel_switching(self, s, inplace=True): True """ from itertools import product - G = self if inplace else self.copy() + G = self if inplace else copy(self) boundary = self.edge_boundary(s) G.add_edges(product(s, set(self).difference(s))) G.delete_edges(boundary) @@ -5366,7 +5370,7 @@ def topological_minor(self, H, vertices = False, paths = False, solver=None, ver return False - minor = G.subgraph() + minor = G.subgraph(immutable=False) is_repr = p.get_values(is_repr) v_repr = p.get_values(v_repr) @@ -6680,7 +6684,7 @@ def _gomory_hu_tree(self, vertices, method="FF"): flow,edges,[U,V] = self.edge_cut(u, v, use_edge_labels=True, vertices=True, method=method) # One graph for each part of the previous one - gU,gV = self.subgraph(U), self.subgraph(V) + gU,gV = self.subgraph(U, immutable=False), self.subgraph(V, immutable=False) # A fake vertex fU (resp. fV) to represent U (resp. V) fU = frozenset(U) From 6ca04d72133d23e16d71d134cc52039c0867fd3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Tue, 3 Nov 2015 11:01:38 +0100 Subject: [PATCH 1806/1872] Fix tutte_polynomial to make a copy of an immutable graph --- src/sage/graphs/tutte_polynomial.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 2bc77eb28a8..76719ecca2c 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -584,7 +584,11 @@ def tutte_polynomial(G, edge_selector=None, cache=None): if G.num_edges() == 0: return R.one() - G = G.relabel(inplace=False) # making sure the vertices are integers + if getattr(G, "_immutable", False): + G = G.copy(immutable=False) + G.relabel(inplace=True) + else: + G = G.relabel(inplace=False) # making sure the vertices are integers G.allow_loops(True) G.allow_multiple_edges(True) From e7f99be6ecd3a50518fe9e060f5fabf177d65003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Tue, 3 Nov 2015 11:11:29 +0100 Subject: [PATCH 1807/1872] Fix is_long_(anti)hole_free to make a copy of an immutable graph --- src/sage/graphs/weakly_chordal.pyx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/graphs/weakly_chordal.pyx b/src/sage/graphs/weakly_chordal.pyx index 9f971a3b982..6398d1510e3 100644 --- a/src/sage/graphs/weakly_chordal.pyx +++ b/src/sage/graphs/weakly_chordal.pyx @@ -110,6 +110,9 @@ def is_long_hole_free(g, certificate=False): g._scream_if_not_simple() cdef int a,b,c,i,u,v,d + if getattr(g, "_immutable", False): + g = g.copy(immutable=False) + # relabel the graph on 0...n-1 cdef dict label_id = g.relabel(return_map = True) cdef dict id_label = {idd:label for label, idd in label_id.iteritems()} @@ -279,6 +282,9 @@ def is_long_antihole_free(g, certificate = False): g._scream_if_not_simple() cdef int a,b,c,i,u,v,d + if getattr(g, "_immutable", False): + g = g.copy(immutable=False) + # relabel the graph on 0...n-1 cdef dict label_id = g.relabel(return_map = True) cdef dict id_label = {idd:label for label, idd in label_id.iteritems()} From 8d1ae9f0a1b9479a4acef00d0a778230cb7dcba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 3 Nov 2015 12:10:07 +0100 Subject: [PATCH 1808/1872] trac #19514 better hash for UCF elements --- src/sage/rings/universal_cyclotomic_field.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index 8373d8e7dde..d4751177d3b 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -533,15 +533,24 @@ def __hash__(self): sage: UCF = UniversalCyclotomicField() sage: hash(UCF.zero()) # indirect doctest - 1302034650 # 32-bit - 3713081631936575706 # 64-bit + 0 sage: hash(UCF.gen(3,2)) 313156239 # 32-bit 1524600308199219855 # 64-bit + + TESTS: + + See :trac:`19514`:: + + sage: hash(UCF.one()) + 1 """ k = self._obj.Conductor().sage() coeffs = self._obj.CoeffsCyc(k).sage() - return hash((k,) + tuple(coeffs)) + if k == 1: + return hash(coeffs[0]) + else: + return hash((k,) + tuple(coeffs)) def _algebraic_(self, R): r""" From ebba4ece62fde88459e50417f233c2c4f5c94263 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 3 Nov 2015 06:25:27 -0500 Subject: [PATCH 1809/1872] following Travis's comment replace :1: --- src/sage/combinat/choose_nk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/choose_nk.py b/src/sage/combinat/choose_nk.py index 2b0420f483e..285c954b4f9 100644 --- a/src/sage/combinat/choose_nk.py +++ b/src/sage/combinat/choose_nk.py @@ -13,7 +13,7 @@ def rank(comb, n, check=True): sage: import sage.combinat.choose_nk as choose_nk sage: choose_nk.rank((), 3) - doctest:1: DeprecationWarning: choose_nk.rank is deprecated and will be removed. Use combination.rank instead + doctest:...: DeprecationWarning: choose_nk.rank is deprecated and will be removed. Use combination.rank instead See http://trac.sagemath.org/18674 for details. 0 sage: choose_nk.rank((0,), 3) @@ -61,7 +61,7 @@ def from_rank(r, n, k): sage: import sage.combinat.choose_nk as choose_nk sage: choose_nk.from_rank(0,3,0) - doctest:1: DeprecationWarning: choose_nk.from_rank is deprecated and will be removed. Use combination.from_rank instead + doctest:...: DeprecationWarning: choose_nk.from_rank is deprecated and will be removed. Use combination.from_rank instead See http://trac.sagemath.org/18674 for details. () sage: choose_nk.from_rank(0,3,1) From 93348b31df8eaa8575e37a9cc447c891cbdc9c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Tue, 3 Nov 2015 20:04:04 +0100 Subject: [PATCH 1810/1872] Remove the superfluous copy in multicommodity_flow This fixes GraphZOO/GraphZOO#3. --- 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 daacfdf5597..1d880e1d79c 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8169,7 +8169,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False,ver """ self._scream_if_not_simple(allow_loops=True) from sage.numerical.mip import MixedIntegerLinearProgram - g=copy(self) + g=self p=MixedIntegerLinearProgram(maximization=True, solver = solver) # Adding the intensity if not present From 7e3dd2456524efbce5fdf447a59ad8918ce59858 Mon Sep 17 00:00:00 2001 From: Jonas Jermann Date: Tue, 3 Nov 2015 23:32:12 +0100 Subject: [PATCH 1811/1872] improvements according to comments from tscrim, enable _act_on for HyperbolicPlane(), allow to specify the model for isometries --- .../graded_ring_element.py | 4 +- .../hecke_triangle_group_element.py | 50 +++++++++++++------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index 4fc191f4140..3bd9602624e 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -2082,9 +2082,7 @@ def evaluate(self, tau, prec = None, num_prec = None, check=False): sage: (f.q_expansion_fixed_d().polynomial())(exp((2*pi*i).n(1000)*az/G.lam())) # long time -140.471170232432551196978... + 469.079369280804086032719...*I - It is possible to evaluate at points of ``HyperbolicPlane()``: - - :: + It is possible to evaluate at points of ``HyperbolicPlane()``:: sage: p = HyperbolicPlane().PD().get_point(-I/2) sage: bool(p.to_model('UHP').coordinates() == I/3) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index 2e05fea4009..569ba54a5a7 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -23,6 +23,7 @@ from sage.rings.all import AA, QQbar, ZZ, infinity from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic +from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane # We want to simplify p after the coercion (pari bug for AA) @@ -3141,10 +3142,6 @@ def acton(self, tau): return self*tau*self.inverse() # if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model - # TODO: Make it possible to interpret elements as isometries of the HyperbolicPlane - # and possibly use/implement actions using the HyperbolicPlane model - from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane - model = None if (tau in HyperbolicPlane()): model = tau.model() @@ -3167,10 +3164,33 @@ def acton(self, tau): else: return HyperbolicPlane().UHP().get_point(result).to_model(model) - # def _act_on_(self, other, self_on_left): - # TODO: implement default actions for "suitable" other - # if (self_on_left): - # return self.acton(other) + # TODO: extend the action to more general settings, e.g. try if other coerces into HyperbolicPlane() + # Note however that the group also acts on itself by conjugation. So it's not completely clear + # what exactly should be the default action... + def _act_on_(self, other, self_on_left): + r""" + Defines what Hecke triangle group elements act on using :meth:`acton`. + For now only the action on HyperbolicPlane() is enabled. + + EXAMPLES:: + + sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup + sage: G = HeckeTriangleGroup(5) + sage: p = HyperbolicPlane().PD().get_point(I) + sage: G.U()*p + Boundary point in PD 1/2*(sqrt(5) - 2*I + 1)/(-1/2*I*sqrt(5) - 1/2*I + 1) + sage: G.S()*G.U()*p == G.S()*(G.U()*p) + True + sage: G.S()*G.U()*p == (G.S()*G.U())*p + True + sage: (G.S()*G.U())*p == G.S()*(G.U()*p) + True + """ + + if (self_on_left): + if (other in HyperbolicPlane()): + return self.acton(other) + return None def slash(self, f, tau=None, k=None): r""" @@ -3256,14 +3276,12 @@ def slash(self, f, tau=None, k=None): except (ValueError, TypeError, AttributeError): raise ValueError("f={} is not a rational function or a polynomial in one variable, so tau has to be specfied explicitely!".format(f)) - from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane - if (tau in HyperbolicPlane()): tau = tau.to_model('UHP').coordinates() return (self.c()*tau + self.d())**(-k) * f(self.acton(tau)) - def as_isometry(self): + def as_hyperbolic_plane_isometry(self, model="UHP"): r""" Return ``self`` as an isometry of ``HyperbolicPlane()`` (in the upper half plane model). @@ -3271,14 +3289,14 @@ def as_isometry(self): sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup sage: el = HeckeTriangleGroup(7).V(4) - sage: el.as_isometry() + sage: el.as_hyperbolic_plane_isometry() Isometry in UHP [lam^2 - 1 lam] [lam^2 - 1 lam^2 - 1] - sage: el.as_isometry().parent() + sage: el.as_hyperbolic_plane_isometry().parent() Set of Morphisms from Hyperbolic plane in the Upper Half Plane Model model to Hyperbolic plane in the Upper Half Plane Model model in Category of hyperbolic models of Hyperbolic plane + sage: el.as_hyperbolic_plane_isometry("KM").parent() + Set of Morphisms from Hyperbolic plane in the Klein Disk Model model to Hyperbolic plane in the Klein Disk Model model in Category of hyperbolic models of Hyperbolic plane """ - from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane - - return HyperbolicPlane().UHP().get_isometry(self.matrix()) + return HyperbolicPlane().UHP().get_isometry(self.matrix()).to_model(model) From 89f0878a41bbe4b7a68c11dd5d00efa6f7ad7950 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 4 Nov 2015 09:16:31 -0300 Subject: [PATCH 1812/1872] Trac 19494: faster nb_subword_occurrences_in --- src/sage/combinat/words/finite_word.py | 83 +++++++++++++++++--------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 072662e5732..9beac17bdf4 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -4245,39 +4245,66 @@ def nb_subword_occurrences_in(self, other): r""" Returns the number of times self appears in other as a subword. + This corresponds to the notion of `binomial coefficient` of two + finite words whose properties are presented in the chapter of + Lothaire's book written by Sakarovitch and Simon [1]. + + INPUT: + + - ``other`` -- finite word + EXAMPLES:: - sage: Word().nb_subword_occurrences_in(Word('123')) - Traceback (most recent call last): - ... - NotImplementedError: undefined value - sage: Word('123').nb_subword_occurrences_in(Word('1133432311132311112')) + sage: u = words.ThueMorseWord()[:1000] + sage: w = Word([0,1,0,1]) + sage: w.nb_subword_occurrences_in(u) + 2604124996 + + TESTS:: + + sage: v,u = Word(), Word('123') + sage: v.nb_subword_occurrences_in(u) + 1 + sage: v,u = Word('123'), Word('1133432311132311112') + sage: v.nb_subword_occurrences_in(u) 11 - sage: Word('4321').nb_subword_occurrences_in(Word('1132231112233212342231112')) + sage: v,u = Word('4321'), Word('1132231112233212342231112') + sage: v.nb_subword_occurrences_in(u) 0 - sage: Word('3').nb_subword_occurrences_in(Word('122332112321213')) + sage: v,u = Word('3'), Word('122332112321213') + sage: v.nb_subword_occurrences_in(u) 4 - """ - ls = self.length() - if ls == 0: - raise NotImplementedError("undefined value") - elif ls == 1: - return self.nb_factor_occurrences_in(other) - elif len(other) < ls: - return 0 - symb = self[:1] - suffword = other - suffsm = self[1:] - n = 0 - cpt = 0 - i = symb.first_pos_in(suffword) - while i is not None: - suffword = suffword[i+1:] - m = suffsm.nb_subword_occurrences_in(suffword) - if m == 0: break - n += m - i = symb.first_pos_in(suffword) - return n + sage: v,u = Word([]), words.ThueMorseWord()[:1000] + sage: v.nb_subword_occurrences_in(u) + 1 + + REFERENCES: + + - [1] M. Lothaire, Combinatorics on Words, Cambridge University + Press, (1997). + - [2] Mateescu, A., Salomaa, A., Salomaa, K. and Yu, S., A + sharpening of the Parikh mapping. Theoret. Informatics Appl. 35 + (2001) 551-564. + """ + # record the position of letters in self + pos = {} + for i,a in enumerate(self): + if a in pos: + pos[a].append(i) + else: + pos[a] = [i] + + # compute the occurrences of all prefixes of self as subwords in other + occ = [0] * (len(self)+1) + occ[0] = 1 + for a in other: + l = pos.get(a) + if l is not None: + for i in l: + occ[i+1] += occ[i] + + # return only the number of occurrences of self + return occ[-1] def _return_words_list(self, fact): r""" From 5524971c04d75c7f85ad0e801ac865868090d5fe Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 4 Nov 2015 15:56:08 +0100 Subject: [PATCH 1813/1872] Fix random beta() doctest --- src/sage/functions/other.py | 7 +++---- src/sage/symbolic/ginac.pxd | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 081ba6f731f..9b7da16b67c 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1688,11 +1688,10 @@ def __init__(self): sage: beta(3,x+I) beta(3, x + I) - Note that the order of arguments does not matter:: + Ginac might reorder the arguments:: - sage: beta(1/2, 3*x) - beta(3*x, 1/2) # 32-bit - beta(1/2, 3*x) # 64-bit + sage: beta(1/3, 1/2) + beta(1/2, 1/3) The result is symbolic if exact input is given:: diff --git a/src/sage/symbolic/ginac.pxd b/src/sage/symbolic/ginac.pxd index 95b10bb44e3..917a6a17235 100644 --- a/src/sage/symbolic/ginac.pxd +++ b/src/sage/symbolic/ginac.pxd @@ -355,7 +355,7 @@ cdef extern from "sage/symbolic/ginac_wrap.h": GEx g_zetaderiv "GiNaC::zetaderiv" (GEx n, GEx x) except + # derivatives of Riemann's zeta function GEx g_tgamma "GiNaC::tgamma" (GEx x) except + # gamma function GEx g_lgamma "GiNaC::lgamma" (GEx x) except + # logarithm of gamma function - GEx g_beta "GiNaC::beta" (GEx x, GEx y) except + # beta function (tgamma*tgamma(y)/tgamma(x+y)) + GEx g_beta "GiNaC::beta" (GEx x, GEx y) except + # beta function (tgamma(x)*tgamma(y)/tgamma(x+y)) GEx g_psi "GiNaC::psi" (GEx x) except + # psi (digamma) function GEx g_psi2 "GiNaC::psi" (GEx n, GEx x) except + # derivatives of psi function (polygamma functions) GEx g_factorial "GiNaC::factorial" (GEx n) except + # factorial function n! @@ -458,7 +458,7 @@ cdef extern from "sage/symbolic/ginac_wrap.h": unsigned zetaderiv_serial "GiNaC::zetaderiv_SERIAL::serial" # derivatives of Riemann's zeta function unsigned tgamma_serial "GiNaC::tgamma_SERIAL::serial" # gamma function unsigned lgamma_serial "GiNaC::lgamma_SERIAL::serial" # logarithm of gamma function - unsigned beta_serial "GiNaC::beta_SERIAL::serial" # beta function (tgamma*tgamma(y)/tgamma(x+y)) + unsigned beta_serial "GiNaC::beta_SERIAL::serial" # beta function (tgamma(x)*tgamma(y)/tgamma(x+y)) unsigned psi_serial "GiNaC::psi_SERIAL::serial" # psi (digamma) function #unsigned psi2_serial "GiNaC::psi_SERIAL::serial" # derivatives of psi function (polygamma functions) unsigned factorial_serial "GiNaC::factorial_SERIAL::serial" # factorial function n! From bb091596d543140f5077e05698b2f18e4711bddd Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 4 Nov 2015 16:32:02 +0100 Subject: [PATCH 1814/1872] Change doctest for Integers(is_field=True) to use an unused ring --- .../rings/finite_rings/integer_mod_ring.py | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index 9388bec34c2..8ab0fa50415 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -50,20 +50,12 @@ """ #***************************************************************************** -# -# Sage: System for Algebra and Geometry Experimentation -# # Copyright (C) 2005 William Stein # -# 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: -# +# 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/ #***************************************************************************** @@ -169,7 +161,7 @@ class IntegerModFactory(UniqueFactory): EXAMPLES:: - sage: R = IntegerModRing(15, is_field=True) + sage: R = IntegerModRing(33, is_field=True) sage: R in Fields() True sage: R.is_field() @@ -182,7 +174,7 @@ class IntegerModFactory(UniqueFactory): Traceback (most recent call last): ... ValueError: THIS SAGE SESSION MIGHT BE SERIOUSLY COMPROMISED! - The order 15 is not prime, but this ring has been put + The order 33 is not prime, but this ring has been put into the category of fields. This may already have consequences in other parts of Sage. Either it was a mistake of the user, or a probabilitstic primality test has failed. @@ -1568,17 +1560,6 @@ def degree(self): from sage.structure.sage_object import register_unpickle_override register_unpickle_override('sage.rings.integer_mod_ring', 'IntegerModRing_generic', IntegerModRing_generic) -## def GF(p): -## """ -## EXAMPLES: -## sage: F = GF(11) -## sage: F -## Finite field of size 11 -## """ -## if not arith.is_prime(p): -## raise NotImplementedError("only prime fields currently implemented") -## return IntegerModRing(p) - def crt(v): """ INPUT: From bcef7f315975b6ca471615ba3d0e467a250886ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 4 Nov 2015 16:58:57 +0100 Subject: [PATCH 1815/1872] correcting a few bad trac roles --- src/sage/libs/cremona/newforms.pyx | 2 +- src/sage/rings/number_field/number_field.py | 2 +- src/sage/schemes/elliptic_curves/ell_local_data.py | 2 +- src/sage/schemes/elliptic_curves/padic_lseries.py | 4 ++-- src/sage/schemes/elliptic_curves/sha_tate.py | 4 ++-- src/sage/schemes/generic/morphism.py | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/libs/cremona/newforms.pyx b/src/sage/libs/cremona/newforms.pyx index 93f9bc95f9e..9f6877fb225 100644 --- a/src/sage/libs/cremona/newforms.pyx +++ b/src/sage/libs/cremona/newforms.pyx @@ -147,7 +147,7 @@ cdef class ECModularSymbol: sage: [M(1/i) for i in range(1,10)] [0, 0, 0, 0, 4, 0, 2, 0, -2] - TESTS (see :trac: `11211`):: + TESTS (see :trac:`11211`):: sage: from sage.libs.cremona.newforms import ECModularSymbol sage: E = EllipticCurve('11a') diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 6c8a835fcc2..73e1ebee1ac 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -7177,7 +7177,7 @@ def _subfields_helper(self, degree=0, name=None, both_maps=True, optimize=False) sage: L2, _, _ = K.subfields(2)[0]; L2, CDF(L2.gen()) # indirect doctest (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312721) - Test for :trac: `7695`:: + Test for :trac:`7695`:: sage: F = CyclotomicField(7) sage: K = F.subfields(3)[0][0] diff --git a/src/sage/schemes/elliptic_curves/ell_local_data.py b/src/sage/schemes/elliptic_curves/ell_local_data.py index 5dd59f12ab2..da434fe9c83 100644 --- a/src/sage/schemes/elliptic_curves/ell_local_data.py +++ b/src/sage/schemes/elliptic_curves/ell_local_data.py @@ -705,7 +705,7 @@ def _tate(self, proof = None, globally = False): sage: E.tamagawa_number(K.ideal(2)) 4 - This is to show that the bug :trac: `11630` is fixed. (The computation of the class group would produce a warning):: + This is to show that the bug :trac:`11630` is fixed. (The computation of the class group would produce a warning):: sage: K. = NumberField(x^7-2*x+177) sage: E = EllipticCurve([0,1,0,t,t]) diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 1edef217bd7..406681d297f 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -827,7 +827,7 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): sage: L.series(3) O(3^5) + O(3^2)*T + (2 + 2*3 + O(3^2))*T^2 + (2 + O(3))*T^3 + (1 + O(3))*T^4 + O(T^5) - Checks if the precision can be changed (:trac: `5846`):: + Checks if the precision can be changed (:trac:`5846`):: sage: L.series(3,prec=4) O(3^5) + O(3^2)*T + (2 + 2*3 + O(3^2))*T^2 + (2 + O(3))*T^3 + O(T^4) @@ -1098,7 +1098,7 @@ def series(self, n=3, quadratic_twist = +1, prec=5, eta = 0): Univariate Quotient Polynomial Ring in alpha over 3-adic Field with capped relative precision 2 with modulus (1 + O(3^2))*x^2 + (3 + O(3^3))*x + (3 + O(3^3)) - An example where we only compute the leading term (:trac: `15737`):: + An example where we only compute the leading term (:trac:`15737`):: sage: E = EllipticCurve("17a1") sage: L = E.padic_lseries(3) diff --git a/src/sage/schemes/elliptic_curves/sha_tate.py b/src/sage/schemes/elliptic_curves/sha_tate.py index ec1bd73eb02..ab5e46e2a73 100644 --- a/src/sage/schemes/elliptic_curves/sha_tate.py +++ b/src/sage/schemes/elliptic_curves/sha_tate.py @@ -522,10 +522,10 @@ def an_padic(self, p, prec=0, use_twists=True): 4 + O(5) sage: EllipticCurve('448c5').sha().an_padic(7,prec=4, use_twists=False) # long time (2s on sage.math, 2011) 2 + 7 + O(7^6) - sage: EllipticCurve([-19,34]).sha().an_padic(5) # see :trac: `6455`, long time (4s on sage.math, 2011) + sage: EllipticCurve([-19,34]).sha().an_padic(5) # see :trac:`6455`, long time (4s on sage.math, 2011) 1 + O(5) - Test for :trac: `15737`:: + Test for :trac:`15737`:: sage: E = EllipticCurve([-100,0]) sage: s = E.sha() diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 1de864415ed..7d540df7ec5 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -1339,7 +1339,7 @@ def change_ring(self,R, **kwds): Defn: Defined on coordinates by sending (x : y) to (x : y) - Check that :trac:'16834' is fixed:: + Check that :trac:`16834` is fixed:: sage: A. = AffineSpace(RR,3) sage: h = Hom(A,A) From f5c84d1188d3a3e6b06d0e9a372a65eb1eb31342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 4 Nov 2015 17:14:10 +0100 Subject: [PATCH 1816/1872] more trac roles --- src/sage/calculus/calculus.py | 4 ++-- src/sage/calculus/functions.py | 2 +- src/sage/graphs/generic_graph.py | 8 ++++---- src/sage/interfaces/maxima.py | 4 ++-- src/sage/modular/abvar/abvar.py | 2 +- src/sage/modular/arithgroup/congroup_sl2z.py | 2 +- src/sage/modular/congroup.py | 2 +- src/sage/modular/cusps.py | 2 +- src/sage/modular/dims.py | 6 +++--- src/sage/modular/dirichlet.py | 4 ++-- src/sage/modular/hecke/ambient_module.py | 4 ++-- src/sage/modular/modform/constructor.py | 4 ++-- src/sage/modular/modform/half_integral.py | 2 +- src/sage/modular/modform/hecke_operator_on_qexp.py | 4 ++-- src/sage/modular/modform/space.py | 4 ++-- src/sage/modular/modsym/modsym.py | 2 +- src/sage/modular/modsym/space.py | 2 +- src/sage/plot/plot_field.py | 2 +- src/sage/symbolic/expression_conversions.py | 10 +++++----- src/sage/symbolic/relation.py | 2 +- 20 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index c895e9cb135..5480a5f4632 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -13,7 +13,7 @@ - Golam Mortuza Hossain (2009-06-22): _laplace_latex(), _inverse_laplace_latex() -- Tom Coates (2010-06-11): fixed Trac #9217 +- Tom Coates (2010-06-11): fixed :trac:`9217` The Sage calculus module is loosely based on the Sage Enhancement Proposal found at: http://www.sagemath.org:9001/CalculusSEP. @@ -1768,7 +1768,7 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): sage: solve([2*x==3, x != 5], x) [[x == (3/2), (-7/2) != 0]] - Make sure that we don't accidentally pick up variables in the maxima namespace (trac #8734):: + Make sure that we don't accidentally pick up variables in the maxima namespace (:trac:`8734`):: sage: sage.calculus.calculus.maxima('my_new_var : 2') 2 diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 29482d915fd..30483478dd2 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -94,7 +94,7 @@ def wronskian(*args): row = lambda n: [diff(f, n) for f in fs] # NOTE: I rewrote the below as two lines to avoid a possible subtle # memory management problem on some platforms (only VMware as far - # as we know?). See trac #2990. + # as we know?). See :trac:`2990`. # There may still be a real problem that this is just hiding for now. A = matrix([row(_) for _ in range(len(fs))]) return A.determinant() diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b78f3a1da5d..35523ab9145 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -11990,7 +11990,7 @@ def is_chordal(self, certificate = False, algorithm = "B"): TESTS: - Trac Ticket #11735:: + See :trac:`11735`:: sage: g = Graph({3:[2,1,4],2:[1],4:[1],5:[2,1,4]}) sage: _, g1 = g.is_chordal(certificate=True); g1.is_chordal() @@ -16170,7 +16170,7 @@ def lex_BFS(self,reverse=False,tree=False, initial_vertex = None): TESTS: - There were some problems with the following call in the past (trac 10899) -- now + There were some problems with the following call in the past (:trac:`10899`) -- now it should be fine:: sage: Graph(1).lex_BFS(tree=True) @@ -19940,7 +19940,7 @@ def automorphism_group(self, partition=None, verbosity=0, TESTS: - We get a KeyError when given an invalid partition (trac #6087):: + We get a KeyError when given an invalid partition (:trac:`6087`):: sage: g=graphs.CubeGraph(3) sage: g.relabel() @@ -20414,7 +20414,7 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False): sage: D.is_isomorphic(D,edge_labels=True, certify = True) (True, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}) - Ensure that trac :trac:`11620` is fixed:: + Ensure that :trac:`11620` is fixed:: sage: G1 = DiGraph([(0, 0, 'c'), (0, 4, 'b'), (0, 5, 'c'), ... (0, 5, 't'), (1, 1, 'c'), (1, 3,'c'), (1, 3, 't'), (1, 5, 'b'), diff --git a/src/sage/interfaces/maxima.py b/src/sage/interfaces/maxima.py index 0acfd3f7463..bb6c9a1370d 100644 --- a/src/sage/interfaces/maxima.py +++ b/src/sage/interfaces/maxima.py @@ -511,7 +511,7 @@ def __init__(self, script_subdirectory=None, logfile=None, server=None, sage: maxima == loads(dumps(m)) True - We make sure labels are turned off (see trac 6816):: + We make sure labels are turned off (see :trac:`6816`):: sage: 'nolabels : true' in maxima._Expect__init_code True @@ -606,7 +606,7 @@ def _start(self): sage: m.is_running() True - Test that we can use more than 256MB RAM (see trac :trac:`6772`):: + Test that we can use more than 256MB RAM (see :trac:`6772`):: sage: a = maxima(10)^(10^5) sage: b = a^600 # long time -- about 10-15 seconds diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index f70c34e56b4..21f26fb18eb 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -831,7 +831,7 @@ def __add__(self, other): sage: B + J0(33)[2] Abelian subvariety of dimension 2 of J0(33) - TESTS: This exposed a bug in HNF (see trac #4527):: + TESTS: This exposed a bug in HNF (see :trac:`4527`):: sage: A = J0(206).new_subvariety().decomposition()[3] ; A # long time Simple abelian subvariety 206d(1,206) of dimension 4 of J0(206) diff --git a/src/sage/modular/arithgroup/congroup_sl2z.py b/src/sage/modular/arithgroup/congroup_sl2z.py index fd52d7d6478..54d3e50e8ed 100644 --- a/src/sage/modular/arithgroup/congroup_sl2z.py +++ b/src/sage/modular/arithgroup/congroup_sl2z.py @@ -3,7 +3,7 @@ AUTHORS: -- Niles Johnson (2010-08): Trac #3893: ``random_element()`` should pass on ``*args`` and ``**kwds``. +- Niles Johnson (2010-08): :trac:`3893`: ``random_element()`` should pass on ``*args`` and ``**kwds``. """ diff --git a/src/sage/modular/congroup.py b/src/sage/modular/congroup.py index 3964217b393..41fa177d900 100644 --- a/src/sage/modular/congroup.py +++ b/src/sage/modular/congroup.py @@ -9,7 +9,7 @@ # are *DIFFERENT* than the bindings for Gamma0, etc. that # get imported in all.py. # -# See trac #5059. +# See :trac:`5059` # ########################################################### diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index 116b0ac5c29..e158f4b287a 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -766,7 +766,7 @@ def is_gamma0_equiv(self, other, N, transformation = None): x = -x0 * ZZ(a/g) # now x*v1*v2 + a = 0 (mod N) - # the rest is all added in trac 10926 + # the rest is all added in :trac:`10926` s1p = s1+x*v1 M = N//g diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index d453192cd68..7a6951e0d10 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -300,7 +300,7 @@ def dimension_new_cusp_forms(X, k=2, p=0): sage: dimension_new_cusp_forms(Gamma1(30),3) 12 - Check that Trac #12640 is fixed:: + Check that :trac:`12640` is fixed:: sage: dimension_new_cusp_forms(DirichletGroup(1)(1), 12) 1 @@ -314,7 +314,7 @@ def dimension_new_cusp_forms(X, k=2, p=0): if N <= 2: return Gamma0(N).dimension_new_cusp_forms(k,p=p) else: - # Gamma1(N) for N<=2 just returns Gamma0(N), which has no eps parameter. See Trac #12640. + # Gamma1(N) for N<=2 just returns Gamma0(N), which has no eps parameter. See :trac:`12640`. return Gamma1(N).dimension_new_cusp_forms(k,eps=X,p=p) elif isinstance(X, (int,long,Integer)): return Gamma0(X).dimension_new_cusp_forms(k,p=p) @@ -413,7 +413,7 @@ def dimension_cusp_forms(X, k=2): sage: dimension_cusp_forms(e^2,2) 1 - Check that Trac #12640 is fixed:: + Check that :trac:`12640` is fixed:: sage: dimension_cusp_forms(DirichletGroup(1)(1), 12) 1 diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 6bb3cf40cc9..9ee54f5d394 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -1095,9 +1095,9 @@ def jacobi_sum(self, char, check=True): sage: sum([g(x)*g(1-x) for x in IntegerModRing(N)]) 11 - And sums where exactly one character is nontrivial (see trac #6393):: + And sums where exactly one character is nontrivial (see :trac:`6393`):: - sage: G=DirichletGroup(5); X=G.list(); Y=X[0]; Z=X[1] + sage: G = DirichletGroup(5); X=G.list(); Y=X[0]; Z=X[1] sage: Y.jacobi_sum(Z) -1 sage: Z.jacobi_sum(Y) diff --git a/src/sage/modular/hecke/ambient_module.py b/src/sage/modular/hecke/ambient_module.py index 869255f525f..fce23f22343 100644 --- a/src/sage/modular/hecke/ambient_module.py +++ b/src/sage/modular/hecke/ambient_module.py @@ -350,7 +350,7 @@ def degeneracy_map(self, codomain, t=1): Domain: Modular Symbols subspace of dimension 4 of Modular Symbols space ... Codomain: Modular Symbols space of dimension 4 for Gamma_0(5) of weight ... - We check for a subtle caching bug that came up in work on trac #10453:: + We check for a subtle caching bug that came up in work on :trac:`10453`:: sage: loads(dumps(J0(33).decomposition()[0].modular_symbols())) Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field @@ -845,7 +845,7 @@ def old_submodule(self, p=None): sage: M.old_submodule() Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 4 and level 16, weight 3, character [-1, 1], sign 1, over Rational Field - Illustrate that trac 10664 is fixed:: + Illustrate that :trac:`10664` is fixed:: sage: ModularSymbols(DirichletGroup(42)[7], 6, sign=1).old_subspace(3) Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 40 and level 42, weight 6, character [-1, -1], sign 1, over Rational Field diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index febc937fd4c..44ec6faff0c 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -243,12 +243,12 @@ def ModularForms(group = 1, sage: m.T(2).charpoly('x') x^4 - 917*x^2 - 42284 - This came up in a subtle bug (trac #5923):: + This came up in a subtle bug (:trac:`5923`):: sage: ModularForms(gp(1), gap(12)) Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field - This came up in another bug (related to trac #8630):: + This came up in another bug (related to :trac:`8630`):: sage: chi = DirichletGroup(109, CyclotomicField(3)).0 sage: ModularForms(chi, 2, base_ring = CyclotomicField(15)) diff --git a/src/sage/modular/modform/half_integral.py b/src/sage/modular/modform/half_integral.py index 6eede485fd3..8f346be4fef 100644 --- a/src/sage/modular/modform/half_integral.py +++ b/src/sage/modular/modform/half_integral.py @@ -89,7 +89,7 @@ def half_integral_weight_modform_basis(chi, k, prec): q^4 - 2*q^5 - 2*q^6 + 4*q^7 + 4*q^9 + O(q^10), q^5 - 2*q^7 - 2*q^9 + O(q^10)] - This example once raised an error (see trac #5792). + This example once raised an error (see :trac:`5792`). :: diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index c652d316971..080109dce6e 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -188,14 +188,14 @@ def hecke_operator_on_basis(B, n, k, eps=None, TESTS: - This shows that the problem with finite fields reported at trac #8281 is solved:: + This shows that the problem with finite fields reported at :trac:`8281` is solved:: sage: bas_mod5 = [f.change_ring(GF(5)) for f in victor_miller_basis(12, 20)] sage: hecke_operator_on_basis(bas_mod5, 2, 12) [4 0] [0 1] - This shows that empty input is handled sensibly (trac #12202):: + This shows that empty input is handled sensibly (:trac:`12202`):: sage: x = hecke_operator_on_basis([], 3, 12); x [] diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index c6b9a09a129..75e5580c681 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -1495,7 +1495,7 @@ def cuspidal_submodule(self): sage: N.cuspidal_submodule().dimension() 1 - We check that a bug noticed on trac #10450 is fixed:: + We check that a bug noticed on :trac:`10450` is fixed:: sage: M = ModularForms(6, 10) sage: W = M.span_of_basis(M.basis()[0:2]) @@ -1690,7 +1690,7 @@ def eisenstein_submodule(self): sage: M.eisenstein_submodule() Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field - We check that a bug noticed on trac #10450 is fixed:: + We check that a bug noticed on :trac:`10450` is fixed:: sage: M = ModularForms(6, 10) sage: W = M.span_of_basis(M.basis()[0:2]) diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index 48b9afdeb64..d52b6ac64ea 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -48,7 +48,7 @@ sage: t2*t5 - t5*t2 == 0 True -This tests the bug reported in trac #1220:: +This tests the bug reported in :trac:`1220`:: sage: G = GammaH(36, [13, 19]) sage: G.modular_symbols() diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index b1a844a79e4..7faa104c390 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -182,7 +182,7 @@ def compact_system_of_eigenvalues(self, v, names='alpha', nz=None): TESTS: - Verify that Trac #12772 is fixed:: + Verify that :trac:`12772` is fixed:: sage: M = ModularSymbols(1,12,sign=1).cuspidal_subspace().new_subspace() sage: A = M.decomposition()[0] diff --git a/src/sage/plot/plot_field.py b/src/sage/plot/plot_field.py index 0ea97fad579..030a19a757d 100644 --- a/src/sage/plot/plot_field.py +++ b/src/sage/plot/plot_field.py @@ -258,7 +258,7 @@ def plot_slope_field(f, xrange, yrange, **kwds): TESTS: Verify that we're not getting warnings due to use of headless quivers - (trac #11208):: + (:trac:`11208`):: sage: x,y = var('x y') sage: import numpy # bump warnings up to errors for testing purposes diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index 64d9ae6768f..63dfce65952 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -587,7 +587,7 @@ def derivative(self, ex, operator): # symbolic variable, yet we would like to treat it like # one. So, we replace the argument `1` with a temporary # variable e.g. `t0` and then evaluate the derivative - # f'(t0) symbolically at t0=1. See trac #12796. + # f'(t0) symbolically at t0=1. See :trac:`12796`. temp_args = [SR.var("t%s"%i) for i in range(len(args))] f = operator.function()(*temp_args) params = operator.parameter_set() @@ -668,7 +668,7 @@ class SympyConverter(Converter): TESTS: - Make sure we can convert I (trac #6424):: + Make sure we can convert I (:trac:`6424`):: sage: bool(I._sympy_() == I) True @@ -1196,7 +1196,7 @@ def __init__(self, ex, *vars): sage: ff(1.0,2.0,3.0) 4.1780638977... - Using _fast_float_ without specifying the variable names is + Using ``_fast_float_`` without specifying the variable names is deprecated:: sage: f = x._fast_float_() @@ -1208,8 +1208,8 @@ def __init__(self, ex, *vars): sage: f(1.2) 1.2 - Using _fast_float_ on a function which is the identity is - now supported (see Trac 10246):: + Using ``_fast_float_`` on a function which is the identity is + now supported (see :trac:`10246`):: sage: f = symbolic_expression(x).function(x) sage: f._fast_float_(x) diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 45a42df68b7..7fa8459d955 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -764,7 +764,7 @@ def solve(f, *args, **kwds): sage: solve((x==1,x==-1),x,solution_dict=1) [] - This inequality holds for any real ``x`` (trac #8078):: + This inequality holds for any real ``x`` (:trac:`8078`):: sage: solve(x^4+2>0,x) [x < +Infinity] From b9ba668ab0a1bb14fa531c39c58e54bd112dc130 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 4 Nov 2015 17:21:31 +0100 Subject: [PATCH 1817/1872] Trac #19522: Change default for MILP variables to nonnegative=False --- src/sage/numerical/backends/glpk_backend.pyx | 25 ++-- src/sage/numerical/linear_functions.pyx | 2 - src/sage/numerical/mip.pyx | 118 +++++++++---------- 3 files changed, 67 insertions(+), 78 deletions(-) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 35a49121cc5..6c8335a1b7a 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -389,11 +389,10 @@ cdef class GLPKBackend(GenericBackend): EXAMPLE:: sage: p = MixedIntegerLinearProgram(solver='GLPK') - sage: x,y = p[0], p[1] - doctest:...: DeprecationWarning: The default value of 'nonnegative' will change, to False instead of True. You should add the explicit 'nonnegative=True'. - See http://trac.sagemath.org/15521 for details. - sage: p.add_constraint(2*x + 3*y, max = 6) - sage: p.add_constraint(3*x + 2*y, max = 6) + sage: v = p.new_variable(nonnegative=True) + sage: x, y = v['x'], v['y'] + sage: p.add_constraint(2*x + 3*y, max=6) + sage: p.add_constraint(3*x + 2*y, max=6) sage: p.set_objective(x + y + 7) sage: p.set_integer(x); p.set_integer(y) sage: p.solve() @@ -429,9 +428,10 @@ cdef class GLPKBackend(GenericBackend): EXAMPLE:: sage: p = MixedIntegerLinearProgram(solver='GLPK') - sage: x,y = p[0], p[1] - sage: p.add_constraint(2*x + 3*y, max = 6) - sage: p.add_constraint(3*x + 2*y, max = 6) + sage: v = p.new_variable(nonnegative=True) + sage: x, y = v['x'], v['y'] + sage: p.add_constraint(2*x + 3*y, max=6) + sage: p.add_constraint(3*x + 2*y, max=6) sage: p.set_objective(x + y + 7) sage: p.set_integer(x); p.set_integer(y) sage: p.solve() @@ -814,12 +814,13 @@ cdef class GLPKBackend(GenericBackend): EXAMPLE:: sage: lp = MixedIntegerLinearProgram(solver = "GLPK") - sage: lp.add_constraint( lp[1] +lp[2] -2.0 *lp[3] , max =-1.0) - sage: lp.add_constraint( lp[0] -4.0/3 *lp[1] +1.0/3 *lp[2] , max =-1.0/3) - sage: lp.add_constraint( lp[0] +0.5 *lp[1] -0.5 *lp[2] +0.25 *lp[3] , max =-0.25) + sage: v = lp.new_variable(nonnegative=True) + sage: lp.add_constraint(v[1] +v[2] -2.0 *v[3], max=-1.0) + sage: lp.add_constraint(v[0] -4.0/3 *v[1] +1.0/3 *v[2], max=-1.0/3) + sage: lp.add_constraint(v[0] +0.5 *v[1] -0.5 *v[2] +0.25 *v[3], max=-0.25) sage: lp.solve() 0.0 - sage: lp.add_constraint( lp[0] +4.0 *lp[1] -lp[2] +lp[3] , max =-1.0) + sage: lp.add_constraint(v[0] +4.0 *v[1] -v[2] +v[3], max=-1.0) sage: lp.solve() Traceback (most recent call last): ... diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index 2e88237077b..0780adb5db4 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -8,8 +8,6 @@ either equalities or less-or-equal. For example:: sage: p = MixedIntegerLinearProgram() sage: x = p.new_variable() - doctest:...: DeprecationWarning: The default value of 'nonnegative' will change, to False instead of True. You should add the explicit 'nonnegative=True'. - See http://trac.sagemath.org/15521 for details. sage: f = 1 + x[1] + 2*x[2]; f # a linear function 1 + x_0 + 2*x_1 sage: type(f) diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index b645ab75f37..52f196a9205 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -138,7 +138,7 @@ variables. For example:: sage: mip. = MixedIntegerLinearProgram() sage: a - MIPVariable of dimension 1. + MIPVariable of dimension 1 sage: 5 + a[1] + 2*b[3] 5 + x_0 + 2*x_1 @@ -405,10 +405,10 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: del p sage: def just_create_variables(): - ... p = MixedIntegerLinearProgram() - ... b = p.new_variable(nonnegative=True) - ... p.add_constraint(b[3]+b[6] <= 2) - ... p.solve() + ....: p = MixedIntegerLinearProgram() + ....: b = p.new_variable(nonnegative=True) + ....: p.add_constraint(b[3]+b[6] <= 2) + ....: p.solve() sage: C = sage.numerical.mip.MixedIntegerLinearProgram sage: import gc sage: _ = gc.collect() # avoid side effects of other doc tests @@ -425,17 +425,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: sum([1 for x in gc.get_objects() if isinstance(x,C)]) 0 sage: gc.enable() - - Right now the ``nonnegative`` argument is mandatory when a variable is - created, but later the default will change from nonnegative variables to - unbounded variables:: - - sage: p = MixedIntegerLinearProgram() - sage: v = p.new_variable(real=True) - doctest:...: DeprecationWarning: The default value of 'nonnegative' will change, to False instead of True. You should add the explicit 'nonnegative=True'. - See http://trac.sagemath.org/15521 for details. - sage: p.get_min(v[0]) - 0.0 """ self.__BINARY = 0 self.__REAL = -1 @@ -630,7 +619,7 @@ cdef class MixedIntegerLinearProgram(SageObject): """ self._backend.problem_name(name) - def new_variable(self, real=False, binary=False, integer=False, nonnegative=None, name=""): + def new_variable(self, real=False, binary=False, integer=False, nonnegative=False, name=""): r""" Return a new MIPVariable @@ -657,8 +646,9 @@ cdef class MixedIntegerLinearProgram(SageObject): arguments to ``True`` to ensure that the variable gets the corresponding type. - - ``nonnegative`` -- boolean. Whether the variable should be assumed to - be nonnegative. Rather useless for the binary type. + - ``nonnegative`` -- boolean, default ``False``. Whether the + variable should be assumed to be nonnegative. Rather useless + for the binary type. - ``name`` -- string. Associates a name to the variable. This is only useful when exporting the linear program to a file @@ -670,9 +660,20 @@ cdef class MixedIntegerLinearProgram(SageObject): A new instance of :class:`MIPVariable` associated to the current :class:`MixedIntegerLinearProgram`. - EXAMPLE:: + EXAMPLES:: sage: p = MixedIntegerLinearProgram() + sage: x = p.new_variable(); x + MIPVariable of dimension 1 + sage: x0 = x[0]; x0 + x_0 + + By default, variables are unbounded:: + + sage: print p.get_min(x0) + None + sage: print p.get_max(x0) + None To define two dictionaries of variables, the first being of real type, and the second of integer type :: @@ -695,8 +696,8 @@ cdef class MixedIntegerLinearProgram(SageObject): Unbounded variables:: sage: p = MixedIntegerLinearProgram() - sage: x = p.new_variable(real=True, nonnegative=False) - sage: y = p.new_variable(integer=True, nonnegative=False) + sage: x = p.new_variable(real=True) + sage: y = p.new_variable(integer=True) sage: p.add_constraint(x[0]+x[3] <= 8) sage: p.add_constraint(y[0] >= y[1]) sage: p.show() @@ -712,8 +713,7 @@ cdef class MixedIntegerLinearProgram(SageObject): x_3 is an integer variable (min=-oo, max=+oo) On the Sage command line, generator syntax is accepted as a - shorthand for generating new variables with default - (``nonnegative=False``) settings:: + shorthand for generating new variables with default settings:: sage: mip. = MixedIntegerLinearProgram() sage: mip.add_constraint(x[0] + y[1] + z[2] <= 10) @@ -726,25 +726,10 @@ cdef class MixedIntegerLinearProgram(SageObject): x[0] = x_0 is a continuous variable (min=-oo, max=+oo) y[1] = x_1 is a continuous variable (min=-oo, max=+oo) z[2] = x_2 is a continuous variable (min=-oo, max=+oo) - - TESTS: - - Default behaviour (:trac:`15521`):: - - sage: x = p.new_variable(nonnegative=True) - sage: p.get_min(x[0]) - 0.0 """ if sum([real, binary, integer]) > 1: raise ValueError("Exactly one of the available types has to be True") - if nonnegative is None: - if not binary: - deprecation(15521, "The default value of 'nonnegative' will change, to "+ - "False instead of True. You should add the explicit "+ - "'nonnegative=True'.") - nonnegative=True - if binary: vtype = self.__BINARY elif integer: @@ -790,7 +775,7 @@ cdef class MixedIntegerLinearProgram(SageObject): a[0] = x_0 is a continuous variable (min=-oo, max=+oo) b[2] = x_1 is a continuous variable (min=-oo, max=+oo) """ - return tuple(self.new_variable(nonnegative=False) for i in range(n)) + return tuple(self.new_variable() for i in range(n)) def gen(self, i): """ @@ -989,40 +974,45 @@ cdef class MixedIntegerLinearProgram(SageObject): A LP on two variables:: sage: p = MixedIntegerLinearProgram() - sage: p.add_constraint(2*p['x'] + p['y'] <= 1) - sage: p.add_constraint(3*p['y'] + p['x'] <= 2) + sage: v = p.new_variable(nonnegative=True) + sage: p.add_constraint(2*v['x'] + v['y'] <= 1) + sage: p.add_constraint(3*v['y'] + v['x'] <= 2) sage: P = p.polyhedron(); P A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices 3-D Polyhedron:: sage: p = MixedIntegerLinearProgram() - sage: p.add_constraint(2*p['x'] + p['y'] + 3*p['z'] <= 1) - sage: p.add_constraint(2*p['y'] + p['z'] + 3*p['x'] <= 1) - sage: p.add_constraint(2*p['z'] + p['x'] + 3*p['y'] <= 1) + sage: v = p.new_variable(nonnegative=True) + sage: p.add_constraint(2*v['x'] + v['y'] + 3*v['z'] <= 1) + sage: p.add_constraint(2*v['y'] + v['z'] + 3*v['x'] <= 1) + sage: p.add_constraint(2*v['z'] + v['x'] + 3*v['y'] <= 1) sage: P = p.polyhedron(); P A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices An empty polyhedron:: sage: p = MixedIntegerLinearProgram() - sage: p.add_constraint(2*p['x'] + p['y'] + 3*p['z'] <= 1) - sage: p.add_constraint(2*p['y'] + p['z'] + 3*p['x'] <= 1) - sage: p.add_constraint(2*p['z'] + p['x'] + 3*p['y'] >= 2) + sage: v = p.new_variable(nonnegative=True) + sage: p.add_constraint(2*v['x'] + v['y'] + 3*v['z'] <= 1) + sage: p.add_constraint(2*v['y'] + v['z'] + 3*v['x'] <= 1) + sage: p.add_constraint(2*v['z'] + v['x'] + 3*v['y'] >= 2) sage: P = p.polyhedron(); P The empty polyhedron in QQ^3 An unbounded polyhedron:: sage: p = MixedIntegerLinearProgram() - sage: p.add_constraint(2*p['x'] + p['y'] - p['z'] <= 1) + sage: v = p.new_variable(nonnegative=True) + sage: p.add_constraint(2*v['x'] + v['y'] - v['z'] <= 1) sage: P = p.polyhedron(); P A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 3 rays A square (see :trac:`14395`) :: sage: p = MixedIntegerLinearProgram() - sage: x,y = p['x'], p['y'] + sage: v = p.new_variable(nonnegative=True) + sage: x,y = v['x'], v['y'] sage: p.set_min(x,None) sage: p.set_min(y,None) sage: p.add_constraint( x <= 1 ) @@ -1107,8 +1097,8 @@ cdef class MixedIntegerLinearProgram(SageObject): Constraints: Constraint_1: -3.0 Hey[1] + 2.0 Hey[2] <= 2.0 Variables: - Hey[1] = x_0 is a continuous variable (min=0.0, max=+oo) - Hey[2] = x_1 is a continuous variable (min=0.0, max=+oo) + Hey[1] = x_0 is a continuous variable (min=-oo, max=+oo) + Hey[2] = x_1 is a continuous variable (min=-oo, max=+oo) Without any names :: @@ -1576,8 +1566,8 @@ cdef class MixedIntegerLinearProgram(SageObject): Constraints: 1.0 <= x_0 - x_1 Variables: - x_0 is a continuous variable (min=0.0, max=+oo) - x_1 is a continuous variable (min=0.0, max=+oo) + x_0 is a continuous variable (min=-oo, max=+oo) + x_1 is a continuous variable (min=-oo, max=+oo) We check for constant multiples of constraints as well:: @@ -1588,8 +1578,8 @@ cdef class MixedIntegerLinearProgram(SageObject): Constraints: 1.0 <= x_0 - x_1 Variables: - x_0 is a continuous variable (min=0.0, max=+oo) - x_1 is a continuous variable (min=0.0, max=+oo) + x_0 is a continuous variable (min=-oo, max=+oo) + x_1 is a continuous variable (min=-oo, max=+oo) But if the constant multiple is negative, we should add it anyway (once):: @@ -1601,8 +1591,8 @@ cdef class MixedIntegerLinearProgram(SageObject): 1.0 <= x_0 - x_1 -2.0 <= -2.0 x_0 + 2.0 x_1 Variables: - x_0 is a continuous variable (min=0.0, max=+oo) - x_1 is a continuous variable (min=0.0, max=+oo) + x_0 is a continuous variable (min=-oo, max=+oo) + x_1 is a continuous variable (min=-oo, max=+oo) TESTS: @@ -2131,7 +2121,7 @@ cdef class MixedIntegerLinearProgram(SageObject): With a :class:`MIPVariable` as an argument:: - sage: vv = p.new_variable(real=True, nonnegative=False) + sage: vv = p.new_variable(real=True) sage: p.get_min(vv) sage: p.get_min(vv[0]) sage: p.set_min(vv,5) @@ -2168,7 +2158,7 @@ cdef class MixedIntegerLinearProgram(SageObject): With a :class:`MIPVariable` as an argument:: - sage: vv = p.new_variable(real=True, nonnegative=False) + sage: vv = p.new_variable(real=True) sage: p.get_max(vv) sage: p.get_max(vv[0]) sage: p.set_max(vv,5) @@ -2588,7 +2578,7 @@ cdef class MIPVariable(Element): sage: p = MixedIntegerLinearProgram() sage: p.new_variable(nonnegative=True) - MIPVariable of dimension 1. + MIPVariable of dimension 1 """ super(MIPVariable, self).__init__(parent) self._dict = {} @@ -2692,9 +2682,9 @@ cdef class MIPVariable(Element): sage: p=MixedIntegerLinearProgram() sage: v=p.new_variable() sage: v - MIPVariable of dimension 1. + MIPVariable of dimension 1 """ - return "MIPVariable of dimension 1." + return "MIPVariable of dimension 1" def keys(self): r""" @@ -2851,7 +2841,7 @@ cdef class MIPVariableParent(Parent): sage: mip = MixedIntegerLinearProgram() sage: mip.new_variable() # indirect doctest - MIPVariable of dimension 1. + MIPVariable of dimension 1 """ return self.element_class(self, mip, vtype, name, lower_bound, upper_bound) From 52348244c75bb31c86c091e0ba78d362914f7568 Mon Sep 17 00:00:00 2001 From: Jonas Jermann Date: Wed, 4 Nov 2015 20:39:40 +0100 Subject: [PATCH 1818/1872] extend the action to CC (and HyperbolicPlane) --- .../hecke_triangle_group_element.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index 569ba54a5a7..fd8f842c0fd 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -20,7 +20,7 @@ from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method -from sage.rings.all import AA, QQbar, ZZ, infinity +from sage.rings.all import AA, QQbar, ZZ, infinity, CC from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane @@ -3164,13 +3164,13 @@ def acton(self, tau): else: return HyperbolicPlane().UHP().get_point(result).to_model(model) - # TODO: extend the action to more general settings, e.g. try if other coerces into HyperbolicPlane() - # Note however that the group also acts on itself by conjugation. So it's not completely clear - # what exactly should be the default action... def _act_on_(self, other, self_on_left): r""" - Defines what Hecke triangle group elements act on using :meth:`acton`. - For now only the action on HyperbolicPlane() is enabled. + Defines the action by linear fractional transformation of Hecke triangle group + elements on complext points (using :meth:`acton`). + + For the action on matrices by conjugation :meth:`acton` has to be used explicitely + (to avoid confusion/ambiguity in expressions of the form gamma1*gamma2*z). EXAMPLES:: @@ -3185,10 +3185,20 @@ def _act_on_(self, other, self_on_left): True sage: (G.S()*G.U())*p == G.S()*(G.U()*p) True + + sage: p = G.lam() + sage: G.U()*G.T()*p + 1/2*lam + 1/2 + sage: p = QQbar(i*sqrt(2)) + sage: G.U()*p + 1.618033988749895? + 0.7071067811865475?*I + sage: p = CC(-i + sqrt(2)) + sage: G.U()*p + 1.14662946795886 - 0.333333333333333*I """ if (self_on_left): - if (other in HyperbolicPlane()): + if (other in CC or other in HyperbolicPlane()): return self.acton(other) return None From ce78d93c96ce657123a860ce8ba01ae958e8040b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 4 Nov 2015 20:56:30 +0100 Subject: [PATCH 1819/1872] trac #19382 details (pep8, etc) --- .../schemes/elliptic_curves/ell_rational_field.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 390b7b95434..52a79939704 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -7002,13 +7002,13 @@ def elliptic_curve_congruence_graph(curves): INPUT: - - ``curves`` - a list of elliptic curves + - ``curves`` -- a list of elliptic curves OUTPUT: The graph with each curve as a vertex (labelled by its Cremona - label) and an edge from E to F labelled p if and only if E is - congruent to F mod p + label) and an edge from `E` to `F` labelled `p` if and only if `E` is + congruent to `F` mod `p` EXAMPLE:: @@ -7032,16 +7032,16 @@ def elliptic_curve_congruence_graph(curves): F = curves[j] N = F.conductor() MN = lcm(M, N) - lim = prod([(p-1)*p**(e-1) for p,e in MN.factor()]) + lim = prod([(p - 1) * p ** (e - 1) for p, e in MN.factor()]) a_E = E.anlist(lim) a_F = F.anlist(lim) - l_list = [p for p in prime_range(lim) if not p.divides(MN) ] + l_list = [p for p in prime_range(lim) if not p.divides(MN)] p_edges = l_list for l in l_list: n = a_E[l] - a_F[l] if n != 0: p_edges = [p for p in p_edges if p.divides(n)] - if len(p_edges) > 0: + if len(p_edges): G.add_edge(E.cremona_label(), F.cremona_label()) - G.set_edge_label(i,j,str(p_edges)[1:-1]) + G.set_edge_label(i, j, str(p_edges)[1:-1]) return G From de880b190506bb556332b2092f675f49b129ca13 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Wed, 4 Nov 2015 21:34:26 +0100 Subject: [PATCH 1820/1872] fixed a bug in cambrian lattice for Coxeter groups --- src/sage/categories/finite_coxeter_groups.py | 68 ++++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 9897814ccb3..d680c495208 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -357,8 +357,7 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): from sage.combinat.posets.lattices import LatticePoset if hasattr(c,"reduced_word"): c = c.reduced_word() - elif not isinstance(c,list): - c = list(c) + c = list(c) if on_roots: if not hasattr(self.long_element(),"reflection_to_root"): @@ -373,42 +372,41 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): T = self.reflections_from_w0() Twords = {t : t.reduced_word() for t in T} - elements = [] + elements = set() covers = [] - bottom_elt = sorted([[s,0] for s in S]) - new = [bottom_elt] - while new != []: - for new_element in new: - new.remove(new_element) - elements.append(new_element) - for t in new_element: - if t[1] < m: - cov_element = [s for s in new_element if s != t] - cov_element.append([t[0],t[1]+1]) - for t_conj in [[i,t[1]] for i in inv_woc[inv_woc.index(t[0]):]]+[[i,t[1]+1] for i in inv_woc[:inv_woc.index(t[0])]]: - if t_conj in cov_element: - cov_element.remove(t_conj) - if on_roots: - tmp = t_conj[0].weyl_action(t[0].associated_reflection()) - if tmp in PhiP: - cov_element.append([tmp,t_conj[1]]) - else: - cov_element.append([-tmp,t_conj[1]-1]) + bottom_elt = frozenset((s,0) for s in S) + new = set([bottom_elt]) + while new: + new_element = new.pop() + elements.add(new_element) + for t in new_element: + if t[1] < m: + cov_element = [s for s in new_element if s != t] + cov_element.append((t[0],t[1]+1)) + for t_conj in [(i,t[1]) for i in inv_woc[inv_woc.index(t[0]):]]+[(i,t[1]+1) for i in inv_woc[:inv_woc.index(t[0])]]: + if t_conj in cov_element: + cov_element.remove(t_conj) + if on_roots: + tmp = t_conj[0].weyl_action(t[0].associated_reflection()) + if tmp in PhiP: + cov_element.append(( tmp,t_conj[1] )) else: - tmp = t[0]*t_conj[0]*t[0] - invs = self.inversion_sequence(Twords[t[0]]+Twords[t_conj[0]]) - plus_or_minus = invs.count(tmp) - if plus_or_minus % 2 == 1: - cov_element.append([tmp,t_conj[1]]) - else: - cov_element.append([tmp,t_conj[1]-1]) - - cov_element = sorted(cov_element) - if cov_element not in elements and cov_element not in new: - new.append(cov_element) - covers.append([tuple(map(tuple,new_element)),tuple(map(tuple,cov_element))]) - return LatticePoset([[tuple(map(tuple,e)) for e in elements],covers],cover_relations=True) + cov_element.append((-tmp,t_conj[1]-1)) + else: + tmp = t[0]*t_conj[0]*t[0] + invs = self.inversion_sequence(Twords[t[0]]+Twords[t_conj[0]]) + plus_or_minus = invs.count(tmp) + if plus_or_minus % 2 == 1: + cov_element.append((tmp,t_conj[1] )) + else: + cov_element.append((tmp,t_conj[1]-1)) + + cov_element = frozenset(cov_element) + if cov_element not in elements: + new.add(cov_element) + covers.append((new_element,cov_element)) + return LatticePoset([elements,covers],cover_relations=True) def cambrian_lattice(self, c, on_roots=False): """ From 9fba87a45127502a30bfcf3dab393807800f828f Mon Sep 17 00:00:00 2001 From: Jonas Jermann Date: Wed, 4 Nov 2015 23:00:32 +0100 Subject: [PATCH 1821/1872] also allow actions on infinity --- .../modform_hecketriangle/hecke_triangle_group_element.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index fd8f842c0fd..25edc13240c 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -3195,10 +3195,13 @@ def _act_on_(self, other, self_on_left): sage: p = CC(-i + sqrt(2)) sage: G.U()*p 1.14662946795886 - 0.333333333333333*I + sage: p = infinity + sage: G.U()*p + lam """ if (self_on_left): - if (other in CC or other in HyperbolicPlane()): + if (other == infinity or other in CC or other in HyperbolicPlane()): return self.acton(other) return None From fd5dbe2f3bc3c9443f4d81f658bc1885e854c590 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Wed, 4 Nov 2015 21:02:15 -0500 Subject: [PATCH 1822/1872] change choose_nk to combination --- src/sage/homology/koszul_complex.py | 2 +- src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx | 4 ++-- src/sage/rings/polynomial/pbori.pyx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/homology/koszul_complex.py b/src/sage/homology/koszul_complex.py index a5e16aa5e9f..592c2182c5c 100644 --- a/src/sage/homology/koszul_complex.py +++ b/src/sage/homology/koszul_complex.py @@ -14,7 +14,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.combinat.choose_nk import rank +from sage.combinat.combination import rank from sage.rings.arith import binomial from sage.rings.all import ZZ from sage.matrix.constructor import matrix diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx index 773cdebd99b..0991db3ff1e 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx @@ -640,8 +640,8 @@ cdef class MPolynomialRing_generic(sage.rings.ring.CommutativeRing): We do not check if the provided index/rank is within the allowed range. If it is not an infinite loop will occur. """ - from sage.combinat import choose_nk - comb = choose_nk.from_rank(i, n+d-1, n-1) + from sage.combinat import combination + comb = combination.from_rank(i, n+d-1, n-1) if comb == []: return (d,) monomial = [ comb[0] ] diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index ab92d9dd498..7f7954c841c 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -1260,7 +1260,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_generic): [x*y, x*y, x, x, x, x*y, x, y, x*y, 1] """ from sage.rings.integer_ring import ZZ - from sage.combinat.choose_nk import from_rank + from sage.combinat.combination import from_rank t = ZZ.random_element(0,monom_counts[-1]) if t == 0: From d673106fdf9b366aae8ee5f0c0319ce84f102b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Thu, 5 Nov 2015 10:37:46 +0200 Subject: [PATCH 1823/1872] Corrections to indentation in graphs. --- src/sage/graphs/digraph.py | 8 +-- src/sage/graphs/generic_graph.py | 105 +++++++++++++++--------------- src/sage/graphs/graph_coloring.py | 42 ++++++------ 3 files changed, 77 insertions(+), 78 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index e20173a7f4e..39a5fd422c4 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -1603,7 +1603,7 @@ def reverse_edge(self, u, v=None, label=None, inplace=True, multiedges=None): INPUT: - ``inplace`` -- (default: True) if ``False``, a new digraph is created - and returned as output, otherwise ``self`` is modified. + and returned as output, otherwise ``self`` is modified. - ``multiedges`` -- (default: None) how to decide what should be done in case of doubt (for instance when edge `(1,2)` is to be reversed in a @@ -1823,11 +1823,11 @@ def reverse_edges(self, edges, inplace=True, multiedges=None): - ``edges`` -- a list of edges in the DiGraph. - ``inplace`` -- (default: True) if ``False``, a new digraph is created - and returned as output, otherwise ``self`` is modified. + and returned as output, otherwise ``self`` is modified. - ``multiedges`` -- (default: None) if ``True``, input graph will be - forced to allow parallel edges when necessary (for more information - see the documentation of :meth:`~DiGraph.reverse_edge`) + forced to allow parallel edges when necessary (for more information + see the documentation of :meth:`~DiGraph.reverse_edge`) .. SEEALSO:: diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b78f3a1da5d..f14ea8e6cdb 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -3985,27 +3985,26 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se INPUT: - - ``kuratowski`` - returns a tuple with boolean as first entry. If the graph is nonplanar, will return the Kuratowski subgraph (i.e. an edge subdivision of `K_5` or `K_{3,3}`) 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 - embedding.) + 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. + 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. - Note that this value will default to False if set_emb is set to - False. Also, the position dictionary will only be updated if a - planar embedding is found. + - ``set_pos`` - whether or not to set the position + dictionary (for plotting) to reflect the combinatorial embedding. + Note that this value will default to False if set_emb is set to + False. Also, the position dictionary will only be updated if a + planar embedding is found. EXAMPLES:: @@ -4140,34 +4139,34 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, INPUT: - ``kuratowski`` (boolean) - if set to True, returns a tuple with - boolean first entry and the Kuratowski subgraph (i.e. an edge - subdivision of `K_5` or `K_{3,3}`) as the second entry (see OUTPUT below). - It is set to ``False`` by default. + boolean first entry and the Kuratowski subgraph (i.e. an edge + subdivision of `K_5` or `K_{3,3}`) as the second entry (see OUTPUT below). + It is set to ``False`` by default. - ``on_embedding`` (boolean) - the embedding dictionary to test - planarity on. (i.e.: will return ``True`` or ``False`` only for the - given embedding). It is set to ``False`` by default. + planarity on. (i.e.: will return ``True`` or ``False`` only for the + given embedding). It is set to ``False`` by default. - ``set_embedding`` (boolean) - 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 - circular 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. It is set to ``True`` by default. + variable that contains a combinatorial embedding (clockwise ordering + of neighbors at each vertex). This value will only be set if a + circular 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. It is set to ``True`` by default. - ``boundary`` - a set of vertices that are required to be drawn on the circle, all others being drawn inside of it. It is set to ``None`` by default, meaning that *all* vertices should be drawn on the boundary. - ``ordered`` (boolean) - whether or not to consider the order of the - boundary. It is set to ``False`` by default, and required - ``boundary`` to be defined. + boundary. It is set to ``False`` by default, and required + ``boundary`` to be defined. - ``set_pos`` - whether or not to set the position dictionary (for - plotting) to reflect the combinatorial embedding. Note that this - value will default to False if set_emb is set to False. Also, the - position dictionary will only be updated if a circular planar - embedding is found. + plotting) to reflect the combinatorial embedding. Note that this + value will default to False if set_emb is set to False. Also, the + position dictionary will only be updated if a circular planar + embedding is found. OUTPUT: @@ -4542,9 +4541,9 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal default minimal. - ``circular (list)`` - if ``circular`` is a list of vertices, the - method computes the genus preserving a planar embedding of the this - list. If circular is defined, ``on_embedding`` is not a valid - option. It is set to ``None`` by default. + method computes the genus preserving a planar embedding of the this + list. If circular is defined, ``on_embedding`` is not a valid + option. It is set to ``None`` by default. - ``ordered (boolean)`` - if circular is True, then whether or not the boundary order may be permuted. (Default is @@ -11256,11 +11255,11 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None): - ``vertices`` - Vertices is a list of vertices - ``edges`` - Edges can be a single edge or an iterable - container of edges (e.g., a list, set, file, numeric array, - etc.). If not edges are not specified, then all edges are - assumed and the returned graph is an induced subgraph. In - the case of multiple edges, specifying an edge as (u,v) - means to keep all edges (u,v), regardless of the label. + container of edges (e.g., a list, set, file, numeric array, + etc.). If not edges are not specified, then all edges are + assumed and the returned graph is an induced subgraph. In + the case of multiple edges, specifying an edge as (u,v) + means to keep all edges (u,v), regardless of the label. - ``edge_property`` - If specified, this is expected to be a function on edges, which is intersected with the edges @@ -11391,11 +11390,11 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, - ``vertices`` - Vertices is a list of vertices - ``edges`` - Edges can be a single edge or an iterable - container of edges (e.g., a list, set, file, numeric array, - etc.). If not edges are not specified, then all edges are - assumed and the returned graph is an induced subgraph. In - the case of multiple edges, specifying an edge as (u,v) - means to keep all edges (u,v), regardless of the label. + container of edges (e.g., a list, set, file, numeric array, + etc.). If not edges are not specified, then all edges are + assumed and the returned graph is an induced subgraph. In + the case of multiple edges, specifying an edge as (u,v) + means to keep all edges (u,v), regardless of the label. - ``edge_property`` - If specified, this is expected to be a function on edges, which is intersected with the edges @@ -17884,12 +17883,12 @@ def plot(self, **options): - ``iterations`` - how many iterations of the spring layout algorithm to go through, if applicable - - ``color_by_label`` - a boolean or dictionary or function (default: False) - whether to color each edge with a different color according - to its label; the colors are chosen along a rainbow, unless - they are specified by a function or dictionary mapping - labels to colors; this option is incompatible with - ``edge_color`` and ``edge_colors``. + - ``color_by_label`` - a boolean or dictionary or function (default: + False) whether to color each edge with a different color according + to its label; the colors are chosen along a rainbow, unless + they are specified by a function or dictionary mapping + labels to colors; this option is incompatible with + ``edge_color`` and ``edge_colors``. - ``heights`` - if specified, this is a dictionary from a set of floating point heights to a set of vertices @@ -18203,12 +18202,12 @@ def plot3d(self, bgcolor=(1,1,1), colors: each key is a color recognized by tachyon ( default: (0,0,0) ), and each entry is a list of edges. - - ``color_by_label`` - a boolean or dictionary or function (default: False) - whether to color each edge with a different color according - to its label; the colors are chosen along a rainbow, unless - they are specified by a function or dictionary mapping - labels to colors; this option is incompatible with - ``edge_color`` and ``edge_colors``. + - ``color_by_label`` - a boolean or dictionary or function (default: + False) whether to color each edge with a different color according + to its label; the colors are chosen along a rainbow, unless + they are specified by a function or dictionary mapping + labels to colors; this option is incompatible with + ``edge_color`` and ``edge_colors``. - ``edge_size`` - float (default: 0.02) diff --git a/src/sage/graphs/graph_coloring.py b/src/sage/graphs/graph_coloring.py index 9c01512d191..1bdd9412ce2 100644 --- a/src/sage/graphs/graph_coloring.py +++ b/src/sage/graphs/graph_coloring.py @@ -374,7 +374,7 @@ class :class:`MixedIntegerLinearProgram `. - ``verbose`` -- integer (default: ``0``). Sets the level of - verbosity. Set to 0 by default, which means quiet. + verbosity. Set to 0 by default, which means quiet. OUTPUT: @@ -950,7 +950,7 @@ class :class:`MixedIntegerLinearProgram `. - ``verbose`` -- integer (default: ``0``). Sets the level of - verbosity. Set to 0 by default, which means quiet. + verbosity. Set to 0 by default, which means quiet. OUTPUT: @@ -1149,34 +1149,34 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, solv - ``hex_colors`` (boolean) - - If ``hex_colors = True``, the function returns a - dictionary associating to each color a list - of edges (meant as an argument to the ``edge_colors`` - keyword of the ``plot`` method). + - If ``hex_colors = True``, the function returns a + dictionary associating to each color a list + of edges (meant as an argument to the ``edge_colors`` + keyword of the ``plot`` method). - - If ``hex_colors = False`` (default value), returns - a list of graphs corresponding to each color class. + - If ``hex_colors = False`` (default value), returns + a list of graphs corresponding to each color class. - ``value_only`` (boolean) - - If ``value_only = True``, only returns the linear - arboricity as an integer value. + - If ``value_only = True``, only returns the linear + arboricity as an integer value. - - If ``value_only = False``, returns the color classes - according to the value of ``hex_colors`` + - If ``value_only = False``, returns the color classes + according to the value of ``hex_colors`` - ``plus_one`` (integer) -- whether to use `\lceil \frac {\Delta(G)} 2 \rceil` or `\lceil \frac {\Delta(G)+1} 2 \rceil` colors. - - If ``0``, computes a decomposition of `G` into `\lceil \frac - {\Delta(G)} 2 \rceil` forests of paths + - If ``0``, computes a decomposition of `G` into `\lceil \frac + {\Delta(G)} 2 \rceil` forests of paths - - If ``1``, computes a decomposition of `G` into `\lceil \frac - {\Delta(G)+1} 2 \rceil` colors, which is the conjectured general - bound. + - If ``1``, computes a decomposition of `G` into `\lceil \frac + {\Delta(G)+1} 2 \rceil` colors, which is the conjectured general + bound. - - If ``plus_one = None`` (default), computes a decomposition using the - least possible number of colors. + - If ``plus_one = None`` (default), computes a decomposition using the + least possible number of colors. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) solver to be used. If set to ``None``, the default one is used. For more information @@ -1186,7 +1186,7 @@ class :class:`MixedIntegerLinearProgram `. - ``verbose`` -- integer (default: ``0``). Sets the level of verbosity. Set - to 0 by default, which means quiet. + to 0 by default, which means quiet. ALGORITHM: @@ -1384,7 +1384,7 @@ class :class:`MixedIntegerLinearProgram `. - ``verbose`` -- integer (default: ``0``). Sets the level of - verbosity. Set to 0 by default, which means quiet. + verbosity. Set to 0 by default, which means quiet. ALGORITHM: From 9beea8d47a076a5ae01e9a1307d37c641a2692f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 5 Nov 2015 13:40:07 +0100 Subject: [PATCH 1824/1872] removing useless trac role rest syntax in comments --- src/sage/algebras/clifford_algebra.py | 2 +- src/sage/algebras/jordan_algebra.py | 4 ++-- src/sage/calculus/functions.py | 2 +- src/sage/categories/finite_enumerated_sets.py | 4 ++-- src/sage/categories/finite_posets.py | 2 +- src/sage/categories/modules_with_basis.py | 6 +++--- src/sage/combinat/ncsf_qsym/ncsf.py | 2 +- src/sage/combinat/partition.py | 4 ++-- src/sage/databases/cremona.py | 2 +- src/sage/interfaces/expect.py | 2 +- src/sage/interfaces/r.py | 2 +- src/sage/misc/html.py | 2 +- src/sage/misc/latex.py | 2 +- src/sage/modular/congroup.py | 2 +- src/sage/modular/cusps.py | 2 +- src/sage/modular/dims.py | 2 +- src/sage/plot/plot3d/tachyon.py | 2 +- src/sage/repl/rich_output/pretty_print.py | 2 +- src/sage/schemes/elliptic_curves/sha_tate.py | 2 +- src/sage/symbolic/expression_conversions.py | 2 +- 20 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 0e570434890..6bcddfe40f1 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1908,7 +1908,7 @@ def lifted_form(x, y): matr = MC(MS, matrix_list, copy=False, coerce=False) # Using low-level matrix constructor here # because Matrix(...) does too much duck - # typing (:trac:`17124`). + # typing (trac #17124). result += cx * cy * matr.determinant() return result from sage.categories.cartesian_product import cartesian_product diff --git a/src/sage/algebras/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index 0f024e61113..e5c70f6169f 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -239,9 +239,9 @@ def __init__(self, A, names=None): if A in C.Unital(): cat = cat.Unital() self._no_generic_basering_coercion = True - # Remove the preceding line once :trac:`16492` is fixed + # Remove the preceding line once trac #16492 is fixed # Removing this line will also break some of the input formats, - # see :trac:`16054` + # see trac #16054 if A in C.WithBasis(): cat = cat.WithBasis() if A in C.FiniteDimensional(): diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 30483478dd2..29482d915fd 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -94,7 +94,7 @@ def wronskian(*args): row = lambda n: [diff(f, n) for f in fs] # NOTE: I rewrote the below as two lines to avoid a possible subtle # memory management problem on some platforms (only VMware as far - # as we know?). See :trac:`2990`. + # as we know?). See trac #2990. # There may still be a real problem that this is just hiding for now. A = matrix([row(_) for _ in range(len(fs))]) return A.determinant() diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index 1c795543d62..6da25dec992 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -140,9 +140,9 @@ def _cardinality_from_iterator(self, *ignored_args, **ignored_kwds): [1] sage: P.cardinality() 1 - sage: P.cardinality('use alt algorithm') # Used to break here: see :trac:`13688` + sage: P.cardinality('use alt algorithm') # Used to break here: see trac #13688 1 - sage: P.cardinality(dummy_arg='use alg algorithm') # Used to break here: see :trac:`13688` + sage: P.cardinality(dummy_arg='use alg algorithm') # Used to break here: see trac #13688 1 """ c = 0 diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index 06e741dd0fa..b410716cf0f 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -1012,7 +1012,7 @@ def birational_toggle(self, v, labelling): x = FF.one() / b else: x = FF.sum(FF.one() / newdict[j] for j in uppers) - # ``FF.sum``, not ``sum``, see :trac:`15591`. + # ``FF.sum``, not ``sum``, see trac #15591. x = FF.one() / x # Construct the sum ``y`` of the labels at the elements # covered by ``v``: diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index aa4dc15e85c..b1614162528 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -797,10 +797,10 @@ def cardinality(self): sage: S = SymmetricGroupAlgebra(QQ, 4) sage: S.cardinality() +Infinity - sage: S = SymmetricGroupAlgebra(GF(2), 4) # not tested -- MRO bug :trac:`15475` - sage: S.cardinality() # not tested -- MRO bug :trac:`15475` + sage: S = SymmetricGroupAlgebra(GF(2), 4) # not tested -- MRO bug trac #15475 + sage: S.cardinality() # not tested -- MRO bug trac #15475 16777216 - sage: S.cardinality().factor() # not tested -- MRO bug :trac:`15475` + sage: S.cardinality().factor() # not tested -- MRO bug trac #15475 2^24 sage: E. = ExteriorAlgebra(QQ) diff --git a/src/sage/combinat/ncsf_qsym/ncsf.py b/src/sage/combinat/ncsf_qsym/ncsf.py index fff8dd0393c..79441b714ad 100644 --- a/src/sage/combinat/ncsf_qsym/ncsf.py +++ b/src/sage/combinat/ncsf_qsym/ncsf.py @@ -4475,7 +4475,7 @@ def _to_complete_on_basis(self, I): distinct=True ) # Note: sum(I) works both if I is a list and if I is a composition # (although the latter case doesn't work in IPython, cf. - # :trac:`15163`). + # trac #15163). def _from_psi_on_basis(self, I): r""" diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 2a9b05a9482..0954a7b4ea4 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -1383,7 +1383,7 @@ def down_list(self): [[2, 2], [3, 1]] sage: Partition([3,2,1]).down_list() [[2, 2, 1], [3, 1, 1], [3, 2]] - sage: Partition([]).down_list() #checks :trac:`11435` + sage: Partition([]).down_list() # checks trac #11435 [] """ return [p for p in self.down()] @@ -7706,7 +7706,7 @@ def number_of_partitions_length(n, k, algorithm='hybrid'): # Rather than caching an under-used function I have cached the default # number_of_partitions functions which is currently using FLINT. -# AM :trac:`13072` +# AM trac #13072 cached_number_of_partitions = cached_function( flint_number_of_partitions ) # October 2012: fixing outdated pickles which use classes being deprecated diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 96194d26ec5..0a5f79478a5 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -1324,7 +1324,7 @@ def _init_from_ftpdata(self, ftpdata, largest_conductor=0): self.__largest_conductor__ = largest_conductor # Since July 2014 the data files have been arranged in - # subdirectories (see :trac:`16903`). + # subdirectories (see trac #16903). allcurves_dir = os.path.join(ftpdata,'allcurves') allbsd_dir = os.path.join(ftpdata,'allbsd') allgens_dir = os.path.join(ftpdata,'allgens') diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py index 67f267f9154..038f2f39d87 100644 --- a/src/sage/interfaces/expect.py +++ b/src/sage/interfaces/expect.py @@ -455,7 +455,7 @@ def _start(self, alt_message=None, block_during_init=True): self._expect.timeout = None # Calling tcsetattr earlier exposes bugs in various pty - # implementations, see :trac:`16474`. Since we haven't + # implementations, see trac #16474. Since we haven't # **written** anything so far it is safe to wait with # switching echo off until now. if not self._terminal_echo: diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 1dd5fe36c37..964d93e0f43 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -1186,7 +1186,7 @@ def chdir(self, dir): :: - sage: os.path.realpath(tmpdir) == sageobj(r.getwd()) # known bug (:trac:`9970`) + sage: os.path.realpath(tmpdir) == sageobj(r.getwd()) # known bug (trac #9970) True """ self.execute('setwd(%r)' % dir) diff --git a/src/sage/misc/html.py b/src/sage/misc/html.py index e1868885748..5c0a1ffe10d 100644 --- a/src/sage/misc/html.py +++ b/src/sage/misc/html.py @@ -24,7 +24,7 @@ -# Various hacks for the deprecation period in :trac:`18292` are +# Various hacks for the deprecation period in trac #18292 are # conditional on this bool _old_and_deprecated_behavior = True diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 4b90cbd237d..de6325214b2 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -2562,7 +2562,7 @@ def latex_variable_name(x, is_fname=False): TESTS:: - sage: latex_variable_name('_C') # :trac:`16007` + sage: latex_variable_name('_C') # trac #16007 'C' sage: latex_variable_name('_K1') 'K_{1}' diff --git a/src/sage/modular/congroup.py b/src/sage/modular/congroup.py index 41fa177d900..23a6679fdcc 100644 --- a/src/sage/modular/congroup.py +++ b/src/sage/modular/congroup.py @@ -9,7 +9,7 @@ # are *DIFFERENT* than the bindings for Gamma0, etc. that # get imported in all.py. # -# See :trac:`5059` +# See trac #5059 # ########################################################### diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index e158f4b287a..348ed351f19 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -766,7 +766,7 @@ def is_gamma0_equiv(self, other, N, transformation = None): x = -x0 * ZZ(a/g) # now x*v1*v2 + a = 0 (mod N) - # the rest is all added in :trac:`10926` + # the rest is all added in trac #10926 s1p = s1+x*v1 M = N//g diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index 7a6951e0d10..0bcac125b44 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -314,7 +314,7 @@ def dimension_new_cusp_forms(X, k=2, p=0): if N <= 2: return Gamma0(N).dimension_new_cusp_forms(k,p=p) else: - # Gamma1(N) for N<=2 just returns Gamma0(N), which has no eps parameter. See :trac:`12640`. + # Gamma1(N) for N<=2 just returns Gamma0(N), which has no eps parameter. See trac #12640. return Gamma1(N).dimension_new_cusp_forms(k,eps=X,p=p) elif isinstance(X, (int,long,Integer)): return Gamma0(X).dimension_new_cusp_forms(k,p=p) diff --git a/src/sage/plot/plot3d/tachyon.py b/src/sage/plot/plot3d/tachyon.py index 185a5c82e6e..1cbd6a24635 100644 --- a/src/sage/plot/plot3d/tachyon.py +++ b/src/sage/plot/plot3d/tachyon.py @@ -754,7 +754,7 @@ def texture(self, name, ambient=0.2, diffuse=0.8, sage: t.sphere((0,-1,1), 1, 'mirror') sage: t.sphere((2,-1,1), 0.5, 'mirror') sage: t.sphere((2,1,1), 0.5, 'mirror') - sage: show(t) # known bug (:trac:`7232`) + sage: show(t) # known bug (trac #7232) """ if texfunc and not isinstance(texfunc, Texfunc): texfunc = self.texfunc(int(texfunc), imagefile=imagefile) diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py index 89b9db49250..2b950574e74 100644 --- a/src/sage/repl/rich_output/pretty_print.py +++ b/src/sage/repl/rich_output/pretty_print.py @@ -228,7 +228,7 @@ def pretty_print(*args, **kwds): if len(args) == 1 and isinstance(args[0], (types.GeneratorType, collections.Iterator)): args = tuple(args[0]) - # Support deprecation :trac:`18292` + # Support deprecation trac #18292 if len(args) == 1: import sage.misc.html if sage.misc.html.WarnIfNotPrinted.skip_pretty_print(args[0]): diff --git a/src/sage/schemes/elliptic_curves/sha_tate.py b/src/sage/schemes/elliptic_curves/sha_tate.py index ab5e46e2a73..a5c46d09eb2 100644 --- a/src/sage/schemes/elliptic_curves/sha_tate.py +++ b/src/sage/schemes/elliptic_curves/sha_tate.py @@ -522,7 +522,7 @@ def an_padic(self, p, prec=0, use_twists=True): 4 + O(5) sage: EllipticCurve('448c5').sha().an_padic(7,prec=4, use_twists=False) # long time (2s on sage.math, 2011) 2 + 7 + O(7^6) - sage: EllipticCurve([-19,34]).sha().an_padic(5) # see :trac:`6455`, long time (4s on sage.math, 2011) + sage: EllipticCurve([-19,34]).sha().an_padic(5) # see trac #6455, long time (4s on sage.math, 2011) 1 + O(5) Test for :trac:`15737`:: diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index 63dfce65952..cce62bd72b2 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -587,7 +587,7 @@ def derivative(self, ex, operator): # symbolic variable, yet we would like to treat it like # one. So, we replace the argument `1` with a temporary # variable e.g. `t0` and then evaluate the derivative - # f'(t0) symbolically at t0=1. See :trac:`12796`. + # f'(t0) symbolically at t0=1. See trac #12796. temp_args = [SR.var("t%s"%i) for i in range(len(args))] f = operator.function()(*temp_args) params = operator.parameter_set() From f97e522fd09a046ad733045194512f4b82c820f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 5 Nov 2015 13:43:22 +0100 Subject: [PATCH 1825/1872] removing trac roles in comments in pyx files --- src/sage/ext/multi_modular.pyx | 2 +- src/sage/rings/finite_rings/finite_field_base.pyx | 2 +- src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx | 2 +- src/sage/symbolic/function.pyx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/ext/multi_modular.pyx b/src/sage/ext/multi_modular.pyx index 2b47f1c77f3..42c1e83bbe3 100644 --- a/src/sage/ext/multi_modular.pyx +++ b/src/sage/ext/multi_modular.pyx @@ -199,7 +199,7 @@ cdef class MultiModularBasis_base: try: self.extend_with_primes(val, check=True) except ArithmeticError: - #See :trac:`10217` + # See trac #10217 raise ValueError("the values provided are not relatively prime") else: self._extend_moduli_to_height(val) diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index f771390b114..1c923b98179 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -710,7 +710,7 @@ cdef class FiniteField(Field): return self.characteristic()**self.degree() # cached because constructing the Factorization is slow; - # see :trac:`11628`. + # see trac #11628. @cached_method def factored_order(self): """ diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index 46c8e1dcbfc..c3b34922c82 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -669,7 +669,7 @@ cdef class PolynomialRealDense(Polynomial): TESTS:: - sage: R. = RR[] # :trac:`17311` + sage: R. = RR[] # trac #17311 sage: (x^2+1)(x=5) 26.0000000000000 """ diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 08d51cfe37d..a8c501ab4a9 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -1032,7 +1032,7 @@ cdef class BuiltinFunction(Function): sage: p3 = AFunction('p3', 3) sage: p3(x) x^3 - sage: loads(dumps(cot)) == cot # :trac:`15138` + sage: loads(dumps(cot)) == cot # trac #15138 True """ # check if already defined From a11e3ebcc1ac4e66c6b3b985830c179363baa675 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 5 Nov 2015 13:46:18 +0100 Subject: [PATCH 1826/1872] Simplified the square doctest --- src/sage/numerical/mip.pyx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index 52f196a9205..8fa3cb94752 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -1011,17 +1011,13 @@ cdef class MixedIntegerLinearProgram(SageObject): A square (see :trac:`14395`) :: sage: p = MixedIntegerLinearProgram() - sage: v = p.new_variable(nonnegative=True) - sage: x,y = v['x'], v['y'] - sage: p.set_min(x,None) - sage: p.set_min(y,None) + sage: x,y = p['x'], p['y'] sage: p.add_constraint( x <= 1 ) sage: p.add_constraint( x >= -1 ) sage: p.add_constraint( y <= 1 ) sage: p.add_constraint( y >= -1 ) sage: p.polyhedron() A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices - """ from sage.geometry.polyhedron.constructor import Polyhedron cdef GenericBackend b = self._backend From 7e9446923aad2afc80a2103dd8d510463ba80fc4 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 5 Nov 2015 14:05:16 +0100 Subject: [PATCH 1827/1872] trac #19522: Preserve the p['x'] syntax --- src/sage/numerical/backends/glpk_backend.pyx | 20 ++++++++++---------- src/sage/numerical/mip.pyx | 17 +++++++---------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 6c8335a1b7a..04faf46a066 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -389,10 +389,10 @@ cdef class GLPKBackend(GenericBackend): EXAMPLE:: sage: p = MixedIntegerLinearProgram(solver='GLPK') - sage: v = p.new_variable(nonnegative=True) - sage: x, y = v['x'], v['y'] - sage: p.add_constraint(2*x + 3*y, max=6) - sage: p.add_constraint(3*x + 2*y, max=6) + sage: x, y = p['x'], p['y'] + sage: p.add_constraint(2*x + 3*y <= 6) + sage: p.add_constraint(3*x + 2*y <= 6) + sage: p.add_constraint(x >= 0) sage: p.set_objective(x + y + 7) sage: p.set_integer(x); p.set_integer(y) sage: p.solve() @@ -428,19 +428,19 @@ cdef class GLPKBackend(GenericBackend): EXAMPLE:: sage: p = MixedIntegerLinearProgram(solver='GLPK') - sage: v = p.new_variable(nonnegative=True) - sage: x, y = v['x'], v['y'] - sage: p.add_constraint(2*x + 3*y, max=6) - sage: p.add_constraint(3*x + 2*y, max=6) + sage: x, y = p['x'], p['y'] + sage: p.add_constraint(2*x + 3*y <= 6) + sage: p.add_constraint(3*x + 2*y <= 6) + sage: p.add_constraint(x >= 0) sage: p.set_objective(x + y + 7) sage: p.set_integer(x); p.set_integer(y) sage: p.solve() 9.0 - sage: p.remove_constraints([1]) + sage: p.remove_constraints([0]) sage: p.solve() 10.0 sage: p.get_values([x,y]) - [3.0, 0.0] + [0.0, 3.0] TESTS: diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index 8fa3cb94752..165392312f5 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -974,19 +974,17 @@ cdef class MixedIntegerLinearProgram(SageObject): A LP on two variables:: sage: p = MixedIntegerLinearProgram() - sage: v = p.new_variable(nonnegative=True) - sage: p.add_constraint(2*v['x'] + v['y'] <= 1) - sage: p.add_constraint(3*v['y'] + v['x'] <= 2) + sage: p.add_constraint(0 <= 2*p['x'] + p['y'] <= 1) + sage: p.add_constraint(0 <= 3*p['y'] + p['x'] <= 2) sage: P = p.polyhedron(); P A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices 3-D Polyhedron:: sage: p = MixedIntegerLinearProgram() - sage: v = p.new_variable(nonnegative=True) - sage: p.add_constraint(2*v['x'] + v['y'] + 3*v['z'] <= 1) - sage: p.add_constraint(2*v['y'] + v['z'] + 3*v['x'] <= 1) - sage: p.add_constraint(2*v['z'] + v['x'] + 3*v['y'] <= 1) + sage: p.add_constraint(0 <= 2*p['x'] + p['y'] + 3*p['z'] <= 1) + sage: p.add_constraint(0 <= 2*p['y'] + p['z'] + 3*p['x'] <= 1) + sage: p.add_constraint(0 <= 2*p['z'] + p['x'] + 3*p['y'] <= 1) sage: P = p.polyhedron(); P A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices @@ -1003,10 +1001,9 @@ cdef class MixedIntegerLinearProgram(SageObject): An unbounded polyhedron:: sage: p = MixedIntegerLinearProgram() - sage: v = p.new_variable(nonnegative=True) - sage: p.add_constraint(2*v['x'] + v['y'] - v['z'] <= 1) + sage: p.add_constraint(2*p['x'] + p['y'] - p['z'] <= 1) sage: P = p.polyhedron(); P - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 3 rays + A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 2 lines A square (see :trac:`14395`) :: From 2288445cebc253721e8495c1b8161cf3138b0a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Thu, 5 Nov 2015 20:21:07 +0100 Subject: [PATCH 1828/1872] Revert "Add parameter immutable to functions to_simple, to_directed and to_undirected" This reverts commit e772c76a06e90d7d5b7649b4c546e428e8ab2a11. Conflicts: src/sage/graphs/generic_graph.py --- src/sage/graphs/digraph.py | 22 +++++----------------- src/sage/graphs/generic_graph.py | 8 ++++---- src/sage/graphs/graph.py | 22 +++++----------------- 3 files changed, 14 insertions(+), 38 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index ef062c44889..3abc113977f 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -1071,26 +1071,20 @@ def is_directed_acyclic(self, certificate = False): """ return self._backend.is_directed_acyclic(certificate = certificate) - def to_directed(self, immutable=None): + def to_directed(self): """ Since the graph is already directed, simply returns a copy of itself. - INPUT: - - - ``immutable`` (boolean) -- whether to create a mutable/immutable - copy. ``immutable=None`` (default) means that the graph and its copy - will behave the same way. - EXAMPLES:: sage: DiGraph({0:[1,2,3],4:[5,1]}).to_directed() Digraph on 6 vertices """ - return self.copy(immutable=immutable) + return self.copy() def to_undirected(self, implementation='c_graph', data_structure=None, - sparse=None, immutable=None): + sparse=None): """ Returns an undirected version of the graph. Every directed edge becomes an edge. @@ -1105,10 +1099,6 @@ def to_undirected(self, implementation='c_graph', data_structure=None, ``data_structure="sparse"``, and ``sparse=False`` is an alias for ``data_structure="dense"``. - - ``immutable`` (boolean) -- whether to create a mutable/immutable - graph. ``immutable=None`` (default) means that the graph and its - undirected version will behave the same way. - EXAMPLES:: sage: D = DiGraph({0:[1,2],1:[0]}) @@ -1140,8 +1130,6 @@ def to_undirected(self, implementation='c_graph', data_structure=None, data_structure = "sparse" else: data_structure = "static_sparse" - if immutable is None: - immutable = (data_structure == "static_sparse") from sage.graphs.all import Graph G = Graph(name = self.name(), pos = self._pos, @@ -1157,8 +1145,8 @@ def to_undirected(self, implementation='c_graph', data_structure=None, G._embedding = copy(self._embedding) G._weighted = self._weighted - if immutable: - G=G.copy(data_structure="static_sparse") + if data_structure == "static_sparse": + G=G.copy(data_structure=data_structure) return G diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 1d880e1d79c..78b83a8e340 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16399,8 +16399,8 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): largest (``'max'``). - ``immutable`` (boolean) -- whether to create a mutable/immutable - copy. ``immutable=None`` (default) means that the graph and its copy - will behave the same way. + copy. ``immutable=None`` (default) means that the graph and its copy + will behave the same way. EXAMPLES:: @@ -16423,9 +16423,9 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): [(2, 3, 2), (3, 2, None)] """ if to_undirected: - g=self.to_undirected(immutable=False) + g=Graph(self) else: - g=self.copy(immutable=False) + g=copy(self) g.allow_loops(False) g.allow_multiple_edges(False, keep_label=keep_label) if immutable is None: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 0704bdf0cb4..b65505eb7d7 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4835,7 +4835,7 @@ def centrality_degree(self, v=None): ### Constructors def to_directed(self, implementation='c_graph', data_structure=None, - sparse=None, immutable=None): + sparse=None): """ Returns a directed version of the graph. A single edge becomes two edges, one in each direction. @@ -4850,10 +4850,6 @@ def to_directed(self, implementation='c_graph', data_structure=None, ``data_structure="sparse"``, and ``sparse=False`` is an alias for ``data_structure="dense"``. - - ``immutable`` (boolean) -- whether to create a mutable/immutable - digraph. ``immutable=None`` (default) means that the graph and its - directed version will behave the same way. - EXAMPLES:: sage: graphs.PetersenGraph().to_directed() @@ -4886,8 +4882,6 @@ def to_directed(self, implementation='c_graph', data_structure=None, data_structure = "sparse" else: data_structure = "static_sparse" - if immutable is None: - immutable = (data_structure == "static_sparse") from sage.graphs.all import DiGraph D = DiGraph(name = self.name(), pos = self._pos, @@ -4905,28 +4899,22 @@ def to_directed(self, implementation='c_graph', data_structure=None, D._embedding = copy(self._embedding) D._weighted = self._weighted - if immutable: - D = D.copy(data_structure="static_sparse") + if data_structure == "static_sparse": + D = D.copy(data_structure=data_structure) return D - def to_undirected(self, immutable=None): + def to_undirected(self): """ Since the graph is already undirected, simply returns a copy of itself. - INPUT: - - - ``immutable`` (boolean) -- whether to create a mutable/immutable - copy. ``immutable=None`` (default) means that the graph and its copy - will behave the same way. - EXAMPLES:: sage: graphs.PetersenGraph().to_undirected() Petersen graph: Graph on 10 vertices """ - return self.copy(immutable=immutable) + return self.copy() def join(self, other, verbose_relabel=None, labels="pairs", immutable=None): """ From ea67b0034642ecd69ff4482490a9386bceb05f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Thu, 5 Nov 2015 20:23:31 +0100 Subject: [PATCH 1829/1872] Replace self.to_undirected(immutable=False) with Graph(self) --- 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 78b83a8e340..2d6ef68e990 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -4239,7 +4239,7 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, # A local copy of self from sage.graphs.planarity import is_planar - graph = self.to_undirected(immutable=False) + graph = Graph(self) if hasattr(graph, '_embedding'): del(graph._embedding) @@ -4357,7 +4357,7 @@ def layout_planar(self, set_embedding=False, on_embedding=None, external_face=No """ from sage.graphs.schnyder import _triangulate, _normal_label, _realizer, _compute_coordinates - G = self.to_undirected(immutable=False) + G = Graph(self) try: G._embedding = self._embedding except AttributeError: From cca899d407910aea012d3e38ec71a62efd086bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Thu, 5 Nov 2015 23:03:55 +0100 Subject: [PATCH 1830/1872] Add is_immutable() --- src/sage/graphs/generic_graph.py | 47 ++++++++++++++++++++------------ src/sage/graphs/graph.py | 7 ++--- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 2d6ef68e990..55eb969c4fb 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -30,6 +30,7 @@ :meth:`~GenericGraph.allow_multiple_edges` | Change whether multiple edges are permitted in the (di)graph. :meth:`~GenericGraph.multiple_edges` | Return any multiple edges in the (di)graph. :meth:`~GenericGraph.name` | Return or sets the graph's name. + :meth:`~GenericGraph.is_immutable` | Returns whether the graph is immutable. :meth:`~GenericGraph.weighted` | Whether the (di)graph is to be considered as a weighted (di)graph. :meth:`~GenericGraph.antisymmetric` | Test whether the graph is antisymmetric :meth:`~GenericGraph.density` | Return the density @@ -571,7 +572,7 @@ def __hash__(self): True """ - if getattr(self, "_immutable", False): + if self.is_immutable(): edge_items = self.edge_iterator(labels = self._weighted) if self.allows_multiple_edges(): from collections import Counter @@ -796,6 +797,20 @@ def _repr_(self): name = self.name() + ": " + name return name + def is_immutable(self): + """ + Returns whether the graph is immutable. + + EXAMPLES: + + sage: G = graphs.PetersenGraph() + sage: G.is_immutable() + False + sage: Graph(G, immutable=True).is_immutable() + True + """ + return getattr(self, '_immutable', False) + ### Formats def copy(self, weighted=None, implementation='c_graph', data_structure=None, @@ -1013,7 +1028,7 @@ def copy(self, weighted=None, implementation='c_graph', data_structure=None, # If the users requests a mutable graph and input is immutable, we # chose the 'sparse' cgraph backend. Unless the user explicitly # asked for something different. - if getattr(self, '_immutable', False): + if self.is_immutable(): data_structure = 'dense' if sparse is False else 'sparse' elif sparse is True: data_structure = "sparse" @@ -1022,7 +1037,7 @@ def copy(self, weighted=None, implementation='c_graph', data_structure=None, # Immutable copy of an immutable graph ? return self ! # (if okay for weightedness) - if (getattr(self, '_immutable', False) and + if (self.is_immutable() and (weighted is None or self._weighted == weighted)): from sage.graphs.base.static_sparse_backend import StaticSparseBackend if (isinstance(self._backend, StaticSparseBackend) and @@ -2772,7 +2787,7 @@ def name(self, new=None): if new is None: return getattr(self, '_name', "") - if getattr(self, '_immutable', False): + if self.is_immutable(): raise NotImplementedError("An immutable graph does not change name") self._name = str(new) @@ -2962,7 +2977,7 @@ def weighted(self, new=None): """ if new is not None: - if getattr(self, '_immutable', False): + if self.is_immutable(): raise TypeError("This graph is immutable and can thus not be changed. " "Create a mutable copy, e.g., by `copy(g)`") if new in [True, False]: @@ -5237,10 +5252,7 @@ def is_cut_edge(self, u, v=None, label=None): if len([(uu,vv) for uu,vv,ll in self.edges_incident(u) if uu == v or vv == v]) > 1: return False - if getattr(self, '_immutable', False): - G = copy(self) - else: - G = self + G = self.copy(immutable=False) if self.is_immutable() else self G.delete_edge(u,v,label) if G.is_directed(): # (u,v) is a cut-edge if u is not in the connected @@ -5251,8 +5263,7 @@ def is_cut_edge(self, u, v=None, label=None): # self-(u,v) sol = not G.distance(u,v) < G.order() - if not getattr(self, '_immutable', False): - G.add_edge(u,v,label) + G.add_edge(u,v,label) return sol @@ -11394,7 +11405,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm setattr(G, attr,value) if immutable is None: - immutable = getattr(self, '_immutable', False) + immutable = self.is_immutable() if immutable: G = G.copy(immutable=True) @@ -11553,7 +11564,7 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, G.delete_edges(edges_to_delete) if not inplace: if immutable is None: - immutable = getattr(self, '_immutable', False) + immutable = self.is_immutable() if immutable: G = G.copy(immutable=True) return G @@ -16377,7 +16388,7 @@ def complement(self): for v in self: if not self.has_edge(u,v): G.add_edge(u,v) - if getattr(self, '_immutable', False): + if self.is_immutable(): return G.copy(immutable=True) return G @@ -16429,7 +16440,7 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): g.allow_loops(False) g.allow_multiple_edges(False, keep_label=keep_label) if immutable is None: - immutable = getattr(self, '_immutable', False) + immutable = self.is_immutable() if immutable: g = g.copy(immutable=True) return g @@ -16587,7 +16598,7 @@ def union(self, other, immutable=None): G.add_edges(other.edges()) if immutable is None: - immutable = getattr(self, "_immutable", False) and getattr(other, "_immutable", False) + immutable = self.is_immutable() and other.is_immutable() if immutable: G = G.copy(immutable=True) @@ -19549,7 +19560,7 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, check_input = check_input, complete_partial_function = complete_partial_function) - if getattr(self, "_immutable", False): + if self.is_immutable(): G = self.__class__(G, immutable = True) if return_map: @@ -19557,7 +19568,7 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, else: return G - if getattr(self, "_immutable", False): + if self.is_immutable(): raise ValueError("To relabel an immutable graph use inplace=False") # If perm is not a dictionary, we build one ! diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index b65505eb7d7..3f55e2fcc08 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1919,10 +1919,7 @@ def _recursive_spanning_trees(G,forest): forest = Graph([]) forest.add_vertices(self.vertices()) forest.add_edges(self.bridges()) - if getattr(self, "_immutable", False): - G = copy(self) - else: - G = self + G = self.copy(immutable=False) if self.is_immutable() else self return _recursive_spanning_trees(G, forest) else: return [] @@ -4988,7 +4985,7 @@ def join(self, other, verbose_relabel=None, labels="pairs", immutable=None): G.name('%s join %s'%(self.name(), other.name())) if immutable is None: - immutable = getattr(self, "_immutable", False) and getattr(other, "_immutable", False) + immutable = self.is_immutable() and other.is_immutable() if immutable: G = G.copy(immutable=True) From d891688defdc5ecfaee1c294ec1139b76af5f055 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 5 Nov 2015 20:26:47 -0300 Subject: [PATCH 1831/1872] Trac 19494: right code --- src/sage/combinat/words/finite_word.py | 43 +++++++++++++++++--------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 9beac17bdf4..63d0578108c 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -191,6 +191,7 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** +from collections import defaultdict from itertools import islice, izip, cycle from sage.combinat.words.abstract_word import Word_class from sage.combinat.words.words import Words @@ -4255,13 +4256,30 @@ def nb_subword_occurrences_in(self, other): EXAMPLES:: - sage: u = words.ThueMorseWord()[:1000] - sage: w = Word([0,1,0,1]) - sage: w.nb_subword_occurrences_in(u) + sage: tm = words.ThueMorseWord() + + sage: u = Word([0,1,0,1]) + sage: u.nb_subword_occurrences_in(tm[:1000]) 2604124996 + sage: u = Word([0,1,0,1,1,0]) + sage: u.nb_subword_occurrences_in(tm[:100]) + 20370432 + + .. NOTE:: + + This code actually compute the number of occurrences of all prefixes + of ``self`` as subwords in all prefixes of ``other``. In particular, + its complexity is bounded by ``len(self) * len(other)`` and one can + extract much more information from it rather than only the total + number of occurrences. + TESTS:: + sage: Word('').nb_subword_occurrences_in(Word('')) + 1 + sage: parent(_) + Integer Ring sage: v,u = Word(), Word('123') sage: v.nb_subword_occurrences_in(u) 1 @@ -4287,21 +4305,18 @@ def nb_subword_occurrences_in(self, other): (2001) 551-564. """ # record the position of letters in self - pos = {} + pos = defaultdict(list) for i,a in enumerate(self): - if a in pos: - pos[a].append(i) - else: - pos[a] = [i] + pos[a].append(i) + for a in pos: + pos[a].reverse() # compute the occurrences of all prefixes of self as subwords in other - occ = [0] * (len(self)+1) - occ[0] = 1 + occ = [ZZ.zero()] * (len(self)+1) + occ[0] = ZZ.one() for a in other: - l = pos.get(a) - if l is not None: - for i in l: - occ[i+1] += occ[i] + for i in pos[a]: + occ[i+1] += occ[i] # return only the number of occurrences of self return occ[-1] From 94635cc51e5ff4c02f13b6c7a65d944c07783374 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Fri, 6 Nov 2015 00:45:56 +0100 Subject: [PATCH 1832/1872] Updated Sage version to 6.10.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 feb64723094..5701b3c1bf6 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Sage version 6.10.beta2, released 2015-10-28 +Sage version 6.10.beta3, released 2015-11-05 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index c6a3fac1146..0ec9977aa41 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=d7f2ecde69b59bec3887fd0ba1f4e2784394fd6b -md5=fa6127892f72b56b96a592fcec729f25 -cksum=1455899060 +sha1=ff6a33eb58523267e51397577213b038fe81fe38 +md5=b694e1f431bb6f8fe6fbfc63b7640078 +cksum=1772005708 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 9f54fe3133b..190a18037c6 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -122 +123 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index f2a44eff412..23ca8c82c47 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath Version 6.10.beta2, Release Date: 2015-10-28 │ +│ SageMath Version 6.10.beta3, Release Date: 2015-11-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 9330d0a3dbb..c50d4aaa35a 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.10.beta2' -SAGE_RELEASE_DATE='2015-10-28' +SAGE_VERSION='6.10.beta3' +SAGE_RELEASE_DATE='2015-11-05' diff --git a/src/sage/version.py b/src/sage/version.py index 6de652178fb..f9d17c83c11 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.10.beta2' -date = '2015-10-28' +version = '6.10.beta3' +date = '2015-11-05' From b90f1349c53364924fd1ef179bf592702a68344d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Fri, 6 Nov 2015 00:52:04 +0100 Subject: [PATCH 1833/1872] Import sage.graphs.Graph where needed --- src/sage/graphs/generic_graph.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 55eb969c4fb..19933e361ef 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -4253,6 +4253,7 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, boundary = self # A local copy of self + from sage.graphs.graph import Graph from sage.graphs.planarity import is_planar graph = Graph(self) if hasattr(graph, '_embedding'): @@ -4370,6 +4371,7 @@ def layout_planar(self, set_embedding=False, on_embedding=None, external_face=No ... ValueError: Complete graph is not a planar graph """ + from sage.graphs.graph import Graph from sage.graphs.schnyder import _triangulate, _normal_label, _realizer, _compute_coordinates G = Graph(self) @@ -16434,6 +16436,7 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): [(2, 3, 2), (3, 2, None)] """ if to_undirected: + from sage.graphs.graph import Graph g=Graph(self) else: g=copy(self) From 63d9a27f7baaf23da309949f0c58fd149bf09af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Fri, 6 Nov 2015 00:57:11 +0100 Subject: [PATCH 1834/1872] Use is_immutable() in weakly_chordal.pyx --- src/sage/graphs/weakly_chordal.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/weakly_chordal.pyx b/src/sage/graphs/weakly_chordal.pyx index 6398d1510e3..db5ad37c6d9 100644 --- a/src/sage/graphs/weakly_chordal.pyx +++ b/src/sage/graphs/weakly_chordal.pyx @@ -110,7 +110,7 @@ def is_long_hole_free(g, certificate=False): g._scream_if_not_simple() cdef int a,b,c,i,u,v,d - if getattr(g, "_immutable", False): + if g.is_immutable(): g = g.copy(immutable=False) # relabel the graph on 0...n-1 @@ -282,7 +282,7 @@ def is_long_antihole_free(g, certificate = False): g._scream_if_not_simple() cdef int a,b,c,i,u,v,d - if getattr(g, "_immutable", False): + if g.is_immutable(): g = g.copy(immutable=False) # relabel the graph on 0...n-1 From 30752fa312661f537faf61171a4fe5db6b837856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Fri, 6 Nov 2015 01:20:01 +0100 Subject: [PATCH 1835/1872] Use is_immutable in tutte_polynomial.py --- 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 76719ecca2c..9c6540f5759 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -584,7 +584,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): if G.num_edges() == 0: return R.one() - if getattr(G, "_immutable", False): + if G.is_immutable(): G = G.copy(immutable=False) G.relabel(inplace=True) else: From fa6b8f6b84f3d05d9ece181a465c5f1c445575a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Fri, 6 Nov 2015 01:25:47 +0100 Subject: [PATCH 1836/1872] Use imperative in documentation index --- 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 19933e361ef..c5e6ae44a32 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -30,7 +30,7 @@ :meth:`~GenericGraph.allow_multiple_edges` | Change whether multiple edges are permitted in the (di)graph. :meth:`~GenericGraph.multiple_edges` | Return any multiple edges in the (di)graph. :meth:`~GenericGraph.name` | Return or sets the graph's name. - :meth:`~GenericGraph.is_immutable` | Returns whether the graph is immutable. + :meth:`~GenericGraph.is_immutable` | Return whether the graph is immutable. :meth:`~GenericGraph.weighted` | Whether the (di)graph is to be considered as a weighted (di)graph. :meth:`~GenericGraph.antisymmetric` | Test whether the graph is antisymmetric :meth:`~GenericGraph.density` | Return the density From 9c03d896e16379ce67fe8e8c2dc2e9e2c221d525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Fri, 6 Nov 2015 01:36:14 +0100 Subject: [PATCH 1837/1872] Fix indents in documentation --- src/sage/graphs/generic_graph.py | 16 ++++++++-------- src/sage/graphs/graph.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index c5e6ae44a32..9be6007ab4f 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -11140,8 +11140,8 @@ def subgraph(self, vertices=None, edges=None, inplace=False, on the number of vertices in the subgraph. - ``immutable`` (boolean) -- whether to create a mutable/immutable - subgraph. ``immutable=None`` (default) means that the graph and its - subgraph will behave the same way. + subgraph. ``immutable=None`` (default) means that the graph and its + subgraph will behave the same way. EXAMPLES:: @@ -11292,7 +11292,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm to be a function on edges, which is intersected with the edges specified, if any are. - - ``immutable`` (boolean) -- whether to create a mutable/immutable + - ``immutable`` (boolean) -- whether to create a mutable/immutable subgraph. ``immutable=None`` (default) means that the graph and its subgraph will behave the same way. @@ -11440,7 +11440,7 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, delete the extra vertices and edges from the current graph. This will modify the graph. - - ``immutable`` (boolean) -- whether to create a mutable/immutable + - ``immutable`` (boolean) -- whether to create a mutable/immutable subgraph. ``immutable=None`` (default) means that the graph and its subgraph will behave the same way. @@ -16464,8 +16464,8 @@ def disjoint_union(self, other, verbose_relabel=None, labels="pairs", will be relabeled with consecutive integers. - ``immutable`` (boolean) -- whether to create a mutable/immutable - disjoint union. ``immutable=None`` (default) means that the graphs - and their disjoint union will behave the same way. + disjoint union. ``immutable=None`` (default) means that the graphs + and their disjoint union will behave the same way. .. SEEALSO:: @@ -16542,8 +16542,8 @@ def union(self, other, immutable=None): INPUT: - ``immutable`` (boolean) -- whether to create a mutable/immutable - union. ``immutable=None`` (default) means that the graphs and their - union will behave the same way. + union. ``immutable=None`` (default) means that the graphs and their + union will behave the same way. .. SEEALSO:: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 3f55e2fcc08..f77b7844514 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4928,8 +4928,8 @@ def join(self, other, verbose_relabel=None, labels="pairs", immutable=None): will be relabeled with consecutive integers. - ``immutable`` (boolean) -- whether to create a mutable/immutable - join. ``immutable=None`` (default) means that the graphs and their - join will behave the same way. + join. ``immutable=None`` (default) means that the graphs and their + join will behave the same way. .. SEEALSO:: From c65866abe29c01477544944371bac5fee6325aff Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Thu, 5 Nov 2015 22:23:49 -0500 Subject: [PATCH 1838/1872] 19512: Attempt at implementing new is_morphism check --- .../schemes/product_projective/morphism.py | 54 ++++++++----------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/src/sage/schemes/product_projective/morphism.py b/src/sage/schemes/product_projective/morphism.py index c5f90f7121c..8efe970bb49 100644 --- a/src/sage/schemes/product_projective/morphism.py +++ b/src/sage/schemes/product_projective/morphism.py @@ -168,8 +168,9 @@ def __call__(self, P, check = True): def is_morphism(self): r""" - Returns ``True`` if ``self`` is a morphism of products of projective spaces. This is determined by checking - that the coordinates of ``self`` corresponding to each component space have no common zeros. + Returns ``True`` if ``self`` is a morphism of products of projective spaces. For each component space of + the domain of ``self`` we consider the subscheme generated by the corresponding set of coordinates of ``self``. + ``self`` is a morphism iff each of these subschemes has no points. OUTPUT: @@ -178,45 +179,34 @@ def is_morphism(self): EXAMPLES:: sage: Z. = ProductProjectiveSpaces([1,2],QQ) - sage: H = Hom(Z,Z) + sage: H = End(Z) sage: f = H([a^2,b^2,x*z-y*z,x^2-y^2,z^2]) sage: f.is_morphism() False :: - sage: Z. = ProductProjectiveSpaces([2,2],CC) - sage: H = Hom(Z,Z) - sage: f = H([a^3-a*b*c,b^3,c^3,x^2,x^2+y^2,CC.0*z^2]) + sage: P.=ProductProjectiveSpaces([2,2], QQ) + sage: H = End(P) + sage: f = H([u,v,w,u^2,v^2,w^2]) sage: f.is_morphism() True + + :: + + sage: P. = ProductProjectiveSpaces([2,2],QQ) + sage: H = End(P) + sage: f = H([x^2*u,y^2*w,z^2*v,w^2,u^2,v^2]) + sage: f.is_morphism() + False """ - Z = self.domain().ambient_space() - counter = 0 - for t in range(Z.num_components()): - M = Z.dimension_relative_components()[t] + 1 - R = Z._components[t].coordinate_ring() - F = [self._polys[k] for k in range(counter,M+counter)] - H = Hom(Z.coordinate_ring(),R) - l = [] - for i in range(0,len(Z.coordinate_ring().gens())): - if i in range(counter, M+counter): - l.append(R.gens()[i-counter]) - else: - l.append(R(0)) - phi = H(l) - F = [phi(f) for f in F] - - defpolys = list(Z._components[t].defining_polynomials()) - if R.base_ring().is_field(): - F.extend(defpolys) - J = R.ideal(F) - else: - S = PolynomialRing(R.base_ring().fraction_field(), R.gens(), R.ngens()) - L = [S(f) for f in F] + [S(f) for f in defpolys] - J = S.ideal(L) - if J.dimension() > 0: + m = 0 + T = self.domain().ambient_space() + for i in range(T.num_components()): + t = T[i].dimension_relative() + 1 + X = T.subscheme(list(self)[m : m + t]) + if X.dimension() > -1: return False - counter = counter + M + m = m + t return True \ No newline at end of file From 96b473af366e3753a379284bdf3b33cc094fe133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 6 Nov 2015 14:35:54 +0100 Subject: [PATCH 1839/1872] trac #19382 fixing the code --- src/sage/schemes/elliptic_curves/ell_rational_field.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 52a79939704..603ad38acca 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -6996,6 +6996,7 @@ def is_approx_integral(P): return xs + def elliptic_curve_congruence_graph(curves): r""" Return the congruence graph for this set of elliptic curves. @@ -7041,7 +7042,7 @@ def elliptic_curve_congruence_graph(curves): n = a_E[l] - a_F[l] if n != 0: p_edges = [p for p in p_edges if p.divides(n)] - if len(p_edges): - G.add_edge(E.cremona_label(), F.cremona_label()) - G.set_edge_label(i, j, str(p_edges)[1:-1]) + if len(p_edges): + G.add_edge(E.cremona_label(), F.cremona_label(), + p_edges) return G From c5751c497a1413329060a10d91aa028bcade0005 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 6 Nov 2015 14:49:16 +0100 Subject: [PATCH 1840/1872] Use future division in colors --- src/sage/plot/colors.py | 45 ++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index 6fbc369c3a9..cc5b4706e68 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -27,6 +27,8 @@ .. _cm: http://matplotlib.sourceforge.net/api/cm_api.html """ +from __future__ import division + #***************************************************************************** # 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 @@ -261,7 +263,7 @@ def html_to_float(c): h = '%s%s%s%s%s%s' % (h[0], h[0], h[1], h[1], h[2], h[2]) elif len(h) != 6: raise ValueError("color hex string (= '%s') must have length 3 or 6" % h) - return tuple([int(h[i:i + 2], base=16) / float(255) for i in [0, 2, 4]]) + return tuple([int(h[i:i + 2], base=16) / 255 for i in [0, 2, 4]]) def rgbcolor(c, space='rgb'): @@ -776,15 +778,14 @@ def __rmul__(self, left): """ return self * left - def __div__(self, right): + def __truediv__(self, right): """ Return a color whose RGB coordinates are this color's - coordinates divided by a scalar. This method is called for - "classic division." + coordinates divided by a scalar. INPUT: - - ``right`` - a float-convertible, non-zero number + - ``right`` -- a float-convertible, non-zero number OUTPUT: @@ -795,7 +796,7 @@ def __div__(self, right): sage: from sage.plot.colors import papayawhip, yellow sage: yellow / 4 RGB color (0.25, 0.25, 0.0) - sage: yellow.__div__(4) + sage: yellow.__truediv__(4) RGB color (0.25, 0.25, 0.0) sage: (papayawhip + Color(0.5, 0.5, 0.1) + yellow) / 3.0 RGB color (0.29166666666666663, 0.286437908496732, 0.07794117647058824) @@ -812,17 +813,16 @@ def __div__(self, right): ... TypeError: float() argument must be a string or a number """ - return self * (float(1.0) / float(right)) + return self * (1 / float(right)) - def __truediv__(self, right): + def __div__(self, right): """ Return a color whose RGB coordinates are this color's - coordinates divided by a scalar. This method is called for - "true division." + coordinates divided by a scalar. INPUT: - - ``right`` - a float-convertible, non-zero number + - ``right`` -- a float-convertible, non-zero number OUTPUT: @@ -830,16 +830,11 @@ def __truediv__(self, right): EXAMPLES:: - sage: from __future__ import division - sage: from sage.plot.colors import yellow, gold - sage: yellow / 4 - RGB color (0.25, 0.25, 0.0) - sage: yellow.__truediv__(4) + sage: from sage.plot.colors import yellow + sage: yellow.__div__(4) RGB color (0.25, 0.25, 0.0) - sage: gold / pi + yellow * e - RGB color (0.51829585732141..., 0.49333037605210..., 0.0) """ - return self.__div__(right) + return self / right def __int__(self): """ @@ -1022,7 +1017,7 @@ def html_color(self): """ return float_to_html(*self._rgb) - def lighter(self, fraction=1.0/3.0): + def lighter(self, fraction=1/3): """ Return a lighter "shade" of this RGB color by :meth:`blend`-ing it with white. This is **not** an inverse @@ -1030,7 +1025,7 @@ def lighter(self, fraction=1.0/3.0): INPUT: - - ``fraction`` - a float (default: 1.0/3.0); blending fraction + - ``fraction`` - a float (default: 1/3); blending fraction to apply OUTPUT: @@ -1051,14 +1046,14 @@ def lighter(self, fraction=1.0/3.0): """ return self.blend((1.0, 1.0, 1.0), fraction) - def darker(self, fraction=1.0/3.0): + def darker(self, fraction=1/3): """ Return a darker "shade" of this RGB color by :meth:`blend`-ing it with black. This is **not** an inverse of :meth:`lighter`. INPUT: - - ``fraction`` - a float (default: 1.0/3.0); blending fraction + - ``fraction`` - a float (default: 1/3); blending fraction to apply OUTPUT: @@ -1316,6 +1311,8 @@ def rainbow(n, format='hex'): sage: from sage.plot.colors import rainbow sage: rainbow(7) ['#ff0000', '#ffda00', '#48ff00', '#00ff91', '#0091ff', '#4800ff', '#ff00da'] + sage: rainbow(int(7)) + ['#ff0000', '#ffda00', '#48ff00', '#00ff91', '#0091ff', '#4800ff', '#ff00da'] sage: rainbow(7, 'rgbtuple') [(1.0, 0.0, 0.0), (1.0, 0.8571428571428571, 0.0), (0.2857142857142858, 1.0, 0.0), (0.0, 1.0, 0.5714285714285712), (0.0, 0.5714285714285716, 1.0), (0.2857142857142856, 0.0, 1.0), (1.0, 0.0, 0.8571428571428577)] @@ -1325,8 +1322,6 @@ def rainbow(n, format='hex'): - Karl-Dieter Crisman (directly use :func:`hsv_to_rgb` for hues) """ - from sage.rings.integer import Integer - n = Integer(n) # In case n is a Python int and i/n below would give 0! R = [] for i in range(n): From 0d0164cb64631a1f192cb886c2bde878d090e20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 6 Nov 2015 14:54:14 +0100 Subject: [PATCH 1841/1872] trac #18597 doc and code cleanup --- src/sage/categories/finite_coxeter_groups.py | 85 ++++++++++++-------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index d680c495208..e5d84203bca 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -303,11 +303,13 @@ def inversion_sequence(self, word): [[2], [1, 2, 1], [2, 3, 2], [1, 2, 3, 2, 1], [3], [1]] """ - return [self.from_reduced_word(word[:i+1]+list(reversed(word[:i]))) for i in range(len(word))] + return [self.from_reduced_word(word[:i+1]+list(reversed(word[:i]))) + for i in range(len(word))] def reflections_from_w0(self): """ - Return the reflections of ``self`` using the inversion set of ``w_0``. + Return the reflections of ``self`` using the inversion set + of ``w_0``. EXAMPLES:: @@ -331,19 +333,25 @@ def reflections_from_w0(self): @cached_method def m_cambrian_lattice(self, c, m=1, on_roots=False): """ - Return the m-Cambrian lattice on ``m``-delta sequences (see arXiv:1503.00710 and arXiv:math/0611106). - ``m``-delta sequences are certain ``m``-colored minimal factorizations of ``c`` into reflections. + Return the `m`-Cambrian lattice on `m`-delta sequences. + + See :arxiv:`1503.00710` and :arXiv:`math/0611106`. + + The `m`-delta sequences are certain `m`-colored minimal + factorizations of `c` into reflections. INPUT: - - ``c`` -- a Coxeter element of ``self`` (as a tuple, or as an element of ``self``) + - `c` -- a Coxeter element of ``self`` (as a tuple, or + as an element of ``self``) - - ``m`` -- a positive integer (default: 1) + - `m` -- a positive integer (optional, default 1) - - ``on_roots`` (optional) -- if ``on_roots`` is ``True``, - the lattice is realized on roots rather than on - reflections. In order for this to work, the ElementMethod - ``reflection_to_root`` must be available. + - ``on_roots`` (optional, default ``False``) -- if + ``on_roots`` is ``True``, the lattice is realized on + roots rather than on reflections. In order for this to + work, the ElementMethod ``reflection_to_root`` must be + available. EXAMPLES:: @@ -352,22 +360,25 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): sage: CoxeterGroup(["A",2]).m_cambrian_lattice((1,2),2) Finite lattice containing 12 elements - """ from sage.combinat.posets.lattices import LatticePoset - if hasattr(c,"reduced_word"): + if hasattr(c, "reduced_word"): c = c.reduced_word() c = list(c) + sorting_word = self.long_element().coxeter_sorting_word(c) + if on_roots: - if not hasattr(self.long_element(),"reflection_to_root"): - raise ValueError("The parameter 'on_root=True' needs the ElementMethod 'reflection_to_root'") - - inv_woc = [t.reflection_to_root() for t in self.inversion_sequence(self.long_element().coxeter_sorting_word(c))] + if not hasattr(self.long_element(), "reflection_to_root"): + raise ValueError("The parameter 'on_root=True' needs " + "the ElementMethod 'reflection_to_root'") + + inv_woc = [t.reflection_to_root() + for t in self.inversion_sequence(sorting_word)] S = [s.reflection_to_root() for s in self.simple_reflections()] - PhiP = [t.reflection_to_root() for t in self.reflections().keys()] + PhiP = [t.reflection_to_root() for t in self.reflections()] else: - inv_woc = self.inversion_sequence(self.long_element().coxeter_sorting_word(c)) + inv_woc = self.inversion_sequence(sorting_word) S = self.simple_reflections() T = self.reflections_from_w0() Twords = {t : t.reduced_word() for t in T} @@ -375,7 +386,7 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): elements = set() covers = [] - bottom_elt = frozenset((s,0) for s in S) + bottom_elt = frozenset((s, 0) for s in S) new = set([bottom_elt]) while new: new_element = new.pop() @@ -383,35 +394,38 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): for t in new_element: if t[1] < m: cov_element = [s for s in new_element if s != t] - cov_element.append((t[0],t[1]+1)) - for t_conj in [(i,t[1]) for i in inv_woc[inv_woc.index(t[0]):]]+[(i,t[1]+1) for i in inv_woc[:inv_woc.index(t[0])]]: + cov_element.append((t[0], t[1] + 1)) + idx_t0 = inv_woc.index(t[0]) + for t_conj in [(i, t[1]) for i in inv_woc[idx_t0:]] + [(i, t[1] + 1) for i in inv_woc[:idx_t0]]: if t_conj in cov_element: cov_element.remove(t_conj) if on_roots: tmp = t_conj[0].weyl_action(t[0].associated_reflection()) if tmp in PhiP: - cov_element.append(( tmp,t_conj[1] )) + cov_element.append((tmp, t_conj[1])) else: - cov_element.append((-tmp,t_conj[1]-1)) + cov_element.append((-tmp, t_conj[1] - 1)) else: - tmp = t[0]*t_conj[0]*t[0] + tmp = t[0] * t_conj[0] * t[0] invs = self.inversion_sequence(Twords[t[0]]+Twords[t_conj[0]]) plus_or_minus = invs.count(tmp) - if plus_or_minus % 2 == 1: - cov_element.append((tmp,t_conj[1] )) + if plus_or_minus % 2: + cov_element.append((tmp, t_conj[1])) else: - cov_element.append((tmp,t_conj[1]-1)) + cov_element.append((tmp, t_conj[1] - 1)) cov_element = frozenset(cov_element) if cov_element not in elements: new.add(cov_element) - covers.append((new_element,cov_element)) - return LatticePoset([elements,covers],cover_relations=True) + covers.append((new_element, cov_element)) + return LatticePoset([elements, covers], cover_relations=True) def cambrian_lattice(self, c, on_roots=False): """ - Return the c-Cambrian lattice on delta sequences, see - :arXiv:`1503.00710` and :arXiv:`math/0611106`. + Return the `c`-Cambrian lattice on delta sequences. + + See :arxiv:`1503.00710` and :arxiv:`math/0611106`. + Delta sequences are certain 2-colored minimal factorizations of ``c`` into reflections. @@ -420,10 +434,11 @@ def cambrian_lattice(self, c, on_roots=False): - ``c`` -- a standard Coxeter element in ``self`` (as a tuple, or as an element of ``self``) - - ``on_roots`` (optional) -- if ``on_roots`` is ``True``, - the lattice is realized on roots rather than on - reflections. In order for this to work, the ElementMethod - ``reflection_to_root`` must be available. + - ``on_roots`` (optional, default ``False``) -- if + ``on_roots`` is ``True``, the lattice is realized on + roots rather than on reflections. In order for this to + work, the ElementMethod ``reflection_to_root`` must be + available. EXAMPLES:: From 5607dac76b7409d68a72d501de00339b3bdbc6d2 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 6 Nov 2015 16:22:08 +0100 Subject: [PATCH 1842/1872] trac #19382: Leftover occurrence of 'elliptic_curve' --- src/sage/graphs/graph.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 346a47ffd0d..841f6be9214 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -534,8 +534,7 @@ class Graph(GenericGraph): ``"graph6"``, ``"sparse6"``, ``"rule"``, ``"list_of_edges"``, ``"dict_of_lists"``, ``"dict_of_dicts"``, ``"adjacency_matrix"``, ``"weighted_adjacency_matrix"``, ``"seidel_adjacency_matrix"``, - ``"incidence_matrix"``, ``"elliptic_curve_congruence"``, ``"NX"``, - ``"igraph"``. + ``"incidence_matrix"``, ``"NX"``, ``"igraph"``. - ``sparse`` (boolean) -- ``sparse=True`` is an alias for ``data_structure="sparse"``, and ``sparse=False`` is an alias for From c7185e90448cd68a3417fd5b634b99fb0e744933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jano=C5=A1=20Vidali?= Date: Fri, 6 Nov 2015 17:10:14 +0100 Subject: [PATCH 1843/1872] Add parameter immutable to relabel --- src/sage/graphs/generic_graph.py | 13 +++++++++++-- src/sage/graphs/tutte_polynomial.py | 6 +----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 9be6007ab4f..fd424f3d09c 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19362,7 +19362,7 @@ def eigenspaces(self, laplacian=False): ### Automorphism and isomorphism - def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, complete_partial_function = True): + def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, complete_partial_function = True, immutable = None): r""" Relabels the vertices of ``self`` @@ -19383,6 +19383,10 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, associated with any new name. In this case, those elements are not relabeled *This can potentially be very time-consuming !*. + - ``immutable`` (boolean) -- with ``inplace=False``, whether to create + a mutable/immutable relabelled copy. ``immutable=None`` (default) + means that the graph and its copy will behave the same way. + If ``perm`` is a function ``f``, then each vertex ``v`` is relabeled to ``f(v)``. @@ -19563,7 +19567,9 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, check_input = check_input, complete_partial_function = complete_partial_function) - if self.is_immutable(): + if immutable is None: + immutable = self.is_immutable() + if immutable: G = self.__class__(G, immutable = True) if return_map: @@ -19571,6 +19577,9 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, else: return G + if immutable: + raise ValueError("To make an immutable copy use inplace=False") + if self.is_immutable(): raise ValueError("To relabel an immutable graph use inplace=False") diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 9c6540f5759..d93a094909f 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -584,11 +584,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): if G.num_edges() == 0: return R.one() - if G.is_immutable(): - G = G.copy(immutable=False) - G.relabel(inplace=True) - else: - G = G.relabel(inplace=False) # making sure the vertices are integers + G = G.relabel(inplace=False, immutable=False) # making sure the vertices are integers G.allow_loops(True) G.allow_multiple_edges(True) From e3741280d9f8ece94c3f6aa0b333d9274e17cdfb Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 6 Nov 2015 15:35:55 -0300 Subject: [PATCH 1844/1872] Trac 19539: remove args and kwds in Graphics.plot --- src/sage/plot/graphics.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index d5c68742c62..0060343e12f 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -1128,7 +1128,7 @@ def add_primitive(self, primitive): """ self._objects.append(primitive) - def plot(self, *args, **kwds): + def plot(self): """ Draw a 2D plot of this graphics object, which just returns this object since this is already a 2D graphics object. @@ -1138,6 +1138,17 @@ def plot(self, *args, **kwds): sage: S = circle((0,0), 2) sage: S.plot() is S True + + It does not accept any argument (:trac:`19539`):: + + sage: S.plot(1) + Traceback (most recent call last): + ... + TypeError: plot() takes exactly 1 argument (2 given) + sage: S.plot(hey="hou") + Traceback (most recent call last): + ... + TypeError: plot() got an unexpected keyword argument 'hey' """ return self From 03dbb2eefc569424de29f6d36d875ba427eb7b2c Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 6 Nov 2015 20:21:20 -0300 Subject: [PATCH 1845/1872] Trac 19539: fix doctests --- src/sage/combinat/words/paths.py | 4 +++- src/sage/plot/plot.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 8e9083cfae2..5d64fc5907a 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -1731,7 +1731,9 @@ def plot_directive_vector(self, options=dict(rgbcolor='blue')): sage: p = P('aaaccaccacacacaccccccbbdd'); p Path: aaaccaccacacacaccccccbbdd sage: R = p.plot() + p.plot_directive_vector() - sage: R.plot(axes=False, aspect_ratio=1) + sage: R.axes(False) + sage: R.set_aspect_ratio(1) + sage: R.plot() Graphics object consisting of 4 graphics primitives TESTS: diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 907ef6cdaea..4dddab0bc89 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -1281,7 +1281,9 @@ def plot(funcs, *args, **kwds): funcs = tuple(funcs) - if hasattr(funcs, 'plot'): + if isinstance(funcs, Graphics): + G = funcs + elif hasattr(funcs, 'plot'): G = funcs.plot(*args, **original_opts) # if we are using the generic plotting method else: From f28a7df331d742ca60cee361cd245a1fe1a50832 Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Fri, 6 Nov 2015 22:13:22 -0500 Subject: [PATCH 1846/1872] 19512: adapted is_morphism to accomodate maps with different domains and codomains --- .../schemes/product_projective/morphism.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/product_projective/morphism.py b/src/sage/schemes/product_projective/morphism.py index 8efe970bb49..7baf06ce6ce 100644 --- a/src/sage/schemes/product_projective/morphism.py +++ b/src/sage/schemes/product_projective/morphism.py @@ -169,8 +169,8 @@ def __call__(self, P, check = True): def is_morphism(self): r""" Returns ``True`` if ``self`` is a morphism of products of projective spaces. For each component space of - the domain of ``self`` we consider the subscheme generated by the corresponding set of coordinates of ``self``. - ``self`` is a morphism iff each of these subschemes has no points. + the codomain of ``self`` we consider the subscheme of the domain of ``self`` generated by the corresponding + coordinates of ``self``. ``self`` is a morphism iff each of these subschemes has no points. OUTPUT: @@ -194,19 +194,21 @@ def is_morphism(self): :: - sage: P. = ProductProjectiveSpaces([2,2],QQ) - sage: H = End(P) - sage: f = H([x^2*u,y^2*w,z^2*v,w^2,u^2,v^2]) + sage: P. = ProductProjectiveSpaces([2,1],QQ) + sage: Q. = ProductProjectiveSpaces([1,2],QQ) + sage: H = Hom(P,Q) + sage: f = H([x^2,y^2,z^3,w^3,u^3]) sage: f.is_morphism() False """ m = 0 T = self.domain().ambient_space() - for i in range(T.num_components()): - t = T[i].dimension_relative() + 1 + S = self.codomain().ambient_space() + for i in range(S.num_components()): + t = S[i].dimension_relative() + 1 X = T.subscheme(list(self)[m : m + t]) if X.dimension() > -1: return False m = m + t - return True \ No newline at end of file + return True From 8e5fab74a07aced8c22482d287e8fd3cc5323466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Sat, 7 Nov 2015 14:13:46 +0100 Subject: [PATCH 1847/1872] Trac 19494: Changed the .. NOTE:: --- src/sage/combinat/words/finite_word.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 63d0578108c..458eab92c14 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -4268,11 +4268,10 @@ def nb_subword_occurrences_in(self, other): .. NOTE:: - This code actually compute the number of occurrences of all prefixes - of ``self`` as subwords in all prefixes of ``other``. In particular, - its complexity is bounded by ``len(self) * len(other)`` and one can - extract much more information from it rather than only the total - number of occurrences. + This code, based on [2], actually compute the number of + occurrences of all prefixes of ``self`` as subwords in all + prefixes of ``other``. In particular, its complexity is + bounded by ``len(self) * len(other)``. TESTS:: From 2b1cff1a4f2a756bd1130fadc5ee94a7386f3434 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 7 Nov 2015 10:00:31 -0600 Subject: [PATCH 1848/1872] Implement the chromatic quasisymmetric function of a graph. --- src/sage/graphs/graph.py | 105 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index e4d1c773fe2..7a03cf1fc63 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -3655,6 +3655,111 @@ def chromatic_symmetric_function(self, R=None): ret += (-1)**len(F) * p[la] return ret + @doc_index("Algorithmically hard stuff") + def chromatic_quasisymmetric_function(self, t=None, R=None): + r""" + Return the chromatic quasisymmetric function of ``self``. + + Let `G` be a graph. The chromatic quasisymmetric function `X_G(t)` + was first described in [SW12]_. We use the equivalent definition + given in [BC15]_: + + .. MATH:: + + X_G(t) = \sum_{\sigma=(\sigma_1,\ldots,\sigma_n)} + t^{\operatorname{asc}(\sigma) M_{|\sigma_1|,\ldots,|\sigma_n|}, + + where we sum over all ordered set partitions of the vertices of `G` + such that `\sigma_i` is an independent (i.e., stable) set of `G` + and `\operatorname{asc}(\sigma)` is the number of edges `\{u, v\}` + of `G` such that `u < v` and `v` appears in a later part of + `\sigma` than `u`. + + INPUT: + + - ``t`` -- (optional) the parameter `t`; uses the variable `t` + in `\ZZ[t]` by default + - ``R`` -- (optional) the base ring for the symmetric functions; + uses the parent of `t` by default + + EXAMPLES:: + + sage: G = graphs.PathGraph(4) + sage: XG = G.chromatic_quasisymmetric_function(); XG + (t^3+11*t^2+11*t+1)*M[1, 1, 1, 1] + (3*t^2+3*t)*M[1, 1, 2] + + (3*t^2+3*t)*M[1, 2, 1] + (3*t^2+3*t)*M[2, 1, 1] + + (t^2+t)*M[2, 2] + sage: XG.to_symmetric_function() + (t^3+11*t^2+11*t+1)*m[1, 1, 1, 1] + (3*t^2+3*t)*m[2, 1, 1] + + (t^2+t)*m[2, 2] + sage: G = graphs.CompleteGraph(4) + sage: G.chromatic_quasisymmetric_function() + (t^6+3*t^5+5*t^4+6*t^3+5*t^2+3*t+1)*M[1, 1, 1, 1] + + Not all chromatic quasisymmetric functions are symmetric:: + + sage: G = Graph([[1,2], [1,5], [3,4], [3,5]]) + sage: G.chromatic_quasisymmetric_function().is_symmetric() + False + + We check that at `t = 1`, we recover the usual chromatic + symmetric function:: + + sage: p = SymmetricFunctions(QQ).p() + sage: G = graphs.CycleGraph(5) + sage: XG = G.chromatic_quasisymmetric_function(t=1); XG + 120*M[1, 1, 1, 1, 1] + 30*M[1, 1, 1, 2] + 30*M[1, 1, 2, 1] + + 30*M[1, 2, 1, 1] + 10*M[1, 2, 2] + 30*M[2, 1, 1, 1] + + 10*M[2, 1, 2] + 10*M[2, 2, 1] + sage: p(XG.to_symmetric_function()) + p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1] + + 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5] + + sage: G = graphs.ClawGraph() + sage: XG = G.chromatic_quasisymmetric_function(t=1); XG + 24*M[1, 1, 1, 1] + 6*M[1, 1, 2] + 6*M[1, 2, 1] + M[1, 3] + + 6*M[2, 1, 1] + M[3, 1] + sage: p(XG.to_symmetric_function()) + p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4] + + REFERENCES: + + .. [SW12] John Shareshian and Michelle Wachs. + *Chromatic quasisymmetric functions and Hessenberg varieties*. + Configuration Spaces. CRM Series. Scuola Normale Superiore. + (2012) pp. 433-460. + http://www.math.miami.edu/~wachs/papers/chrom.pdf + + .. [BC15] Patrick Brosnan and Timothy Y. Chow. + *Unit interval orders and the dot action on the cohomology + of regular semisimple Hessenberg varieties*. + (2015) :arxiv:`1511.00773v1`. + """ + from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions + from sage.combinat.composition import Compositions + from sage.combinat.set_partition_ordered import OrderedSetPartitions + if t is None: + t = ZZ['t'].gen() + if R is None: + R = t.parent() + M = QuasiSymmetricFunctions(R).M() + ret = M.zero() + V = self.vertices() + def asc(sigma): + stat = 0 + for u in V: + for i,s in enumerate(sigma): + if u in s: + stat += sum(1 for p in sigma[i+1:] for v in p + if v > u and self.has_edge(u, v)) + break + return stat + for sigma in OrderedSetPartitions(V): + if any(not self.is_independent_set(s) for s in sigma): + continue + ret += M.term(sigma.to_composition(), t**asc(sigma)) + return ret + @doc_index("Leftovers") def matching(self, value_only=False, algorithm="Edmonds", use_edge_labels=True, solver=None, verbose=0): r""" From 41dcc536af4088bf58b4c13ae54c0ece72aa0e19 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 7 Nov 2015 13:03:02 -0300 Subject: [PATCH 1849/1872] Trac 19539: revert the change to the function plot --- src/sage/plot/plot.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 4dddab0bc89..907ef6cdaea 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -1281,9 +1281,7 @@ def plot(funcs, *args, **kwds): funcs = tuple(funcs) - if isinstance(funcs, Graphics): - G = funcs - elif hasattr(funcs, 'plot'): + if hasattr(funcs, 'plot'): G = funcs.plot(*args, **original_opts) # if we are using the generic plotting method else: From 82f3805f492bb7e9688043ae002315caef54dc83 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 7 Nov 2015 13:03:15 -0300 Subject: [PATCH 1850/1872] Trac 19539: fix ode_solver.plot_solutions --- src/sage/gsl/ode.pyx | 53 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/src/sage/gsl/ode.pyx b/src/sage/gsl/ode.pyx index c5c4538359c..0ecea9ab65d 100644 --- a/src/sage/gsl/ode.pyx +++ b/src/sage/gsl/ode.pyx @@ -231,10 +231,10 @@ class ode_solver(object): prince-dormand algorithm. :: sage: def f_1(t,y,params): - ... return[y[1],-y[0]-params[0]*y[1]*(y[0]**2-1.0)] + ....: return[y[1],-y[0]-params[0]*y[1]*(y[0]**2-1.0)] sage: def j_1(t,y,params): - ... return [ [0.0, 1.0],[-2.0*params[0]*y[0]*y[1]-1.0,-params[0]*(y[0]*y[0]-1.0)], [0.0, 0.0] ] + ....: return [ [0.0, 1.0],[-2.0*params[0]*y[0]*y[1]-1.0,-params[0]*(y[0]*y[0]-1.0)], [0.0, 0.0] ] sage: T=ode_solver() sage: T.algorithm="rk8pd" @@ -356,20 +356,49 @@ class ode_solver(object): object.__setattr__(self,name,value) def interpolate_solution(self,i=0): - l=eval('[ (x[0],x[1][i]) for x in solution]',{'solution':self.solution,'i':i}) - return sage.gsl.interpolation.spline(l) + pts = [(t,y[i]) for t,y in self.solution] + return sage.gsl.interpolation.spline(pts) + def plot_solution(self, i=0, filename=None, interpolate=False, **kwds): + r""" + Plot a one dimensional projection of the solution. - def plot_solution(self, i=0, filename=None, interpolate=False): - from sage.plot.all import plot, point - points=[] - for x in self.solution: - points.append(point((x[0],x[1][i]))) - t = plot(points) + INPUT: + + - ``i`` -- (non-negative integer) composant of the projection + + - ``filename`` -- (string or ``None``) whether to plot the picture or + save it in a file + + - ``interpolate`` -- whether to interpolate between the points of the + discretized solution + + - additional keywords are passed to the graphics primitive + + EXAMPLES:: + + sage: T = ode_solver() + sage: T.function = lambda t,y: [cos(y[0]) * sin(t)] + sage: T.jacobian = lambda t,y: [[-sin(y[0]) * sin(t)]] + sage: T.ode_solve(y_0=[1],t_span=[0,20],num_points=1000) + sage: T.plot_solution() + + And with some options:: + + sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) + """ + if interpolate: + from sage.plot.line import line2d + pts = self.interpolate_solution(i) + G = line2d(pts, **kwds) + else: + pts = [(t,y[i]) for t,y in self.solution] + from sage.plot.point import point2d + G = point2d([(t,y[i]) for t,y in self.solution], **kwds) if filename is None: - t.show() + G.show() else: - t.save(filename=filename) + G.save(filename=filename) def ode_solve(self,t_span=False,y_0=False,num_points=False,params=[]): import inspect From a322663068ebaa3473dceece77a5abab81689250 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 7 Nov 2015 13:29:45 -0300 Subject: [PATCH 1851/1872] Trac 19539: fix more doctests --- src/doc/de/thematische_anleitungen/sage_gymnasium.rst | 6 +++--- src/doc/en/thematic_tutorials/numerical_sage/scipy.rst | 4 ++-- src/sage/tests/french_book/nonlinear_doctest.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/de/thematische_anleitungen/sage_gymnasium.rst b/src/doc/de/thematische_anleitungen/sage_gymnasium.rst index f185bee6ac8..9b7da4cc927 100644 --- a/src/doc/de/thematische_anleitungen/sage_gymnasium.rst +++ b/src/doc/de/thematische_anleitungen/sage_gymnasium.rst @@ -916,7 +916,7 @@ Die Addition von Vektoren könnte also zum Beispiel wie folgt veranschaulicht we sage: v1 = arrow((0,0), (3,4)) sage: v2 = arrow((3,4), (6,1)) sage: sum_v1_v2 = arrow((0,0), (6,1), color='red') - sage: plot(v1 + v2 + sum_v1_v2) + sage: v1 + v2 + sum_v1_v2 Graphics object consisting of 3 graphics primitives Falls die Vektorpfeile zu dick oder zu dünn sind, kann mit der ``width`` Option die Strichbreite angepasst werden. @@ -926,8 +926,8 @@ in der Grafik erwünscht sind:: sage: v1 = arrow((0,0), (3,4), width=5) sage: v2 = arrow((3,4), (6,1), width=5) sage: sum_v1_v2 = arrow((0,0), (6,1), color='red', width=6) - sage: plot(v1 + v2 + sum_v1_v2, gridlines=true) - Graphics object consisting of 3 graphics primitives + sage: G = v1 + v2 + sum_v1_v2 + sage: G.show(gridlines=true) Analysis ======== diff --git a/src/doc/en/thematic_tutorials/numerical_sage/scipy.rst b/src/doc/en/thematic_tutorials/numerical_sage/scipy.rst index 65a516abf49..6cc185b4095 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/scipy.rst +++ b/src/doc/en/thematic_tutorials/numerical_sage/scipy.rst @@ -104,8 +104,8 @@ We could plot the solution if we wanted by doing :: - sage: p=[point((x[i],y[i][0])) for i in range(len(x))] - sage: plot(p).show() + sage: pts = [(x[i],y[i][0]) for i in range(len(x))] + sage: point2d(pts).show() Optimization ------------ diff --git a/src/sage/tests/french_book/nonlinear_doctest.py b/src/sage/tests/french_book/nonlinear_doctest.py index e51096a073e..de863f13ea0 100644 --- a/src/sage/tests/french_book/nonlinear_doctest.py +++ b/src/sage/tests/french_book/nonlinear_doctest.py @@ -45,7 +45,7 @@ ....: v.extend(R(c).roots(multiplicities=False)) ....: return v sage: data = build_complex_roots(12) # long time - sage: g = plot(points(data, pointsize=1), aspect_ratio=1) # long time + sage: g = points(data, pointsize=1, aspect_ratio=1) # long time Sage example in ./nonlinear.tex, line 275:: From 121ad6e3a31d7fb2e173900747fdc49ce9199619 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 7 Nov 2015 11:56:01 -0500 Subject: [PATCH 1852/1872] optimization, I guess --- src/sage/graphs/graph.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 7a03cf1fc63..f20e0c27fe1 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -3660,30 +3660,36 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): r""" Return the chromatic quasisymmetric function of ``self``. - Let `G` be a graph. The chromatic quasisymmetric function `X_G(t)` - was first described in [SW12]_. We use the equivalent definition + Let `G` be a graph whose vertex set is totally ordered. The + chromatic quasisymmetric function `X_G(t)` was first + described in [SW12]_. We use the equivalent definition given in [BC15]_: .. MATH:: X_G(t) = \sum_{\sigma=(\sigma_1,\ldots,\sigma_n)} - t^{\operatorname{asc}(\sigma) M_{|\sigma_1|,\ldots,|\sigma_n|}, + t^{\operatorname{asc}(\sigma)} + M_{|\sigma_1|,\ldots,|\sigma_n|}, - where we sum over all ordered set partitions of the vertices of `G` - such that `\sigma_i` is an independent (i.e., stable) set of `G` - and `\operatorname{asc}(\sigma)` is the number of edges `\{u, v\}` - of `G` such that `u < v` and `v` appears in a later part of - `\sigma` than `u`. + where we sum over all ordered set partitions of the vertex + set of `G` such that each block `\sigma_i` is an independent + (i.e., stable) set of `G`, and where + `\operatorname{asc}(\sigma)` denotes the number of edges + `\{u, v\}` of `G` such that `u < v` and `v` appears in a + later part of `\sigma` than `u`. INPUT: - ``t`` -- (optional) the parameter `t`; uses the variable `t` in `\ZZ[t]` by default - - ``R`` -- (optional) the base ring for the symmetric functions; - uses the parent of `t` by default + - ``R`` -- (optional) the base ring for the quasisymmetric + functions; uses the parent of `t` by default EXAMPLES:: + sage: G = Graph([[1,2,3], [[1,3], [2,3]]]) + sage: G.chromatic_quasisymmetric_function() + (2*t^2+2*t+2)*M[1, 1, 1] + M[1, 2] + t^2*M[2, 1] sage: G = graphs.PathGraph(4) sage: XG = G.chromatic_quasisymmetric_function(); XG (t^3+11*t^2+11*t+1)*M[1, 1, 1, 1] + (3*t^2+3*t)*M[1, 1, 2] @@ -3747,12 +3753,10 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): V = self.vertices() def asc(sigma): stat = 0 - for u in V: - for i,s in enumerate(sigma): - if u in s: - stat += sum(1 for p in sigma[i+1:] for v in p - if v > u and self.has_edge(u, v)) - break + for i, s in enumerate(sigma): + for u in s: + stat += sum(1 for p in sigma[i+1:] for v in p + if v > u and self.has_edge(u, v)) return stat for sigma in OrderedSetPartitions(V): if any(not self.is_independent_set(s) for s in sigma): From f3e8482548d9e10dd174296f982b32c3054f76b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Sat, 7 Nov 2015 21:25:51 +0200 Subject: [PATCH 1853/1872] Check 0- and 1-element graphs on is_cartesian_product(). --- src/sage/graphs/graph_decompositions/graph_products.pyx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/graph_decompositions/graph_products.pyx b/src/sage/graphs/graph_decompositions/graph_products.pyx index fecd8d48af1..5ab75da1682 100644 --- a/src/sage/graphs/graph_decompositions/graph_products.pyx +++ b/src/sage/graphs/graph_decompositions/graph_products.pyx @@ -212,6 +212,13 @@ def is_cartesian_product(g, certificate = False, relabeling = False): sage: g = graphs.WagnerGraph() sage: g.is_cartesian_product() False + + Empty and one-element graph (:trac:`19546`):: + + sage: Graph().is_cartesian_product() + False + sage: Graph({0:[]}).is_cartesian_product() + False """ g._scream_if_not_simple() if relabeling: @@ -221,7 +228,7 @@ def is_cartesian_product(g, certificate = False, relabeling = False): H = g # Of course the number of vertices of g can not be prime ! - if Integer(g.order()).is_prime(): + if g.order() <= 1 or Integer(g.order()).is_prime(): return (False, None) if relabeling else False if not g.is_connected(): raise ValueError("The graph must be connected !") From ee5676f3f02327ba15d9b9c13d337b4543b696a5 Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Sat, 7 Nov 2015 15:21:51 -0500 Subject: [PATCH 1854/1872] 19512: base rings no longer required to be fields --- src/sage/schemes/product_projective/morphism.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/product_projective/morphism.py b/src/sage/schemes/product_projective/morphism.py index 7baf06ce6ce..8458d03c70c 100644 --- a/src/sage/schemes/product_projective/morphism.py +++ b/src/sage/schemes/product_projective/morphism.py @@ -178,7 +178,7 @@ def is_morphism(self): EXAMPLES:: - sage: Z. = ProductProjectiveSpaces([1,2],QQ) + sage: Z. = ProductProjectiveSpaces([1,2],ZZ) sage: H = End(Z) sage: f = H([a^2,b^2,x*z-y*z,x^2-y^2,z^2]) sage: f.is_morphism() @@ -204,9 +204,16 @@ def is_morphism(self): m = 0 T = self.domain().ambient_space() S = self.codomain().ambient_space() + + if T.base_ring().is_field(): + f = self + else: + f = self.change_ring(T.base_ring().fraction_field()) + T = T.change_ring(T.base_ring().fraction_field()) + for i in range(S.num_components()): t = S[i].dimension_relative() + 1 - X = T.subscheme(list(self)[m : m + t]) + X = T.subscheme(list(f)[m : m + t]) if X.dimension() > -1: return False m = m + t From 4c7cb931a9b80cde29d55e31a1fb219f20a4899b Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sat, 7 Nov 2015 17:41:10 +0000 Subject: [PATCH 1855/1872] construction implemented, and it works! more tests to add, and hook it up into SRGs DB fixed formatting issue and and removed one map(lambda...) and rewritten lambda with def... --- src/sage/graphs/generators/families.py | 112 +++++++++++++++++++++++++ src/sage/graphs/graph_generators.py | 2 + 2 files changed, 114 insertions(+) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index a6ebc74c6b6..fd015e91160 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2470,3 +2470,115 @@ def MathonPseudocyclicMergingGraph(M, t): if t > 1: A += sum(map(lambda x: M[0].tensor_product(x), M[1:])) return Graph(A) + +def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): + r""" + Return a strongly regular graph on `(4t+1)(4t-1)^2` vertices from [Mat78]_ + + Let `4t-1` be a prime power, and `4t+1` be such that there exists + a strongly regular graph `G` with parameters `(4t+1,2t,t-1,t)`. With + this input, Mathon [Mat78]_ gives a construction of a strongly regular + graph with parameters `(4 \mu + 1, 2 \mu, \mu-1, \mu)`, where + `\mu = t(4t(4t-1)-1)`. The construction is optionally parametrised by an + a skew-symmetric Latin square of order `4t+1`, with entries in + `-2t,...,-1,0,1,...,2t`. + + Our implementation follows a description given in [ST78]_. + + INPUT: + + - ``t`` -- a positive integer + + - ``G`` -- if `None` (default), try to construct the necessary graph + with parameters `(4t+1,2t,t-1,t)`, otherwise use the user-supplied one, + with vertices labelled from `0` to `4t`. + + - ``L`` -- if `None` (default), construct a necessary skew Latin square, + otherwise use the user-supplied one. + + EXAMPLES:: + + sage: from sage.graphs.generators.families import MathonPseudocyclicStronglyRegularGraph + sage: G=MathonPseudocyclicStronglyRegularGraph(1); G + Mathon's PC SRG on 45 vertices: Graph on 45 vertices + sage: G.is_strongly_regular(parameters=True) + (45, 22, 10, 11) + + TESTS:: + + sage: G=MathonPseudocyclicStronglyRegularGraph(2); G # long time + Mathon's PC SRG on 441 vertices: Graph on 441 vertices + sage: G.is_strongly_regular(parameters=True) # long time + (441, 220, 109, 110) + + + REFERENCES: + + .. [Mat78] R. A. Mathon, + Symmetric conference matrices of order `pq^2 + 1`, + Canad. J. Math. 30 (1978) 321-331 + + .. [ST78] J. J. Seidel and D. E. Taylor, + Two-graphs, a second survey. + Algebraic methods in graph theory, Vol. I, II (Szeged, 1978), pp. 689–711, + Colloq. Math. Soc. János Bolyai, 25, + North-Holland, Amsterdam-New York, 1981. + """ + from sage.rings.finite_rings.constructor import FiniteField as GF + from sage.rings.integer_ring import ZZ + from sage.matrix.constructor import matrix, block_matrix, \ + ones_matrix, identity_matrix + from sage.graphs.graph import Graph + from itertools import product + p = 4*t+1 + if G is None: + from sage.graphs.strongly_regular_db import strongly_regular_graph as SRG + G = SRG(p, 2*t, t-1) + G.relabel() + if L is None: + from sage.matrix.constructor import circulant + L = circulant(range(2*t+1)+map(lambda i: -2*t+i, range(2*t))) + q = 4*t -1 + K = GF(q,conway=True,prefix='x') + # Order the elements of K in K_list + # so that K_list[i] = -K_list[n-i-1], and 0 comes last + K_pairs = set(frozenset([x,-x]) for x in K) + K_pairs.discard(frozenset([0])) + a = [None]*(q-1) + for i,(x,y) in enumerate(K_pairs): + a[i] = x + a[-i-1] = y + a.append(K(0)) + P = map(lambda b: matrix(ZZ,q,q,lambda i,j: 1 if a[j]==a[i]+b else 0), a) + g = K.primitive_element() + F = sum(P[a.index(g**(2*i))] for i in xrange(1, 2*t)) + E = matrix(ZZ,q,q, lambda i,j: 0 if (a[j]-a[0]).is_square() else 1) + def B(m): + I = identity_matrix(q) + J = ones_matrix(q) + if m == 0: + f = lambda (i, j): 0*I if i==j else\ + I+F if (a[j]-a[i]).is_square() else\ + J-F + elif m < 2*t: + f = lambda (i, j): F*P[a.index(g**(2*m) * (a[i]+a[j]))] + elif m == 2*t: + f = lambda (i, j): E*P[i] + return block_matrix(q,q, map(f, product(xrange(q), xrange(q)))) + + def Acon((i, j)): + J = ones_matrix(q**2) + if i==j: + return B(0) + if L[i,j]>0: + if G.has_edge(i,j): + return B(L[i,j]) + return J-B(L[i,j]) + if G.has_edge(i,j): + return B(-L[i,j]).T + return J-B(-L[i,j]).T + + A = Graph(block_matrix(p, p, map(Acon, product(xrange(p), xrange(p))))) + A.name("Mathon's PC SRG on "+str(p*q**2)+" vertices") + A.relabel() + return A diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 8f44a191a0c..e660f37bca9 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -212,6 +212,7 @@ def __append_to_doc(methods): "LCFGraph", "line_graph_forbidden_subgraphs", "MathonPseudocyclicMergingGraph", + "MathonPseudocyclicStronglyRegularGraph", "MycielskiGraph", "MycielskiStep", "NKStarGraph", @@ -1990,6 +1991,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None LCFGraph = staticmethod(sage.graphs.generators.families.LCFGraph) line_graph_forbidden_subgraphs = staticmethod(sage.graphs.generators.families.line_graph_forbidden_subgraphs) MathonPseudocyclicMergingGraph = staticmethod(sage.graphs.generators.families.MathonPseudocyclicMergingGraph) + MathonPseudocyclicStronglyRegularGraph = staticmethod(sage.graphs.generators.families.MathonPseudocyclicStronglyRegularGraph) MycielskiGraph = staticmethod(sage.graphs.generators.families.MycielskiGraph) MycielskiStep = staticmethod(sage.graphs.generators.families.MycielskiStep) NKStarGraph = staticmethod(sage.graphs.generators.families.NKStarGraph) From ffdcb3762bd47cfac91c6dd4e1330cf0810f0a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Sun, 8 Nov 2015 19:44:39 +0200 Subject: [PATCH 1856/1872] Change few 'method' to 'algorithm'. --- src/sage/graphs/generic_graph.py | 126 ++++++++++++++------------- src/sage/graphs/graph.py | 145 ++++++++++++++++--------------- 2 files changed, 138 insertions(+), 133 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 35523ab9145..a3ab9d27d90 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -314,6 +314,7 @@ from generic_graph_pyx import GenericGraph_pyx, spring_layout_fast from sage.graphs.dot2tex_utils import assert_have_dot2tex from sage.misc.superseded import deprecation, deprecated_function_alias +from sage.misc.decorators import rename_keyword class GenericGraph(GenericGraph_pyx): """ @@ -5716,14 +5717,14 @@ def edge_disjoint_spanning_trees(self,k, root=None, solver = None, verbose = 0): return classes - def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, method="FF", solver=None, verbose=0): + @rename_keyword(deprecation=19550, method='algorithm=') + def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, algorithm="FF", solver=None, verbose=0): r""" - Returns a minimum edge cut between vertices `s` and `t` - represented by a list of edges. + Return a minimum edge cut between vertices `s` and `t`. A minimum edge cut between two vertices `s` and `t` of self is a set `A` of edges of minimum weight such that the graph - obtained by removing `A` from self is disconnected. For more + obtained by removing `A` from the graph is disconnected. For more information, see the `Wikipedia article on cuts `_. @@ -5749,22 +5750,21 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, Note: ``vertices=True`` implies ``value_only=False``. - - ``method`` -- There are currently two different - implementations of this method : + - ``algorithm`` -- algorithm to use: - * If ``method = "FF"``, a Python implementation of the - Ford-Fulkerson algorithm is used + * If ``algorithm = "FF"``, a Python implementation of the + Ford-Fulkerson algorithm is used - * If ``method = "LP"``, the flow problem is solved using - Linear Programming. + * If ``algorithm = "LP"``, the flow problem is solved using + Linear Programming. - * If ``method = "igraph"``, the igraph implementation of the - Goldberg-Tarjan algorithm is used (only available when - igraph is installed) + * If ``algorithm = "igraph"``, the igraph implementation of the + Goldberg-Tarjan algorithm is used (only available when + igraph is installed) - * If ``method = None`` (default), we use ``LP`` if - ``vertex_bound = True``, otherwise, we use ``igraph`` if - it is available, ``FF`` if it is not available. + * If ``algorithm = None`` (default), we use ``LP`` if + ``vertex_bound = True``, otherwise, we use ``igraph`` if + it is available, ``FF`` if it is not available. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) solver to be used. If set to ``None``, the default one is used. For @@ -5829,39 +5829,39 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, TESTS: - If method is set to an exotic value:: + If algorithm is set to an exotic value:: sage: g = graphs.PetersenGraph() - sage: g.edge_cut(0,1, method="Divination") + sage: g.edge_cut(0, 1, algorithm="Divination") Traceback (most recent call last): ... - ValueError: The method argument has to be equal to "FF", "LP", "igraph", or None + ValueError: The algorithm argument has to be equal to "FF", "LP", "igraph", or None Same result for all three methods:: sage: g = graphs.RandomGNP(20,.3) sage: for u,v in g.edges(labels=False): ... g.set_edge_label(u,v,round(random(),5)) - sage: g.edge_cut(0,1, method="FF") == g.edge_cut(0,1,method="LP") + sage: g.edge_cut(0, 1, algorithm="FF") == g.edge_cut(0, 1, algorithm="LP") True - sage: g.edge_cut(0,1, method="FF") == g.edge_cut(0,1,method="igraph") # optional - python_igraph + sage: g.edge_cut(0, 1, algorithm="FF") == g.edge_cut(0, 1, algorithm="igraph") # optional - python_igraph True Rounded return value when using the LP method:: sage: g = graphs.PappusGraph() - sage: g.edge_cut(1, 2, value_only=True, method = "LP") + sage: g.edge_cut(1, 2, value_only=True, algorithm="LP") 3 :trac:`12797`:: sage: G = Graph([(0, 3, 1), (0, 4, 1), (1, 2, 1), (2, 3, 1), (2, 4, 1)]) - sage: G.edge_cut(0,1,value_only=False,use_edge_labels=True) + sage: G.edge_cut(0, 1, value_only=False, use_edge_labels=True) [1, [(1, 2, 1)]] sage: G = DiGraph([(0, 3, 1), (0, 4, 1), (2, 1, 1), (3, 2, 1), (4, 2, 1)]) - sage: G.edge_cut(0,1,value_only=False,use_edge_labels=True) + sage: G.edge_cut(0, 1, value_only=False, use_edge_labels=True) [1, [(2, 1, 1)]] - sage: G.edge_cut(0,1,value_only=False,use_edge_labels=True,method='LP') + sage: G.edge_cut(0, 1, value_only=False, use_edge_labels=True, algorithm='LP') (1.0, [(2, 1)]) """ self._scream_if_not_simple(allow_loops=True) @@ -5873,14 +5873,14 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, else: weight = lambda x: 1 - if method in ["FF", "igraph", None]: + if algorithm in ["FF", "igraph", None]: if value_only: - return self.flow(s,t,value_only=value_only,use_edge_labels=use_edge_labels, method=method) + return self.flow(s,t,value_only=value_only,use_edge_labels=use_edge_labels, algorithm=algorithm) from sage.graphs.digraph import DiGraph g = DiGraph(self) - flow_value, flow_graph = self.flow(s,t,value_only=value_only,use_edge_labels=use_edge_labels, method=method) + flow_value, flow_graph = self.flow(s,t,value_only=value_only,use_edge_labels=use_edge_labels, algorithm=algorithm) for u,v,l in flow_graph.edge_iterator(): g.add_edge(v,u) @@ -5899,8 +5899,8 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, return return_value - if method != "LP": - raise ValueError("The method argument has to be equal to \"FF\", " + + if algorithm != "LP": + raise ValueError("The algorithm argument has to be equal to \"FF\", " + "\"LP\", \"igraph\", or None") from sage.numerical.mip import MixedIntegerLinearProgram @@ -7617,7 +7617,8 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constrai return [v for v in self if b_sol[v] == 1] - def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, vertex_bound=False, method = None, solver=None, verbose=0): + @rename_keyword(deprecation=19550, method='algorithm=') + def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, vertex_bound=False, algorithm = None, solver=None, verbose=0): r""" Returns a maximum flow in the graph from ``x`` to ``y`` represented by an optimal valuation of the edges. For more @@ -7670,21 +7671,21 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, verte a vertex different from `x` to `1` (useful for vertex connectivity parameters). - - ``method`` -- There are currently two different - implementations of this method : + - ``algorithm`` -- There are currently three different + implementations of this method: - * If ``method = "FF"``, a Python implementation of the + * If ``algorithm = "FF"``, a Python implementation of the Ford-Fulkerson algorithm is used (only available when ``vertex_bound = False``) - * If ``method = "LP"``, the flow problem is solved using + * If ``algorithm = "LP"``, the flow problem is solved using Linear Programming. - * If ``method = "igraph"``, the igraph implementation of the + * If ``algorithm = "igraph"``, the igraph implementation of the Goldberg-Tarjan algorithm is used (only available when igraph is installed and ``vertex_bound = False``) - * If ``method = None`` (default), we use ``LP`` if + * If ``algorithm = None`` (default), we use ``LP`` if ``vertex_bound = True``, otherwise, we use ``igraph`` if it is available, ``FF`` if it is not available. @@ -7754,41 +7755,41 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, verte An exception if raised when forcing "FF" or "igraph" with ``vertex_bound = True``:: sage: g = graphs.PetersenGraph() - sage: g.flow(0,1,vertex_bound = True, method = "FF") + sage: g.flow(0,1,vertex_bound = True, algorithm = "FF") Traceback (most recent call last): ... - ValueError: This method does not support both vertex_bound=True and method='FF'. - sage: g.flow(0,1,vertex_bound = True, method = "igraph") + ValueError: This method does not support both vertex_bound=True and algorithm='FF'. + sage: g.flow(0,1,vertex_bound = True, algorithm = "igraph") Traceback (most recent call last): ... - ValueError: This method does not support both vertex_bound=True and method='igraph'. + ValueError: This method does not support both vertex_bound=True and algorithm='igraph'. Or if the method is different from the expected values:: - sage: g.flow(0,1, method="Divination") + sage: g.flow(0,1, algorithm="Divination") Traceback (most recent call last): ... - ValueError: The method argument has to be equal to either "FF", "LP", "igraph", or None + ValueError: The algorithm argument has to be equal to either "FF", "LP", "igraph", or None - The two methods are indeed returning the same results (possibly with + The two algorithms are indeed returning the same results (possibly with some numerical noise, cf. :trac:`12362`):: sage: g = graphs.RandomGNP(20,.3) sage: for u,v in g.edges(labels=False): ... g.set_edge_label(u,v,round(random(),5)) - sage: flow_ff = g.flow(0,1, method="FF") - sage: flow_lp = g.flow(0,1, method="LP") + sage: flow_ff = g.flow(0,1, algorithm="FF") + sage: flow_lp = g.flow(0,1, algorithm="LP") sage: abs(flow_ff-flow_lp) < 0.01 True - sage: flow_igraph = g.flow(0,1, method="igraph") # optional python_igraph + sage: flow_igraph = g.flow(0,1, algorithm="igraph") # optional python_igraph sage: abs(flow_ff-flow_igraph) < 0.00001 # optional python_igraph True """ from sage.misc.package import is_package_installed self._scream_if_not_simple(allow_loops=True) - if vertex_bound and method in ["FF", "igraph"]: + if vertex_bound and algorithm in ["FF", "igraph"]: raise ValueError("This method does not support both " + - "vertex_bound=True and method='" + method + "'.") + "vertex_bound=True and algorithm='" + algorithm + "'.") if use_edge_labels: from sage.rings.real_mpfr import RR if integer: @@ -7799,17 +7800,17 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, verte else: capacity=lambda x: 1 - if method is None: + if algorithm is None: if vertex_bound: - method = "LP" + algorithm = "LP" elif is_package_installed("python_igraph"): - method = "igraph" + algorithm = "igraph" else: - method = "FF" + algorithm = "FF" - if (method == "FF"): + if (algorithm == "FF"): return self._ford_fulkerson(x,y, value_only=value_only, integer=integer, use_edge_labels=use_edge_labels) - elif (method == 'igraph'): + elif (algorithm == 'igraph'): try: import igraph @@ -7851,8 +7852,8 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, verte flow_digraph.relabel({i:vertices[i] for i in flow_digraph}) return [maxflow.value, flow_digraph] - if method != "LP": - raise ValueError("The method argument has to be equal to either " + + if algorithm != "LP": + raise ValueError("The algorithm argument has to be equal to either " + "\"FF\", \"LP\", \"igraph\", or None") @@ -8406,7 +8407,8 @@ def disjoint_routed_paths(self,pairs, solver=None, verbose=0): except EmptySetError: raise EmptySetError("The disjoint routed paths do not exist.") - def edge_disjoint_paths(self, s, t, method = "FF"): + @rename_keyword(deprecation=19550, method='algorithm=') + def edge_disjoint_paths(self, s, t, algorithm = "FF"): r""" Returns a list of edge-disjoint paths between two vertices as given by Menger's theorem. @@ -8421,13 +8423,13 @@ def edge_disjoint_paths(self, s, t, method = "FF"): INPUT: - - ``method`` -- There are currently two different + - ``algorithm`` -- There are currently two different implementations of this method : - * If ``method = "FF"`` (default), a Python implementation of the + * If ``algorithm = "FF"`` (default), a Python implementation of the Ford-Fulkerson algorithm is used. - * If ``method = "LP"``, the flow problem is solved using + * If ``algorithm = "LP"``, the flow problem is solved using Linear Programming. .. NOTE:: @@ -8444,7 +8446,7 @@ def edge_disjoint_paths(self, s, t, method = "FF"): [[0, 2, 1], [0, 3, 1], [0, 4, 1]] """ - [obj, flow_graph] = self.flow(s,t,value_only=False, integer=True, use_edge_labels=False, method=method) + [obj, flow_graph] = self.flow(s,t,value_only=False, integer=True, use_edge_labels=False, algorithm=algorithm) paths = [] diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index e4d1c773fe2..6df92ebf8c6 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -418,6 +418,7 @@ from sage.graphs.independent_sets import IndependentSets from sage.combinat.combinatorial_map import combinatorial_map from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index +from sage.misc.decorators import rename_keyword class Graph(GenericGraph): r""" @@ -2134,13 +2135,13 @@ def is_triangle_free(self, algorithm='bitset'): - ``algorithm`` -- (default: ``'bitset'``) specifies the algorithm to use among: - - ``'matrix'`` -- tests if the trace of the adjacency matrix is - positive. + - ``'matrix'`` -- tests if the trace of the adjacency matrix is + positive. - - ``'bitset'`` -- encodes adjacencies into bitsets and uses fast - bitset operations to test if the input graph contains a - triangle. This method is generaly faster than stantard matrix - multiplication. + - ``'bitset'`` -- encodes adjacencies into bitsets and uses fast + bitset operations to test if the input graph contains a + triangle. This method is generaly faster than stantard matrix + multiplication. EXAMPLE: @@ -3210,14 +3211,14 @@ def bounded_outdegree_orientation(self, bound): - ``bound`` -- Maximum bound on the out-degree. Can be of three different types : - * An integer `k`. In this case, computes an orientation - whose maximum out-degree is less than `k`. + * An integer `k`. In this case, computes an orientation + whose maximum out-degree is less than `k`. - * A dictionary associating to each vertex its associated - maximum out-degree. + * A dictionary associating to each vertex its associated + maximum out-degree. - * A function associating to each vertex its associated - maximum out-degree. + * A function associating to each vertex its associated + maximum out-degree. OUTPUT: @@ -4041,11 +4042,11 @@ def maximum_average_degree(self, value_only=True, solver = None, verbose = 0): - ``value_only`` (boolean) -- ``True`` by default - - If ``value_only=True``, only the numerical - value of the `MAD` is returned. + - If ``value_only=True``, only the numerical + value of the `MAD` is returned. - - Else, the subgraph of `G` realizing the `MAD` - is returned. + - Else, the subgraph of `G` realizing the `MAD` + is returned. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) solver to be used. If set to ``None``, the default one is used. For @@ -5153,17 +5154,17 @@ def clique_maximum(self, algorithm="Cliquer"): - ``algorithm`` -- the algorithm to be used : - - If ``algorithm = "Cliquer"`` (default) - This wraps the C program - Cliquer [NisOst2003]_. + - If ``algorithm = "Cliquer"`` (default) - This wraps the C program + Cliquer [NisOst2003]_. - - If ``algorithm = "MILP"``, the problem is solved through a Mixed - Integer Linear Program. + - If ``algorithm = "MILP"``, the problem is solved through a Mixed + Integer Linear Program. - (see :class:`~sage.numerical.mip.MixedIntegerLinearProgram`) + (see :class:`~sage.numerical.mip.MixedIntegerLinearProgram`) - - If ``algorithm = "mcqd"`` - Uses the MCQD solver - (``_). Note that the MCQD - package must be installed. + - If ``algorithm = "mcqd"`` - Uses the MCQD solver + (``_). Note that the MCQD + package must be installed. .. NOTE:: @@ -5230,21 +5231,21 @@ def clique_number(self, algorithm="Cliquer", cliques=None): - ``algorithm`` -- the algorithm to be used : - - If ``algorithm = "Cliquer"`` - This wraps the C program Cliquer - [NisOst2003]_. + - If ``algorithm = "Cliquer"`` - This wraps the C program Cliquer + [NisOst2003]_. - - If ``algorithm = "networkx"`` - This function is based on - NetworkX's implementation of the Bron and Kerbosch Algorithm - [BroKer1973]_. + - If ``algorithm = "networkx"`` - This function is based on + NetworkX's implementation of the Bron and Kerbosch Algorithm + [BroKer1973]_. - - If ``algorithm = "MILP"``, the problem is solved through a Mixed - Integer Linear Program. + - If ``algorithm = "MILP"``, the problem is solved through a Mixed + Integer Linear Program. - (see :class:`~sage.numerical.mip.MixedIntegerLinearProgram`) + (see :class:`~sage.numerical.mip.MixedIntegerLinearProgram`) - - If ``algorithm = "mcqd"`` - Uses the MCQD solver - (``_). Note that the MCQD - package must be installed. + - If ``algorithm = "mcqd"`` - Uses the MCQD solver + (``_). Note that the MCQD + package must be installed. - ``cliques`` - an optional list of cliques that can be input if already computed. Ignored unless ``algorithm=="networkx"``. @@ -5437,19 +5438,19 @@ def independent_set(self, algorithm = "Cliquer", value_only = False, reduction_r - ``algorithm`` -- the algorithm to be used - * If ``algorithm = "Cliquer"`` (default), the problem is solved - using Cliquer [NisOst2003]_. + * If ``algorithm = "Cliquer"`` (default), the problem is solved + using Cliquer [NisOst2003]_. - (see the :mod:`Cliquer modules `) + (see the :mod:`Cliquer modules `) - * If ``algorithm = "MILP"``, the problem is solved through a Mixed - Integer Linear Program. + * If ``algorithm = "MILP"``, the problem is solved through a Mixed + Integer Linear Program. - (see :class:`~sage.numerical.mip.MixedIntegerLinearProgram`) + (see :class:`~sage.numerical.mip.MixedIntegerLinearProgram`) - * If ``algorithm = "mcqd"`` - Uses the MCQD solver - (``_). Note that the MCQD - package must be installed. + * If ``algorithm = "mcqd"`` - Uses the MCQD solver + (``_). Note that the MCQD + package must be installed. - ``value_only`` -- boolean (default: ``False``). If set to ``True``, only the size of a maximum independent set is returned. Otherwise, @@ -6198,15 +6199,15 @@ def modular_decomposition(self): A pair of two values (recursively encoding the decomposition) : - * The type of the current module : + * The type of the current module : - * ``"Parallel"`` - * ``"Prime"`` - * ``"Serie"`` + * ``"Parallel"`` + * ``"Prime"`` + * ``"Serie"`` - * The list of submodules (as list of pairs ``(type, list)``, - recursively...) or the vertex's name if the module is a - singleton. + * The list of submodules (as list of pairs ``(type, list)``, + recursively...) or the vertex's name if the module is a + singleton. EXAMPLES: @@ -6313,9 +6314,10 @@ def is_prime(self): return D[0] == "Prime" and len(D[1]) == self.order() - def _gomory_hu_tree(self, vertices, method="FF"): + @rename_keyword(deprecation=19550, method='algorithm=') + def _gomory_hu_tree(self, vertices, algorithm="FF"): r""" - Returns a Gomory-Hu tree associated to self. + Return a Gomory-Hu tree associated to self. This function is the private counterpart of ``gomory_hu_tree()``, with the difference that it has an optional argument @@ -6330,15 +6332,15 @@ def _gomory_hu_tree(self, vertices, method="FF"): fakes one introduced during the computations. This variable is useful for the algorithm and for recursion purposes. - - ``method`` -- There are currently two different + - ``algorithm`` -- There are currently two different implementations of this method : - * If ``method = "FF"`` (default), a Python - implementation of the Ford-Fulkerson algorithm is - used. + * If ``algorithm = "FF"`` (default), a Python + implementation of the Ford-Fulkerson algorithm is + used. - * If ``method = "LP"``, the flow problem is solved using - Linear Programming. + * If ``algorithm = "LP"``, the flow problem is solved using + Linear Programming. EXAMPLE: @@ -6363,7 +6365,7 @@ def _gomory_hu_tree(self, vertices, method="FF"): # Compute a uv min-edge-cut. # # The graph is split into U,V with u \in U and v\in V. - flow,edges,[U,V] = self.edge_cut(u, v, use_edge_labels=True, vertices=True, method=method) + flow,edges,[U,V] = self.edge_cut(u, v, use_edge_labels=True, vertices=True, algorithm=algorithm) # One graph for each part of the previous one gU,gV = self.subgraph(U), self.subgraph(V) @@ -6397,8 +6399,8 @@ def _gomory_hu_tree(self, vertices, method="FF"): gV.set_edge_label(vv, fU, gV.edge_label(vv, fU) + capacity) # Recursion on each side - gU_tree = gU._gomory_hu_tree(vertices & frozenset(gU), method=method) - gV_tree = gV._gomory_hu_tree(vertices & frozenset(gV), method=method) + gU_tree = gU._gomory_hu_tree(vertices & frozenset(gU), algorithm=algorithm) + gV_tree = gV._gomory_hu_tree(vertices & frozenset(gV), algorithm=algorithm) # Union of the two partial trees g = gU_tree.union(gV_tree) @@ -6409,7 +6411,8 @@ def _gomory_hu_tree(self, vertices, method="FF"): return g @doc_index("Connectivity, orientations, trees") - def gomory_hu_tree(self, method="FF"): + @rename_keyword(deprecation=19550, method='algorithm=') + def gomory_hu_tree(self, algorithm="FF"): r""" Returns a Gomory-Hu tree of self. @@ -6427,15 +6430,15 @@ def gomory_hu_tree(self, method="FF"): INPUT: - - ``method`` -- There are currently two different + - ``algorithm`` -- There are currently two different implementations of this method : - * If ``method = "FF"`` (default), a Python - implementation of the Ford-Fulkerson algorithm is - used. + * If ``algorithm = "FF"`` (default), a Python + implementation of the Ford-Fulkerson algorithm is + used. - * If ``method = "LP"``, the flow problems are solved - using Linear Programming. + * If ``algorithm = "LP"``, the flow problems are solved + using Linear Programming. OUTPUT: @@ -6497,9 +6500,9 @@ def gomory_hu_tree(self, method="FF"): if not self.is_connected(): g = Graph() for cc in self.connected_components_subgraphs(): - g = g.union(cc._gomory_hu_tree(frozenset(cc.vertices()),method=method)) + g = g.union(cc._gomory_hu_tree(frozenset(cc.vertices()), algorithm=algorithm)) else: - g = self._gomory_hu_tree(frozenset(self.vertices()),method=method) + g = self._gomory_hu_tree(frozenset(self.vertices()), algorithm=algorithm) if self.get_pos() is not None: g.set_pos(dict(self.get_pos())) From d30d5303f3e7d10e643318a4d1fea91ba3c370c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Sun, 8 Nov 2015 19:58:39 +0200 Subject: [PATCH 1857/1872] Stupid typo. --- src/sage/graphs/generic_graph.py | 6 +++--- src/sage/graphs/graph.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index a3ab9d27d90..ae23019ff03 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -5717,7 +5717,7 @@ def edge_disjoint_spanning_trees(self,k, root=None, solver = None, verbose = 0): return classes - @rename_keyword(deprecation=19550, method='algorithm=') + @rename_keyword(deprecation=19550, method='algorithm') def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, algorithm="FF", solver=None, verbose=0): r""" Return a minimum edge cut between vertices `s` and `t`. @@ -7617,7 +7617,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constrai return [v for v in self if b_sol[v] == 1] - @rename_keyword(deprecation=19550, method='algorithm=') + @rename_keyword(deprecation=19550, method='algorithm') def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, vertex_bound=False, algorithm = None, solver=None, verbose=0): r""" Returns a maximum flow in the graph from ``x`` to ``y`` @@ -8407,7 +8407,7 @@ def disjoint_routed_paths(self,pairs, solver=None, verbose=0): except EmptySetError: raise EmptySetError("The disjoint routed paths do not exist.") - @rename_keyword(deprecation=19550, method='algorithm=') + @rename_keyword(deprecation=19550, method='algorithm') def edge_disjoint_paths(self, s, t, algorithm = "FF"): r""" Returns a list of edge-disjoint paths between two diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 6df92ebf8c6..98d3fe449a6 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -6314,7 +6314,7 @@ def is_prime(self): return D[0] == "Prime" and len(D[1]) == self.order() - @rename_keyword(deprecation=19550, method='algorithm=') + @rename_keyword(deprecation=19550, method='algorithm') def _gomory_hu_tree(self, vertices, algorithm="FF"): r""" Return a Gomory-Hu tree associated to self. @@ -6411,7 +6411,7 @@ def _gomory_hu_tree(self, vertices, algorithm="FF"): return g @doc_index("Connectivity, orientations, trees") - @rename_keyword(deprecation=19550, method='algorithm=') + @rename_keyword(deprecation=19550, method='algorithm') def gomory_hu_tree(self, algorithm="FF"): r""" Returns a Gomory-Hu tree of self. From 8aa1ef5188f67a9fcc906b21f3b98e362a804ba7 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 8 Nov 2015 14:14:16 -0500 Subject: [PATCH 1858/1872] Trac #19485: Add examples to plot? and show? of the old legend appearance. Since we're changing the default behavior of legends, some users may want to know how to obtain legends that look like they used to. This commit adds two examples to the docs for `plot()` and `show()`, explaining how to set the background color to gray and disable the drop shadow. This improvement was suggested by Karl-Dieter Crisman. --- src/sage/plot/graphics.py | 8 ++++++++ src/sage/plot/plot.py | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index c401885f7d7..c4d1b7d0af4 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -1628,6 +1628,14 @@ def show(self, filename=None, linkmode=False, **kwds): sage: plot(sin(x), (x, -4, 4), transparent=True) Graphics object consisting of 1 graphics primitive + Prior to :trac:`19485`, legends by default had a shadowless gray + background. This behavior can be recovered by passing in certain + ``legend_options``:: + + sage: p = plot(sin(x), legend_label='$\sin(x)$') + sage: p.show(legend_options={'back_color': (0.9,0.9,0.9), + ....: 'shadow': False}) + We can change the scale of the axes in the graphics before displaying:: diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 907ef6cdaea..521b832f188 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -912,6 +912,13 @@ def plot(funcs, *args, **kwds): sage: p1 + p2 Graphics object consisting of 2 graphics primitives + Prior to :trac:`19485`, legends by default had a shadowless gray + background. This behavior can be recovered by setting the legend + options on your plot object:: + + sage: p = plot(sin(x), legend_label='$\sin(x)$') + sage: p.set_legend_options(back_color=(0.9,0.9,0.9), shadow=False) + Note that the independent variable may be omitted if there is no ambiguity:: From 7da82db694e3b8c0467526ee5cc7141d40604dd6 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 8 Nov 2015 23:18:32 +0000 Subject: [PATCH 1859/1872] added a necessary condition check; hooked the construction into SRG DB Note the TODO added --- src/sage/graphs/generators/families.py | 14 +++++- src/sage/graphs/strongly_regular_db.pyx | 57 +++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index fd015e91160..b4bd2653a02 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2476,7 +2476,8 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): Return a strongly regular graph on `(4t+1)(4t-1)^2` vertices from [Mat78]_ Let `4t-1` be a prime power, and `4t+1` be such that there exists - a strongly regular graph `G` with parameters `(4t+1,2t,t-1,t)`. With + a strongly regular graph `G` with parameters `(4t+1,2t,t-1,t)`. In + particular, `4t+1` must be a sum of two squares [Mat78]_. With this input, Mathon [Mat78]_ gives a construction of a strongly regular graph with parameters `(4 \mu + 1, 2 \mu, \mu-1, \mu)`, where `\mu = t(4t(4t-1)-1)`. The construction is optionally parametrised by an @@ -2510,7 +2511,10 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): Mathon's PC SRG on 441 vertices: Graph on 441 vertices sage: G.is_strongly_regular(parameters=True) # long time (441, 220, 109, 110) - + sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) + Traceback (most recent call last): + ... + ValueError: 21 must be a sum of two squares!... REFERENCES: @@ -2530,7 +2534,13 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): ones_matrix, identity_matrix from sage.graphs.graph import Graph from itertools import product + from sage.rings.arith import two_squares + from exceptions import ValueError p = 4*t+1 + try: + x = two_squares(p) + except ValueError: + raise ValueError(str(p)+" must be a sum of two squares!") if G is None: from sage.graphs.strongly_regular_db import strongly_regular_graph as SRG G = SRG(p, 2*t, t-1) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 636c7f4efa2..4621a004b2e 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -87,6 +87,62 @@ def is_paley(int v,int k,int l,int mu): from sage.graphs.generators.families import PaleyGraph return (lambda q : PaleyGraph(q),v) +@cached_function +def is_mathon_PC_srg(int v,int k,int l,int mu): + r""" + Test whether some Mathon's Pseudocyclic s.r.g. is `(v,k,\lambda,\mu)`-strongly regular. + + INPUT: + + - ``v,k,l,mu`` (integers) + + OUTPUT: + + A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one + exists, and ``None`` otherwise. + + .. TODO:: + + The current implementation only gives a subset of all possible graphs that can be + obtained using this construction. A full implementation should rely on a database + of conference matrices (or, equivalently, on a database of s.r.g.'s with parameters + `(4t+1,2t,t-1,t)`. Currently we make an extra assumtion that `4t+1` is a prime power. + The first case where we miss a construction is `t=11`, where we could (recursively) + use the graph for `t=1` to construct a graph on 83205 vertices. + + EXAMPLES:: + + sage: from sage.graphs.strongly_regular_db import is_mathon_PC_srg + sage: t = is_mathon_PC_srg(45,22,10,11); t + (..., 1) + sage: g = t[0](*t[1:]); g + Mathon's PC SRG on 45 vertices: Graph on 45 vertices + sage: g.is_strongly_regular(parameters=True) + (45, 22, 10, 11) + + TESTS:: + + sage: t = is_mathon_PC_srg(5,5,5,5); t + sage: mu = 1895 # t=5 case -- the construction cannot work + sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t + """ + cdef int t + if (v%4 == 1 and + k == (v-1)/2 and + l == (v-5)/4 and + mu == (v-1)/4): + from sage.rings.integer_ring import ZZ + K = ZZ['x'] + x = K.gen() + rpoly = filter(lambda w: w[0]>0, (x*(4*x*(4*x-1)-1)-mu).roots()) + if rpoly != []: + t = rpoly[0][0] + if (is_prime_power(4*t-1) and + is_prime_power(4*t+1)): # extra assumption in TODO! + from sage.graphs.generators.families import \ + MathonPseudocyclicStronglyRegularGraph + return (lambda q : MathonPseudocyclicStronglyRegularGraph(q),t) + @cached_function def is_orthogonal_array_block_graph(int v,int k,int l,int mu): r""" @@ -3115,6 +3171,7 @@ def strongly_regular_graph(int v,int k,int l,int mu=-1,bint existence=False,bint is_taylor_twograph_srg, is_switch_OA_srg, is_polhill, + is_mathon_PC_srg, is_switch_skewhad] # Going through all test functions, for the set of parameters and its From 6e2144d154fe957ff57bf77972d77e78afc9efed Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Mon, 9 Nov 2015 15:29:08 +0100 Subject: [PATCH 1860/1872] Fix the mpir install when SAGE_FAT_BINARY is set --- build/pkgs/mpir/spkg-install | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/build/pkgs/mpir/spkg-install b/build/pkgs/mpir/spkg-install index 8e8423b60dc..16e4d64a45d 100755 --- a/build/pkgs/mpir/spkg-install +++ b/build/pkgs/mpir/spkg-install @@ -8,7 +8,6 @@ fi CUR=`pwd` -mv mpir-2.7.0 src cd src ############################################################################### @@ -30,10 +29,33 @@ done # before installing the new one. (Done below.) ############################################################################### +############################################################################### +# Find out the machine type +############################################################################### + +MACHINE_TYPE_MPIR=$(sh ./config.guess) +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to determine the machine type (mpir-extended)" + exit 1 +fi + +# This is the vanilla config.guessq (renamed to configfsf.guess in +# MPIR) file instead of MPIR's version. It is used when +# SAGE_FAT_BINARY is set. +MACHINE_TYPE_DEFAULT=$(sh ./configfsf.guess) +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to determine the machine type (default)" + exit 1 +fi + +echo "Machine type (default): $MACHINE_TYPE_DEFAULT" +echo "Machine type (mpir): $MACHINE_TYPE_MPIR" + ############################################################################### # Set up environment variables: ############################################################################### + # The Yasm build uses PYTHON from the environment to find the Python interpreter, # so unset it in case it apparently contains nothing useful (like it did in Sage # versions prior to 5.0.beta10; cf. #10492), to not break Yasm's 'configure': @@ -218,9 +240,8 @@ fi # If SAGE_FAT_BINARY is enabled, then add --enable-fat to configure # options on Linux x86 systems. On other systems, fat binaries are not -# supported. Then we specify a build architecture which doesn't -# have a CPU name in it. This means which use the vanilla config.guess -# (renamed to configfsf.guess in MPIR) file instead of MPIR's version. +# supported. There, we specify a build architecture which doesn't +# have a CPU name in it. if [ "$SAGE_FAT_BINARY" = "yes" ]; then case "$UNAME-`uname -m`" in Linux-i[3456]86) @@ -233,7 +254,7 @@ if [ "$SAGE_FAT_BINARY" = "yes" ]; then ;; *) # Anything else echo "** Building a generic binary (not assuming any specific CPU) **" - MPIR_CONFIGURE="--build=`./configfsf.guess` $MPIR_CONFIGURE" + MPIR_CONFIGURE="--build=$MACHINE_TYPE_DEFAULT $MPIR_CONFIGURE" ;; esac fi From d5128b142779b3f77021e02a3cf12114c2f70431 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Mon, 9 Nov 2015 15:51:38 +0100 Subject: [PATCH 1861/1872] Fix typo, use bash for subshell --- build/pkgs/mpir/spkg-install | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/mpir/spkg-install b/build/pkgs/mpir/spkg-install index 16e4d64a45d..8711de2db6a 100755 --- a/build/pkgs/mpir/spkg-install +++ b/build/pkgs/mpir/spkg-install @@ -33,16 +33,16 @@ done # Find out the machine type ############################################################################### -MACHINE_TYPE_MPIR=$(sh ./config.guess) +MACHINE_TYPE_MPIR=$(bash ./config.guess) if [ $? -ne 0 ]; then echo >&2 "Error: failed to determine the machine type (mpir-extended)" exit 1 fi -# This is the vanilla config.guessq (renamed to configfsf.guess in +# This is the vanilla config.guess (renamed to configfsf.guess in # MPIR) file instead of MPIR's version. It is used when # SAGE_FAT_BINARY is set. -MACHINE_TYPE_DEFAULT=$(sh ./configfsf.guess) +MACHINE_TYPE_DEFAULT=$(bash ./configfsf.guess) if [ $? -ne 0 ]; then echo >&2 "Error: failed to determine the machine type (default)" exit 1 From 1a079718ba286b8c29c80dd5211a921e9179e192 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 9 Nov 2015 22:40:08 +0000 Subject: [PATCH 1862/1872] user-supplied G and L example, and imports trimming --- src/sage/graphs/generators/families.py | 41 +++++++++++++++++++++----- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index b4bd2653a02..e1d010456a5 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2495,9 +2495,12 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): with vertices labelled from `0` to `4t`. - ``L`` -- if `None` (default), construct a necessary skew Latin square, - otherwise use the user-supplied one. + otherwise use the user-supplied one. Limited experimental data below suggests + that non-isomorphic Latin squares still lead to isomorphic graphs. - EXAMPLES:: + EXAMPLES: + + Using default ``G`` and ``L``. :: sage: from sage.graphs.generators.families import MathonPseudocyclicStronglyRegularGraph sage: G=MathonPseudocyclicStronglyRegularGraph(1); G @@ -2505,12 +2508,36 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): sage: G.is_strongly_regular(parameters=True) (45, 22, 10, 11) + Supplying ``G`` and ``L`` (constructed from the automorphism group of ``G``). :: + + sage: G=graphs.PaleyGraph(9) + sage: a=G.automorphism_group() + sage: r=map(lambda z: matrix(libgap.PermutationMat(libgap(z),9).sage()), \ + ....: filter(lambda x: x.order()==9, a.normal_subgroups())[0]) + sage: ff=map(lambda y: (y[0]-1,y[1]-1), \ + ....: Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_tuples()[1:]) + sage: L=sum(map(lambda (i,(a,b)): i*(r[a]-r[b]), zip(range(1,len(ff)+1), ff))); L + [ 0 1 -1 2 3 -4 -2 4 -3] + [-1 0 1 -4 2 3 -3 -2 4] + [ 1 -1 0 3 -4 2 4 -3 -2] + [-2 4 -3 0 1 -1 2 3 -4] + [-3 -2 4 -1 0 1 -4 2 3] + [ 4 -3 -2 1 -1 0 3 -4 2] + [ 2 3 -4 -2 4 -3 0 1 -1] + [-4 2 3 -3 -2 4 -1 0 1] + [ 3 -4 2 4 -3 -2 1 -1 0] + sage: G.relabel() + sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L) + sage: G3x3.is_strongly_regular(parameters=True) + (441, 220, 109, 110) + sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2) + sage: G9.is_strongly_regular(parameters=True) + (441, 220, 109, 110) + sage: G9.is_isomorphic(G3x3) # not tested (long time) + True + TESTS:: - sage: G=MathonPseudocyclicStronglyRegularGraph(2); G # long time - Mathon's PC SRG on 441 vertices: Graph on 441 vertices - sage: G.is_strongly_regular(parameters=True) # long time - (441, 220, 109, 110) sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) Traceback (most recent call last): ... @@ -2532,10 +2559,8 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix, block_matrix, \ ones_matrix, identity_matrix - from sage.graphs.graph import Graph from itertools import product from sage.rings.arith import two_squares - from exceptions import ValueError p = 4*t+1 try: x = two_squares(p) From 9b9d53b154f81144853c15c2916a4ff9eca19b83 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 9 Nov 2015 22:44:28 +0000 Subject: [PATCH 1863/1872] killed few lambdas and ate them --- src/sage/graphs/strongly_regular_db.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 4621a004b2e..4c60e980fbe 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -85,7 +85,7 @@ def is_paley(int v,int k,int l,int mu): l == (v-5)/4 and mu == (v-1)/4): from sage.graphs.generators.families import PaleyGraph - return (lambda q : PaleyGraph(q),v) + return (PaleyGraph,v) @cached_function def is_mathon_PC_srg(int v,int k,int l,int mu): @@ -141,7 +141,7 @@ def is_mathon_PC_srg(int v,int k,int l,int mu): is_prime_power(4*t+1)): # extra assumption in TODO! from sage.graphs.generators.families import \ MathonPseudocyclicStronglyRegularGraph - return (lambda q : MathonPseudocyclicStronglyRegularGraph(q),t) + return (MathonPseudocyclicStronglyRegularGraph,t) @cached_function def is_orthogonal_array_block_graph(int v,int k,int l,int mu): From 7c029f3c98032a985c2ca0329dfe940271e9b86b Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Mon, 9 Nov 2015 15:56:21 -0800 Subject: [PATCH 1864/1872] trac 17447: further doctest adjustments --- src/doc/ja/tutorial/tour_algebra.rst | 2 +- src/doc/pt/tutorial/tour_algebra.rst | 2 +- src/sage/symbolic/expression.pyx | 2 +- src/sage/tests/french_book/calculus_doctest.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/ja/tutorial/tour_algebra.rst b/src/doc/ja/tutorial/tour_algebra.rst index 00518832a09..6fc8040a72b 100644 --- a/src/doc/ja/tutorial/tour_algebra.rst +++ b/src/doc/ja/tutorial/tour_algebra.rst @@ -164,7 +164,7 @@ Sageを使って常微分方程式を研究することもできる. :math:`x' :: sage: t = var('t') # 変数 t を定義 - sage: x = function('x',t) # x を t の関数とする + sage: x = function('x')(t) # x を t の関数とする sage: DE = diff(x, t) + x - 1 sage: desolve(DE, [x,t]) (_C + e^t)*e^(-t) diff --git a/src/doc/pt/tutorial/tour_algebra.rst b/src/doc/pt/tutorial/tour_algebra.rst index 3495e6dcf5a..ba84430ff61 100644 --- a/src/doc/pt/tutorial/tour_algebra.rst +++ b/src/doc/pt/tutorial/tour_algebra.rst @@ -151,7 +151,7 @@ ordinárias. Para resolver a equação :math:`x'+x-1=0`: :: sage: t = var('t') # define a variable t - sage: x = function('x',t) # define x to be a function of that variable + sage: x = function('x')(t) # define x to be a function of that variable sage: DE = diff(x, t) + x - 1 sage: desolve(DE, [x,t]) (_C + e^t)*e^(-t) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index a170c1ef828..e19606ca4fa 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -5645,7 +5645,7 @@ cdef class Expression(CommutativeRingElement): We can find coefficients of symbolic functions, :trac:`12255`:: - sage: g = function('g', var('t')) + sage: g = function('g')(var('t')) sage: f = 3*g + g**2 + t sage: f.coefficients(g) [[t, 0], [3, 1], [1, 2]] diff --git a/src/sage/tests/french_book/calculus_doctest.py b/src/sage/tests/french_book/calculus_doctest.py index 64a7fc80a94..6d130ce6975 100644 --- a/src/sage/tests/french_book/calculus_doctest.py +++ b/src/sage/tests/french_book/calculus_doctest.py @@ -46,7 +46,7 @@ Sage example in ./calculus.tex, line 122:: sage: y = var('y'); u = sin(x) + x*cos(y) - sage: v = u.function(x)(y); v + sage: v = u.function(x,y); v (x, y) |--> x*cos(y) + sin(x) sage: w(x, y) = u; w (x, y) |--> x*cos(y) + sin(x) From 2b7347367862cf2d172faa6ace98bd51e1e88c29 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 4 Nov 2015 16:18:24 +0100 Subject: [PATCH 1865/1872] *graph -> graph --- src/sage/graphs/base/boost_interface.cpp | 48 ++++++++++++------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/sage/graphs/base/boost_interface.cpp b/src/sage/graphs/base/boost_interface.cpp index 1775b51dcbe..4228f52bc9f 100644 --- a/src/sage/graphs/base/boost_interface.cpp +++ b/src/sage/graphs/base/boost_interface.cpp @@ -72,62 +72,60 @@ class BoostGraph typedef typename boost::property_map::type vertex_to_int_map; public: - adjacency_list *graph; + adjacency_list graph; std::vector *vertices; vertex_to_int_map index; BoostGraph() { - graph = new adjacency_list(); vertices = new std::vector(); } ~BoostGraph() { - delete graph; delete vertices; } v_index num_verts() { - return num_vertices(*graph); + return num_vertices(graph); } e_index num_edges() { - return boost::num_edges(*graph); + return boost::num_edges(graph); } void add_vertex() { - (*vertices).push_back(boost::add_vertex((*vertices).size(), *graph)); + (*vertices).push_back(boost::add_vertex((*vertices).size(), graph)); } void add_edge(v_index u, v_index v) { - boost::add_edge((*vertices)[u], (*vertices)[v], *graph); + boost::add_edge((*vertices)[u], (*vertices)[v], graph); } void add_edge(v_index u, v_index v, double weight) { - boost::add_edge((*vertices)[u], (*vertices)[v], weight, *graph); + boost::add_edge((*vertices)[u], (*vertices)[v], weight, graph); } result_ec edge_connectivity() { result_ec to_return; edge_container disconnecting_set; std::back_insert_iterator inserter(disconnecting_set); - to_return.ec = boost::edge_connectivity(*graph, inserter); + to_return.ec = boost::edge_connectivity(graph, inserter); for (v_index i = 0; i < disconnecting_set.size(); i++) { edge_descriptor edge = disconnecting_set[i]; - to_return.edges.push_back(index[boost::source(edge, *graph)]); - to_return.edges.push_back(index[boost::target(edge, *graph)]); + to_return.edges.push_back(index[boost::source(edge, graph)]); + to_return.edges.push_back(index[boost::target(edge, graph)]); } return to_return; } double clustering_coeff(v_index v) { - return clustering_coefficient(*graph, (*vertices)[v]); + return clustering_coefficient(graph, (*vertices)[v]); } result_cc clustering_coeff_all() { result_cc to_return; to_return.clust_of_v.resize(num_verts()); - to_return.average_clustering_coefficient = all_clustering_coefficients(*graph, + to_return.average_clustering_coefficient = all_clustering_coefficients(graph, boost::make_iterator_property_map(to_return.clust_of_v.begin(), index)); return to_return; } @@ -137,7 +135,7 @@ class BoostGraph std::vector fathers_descr(num_verts(), boost::graph_traits::null_vertex()); - lengauer_tarjan_dominator_tree(*graph, (*vertices)[v], + lengauer_tarjan_dominator_tree(graph, (*vertices)[v], boost::make_iterator_property_map( fathers_descr.begin(), index)); @@ -155,12 +153,12 @@ class BoostGraph // Works only in undirected graphs! std::vector bandwidth_ordering(bool cuthill) { std::vector to_return; - std::vector inv_perm(num_vertices(*graph)); + std::vector inv_perm(num_vertices(graph)); if (cuthill) { - boost::cuthill_mckee_ordering(*graph, inv_perm.rbegin()); + boost::cuthill_mckee_ordering(graph, inv_perm.rbegin()); } else { - boost::king_ordering(*graph, inv_perm.rbegin()); + boost::king_ordering(graph, inv_perm.rbegin()); } for (int i = 0; i < inv_perm.size(); i++) { @@ -173,11 +171,11 @@ class BoostGraph std::vector kruskal_min_spanning_tree() { std::vector to_return; std::vector spanning_tree; - kruskal_minimum_spanning_tree(*graph, std::back_inserter(spanning_tree)); + kruskal_minimum_spanning_tree(graph, std::back_inserter(spanning_tree)); for (unsigned int i = 0; i < spanning_tree.size(); i++) { - to_return.push_back(index[source(spanning_tree[i], *graph)]); - to_return.push_back(index[target(spanning_tree[i], *graph)]); + to_return.push_back(index[source(spanning_tree[i], graph)]); + to_return.push_back(index[target(spanning_tree[i], graph)]); } return to_return; } @@ -186,7 +184,7 @@ class BoostGraph std::vector prim_min_spanning_tree() { std::vector to_return; std::vector predecessors(num_verts()); - prim_minimum_spanning_tree(*graph, boost::make_iterator_property_map(predecessors.begin(), index)); + prim_minimum_spanning_tree(graph, boost::make_iterator_property_map(predecessors.begin(), index)); for (unsigned int i = 0; i < predecessors.size(); i++) { if (index[predecessors[i]] != i) { @@ -203,7 +201,7 @@ class BoostGraph std::vector distances(N, (std::numeric_limits::max)()); std::vector predecessors(N); try { - boost::dijkstra_shortest_paths(*graph, (*vertices)[s], distance_map(boost::make_iterator_property_map(distances.begin(), index)) + boost::dijkstra_shortest_paths(graph, (*vertices)[s], distance_map(boost::make_iterator_property_map(distances.begin(), index)) .predecessor_map(boost::make_iterator_property_map(predecessors.begin(), index))); } catch (boost::exception_detail::clone_impl > e) { return to_return; @@ -224,14 +222,14 @@ class BoostGraph std::vector distance(N, (std::numeric_limits::max)()); std::vector predecessors(N); result_distances to_return; - typename boost::property_map::type weight = get(boost::edge_weight, (*graph)); + typename boost::property_map::type weight = get(boost::edge_weight, (graph)); for (v_index i = 0; i < N; ++i) predecessors[i] = (*vertices)[i]; distance[s] = 0; bool r = boost::bellman_ford_shortest_paths - (*graph, N, boost::weight_map(weight).distance_map(boost::make_iterator_property_map(distance.begin(), index)).predecessor_map(boost::make_iterator_property_map(predecessors.begin(), index))); + (graph, N, boost::weight_map(weight).distance_map(boost::make_iterator_property_map(distance.begin(), index)).predecessor_map(boost::make_iterator_property_map(predecessors.begin(), index))); if (!r) { return to_return; @@ -248,7 +246,7 @@ class BoostGraph v_index N = num_verts(); std::vector > D(N, std::vector(N)); - if (johnson_all_pairs_shortest_paths(*graph, D)) { + if (johnson_all_pairs_shortest_paths(graph, D)) { return D; } else { return std::vector >(); From 6d81760a88ec4ea8a7688f34b498dd01263b01ab Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 4 Nov 2015 16:20:02 +0100 Subject: [PATCH 1866/1872] *vertices -> vertices --- src/sage/graphs/base/boost_interface.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/sage/graphs/base/boost_interface.cpp b/src/sage/graphs/base/boost_interface.cpp index 4228f52bc9f..65f4d2e9d84 100644 --- a/src/sage/graphs/base/boost_interface.cpp +++ b/src/sage/graphs/base/boost_interface.cpp @@ -73,15 +73,10 @@ class BoostGraph public: adjacency_list graph; - std::vector *vertices; + std::vector vertices; vertex_to_int_map index; BoostGraph() { - vertices = new std::vector(); - } - - ~BoostGraph() { - delete vertices; } v_index num_verts() { @@ -93,15 +88,15 @@ class BoostGraph } void add_vertex() { - (*vertices).push_back(boost::add_vertex((*vertices).size(), graph)); + vertices.push_back(boost::add_vertex(vertices.size(), graph)); } void add_edge(v_index u, v_index v) { - boost::add_edge((*vertices)[u], (*vertices)[v], graph); + boost::add_edge(vertices[u], vertices[v], graph); } void add_edge(v_index u, v_index v, double weight) { - boost::add_edge((*vertices)[u], (*vertices)[v], weight, graph); + boost::add_edge(vertices[u], vertices[v], weight, graph); } result_ec edge_connectivity() { @@ -119,7 +114,7 @@ class BoostGraph } double clustering_coeff(v_index v) { - return clustering_coefficient(graph, (*vertices)[v]); + return clustering_coefficient(graph, vertices[v]); } result_cc clustering_coeff_all() { @@ -135,7 +130,7 @@ class BoostGraph std::vector fathers_descr(num_verts(), boost::graph_traits::null_vertex()); - lengauer_tarjan_dominator_tree(graph, (*vertices)[v], + lengauer_tarjan_dominator_tree(graph, vertices[v], boost::make_iterator_property_map( fathers_descr.begin(), index)); @@ -201,7 +196,7 @@ class BoostGraph std::vector distances(N, (std::numeric_limits::max)()); std::vector predecessors(N); try { - boost::dijkstra_shortest_paths(graph, (*vertices)[s], distance_map(boost::make_iterator_property_map(distances.begin(), index)) + boost::dijkstra_shortest_paths(graph, vertices[s], distance_map(boost::make_iterator_property_map(distances.begin(), index)) .predecessor_map(boost::make_iterator_property_map(predecessors.begin(), index))); } catch (boost::exception_detail::clone_impl > e) { return to_return; @@ -225,7 +220,7 @@ class BoostGraph typename boost::property_map::type weight = get(boost::edge_weight, (graph)); for (v_index i = 0; i < N; ++i) - predecessors[i] = (*vertices)[i]; + predecessors[i] = vertices[i]; distance[s] = 0; bool r = boost::bellman_ford_shortest_paths From 8cdc311f5714a8eeaae16b616a1c6da79a5aef7c Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 10 Nov 2015 13:06:10 +0000 Subject: [PATCH 1867/1872] fixed wrong(!) claim in EXAMPES, removed '\', added `` around None's and fixed the old comment in the code --- src/sage/graphs/generators/families.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index e1d010456a5..215883f65af 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2490,13 +2490,14 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): - ``t`` -- a positive integer - - ``G`` -- if `None` (default), try to construct the necessary graph + - ``G`` -- if ``None`` (default), try to construct the necessary graph with parameters `(4t+1,2t,t-1,t)`, otherwise use the user-supplied one, with vertices labelled from `0` to `4t`. - - ``L`` -- if `None` (default), construct a necessary skew Latin square, - otherwise use the user-supplied one. Limited experimental data below suggests - that non-isomorphic Latin squares still lead to isomorphic graphs. + - ``L`` -- if ``None`` (default), construct a necessary skew Latin square, + otherwise use the user-supplied one. Here non-isomorphic Latin squares + -- one constructed from `Z/9Z`, and the other from `(Z/3Z)^2` -- + lead to non-isomorphic graphs. EXAMPLES: @@ -2512,9 +2513,9 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): sage: G=graphs.PaleyGraph(9) sage: a=G.automorphism_group() - sage: r=map(lambda z: matrix(libgap.PermutationMat(libgap(z),9).sage()), \ + sage: r=map(lambda z: matrix(libgap.PermutationMat(libgap(z),9).sage()), ....: filter(lambda x: x.order()==9, a.normal_subgroups())[0]) - sage: ff=map(lambda y: (y[0]-1,y[1]-1), \ + sage: ff=map(lambda y: (y[0]-1,y[1]-1), ....: Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_tuples()[1:]) sage: L=sum(map(lambda (i,(a,b)): i*(r[a]-r[b]), zip(range(1,len(ff)+1), ff))); L [ 0 1 -1 2 3 -4 -2 4 -3] @@ -2530,11 +2531,13 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L) sage: G3x3.is_strongly_regular(parameters=True) (441, 220, 109, 110) + sage: G3x3.automorphism_group().order() # long time + 27 sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2) sage: G9.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G9.is_isomorphic(G3x3) # not tested (long time) - True + sage: G9.automorphism_group().order() # long time + 9 TESTS:: @@ -2575,15 +2578,13 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): L = circulant(range(2*t+1)+map(lambda i: -2*t+i, range(2*t))) q = 4*t -1 K = GF(q,conway=True,prefix='x') - # Order the elements of K in K_list - # so that K_list[i] = -K_list[n-i-1], and 0 comes last K_pairs = set(frozenset([x,-x]) for x in K) K_pairs.discard(frozenset([0])) - a = [None]*(q-1) + a = [None]*(q-1) # order the non-0 elements of K as required for i,(x,y) in enumerate(K_pairs): a[i] = x a[-i-1] = y - a.append(K(0)) + a.append(K(0)) # and append the 0 of K at the end P = map(lambda b: matrix(ZZ,q,q,lambda i,j: 1 if a[j]==a[i]+b else 0), a) g = K.primitive_element() F = sum(P[a.index(g**(2*i))] for i in xrange(1, 2*t)) From dc6d482122b25bd1e23cf78b7781a2c7314a1796 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Tue, 10 Nov 2015 05:59:59 -0800 Subject: [PATCH 1868/1872] Erase libtool archive files after running spkg-install --- build/bin/sage-spkg | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/bin/sage-spkg b/build/bin/sage-spkg index f734d49bee5..a3571a0271d 100755 --- a/build/bin/sage-spkg +++ b/build/bin/sage-spkg @@ -637,8 +637,8 @@ if [ ! -x spkg-install ]; then echo >&2 "WARNING: spkg-install is not executable, making it executable" chmod +x spkg-install fi -time ./spkg-install +time ./spkg-install if [ $? -ne 0 ]; then error_msg "Error installing package $PKG_NAME" "make" exit 1 @@ -665,6 +665,12 @@ if [ "$SAGE_CHECK" = "yes" ]; then fi fi +rm -f "$SAGE_LOCAL"/lib/*.la +if [ $? -ne 0 ]; then + error_msg "Error deleting unnecessary libtool archive files" + exit 1 +fi + # Mark that the new package has been installed (and tested, if # applicable). PKG_NAME_INSTALLED="$SAGE_SPKG_INST/$PKG_NAME" From a95ee91208af7b91b19d09f604cdc1cac0904e97 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 10 Nov 2015 15:45:53 +0000 Subject: [PATCH 1869/1872] specified bliss explicitly for the example; doctest fix-next graph --- src/sage/graphs/generators/families.py | 4 ++-- src/sage/graphs/strongly_regular_db.pyx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 215883f65af..d1e0de51efd 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2531,12 +2531,12 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L) sage: G3x3.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G3x3.automorphism_group().order() # long time + sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss 27 sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2) sage: G9.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G9.automorphism_group().order() # long time + sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss 9 TESTS:: diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 4c60e980fbe..164a9d2d716 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -3301,7 +3301,7 @@ def _check_database(): sage: from sage.graphs.strongly_regular_db import _check_database sage: _check_database() # long time - Sage cannot build a (45 22 10 11 ) that exists. Comment from Brouwer's database: Mathon; 2-graph* + Sage cannot build a (96 19 2 4 ) that exists. Comment from Brouwer's database: Haemers(4)... ... In Andries Brouwer's database: - 448 impossible entries From 72095846dfdaf16e984c3d3be4d4750775eadea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Wed, 11 Nov 2015 08:59:13 +0200 Subject: [PATCH 1870/1872] Change "INPUTS:" to "INPUT:". --- src/sage/categories/magmas.py | 2 +- src/sage/categories/sets_cat.py | 2 +- src/sage/combinat/free_module.py | 4 ++-- src/sage/combinat/output.py | 2 +- src/sage/combinat/words/finite_word.py | 2 +- src/sage/crypto/mq/sr.py | 2 +- src/sage/doctest/control.py | 2 +- src/sage/doctest/parsing.py | 2 +- src/sage/ext/fast_callable.pyx | 2 +- src/sage/game_theory/matching_game.py | 4 ++-- src/sage/graphs/bipartite_graph.py | 2 +- src/sage/graphs/digraph_generators.py | 8 ++++---- src/sage/graphs/distances_all_pairs.pyx | 10 +++++----- src/sage/graphs/generators/chessboard.py | 12 ++++++------ src/sage/graphs/generators/random.py | 2 +- src/sage/graphs/generic_graph.py | 2 +- src/sage/graphs/graph_generators_pyx.pyx | 2 +- src/sage/graphs/graph_latex.py | 4 ++-- src/sage/graphs/hyperbolicity.pyx | 6 +++--- .../additive_abelian/additive_abelian_group.py | 2 +- src/sage/groups/perm_gps/permgroup.py | 2 +- src/sage/homology/cell_complex.py | 6 +++--- src/sage/homology/chain_complex_morphism.py | 2 +- src/sage/homology/chain_homotopy.py | 2 +- src/sage/homology/delta_complex.py | 2 +- src/sage/homology/homology_morphism.py | 8 ++++---- src/sage/homology/simplicial_complex.py | 4 ++-- src/sage/homology/simplicial_complex_morphism.py | 2 +- src/sage/interfaces/magma.py | 2 +- src/sage/interfaces/qepcad.py | 2 +- src/sage/matrix/matrix_integer_dense.pyx | 4 ++-- src/sage/matrix/matrix_integer_dense_hnf.py | 2 +- src/sage/misc/cython.py | 2 +- src/sage/misc/explain_pickle.py | 2 +- src/sage/misc/function_mangling.pyx | 2 +- src/sage/misc/nested_class.pyx | 2 +- src/sage/misc/table.py | 6 +++--- src/sage/misc/viewer.py | 12 ++++++------ .../modular/arithgroup/arithgroup_generic.py | 2 +- src/sage/modular/etaproducts.py | 2 +- src/sage/modular/modsym/ambient.py | 2 +- src/sage/modules/fg_pid/fgp_module.py | 4 ++-- src/sage/modules/free_module.py | 4 ++-- src/sage/parallel/multiprocessing_sage.py | 2 +- src/sage/plot/plot.py | 12 ++++++------ src/sage/rings/complex_interval.pyx | 2 +- src/sage/rings/complex_mpc.pyx | 2 +- src/sage/rings/complex_number.pyx | 4 ++-- src/sage/rings/fraction_field_FpT.pyx | 12 ++++++------ .../rings/padics/eisenstein_extension_generic.py | 4 ++-- src/sage/rings/padics/padic_ZZ_pX_element.pyx | 12 ++++++------ src/sage/rings/padics/padic_base_leaves.py | 8 ++++---- src/sage/rings/padics/padic_ext_element.pyx | 2 +- src/sage/rings/padics/padic_extension_leaves.py | 16 ++++++++-------- src/sage/rings/padics/padic_generic.py | 4 ++-- src/sage/rings/padics/padic_generic_element.pyx | 4 ++-- src/sage/rings/padics/padic_printing.pyx | 8 ++++---- .../rings/padics/unramified_extension_generic.py | 10 +++++----- src/sage/rings/polynomial/polynomial_element.pyx | 2 +- src/sage/rings/real_mpfi.pyx | 2 +- src/sage/schemes/elliptic_curves/heegner.py | 4 ++-- src/sage/sets/cartesian_product.py | 2 +- src/sage/structure/global_options.py | 2 +- src/sage/structure/sage_object.pyx | 2 +- src/sage/symbolic/pynac.pyx | 2 +- 65 files changed, 135 insertions(+), 135 deletions(-) diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index 42f03fc918a..05e1d7ab64b 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -769,7 +769,7 @@ def multiplication_table(self, names='letters', elements=None): :meth:`~sage.matrix.operation_table.OperationTable.dict` method. - INPUTS: + INPUT: - ``names`` - the type of names used diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index bc219f5a264..6c10d2df7f2 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -2352,7 +2352,7 @@ def cartesian_projection(self, i): Return the projection of ``self`` onto the `i`-th factor of the cartesian product. - INPUTS: + INPUT: - ``i`` -- the index of a factor of the cartesian product diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 3a9c4679b2a..eff14026f07 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -2240,7 +2240,7 @@ def cartesian_embedding(self, i): Return the natural embedding morphism of the ``i``-th cartesian factor (summand) of ``self`` into ``self``. - INPUTS: + INPUT: - ``i`` -- an integer @@ -2274,7 +2274,7 @@ def cartesian_projection(self, i): Return the natural projection onto the `i`-th cartesian factor (summand) of ``self``. - INPUTS: + INPUT: - ``i`` -- an integer diff --git a/src/sage/combinat/output.py b/src/sage/combinat/output.py index e0538ad33a8..619feafb3ab 100644 --- a/src/sage/combinat/output.py +++ b/src/sage/combinat/output.py @@ -252,7 +252,7 @@ def tex_from_skew_array(array, with_lines=False, align='b'): principe, be anything but probably should be strings or integers of similar width. A row consisting completely of ``None``'s is allowed. - INPUTS: + INPUT: - ``array`` -- The array diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 072662e5732..40b0ce6f68b 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -3782,7 +3782,7 @@ def degree(self, weights=None): each letter in the ordered alphabet is given by weights, which defaults to [1, 2, 3, ...]. - INPUTS: + INPUT: - ``weights`` - a list or tuple, or a dictionary keyed by the letters occurring in self. diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index e0b7fce380e..539d05dce2b 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -1219,7 +1219,7 @@ def __call__(self, P, K): Both must be given as state arrays or coercible to state arrays. - INPUTS: + INPUT: - ``P`` - plaintext as state array or something coercible to a qstate array diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 47449304c22..4edad5c4da8 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -1042,7 +1042,7 @@ def run_doctests(module, options=None): """ Runs the doctests in a given file. - INPUTS: + INPUT: - ``module`` -- a Sage module, a string, or a list of such. diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 94f3ddf82a9..3d9c831a552 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -458,7 +458,7 @@ def parse(self, string, *args): r""" A Sage specialization of :class:`doctest.DocTestParser`. - INPUTS: + INPUT: - ``string`` -- the string to parse. - ``name`` -- optional string giving the name indentifying string, diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 2bb7c37131c..f28e17a6505 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -1920,7 +1920,7 @@ cdef class InstructionStream: r""" Initialize an InstructionStream. - INPUTS: + INPUT: - metadata - The metadata_by_opname from a wrapper module diff --git a/src/sage/game_theory/matching_game.py b/src/sage/game_theory/matching_game.py index ae4f0d038db..c755060559a 100644 --- a/src/sage/game_theory/matching_game.py +++ b/src/sage/game_theory/matching_game.py @@ -689,7 +689,7 @@ def add_suitor(self, name=None): r""" Add a suitor to the game. - INPUTS: + INPUT: - ``name`` -- can be a string or a number; if left blank will automatically generate an integer @@ -760,7 +760,7 @@ def add_reviewer(self, name=None): r""" Add a reviewer to the game. - INPUTS: + INPUT: - ``name`` -- can be a string or number; if left blank will automatically generate an integer diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 5dd6026b55d..df05287f8a5 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -521,7 +521,7 @@ def add_vertices(self, vertices, left=False, right=False): vertices. Vertices that already exist in the graph will not be added again. - INPUTS: + INPUT: - ``vertices`` -- sequence of vertices to add. diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index 7201e2f6d3c..700f67ac5a6 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -721,7 +721,7 @@ def GeneralizedDeBruijn(self, n, d): When `n = d^{D}`, the generalized de Bruijn digraph is isomorphic to the de Bruijn digraph of degree `d` and diameter `D`. - INPUTS: + INPUT: - ``n`` -- is the number of vertices of the digraph @@ -795,7 +795,7 @@ def ImaseItoh(self, n, d): the digraph of Imase and Itoh is isomorphic to the Kautz digraph [Kautz68]_ of degree `d` and diameter `D`. - INPUTS: + INPUT: - ``n`` -- is the number of vertices of the digraph @@ -868,7 +868,7 @@ def Kautz(self, k, D, vertices = 'strings'): See also the :wikipedia:`Wikipedia article on Kautz Graphs `. - INPUTS: + INPUT: - ``k`` -- Two possibilities for this parameter : - An integer equal to the degree of the digraph to be produced, that @@ -1052,7 +1052,7 @@ def RandomDirectedGNP(self, n, p, loops = False, seed = None): Returns a random digraph on `n` nodes. Each edge is inserted independently with probability `p`. - INPUTS: + INPUT: - ``n`` -- number of nodes of the digraph diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index db1238e0af3..952b9e635a0 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -910,7 +910,7 @@ cdef inline uint32_t simple_BFS(uint32_t n, either the last computed distance when all vertices are seen, or a very large number (UINT32_MAX) when the graph is not connected. - INPUTS: + INPUT: - ``n`` -- number of vertices of the graph. @@ -1007,7 +1007,7 @@ cdef uint32_t diameter_lower_bound_2sweep(uint32_t n, this method is linear in the size of the graph. - INPUTS: + INPUT: - ``n`` -- number of vertices of the graph. @@ -1076,7 +1076,7 @@ cdef tuple diameter_lower_bound_multi_sweep(uint32_t n, bound on the diameter, s is a vertex of eccentricity LB, d is a vertex at distance LB from s, and m is a vertex at distance LB/2 from both s and d. - INPUTS: + INPUT: - ``n`` -- number of vertices of the graph. @@ -1152,7 +1152,7 @@ cdef uint32_t diameter_iFUB(uint32_t n, `O(nm)`, but it can be very fast in practice. See the code's documentation and [CGH+13]_ for more details. - INPUTS: + INPUT: - ``n`` -- number of vertices of the graph. @@ -1239,7 +1239,7 @@ def diameter(G, method='iFUB', source=None): quickly return a lower bound on the diameter using the ``2sweep`` and ``multi-sweep`` schemes. - INPUTS: + INPUT: - ``method`` -- (default: 'iFUB') specifies the algorithm to use among: diff --git a/src/sage/graphs/generators/chessboard.py b/src/sage/graphs/generators/chessboard.py index 21c2189ba1c..0c89cbd78b7 100644 --- a/src/sage/graphs/generators/chessboard.py +++ b/src/sage/graphs/generators/chessboard.py @@ -36,7 +36,7 @@ def ChessboardGraphGenerator(dim_list, Graphs, Bishop Graph, and many generalizations. It also allows to avoid redondant code. - INPUTS: + INPUT: - ``dim_list`` -- an iterable object (list, set, dict) providing the dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard. @@ -248,7 +248,7 @@ def QueenGraph(dim_list, radius=None, relabel=False): chromatic number of a `(n,n)`-Queen Graph is at least `n`, and it is exactly `n` when `n\equiv 1,5 \bmod{6}`. - INPUTS: + INPUT: - ``dim_list`` -- an iterable object (list, set, dict) providing the dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard. @@ -321,7 +321,7 @@ def KingGraph(dim_list, radius=None, relabel=False): All 2-dimensional King Graphs are Hamiltonian, biconnected, and have chromatic number 4 as soon as both dimensions are larger or equal to 2. - INPUTS: + INPUT: - ``dim_list`` -- an iterable object (list, set, dict) providing the dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard. @@ -382,7 +382,7 @@ def KnightGraph(dim_list, one=1, two=2, relabel=False): The `(n,n)`-Knight Graph is Hamiltonian for even `n > 4`. - INPUTS: + INPUT: - ``dim_list`` -- an iterable object (list, set, dict) providing the dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard. @@ -443,7 +443,7 @@ def RookGraph(dim_list, radius=None, relabel=False): The Rook's Graph for an `n\times m` chessboard may also be defined as the Cartesian product of two complete graphs `K_n \square K_m`. - INPUTS: + INPUT: - ``dim_list`` -- an iterable object (list, set, dict) providing the dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard. @@ -497,7 +497,7 @@ def BishopGraph(dim_list, radius=None, relabel=False): The Bishop Graph is not connected. - INPUTS: + INPUT: - ``dim_list`` -- an iterable object (list, set, dict) providing the dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard. diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 246250dc086..298e35dc60b 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -24,7 +24,7 @@ def RandomGNP(n, p, seed=None, fast=True, method='Sage'): Returns a random graph on `n` nodes. Each edge is inserted independently with probability `p`. - INPUTS: + INPUT: - ``n`` -- number of nodes of the graph diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 35523ab9145..8c855000475 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -17178,7 +17178,7 @@ def set_latex_options(self, **kwds): r""" Sets multiple options for rendering a graph with LaTeX. - INPUTS: + INPUT: - ``kwds`` - any number of option/value pairs to set many graph latex options at once (a variable number, in any diff --git a/src/sage/graphs/graph_generators_pyx.pyx b/src/sage/graphs/graph_generators_pyx.pyx index ba9dfe8281c..9feb6301b30 100644 --- a/src/sage/graphs/graph_generators_pyx.pyx +++ b/src/sage/graphs/graph_generators_pyx.pyx @@ -22,7 +22,7 @@ def RandomGNP(n, p, directed = False, loops = False): Returns a random graph or a digraph on `n` nodes. Each edge is inserted independently with probability `p`. - INPUTS: + INPUT: - ``n`` -- number of nodes of the digraph diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 695a464a456..b5b7e3182c8 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -596,7 +596,7 @@ def set_option(self, option_name, option_value = None): :meth:`sage.graphs.generic_graph.GenericGraph.set_latex_options` method is the easiest way to set options, and allows several to be set at once. - INPUTS: + INPUT: - ``option_name`` - a string for a latex option contained in the list ``sage.graphs.graph_latex.GraphLatex.__graphlatex_options``. A @@ -1198,7 +1198,7 @@ def set_options(self, **kwds): r""" Set several LaTeX options for a graph all at once. - INPUTS: + INPUT: - kwds - any number of option/value pairs to se many graph latex options at once (a variable number, in any order). Existing diff --git a/src/sage/graphs/hyperbolicity.pyx b/src/sage/graphs/hyperbolicity.pyx index 07d3b4703f4..5e790dbe057 100644 --- a/src/sage/graphs/hyperbolicity.pyx +++ b/src/sage/graphs/hyperbolicity.pyx @@ -294,7 +294,7 @@ cdef tuple hyperbolicity_basic_algorithm(int N, of a graph which tests all 4-tuples of vertices not satisfying a cutting rule proposed in [Soto11]_. - INPUTS: + INPUT: - ``N`` -- number of vertices of the graph. @@ -619,7 +619,7 @@ cdef tuple hyperbolicity_BCCM(int N, This method assumes that the graph under consideration is connected. - INPUTS: + INPUT: - ``N`` -- number of vertices of the graph @@ -875,7 +875,7 @@ cdef tuple hyperbolicity_CCL(int N, This method assumes that the graph under consideration is connected. - INPUTS: + INPUT: - ``N`` -- number of vertices of the graph diff --git a/src/sage/groups/additive_abelian/additive_abelian_group.py b/src/sage/groups/additive_abelian/additive_abelian_group.py index 3bf8aef61e6..9337a6866b5 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_group.py +++ b/src/sage/groups/additive_abelian/additive_abelian_group.py @@ -15,7 +15,7 @@ def AdditiveAbelianGroup(invs, remember_generators = True): r""" Construct a finitely-generated additive abelian group. - INPUTS: + INPUT: - ``invs`` (list of integers): the invariants. These should all be greater than or equal to zero. diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 517575ccfca..22cd0a9927c 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -4081,7 +4081,7 @@ def __init__(self, ambient, gens=None, gap_group=None, domain=None, Initialization method for the ``PermutationGroup_subgroup`` class. - INPUTS: + INPUT: - ``ambient`` - the ambient group from which to construct this subgroup diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index f0767a22201..809c7236e7f 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -657,7 +657,7 @@ def n_chains(self, n, base_ring=None, cochains=False): r""" Return the free module of chains in degree ``n`` over ``base_ring``. - INPUTS: + INPUT: - ``n`` -- integer - ``base_ring`` -- ring (optional, default `\ZZ`) @@ -760,7 +760,7 @@ def homology_with_basis(self, base_ring=None, cohomology=False): This is implemented for simplicial, cubical, and `\Delta`-complexes, not for arbitrary generic cell complexes. - INPUTS: + INPUT: - ``base_ring`` -- coefficient ring (optional, default ``QQ``); must be a field @@ -819,7 +819,7 @@ def cohomology_ring(self, base_ring=None): for computing cohomology operations; so far, only mod 2 cohomology operations have been implemented. - INPUTS: + INPUT: - ``base_ring`` -- coefficient ring (optional, default ``QQ``); must be a field diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index 5e79d25db3b..94755cdfc40 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -228,7 +228,7 @@ def to_matrix(self, deg=None): degree; otherwise, return the (block) matrix for the whole chain map. - INPUTS: + INPUT: - ``deg`` -- (optional, default ``None``) the degree diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index 11350ec6c43..5585410d77a 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -401,7 +401,7 @@ class ChainContraction(ChainHomotopy): ``H`` is defined by a dictionary ``matrices`` of matrices. - INPUTS: + INPUT: - ``matrices`` -- dictionary of matrices, keyed by dimension - ``pi`` -- a chain map `C \to D` diff --git a/src/sage/homology/delta_complex.py b/src/sage/homology/delta_complex.py index b859b480057..6580df47746 100644 --- a/src/sage/homology/delta_complex.py +++ b/src/sage/homology/delta_complex.py @@ -1442,7 +1442,7 @@ def n_chains(self, n, base_ring=None, cochains=False): r""" Return the free module of chains in degree ``n`` over ``base_ring``. - INPUTS: + INPUT: - ``n`` -- integer - ``base_ring`` -- ring (optional, default `\ZZ`) diff --git a/src/sage/homology/homology_morphism.py b/src/sage/homology/homology_morphism.py index c18cc78b1bf..fca4a6691a1 100644 --- a/src/sage/homology/homology_morphism.py +++ b/src/sage/homology/homology_morphism.py @@ -39,7 +39,7 @@ class InducedHomologyMorphism(Morphism): induced by a map of simplicial complexes. It requires working with field coefficients. - INPUTS: + INPUT: - ``map`` -- the map of simplicial complexes - ``base_ring`` -- a field (optional, default ``QQ``) @@ -122,7 +122,7 @@ class in the torus, we can define a map `S^1 \to T` inducing an """ def __init__(self, map, base_ring=None, cohomology=False): """ - INPUTS: + INPUT: - ``map`` -- the map of simplicial complexes - ``base_ring`` -- a field (optional, default ``QQ``) @@ -200,7 +200,7 @@ def to_matrix(self, deg=None): degree; otherwise, return the block matrix representing the entire map. - INPUTS: + INPUT: - ``deg`` -- (optional, default ``None``) the degree @@ -280,7 +280,7 @@ def __eq__(self, other): """ Return ``True`` if and only if this map agrees with ``other``. - INPUTS: + INPUT: - ``other`` -- another induced homology morphism diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index 98c5ab48003..65612155276 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -634,7 +634,7 @@ def alexander_whitney(self, dim): subdivide it into simplices `(v_0, v_1, ..., v_{dim})` and `(v_{dim}, v_{dim + 1}, ..., v_n)`. - INPUTS: + INPUT: - ``dim`` -- integer between 0 and one more than the dimension of this simplex @@ -1223,7 +1223,7 @@ def face_iterator(self, increasing=True): """ An iterator for the faces in this simplicial complex. - INPUTS: + INPUT: - ``increasing`` -- (optional, default ``True``) if ``True``, return faces in increasing order of dimension, thus starting with diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py index 4ad792a2778..7a1c1258a49 100644 --- a/src/sage/homology/simplicial_complex_morphism.py +++ b/src/sage/homology/simplicial_complex_morphism.py @@ -649,7 +649,7 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): """ The map in (co)homology induced by this map - INPUTS: + INPUT: - ``base_ring`` -- must be a field (optional, default ``QQ``) diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index a4106b43d51..cc6522a9830 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -2410,7 +2410,7 @@ def _latex_(self): def set_magma_attribute(self, attrname, value): """ - INPUTS: attrname - string value - something coercible to a + INPUT: attrname - string value - something coercible to a MagmaElement EXAMPLES:: diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index b0a2e15554b..e90bfffbb37 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -1914,7 +1914,7 @@ def formula(self, formula): r""" Constructs a QEPCAD formula from the given input. - INPUTS: + INPUT: - ``formula`` -- a polynomial, a symbolic equality or inequality, or a list of polynomials, equalities, or inequalities diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 043b70f29b8..bc48e835830 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -2681,7 +2681,7 @@ cdef class Matrix_integer_dense(matrix_dense.Matrix_dense): # dense or sparse ``block_size`` should be between 2 and the number of rows of ``self``. - NLT SPECIFIC INPUTS: + NLT SPECIFIC INPUT: - ``prune`` -- (default: ``0``) The optional parameter ``prune`` can be set to any positive number to invoke the Volume Heuristic from @@ -2697,7 +2697,7 @@ cdef class Matrix_integer_dense(matrix_dense.Matrix_dense): # dense or sparse orthogonalization strategy. For a nice description of this, see Chapter 5 of [GL96]_. - fpLLL SPECIFIC INPUTS: + fpLLL SPECIFIC INPUT: - ``precision`` -- (default: ``0`` for automatic choice) bit precision to use if ``fp='rr'`` is set diff --git a/src/sage/matrix/matrix_integer_dense_hnf.py b/src/sage/matrix/matrix_integer_dense_hnf.py index 498c6fda4a1..3460cb405c2 100644 --- a/src/sage/matrix/matrix_integer_dense_hnf.py +++ b/src/sage/matrix/matrix_integer_dense_hnf.py @@ -190,7 +190,7 @@ def det_padic(A, proof=True, stabilize=2): Return the determinant of A, computed using a p-adic/multimodular algorithm. - INPUTS: + INPUT: - ``A`` -- a square matrix diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 8fd9e67f6ff..981df7ce466 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -288,7 +288,7 @@ def cython(filename, verbose=False, compile_message=False, and then compiles that. The .c file and the .so file are created in a temporary directory. - INPUTS: + INPUT: - ``filename`` - the name of the file to be compiled. Should end with 'pyx'. diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index 50d7c2f9858..3e0661ce494 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -177,7 +177,7 @@ def explain_pickle(pickle=None, file=None, compress=True, **kwargs): of ``explain_pickle`` to ``sage_eval`` should be totally equivalent to loading the ``pickle`` with ``cPickle``. - INPUTS: + INPUT: - ``pickle`` -- the pickle to explain, as a string (default: None) - ``file`` -- a filename of a pickle (default: None) diff --git a/src/sage/misc/function_mangling.pyx b/src/sage/misc/function_mangling.pyx index 83ab48bdfe9..ae8b0cdfb60 100644 --- a/src/sage/misc/function_mangling.pyx +++ b/src/sage/misc/function_mangling.pyx @@ -78,7 +78,7 @@ cdef class ArgumentFixer: For the purpose of cached functions, it is important not to distinguish between these uses. - INPUTS: + INPUT: - f -- a function - classmethod -- boolean (default False) -- True if the function diff --git a/src/sage/misc/nested_class.pyx b/src/sage/misc/nested_class.pyx index e05930d55d6..fa6f905e8cf 100644 --- a/src/sage/misc/nested_class.pyx +++ b/src/sage/misc/nested_class.pyx @@ -85,7 +85,7 @@ cpdef modify_for_nested_pickle(cls, str name_prefix, module, first_run=True): giving them a mangled name and putting the mangled name in the module namespace. - INPUTS: + INPUT: - ``cls`` - The class to modify. - ``name_prefix`` - The prefix to prepend to the class name. diff --git a/src/sage/misc/table.py b/src/sage/misc/table.py index 521b60714e3..2e6df24a755 100644 --- a/src/sage/misc/table.py +++ b/src/sage/misc/table.py @@ -19,7 +19,7 @@ class table(SageObject): Display a rectangular array as a table, either in plain text, LaTeX, or html. - INPUTS: + INPUT: - ``rows`` (default ``None``) - a list of lists (or list of tuples, etc.), containing the data to be displayed. @@ -303,7 +303,7 @@ def options(self, **kwds): With no arguments, return the dictionary of options for this table. With arguments, modify options. - INPUTS: + INPUT: - ``header_row`` - if True, first row is highlighted. - ``header_column`` - if True, first column is highlighted. @@ -752,7 +752,7 @@ def _html_table_row(self, file, row, header=False): Helper method used by the :meth:`_html_` method. - INPUTS: + INPUT: - ``file`` -- file-like object. The table row data will be written to it. diff --git a/src/sage/misc/viewer.py b/src/sage/misc/viewer.py index 1a1fec36247..563f007c18a 100644 --- a/src/sage/misc/viewer.py +++ b/src/sage/misc/viewer.py @@ -161,7 +161,7 @@ def _set(self, app=None, TYPE='browser'): Change the default viewer. Return the current setting if the argument ``app`` is ``None``. - INPUTS: + INPUT: - ``app`` -- ``None`` or a string, the program to use - ``TYPE`` -- a string, must be in the list ``VIEWERS`` defined in @@ -197,7 +197,7 @@ def browser(self, app=None): Change the default browser. Return the current setting if arg is ``None``, which is the default. - INPUTS: + INPUT: - ``app`` -- ``None`` or a string, the program to use @@ -217,7 +217,7 @@ def dvi_viewer(self, app=None): Change the default dvi viewer. Return the current setting if arg is ``None``, which is the default. - INPUTS: + INPUT: - ``app`` -- ``None`` or a string, the program to use @@ -237,7 +237,7 @@ def pdf_viewer(self, app=None): Change the default pdf viewer. Return the current setting if arg is ``None``, which is the default. - INPUTS: + INPUT: - ``app`` -- ``None`` or a string, the program to use @@ -257,7 +257,7 @@ def png_viewer(self, app=None): Change the default png viewer. Return the current setting if arg is ``None``, which is the default. - INPUTS: + INPUT: - ``app`` -- ``None`` or a string, the program to use @@ -276,7 +276,7 @@ def __call__(self, x=None): """ Return the current setting for a viewer program. - INPUTS: + INPUT: - ``x`` -- string diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index aa88edc54c8..51f79004585 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -679,7 +679,7 @@ def cusps(self, algorithm='default'): representatives for the orbits of self on `\mathbb{P}^1(\QQ)`. These should be returned in a reduced form where this makes sense. - INPUTS: + INPUT: - ``algorithm`` -- which algorithm to use to compute the cusps of self. ``'default'`` finds representatives for a known complete set of diff --git a/src/sage/modular/etaproducts.py b/src/sage/modular/etaproducts.py index 688f16ad710..4596534a2f0 100644 --- a/src/sage/modular/etaproducts.py +++ b/src/sage/modular/etaproducts.py @@ -850,7 +850,7 @@ def eta_poly_relations(eta_elements, degree, labels=['x1','x2'], verbose=False): r""" Find polynomial relations between eta products. - INPUTS: + INPUT: - ``eta_elements`` - (list): a list of EtaGroupElement objects. Not implemented unless this list has precisely two elements. degree diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index d59a2e6475e..7d70b346060 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -366,7 +366,7 @@ def _element_constructor_(self, x, computed_with_hecke=False): Coerce `x` into this modular symbols space. The result is either an element of self or a subspace of self. - INPUTS: + INPUT: The allowed input types for `x` are as follows: diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index ca2b8b46efa..aa985c95818 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -1237,7 +1237,7 @@ def hom(self, im_gens, codomain=None, check=True): the same as the Smith form generators, since this may not be true for a general derived class. - INPUTS: + INPUT: - ``im_gens`` -- a list of the images of ``self.gens()`` in some R-module @@ -1396,7 +1396,7 @@ def _hom_from_smith(self, im_smith_gens, check=True): Homomorphism defined by giving the images of the Smith-form generators of self in some fixed fg R-module. - INPUTS: + INPUT: - ``im_gens`` -- a Sequence object giving the images of the Smith-form generators of self, whose universe is some fixed fg R-module diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index c688167722d..101d05f144e 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -4488,7 +4488,7 @@ def linear_combination_of_basis(self, v): Return the linear combination of the basis for self obtained from the elements of the list v. - INPUTS: + INPUT: - ``v`` - list @@ -6047,7 +6047,7 @@ def linear_combination_of_basis(self, v): Return the linear combination of the basis for self obtained from the coordinates of v. - INPUTS: + INPUT: - ``v`` - list diff --git a/src/sage/parallel/multiprocessing_sage.py b/src/sage/parallel/multiprocessing_sage.py index 579582aeb69..b8b77a0833f 100644 --- a/src/sage/parallel/multiprocessing_sage.py +++ b/src/sage/parallel/multiprocessing_sage.py @@ -21,7 +21,7 @@ def pyprocessing(processes=0): Return a parallel iterator using a given number of processes implemented using pyprocessing. - INPUTS: + INPUT: - ``processes`` -- integer (default: 0); if 0, set to the number of processors on the computer. diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 907ef6cdaea..59513ecf4b5 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -2075,7 +2075,7 @@ def plot_loglog(funcs, *args, **kwds): Plot graphics in 'loglog' scale, that is, both the horizontal and the vertical axes will be in logarithmic scale. - INPUTS: + INPUT: - ``base`` -- (default: 10) the base of the logarithm. This must be greater than 1. The base can be also given as a list or tuple @@ -2110,7 +2110,7 @@ def plot_semilogx(funcs, *args, **kwds): Plot graphics in 'semilogx' scale, that is, the horizontal axis will be in logarithmic scale. - INPUTS: + INPUT: - ``base`` -- (default: 10) the base of the logarithm. This must be greater than 1. @@ -2138,7 +2138,7 @@ def plot_semilogy(funcs, *args, **kwds): Plot graphics in 'semilogy' scale, that is, the vertical axis will be in logarithmic scale. - INPUTS: + INPUT: - ``base`` -- (default: 10) the base of the logarithm. This must be greater than 1. @@ -2166,7 +2166,7 @@ def list_plot_loglog(data, plotjoined=False, **kwds): Plot the ``data`` in 'loglog' scale, that is, both the horizontal and the vertical axes will be in logarithmic scale. - INPUTS: + INPUT: - ``base`` -- (default: 10) the base of the logarithm. This must be greater than 1. The base can be also given as a list or tuple @@ -2219,7 +2219,7 @@ def list_plot_semilogx(data, plotjoined=False, **kwds): Plot ``data`` in 'semilogx' scale, that is, the horizontal axis will be in logarithmic scale. - INPUTS: + INPUT: - ``base`` -- (default: 10) the base of the logarithm. This must be greater than 1. @@ -2263,7 +2263,7 @@ def list_plot_semilogy(data, plotjoined=False, **kwds): Plot ``data`` in 'semilogy' scale, that is, the vertical axis will be in logarithmic scale. - INPUTS: + INPUT: - ``base`` -- (default: 10) the base of the logarithm. This must be greater than 1. diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 936ed82c762..190e4be0025 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -175,7 +175,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): Returns either the real or imaginary component of ``self`` depending on the choice of ``i``: real (``i=0``), imaginary (``i=1``) - INPUTS: + INPUT: - ``i`` - 0 or 1 diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 16deacd6dab..900f26956fa 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -941,7 +941,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): Returns either the real or imaginary component of ``self`` depending on the choice of ``i``: real (``i``=0), imaginary (``i``=1). - INPUTS: + INPUT: - ``i`` -- 0 or 1 diff --git a/src/sage/rings/complex_number.pyx b/src/sage/rings/complex_number.pyx index 8e4de8876a7..26f5c955b11 100644 --- a/src/sage/rings/complex_number.pyx +++ b/src/sage/rings/complex_number.pyx @@ -388,7 +388,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): Returns either the real or imaginary component of self depending on the choice of i: real (i=0), imaginary (i=1) - INPUTS: + INPUT: - ``i`` - 0 or 1 - ``0`` -- will return the real component of ``self`` @@ -462,7 +462,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): r""" Return a string representation of ``self``. - INPUTS: + INPUT: - ``base`` -- (Default: 10) The base to use for printing diff --git a/src/sage/rings/fraction_field_FpT.pyx b/src/sage/rings/fraction_field_FpT.pyx index ee3c10cf786..507a1baef77 100644 --- a/src/sage/rings/fraction_field_FpT.pyx +++ b/src/sage/rings/fraction_field_FpT.pyx @@ -851,7 +851,7 @@ cdef class FpT_iter: """ def __init__(self, parent, degree=None, FpTElement start=None): """ - INPUTS: + INPUT: - parent -- The FpT that we're iterating over. @@ -1013,7 +1013,7 @@ cdef class Polyring_FpT_coerce(RingHomomorphism_coercion): def __init__(self, R): """ - INPUTS: + INPUT: - R -- An FpT @@ -1196,7 +1196,7 @@ cdef class FpT_Polyring_section(Section): def __init__(self, Polyring_FpT_coerce f): """ - INPUTS: + INPUT: - f -- A Polyring_FpT_coerce homomorphism @@ -1307,7 +1307,7 @@ cdef class Fp_FpT_coerce(RingHomomorphism_coercion): def __init__(self, R): """ - INPUTS: + INPUT: - R -- An FpT @@ -1474,7 +1474,7 @@ cdef class FpT_Fp_section(Section): def __init__(self, Fp_FpT_coerce f): """ - INPUTS: + INPUT: - f -- An Fp_FpT_coerce homomorphism @@ -1604,7 +1604,7 @@ cdef class ZZ_FpT_coerce(RingHomomorphism_coercion): def __init__(self, R): """ - INPUTS: + INPUT: - R -- An FpT diff --git a/src/sage/rings/padics/eisenstein_extension_generic.py b/src/sage/rings/padics/eisenstein_extension_generic.py index b45a5fbfd0e..62488dbe413 100644 --- a/src/sage/rings/padics/eisenstein_extension_generic.py +++ b/src/sage/rings/padics/eisenstein_extension_generic.py @@ -64,7 +64,7 @@ def ramification_index(self, K = None): valuation map on K in the image of the valuation map on self (both normalized so that the valuation of p is 1). - INPUTS: + INPUT: - self -- an Eisenstein extension - K -- a subring of self (default None -> self.ground_ring()) @@ -97,7 +97,7 @@ def inertia_degree(self, K = None): fields induced by this extensions. Since Eisenstein extensions are totally ramified, this will be 1 for K=None. - INPUTS: + INPUT: - self -- an Eisenstein extension - K -- a subring of self (default None -> self.ground_ring()) diff --git a/src/sage/rings/padics/padic_ZZ_pX_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_element.pyx index 1a532f9423c..e2c518b841d 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_element.pyx @@ -238,7 +238,7 @@ cdef class pAdicZZpXElement(pAdicExtElement): Note that zeros are truncated from the returned list, so you must use the valuation() function to completely recover self. - INPUTS: + INPUT: - ``pos`` -- ``bint``. If ``True``, all integers will be in the range `[0,p-1]`, otherwise they will be in the range @@ -552,7 +552,7 @@ def _test_preprocess_list(R, L): Given a list of elements convertible to ``ntl_ZZ_p``s, finds the appropriate absolute precision and returns a list of either ``ntl_ZZs`` or ``ntl_ZZ_ps``. - INPUTS: + INPUT: - ``R`` -- a `p`-adic extension ring @@ -678,7 +678,7 @@ def _find_val_aprec_test(R, L): Given a list ``L``, finds the minimum valuation, minimum absolute precision and minimum common type of the elements. - INPUTS: + INPUT: - ``R`` -- a `p`-adic extension - ``L`` -- a list of integers, rationals, ``IntegerMods``, etc. @@ -720,7 +720,7 @@ cdef find_val_aprec(PowComputer_ext pp, L): Given a list ``L``, finds the minimum valuation, minimum absolute precision and minimum common type of the elements. - INPUTS: + INPUT: - ``pp`` -- a PowComputer_ext for the element that this list is being initialized into. @@ -754,7 +754,7 @@ def _test_get_val_prec(R, a): Returns valuation, absolute precision and type of an input element. - INPUTS: + INPUT: - ``R`` -- A `p`-adic extension ring to provide a ``PowComputer_ext`` @@ -825,7 +825,7 @@ cdef get_val_prec(PowComputer_ext pp, a): """ Returns valuation, absolute precision and type of an input element. - INPUTS: + INPUT: - ``pp`` -- A ``PowComputer_ext`` diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 55de7f5c625..c9eb87c5e1b 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -208,7 +208,7 @@ def __init__(self, p, prec, print_mode, names): """ Initialization. - INPUTS: + INPUT: - ``p`` -- prime - ``prec`` -- precision cap @@ -297,7 +297,7 @@ def __init__(self, p, prec, print_mode, names): """ Initialization. - INPUTS: + INPUT: - ``p`` -- prime - ``prec`` -- precision cap @@ -388,7 +388,7 @@ def __init__(self, p, prec, print_mode, names): """ Initialization - INPUTS: + INPUT: - ``p`` -- prime - ``prec`` -- precision cap @@ -505,7 +505,7 @@ def __init__(self, p, prec, print_mode, names): """ Initialization. - INPUTS:: + INPUT:: - ``p`` -- prime - ``prec`` -- precision cap diff --git a/src/sage/rings/padics/padic_ext_element.pyx b/src/sage/rings/padics/padic_ext_element.pyx index 9212b83cfef..9a1802248b0 100644 --- a/src/sage/rings/padics/padic_ext_element.pyx +++ b/src/sage/rings/padics/padic_ext_element.pyx @@ -299,7 +299,7 @@ cdef class pAdicExtElement(pAdicGenericElement): Note that zeros are truncated from the returned list, so you must use the valuation() function to completely recover self. - INPUTS:: + INPUT:: - pos -- bint. If True, all integers will be in the range [0,p-1], otherwise they will be in the range [(1-p)/2, p/2]. diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index e66cd48d0e6..c22eef50600 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -58,7 +58,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped relative representation of Zq. - INPUTS:: + INPUT:: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -106,7 +106,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A representation of Qq. - INPUTS:: + INPUT:: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -165,7 +165,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped absolute representation of Zq. - INPUTS:: + INPUT:: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -214,7 +214,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A fixed modulus representation of Zq. - INPUTS:: + INPUT:: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -268,7 +268,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped relative representation of an eisenstein extension of Zp. - INPUTS:: + INPUT:: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -325,7 +325,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped relative representation of an eisenstein extension of Qp. - INPUTS:: + INPUT:: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -393,7 +393,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped absolute representation of an eisenstein extension of Zp. - INPUTS:: + INPUT:: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -450,7 +450,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A fixed modulus representation of an eisenstein extension of Zp. - INPUTS:: + INPUT:: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 6cccca5d9e8..4d11a528800 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -44,7 +44,7 @@ def __init__(self, base, p, prec, print_mode, names, element_class, category=Non """ Initialization. - INPUTS:: + INPUT:: - base -- Base ring. - p -- prime @@ -85,7 +85,7 @@ def _modified_print_mode(self, print_mode): print options but modified by the options in the dictionary print_mode. - INPUTS:: + INPUT:: - print_mode -- dictionary with keys in ['mode', 'pos', 'ram_name', 'unram_name', 'var_name', 'max_ram_terms', 'max_unram_terms', 'max_terse_terms', 'sep', 'alphabet'] diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 1a334b28f17..203abfab923 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -528,7 +528,7 @@ cdef class pAdicGenericElement(LocalGenericElement): """ Returns a string representation of self. - INPUTS: + INPUT: - ``mode`` -- allows one to override the default print mode of the parent (default: ``None``). @@ -1704,7 +1704,7 @@ cdef class pAdicGenericElement(LocalGenericElement): to 0 under any homomorphism to the fraction field, which is a torsion free group. - INPUTS: + INPUT: - ``p_branch`` -- an element in the base ring or its fraction field; the implementation will choose the branch of the diff --git a/src/sage/rings/padics/padic_printing.pyx b/src/sage/rings/padics/padic_printing.pyx index 9b40318bc74..dc97838d98c 100644 --- a/src/sage/rings/padics/padic_printing.pyx +++ b/src/sage/rings/padics/padic_printing.pyx @@ -299,7 +299,7 @@ cdef class pAdicPrinter_class(SageObject): """ Initializes a pAdicPrinter. - INPUTS:: + INPUT:: - ring -- the ring or field to which this pAdicPrinter is attached. @@ -1190,7 +1190,7 @@ cdef class pAdicPrinter_class(SageObject): """ Takes a list L of coefficients and returns a list with at most max_terms nonzero terms. - INPUTS:: + INPUT:: - L -- a list @@ -1224,7 +1224,7 @@ cdef class pAdicPrinter_class(SageObject): """ Returns a string representation of L when considered as a polynomial, truncating to at most max_unram_terms nonzero terms. - INPUTS:: + INPUT:: - L -- A list of coefficients. @@ -1317,7 +1317,7 @@ cdef class pAdicPrinter_class(SageObject): """ Prints a list L as a polynomial. - INPUTS:: + INPUT:: - L -- A list of coefficients. diff --git a/src/sage/rings/padics/unramified_extension_generic.py b/src/sage/rings/padics/unramified_extension_generic.py index 26f28ce7629..076ef123f31 100644 --- a/src/sage/rings/padics/unramified_extension_generic.py +++ b/src/sage/rings/padics/unramified_extension_generic.py @@ -31,7 +31,7 @@ def __init__(self, poly, prec, print_mode, names, element_class): """ Initializes self - INPUTS:: + INPUT:: - poly -- Polynomial defining this extension. - prec -- The precision cap @@ -78,7 +78,7 @@ def ramification_index(self, K = None): """ Returns the ramification index of self over the subring K. - INPUTS:: + INPUT:: - K -- a subring (or subfield) of self. Defaults to the base. @@ -99,7 +99,7 @@ def inertia_degree(self, K = None): """ Returns the inertia degree of self over the subring K. - INPUTS:: + INPUT:: - K -- a subring (or subfield) of self. Defaults to the base. @@ -141,7 +141,7 @@ def discriminant(self, K=None): """ Returns the discriminant of self over the subring K. - INPUTS:: + INPUT:: - K -- a subring/subfield (defaults to the base ring). @@ -182,7 +182,7 @@ def is_galois(self, K=None): Every unramified extension is Galois. - INPUTS:: + INPUT:: - K -- a subring/subfield (defaults to the base ring). diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 0ec9ccc1560..47020dd5243 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4156,7 +4156,7 @@ cdef class Polynomial(CommutativeAlgebraElement): The additional inputs to this function are to speed up computation for field semantics (see note). - INPUTS: + INPUT: - ``n`` (default: ``None``) - if provided, should equal `q-1` where ``self.parent()`` is the field with `q` diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 7f2c6d1c296..884721a0959 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -1676,7 +1676,7 @@ cdef class RealIntervalFieldElement(RingElement): with the given base and error_digits. See the documentation for the str method for the definition of the question style. - INPUTS: + INPUT: - ``base`` - base for output diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index a15ae57d175..f601ae9a3c9 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -229,7 +229,7 @@ class RingClassField(SageObject): """ def __init__(self, D, c, check=True): """ - INPUTS: + INPUT: - `D` -- discriminant of quadratic imaginary field @@ -1994,7 +1994,7 @@ def discriminants(self, n=10, weak=False): Return the first `n` quadratic imaginary discriminants that satisfy the Heegner hypothesis for `N`. - INPUTS: + INPUT: - `n` -- nonnegative integer diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 0afc8910e2d..fe14890ec95 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -278,7 +278,7 @@ def cartesian_projection(self, i): :meth:`Sets.CartesianProducts.ElementMethods.cartesian_projection() `. - INPUTS: + INPUT: - ``i`` -- the index of a factor of the cartesian product diff --git a/src/sage/structure/global_options.py b/src/sage/structure/global_options.py index 432940e3f67..5932bf38e39 100644 --- a/src/sage/structure/global_options.py +++ b/src/sage/structure/global_options.py @@ -381,7 +381,7 @@ class GlobalOptions(SageObject): which specifies the individual options. The allowed/expected keys in the dictionary are the following: - INPUTS: + INPUT: - ``name`` -- Specifies a name for the options class (required) diff --git a/src/sage/structure/sage_object.pyx b/src/sage/structure/sage_object.pyx index 0a146b5c83c..c797b85cb4a 100644 --- a/src/sage/structure/sage_object.pyx +++ b/src/sage/structure/sage_object.pyx @@ -1424,7 +1424,7 @@ def picklejar(obj, dir=None): descriptions of them. Use the :func:`unpickle_all` to see if they unpickle later. - INPUTS: + INPUT: - ``obj`` -- a pickleable object diff --git a/src/sage/symbolic/pynac.pyx b/src/sage/symbolic/pynac.pyx index 1728d8bbb4a..46b9e0a89de 100644 --- a/src/sage/symbolic/pynac.pyx +++ b/src/sage/symbolic/pynac.pyx @@ -2120,7 +2120,7 @@ def register_symbol(obj, conversions): other systems such as Maxima, Mathematica, etc. This table is used to convert *from* other systems back to Sage. - INPUTS: + INPUT: - `obj` -- a symbolic object or function. From 878b2dd6ff7123a8d1aca1fe057a8ae0fcac0782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jori=20M=C3=A4ntysalo?= Date: Wed, 11 Nov 2015 13:47:30 +0200 Subject: [PATCH 1871/1872] Changed few "INPUT::" to "INPUT:". --- src/sage/graphs/base/graph_backends.pyx | 2 +- .../perm_gps/partn_ref/refinement_python.pyx | 4 ++-- src/sage/interfaces/qepcad.py | 2 +- src/sage/numerical/backends/generic_backend.pyx | 2 +- src/sage/rings/finite_rings/element_base.pyx | 2 +- src/sage/rings/finite_rings/residue_field.pyx | 2 +- src/sage/rings/padics/padic_base_leaves.py | 2 +- src/sage/rings/padics/padic_ext_element.pyx | 2 +- src/sage/rings/padics/padic_extension_leaves.py | 16 ++++++++-------- src/sage/rings/padics/padic_generic.py | 4 ++-- src/sage/rings/padics/padic_printing.pyx | 8 ++++---- .../rings/padics/unramified_extension_generic.py | 10 +++++----- .../polynomial/multi_polynomial_libsingular.pyx | 2 +- src/sage/rings/rational.pyx | 4 ++-- src/sage/sets/finite_set_map_cy.pyx | 4 ++-- src/sage/stats/hmm/chmm.pyx | 2 +- src/sage/structure/misc.pyx | 2 +- 17 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 92683e96318..f5ab9e8dc32 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -76,7 +76,7 @@ cdef class GenericGraphBackend(SageObject): Add an edge (u,v) to self, with label l. If directed is True, this is interpreted as an arc from u to v. - INPUT:: + INPUT: - ``u,v`` -- vertices - ``l`` -- edge label diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx index f6d6c998354..0a4ae3c67a7 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx @@ -414,7 +414,7 @@ def aut_gp_and_can_lab_python(S, partition, n, """ Calls the automorphism group and canonical label function. - INPUT:: + INPUT: S -- the object to examine partition -- an ordered partition, as a list of lists @@ -500,7 +500,7 @@ def double_coset_python(S1, S2, partition1, ordering2, n, """ Calls the double coset function. - INPUT:: + INPUT: S1, S2 -- the objects to examine partition1 -- an ordered partition, as a list of lists diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index e90bfffbb37..10667889576 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -619,7 +619,7 @@ def _qepcad_atoms(formula): r""" Return the atoms of a qepcad quantifier-free formula, as a set of strings. - INPUT:: + INPUT: - `formula` (string) - a quantifier-free formula. diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index dbf536daffd..bc7782583dc 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -262,7 +262,7 @@ cdef class GenericBackend: r""" Remove a constraint. - INPUT:: + INPUT: - ``i`` -- index of the constraint to remove. diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx index 37810256d0c..163c4ec9fe2 100644 --- a/src/sage/rings/finite_rings/element_base.pyx +++ b/src/sage/rings/finite_rings/element_base.pyx @@ -180,7 +180,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): Return a vector in self.parent().vector_space() matching self. The most significant bit is to the right. - INPUT:: + INPUT: - ``reverse`` -- reverse the order of the bits from little endian to big endian. diff --git a/src/sage/rings/finite_rings/residue_field.pyx b/src/sage/rings/finite_rings/residue_field.pyx index c6041c3e843..6c8fb487ce0 100644 --- a/src/sage/rings/finite_rings/residue_field.pyx +++ b/src/sage/rings/finite_rings/residue_field.pyx @@ -1739,7 +1739,7 @@ class ResidueFiniteField_givaro(ResidueField_generic, FiniteField_givaro): def _element_constructor_(self, x): """ - INPUT:: + INPUT: - ``x`` -- Something to cast into ``self``. diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index c9eb87c5e1b..39adebd1366 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -505,7 +505,7 @@ def __init__(self, p, prec, print_mode, names): """ Initialization. - INPUT:: + INPUT: - ``p`` -- prime - ``prec`` -- precision cap diff --git a/src/sage/rings/padics/padic_ext_element.pyx b/src/sage/rings/padics/padic_ext_element.pyx index 9a1802248b0..2b29ac84752 100644 --- a/src/sage/rings/padics/padic_ext_element.pyx +++ b/src/sage/rings/padics/padic_ext_element.pyx @@ -299,7 +299,7 @@ cdef class pAdicExtElement(pAdicGenericElement): Note that zeros are truncated from the returned list, so you must use the valuation() function to completely recover self. - INPUT:: + INPUT: - pos -- bint. If True, all integers will be in the range [0,p-1], otherwise they will be in the range [(1-p)/2, p/2]. diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index c22eef50600..644a715cd77 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -58,7 +58,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped relative representation of Zq. - INPUT:: + INPUT: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -106,7 +106,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A representation of Qq. - INPUT:: + INPUT: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -165,7 +165,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped absolute representation of Zq. - INPUT:: + INPUT: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -214,7 +214,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A fixed modulus representation of Zq. - INPUT:: + INPUT: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -268,7 +268,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped relative representation of an eisenstein extension of Zp. - INPUT:: + INPUT: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -325,7 +325,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped relative representation of an eisenstein extension of Qp. - INPUT:: + INPUT: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -393,7 +393,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A capped absolute representation of an eisenstein extension of Zp. - INPUT:: + INPUT: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer @@ -450,7 +450,7 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names): """ A fixed modulus representation of an eisenstein extension of Zp. - INPUT:: + INPUT: - prepoly -- The original polynomial defining the extension. This could be a polynomial with integer diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 4d11a528800..02d56d65d96 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -44,7 +44,7 @@ def __init__(self, base, p, prec, print_mode, names, element_class, category=Non """ Initialization. - INPUT:: + INPUT: - base -- Base ring. - p -- prime @@ -85,7 +85,7 @@ def _modified_print_mode(self, print_mode): print options but modified by the options in the dictionary print_mode. - INPUT:: + INPUT: - print_mode -- dictionary with keys in ['mode', 'pos', 'ram_name', 'unram_name', 'var_name', 'max_ram_terms', 'max_unram_terms', 'max_terse_terms', 'sep', 'alphabet'] diff --git a/src/sage/rings/padics/padic_printing.pyx b/src/sage/rings/padics/padic_printing.pyx index dc97838d98c..1e58a01d0da 100644 --- a/src/sage/rings/padics/padic_printing.pyx +++ b/src/sage/rings/padics/padic_printing.pyx @@ -299,7 +299,7 @@ cdef class pAdicPrinter_class(SageObject): """ Initializes a pAdicPrinter. - INPUT:: + INPUT: - ring -- the ring or field to which this pAdicPrinter is attached. @@ -1190,7 +1190,7 @@ cdef class pAdicPrinter_class(SageObject): """ Takes a list L of coefficients and returns a list with at most max_terms nonzero terms. - INPUT:: + INPUT: - L -- a list @@ -1224,7 +1224,7 @@ cdef class pAdicPrinter_class(SageObject): """ Returns a string representation of L when considered as a polynomial, truncating to at most max_unram_terms nonzero terms. - INPUT:: + INPUT: - L -- A list of coefficients. @@ -1317,7 +1317,7 @@ cdef class pAdicPrinter_class(SageObject): """ Prints a list L as a polynomial. - INPUT:: + INPUT: - L -- A list of coefficients. diff --git a/src/sage/rings/padics/unramified_extension_generic.py b/src/sage/rings/padics/unramified_extension_generic.py index 076ef123f31..d731901b789 100644 --- a/src/sage/rings/padics/unramified_extension_generic.py +++ b/src/sage/rings/padics/unramified_extension_generic.py @@ -31,7 +31,7 @@ def __init__(self, poly, prec, print_mode, names, element_class): """ Initializes self - INPUT:: + INPUT: - poly -- Polynomial defining this extension. - prec -- The precision cap @@ -78,7 +78,7 @@ def ramification_index(self, K = None): """ Returns the ramification index of self over the subring K. - INPUT:: + INPUT: - K -- a subring (or subfield) of self. Defaults to the base. @@ -99,7 +99,7 @@ def inertia_degree(self, K = None): """ Returns the inertia degree of self over the subring K. - INPUT:: + INPUT: - K -- a subring (or subfield) of self. Defaults to the base. @@ -141,7 +141,7 @@ def discriminant(self, K=None): """ Returns the discriminant of self over the subring K. - INPUT:: + INPUT: - K -- a subring/subfield (defaults to the base ring). @@ -182,7 +182,7 @@ def is_galois(self, K=None): Every unramified extension is Galois. - INPUT:: + INPUT: - K -- a subring/subfield (defaults to the base ring). diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index f96796667b1..ea6b3e06cf6 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -492,7 +492,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_generic): Construct a new element in this polynomial ring by converting ``element`` into ``self`` if possible. - INPUT:: + INPUT: - ``element`` -- several types are supported, see below diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index d1680334abe..b078c0428dc 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -158,7 +158,7 @@ cpdef Integer integer_rational_power(Integer a, Rational b): Compute `a^b` as an integer, if it is integral, or return None. The positive real root is taken for even denominators. - INPUT:: + INPUT: a -- an Integer b -- a positive Rational @@ -230,7 +230,7 @@ cpdef rational_power_parts(a, b, factor_limit=10**5): Compute rationals or integers `c` and `d` such that `a^b = c*d^b` with `d` small. This is used for simplifying radicals. - INPUT:: + INPUT: - ``a`` -- a rational or integer - ``b`` -- a rational diff --git a/src/sage/sets/finite_set_map_cy.pyx b/src/sage/sets/finite_set_map_cy.pyx index b8641cfcfeb..20b95807018 100644 --- a/src/sage/sets/finite_set_map_cy.pyx +++ b/src/sage/sets/finite_set_map_cy.pyx @@ -634,7 +634,7 @@ cdef class FiniteSetEndoMap_N(FiniteSetMap_MN): """ Return the ``n``-th power of ``self``. - INPUT:: + INPUT: - ``n`` -- a positive integer - ``dummy`` -- not used; must be set to ``None`` (for compatibility only). @@ -692,7 +692,7 @@ cdef class FiniteSetEndoMap_Set(FiniteSetMap_Set): """ Return the ``n``-th power of self. - INPUT:: + INPUT: - ``n`` -- a positive integer - ``dummy`` -- not used; must be set to None (for compatibility only). diff --git a/src/sage/stats/hmm/chmm.pyx b/src/sage/stats/hmm/chmm.pyx index 96152f46418..f4eeca92cfb 100644 --- a/src/sage/stats/hmm/chmm.pyx +++ b/src/sage/stats/hmm/chmm.pyx @@ -143,7 +143,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): matrix A, normal emissions given by B, and initial state probability distribution pi. - INPUT:: + INPUT: - A -- a list of lists or a square N x N matrix, whose (i,j) entry gives the probability of transitioning from diff --git a/src/sage/structure/misc.pyx b/src/sage/structure/misc.pyx index e11c38b7d81..55d857160cb 100644 --- a/src/sage/structure/misc.pyx +++ b/src/sage/structure/misc.pyx @@ -148,7 +148,7 @@ dummy_attribute_error = AttributeError(dummy_error_message) def getattr_from_other_class(self, cls, str name): """ - INPUT:: + INPUT: - ``self``: some object - ``cls``: a class From 0d3caa0063bcf2486d467c57ed8c9bbfe500b91f Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Wed, 11 Nov 2015 21:53:57 -0800 Subject: [PATCH 1872/1872] Updated Sage version to 6.10.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 5701b3c1bf6..fbfdd2d7e15 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Sage version 6.10.beta3, released 2015-11-05 +Sage version 6.10.beta4, released 2015-11-12 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 0ec9977aa41..9e100c5fc81 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=ff6a33eb58523267e51397577213b038fe81fe38 -md5=b694e1f431bb6f8fe6fbfc63b7640078 -cksum=1772005708 +sha1=be0238a7e8903bc9c67dfda766837fbd1af799a8 +md5=77df2c703d001f4648d37d0ef805adbe +cksum=3213063265 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 190a18037c6..fc902f4f956 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -123 +124 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index 23ca8c82c47..95b598f76ee 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath Version 6.10.beta3, Release Date: 2015-11-05 │ +│ SageMath Version 6.10.beta4, Release Date: 2015-11-12 │ │ 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 c50d4aaa35a..acd802dd5f0 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.10.beta3' -SAGE_RELEASE_DATE='2015-11-05' +SAGE_VERSION='6.10.beta4' +SAGE_RELEASE_DATE='2015-11-12' diff --git a/src/sage/version.py b/src/sage/version.py index f9d17c83c11..2a013b13a9f 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.10.beta3' -date = '2015-11-05' +version = '6.10.beta4' +date = '2015-11-12'