Common Automata and Transducers (Finite State Machines Generators)#
Automata and Transducers in Sage can be built through the
automata
and transducers
objects, respectively.
It contains generators for
common finite state machines. For example,
sage: I = transducers.Identity([0, 1, 2])
generates an identity transducer on the alphabet \(\{0, 1, 2\}\).
To construct automata and transducers manually, you can use the
classes Automaton
and Transducer
, respectively. See
Finite state machines, automata, transducers for more details and a lot
of examples.
Automata
Return an automaton recognizing any letter. 

Return an automaton recognizing any word. 

Return an automaton recognizing the empty word. 

Return an automaton recognizing the given word. 

Return an automaton recognizing words containing the given word. 
Transducers
Returns a transducer realizing the identity map. 

Returns a transducer realizing absolute value. 

Returns a transducer realizing a function. 

Returns a transducer realizing a binary operation. 

Returns a transducer realizing logical 

Returns a transducer realizing logical 

Returns a transducer realizing addition. 

Returns a transducer realizing subtraction. 

Returns a transducer counting the occurrences of a subblock. 

Returns a transducer writing 

Returns a transducer realizing the Hamming weight. 

Returns a transducer realizing binary Gray code. 

Returns a transducer defined by recursions. 
AUTHORS:
Clemens Heuberger (20140407): initial version
Sara Kropf (20140410): some changes in TransducerGenerator
Daniel Krenn (20140415): improved common docstring during review
Clemens Heuberger, Daniel Krenn, Sara Kropf (20140416–20140502): A couple of improvements. Details see github issue #16141, github issue #16142, github issue #16143, github issue #16186.
Sara Kropf (20140429): weight transducer
Clemens Heuberger, Daniel Krenn (20140718): transducers Wait, all, any
Clemens Heuberger (20140810): transducer Recursion
Clemens Heuberger (20150731): automaton word
Daniel Krenn (20150914): cleanup github issue #18227
ACKNOWLEDGEMENT:
Clemens Heuberger, Daniel Krenn and Sara Kropf are supported by the Austrian Science Fund (FWF): P 24644N26.
Functions and methods#
 class sage.combinat.finite_state_machine_generators.AutomatonGenerators#
Bases:
object
A collection of constructors for several common automata.
A list of all automata in this database is available via tab completion. Type “
automata.
” and then hit tab to see which automata are available.The automata currently in this class include:
 AnyLetter(input_alphabet)#
Return an automaton recognizing any letter of the given input alphabet.
INPUT:
input_alphabet
– a list, the input alphabet
OUTPUT:
An
Automaton
.EXAMPLES:
sage: A = automata.AnyLetter([0, 1]) sage: A([]) False sage: A([0]) True sage: A([1]) True sage: A([0, 0]) False
See also
 AnyWord(input_alphabet)#
Return an automaton recognizing any word of the given input alphabet.
INPUT:
input_alphabet
– a list, the input alphabet
OUTPUT:
An
Automaton
.EXAMPLES:
sage: A = automata.AnyWord([0, 1]) sage: A([0]) True sage: A([1]) True sage: A([0, 1]) True sage: A([0, 2]) False
This is equivalent to taking the
kleene_star()
ofAnyLetter()
and minimizing the result. This method immediately gives a minimized version:sage: B = automata.AnyLetter([0, 1]).kleene_star().minimization().relabeled() sage: B == A True
See also
 ContainsWord(word, input_alphabet)#
Return an automaton recognizing the words containing the given word as a factor.
INPUT:
word
– a list (or other iterable) of letters, the word we are looking for.input_alphabet
– a list or other iterable, the input alphabet.
OUTPUT:
An
Automaton
.EXAMPLES:
sage: A = automata.ContainsWord([0, 1, 0, 1, 1], ....: input_alphabet=[0, 1]) sage: A([1, 0, 1, 0, 1, 0, 1, 1, 0, 0]) True sage: A([1, 0, 1, 0, 1, 0, 1, 0]) False
This is equivalent to taking the concatenation of
AnyWord()
,Word()
andAnyWord()
and minimizing the result. This method immediately gives a minimized version:sage: B = (automata.AnyWord([0, 1]) * ....: automata.Word([0, 1, 0, 1, 1], [0, 1]) * ....: automata.AnyWord([0, 1])).minimization() sage: B.is_equivalent(A) True
See also
 EmptyWord(input_alphabet=None)#
