Whether the automaton has the twins property.

- Sibling states: Two states $p$, $q$ are
*siblings*if there exist two labels $x$ and $y$ such that $p$ and $q$ can be reached from an initial state by path labeled with $x$ and there is a cycle at $p$ and $q$ both labeled with $y$. - Twins states: Two sibling states $p$ and $q$ are
*twins*iff for any label $y$: $w[P(p, y, p)] = w(P[q, y, q])$ - Has twins property: An automaton has the twins property if any two sibling states of this automaton are twins.

Preconditions:

- The automaton is not cycle ambiguous

See also:

In [1]:

```
import vcsn
q = vcsn.context('lal_char(ab), q')
def std(e):
return q.expression(e, 'binary').standard()
```

Consider the following $\mathbb{Q}$-automaton:

In [2]:

```
a = std('(ab)* + (ab)*')
a
```

Out[2]:

In [3]:

```
a.has_twins_property()
```

Out[3]:

In [4]:

```
a = std('(<2>ab)* + (ab)*')
a
```

Out[4]:

In [5]:

```
a.has_twins_property()
```

Out[5]:

When the automaton has no sibling states, it has the twins property.

In [6]:

```
a = std("(aa)*+(ab)*")
a
```

Out[6]:

In [7]:

```
a.has_twins_property()
```

Out[7]:

In [8]:

```
%%automaton a
context = "lal_char(abcd), zmin"
$ -> 0
0 -> 1 <1>a
0 -> 2 <2>a
1 -> 1 <3>b
1 -> 3 <5>c
2 -> 2 <3>b
2 -> 3 <6>d
3 -> $
```

In [9]:

```
a.determinize()
```

Out[9]:

The twins property can also be checked in $\mathbb{Z}$:

In [10]:

```
%%automaton a
context = "lal(abcd), z"
$ -> 0
0 -> 1 a
0 -> 2 <2>a
1 -> 1 <3>b
1 -> 3 <5>c
2 -> 2 <3>b
2 -> 3 <6>d
3 -> $
```

In [11]:

```
a.has_twins_property()
```

Out[11]:

Or with tuples of weightsets:

In [12]:

```
%%automaton a
context = "lal_char(abc), lat<z,zmin>"
$ -> 0
0 -> 1 <(1, 3)>a
0 -> 2 <(1, 5)>a
1 -> 3 <(4, 8)>b
3 -> $
2 -> 4 <(6, 4)>b
4 -> $
3 -> 1 <(9, 3)>a
4 -> 2 <(6, 7)>a
```

In [13]:

```
a.has_twins_property()
```

Out[13]: