Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 45900
Kernel: Python 3

automaton.ldivide(aut)

\newcommand\ldivide{\setminus} Compute the left quotient of two automata, i.e. the automaton recognizing the language of words vv such that there exists a word uu recognized by lhs with uvuv recognized by rhs.

In other words, it is the automata equivalent of languages left quotient, denoted by the operator \ldivide or by a 1-1 exposant on the left-hand side, and defined by:

KL=K1L=uKu1LK \ldivide L = K^{-1}L = \bigcup\limits_{u \in K} u^{-1}L

where u1Lu^{-1}L is the (left) quotient of L by the word u, defined like this:

u1L=vLu1v={wuwL}u^{-1}L = \bigcup\limits_{v \in L}u^{-1}v = \{w \mid uw \in L\}

See also:

Algorithm

Boolean case

For two automata A1,A2\mathcal{A}_1, \mathcal{A}_2 with respective state set Q1,Q2Q_1, Q_2, the algorithm works as follows:

  • Remove all initial transitions of A2\mathcal{A}_2

  • For every state pair (q1,q2)Q1×Q2(q_1, q_2) \in Q_1 \times Q_2, set q2q_2 as initial if the following conditions are respected:

    • (q1,q2)(q_1, q_2) is accessible in A1×A2\mathcal{A}_1 \times \mathcal{A}_2

    • q1q_1 is final

    Let ini_n and fnf_n denote an initial and a final state of An\mathcal{A}_n. The first condition ensures that, for any path i2uq2vf2i_2 \xrightarrow{u} q2 \xrightarrow{v} f_2, there is a path (i1,i2)u(q1,q2)(i_1, i_2) \xrightarrow{u} (q_1, q2) in A1×A2\mathcal{A}_1 \times \mathcal{A}_2, and therefore a path i1uq1i_1 \xrightarrow{u} q_1 in A1\mathcal{A}_1. The second condition ensures that uu is recognized by A1\mathcal{A}_1.

  • Since q2q_2 is set as initial, A2\mathcal{A}_2 now recognizes vv. So for any path accepting uvuv in A2\mathcal{A}_2, the constructed automaton recognizes vv if and only if uu is recognized by A1\mathcal{A}_1.

Preconditions:

  • None

Postconditions:

  • None

Weighted case

In the weighted case, the algorithm is similar to the conjunction between A1\mathcal{A}_1 and A2\mathcal{A}_2 except for three things:

  • A1\mathcal{A}_1 continues matching even when it reaches an accepting state

  • if A1\mathcal{A}_1 has not reached an accepting state yet, transitions are labelled one

  • weights are multiplied

Preconditions:

  • the labelset is free

Postconditions:

  • None

Examples

import vcsn ctx = vcsn.context('lan_char, b') aut = lambda e: ctx.expression(e).automaton()

Quotient of two words

The quotient can be seen as a prefix-remover operator, such that the identity u\(uv)=vu\backslash (uv) = v is respected for any word uu and vv.

a1 = aut('ab').ldivide(aut('abcd')) a1
Image in a Jupyter notebook

On this example, u=abu = ab and v=cdv = cd. The suppression of the original initial transitions (on state 0 in this example) will often lead to non-accessible states, which we may want to remove with the automaton.trim method:

a1.trim()
Image in a Jupyter notebook

Quotient of a language by a word

The quotient of a language by a word is the union of word quotients for all words of the language:

aut('a').ldivide(aut('ab + ac + bc'))
Image in a Jupyter notebook

Since "a" is not a prefix of "bc", it is not taken into account in the resulting automaton.

Quotient of two languages

The quotient of two languages is the union of the quotient of the right-hand side by words of the left-hand side:

aut('a+b').ldivide(aut('ab + ac + bd + be'))
Image in a Jupyter notebook

Weighted automata

Left quotient also works on weighted automata:

q = vcsn.context('lan_char, q') qaut = lambda e: q.expression(e).automaton() qaut('<2>ab').ldivide(qaut('<6>abcd'))
Image in a Jupyter notebook

Right quotient

The right quotient of a language by a word is defined similarly as the left quotient:

L/v=uLu/v={wwvL}L / v = \bigcup\limits_{u \in L}u / v = \{w \mid wv \in L\}

Which naturaly leads to the right quotient of two languages:

K/L=vLK/vK / L = \bigcup\limits_{v \in L} K / v

The right quotient can be expressed using the left quotient and the transpose operator:

K/L=(LtKt)tK / L = (L^t \ldivide K^t)^t
def rdivide(a1, a2): return (a2.transpose().ldivide(a1.transpose())).transpose() rdivide(aut('abc'), aut('c'))
Image in a Jupyter notebook