# We disable autosave for technical reasons.
# Replace 0 by 120 in next line to restore default.
%autosave 0
Autosave disabled
import awalipy # If import fails, check that
# Python version used as Jupyter
# kernel matches the one
# Awalipy was compiled with.
[Warning] The python module awalipy relies on compilation executed "on-the-fly" depending on the context (type of weights, of labels, etc.). As a result, the very first call to a given function in a given context may take up to one minute.
When parsing a rational expression operator precedence is : star > concatenation > union . In other words,
a+(b*)
= a+b*
!= (a+b)*
a(b*)
= ab*
!= (ab)*
a+(bc)
= a+bc
!= (a+b)c
e = awalipy.RatExp("(a+bc)c*(ab)*")
e
(a+bc)c*(ab)*
By default, the alphabet of a rational expression is the set of all letters appearing in it. However the alphabet may be increased artifically as follows.
f = awalipy.RatExp("(a+b)(c*+a)*", alphabet="abcd")
f
(a+b)(c*+a)*
Displaying a rational expression as a tree.
e.display()
e+f
(a+bc)c*(ab)*+(a+b)(c*+a)*
e+=e
e
(a+bc)c*(ab)*+(a+bc)c*(ab)*
e^f
((a+bc)c*(ab)*+(a+bc)c*(ab)*)((a+b)(c*+a)*)
e^="abc*"
e
((a+bc)c*(ab)*+(a+bc)c*(ab)*)(abc*)
e.star()
(((a+bc)c*(ab)*+(a+bc)c*(ab)*)(abc*))*
e.star_here()
e
(((a+bc)c*(ab)*+(a+bc)c*(ab)*)(abc*))*
e.star_height()
2
e.star_normal_form()
(((a+bc)c*(ab)*+(a+bc)c*(ab)*)(abc*))*
The method expand
distribute union and concatenation as much as possible.
awalipy.RatExp("(a+bc)(d+e)(f+g)*").expand()
ad(f+g)*+ae(f+g)*+bcd(f+g)*+bce(f+g)*
By default, awali uses the derived term algorithm.
A = e.exp_to_aut()
A.display()
The states of A
are indeed all the derived expressions of e
. It may be displayed by setting to True
the optional argument history
.
A.display(horizontal=False)
For convenience, one may give an expression to the constructor of an automaton.
A = awalipy.Automaton(awalipy.RatExp("01*0*"))
A.display()
Awali implements multiple algorithms for transforming expressions to automata, such as thompson or standard
g = awalipy.RatExp("1*0")
g.exp_to_aut("thompson").display()
g.exp_to_aut("standard").display()
SC = awalipy.load("slowcerny") # Lets us load some automaton
SC.display()
Awalipy uses the classical state-elimination algorithm to compute an expression from an automaton.
To choose which state to eliminate first we use the min_inout_degree
heuristics that is: at each step, the next eliminated state is the one with the minimal product of its in-degree by its out-degree.
SC_exp1 = SC.aut_to_exp()
SC_exp1
(\e+(\e+b*a)b*a+(\e+b*a)b+(\e+(\e+b*a)a)(ab*aa)*(b+ab*ab))(ab*ab*a+b(ab*aa)*(b+ab*ab))*
To disable this heuristics, use the method "id_order"
: states are eliminated in increasing order of identifier.
SC_exp2 = SC.aut_to_exp(method="id_order")
SC_exp2
(\e+b+b*(ab)+(\e+a+b*(aa))(ab*(aa))*(b+ab*(ab)))(b(ab*(aa))*(b+ab*(ab)))*+b*(a(b(ab*(aa))*(b+ab*(ab)))*)+(\e+(\e+b+b*(ab)+(\e+a+b*(aa))(ab*(aa))*(b+ab*(ab)))(b(ab*(aa))*(b+ab*(ab)))*a+b*(a(b(ab*(aa))*(b+ab*(ab)))*a))(b+ab*(a(b(ab*(aa))*(b+ab*(ab)))*a))*(ab*(a(b(ab*(aa))*(b+ab*(ab)))*))
Weights must be put between "<>" and weights takes precedence over other operators:
<-1>a*
= (<-1>a)*
!= <-1>(a*)
<-1>ab
= (<-1>a)b
!= <-1>(ab)
<-1>a+b
= (<-1>a)+b
!= <-1>(a+b)
The weighset must be given as a second argument at construction.
h = awalipy.RatExp("(<1>a*+<-1>(b*))","Z")
h
a*+<-1>(b*)
h.display()
awalipy.RatExp("<-2>","Z")
<-2>\e
i = h ^ h + ("<-1>" ^ h).star()
i
(a*+<-1>(b*))(a*+<-1>(b*)+<-1>(a*+<-1>(b*))*)
For aut_to_exp
or standard
to work, the rational expression needs to be valid.
An expression is valid if, in every sub-expression, the weight of $\epsilon$ is well defined.
For instance the expression *(< 2 >\e)** is not valid (with weightset $(\mathbb{Z},+,\times$))
i.is_valid()
True
i.exp_to_aut().display()
The method thompson()
is not suitable for weighted expressions.
Indeed, let us consider the following valid expression g
:
g = awalipy.RatExp("(<1>(a*)+<-1>(b*))*","Z")
g.is_valid()
True
G = g.exp_to_aut(method="thompson")
G.display(horizontal=False)
In this case, thompson
produces an automaton that is not valid.
G.is_valid()
False
The method constant_term
gives the weight of epsilon
j = awalipy.RatExp("<3>((<1/4>(a*)+<1/4>(b*))*)<2>","Q")
j
<3>((<1/4>(a*)+<1/4>(b*))*)<2>
j.constant_term()
'12'
j.get_weightset()
Q
The method exp.get_kind()
gives the top level kind of a RatExp exp
.
(For instance, below, the top level operator of expression j
is the Kleene star.)
j.get_kind()
STAR~5
The method get_kind()
returns an object of RatExpKind
, which is a sort of enum. The different instances are accessible as follows.
awalipy.RatExp.ZERO
ZERO~0
awalipy.RatExp.ONE
ONE~1
awalipy.RatExp.ATOM
ATOM~2
awalipy.RatExp.SUM
SUM~3
awalipy.RatExp.PROD
PROD~4
awalipy.RatExp.STAR
STAR~5
The list of all possible instances of RatExpKind
can be accessed via RatExpKind.instance
.
awalipy.RatExpKind.instances
[ZERO~0, ONE~1, ATOM~2, SUM~3, PROD~4, STAR~5]
Object of type RatExpKind
can be converted to or built from their integer value or their string value as follows.
awalipy.RatExpKind.of["STAR"]
STAR~5
str(awalipy.RatExp.PROD)
'PROD'
awalipy.RatExpKind.of[2]
ATOM~2
int(awalipy.RatExp.ATOM)
2
The method ratexp.children()
gives the sub-expressions of a RatExp
ratexp
.
j.children()
[<1/4>(a*)+<1/4>(b*)]
In the case where the expression is a RatExp.ATOM
, then children()
gives the held label as string.
k = awalipy.RatExp('a')
k.get_kind()
ATOM~2
k.children()
['a']
l = awalipy.RatExp('<2>a','Z')
l.get_kind()
ATOM~2
l.children()
['a']
The method ratexp.weight()
gives the left and right weights of a RatExp
ratexp
.
j.display()
j.weight()
['3', '2']
k.display()
k.weight()
['true', 'true']
l.display()
l.weight()
['2', '1']
The method ratexp.content()
gives the full top-level content of a RatExp
exp
.
j.display()
j
<3>((<1/4>(a*)+<1/4>(b*))*)<2>
j.content()
[STAR~5, '3', <1/4>(a*)+<1/4>(b*), '2']