Return an automaton recognizing the empty word.
INPUT:
input_alphabet
– (default:None
) an iterable orNone
.
OUTPUT:
An
Automaton
.EXAMPLES:
sage: A = automata.EmptyWord() sage: A([]) True sage: A([0]) False
See also
 Word(word, input_alphabet=None)#
Return an automaton recognizing the given word.
INPUT:
word
– an iterable.input_alphabet
– a list orNone
. IfNone
, then the letters occurring in the word are used.
OUTPUT:
An
Automaton
.EXAMPLES:
sage: A = automata.Word([0]) sage: A.transitions() [Transition from 0 to 1: 0] sage: [A(w) for w in ([], [0], [1])] [False, True, False] sage: A = automata.Word([0, 1, 0]) sage: A.transitions() [Transition from 0 to 1: 0, Transition from 1 to 2: 1, Transition from 2 to 3: 0] sage: [A(w) for w in ([], [0], [0, 1], [0, 1, 1], [0, 1, 0])] [False, False, False, False, True]
If the input alphabet is not given, it is derived from the given word.
sage: A.input_alphabet [0, 1] sage: A = automata.Word([0, 1, 0], input_alphabet=[0, 1, 2]) sage: A.input_alphabet [0, 1, 2]
See also
 class sage.combinat.finite_state_machine_generators.TransducerGenerators#
Bases:
object
A collection 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:
 CountSubblockOccurrences(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
– a list or other iterable.
OUTPUT:
A transducer counting (in unary) the number of occurrences of the given block in the input. Overlapping occurrences are counted several times.
Denoting the block by \(b_0\ldots b_{k1}\), 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 if \(i_{jk+1}\ldots i_{j} = b_0\ldots b_{k1}\). 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 (): 00, Transition from () to (1,): 10, Transition from (1,) to (): 01, Transition from (1,) to (1,): 10] sage: T.input_alphabet [0, 1] sage: T.output_alphabet [0, 1] sage: T.initial_states() [()] sage: T.final_states() [(), (1,)]
Check some sequence:
sage: T([0, 1, 0, 1, 1, 0]) [0, 0, 1, 0, 0, 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 (): 00, Transition from () to (1,): 10, Transition from (1,) to (): 00, Transition from (1,) to (1,): 11]
Check some sequence:
sage: T([0, 1, 0, 1, 1, 0]) [0, 0, 0, 0, 1, 0]
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 (): 00, Transition from () to (1,): 10, Transition from () to (): 20, Transition from (1,) to (1, 0): 00, Transition from (1,) to (1,): 10, Transition from (1,) to (): 20, Transition from (1, 0) to (): 00, Transition from (1, 0) to (1, 0, 1): 10, Transition from (1, 0) to (): 20, Transition from (1, 0, 1) to (1, 0): 01, Transition from (1, 0, 1) to (1,): 10, Transition from (1, 0, 1) to (): 20] 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) == output True
See also
 GrayCode()#
Returns a transducer converting the standard binary expansion to Gray code.
INPUT:
Nothing.
OUTPUT:
A transducer.
Cf. the Wikipedia article Gray_code for a description of the Gray code.
EXAMPLES:
sage: G = transducers.GrayCode() sage: G Transducer with 3 states sage: for v in srange(10): ....: print("{} {}".format(v, G(v.digits(base=2)))) 0 [] 1 [1] 2 [1, 1] 3 [0, 1] 4 [0, 1, 1] 5 [1, 1, 1] 6 [1, 0, 1] 7 [0, 0, 1] 8 [0, 0, 1, 1] 9 [1, 0, 1, 1]
In the example Gray Code in the documentation of the Finite state machines, automata, transducers module, the Gray code transducer is derived from the algorithm converting the binary expansion to the Gray code. The result is the same as the one given here.
 Identity(input_alphabet)#
