From 9af0b91992bf0ff267a2c8c684b1f79b456f4a1e Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 10 Mar 2014 06:26:20 +0100 Subject: [PATCH 1/7] Whitespace correction in FSMTransition.__lt__ --- src/sage/combinat/finite_state_machine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 851690ddba5..775ebec52a9 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -910,7 +910,7 @@ def __init__(self, from_state, to_state, def __lt__(self, other): """ - Returns True if ``self`` is less than ``other`` with respect to the + Returns True if ``self`` is less than ``other`` with respect to the key ``(self.from_state, self.word_in, self.to_state, self.word_out)``. INPUT: From be59e47c5b519b93f82a77b7160767b8b03a5f2a Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Apr 2014 10:41:59 +0200 Subject: [PATCH 2/7] TransducerGenerators: New class, collecting common transducers Inspired by the (Di)graph_generators, provide a class TransducerGenerators where commonly usable transducers performing simple tasks can be collected. As for graphs, an abbreviation transducers is injected in the global namespace by a lazy_import. To start with, there is a Identity transducer and a CountSubblockOccurrences transducer. --- src/doc/en/reference/combinat/index.rst | 1 + src/sage/combinat/all.py | 2 + .../finite_state_machine_generators.py | 180 ++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 src/sage/combinat/finite_state_machine_generators.py diff --git a/src/doc/en/reference/combinat/index.rst b/src/doc/en/reference/combinat/index.rst index 2f2744634d9..7c913e4330d 100644 --- a/src/doc/en/reference/combinat/index.rst +++ b/src/doc/en/reference/combinat/index.rst @@ -85,6 +85,7 @@ Combinatorics species developer sage/combinat/finite_state_machine + sage/combinat/finite_state_machine_generators words sage/combinat/dict_addition diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 9185bf5dc17..c9b2af6284d 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -164,6 +164,8 @@ from sage.misc.lazy_import import lazy_import lazy_import('sage.combinat.finite_state_machine', ['Automaton', 'Transducer', 'FiniteStateMachine']) +lazy_import('sage.combinat.finite_state_machine_generators', + ['transducers']) # Binary Recurrence Sequences from binary_recurrence_sequences import BinaryRecurrenceSequence diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py new file mode 100644 index 00000000000..77d7fc35233 --- /dev/null +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -0,0 +1,180 @@ +r""" +Common Finite State Machines + +Generators for common finite state machines. + +.. csv-table:: + :class: contentstable + :widths: 30, 70 + :delim: | + + :meth:`~TransducerGenerators.Identity` | Returns a transducer realizing the identity map. + :meth:`~TransducerGenerators.CountSubblockOccurrences` | Returns a transducer counting the occurrences of a subblock. + +Functions and methods +--------------------- + +""" + +from sage.combinat.finite_state_machine import Transducer + +class TransducerGenerators(object): + r""" + A class consisting of constructors for several common transducers. + + A list of all transducers in this database is available via tab + completion. Type "``transducers.``" and then hit tab to see which + transducers are available. + + The transducers currently in this class include: + + - :meth:`~Identity` + - :meth:`~CountSubblockOccurrences` + + """ + + def Identity(self, input_alphabet): + """ + Returns the identity transducer realizing the identity map. + + INPUT: + + - ``input_alphabet`` -- the input alphabet. + + OUTPUT: + + A transducer mapping each word over ``input_alphabet`` to + itself. + + EXAMPLES:: + + sage: T = transducers.Identity([0, 1]) + sage: sorted(T.transitions()) + [Transition from 0 to 0: 0|0, + Transition from 0 to 0: 1|1] + sage: T.initial_states() + [0] + sage: T.final_states() + [0] + sage: T.input_alphabet + [0, 1] + sage: T.output_alphabet + [0, 1] + sage: T([0, 1, 0, 1, 1])[2] + [0, 1, 0, 1, 1] + + """ + return Transducer( + [(0, 0, d, d) for d in input_alphabet], + input_alphabet=input_alphabet, + output_alphabet=input_alphabet, + initial_states=[0], + final_states=[0]) + + def CountSubblockOccurrences(self, block, input_alphabet): + """ + Returns a transducer counting the number of (possibly + overlapping) occurrences of a block in the input. + + INPUT: + + - ``block`` -- a list (or other iterable) of letters. + - ``input_alphabet`` -- input alphabet. + + OUTPUT: + + A transducer counting (in unary) the number of occurrences of a + block in the input. Overlapping occurrences are counted several + times. + + Denoting the block by `b_0\ldots b_{k-1}`, the input word by + `i_0\ldots i_L` and the output word by `o_0\ldots o_L`, we + have `o_j = 1` if and only `i_{j-k+1}\ldots i_{j} = b_0\ldots + b_k`. Otherwise, `o_j = 0`. + + EXAMPLES: + + #. Counting the number of ``10`` blocks over the alphabet + ``[0, 1]``:: + + sage: T = transducers.CountSubblockOccurrences( + ....: [1, 0], + ....: [0, 1]) + sage: sorted(T.transitions()) + [Transition from () to (): 0|0, + Transition from () to (1,): 1|0, + Transition from (1,) to (): 0|1, + Transition from (1,) to (1,): 1|0] + sage: T.input_alphabet + [0, 1] + sage: T.output_alphabet + [0, 1] + sage: T.initial_states() + [()] + sage: T.final_states() + [(), (1,)] + + #. Counting the number of ``11`` blocks over the alphabet + ``[0, 1]``:: + + sage: T = transducers.CountSubblockOccurrences( + ....: [1, 1], + ....: [0, 1]) + sage: sorted(T.transitions()) + [Transition from () to (): 0|0, + Transition from () to (1,): 1|0, + Transition from (1,) to (): 0|0, + Transition from (1,) to (1,): 1|1] + + #. Counting the number of ``1010`` blocks over the + alphabet ``[0, 1, 2]``:: + + sage: T = transducers.CountSubblockOccurrences( + ....: [1, 0, 1, 0], + ....: [0, 1, 2]) + sage: sorted(T.transitions()) + [Transition from () to (): 0|0, + Transition from () to (1,): 1|0, + Transition from () to (): 2|0, + Transition from (1,) to (1, 0): 0|0, + Transition from (1,) to (1,): 1|0, + Transition from (1,) to (): 2|0, + Transition from (1, 0) to (): 0|0, + Transition from (1, 0) to (1, 0, 1): 1|0, + Transition from (1, 0) to (): 2|0, + Transition from (1, 0, 1) to (1, 0): 0|1, + Transition from (1, 0, 1) to (1,): 1|0, + Transition from (1, 0, 1) to (): 2|0] + sage: input = [0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 2] + sage: output = [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0] + sage: T(input)[2] == output + True + + """ + block_as_tuple = tuple(block) + + def starts_with(what, pattern): + return len(what) >= len(pattern) \ + and what[:len(pattern)] == pattern + + def transition_function(read, input): + current = read + (input, ) + if starts_with(block_as_tuple, current) and len(block_as_tuple) > len(current): + return (current, 0) + else: + k = 1 + while not starts_with(block_as_tuple, current[k:]): + k += 1 + return (current[k:], int(block_as_tuple == current)) + + T = Transducer( + transition_function, + input_alphabet=input_alphabet, + output_alphabet=[0, 1], + initial_states=[()]) + for s in T.iter_states(): + s.is_final = True + return T + +# Easy access to the transducer generators from the command line: +transducers = TransducerGenerators() From 973d4d3ad8835db4a3d27752d24a8fa88dd7a082 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 7 Apr 2014 12:23:22 +0200 Subject: [PATCH 3/7] transducers.add, transducers.sub: New transducers --- .../finite_state_machine_generators.py | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py index 77d7fc35233..89d6c65c44b 100644 --- a/src/sage/combinat/finite_state_machine_generators.py +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -9,6 +9,8 @@ :delim: | :meth:`~TransducerGenerators.Identity` | Returns a transducer realizing the identity map. + :meth:`~TransducerGenerators.add` | Returns a transducer realizing addition. + :meth:`~TransducerGenerators.sub` | Returns a transducer realizing subtraction. :meth:`~TransducerGenerators.CountSubblockOccurrences` | Returns a transducer counting the occurrences of a subblock. Functions and methods @@ -29,6 +31,8 @@ class TransducerGenerators(object): The transducers currently in this class include: - :meth:`~Identity` + - :meth:`~add` + - :meth:`~sub` - :meth:`~CountSubblockOccurrences` """ @@ -176,5 +180,115 @@ def transition_function(read, input): s.is_final = True return T + def _operator(self, operator, input_alphabet): + r""" + Returns a transducer which realizes the binary operator over + an input alphabet. + + INPUT: + + - ``operator`` -- binary operator to realize (a map + ``input_alphabet`` `\times ``input_alphabet`` `to` + ``input_alphabet``). + - ``input_alphabet`` -- input alphabet. + + OUTPUT: + + A transducer mapping `(i_0, i'_0)\ldots (i_k, i'_k)` + to `(i_0\odot i'_0)\ldots (i_k \odot i'_k)` where + `\odot` stands for the operator given. + + EXAMPLE: + + The following transducer realizes component-wise + addition:: + + sage: import operator + sage: T = transducers._operator(operator.add, + ....: [0, 1]) + sage: T.transitions() + [Transition from 0 to 0: (0, 0)|0, + Transition from 0 to 0: (0, 1)|1, + Transition from 0 to 0: (1, 0)|1, + Transition from 0 to 0: (1, 1)|2] + sage: T.input_alphabet + [(0, 0), (0, 1), (1, 0), (1, 1)] + """ + from itertools import product + + def transition_function(state, (i, o)): + return(0, operator(i, o)) + pairs = list(product(input_alphabet, repeat=2)) + return Transducer(transition_function, + input_alphabet=pairs, + initial_states=[0]) + + def add(self, input_alphabet): + """ + Returns a transducer which realizes the component-wise + addition over an input alphabet. + + INPUT: + + - ``input_alphabet`` -- input alphabet. + + OUTPUT: + + A transducer mapping `(i_0, i'_0)\ldots (i_k, i'_k)` + to `(i_0 + i'_0)\ldots (i_k + i'_k)`. + + EXAMPLE: + + The following transducer realizes component-wise + addition:: + + sage: T = transducers.add([0, 1]) + sage: T.transitions() + [Transition from 0 to 0: (0, 0)|0, + Transition from 0 to 0: (0, 1)|1, + Transition from 0 to 0: (1, 0)|1, + Transition from 0 to 0: (1, 1)|2] + sage: T.input_alphabet + [(0, 0), (0, 1), (1, 0), (1, 1)] + """ + import operator + return self._operator(operator.add, input_alphabet) + + def sub(self, input_alphabet): + """ + Returns a transducer which realizes the component-wise + addition over an input alphabet. + + INPUT: + + - ``input_alphabet`` -- input alphabet. + + OUTPUT: + + A transducer mapping `(i_0, i'_0)\ldots (i_k, i'_k)` + to `(i_0 - i'_0)\ldots (i_k - i'_k)`. + + EXAMPLE: + + The following transducer realizes component-wise + subtraction:: + + sage: T = transducers.sub([0, 1]) + sage: T.transitions() + [Transition from 0 to 0: (0, 0)|0, + Transition from 0 to 0: (0, 1)|-1, + Transition from 0 to 0: (1, 0)|1, + Transition from 0 to 0: (1, 1)|0] + sage: T.input_alphabet + [(0, 0), (0, 1), (1, 0), (1, 1)] + + """ + import operator + return self._operator(operator.sub, input_alphabet) + + + + + # Easy access to the transducer generators from the command line: transducers = TransducerGenerators() From 86be453f6fbdf906f48c27981b91348467de3d0f Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Wed, 9 Apr 2014 09:48:22 +0200 Subject: [PATCH 4/7] generators.abs: new common Transducer: absolute Value --- .../finite_state_machine_generators.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py index 89d6c65c44b..0b7ccc96d5a 100644 --- a/src/sage/combinat/finite_state_machine_generators.py +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -9,6 +9,7 @@ :delim: | :meth:`~TransducerGenerators.Identity` | Returns a transducer realizing the identity map. + :meth:`~TransducerGenerators.abs` | Returns a transducer realizing absolute value. :meth:`~TransducerGenerators.add` | Returns a transducer realizing addition. :meth:`~TransducerGenerators.sub` | Returns a transducer realizing subtraction. :meth:`~TransducerGenerators.CountSubblockOccurrences` | Returns a transducer counting the occurrences of a subblock. @@ -31,6 +32,7 @@ class TransducerGenerators(object): The transducers currently in this class include: - :meth:`~Identity` + - :meth:`~abs` - :meth:`~add` - :meth:`~sub` - :meth:`~CountSubblockOccurrences` @@ -287,8 +289,38 @@ def sub(self, input_alphabet): return self._operator(operator.sub, input_alphabet) + def abs(self, input_alphabet): + """ + Returns a transducer which realizes the component-wise + absolute value over an input alphabet. + + INPUT: + + - ``input_alphabet`` -- input alphabet. + + OUTPUT: + A transducer mapping `i_0\ldots i_k` + to `|i_0|\ldots |i_k|`. + EXAMPLE: + + The following transducer realizes component-wise + absolute value:: + + sage: T = transducers.abs([-1, 0, 1]) + sage: T.transitions() + [Transition from 0 to 0: -1|1, + Transition from 0 to 0: 0|0, + Transition from 0 to 0: 1|1] + sage: T([-1, -1, 0, 1])[2] + [1, 1, 0, 1] + + """ + return Transducer(lambda state, input: (0, abs(input)), + input_alphabet=input_alphabet, + initial_states=[0], + final_states=[0]) # Easy access to the transducer generators from the command line: transducers = TransducerGenerators() From fdf3dc4fd081fd6652396b39f78de5c40d5588a7 Mon Sep 17 00:00:00 2001 From: Sara Kropf Date: Thu, 10 Apr 2014 18:34:54 +0200 Subject: [PATCH 5/7] TransducerGenerators.operator is now a public function --- src/sage/combinat/finite_state_machine_generators.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py index 0b7ccc96d5a..9ee351d4d99 100644 --- a/src/sage/combinat/finite_state_machine_generators.py +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -182,7 +182,7 @@ def transition_function(read, input): s.is_final = True return T - def _operator(self, operator, input_alphabet): + def operator(self, operator, input_alphabet): r""" Returns a transducer which realizes the binary operator over an input alphabet. @@ -190,7 +190,7 @@ def _operator(self, operator, input_alphabet): INPUT: - ``operator`` -- binary operator to realize (a map - ``input_alphabet`` `\times ``input_alphabet`` `to` + ``input_alphabet`` `\times` ``input_alphabet`` `to` ``input_alphabet``). - ``input_alphabet`` -- input alphabet. @@ -254,7 +254,7 @@ def add(self, input_alphabet): [(0, 0), (0, 1), (1, 0), (1, 1)] """ import operator - return self._operator(operator.add, input_alphabet) + return self.operator(operator.add, input_alphabet) def sub(self, input_alphabet): """ @@ -286,7 +286,7 @@ def sub(self, input_alphabet): """ import operator - return self._operator(operator.sub, input_alphabet) + return self.operator(operator.sub, input_alphabet) def abs(self, input_alphabet): From 92a2b264b3d6b0c6d71bf2871584ba26fbbd0580 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 11 Apr 2014 08:16:59 +0200 Subject: [PATCH 6/7] operator in TOC, corrected docstring --- src/sage/combinat/finite_state_machine_generators.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py index 9ee351d4d99..50d8cdb675a 100644 --- a/src/sage/combinat/finite_state_machine_generators.py +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -10,6 +10,7 @@ :meth:`~TransducerGenerators.Identity` | Returns a transducer realizing the identity map. :meth:`~TransducerGenerators.abs` | Returns a transducer realizing absolute value. + :meth:`~TransducerGenerators.operator` | Returns a transducer realizing a binary operation. :meth:`~TransducerGenerators.add` | Returns a transducer realizing addition. :meth:`~TransducerGenerators.sub` | Returns a transducer realizing subtraction. :meth:`~TransducerGenerators.CountSubblockOccurrences` | Returns a transducer counting the occurrences of a subblock. @@ -33,6 +34,7 @@ class TransducerGenerators(object): - :meth:`~Identity` - :meth:`~abs` + - :meth:`~TransducerGenerators.operator` - :meth:`~add` - :meth:`~sub` - :meth:`~CountSubblockOccurrences` @@ -189,9 +191,8 @@ def operator(self, operator, input_alphabet): INPUT: - - ``operator`` -- binary operator to realize (a map - ``input_alphabet`` `\times` ``input_alphabet`` `to` - ``input_alphabet``). + - ``operator`` -- binary operator to realize (a map defined on + ``input_alphabet`` `\times` ``input_alphabet``). - ``input_alphabet`` -- input alphabet. OUTPUT: From 9029a07855acdf28ebc3a058ac0f206a238526f9 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 11 Apr 2014 15:35:21 +0200 Subject: [PATCH 7/7] Fixed doctest for operator --- src/sage/combinat/finite_state_machine_generators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py index 50d8cdb675a..44c140b326e 100644 --- a/src/sage/combinat/finite_state_machine_generators.py +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -207,7 +207,7 @@ def operator(self, operator, input_alphabet): addition:: sage: import operator - sage: T = transducers._operator(operator.add, + sage: T = transducers.operator(operator.add, ....: [0, 1]) sage: T.transitions() [Transition from 0 to 0: (0, 0)|0,