# automaton.infiltrate¶

Create the (accessible part of the) infiltration product of two automata. In a way the infiltration product combines the conjunction (synchronized) and the shuffle product.

Preconditions:

• all the labelsets are letterized

## Examples¶

In [1]:
import vcsn
c = vcsn.context('lal_char, seriesset<lal_char, z>')
std = lambda exp: c.expression(exp).standard()
c

Out[1]:
$\{\ldots\}\to\mathsf{Series}[\{\ldots\}\to\mathbb{Z}]$

The following simple example aims at emphasizing that the transitions of the infiltration combine those of the shuffle and the conjunction products.

In [2]:
x = std("<x>a"); x

Out[2]:
In [3]:
y = std("<y>a"); y

Out[3]:
In [4]:
x & y

Out[4]:
In [5]:
x.shuffle(y)

Out[5]:
In [6]:
x.infiltrate(y)

Out[6]:

Don't be mistaken though: if in this example the sum of the shuffle and conjunction products indeed match the infiltration product, this no longer applies to larger automata. In the following example (which nicely highlights the features of these three types of product) the transition from $(1, 0)$ to $(2, 1)$ would be missing.

In [7]:
xx = x * x
xx

Out[7]:
In [8]:
yy = y * y
xx & yy

Out[8]:
In [9]:
xx.shuffle(yy)

Out[9]:
In [10]:
xx.infiltrate(yy)

Out[10]:

### Associativity¶

This operator is associative.

In [11]:
x = std('<x>a')
y = std('<y>a')
z = std('<z>a')

In [12]:
a = x.infiltrate(y).infiltrate(z); a

Out[12]:
In [13]:
b = x.infiltrate(y.infiltrate(z)); b

Out[13]:
In [14]:
a.strip().is_isomorphic(b.strip())

Out[14]:
True

As a convenience, infiltrate is variadic: it may accept more than two arguments. However, it's (currently) only a wrapper around repeated calls to the binary operation (as can be seen by the parentheses in the state names below).
c = x.infiltrate(y, z); c

c.strip().is_isomorphic(a.strip())

True