Returns the identity transducer realizing the identity map.
INPUT:
input_alphabet
– a list or other iterable.
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: 00, Transition from 0 to 0: 11] 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]) [0, 1, 0, 1, 1]
 Recursion(recursions, base, function=None, var=None, input_alphabet=None, word_function=None, is_zero=None, output_rings=[Integer Ring, Rational Field])#
Return a transducer realizing the given recursion when reading the digit expansion with base
base
.INPUT:
recursions
– list or iterable of equations. Each equation has either the formf(base^K * n + r) == f(base^k * n + s) + t
for some integers0 <= k < K
,r
and somet
—valid for alln
such that the arguments on both sides are nonnegative—
or the form
f(r) == t
for some integerr
and somet
.
Alternatively, an equation may be replaced by a
transducers.RecursionRule
with the attributesK
,r
,k
,s
,t
as above or a tuple(r, t)
. Note thatt
must be a list in this case.base
– base of the digit expansion.function
– symbolic functionf
occurring in the recursions.var
– symbolic variable.input_alphabet
– (default:None
) a list of digits to be used as the input alphabet. IfNone
and the base is an integer,input_alphabet
is chosen to besrange(base.abs())
.word_function
– (default:None
) a symbolic function. If notNone
,word_function(arg1, ..., argn)
in a symbolic recurrence relation is interpreted as a transition with output[arg1, ..., argn]
. This could not be entered in a symbolic recurrence relation because lists do not coerce into theSymbolicRing
.is_zero
– (default:None
) a callable. The recursion relations are only wellposed if there is no cycle with nonzero output and input consisting of zeros. This parameter is used to determine whether the output of such a cycle is nonzero. By default, the output must evaluate toFalse
as a boolean.output_rings
– (default:[ZZ, QQ]
) a list of rings. The output labels are converted into the first ring of the list in which they are contained. If they are not contained in any ring, they remain in whatever ring they are after parsing the recursions, typically the symbolic ring.
OUTPUT:
A transducer
T
.The transducer is constructed such that
T(expansion) == f(n)
ifexpansion
is the digit expansion ofn
to the basebase
with the given input alphabet as set of digits. Here, the+
on the right hand side of the recurrence relation is interpreted as the concatenation of words.The formal equations and initial conditions in the recursion have to be selected such that
f
is uniquely defined.EXAMPLES:
The following example computes the Hamming weight of the ternary expansion of integers.
sage: function('f') # optional  sage.symbolic f sage: var('n') # optional  sage.symbolic n sage: T = transducers.Recursion([ # optional  sage.symbolic ....: f(3*n + 1) == f(n) + 1, ....: f(3*n + 2) == f(n) + 1, ....: f(3*n) == f(n), ....: f(0) == 0], ....: 3, f, n) sage: T.transitions() # optional  sage.symbolic [Transition from (0, 0) to (0, 0): 0, Transition from (0, 0) to (0, 0): 11, Transition from (0, 0) to (0, 0): 21]
To illustrate what this transducer does, we consider the example of \(n=601\):
sage: ternary_expansion = 601.digits(base=3) # optional  sage.symbolic sage: ternary_expansion # optional  sage.symbolic [1, 2, 0, 1, 1, 2] sage: weight_sequence = T(ternary_expansion) # optional  sage.symbolic sage: weight_sequence # optional  sage.symbolic [1, 1, 1, 1, 1] sage: sum(weight_sequence) # optional  sage.symbolic 5
Note that the digit zero does not show up in the output because the equation
f(3*n) == f(n)
means that no output is added tof(n)
.The following example computes the Hamming weight of the nonadjacent form, cf. the Wikipedia article Nonadjacent_form.
sage: function('f') # optional  sage.symbolic f sage: var('n') # optional  sage.symbolic n sage: T = transducers.Recursion([ # optional  sage.symbolic ....: f(4*n + 1) == f(n) + 1, ....: f(4*n  1) == f(n) + 1, ....: f(2*n) == f(n), ....: f(0) == 0], ....: 2, f, n) sage: T.transitions() # optional  sage.symbolic [Transition from (0, 0) to (0, 0): 0, Transition from (0, 0) to (1, 1): 1, Transition from (1, 1) to (0, 0): 01, Transition from (1, 1) to (1, 0): 11, Transition from (1, 0) to (1, 1): 0, Transition from (1, 0) to (1, 0): 1] sage: [(s.label(), s.final_word_out) # optional  sage.symbolic ....: for s in T.iter_final_states()] [((0, 0), []), ((1, 1), [1]), ((1, 0), [1])]
As we are interested in the weight only, we also output \(1\) for numbers congruent to \(3\) mod \(4\). The actual expansion is computed in the next example.
Consider the example of \(29=(100\bar 101)_2\) (as usual, the digit \(1\) is denoted by \(\bar 1\) and digits are written from the most significant digit at the left to the least significant digit at the right; for the transducer, we have to give the digits in the reverse order):
sage: NAF = [1, 0, 1, 0, 0, 1] sage: ZZ(NAF, base=2) 29 sage: binary_expansion = 29.digits(base=2) sage: binary_expansion [1, 0, 1, 1, 1] sage: T(binary_expansion) # optional  sage.symbolic [1, 1, 1] sage: sum(T(binary_expansion)) # optional  sage.symbolic 3
Indeed, the given nonadjacent form has three nonzero digits.
The following example computes the nonadjacent form from the binary expansion, cf. the Wikipedia article Nonadjacent_form. In contrast to the previous example, we actually compute the expansion, not only the weight.
We have to write the output \(0\) when converting an even number. This cannot be encoded directly by an equation in the symbolic ring, because
f(2*n) == f(n) + 0
would be equivalent tof(2*n) == f(n)
and an empty output would be written. Therefore, we wrap the output in the symbolic functionw
and use the parameterword_function
to announce this.Similarly, we use
w(1, 0)
to write an output word of length \(2\) in one iteration. Finally, we writef(0) == w()
to write an empty word upon completion.Moreover, there is a cycle with output
[0]
which—from the point of view of this method—is a contradicting recursion. We override this by the parameteris_zero
.sage: var('n') # optional  sage.symbolic n sage: function('f w') # optional  sage.symbolic (f, w) sage: T = transducers.Recursion([ # optional  sage.symbolic ....: f(2*n) == f(n) + w(0), ....: f(4*n + 1) == f(n) + w(1, 0), ....: f(4*n  1) == f(n) + w(1, 0), ....: f(0) == w()], ....: 2, f, n, ....: word_function=w, ....: is_zero=lambda x: sum(x).is_zero()) sage: T.transitions() # optional  sage.symbolic [Transition from (0, 0) to (0, 0): 00, Transition from (0, 0) to (1, 1): 1, Transition from (1, 1) to (0, 0): 01,0, Transition from (1, 1) to (1, 0): 11,0, Transition from (1, 0) to (1, 1): 0, Transition from (1, 0) to (1, 0): 10] sage: for s in T.iter_states(): # optional  sage.symbolic ....: print("{} {}".format(s, s.final_word_out)) (0, 0) [] (1, 1) [1, 0] (1, 0) [1, 0]
We again consider the example of \(n=29\):
sage: T(29.digits(base=2)) # optional  sage.symbolic [1, 0, 1, 0, 0, 1, 0]
The same transducer can also be entered bypassing the symbolic equations:
sage: R = transducers.RecursionRule sage: TR = transducers.Recursion([ ....: R(K=1, r=0, k=0, s=0, t=[0]), ....: R(K=2, r=1, k=0, s=0, t=[1, 0]), ....: R(K=2, r=1, k=0, s=0, t=[1, 0]), ....: (0, [])], ....: 2, ....: is_zero=lambda x: sum(x).is_zero()) sage: TR == T # optional  sage.symbolic True
Here is an artificial example where some of the \(s\) are negative:
sage: function('f') # optional  sage.symbolic f sage: var('n') # optional  sage.symbolic n sage: T = transducers.Recursion([ # optional  sage.symbolic ....: f(2*n + 1) == f(n1) + 1, ....: f(2*n) == f(n), ....: f(1) == 1, ....: f(0) == 0], 2, f, n) sage: T.transitions() # optional  sage.symbolic [Transition from (0, 0) to (0, 0): 0, Transition from (0, 0) to (1, 1): 1, Transition from (1, 1) to (1, 1): 01, Transition from (1, 1) to (0, 0): 11, Transition from (1, 1) to (1, 2): 0, Transition from (1, 1) to (1, 2): 1, Transition from (1, 2) to (1, 1): 01, Transition from (1, 2) to (0, 0): 11, Transition from (1, 2) to (1, 2): 01, Transition from (1, 2) to (1, 2): 11] sage: [(s.label(), s.final_word_out) # optional  sage.symbolic ....: for s in T.iter_final_states()] [((0, 0), []), ((1, 1), [1]), ((1, 1), [0]), ((1, 2), [0]), ((1, 2), [1])]
Abelian complexity of the paperfolding sequence (cf. [HKP2015], Example 2.8):
sage: T = transducers.Recursion([ # optional  sage.symbolic ....: f(4*n) == f(2*n), ....: f(4*n+2) == f(2*n+1)+1, ....: f(16*n+1) == f(8*n+1), ....: f(16*n+5) == f(4*n+1)+2, ....: f(16*n+11) == f(4*n+3)+2, ....: f(16*n+15) == f(2*n+2)+1, ....: f(1) == 2, f(0) == 0] ....: + [f(16*n+jj) == f(2*n+1)+2 for jj in [3,7,9,13]], ....: 2, f, n) sage: T.transitions() # optional  sage.symbolic [Transition from (0, 0) to (0, 1): 0, Transition from (0, 0) to (1, 1): 1, Transition from (0, 1) to (0, 1): 0, Transition from (0, 1) to (1, 1): 11, Transition from (1, 1) to (1, 2): 0, Transition from (1, 1) to (3, 2): 1, Transition from (1, 2) to (1, 3): 0, Transition from (1, 2) to (5, 3): 1, Transition from (3, 2) to (3, 3): 0, Transition from (3, 2) to (7, 3): 1, Transition from (1, 3) to (1, 3): 0, Transition from (1, 3) to (1, 1): 12, Transition from (5, 3) to (1, 2): 02, Transition from (5, 3) to (1, 1): 12, Transition from (3, 3) to (1, 1): 02, Transition from (3, 3) to (3, 2): 12, Transition from (7, 3) to (1, 1): 02, Transition from (7, 3) to (2, 1): 11, Transition from (2, 1) to (1, 1): 01, Transition from (2, 1) to (2, 1): 1] sage: for s in T.iter_states(): # optional  sage.symbolic ....: print("{} {}".format(s, s.final_word_out)) (0, 0) [] (0, 1) [] (1, 1) [2] (1, 2) [2] (3, 2) [2, 2] (1, 3) [2] (5, 3) [2, 2] (3, 3) [2, 2] (7, 3) [2, 2] (2, 1) [1, 2] sage: list(sum(T(n.bits())) for n in srange(1, 21)) # optional  sage.symbolic [2, 3, 4, 3, 4, 5, 4, 3, 4, 5, 6, 5, 4, 5, 4, 3, 4, 5, 6, 5]
We now demonstrate the use of the
output_rings
parameter. If nooutput_rings
are specified, the output labels are converted intoZZ
:sage: function('f') # optional  sage.symbolic f sage: var('n') # optional  sage.symbolic n sage: T = transducers.Recursion([ # optional  sage.symbolic ....: f(2*n + 1) == f(n) + 1, ....: f(2*n) == f(n), ....: f(0) == 2], ....: 2, f, n) sage: for t in T.transitions(): # optional  sage.symbolic ....: print([x.parent() for x in t.word_out]) [] [Integer Ring] sage: [x.parent() for x in T.states()[0].final_word_out] # optional  sage.symbolic [Integer Ring]
In contrast, if
output_rings
is set to the empty list, the results are not converted:sage: T = transducers.Recursion([ # optional  sage.symbolic ....: f(2*n + 1) == f(n) + 1, ....: f(2*n) == f(n), ....: f(0) == 2], ....: 2, f, n, output_rings=[]) sage: for t in T.transitions(): # optional  sage.symbolic ....: print([x.parent() for x in t.word_out]) [] [Symbolic Ring] sage: [x.parent() for x in T.states()[0].final_word_out] # optional  sage.symbolic [Symbolic Ring]
Finally, we use a somewhat questionable conversion:
sage: T = transducers.Recursion([ # optional  sage.rings.finite_rings sage.symbolic ....: f(2*n + 1) == f(n) + 1, ....: f(2*n) == f(n), ....: f(0) == 0], ....: 2, f, n, output_rings=[GF(5)]) sage: for t in T.transitions(): # optional  sage.rings.finite_rings sage.symbolic ....: print([x.parent() for x in t.word_out]) [] [Finite Field of size 5]
Todo
Extend the method to
nonintegral bases,
higher dimensions.
ALGORITHM:
See [HKP2015], Section 6. However, there are also recursion transitions for states of level \(<\kappa\) if the recursion rules allow such a transition. Furthermore, the intermediate step of a nondeterministic transducer is left out by implicitly using recursion transitions. The wellposedness is checked in a truncated version of the recursion digraph.
 class RecursionRule(K, r, k, s, t)#
Bases:
tuple
 K#
Alias for field number 0
 k#
Alias for field number 2
 r#
Alias for field number 1
 s#
Alias for field number 3
 t#
Alias for field number 4
 Wait(input_alphabet, threshold=1)#
Writes
False
until reading thethreshold
th occurrence of a true input letter; then writesTrue
.INPUT:
input_alphabet
– a list or other iterable.threshold
– a positive integer specifying how many occurrences ofTrue
inputs are waited for.
OUTPUT:
A transducer writing
False
until thethreshold
th true (Python’s standard conversion to boolean is used to convert the actual input to boolean) input is read. Subsequently, the transducer writesTrue
.EXAMPLES:
sage: T = transducers.Wait([0, 1]) sage: T([0, 0, 1, 0, 1, 0]) [False, False, True, True, True, True] sage: T2 = transducers.Wait([0, 1], threshold=2) sage: T2([0, 0, 1, 0, 1, 0]) [False, False, False, False, True, True]
 abs(input_alphabet)#
Returns a transducer which realizes the letterwise absolute value of an input word over the given input alphabet.
INPUT:
input_alphabet
– a list or other iterable.
OUTPUT:
A transducer mapping \(i_0\ldots i_k\) to \(i_0\ldots i_k\).
EXAMPLES:
The following transducer realizes letterwise absolute value:
sage: T = transducers.abs([1, 0, 1]) sage: T.transitions() [Transition from 0 to 0: 11, Transition from 0 to 0: 00, Transition from 0 to 0: 11] sage: T.initial_states() [0] sage: T.final_states() [0] sage: T([1, 1, 0, 1]) [1, 1, 0, 1]
 add(input_alphabet, number_of_operands=2)#
Returns a transducer which realizes addition on pairs over the given input alphabet.
INPUT:
input_alphabet
– a list or other iterable.number_of_operands
– (default: \(2\)) it specifies the number of input arguments the operator takes.
OUTPUT:
A transducer mapping an input word \((i_{01}, \ldots, i_{0d})\ldots (i_{k1}, \ldots, i_{kd})\) to the word \((i_{01} + \cdots + i_{0d})\ldots (i_{k1} + \cdots + i_{kd})\).
The input alphabet of the generated transducer is the Cartesian product of
number_of_operands
copies ofinput_alphabet
.EXAMPLES:
The following transducer realizes letterwise 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)] sage: T.initial_states() [0] sage: T.final_states() [0] sage: T([(0, 0), (0, 1), (1, 0), (1, 1)]) [0, 1, 1, 2]
More than two operands can also be handled:
sage: T3 = transducers.add([0, 1], number_of_operands=3) sage: T3.input_alphabet [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)] sage: T3([(0, 0, 0), (0, 1, 0), (0, 1, 1), (1, 1, 1)]) [0, 1, 2, 3]
 all(input_alphabet, number_of_operands=2)#
Returns a transducer which realizes logical
and
over the given input alphabet.INPUT:
input_alphabet
– a list or other iterable.number_of_operands
– (default: \(2\)) specifies the number of input arguments for theand
operation.
OUTPUT:
A transducer mapping an input word \((i_{01}, \ldots, i_{0d})\ldots (i_{k1}, \ldots, i_{kd})\) to the word \((i_{01} \land \cdots \land i_{0d})\ldots (i_{k1} \land \cdots \land i_{kd})\).
The input alphabet of the generated transducer is the Cartesian product of
number_of_operands
copies ofinput_alphabet
.EXAMPLES:
The following transducer realizes letterwise logical
and
:sage: T = transducers.all([False, True]) sage: T.transitions() [Transition from 0 to 0: (False, False)False, Transition from 0 to 0: (False, True)False, Transition from 0 to 0: (True, False)False, Transition from 0 to 0: (True, True)True] sage: T.input_alphabet [(False, False), (False, True), (True, False), (True, True)] sage: T.initial_states() [0] sage: T.final_states() [0] sage: T([(False, False), (False, True), (True, False), (True, True)]) [False, False, False, True]
More than two operands and other input alphabets (with conversion to boolean) are also possible:
sage: T3 = transducers.all([0, 1], number_of_operands=3) sage: T3([(0, 0, 0), (1, 0, 0), (1, 1, 1)]) [False, False, True]
 any(input_alphabet, number_of_operands=2)#
Returns a transducer which realizes logical
or
over the given input alphabet.INPUT:
input_alphabet
– a list or other iterable.number_of_operands
– (default: \(2\)) specifies the number of input arguments for theor
operation.
OUTPUT:
A transducer mapping an input word \((i_{01}, \ldots, i_{0d})\ldots (i_{k1}, \ldots, i_{kd})\) to the word \((i_{01} \lor \cdots \lor i_{0d})\ldots (i_{k1} \lor \cdots \lor i_{kd})\).
The input alphabet of the generated transducer is the Cartesian product of
number_of_operands
copies ofinput_alphabet
.EXAMPLES:
The following transducer realizes letterwise logical
or
:sage: T = transducers.any([False, True]) sage: T.transitions() [Transition from 0 to 0: (False, False)False, Transition from 0 to 0: (False, True)True, Transition from 0 to 0: (True, False)True, Transition from 0 to 0: (True, True)True] sage: T.input_alphabet [(False, False), (False, True), (True, False), (True, True)] sage: T.initial_states() [0] sage: T.final_states() [0] sage: T([(False, False), (False, True), (True, False), (True, True)]) [False, True, True, True]
More than two operands and other input alphabets (with conversion to boolean) are also possible:
sage: T3 = transducers.any([0, 1], number_of_operands=3) sage: T3([(0, 0, 0), (1, 0, 0), (1, 1, 1)]) [False, True, True]
 map(f, input_alphabet)#
Return a transducer which realizes a function on the alphabet.
INPUT:
f
– function to realize.input_alphabet
– a list or other iterable.
OUTPUT:
A transducer mapping an input letter \(x\) to \(f(x)\).
EXAMPLES:
The following binary transducer realizes componentwise absolute value (this transducer is also available as
abs()
):sage: T = transducers.map(abs, [1, 0, 1]) sage: T.transitions() [Transition from 0 to 0: 11, Transition from 0 to 0: 00, Transition from 0 to 0: 11] sage: T.input_alphabet [1, 0, 1] sage: T.initial_states() [0] sage: T.final_states() [0] sage: T([1, 1, 0, 1]) [1, 1, 0, 1]
See also
 operator(operator, input_alphabet, number_of_operands=2)#
Returns a transducer which realizes an operation on tuples over the given input alphabet.
INPUT:
operator
– operator to realize. It is a function which takesnumber_of_operands
input arguments (each out ofinput_alphabet
).input_alphabet
– a list or other iterable.number_of_operands
– (default: \(2\)) it specifies the number of input arguments the operator takes.
OUTPUT:
A transducer mapping an input letter \((i_1, \dots, i_n)\) to \(\mathrm{operator}(i_1, \dots, i_n)\). Here, \(n\) equals
number_of_operands
.The input alphabet of the generated transducer is the Cartesian product of
number_of_operands
copies ofinput_alphabet
.EXAMPLES:
The following binary transducer realizes componentwise addition (this transducer is also available as
add()
):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)] sage: T.initial_states() [0] sage: T.final_states() [0] sage: T([(0, 0), (0, 1), (1, 0), (1, 1)]) [0, 1, 1, 2]
Note that for a unary operator the input letters of the new transducer are tuples of length \(1\):
sage: T = transducers.operator(abs, ....: [1, 0, 1], ....: number_of_operands=1) sage: T([1, 1, 0]) Traceback (most recent call last): ... ValueError: Invalid input sequence. sage: T([(1,), (1,), (0,)]) [1, 1, 0]
Compare this with the transducer generated by
map()
:sage: T = transducers.map(abs, ....: [1, 0, 1]) sage: T([1, 1, 0]) [1, 1, 0]
In fact, this transducer is also available as
abs()
:sage: T = transducers.abs([1, 0, 1]) sage: T([1, 1, 0]) [1, 1, 0]
 sub(input_alphabet)#
Returns a transducer which realizes subtraction on pairs over the given input alphabet.
INPUT:
input_alphabet
– a list or other iterable.
OUTPUT:
A transducer mapping an input word \((i_0, i'_0)\ldots (i_k, i'_k)\) to the word \((i_0  i'_0)\ldots (i_k  i'_k)\).
The input alphabet of the generated transducer is the Cartesian product of two copies of
input_alphabet
.EXAMPLES:
The following transducer realizes letterwise 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)] sage: T.initial_states() [0] sage: T.final_states() [0] sage: T([(0, 0), (0, 1), (1, 0), (1, 1)]) [0, 1, 1, 0]
 weight(input_alphabet, zero=0)#
