This page is a complement to our submission to ICTAC 2017. This page exists in several forms:
More information is available here:
You may change the cells, and run then. To run a cell in a notebook, hit "Control-Enter" (in which case the focus stays on the same cell) or "Shift-Enter" (focus goes to the next cell). Beware that depending on the requested operations, Vcsn may generate and compile code, which may be a really slow process on small machines (about a minute): be patient! However, the code is compiled only once: successive uses will be way faster.
To run all the cells anew, select "Restart & Run All" in the "Kernel" menu above.
import sys
import vcsn
First we introduce the "context" we are interested in: labels are letter-or-empty-word ("lan": labels are nullable), values are rational numbers.
Q = vcsn.context('lan, q')
Q
The rational expressions in Vcsn supports several operators beyond the classical ones. See Expressions for all the details. The following examples should be self-explanatory.
e1 = Q.expression('[ab]'); e1
e1.star()
2 * e1 + e1 * e1.star()
One can play with the different operations on expansions. However, there is no direct means to enter an expansion, one has to compute the expansion of an expression.
e1 = Q.expression('ab')
x1 = e1.expansion()
x1
e2 = Q.expression('[ab]*')
x2 = e2.expansion()
x2
The left-quotient is denoted {\}
in the syntax of Vcsn's expressions, but we use Python's operator //
to denote it. So e // f
denotes e {\} f
.
x2 // x1
x1 // x2
Although not covered in the paper, Vcsn does support the derivatives. However, the quotient operator is not supported.
e = Q.expression('<2>[ab]*')
e
e.constant_term()
e.derivation('a')
e.derivation('b')
Those three facts, constant term and derivative wrt a and b, are fully captured by this expansion.
e.expansion()
In Vcsn, the left-quotient is written {\}
(because the backslash character is used to escape operators, e.g., \*
denotes the letter *
, not the Kleene star).
The expression E1 is therefore:
e1 = Q.expression('(<2>a) {\} (<3>[ab] + <5>aa* + <7>ab*) + <11>ab*')
e1
Its expansion is (contrary to the paper, the empty expression is denoted ε instead of 1):
e1.expansion()
For sake of performance, the constant term is actually kept separate in our implementation of expansions. The previous result, rewritten in the style of the paper, is exactly the same:
$$
\varepsilon \odot \left[ \left\langle 6\right\rangle \odot \varepsilon \oplus \left\langle 10\right\rangle \odot {a}^{} \oplus \left\langle 14\right\rangle \odot {b}^{}\right] \oplus a \odot \left[\left\langle 11\right\rangle \odot {b}^{*}\right] $$
The derived-term automaton of E1, AE1, is:
a1 = e1.derived_term()
a1
e = Q.expression('(<1/2>ab {\} ab*)*')
e
e.expansion()
a = e.derived_term()
a
As such, this automaton in Q is invalid: it contains a spontaneous loop whose weight, 1, is not starrable.
a.is_valid()
Once trimmed, it is valid though, and its spontaneous transitions may be removed.
a.trim()
a.trim().proper()
A (basic) rational expression is therefore:
a.trim().proper().expression()
The following expression in invalid in Q, but valid in B.
e = Q.expression('(ab {\} ab)*')
a = e.derived_term()
a
a.is_valid()
This is because the weight of the spontaneous cycle, 1, is not starrable:
w = Q.weight('1')
w
try:
w.star()
except RuntimeError as e:
print(e, file=sys.stderr)
But in B, it is well defined (Vcsn uses ⊤ to denote True, and ⊥ for False):
B = vcsn.context('lan, b')
B
w = B.weight('1')
w
w.star()
Hence the automaton is valid.
e = B.expression('(ab {\} ab)*')
a = e.derived_term()
a
a.is_valid()
a.proper()
The right quotient is written as {/}
, and transpose as a postfix operator {T}
.
The following simple example shows how transpose is handled.
e = Q.expression('(abc)*{T}')
e
e.expansion()
e.derived_term()
Then with a right quotient.
e = Q.expression('aba {/} ba')
e
e.derived_term()
The following example, in B, computes the suffixes of the language ab.
e = B.expression('(ab){/}[ab]*')
e
a = e.derived_term()
a
a.trim().proper().determinize().minimize()