expression
.compose(e)
¶The composition of two (two-tape) expressions.
Since Python 3.5, can also be written with the infix operator @
: e @ f
is syntactic sugar for e.compose(f)
.
See also:
import vcsn
ctx1 = vcsn.context("lat<lan(ab), lan(jk)>, zmin")
ctx2 = vcsn.context("lat<lan(jk), lan(xy)>, zmin")
As a simple example, let's compose $a|j+b|j$ with $j|x + k|y$, convert this expression into an automaton, and then extract an expression from it. In other words, let's build an extended expression, and eliminate its compose operator.
e1 = ctx1.expression('a|j + b|k')
e2 = ctx2.expression('j|x* + k|y*')
e = e1 @ e2
e
a = e.automaton()
a
a.expression()
Using expression.automaton
(aka, expression.derived_term
) on the composition of expressions often gives better results than composing the automata:
(e1.automaton() @ e2.automaton()).strip()
In this example (taken from SACS-2017 which was based on mohri.2002.ciaa), we build a Levenshtein automaton which can be used to compute the distance between words and/or languages.
We introduce two weighted expressions: the first one specifies the costs: _I_nserting or _S_uppressng a letter costs 1, but merely copying it is free (cost 0, left implicit).
ctx = vcsn.context("lat<lan(a-zIS), lan(a-zIS)>, zmin")
f1 = ctx.expression('([a-z] + ⟨1⟩(\e|I + [a-z]|S))∗'); f1
The second specifies what letters can be inserted, and what suppression means.
f2 = ctx.expression('([a-z] + I|[a-z] + S|\e)∗')
f2
Finally, this expression is equivalent to the Levenshtein automaton (for these costs).
f = f1 @ f2
f
f.automaton()
The edit distance between train and plane is
(ctx.expression('train') @ f1 @ f2 @ ctx.expression('plane')).shortest(3)