Common automata and transducers (finite state machines generators) - Combinatorics

Skip to content
Back to top
View this page
Edit this page

# 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

    sage: I = transducers.Identity([0, 1, 2])

Python

    >>> from sage.all import *
    >>> I = transducers.Identity([Integer(0), Integer(1), Integer(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

`AnyLetter()` | Return an automaton recognizing any letter.
`AnyWord()` | Return an automaton recognizing any word.
`EmptyWord()` | Return an automaton recognizing the empty word.
`Word()` | Return an automaton recognizing the given word.
`ContainsWord()` | Return an automaton recognizing words containing the given word.

Transducers

`Identity()` | Return a transducer realizing the identity map.
`abs()` | Return a transducer realizing absolute value.
`map()` | Return a transducer realizing a function.
`operator()` | Return a transducer realizing a binary operation.
`all()` | Return a transducer realizing logical `and`.
`any()` | Return a transducer realizing logical `or`.
`add()` | Return a transducer realizing addition.
`sub()` | Return a transducer realizing subtraction.
`CountSubblockOccurrences()` | Return a transducer counting the occurrences of a subblock.
`Wait()` | Return a transducer writing `False` until first (or \(k\)-th) true input is read.
`weight()` | Return a transducer realizing the Hamming weight.
`GrayCode()` | Return a transducer realizing binary Gray code.
`Recursion()` | Return a transducer defined by recursions.

AUTHORS:

- Clemens Heuberger (2014-04-07): initial version

- Sara Kropf (2014-04-10): some changes in TransducerGenerator

- Daniel Krenn (2014-04-15): improved common docstring during review

- Clemens Heuberger, Daniel Krenn, Sara Kropf (2014-04-16–2014-05-02): A couple of improvements. Details see Issue #16141, Issue #16142, Issue #16143, Issue #16186.

- Sara Kropf (2014-04-29): weight transducer

- Clemens Heuberger, Daniel Krenn (2014-07-18): transducers Wait, all, any

- Clemens Heuberger (2014-08-10): transducer Recursion

- Clemens Heuberger (2015-07-31): automaton word

- Daniel Krenn (2015-09-14): cleanup Issue #18227

ACKNOWLEDGEMENT:

- Clemens Heuberger, Daniel Krenn and Sara Kropf are supported by the Austrian Science Fund (FWF): P 24644-N26.

## 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()`

  - `AnyWord()`

  - `EmptyWord()`

  - `Word()`

  - `ContainsWord()`

  AnyLetter(input_alphabet)

    Return an automaton recognizing any letter of the given input alphabet.

    INPUT:

    - `input_alphabet` – list; the input alphabet

    OUTPUT: an `Automaton`

    EXAMPLES:

    Sage

        sage: A = automata.AnyLetter([0, 1])
        sage: A([])
        False
        sage: A([0])
        True
        sage: A([1])
        True
        sage: A([0, 0])
        False

    Python

        >>> from sage.all import *
        >>> A = automata.AnyLetter([Integer(0), Integer(1)])
        >>> A([])
        False
        >>> A([Integer(0)])
        True
        >>> A([Integer(1)])
        True
        >>> A([Integer(0), Integer(0)])
        False

    See also

    `AnyWord()`

  AnyWord(input_alphabet)

    Return an automaton recognizing any word of the given input alphabet.

    INPUT:

    - `input_alphabet` – list; the input alphabet

    OUTPUT: an `Automaton`

    EXAMPLES:

    Sage

        sage: A = automata.AnyWord([0, 1])
        sage: A([0])
        True
        sage: A([1])
        True
        sage: A([0, 1])
        True
        sage: A([0, 2])
        False

    Python

        >>> from sage.all import *
        >>> A = automata.AnyWord([Integer(0), Integer(1)])
        >>> A([Integer(0)])
        True
        >>> A([Integer(1)])
        True
        >>> A([Integer(0), Integer(1)])
        True
        >>> A([Integer(0), Integer(2)])
        False

    This is equivalent to taking the `kleene_star()` of `AnyLetter()` and minimizing the result. This method immediately gives a minimized version:

    Sage

        sage: B = automata.AnyLetter([0, 1]).kleene_star().minimization().relabeled()
        sage: B == A
        True

    [Python]

        >>> from sage.all import *
        >>> B = automata.AnyLetter([Integer(0), Integer(1)]).kleene_star().minimization().relabeled()
        >>> B == A
        True

    See also

    `AnyLetter()`, `Word()`.

  ContainsWord(word, input_alphabet)

    Return an automaton recognizing the words containing the given word as a factor.

    INPUT:

    - `word` – list (or other iterable) of letters; the word we are looking for

    - `input_alphabet` – list or other iterable; the input alphabet

    OUTPUT: an `Automaton`

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> A = automata.ContainsWord([Integer(0), Integer(1), Integer(0), Integer(1), Integer(1)],
        ...                           input_alphabet=[Integer(0), Integer(1)])
        >>> A([Integer(1), Integer(0), Integer(1), Integer(0), Integer(1), Integer(0), Integer(1), Integer(1), Integer(0), Integer(0)])
        True
        >>> A([Integer(1), Integer(0), Integer(1), Integer(0), Integer(1), Integer(0), Integer(1), Integer(0)])
        False

    This is equivalent to taking the concatenation of `AnyWord()`, `Word()` and `AnyWord()` and minimizing the result. This method immediately gives a minimized version:

    Sage

        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

    [Python]

        >>> from sage.all import *
        >>> B = (automata.AnyWord([Integer(0), Integer(1)]) *
        ...     automata.Word([Integer(0), Integer(1), Integer(0), Integer(1), Integer(1)], [Integer(0), Integer(1)]) *
        ...     automata.AnyWord([Integer(0), Integer(1)])).minimization()
        >>> B.is_equivalent(A)
        True

    See also

    `CountSubblockOccurrences()`, `AnyWord()`, `Word()`.

  EmptyWord(input_alphabet=None)

    Return an automaton recognizing the empty word.

    INPUT:

    - `input_alphabet` – iterable or `None` (default: `None`)

    OUTPUT: an `Automaton`

    EXAMPLES:

    Sage

        sage: A = automata.EmptyWord()
        sage: A([])
        True
        sage: A([0])
        False

    Python

        >>> from sage.all import *
        >>> A = automata.EmptyWord()
        >>> A([])
        True
        >>> A([Integer(0)])
        False

    See also

    `AnyLetter()`, `AnyWord()`.

  Word(word, input_alphabet=None)

    Return an automaton recognizing the given word.

    INPUT:

    - `word` – an iterable

    - `input_alphabet` – list or `None`; if `None`, then the letters occurring in the word are used

    OUTPUT: an `Automaton`

    EXAMPLES:

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> A = automata.Word([Integer(0)])
        >>> A.transitions()
        [Transition from 0 to 1: 0|-]
        >>> [A(w) for w in ([], [Integer(0)], [Integer(1)])]
        [False, True, False]
        >>> A = automata.Word([Integer(0), Integer(1), Integer(0)])
        >>> A.transitions()
        [Transition from 0 to 1: 0|-,
        Transition from 1 to 2: 1|-,
        Transition from 2 to 3: 0|-]
        >>> [A(w) for w in ([], [Integer(0)], [Integer(0), Integer(1)], [Integer(0), Integer(1), Integer(1)], [Integer(0), Integer(1), Integer(0)])]
        [False, False, False, False, True]

    If the input alphabet is not given, it is derived from the given word.

    Sage

        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]

    [Python]

        >>> from sage.all import *
        >>> A.input_alphabet
        [0, 1]
        >>> A = automata.Word([Integer(0), Integer(1), Integer(0)], input_alphabet=[Integer(0), Integer(1), Integer(2)])
        >>> A.input_alphabet
        [0, 1, 2]

    See also

    `AnyWord()`, `ContainsWord()`.

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:

  - `Identity()`

  - `abs()`

  - `operator()`

  - `all()`

  - `any()`

  - `add()`

  - `sub()`

  - `CountSubblockOccurrences()`

  - `Wait()`

  - `GrayCode()`

  - `Recursion()`

  CountSubblockOccurrences(block, input_alphabet)

    Return a transducer counting the number of (possibly overlapping) occurrences of a block in the input.

    INPUT:

    - `block` – list (or other iterable) of letters

    - `input_alphabet` – 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_{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 if \(i_{j-k+1}\ldots i_{j} = b_0\ldots b_{k-1}\). Otherwise, \(o_j = 0\).

    EXAMPLES:

    1. Counting the number of `10` blocks over the alphabet `[0, 1]`:

       Sage

           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,)]

       Python

           >>> from sage.all import *
           >>> T = transducers.CountSubblockOccurrences(
           ...     [Integer(1), Integer(0)],
           ...     [Integer(0), Integer(1)])
           >>> 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]
           >>> T.input_alphabet
           [0, 1]
           >>> T.output_alphabet
           [0, 1]
           >>> T.initial_states()
           [()]
           >>> T.final_states()
           [(), (1,)]

       Check some sequence:

       Sage

           sage: T([0, 1, 0, 1, 1, 0])
           [0, 0, 1, 0, 0, 1]

       [Python]

           >>> from sage.all import *
           >>> T([Integer(0), Integer(1), Integer(0), Integer(1), Integer(1), Integer(0)])
           [0, 0, 1, 0, 0, 1]

    2. Counting the number of `11` blocks over the alphabet `[0, 1]`:

       Sage

           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]

       Python

           >>> from sage.all import *
           >>> T = transducers.CountSubblockOccurrences(
           ...     [Integer(1), Integer(1)],
           ...     [Integer(0), Integer(1)])
           >>> 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]

       Check some sequence:

       Sage

           sage: T([0, 1, 0, 1, 1, 0])
           [0, 0, 0, 0, 1, 0]

       [Python]

           >>> from sage.all import *
           >>> T([Integer(0), Integer(1), Integer(0), Integer(1), Integer(1), Integer(0)])
           [0, 0, 0, 0, 1, 0]

    3. Counting the number of `1010` blocks over the alphabet `[0, 1, 2]`:

       Sage

           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) == output
           True

       Python

           >>> from sage.all import *
           >>> T = transducers.CountSubblockOccurrences(
           ...     [Integer(1), Integer(0), Integer(1), Integer(0)],
           ...     [Integer(0), Integer(1), Integer(2)])
           >>> 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]
           >>> input =  [Integer(0), Integer(1), Integer(0), Integer(1), Integer(0), Integer(1), Integer(0), Integer(0), Integer(1), Integer(0), Integer(1), Integer(0), Integer(2)]
           >>> output = [Integer(0), Integer(0), Integer(0), Integer(0), Integer(1), Integer(0), Integer(1), Integer(0), Integer(0), Integer(0), Integer(0), Integer(1), Integer(0)]
           >>> T(input) == output
           True

    See also

    `ContainsWord()`

  GrayCode()

    Return a transducer converting the standard binary expansion to Gray code.

    OUTPUT: a transducer

    Cf. the Wikipedia article Gray_code for a description of the Gray code.

    EXAMPLES:

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> G = transducers.GrayCode()
        >>> G
        Transducer with 3 states
        >>> for v in srange(Integer(10)):
        ...     print("{} {}".format(v, G(v.digits(base=Integer(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)

    Return the identity transducer realizing the identity map.

    INPUT:

    - `input_alphabet` – list or other iterable

    OUTPUT: a transducer mapping each word over `input_alphabet` to itself

    EXAMPLES:

    Sage

        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])
        [0, 1, 0, 1, 1]

    Python

        >>> from sage.all import *
        >>> T = transducers.Identity([Integer(0), Integer(1)])
        >>> sorted(T.transitions())
        [Transition from 0 to 0: 0|0,
         Transition from 0 to 0: 1|1]
        >>> T.initial_states()
        [0]
        >>> T.final_states()
        [0]
        >>> T.input_alphabet
        [0, 1]
        >>> T.output_alphabet
        [0, 1]
        >>> T([Integer(0), Integer(1), Integer(0), Integer(1), Integer(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 form

      - `f(base^K * n + r) == f(base^k * n + s) + t` for some integers `0 <= k < K`, `r` and some `t`—valid for all `n` such that the arguments on both sides are nonnegative—

      or the form

      - `f(r) == t` for some integer `r` and some `t`.

      Alternatively, an equation may be replaced by a `transducers.RecursionRule` with the attributes `K`, `r`, `k`, `s`, `t` as above or a tuple `(r, t)`. Note that `t` must be a list in this case.

    - `base` – base of the digit expansion

    - `function` – symbolic function `f` occurring in the recursions

    - `var` – symbolic variable

    - `input_alphabet` – (default: `None`) a list of digits to be used as the input alphabet. If `None` and the base is an integer, `input_alphabet` is chosen to be `srange(base.abs())`.

    - `word_function` – (default: `None`) a symbolic function. If not `None`, `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 the `SymbolicRing`.

    - `is_zero` – (default: `None`) a callable. The recursion relations are only well-posed 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 to `False` 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)` if `expansion` is the digit expansion of `n` to the base `base` 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

          sage: # needs sage.symbolic
          sage: function('f')
          f
          sage: var('n')
          n
          sage: T = transducers.Recursion([
          ....:     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()
          [Transition from (0, 0) to (0, 0): 0|-,
           Transition from (0, 0) to (0, 0): 1|1,
           Transition from (0, 0) to (0, 0): 2|1]

      Python

          >>> from sage.all import *
          >>> # needs sage.symbolic
          >>> function('f')
          f
          >>> var('n')
          n
          >>> T = transducers.Recursion([
          ...     f(Integer(3)*n + Integer(1)) == f(n) + Integer(1),
          ...     f(Integer(3)*n + Integer(2)) == f(n) + Integer(1),
          ...     f(Integer(3)*n) == f(n),
          ...     f(Integer(0)) == Integer(0)],
          ...     Integer(3), f, n)
          >>> T.transitions()
          [Transition from (0, 0) to (0, 0): 0|-,
           Transition from (0, 0) to (0, 0): 1|1,
           Transition from (0, 0) to (0, 0): 2|1]

      To illustrate what this transducer does, we consider the example of \(n=601\):

      Sage

          sage: # needs sage.symbolic
          sage: ternary_expansion = 601.digits(base=3)
          sage: ternary_expansion
          [1, 2, 0, 1, 1, 2]
          sage: weight_sequence = T(ternary_expansion)
          sage: weight_sequence
          [1, 1, 1, 1, 1]
          sage: sum(weight_sequence)
          5

      [Python]

          >>> from sage.all import *
          >>> # needs sage.symbolic
          >>> ternary_expansion = Integer(601).digits(base=Integer(3))
          >>> ternary_expansion
          [1, 2, 0, 1, 1, 2]
          >>> weight_sequence = T(ternary_expansion)
          >>> weight_sequence
          [1, 1, 1, 1, 1]
          >>> sum(weight_sequence)
          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 to `f(n)`.

    - The following example computes the Hamming weight of the non-adjacent form, cf. the Wikipedia article Non-adjacent_form.

      Sage

          sage: # needs sage.symbolic
          sage: function('f')
          f
          sage: var('n')
          n
          sage: T = transducers.Recursion([
          ....:     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()
          [Transition from (0, 0) to (0, 0): 0|-,
           Transition from (0, 0) to (1, 1): 1|-,
           Transition from (1, 1) to (0, 0): 0|1,
           Transition from (1, 1) to (1, 0): 1|1,
           Transition from (1, 0) to (1, 1): 0|-,
           Transition from (1, 0) to (1, 0): 1|-]
          sage: [(s.label(), s.final_word_out)
          ....:  for s in T.iter_final_states()]
          [((0, 0), []),
           ((1, 1), [1]),
           ((1, 0), [1])]

      Python

          >>> from sage.all import *
          >>> # needs sage.symbolic
          >>> function('f')
          f
          >>> var('n')
          n
          >>> T = transducers.Recursion([
          ...     f(Integer(4)*n + Integer(1)) == f(n) + Integer(1),
          ...     f(Integer(4)*n - Integer(1)) == f(n) + Integer(1),
          ...     f(Integer(2)*n) == f(n),
          ...     f(Integer(0)) == Integer(0)],
          ...     Integer(2), f, n)
          >>> T.transitions()
          [Transition from (0, 0) to (0, 0): 0|-,
           Transition from (0, 0) to (1, 1): 1|-,
           Transition from (1, 1) to (0, 0): 0|1,
           Transition from (1, 1) to (1, 0): 1|1,
           Transition from (1, 0) to (1, 1): 0|-,
           Transition from (1, 0) to (1, 0): 1|-]
          >>> [(s.label(), s.final_word_out)
          ...  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

          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)                                               # needs sage.symbolic
          [1, 1, 1]
          sage: sum(T(binary_expansion))                                          # needs sage.symbolic
          3

      [Python]

          >>> from sage.all import *
          >>> NAF = [Integer(1), Integer(0), -Integer(1), Integer(0), Integer(0), Integer(1)]
          >>> ZZ(NAF, base=Integer(2))
          29
          >>> binary_expansion = Integer(29).digits(base=Integer(2))
          >>> binary_expansion
          [1, 0, 1, 1, 1]
          >>> T(binary_expansion)                                               # needs sage.symbolic
          [1, 1, 1]
          >>> sum(T(binary_expansion))                                          # needs sage.symbolic
          3

      Indeed, the given non-adjacent form has three nonzero digits.

    - The following example computes the non-adjacent form from the binary expansion, cf. the Wikipedia article Non-adjacent_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 to `f(2*n) == f(n)` and an empty output would be written. Therefore, we wrap the output in the symbolic function `w` and use the parameter `word_function` to announce this.

      Similarly, we use `w(-1, 0)` to write an output word of length \(2\) in one iteration. Finally, we write `f(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 parameter `is_zero`.

      Sage

          sage: # needs sage.symbolic
          sage: var('n')
          n
          sage: function('f w')
          (f, w)
          sage: T = transducers.Recursion([
          ....:      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()
          [Transition from (0, 0) to (0, 0): 0|0,
           Transition from (0, 0) to (1, 1): 1|-,
           Transition from (1, 1) to (0, 0): 0|1,0,
           Transition from (1, 1) to (1, 0): 1|-1,0,
           Transition from (1, 0) to (1, 1): 0|-,
           Transition from (1, 0) to (1, 0): 1|0]
          sage: for s in T.iter_states():
          ....:     print("{} {}".format(s, s.final_word_out))
          (0, 0) []
          (1, 1) [1, 0]
          (1, 0) [1, 0]

      Python

          >>> from sage.all import *
          >>> # needs sage.symbolic
          >>> var('n')
          n
          >>> function('f w')
          (f, w)
          >>> T = transducers.Recursion([
          ...      f(Integer(2)*n) == f(n) + w(Integer(0)),
          ...      f(Integer(4)*n + Integer(1)) == f(n) + w(Integer(1), Integer(0)),
          ...      f(Integer(4)*n - Integer(1)) == f(n) + w(-Integer(1), Integer(0)),
          ...      f(Integer(0)) == w()],
          ...      Integer(2), f, n,
          ...      word_function=w,
          ...      is_zero=lambda x: sum(x).is_zero())
          >>> T.transitions()
          [Transition from (0, 0) to (0, 0): 0|0,
           Transition from (0, 0) to (1, 1): 1|-,
           Transition from (1, 1) to (0, 0): 0|1,0,
           Transition from (1, 1) to (1, 0): 1|-1,0,
           Transition from (1, 0) to (1, 1): 0|-,
           Transition from (1, 0) to (1, 0): 1|0]
          >>> for s in T.iter_states():
          ...     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

          sage: T(29.digits(base=2))                                              # needs sage.symbolic
          [1, 0, -1, 0, 0, 1, 0]

      [Python]

          >>> from sage.all import *
          >>> T(Integer(29).digits(base=Integer(2)))                                              # needs sage.symbolic
          [1, 0, -1, 0, 0, 1, 0]

      The same transducer can also be entered bypassing the symbolic equations:

      Sage

          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                                                           # needs sage.symbolic
          True

      Python

          >>> from sage.all import *
          >>> R = transducers.RecursionRule
          >>> TR = transducers.Recursion([
          ...       R(K=Integer(1), r=Integer(0), k=Integer(0), s=Integer(0), t=[Integer(0)]),
          ...       R(K=Integer(2), r=Integer(1), k=Integer(0), s=Integer(0), t=[Integer(1), Integer(0)]),
          ...       R(K=Integer(2), r=-Integer(1), k=Integer(0), s=Integer(0), t=[-Integer(1), Integer(0)]),
          ...       (Integer(0), [])],
          ...       Integer(2),
          ...       is_zero=lambda x: sum(x).is_zero())
          >>> TR == T                                                           # needs sage.symbolic
          True

    - Here is an artificial example where some of the \(s\) are negative:

      Sage

          sage: # needs sage.symbolic
          sage: function('f')
          f
          sage: var('n')
          n
          sage: T = transducers.Recursion([
          ....:     f(2*n + 1) == f(n-1) + 1,
          ....:     f(2*n) == f(n),
          ....:     f(1) == 1,
          ....:     f(0) == 0], 2, f, n)
          sage: T.transitions()
          [Transition from (0, 0) to (0, 0): 0|-,
           Transition from (0, 0) to (1, 1): 1|-,
           Transition from (1, 1) to (-1, 1): 0|1,
           Transition from (1, 1) to (0, 0): 1|1,
           Transition from (-1, 1) to (-1, 2): 0|-,
           Transition from (-1, 1) to (1, 2): 1|-,
           Transition from (-1, 2) to (-1, 1): 0|1,
           Transition from (-1, 2) to (0, 0): 1|1,
           Transition from (1, 2) to (-1, 2): 0|1,
           Transition from (1, 2) to (1, 2): 1|1]
          sage: [(s.label(), s.final_word_out)
          ....:  for s in T.iter_final_states()]
          [((0, 0), []),
           ((1, 1), [1]),
           ((-1, 1), [0]),
           ((-1, 2), [0]),
           ((1, 2), [1])]

      Python

          >>> from sage.all import *
          >>> # needs sage.symbolic
          >>> function('f')
          f
          >>> var('n')
          n
          >>> T = transducers.Recursion([
          ...     f(Integer(2)*n + Integer(1)) == f(n-Integer(1)) + Integer(1),
          ...     f(Integer(2)*n) == f(n),
          ...     f(Integer(1)) == Integer(1),
          ...     f(Integer(0)) == Integer(0)], Integer(2), f, n)
          >>> T.transitions()
          [Transition from (0, 0) to (0, 0): 0|-,
           Transition from (0, 0) to (1, 1): 1|-,
           Transition from (1, 1) to (-1, 1): 0|1,
           Transition from (1, 1) to (0, 0): 1|1,
           Transition from (-1, 1) to (-1, 2): 0|-,
           Transition from (-1, 1) to (1, 2): 1|-,
           Transition from (-1, 2) to (-1, 1): 0|1,
           Transition from (-1, 2) to (0, 0): 1|1,
           Transition from (1, 2) to (-1, 2): 0|1,
           Transition from (1, 2) to (1, 2): 1|1]
          >>> [(s.label(), s.final_word_out)
          ...  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

          sage: # needs sage.symbolic
          sage: T = transducers.Recursion([
          ....:     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()
          [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): 1|1,
           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): 1|2,
           Transition from (5, 3) to (1, 2): 0|2,
           Transition from (5, 3) to (1, 1): 1|2,
           Transition from (3, 3) to (1, 1): 0|2,
           Transition from (3, 3) to (3, 2): 1|2,
           Transition from (7, 3) to (1, 1): 0|2,
           Transition from (7, 3) to (2, 1): 1|1,
           Transition from (2, 1) to (1, 1): 0|1,
           Transition from (2, 1) to (2, 1): 1|-]
          sage: for s in T.iter_states():
          ....:     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))
          [2, 3, 4, 3, 4, 5, 4, 3, 4, 5, 6, 5, 4, 5, 4, 3, 4, 5, 6, 5]

      Python

          >>> from sage.all import *
          >>> # needs sage.symbolic
          >>> T = transducers.Recursion([
          ...     f(Integer(4)*n) == f(Integer(2)*n),
          ...     f(Integer(4)*n+Integer(2)) == f(Integer(2)*n+Integer(1))+Integer(1),
          ...     f(Integer(16)*n+Integer(1)) == f(Integer(8)*n+Integer(1)),
          ...     f(Integer(16)*n+Integer(5)) == f(Integer(4)*n+Integer(1))+Integer(2),
          ...     f(Integer(16)*n+Integer(11)) == f(Integer(4)*n+Integer(3))+Integer(2),
          ...     f(Integer(16)*n+Integer(15)) == f(Integer(2)*n+Integer(2))+Integer(1),
          ...     f(Integer(1)) == Integer(2), f(Integer(0)) == Integer(0)]
          ...     + [f(Integer(16)*n+jj) == f(Integer(2)*n+Integer(1))+Integer(2) for jj in [Integer(3),Integer(7),Integer(9),Integer(13)]],
          ...     Integer(2), f, n)
          >>> T.transitions()
          [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): 1|1,
           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): 1|2,
           Transition from (5, 3) to (1, 2): 0|2,
           Transition from (5, 3) to (1, 1): 1|2,
           Transition from (3, 3) to (1, 1): 0|2,
           Transition from (3, 3) to (3, 2): 1|2,
           Transition from (7, 3) to (1, 1): 0|2,
           Transition from (7, 3) to (2, 1): 1|1,
           Transition from (2, 1) to (1, 1): 0|1,
           Transition from (2, 1) to (2, 1): 1|-]
          >>> for s in T.iter_states():
          ...     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]
          >>> list(sum(T(n.bits())) for n in srange(Integer(1), Integer(21)))
          [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 no `output_rings` are specified, the output labels are converted into `ZZ`:

      Sage

          sage: # needs sage.symbolic
          sage: function('f')
          f
          sage: var('n')
          n
          sage: T = transducers.Recursion([
          ....:     f(2*n + 1) == f(n) + 1,
          ....:     f(2*n) == f(n),
          ....:     f(0) == 2],
          ....:     2, f, n)
          sage: for t in T.transitions():
          ....:     print([x.parent() for x in t.word_out])
          []
          [Integer Ring]
          sage: [x.parent() for x in T.states()[0].final_word_out]
          [Integer Ring]

      Python

          >>> from sage.all import *
          >>> # needs sage.symbolic
          >>> function('f')
          f
          >>> var('n')
          n
          >>> T = transducers.Recursion([
          ...     f(Integer(2)*n + Integer(1)) == f(n) + Integer(1),
          ...     f(Integer(2)*n) == f(n),
          ...     f(Integer(0)) == Integer(2)],
          ...     Integer(2), f, n)
          >>> for t in T.transitions():
          ...     print([x.parent() for x in t.word_out])
          []
          [Integer Ring]
          >>> [x.parent() for x in T.states()[Integer(0)].final_word_out]
          [Integer Ring]

      In contrast, if `output_rings` is set to the empty list, the results are not converted:

      Sage

          sage: T = transducers.Recursion([                                       # needs 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():                                         # needs 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]                # needs sage.symbolic
          [Symbolic Ring]

      [Python]

          >>> from sage.all import *
          >>> T = transducers.Recursion([                                       # needs sage.symbolic
          ...     f(Integer(2)*n + Integer(1)) == f(n) + Integer(1),
          ...     f(Integer(2)*n) == f(n),
          ...     f(Integer(0)) == Integer(2)],
          ...     Integer(2), f, n, output_rings=[])
          >>> for t in T.transitions():                                         # needs sage.symbolic
          ...     print([x.parent() for x in t.word_out])
          []
          [Symbolic Ring]
          >>> [x.parent() for x in T.states()[Integer(0)].final_word_out]                # needs sage.symbolic
          [Symbolic Ring]

      Finally, we use a somewhat questionable conversion:

      Sage

          sage: T = transducers.Recursion([                                       # needs 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():                                         # needs sage.rings.finite_rings sage.symbolic
          ....:     print([x.parent() for x in t.word_out])
          []
          [Finite Field of size 5]

      Python

          >>> from sage.all import *
          >>> T = transducers.Recursion([                                       # needs sage.rings.finite_rings sage.symbolic
          ...     f(Integer(2)*n + Integer(1)) == f(n) + Integer(1),
          ...     f(Integer(2)*n) == f(n),
          ...     f(Integer(0)) == Integer(0)],
          ...     Integer(2), f, n, output_rings=[GF(Integer(5))])
          >>> for t in T.transitions():                                         # needs 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

    - non-integral 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 non-deterministic transducer is left out by implicitly using recursion transitions. The well-posedness 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 the `threshold`-th occurrence of a true input letter; then writes `True`.

    INPUT:

    - `input_alphabet` – list or other iterable

    - `threshold` – positive integer specifying how many occurrences of `True` inputs are waited for

    OUTPUT:

    A transducer writing `False` until the `threshold`-th true (Python’s standard conversion to boolean is used to convert the actual input to boolean) input is read. Subsequently, the transducer writes `True`.

    EXAMPLES:

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> T = transducers.Wait([Integer(0), Integer(1)])
        >>> T([Integer(0), Integer(0), Integer(1), Integer(0), Integer(1), Integer(0)])
        [False, False, True, True, True, True]
        >>> T2 = transducers.Wait([Integer(0), Integer(1)], threshold=Integer(2))
        >>> T2([Integer(0), Integer(0), Integer(1), Integer(0), Integer(1), Integer(0)])
        [False, False, False, False, True, True]

  abs(input_alphabet)

    Return a transducer which realizes the letter-wise absolute value of an input word over the given input alphabet.

    INPUT:

    - `input_alphabet` – list or other iterable

    OUTPUT:

    A transducer mapping \(i_0\ldots i_k\) to \(|i_0|\ldots |i_k|\).

    EXAMPLES:

    The following transducer realizes letter-wise absolute value:

    Sage

        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.initial_states()
        [0]
        sage: T.final_states()
        [0]
        sage: T([-1, -1, 0, 1])
        [1, 1, 0, 1]

    Python

        >>> from sage.all import *
        >>> T = transducers.abs([-Integer(1), Integer(0), Integer(1)])
        >>> T.transitions()
        [Transition from 0 to 0: -1|1,
         Transition from 0 to 0: 0|0,
         Transition from 0 to 0: 1|1]
        >>> T.initial_states()
        [0]
        >>> T.final_states()
        [0]
        >>> T([-Integer(1), -Integer(1), Integer(0), Integer(1)])
        [1, 1, 0, 1]

  add(input_alphabet, number_of_operands=2)

    Return a transducer which realizes addition on pairs over the given input alphabet.

    INPUT:

    - `input_alphabet` – 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 of `input_alphabet`.

    EXAMPLES:

    The following transducer realizes letter-wise addition:

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> T = transducers.add([Integer(0), Integer(1)])
        >>> 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]
        >>> T.input_alphabet
        [(0, 0), (0, 1), (1, 0), (1, 1)]
        >>> T.initial_states()
        [0]
        >>> T.final_states()
        [0]
        >>> T([(Integer(0), Integer(0)), (Integer(0), Integer(1)), (Integer(1), Integer(0)), (Integer(1), Integer(1))])
        [0, 1, 1, 2]

    More than two operands can also be handled:

    Sage

        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]

    [Python]

        >>> from sage.all import *
        >>> T3 = transducers.add([Integer(0), Integer(1)], number_of_operands=Integer(3))
        >>> 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)]
        >>> T3([(Integer(0), Integer(0), Integer(0)), (Integer(0), Integer(1), Integer(0)), (Integer(0), Integer(1), Integer(1)), (Integer(1), Integer(1), Integer(1))])
        [0, 1, 2, 3]

  all(input_alphabet, number_of_operands=2)

    Return a transducer which realizes logical `and` over the given input alphabet.

    INPUT:

    - `input_alphabet` – list or other iterable

    - `number_of_operands` – (default: \(2\)) specifies the number of input arguments for the `and` 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 of `input_alphabet`.

    EXAMPLES:

    The following transducer realizes letter-wise logical `and`:

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> T = transducers.all([False, True])
        >>> 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]
        >>> T.input_alphabet
        [(False, False), (False, True), (True, False), (True, True)]
        >>> T.initial_states()
        [0]
        >>> T.final_states()
        [0]
        >>> 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

        sage: T3 = transducers.all([0, 1], number_of_operands=3)
        sage: T3([(0, 0, 0), (1, 0, 0), (1, 1, 1)])
        [False, False, True]

    [Python]

        >>> from sage.all import *
        >>> T3 = transducers.all([Integer(0), Integer(1)], number_of_operands=Integer(3))
        >>> T3([(Integer(0), Integer(0), Integer(0)), (Integer(1), Integer(0), Integer(0)), (Integer(1), Integer(1), Integer(1))])
        [False, False, True]

  any(input_alphabet, number_of_operands=2)

    Return a transducer which realizes logical `or` over the given input alphabet.

    INPUT:

    - `input_alphabet` – list or other iterable

    - `number_of_operands` – (default: \(2\)) specifies the number of input arguments for the `or` 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 of `input_alphabet`.

    EXAMPLES:

    The following transducer realizes letter-wise logical `or`:

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> T = transducers.any([False, True])
        >>> 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]
        >>> T.input_alphabet
        [(False, False), (False, True), (True, False), (True, True)]
        >>> T.initial_states()
        [0]
        >>> T.final_states()
        [0]
        >>> 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

        sage: T3 = transducers.any([0, 1], number_of_operands=3)
        sage: T3([(0, 0, 0), (1, 0, 0), (1, 1, 1)])
        [False, True, True]

    [Python]

        >>> from sage.all import *
        >>> T3 = transducers.any([Integer(0), Integer(1)], number_of_operands=Integer(3))
        >>> T3([(Integer(0), Integer(0), Integer(0)), (Integer(1), Integer(0), Integer(0)), (Integer(1), Integer(1), Integer(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` – list or other iterable

    OUTPUT:

    A transducer mapping an input letter \(x\) to \(f(x)\).

    EXAMPLES:

    The following binary transducer realizes component-wise absolute value (this transducer is also available as `abs()`):

    Sage

        sage: T = transducers.map(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.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]

    Python

        >>> from sage.all import *
        >>> T = transducers.map(abs, [-Integer(1), Integer(0), Integer(1)])
        >>> T.transitions()
        [Transition from 0 to 0: -1|1,
         Transition from 0 to 0: 0|0,
         Transition from 0 to 0: 1|1]
        >>> T.input_alphabet
        [-1, 0, 1]
        >>> T.initial_states()
        [0]
        >>> T.final_states()
        [0]
        >>> T([-Integer(1), Integer(1), Integer(0), Integer(1)])
        [1, 1, 0, 1]

    See also

    `Automaton.with_output()`.

  operator(operator, input_alphabet, number_of_operands=2)

    Return a transducer which realizes an operation on tuples over the given input alphabet.

    INPUT:

    - `operator` – operator to realize; it is a function which takes `number_of_operands` input arguments (each out of `input_alphabet`)

    - `input_alphabet` – 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 of `input_alphabet`.

    EXAMPLES:

    The following binary transducer realizes component-wise addition (this transducer is also available as `add()`):

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> import operator
        >>> T = transducers.operator(operator.add, [Integer(0), Integer(1)])
        >>> 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]
        >>> T.input_alphabet
        [(0, 0), (0, 1), (1, 0), (1, 1)]
        >>> T.initial_states()
        [0]
        >>> T.final_states()
        [0]
        >>> T([(Integer(0), Integer(0)), (Integer(0), Integer(1)), (Integer(1), Integer(0)), (Integer(1), Integer(1))])
        [0, 1, 1, 2]

    Note that for a unary operator the input letters of the new transducer are tuples of length \(1\):

    Sage

        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]

    [Python]

        >>> from sage.all import *
        >>> T = transducers.operator(abs,
        ...                          [-Integer(1), Integer(0), Integer(1)],
        ...                          number_of_operands=Integer(1))
        >>> T([-Integer(1), Integer(1), Integer(0)])
        Traceback (most recent call last):
        ...
        ValueError: Invalid input sequence.
        >>> T([(-Integer(1),), (Integer(1),), (Integer(0),)])
        [1, 1, 0]

    Compare this with the transducer generated by `map()`:

    Sage

        sage: T = transducers.map(abs,
        ....:                     [-1, 0, 1])
        sage: T([-1, 1, 0])
        [1, 1, 0]

    Python

        >>> from sage.all import *
        >>> T = transducers.map(abs,
        ...                     [-Integer(1), Integer(0), Integer(1)])
        >>> T([-Integer(1), Integer(1), Integer(0)])
        [1, 1, 0]

    In fact, this transducer is also available as `abs()`:

    Sage

        sage: T = transducers.abs([-1, 0, 1])
        sage: T([-1, 1, 0])
        [1, 1, 0]

    [Python]

        >>> from sage.all import *
        >>> T = transducers.abs([-Integer(1), Integer(0), Integer(1)])
        >>> T([-Integer(1), Integer(1), Integer(0)])
        [1, 1, 0]

  sub(input_alphabet)

    Return a transducer which realizes subtraction on pairs over the given input alphabet.

    INPUT:

    - `input_alphabet` – 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 letter-wise subtraction:

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> T = transducers.sub([Integer(0), Integer(1)])
        >>> 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]
        >>> T.input_alphabet
        [(0, 0), (0, 1), (1, 0), (1, 1)]
        >>> T.initial_states()
        [0]
        >>> T.final_states()
        [0]
        >>> T([(Integer(0), Integer(0)), (Integer(0), Integer(1)), (Integer(1), Integer(0)), (Integer(1), Integer(1))])
        [0, -1, 1, 0]

  weight(input_alphabet, zero=0)

    Return a transducer which realizes the Hamming weight of the input over the given input alphabet.

    INPUT:

    - `input_alphabet` – 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

        sage: W = transducers.weight([-1, 0, 2])
        sage: W.transitions()
        [Transition from 0 to 0: -1|1,
         Transition from 0 to 0: 0|0,
         Transition from 0 to 0: 2|1]
        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

    Python

        >>> from sage.all import *
        >>> W = transducers.weight([-Integer(1), Integer(0), Integer(2)])
        >>> W.transitions()
        [Transition from 0 to 0: -1|1,
         Transition from 0 to 0: 0|0,
         Transition from 0 to 0: 2|1]
        >>> unary_weight = W([-Integer(1), Integer(0), Integer(0), Integer(2), -Integer(1)])
        >>> unary_weight
        [1, 0, 0, 1, 1]
        >>> weight = add(unary_weight)
        >>> weight
        3

    Also the joint Hamming weight can be computed:

    Sage

        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

    [Python]

        >>> from sage.all import *
        >>> v1 = vector([-Integer(1), Integer(0)])
        >>> v0 = vector([Integer(0), Integer(0)])
        >>> W = transducers.weight([v1, v0])
        >>> unary_weight = W([v1, v0, v1, v0])
        >>> add(unary_weight)
        2

    For the input alphabet `[-1, 0, 1]` the weight transducer is the same as the absolute value transducer `abs()`:

    Sage

        sage: W = transducers.weight([-1, 0, 1])
        sage: A = transducers.abs([-1, 0, 1])
        sage: W == A
        True

    Python

        >>> from sage.all import *
        >>> W = transducers.weight([-Integer(1), Integer(0), Integer(1)])
        >>> A = transducers.abs([-Integer(1), Integer(0), Integer(1)])
        >>> W == A
        True

    For other input alphabets, we can specify the zero symbol:

    Sage

        sage: W = transducers.weight(['a', 'b'], zero='a')
        sage: add(W(['a', 'b', 'b']))
        2

    [Python]

        >>> from sage.all import *
        >>> W = transducers.weight(['a', 'b'], zero='a')
        >>> add(W(['a', 'b', 'b']))
        2