This repository has been archived by the owner on Jan 30, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'fsm/operator_transducers' into fsm/example_gray_code
- Loading branch information
Showing
4 changed files
with
331 additions
and
1 deletion.
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,327 @@ | ||
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.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. | ||
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:`~abs` | ||
- :meth:`~TransducerGenerators.operator` | ||
- :meth:`~add` | ||
- :meth:`~sub` | ||
- :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 | ||
|
||
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 defined on | ||
``input_alphabet`` `\times` ``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) | ||
|
||
|
||
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() |