-
-
Notifications
You must be signed in to change notification settings - Fork 481
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Trac #21203: basic element and parent for k-regular sequences
Implement minimal element and parent classes for working with k-regular sequences See also Meta ticket #21202. URL: https://trac.sagemath.org/21203 Reported by: dkrenn Ticket author(s): Daniel Krenn Reviewer(s): Clemens Heuberger
- Loading branch information
Showing
5 changed files
with
418 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,365 @@ | ||
r""" | ||
`k`-regular Sequences | ||
An introduction and formal definition of `k`-regular sequences can be | ||
found, for example, on the :wikipedia:`k-regular_sequence` or in | ||
[AS2003]_. | ||
.. WARNING:: | ||
As this code is experimental, warnings are thrown when a | ||
`k`-regular sequence space is created for the first time in a | ||
session (see :class:`sage.misc.superseded.experimental`). | ||
TESTS:: | ||
sage: Seq2 = kRegularSequenceSpace(2, 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/21202 for details. | ||
Examples | ||
======== | ||
Binary sum of digits | ||
-------------------- | ||
The binary sum of digits `S(n)` of a nonnegative integer `n` satisfies | ||
`S(2n) = S(n)` and `S(2n+1) = S(n) + 1`. We model this by the following:: | ||
sage: Seq2 = kRegularSequenceSpace(2, ZZ) | ||
sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), | ||
....: left=vector([0, 1]), right=vector([1, 0])) | ||
sage: S | ||
2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... | ||
sage: all(S[n] == sum(n.digits(2)) for n in srange(10)) | ||
True | ||
Number of odd entries in Pascal's triangle | ||
------------------------------------------ | ||
Let us consider the number of odd entries in the first `n` rows | ||
of Pascals's triangle:: | ||
sage: @cached_function | ||
....: def u(n): | ||
....: if n <= 1: | ||
....: return n | ||
....: return 2*u(floor(n/2)) + u(ceil(n/2)) | ||
sage: tuple(u(n) for n in srange(10)) | ||
(0, 1, 3, 5, 9, 11, 15, 19, 27, 29) | ||
There is a `2`-recursive sequence describing the numbers above as well:: | ||
sage: U = Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), | ||
....: left=vector([0, 1]), right=vector([1, 0])).transposed() | ||
sage: all(U[n] == u(n) for n in srange(30)) | ||
True | ||
Various | ||
======= | ||
.. SEEALSO:: | ||
:mod:`recognizable series <sage.combinat.recognizable_series>`, | ||
:mod:`sage.rings.cfinite_sequence`, | ||
:mod:`sage.combinat.binary_recurrence_sequences`. | ||
AUTHORS: | ||
- Daniel Krenn (2016, 2021) | ||
ACKNOWLEDGEMENT: | ||
- Daniel Krenn is supported by the | ||
Austrian Science Fund (FWF): P 24644-N26. | ||
Classes and Methods | ||
=================== | ||
""" | ||
#***************************************************************************** | ||
# Copyright (C) 2016 Daniel Krenn <[email protected]> | ||
# | ||
# 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 3 of the License, or | ||
# (at your option) any later version. | ||
# http://www.gnu.org/licenses/ | ||
#***************************************************************************** | ||
|
||
from .recognizable_series import RecognizableSeries | ||
from .recognizable_series import RecognizableSeriesSpace | ||
from sage.misc.cachefunc import cached_method | ||
|
||
|
||
class kRegularSequence(RecognizableSeries): | ||
def __init__(self, parent, mu, left=None, right=None): | ||
r""" | ||
A `k`-regular sequence. | ||
INPUT: | ||
- ``parent`` -- an instance of :class:`kRegularSequenceSpace` | ||
- ``mu`` -- a family of square matrices, all of which have the | ||
same dimension. The indices of this family are `0,...,k-1`. | ||
``mu`` may be a list or tuple of cardinality `k` | ||
as well. See also | ||
:meth:`~sage.combinat.recognizable_series.RecognizableSeries.mu`. | ||
- ``left`` -- (default: ``None``) a vector. | ||
When evaluating the sequence, this vector is multiplied | ||
from the left to the matrix product. If ``None``, then this | ||
multiplication is skipped. | ||
- ``right`` -- (default: ``None``) a vector. | ||
When evaluating the sequence, this vector is multiplied | ||
from the right to the matrix product. If ``None``, then this | ||
multiplication is skipped. | ||
EXAMPLES:: | ||
sage: Seq2 = kRegularSequenceSpace(2, ZZ) | ||
sage: S = Seq2((Matrix([[3, 6], [0, 1]]), Matrix([[0, -6], [1, 5]])), | ||
....: vector([0, 1]), vector([1, 0])).transposed(); S | ||
2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... | ||
We can access the coefficients of a sequence by | ||
:: | ||
sage: S[5] | ||
11 | ||
or iterating over the first, say `10`, by | ||
:: | ||
sage: from itertools import islice | ||
sage: list(islice(S, 10)) | ||
[0, 1, 3, 5, 9, 11, 15, 19, 27, 29] | ||
.. SEEALSO:: | ||
:doc:`k-regular sequence <k_regular_sequence>`, | ||
:class:`kRegularSequenceSpace`. | ||
""" | ||
super(kRegularSequence, self).__init__( | ||
parent=parent, mu=mu, left=left, right=right) | ||
|
||
def _repr_(self): | ||
r""" | ||
Return a representation string of this `k`-regular sequence. | ||
OUTPUT: | ||
A string | ||
TESTS:: | ||
sage: Seq2 = kRegularSequenceSpace(2, ZZ) | ||
sage: s = Seq2((Matrix([[3, 6], [0, 1]]), Matrix([[0, -6], [1, 5]])), | ||
....: vector([0, 1]), vector([1, 0])).transposed() | ||
sage: repr(s) # indirect doctest | ||
'2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...' | ||
""" | ||
from sage.misc.lazy_list import lazy_list_formatter | ||
return lazy_list_formatter( | ||
self, | ||
name='{}-regular sequence'.format(self.parent().k), | ||
opening_delimiter='', closing_delimiter='', | ||
preview=10) | ||
|
||
@cached_method | ||
def __getitem__(self, n, **kwds): | ||
r""" | ||
Return the `n`-th entry of this sequence. | ||
INPUT: | ||
- ``n`` -- a nonnegative integer | ||
OUTPUT: | ||
An element of the universe of the sequence | ||
EXAMPLES:: | ||
sage: Seq2 = kRegularSequenceSpace(2, ZZ) | ||
sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), | ||
....: left=vector([0, 1]), right=vector([1, 0])) | ||
sage: S[7] | ||
3 | ||
TESTS:: | ||
sage: S[-1] | ||
Traceback (most recent call last): | ||
... | ||
ValueError: value -1 of index is negative | ||
:: | ||
sage: Seq2 = kRegularSequenceSpace(2, ZZ) | ||
sage: W = Seq2.indices() | ||
sage: M0 = Matrix([[1, 0], [0, 1]]) | ||
sage: M1 = Matrix([[0, -1], [1, 2]]) | ||
sage: S = Seq2((M0, M1), [0, 1], [1, 1]) | ||
sage: S._mu_of_word_(W(0.digits(2))) == M0 | ||
True | ||
sage: S._mu_of_word_(W(1.digits(2))) == M1 | ||
True | ||
sage: S._mu_of_word_(W(3.digits(2))) == M1^2 | ||
True | ||
""" | ||
return self.coefficient_of_word(self.parent()._n_to_index_(n), **kwds) | ||
|
||
def __iter__(self): | ||
r""" | ||
Return an iterator over the coefficients of this sequence. | ||
EXAMPLES:: | ||
sage: Seq2 = kRegularSequenceSpace(2, ZZ) | ||
sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), | ||
....: left=vector([0, 1]), right=vector([1, 0])) | ||
sage: from itertools import islice | ||
sage: tuple(islice(S, 10)) | ||
(0, 1, 1, 2, 1, 2, 2, 3, 1, 2) | ||
TESTS:: | ||
sage: it = iter(S) | ||
sage: iter(it) is it | ||
True | ||
sage: iter(S) is not it | ||
True | ||
""" | ||
from itertools import count | ||
return iter(self[n] for n in count()) | ||
|
||
|
||
class kRegularSequenceSpace(RecognizableSeriesSpace): | ||
r""" | ||
The space of `k`-regular Sequences over the given ``coefficients``. | ||
INPUT: | ||
- ``k`` -- an integer at least `2` specifying the base | ||
- ``coefficient_ring`` -- a (semi-)ring. | ||
- ``category`` -- (default: ``None``) the category of this | ||
space | ||
EXAMPLES:: | ||
sage: kRegularSequenceSpace(2, ZZ) | ||
Space of 2-regular sequences over Integer Ring | ||
sage: kRegularSequenceSpace(3, ZZ) | ||
Space of 3-regular sequences over Integer Ring | ||
.. SEEALSO:: | ||
:doc:`k-regular sequence <k_regular_sequence>`, | ||
:class:`kRegularSequence`. | ||
""" | ||
Element = kRegularSequence | ||
|
||
@classmethod | ||
def __normalize__(cls, k, coefficient_ring, **kwds): | ||
r""" | ||
Normalizes the input in order to ensure a unique | ||
representation. | ||
For more information see :class:`kRegularSequenceSpace`. | ||
TESTS:: | ||
sage: Seq2 = kRegularSequenceSpace(2, ZZ) | ||
sage: Seq2.category() | ||
Category of sets | ||
sage: Seq2.alphabet() | ||
{0, 1} | ||
""" | ||
from sage.arith.srange import srange | ||
nargs = super(kRegularSequenceSpace, cls).__normalize__( | ||
coefficient_ring, alphabet=srange(k), **kwds) | ||
return (k,) + nargs | ||
|
||
def __init__(self, k, *args, **kwds): | ||
r""" | ||
See :class:`kRegularSequenceSpace` for details. | ||
INPUT: | ||
- ``k`` -- an integer at least `2` specifying the base | ||
Other input arguments are passed on to | ||
:meth:`~sage.combinat.recognizable_series.RecognizableSeriesSpace.__init__`. | ||
TESTS:: | ||
sage: kRegularSequenceSpace(2, ZZ) | ||
Space of 2-regular sequences over Integer Ring | ||
sage: kRegularSequenceSpace(3, ZZ) | ||
Space of 3-regular sequences over Integer Ring | ||
.. SEEALSO:: | ||
:doc:`k-regular sequence <k_regular_sequence>`, | ||
:class:`kRegularSequence`. | ||
""" | ||
self.k = k | ||
super(kRegularSequenceSpace, self).__init__(*args, **kwds) | ||
|
||
def _repr_(self): | ||
r""" | ||
Return a representation string of this `k`-regular sequence space. | ||
OUTPUT: | ||
A string | ||
TESTS:: | ||
sage: repr(kRegularSequenceSpace(2, ZZ)) # indirect doctest | ||
'Space of 2-regular sequences over Integer Ring' | ||
""" | ||
return 'Space of {}-regular sequences over {}'.format(self.k, self.base()) | ||
|
||
def _n_to_index_(self, n): | ||
r""" | ||
Convert `n` to an index usable by the underlying | ||
recognizable series. | ||
INPUT: | ||
- ``n`` -- a nonnegative integer | ||
OUTPUT: | ||
A word | ||
TESTS:: | ||
sage: Seq2 = kRegularSequenceSpace(2, ZZ) | ||
sage: Seq2._n_to_index_(6) | ||
word: 011 | ||
sage: Seq2._n_to_index_(-1) | ||
Traceback (most recent call last): | ||
... | ||
ValueError: value -1 of index is negative | ||
""" | ||
from sage.rings.integer_ring import ZZ | ||
n = ZZ(n) | ||
W = self.indices() | ||
try: | ||
return W(n.digits(self.k)) | ||
except OverflowError: | ||
raise ValueError('value {} of index is negative'.format(n)) from None |
Oops, something went wrong.