Processing math: 100%

expression.expansion()

Compute the expansion of a weighted expression. An expansion is a structure that combines three different features of a (weighted) rational expression r:

  • its constant-term, i.e., the weight associated to the empty word, denoted c(r)
  • its firsts, i.e., the set of labels that prefix the defined language, denoted f(r)
  • its derived-terms, i.e., for each label a, its associated polynomials of "subsequent" expressions, denoted ar.

If one denotes d(r) the expansion of r, it holds that: d(r)=c(r)af(r)aar

The main use of expansions (and derivations) is to compute the derived-term automaton of an expression. The advantage of expansions over derivations is their independence with respect to the alphabet. As a matter of fact, they do not require a finite-alphabet (see examples below). Besides, the reunite constant-term, first, and derivation into a single concept.

See also:

References:

Examples

The following function will prove handy to demonstrate the relation between the expansion on the one hand, and, on the other hand, the constant-term and the derivations. It takes an expression r and a list of letters, and returns a LATEX aligned environment to display:

  1. d(r) the expansion
  2. c(r) the constant-term
  3. ar the derivation with respect to a.
In [1]:
import vcsn
from IPython.display import Latex

def diffs(e, ss):
    eqs = [r'd\left({0:x}\right) &= {1:x}'.format(e, e.expansion()),
           r'c\left({0:x}\right) &= {1:x}'.format(e, e.constant_term())]
    for s in ss:
        eqs.append(r'\frac{{\partial}}{{\partial {0}}} {1:x} &= {2:x}'
                   .format(s, e, e.derivation(s)))
    return Latex(r'''\begin{{aligned}}
        {eqs}
    \end{{aligned}}'''.format(eqs=r'\\'.join(eqs)))

Classical Expressions

In the classical case (labels are letters, and weights are Boolean), this is the construct as described by Antimirov.

In [2]:
b = vcsn.context('lal_char(ab), b')
e = b.expression('[ab]{3}')
e.expansion()
Out[2]:
a[(a+b)2]b[(a+b)2]

Or, using the diffs function we defined above:

In [3]:
diffs(e, ['a', 'b'])
Out[3]:
d((a+b)3)=a[(a+b)2]b[(a+b)2]c((a+b)3)=a(a+b)3=(a+b)2b(a+b)3=(a+b)2

Weighted Expressions

Of course, expressions can be weighted.

In [4]:
q = vcsn.context('lal_char(abc), q')
e = q.expression('(<1/6>a*+<1/3>b*)*')
diffs(e, ['a', 'b'])
Out[4]:
d((16a+13b))=2a[13a(16a+13b)]b[23b(16a+13b)]c((16a+13b))=2a(16a+13b)=13a(16a+13b)b(16a+13b)=23b(16a+13b)

And this is tightly connected with the construction of the derived-term automaton.

In [5]:
e.derived_term()
Out[5]:
%3 I0 0 (⟨1/6⟩a*+⟨1/3⟩b*)* I0->0 F0 F1 F2 0->F0 ⟨2⟩ 1 a*(⟨1/6⟩a*+⟨1/3⟩b*)* 0->1 ⟨1/3⟩a 2 b*(⟨1/6⟩a*+⟨1/3⟩b*)* 0->2 ⟨2/3⟩b 1->F1 ⟨2⟩ 1->1 ⟨4/3⟩a 1->2 ⟨2/3⟩b 2->F2 ⟨2⟩ 2->1 ⟨1/3⟩a 2->2 ⟨5/3⟩b

Breaking expansion

There is (currently) no means to break an expansion (which would mean breaking its polynomials). The construction of the derived-term automaton does it on the fly.

Non-free labelsets

Contrary to derivation, which requires a finite alphabet, expansions support labels which are words, or even tuples.

Below, we define a two-tape-of-words context, and a simple expression that uses three different multitape labels: (11|eleven), etc. Then derived_term is used to build the automaton.

In [6]:
ctx = vcsn.context('lat<law_char(0-9), law_char(a-zA-Z)>, b')
ctx
Out[6]:
{0,1,2,3,4,5,6,7,8,9}×{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}B
In [7]:
e = ctx.expression("(11|eleven + 12|twelve + 13|thirteen)*")
e
Out[7]:
(11|eleven+12|twelve+13|thirteen)
In [8]:
e.expansion()
Out[8]:
11|eleven[(11|eleven+12|twelve+13|thirteen)]12|twelve[(11|eleven+12|twelve+13|thirteen)]13|thirteen[(11|eleven+12|twelve+13|thirteen)]

This enables the construction of the associated derived-term automaton.

In [9]:
e.derived_term()
Out[9]:
%3 I0 0 (11|eleven+12|twelve+13|thirteen)* I0->0 F0 0->F0 0->0 11|eleven, 12|twelve, 13|thirteen