예제 #1
0
 def _int_list_to_substitutions(self, words):
     A = self._start._alphabet
     W = FiniteWords(A)
     s = {}
     for i, w in enumerate(words):
         s[A.unrank(i)] = [A.unrank(j) for j in w]
     return WordMorphism(s, domain=W, codomain=W)
예제 #2
0
    def __init__(self, e):
        """
        TESTS::

            sage: LW21 = LyndonWords([2,1]); LW21
            Lyndon words with evaluation [2, 1]
            sage: LW21 == loads(dumps(LW21))
            True
        """
        self._e = e
        self._words = FiniteWords(len(e))

        from sage.categories.enumerated_sets import EnumeratedSets
        Parent.__init__(self,
                        category=EnumeratedSets().Finite(),
                        facade=(self._words, ))
예제 #3
0
def iter_pisot_irreductible(d=3, arg=None):
    r"""
    Return an iterator over Pisot irreductible substitutions

    INPUT:

    - ``d`` -- size of alphabet, [0,1,...,d-1]

    - "arg" -- (optional, default: None) It can be one of the
      following :

      * "None" -- then the method iterates through all morphisms.

      * tuple (a, b) of two integers  - It specifies the range
        "range(a, b)" of values to consider for the sum of the length

    EXAMPLES::

        sage: from slabbe.word_morphisms import iter_pisot_irreductible
        sage: it = iter_pisot_irreductible(3)
        sage: for _ in range(4): next(it)
        WordMorphism: 0->01, 1->2, 2->0
        WordMorphism: 0->02, 1->0, 2->1
        WordMorphism: 0->10, 1->2, 2->0
        WordMorphism: 0->12, 1->0, 2->1

    Pour linstant, avec le tuple, il y a un bogue::

        sage: it = iter_pisot_irreductible(3, (5,10))
        sage: for _ in range(4): next(it)
        WordMorphism: 0->0000001, 1->2, 2->0
        WordMorphism: 0->0000002, 1->0, 2->1
        WordMorphism: 0->0000010, 1->2, 2->0
        WordMorphism: 0->0000012, 1->0, 2->1
    """
    from slabbe.matrices import is_pisot
    W = FiniteWords(range(d))
    for m in W.iter_morphisms(arg):
        incidence_matrix = m.incidence_matrix()
        if not incidence_matrix.det() == 1:
            continue
        if not m.is_primitive(): # mathematiquement non necessaire
            continue
        if not is_pisot(incidence_matrix):
            continue
        yield m
예제 #4
0
def iter_pisot_irreductible(d=3, arg=None):
    r"""
    Return an iterator over Pisot irreductible substitutions

    INPUT:

    - ``d`` -- size of alphabet, [0,1,...,d-1]

    - "arg" -- (optional, default: None) It can be one of the
      following :

      * "None" -- then the method iterates through all morphisms.

      * tuple (a, b) of two integers  - It specifies the range
        "range(a, b)" of values to consider for the sum of the length

    EXAMPLES::

        sage: from slabbe.word_morphisms import iter_pisot_irreductible
        sage: it = iter_pisot_irreductible(3)
        sage: for _ in range(4): next(it)
        WordMorphism: 0->01, 1->2, 2->0
        WordMorphism: 0->02, 1->0, 2->1
        WordMorphism: 0->10, 1->2, 2->0
        WordMorphism: 0->12, 1->0, 2->1

    Pour linstant, avec le tuple, il y a un bogue::

        sage: it = iter_pisot_irreductible(3, (5,10))
        sage: for _ in range(4): next(it)
        WordMorphism: 0->0000001, 1->2, 2->0
        WordMorphism: 0->0000002, 1->0, 2->1
        WordMorphism: 0->0000010, 1->2, 2->0
        WordMorphism: 0->0000012, 1->0, 2->1
    """
    from slabbe.matrices import is_pisot
    W = FiniteWords(range(d))
    for m in W.iter_morphisms(arg):
        incidence_matrix = m.incidence_matrix()
        if not incidence_matrix.det() == 1:
            continue
        if not m.is_primitive():  # mathematiquement non necessaire
            continue
        if not is_pisot(incidence_matrix):
            continue
        yield m
    def __init__(self, alphabet):
        '''
        This would be hidden without the ``.. automethod::``

        INPUT:

        - ``alphabet`` -- alphabet or number for len of Alphabet to construct

        OUTPUT:

        instance of FreeGoupWord

        '''

        if not isinstance(alphabet, AlphabetWithInverses):
            alphabet = AlphabetWithInverses(alphabet)
        FiniteWords.__init__(self, alphabet)
        self.element_class = FreeGroupWord
