Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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 <Brg008@gmail.com> # Nicolas M. Thiery <nthiery at users.sf.net> # Anne Schilling <anne@math.ucdavis.edu> # Jeroen Demeyer <jdemeyer@cage.ugent.be> # # 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 from six import get_method_function
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 """
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 """
# Not all element classes support check=False, but # ClonableArray certainly does. else:
# Let self.backend be some IntegerListsBackend
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]] """
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 """
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]] """
@staticmethod def _element_iter(itr, constructor): """ Given an iterator ``itr`` and an element constructor ``constructor``, iterate over ``constructor(v)`` where `v` are the values of ``itr``.
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)] """
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.
EXAMPLES::
sage: C = IntegerListsLex(2, length=3) sage: C.min_length 3
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' """
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 """
def _element_constructor_default(self, l): """ Default element constructor
EXAMPLES::
sage: L = IntegerListsLex(4) sage: L._element_constructor_default([1,2,3]) [1, 2, 3]
We construct a variant of :class:`IntegerLists` with a custom element class::
sage: class MyElt(list): ....: def __init__(self, parent, x): ....: list.__init__(self, x) sage: from sage.combinat.integer_lists import IntegerLists sage: class MyIntegersLists(IntegerLists): ....: Element = MyElt sage: L = MyIntegersLists(5) sage: L._element_constructor_ <bound method MyIntegersLists._element_constructor_default of Integer lists of sum 5 satisfying certain constraints> """
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_ <bound method IntegerListsLex._element_constructor_nocheck of ...> sage: L._element_constructor_([1,2,3]) [1, 2, 3] """ |