Returns a transducer which realizes the Hamming weight of the input over the given input alphabet.
INPUT:
input_alphabet
– a list or other iterable.zero
– the zero symbol in the alphabet used
OUTPUT:
A transducer mapping \(i_0\ldots i_k\) to \((i_0\neq 0)\ldots(i_k\neq 0)\).
The Hamming weight is defined as the number of nonzero digits in the input sequence over the alphabet
input_alphabet
(see Wikipedia article Hamming_weight). The output sequence of the transducer is a unary encoding of the Hamming weight. Thus the sum of the output sequence is the Hamming weight of the input.EXAMPLES:
sage: W = transducers.weight([1, 0, 2]) sage: W.transitions() [Transition from 0 to 0: 11, Transition from 0 to 0: 00, Transition from 0 to 0: 21] sage: unary_weight = W([1, 0, 0, 2, 1]) sage: unary_weight [1, 0, 0, 1, 1] sage: weight = add(unary_weight) sage: weight 3
Also the joint Hamming weight can be computed:
sage: v1 = vector([1, 0]) sage: v0 = vector([0, 0]) sage: W = transducers.weight([v1, v0]) sage: unary_weight = W([v1, v0, v1, v0]) sage: add(unary_weight) 2
For the input alphabet
[1, 0, 1]
the weight transducer is the same as the absolute value transducerabs()
:sage: W = transducers.weight([1, 0, 1]) sage: A = transducers.abs([1, 0, 1]) sage: W == A True
For other input alphabets, we can specify the zero symbol:
sage: W = transducers.weight(['a', 'b'], zero='a') sage: add(W(['a', 'b', 'b'])) 2