예제 #6
0
    def __init__(self, n, k):
        """
        Initialize ``self``.

        TESTS::

            sage: LW23 = LyndonWords(2,3); LW23
            Lyndon words from an alphabet of size 2 of length 3
            sage: LW23== loads(dumps(LW23))
            True
        """
        self._n = n
        self._k = k
        self._words = FiniteWords(self._n)

        from sage.categories.enumerated_sets import EnumeratedSets
        Parent.__init__(self,
                        category=EnumeratedSets().Finite(),
                        facade=(self._words, ))
예제 #7
0
    def __init__(self, alphabet=None):
        r"""
        INPUT:

        - ``alphabet`` -- the underlying alphabet

        TESTS::

            sage: loads(dumps(LyndonWords())) is LyndonWords()
            True
        """
        from sage.categories.sets_cat import Sets
        self._words = FiniteWords()
        Parent.__init__(self, category=Sets().Infinite(), facade=(self._words))
예제 #8
0
def standard_unbracketing(sblw):
    """
    Return flattened ``sblw`` if it is a standard bracketing of a Lyndon word,
    otherwise raise an error.

    EXAMPLES::

        sage: from sage.combinat.words.lyndon_word import standard_unbracketing
        sage: standard_unbracketing([1, [2, 3]])
        word: 123
        sage: standard_unbracketing([[1, 2], 3])
        Traceback (most recent call last):
        ...
        ValueError: not a standard bracketing of a Lyndon word

    TESTS::

        sage: standard_unbracketing(1) # Letters don't use brackets.
        word: 1
        sage: standard_unbracketing([1])
        Traceback (most recent call last):
        ...
        ValueError: not a standard bracketing of a Lyndon word
    """

    # Nested helper function that not only returns (flattened) w, but also its
    # right factor in the standard Lyndon factorization.
    def standard_unbracketing_rec(w):
        if not isinstance(w, list):
            return [w], []
        if len(w) != 2:
            raise ValueError("not a standard bracketing of a Lyndon word")
        x, t = standard_unbracketing_rec(w[0])
        y, _ = standard_unbracketing_rec(w[1])
        # If x = st is a standard Lyndon factorization, and y is a Lyndon word
        # such that y <= t, then xy is standard (but not necessarily Lyndon).
        if x < y and (len(t) == 0 or y <= t):
            x += y
            return x, y
        else:
            raise ValueError("not a standard bracketing of a Lyndon word")

    lw, _ = standard_unbracketing_rec(sblw)
    return FiniteWords(list(set(lw)))(lw, datatype='list', check=False)
