12. Finite state machines and vector recurrences#
At the end of
ABA and BC)How many strings of length ABA nor BC as a block of consecutive letters?
Call such a string valid. As in
CAB: writing A next would complete ABA, and writing
C would complete BC, so only B can come next. After
CCB, the letters A and B can come next. After
CBA, all three letters can. So the number of ways to continue depends
on how the string built so far ends, and a single total count of valid strings
of length
After studying these notes, you will be able to do the following.
Choose states that record the information needed to decide which extensions of a string, walk, or partial tiling are allowed.
Construct a finite state machine and its transition table for a list of forbidden substrings.
Convert a transition table into a transition matrix and a vector recurrence, with the correct initial vector and final sum.
Use the Cayley–Hamilton theorem to derive a scalar recurrence from a vector recurrence, and check where it holds.
Compute a matrix power by repeated squaring and count the multiplications it uses.
Set up boundary states and transition matrices for tilings of a
board by dominoes, and by dominoes and angles.
12.1 Finite state machines#
12.1.1 Strings#
A string over a finite alphabet CAB are
B, AB, CAB, and the proper prefixes of
ABA are A, AB.
12.1.2 Keeping notes while building: walks#
We start with an example where the bookkeeping is simple. In
LR or RL. A walk is a string over
While building a walk, we keep a one-symbol note: the last step taken. Before
the first step there is no last step, and we write the note LUR produces the notes
ULR produces
Why does this work? Whether the next step is allowed depends only on the last step, and the note records exactly the last step. So the note always tells us what we need, and we never have to look further back in the walk.
A deterministic finite state machine over an alphabet
The table above is the transition table of the walk machine: its
states are
12.1.3 A machine for strings avoiding ABA and BC#
For Problem 12.1, the last letter is not a good enough note:
CB and AB both end in B, but A can be
written after the first and not after the second. Instead, the note records
how much of a forbidden block sits at the end of the string built so far:
nothing (A, B, or AB. The machine
is
CABBA produces
CABBA is valid; building CABA ends with
CABA is not.
How was the table made? Each entry comes from writing the letter after the
state’s name and reading off the new ending. From AB, the letter
C gives ABC, which ends in BC, so the entry is
B, the letter A gives BA; this
contains no forbidden block, and the part of a forbidden block at its end is
A, so the entry is A. From A, the letter C
gives AC, which ends in no part of a forbidden block, so the entry is
Why does this work? A forbidden block is completed by the letter just written,
so just before that letter, a proper prefix of the block (an element of CCAB and BBCAB both have note
AB and can be continued in exactly the same ways as the string
AB itself. Therefore the machine accepts exactly the valid strings.
Note that state C.
12.2 Counting with a transition matrix#
12.2.1 Strings avoiding ABA and BC#
We now count valid strings separately by state. Let
A, B, AB. These symbols denote numbers, not strings:
for instance AB, and C when
The counts satisfy
ABA are
invalid.
Where do the equations come from? Look at the transition table for the
entries equal to B: they are in the rows of B,
and AB, in column B. So a valid string of length B is built by writing B after a valid string of length
B, or AB. Each such string is
built in exactly one way, since removing its last letter recovers the shorter
string. Hence
The four equations are one matrix equation. With the states in the order
B, because from AB only the letter B keeps the string
valid. For other machines the recipe is the same, and an entry can exceed
Since ZZ denotes the
integers and a caret denotes a power. Later code blocks use matrices defined in
earlier ones, so paste the earlier blocks first.
M = matrix(ZZ, [[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 0, 1, 1],
[0, 1, 0, 0]])
v0 = vector(ZZ, [1, 0, 0, 0])
show([sum(M^n * v0) for n in range(9)])Sage displays
12.2.2 Walks#
For walks, let L, U, R, and let
12.3 From a vector recurrence to a scalar recurrence#
The vector recurrence computes
show(M.charpoly('x'))Sage displays
Why does this work? Recall that the characteristic polynomial of a
Every square matrix
For example,
Suppose
Two cautions, both visible for walks. Sage gives
Conversely, every recurrence becomes a vector recurrence if we store several
consecutive terms. For example,
12.4 Computing matrix powers#
Computing
To compute
Set
, , and . If
is odd, replace by . Replace
by . If , stop and output . Replace
by and go to step 2.
For
This counts matrix multiplications, not work on digits. Our counts grow
exponentially, so their number of digits grows in proportion to
12.5 Tilings of three-row boards#
12.5.1 Tiles and boundary states#
A
We build a tiling column by column, the way we built strings letter by
letter. Figure 12.2 follows a domino tiling of the
The note we keep is the set of cells in the next column that are already
covered; we call it the boundary state. We record it as a number,
One step of the building process places the tiles whose leftmost column is
the current column. They cover its uncovered cells and may stick out into the
next column. We call such a set of tiles a filling from
Now we count exactly as for strings. Let
To list the fillings from a state without repeats, we always place next the tile covering the topmost uncovered cell of the column, trying every placement that fits and avoids covered cells.
12.5.2 Dominoes#
Let
There is a quick way to check this table. The cells a domino filling covers in
the next column come from horizontal dominoes, one per row of
D = matrix(ZZ, [[0, 1, 0, 0, 1, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[1, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0]])
show([(D^n)[0, 0] for n in range(11)])
show(D.charpoly('x').factor())The counts are
Sage factors
Why does the shorter recurrence hold? Write
12.5.3 Dominoes and angles#
Let
Listing the fillings from every state in the same way gives
E = matrix(ZZ, [[0, 1, 0, 0, 1, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 1, 0],
[0, 1, 0, 0, 1, 1, 0, 0],
[2, 0, 0, 0, 1, 1, 1, 0],
[1, 1, 0, 1, 0, 0, 0, 0],
[2, 0, 1, 0, 0, 0, 0, 0],
[2, 1, 0, 1, 0, 1, 0, 0],
[3, 1, 2, 0, 1, 0, 0, 0]])
show([(E^n)[0, 0] for n in range(9)])
show(E.charpoly('x'))The counts begin
Sage gives
12.6 Summary of the method#
Build the objects one piece at a time: a letter, a step, or a column filling.
Choose states that record what decides the allowed next pieces: the longest suffix that is a proper prefix of a forbidden string, the last step, or the covered cells beyond the cut.
Form the transition matrix, whose entry in row
and column counts the pieces leading from to , together with the initial vector and the coordinates to add at the end. Use the characteristic polynomial to get a scalar recurrence, and check where it starts.
Let abca,
bcab, and cabc, as at the end of