예제 #9
0
class LyndonWords_nk(UniqueRepresentation, Parent):
    r"""
    Lyndon words of fixed length `k` over the alphabet `\{1, 2, \ldots, n\}`.

    INPUT:

    - ``n`` -- the size of the alphabet
    - ``k`` -- the length of the words

    EXAMPLES::

        sage: L = LyndonWords(3, 4)
        sage: L.list()
        [word: 1112,
         word: 1113,
         word: 1122,
         word: 1123,
         ...
         word: 1333,
         word: 2223,
         word: 2233,
         word: 2333]
    """
    def __init__(self, n, k):
        """
        Initialize ``self``.

        TESTS::

            sage: LW23 = LyndonWords(2,3); LW23
            Lyndon words from an alphabet of size 2 of length 3
            sage: LW23== loads(dumps(LW23))
            True
        """
        self._n = n
        self._k = k
        self._words = FiniteWords(self._n)

        from sage.categories.enumerated_sets import EnumeratedSets
        Parent.__init__(self,
                        category=EnumeratedSets().Finite(),
                        facade=(self._words, ))

    def __repr__(self):
        """
        TESTS::

            sage: repr(LyndonWords(2, 3))
            'Lyndon words from an alphabet of size 2 of length 3'
        """
        return "Lyndon words from an alphabet of size %s of length %s" % (
            self._n, self._k)

    def __call__(self, *args, **kwds):
        r"""
        TESTS::

            sage: L = LyndonWords(3,3)
            sage: L([1,2,3])
            word: 123
            sage: L([2,3,4])
            Traceback (most recent call last):
            ...
            ValueError: 4 not in alphabet!
            sage: L([2,1,3])
            Traceback (most recent call last):
            ...
            ValueError: not a Lyndon word
            sage: L([1,2,2,3,3])
            Traceback (most recent call last):
            ...
            ValueError: length is not k=3

        Make sure that the correct length is checked (:trac:`30186`)::

            sage: L = LyndonWords(2, 4)
            sage: _ = L(L.random_element())
        """
        w = self._words(*args, **kwds)
        if kwds.get('check', True) and not w.is_lyndon():
            raise ValueError("not a Lyndon word")
        if kwds.get('check', True) and w.length() != self._k:
            raise ValueError("length is not k={}".format(self._k))
        return w

    def __contains__(self, w):
        """
        TESTS::

            sage: LW33 = LyndonWords(3,3)
            sage: all(lw in LW33 for lw in LW33)
            True
        """
        if isinstance(w, list):
            w = self._words(w, check=False)
        return isinstance(w, FiniteWord_class) and w.length() == self._k \
            and all(x in self._words.alphabet() for x in w) and w.is_lyndon()

    def cardinality(self):
        """
        TESTS::

            sage: [ LyndonWords(3,i).cardinality() for i in range(1, 11) ]
            [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880]
        """
        if self._k == 0:
            return Integer(1)
        else:
            s = Integer(0)
            for d in divisors(self._k):
                s += moebius(d) * self._n**(self._k // d)
        return s // self._k

    def __iter__(self):
        """
        TESTS::

            sage: LyndonWords(3,3).list()  # indirect doctest
            [word: 112, word: 113, word: 122, word: 123, word: 132, word: 133, word: 223, word: 233]

            sage: sum(1 for lw in LyndonWords(11, 6))
            295020

            sage: sum(1 for lw in LyndonWords(1000, 1))
            1000

            sage: sum(1 for lw in LyndonWords(1, 1000))
            0

            sage: list(LyndonWords(1, 1))
            [word: 1]
        """
        W = self._words._element_classes['list']
        for lw in lyndon_word_iterator(self._n, self._k):
            yield W(self._words, [i + 1 for i in lw])
예제 #10
0
class LyndonWords_evaluation(UniqueRepresentation, Parent):
    r"""
    The set of Lyndon words on a fixed multiset of letters.

    EXAMPLES::

        sage: L = LyndonWords([1,2,1])
        sage: L
        Lyndon words with evaluation [1, 2, 1]
        sage: L.list()
        [word: 1223, word: 1232, word: 1322]
    """
    def __init__(self, e):
        """
        TESTS::

            sage: LW21 = LyndonWords([2,1]); LW21
            Lyndon words with evaluation [2, 1]
            sage: LW21 == loads(dumps(LW21))
            True
        """
        self._e = e
        self._words = FiniteWords(len(e))

        from sage.categories.enumerated_sets import EnumeratedSets
        Parent.__init__(self,
                        category=EnumeratedSets().Finite(),
                        facade=(self._words, ))

    def __repr__(self):
        """
        TESTS::

            sage: repr(LyndonWords([2,1,1]))
            'Lyndon words with evaluation [2, 1, 1]'
        """
        return "Lyndon words with evaluation %s" % self._e

    def __call__(self, *args, **kwds):
        r"""
        TESTS::

            sage: L = LyndonWords([1,2,1])
            sage: L([1,2,2,3])
            word: 1223
            sage: L([2,1,2,3])
            Traceback (most recent call last):
            ...
            ValueError: not a Lyndon word
            sage: L([1,2])
            Traceback (most recent call last):
            ...
            ValueError: evaluation is not [1, 2, 1]
        """
        w = self._words(*args, **kwds)
        if kwds.get('check', True) and not w.is_lyndon():
            raise ValueError("not a Lyndon word")
        if kwds.get('check', True) and w.evaluation() != self._e:
            raise ValueError("evaluation is not {}".format(self._e))
        return w

    def __contains__(self, w):
        """
        EXAMPLES::

            sage: [1,2,1,2] in LyndonWords([2,2])
            False
            sage: [1,1,2,2] in LyndonWords([2,2])
            True
            sage: all(lw in LyndonWords([2,1,3,1]) for lw in LyndonWords([2,1,3,1]))
            True
        """
        if isinstance(w, list):
            w = self._words(w, check=False)
        if isinstance(w, FiniteWord_class) and all(x in self._words.alphabet()
                                                   for x in w):
            ev_dict = w.evaluation_dict()
            evaluation = [ev_dict.get(x, 0) for x in self._words.alphabet()]
            return evaluation == self._e and w.is_lyndon()
        else:
            return False

    def cardinality(self):
        """
        Return the number of Lyndon words with the evaluation e.

        EXAMPLES::

            sage: LyndonWords([]).cardinality()
            0
            sage: LyndonWords([2,2]).cardinality()
            1
            sage: LyndonWords([2,3,2]).cardinality()
            30

        Check to make sure that the count matches up with the number of
        Lyndon words generated::

            sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list()
            sage: lws = [LyndonWords(comp) for comp in comps]
            sage: all(lw.cardinality() == len(lw.list()) for lw in lws)
            True
        """
        evaluation = self._e
        le = list(evaluation)
        if not evaluation:
            return Integer(0)
        n = sum(evaluation)
        return sum(
            moebius(j) * multinomial([ni // j for ni in evaluation])
            for j in divisors(gcd(le))) // n

    def __iter__(self):
        """
        An iterator for the Lyndon words with evaluation e.

        EXAMPLES::

            sage: LyndonWords([1]).list()    #indirect doctest
            [word: 1]
            sage: LyndonWords([2]).list()    #indirect doctest
            []
            sage: LyndonWords([3]).list()    #indirect doctest
            []
            sage: LyndonWords([3,1]).list()  #indirect doctest
            [word: 1112]
            sage: LyndonWords([2,2]).list()  #indirect doctest
            [word: 1122]
            sage: LyndonWords([1,3]).list()  #indirect doctest
            [word: 1222]
            sage: LyndonWords([3,3]).list()  #indirect doctest
            [word: 111222, word: 112122, word: 112212]
            sage: LyndonWords([4,3]).list()  #indirect doctest
            [word: 1111222, word: 1112122, word: 1112212, word: 1121122, word: 1121212]

        TESTS:

        Check that :trac:`12997` is fixed::

            sage: LyndonWords([0,1]).list()
            [word: 2]
            sage: LyndonWords([0,2]).list()
            []
            sage: LyndonWords([0,0,1,0,1]).list()
            [word: 35]
        """
        if not self._e:
            return
        k = 0
        while self._e[k] == 0:
            k += 1
        for z in _sfc(self._e[k:], equality=True):
            yield self._words([i + k + 1 for i in z], check=False)