コード例 #1
0
ファイル: trie.py プロジェクト: Prateeba/Mini_memoire
def check(algo, ctx, polynomial, exp):
    print(algo, ctx, polynomial)

    # Starting from a polynomial.
    c = vcsn.context(ctx)
    p = c.polynomial(polynomial)
    a = trie(algo, p)
    CHECK_EQ(exp, a.format('daut'))
    if ctx.startswith('lal'):
        CHECK(a.is_deterministic() if algo ==
              'trie' else a.is_codeterministic())
    CHECK_EQ(p, a.shortest(100))

    # Likewise, but via a string.
    c = vcsn.context(ctx)
    a = trie(algo, c, data=p.format('list'))
    CHECK_EQ(exp, a.format('daut'))

    # Likewise, but via a file.
    with open('series.txt', 'w') as file:
        print(p.format('list'), file=file)
    c = vcsn.context(ctx)
    a = trie(algo, c, filename='series.txt')
    os.remove('series.txt')
    CHECK_EQ(exp, a.format('daut'))
コード例 #2
0
def check(c1, c2):
    c1 = vcsn.context(c1)
    c2 = vcsn.context(c2)
    CHECK_EQ(True, c1 == c1)
    CHECK_EQ(True, c2 == c2)
    CHECK_EQ(False, c1 == c2)
    CHECK_EQ(False, c2 == c1)
    CHECK_EQ(False, c1 != c1)
    CHECK_EQ(False, c2 != c2)
    CHECK_EQ(True, c1 != c2)
    CHECK_EQ(True, c2 != c1)
コード例 #3
0
ファイル: standard.py プロジェクト: Prateeba/Mini_memoire
def check(r, exp=None, file=None):
    if not isinstance(r, vcsn.expression):
        r = ctx.expression(r)
    print("check: {:u}".format(r))
    if file:
        exp = metext(file, 'gv')

    # Check inductive, standard flavor.
    a = r.inductive('standard')
    CHECK_EQ(exp, a)
    CHECK(a.is_standard(), 'automaton for {} is not standard: {}'.format(r, a))

    # Check that we are equivalent to derived-term.  However,
    # derived-term sometimes needs a neutral to compute ldivide/rdivide.
    if r.info('ldivide'):
        # FIXME: Not very elegant...  We need means to derive contexts
        # from others.  Unless we get rid of lal.
        nctx = vcsn.context(
            re.sub('(.*?), *(.*)', r'nullableset<\1>, \2',
                   r.context().format('sname')))
        nr = r.expression(nctx)
        a_dt = nr.automaton('expansion')
    else:
        a_dt = r.automaton('expansion')
    CHECK_EQUIV(a, a_dt)

    if r.is_extended():
        XFAIL(lambda: r.standard())
    else:
        # Check that standard computes the same automaton.  Well, not
        # the same state numbers though: `standard` leaves gaps.
        CHECK_ISOMORPHIC(a, r.standard())
コード例 #4
0
def randexp(c, *args, **kwargs):
    '''Generate a random expression.'''

    if not isinstance(c, vcsn.context):
        c = vcsn.context(c)
    res = c.random_expression(*args, **kwargs)
    print('randexp:', res)
    return res
コード例 #5
0
ファイル: tuples.py プロジェクト: Prateeba/Mini_memoire
def check(ctx, exp):
    '''Check round-tripping a multitape expression.'''
    c = vcsn.context(ctx)
    try:
        r = c.expression(exp)
    except RuntimeError:
        FAIL("error parsing " + exp)
    else:
        CHECK_EQ(exp, r)
コード例 #6
0
 def update(self, *_):
     self.updater.abort()
     try:
         self.error.value = ''
         txt = self.widget.getvalue()
         c = vcsn.context(txt)
         if isinstance(self.name, str):
             self.ipython.shell.user_ns[self.name] = c
     except RuntimeError as e:
         self.error.value = formatError(e)
コード例 #7
0
    def __init__(self, ipython, name=None):
        self.ipython = ipython
        self.name = name
        if self.name:
            # A named context (i.e., not used in the d3 widget).
            if not isinstance(self.name, str):
                ctx = name
                text = ctx.format('sname')
            elif not name.isidentifier():
                raise NameError(
                    '`{}` is not a valid variable name'.format(name))
            elif self.name in self.ipython.shell.user_ns:
                if not isinstance(self.ipython.shell.user_ns[self.name],
                                  vcsn.context):
                    raise TypeError(
                        '`{}` exists but is not a context'.format(name))
                ctx = self.ipython.shell.user_ns[self.name]
                text = ctx.format('sname')
            else:
                text = 'lal, b'
                ctx = vcsn.context(text)
        else:
            # An unnamed context (i.e., used in the d3 widget).
            ctx = vcsn.context('lal_char, b')

        toLatex = lambda txt: vcsn.context(txt)._repr_latex_()
        self.widget = TextLatexWidget('Context:', text, toLatex)
        self.widget.text.on_submit(self.update)
        self.widget.text.observe(self.asyncUpdate, 'value')

        # Binding for D3widget
        self.text = self.widget.text

        self.error = widgets.HTML(value='')

        # Display the widget if it is not use into the d3 widget.
        if isinstance(self.name, str):
            ctx = widgets.HBox(children=self.widget.tolist())
            box = widgets.VBox(children=[ctx, self.error])
            display(box)

        self.updater = AsyncUpdater(self, 0.5)
コード例 #8
0
ファイル: test.py プロジェクト: Prateeba/Mini_memoire
def normalize(a):
    '''Turn automaton `a` into something we can check equivalence with.'''
    a = a.strip().realtime()
    # Eliminate nullablesets if there are that remain.  This is safe:
    # if there are \e that remain, the following conversion _will_
    # fail.
    to = re.sub(
        r'nullableset<(lal_char\(.*?\)|letterset<char_letters\(.*?\)>)>',
        r'\1',
        a.context().format('sname'))
    return a.automaton(vcsn.context(to))
コード例 #9
0
ファイル: expression.py プロジェクト: pombredanne/vcsn
def check(e, ctx=None, ids=None, exp=None):
    '''When `e` is converted to `ctx` and `ids`, it should be `exp`.
    `exp` defaults to `e`.'''
    if ctx is None:
        ctx = e.context()
    if ids is None:
        ids = e.identities()
    if exp is None:
        exp = e
    if not isinstance(ctx, vcsn.context):
        ctx = vcsn.context(ctx)
    CHECK_EQ(exp, e.expression(ctx, ids))
コード例 #10
0
ファイル: sms2fr.py プロジェクト: Prateeba/Mini_memoire
def sms_to_fr(sms, grap, synt):
    # Graphemic automaton expect input of the format '[#this#is#my#text#]'.
    sms = re.escape('[#' + sms.replace(' ', '#') + '#]')
    ctx = vcsn.context('lan_char, rmin')
    # Create the automaton corresponding to the sms.
    sms_aut = ctx.expression(sms).automaton().partial_identity().proper()
    # First composition with graphemic automaton.
    aut_g = sms_aut.compose(grap).coaccessible().strip()
    # Second composition with syntactic automaton.
    aut_s = aut_g.compose(synt).coaccessible().strip().project(1).proper()
    # Retrieve the path more likely to correspond to french translation.
    return str(aut_s.lightest())
コード例 #11
0
ファイル: efsm.py プロジェクト: Prateeba/Mini_memoire
def compose(l, r):
    print("Compose:", l, r)
    # We need to enforce the letters, otherwise fstcompose complains
    # about incompatible symbol tables.
    ctx = vcsn.context('lat<lan(amxy), lan(amxy)>, zmin')
    l = ctx.expression(l).automaton()
    r = ctx.expression(r).automaton()
    c_vcsn = l.compose(r).strip()
    c_ofst = l.fstcompose(r)
    # We get a narrower context, restore the original one so that
    # CHECK_EQ does not fail because of context differences.
    c_ofst = c_ofst.automaton(ctx)
    return (c_vcsn, c_ofst)
コード例 #12
0
ファイル: d3Widget.py プロジェクト: pombredanne/vcsn
    def __init__(self, ip, name):
        # Here we call ipython ip to avoid conflict with the ipython file
        self.ip = ip
        self.name = name
        if self.name in self.ip.shell.user_ns:
            aut = self.ip.shell.user_ns[self.name].strip()
            states, transitions, _ = self._d3_of_aut(aut)
            self.context = aut.context()
        # Here Add the conversion from vcsn to d3 datas
        else:
            states = [{'id': 0}]
            transitions = [{'source': '0', 'label': ''},
                           {'target': '0', 'label': ''}]
            self.context = vcsn.context('lal(a-z), b')

        aut = AutomatonD3Widget(states=states, transitions=transitions)#, context=self.context)
        self.error = widgets.HTML(value='')

        self._widget_ctx = vcsn.ipython.ContextText(self, self.context)
        self._widget_ctx.text.observe(self._on_change, 'value')

        self._widget = aut
        self._widget.observe(self._on_change, ['states','transitions'])
コード例 #13
0
    def update(self, *_):
        # Abort asynchronous updates.
        self.updater.abort()
        self.err.value = ''
        self.out.clear_output()
        try:
            cont = self.ctx.getvalue()
            text = self.exp.getvalue()
            algo = self.algo.value
            idt = self.ids.value

            ctx = vcsn.context(cont)
            exp = ctx.expression(text, idt)
            aut = exp.automaton(algo=algo)

            self.exp.latex.value = exp._repr_latex_()
            # There is currently no official documentation on this,
            # so please check out `ipywidgets.Output`'s docstring.
            with self.out:
                aut._display(self.mode.value, self.engine.value)
            self.ipython.shell.user_ns[self.name] = exp
        except RuntimeError as e:
            self.exp.latex.value = ''
            self.err.value = formatError(e)
コード例 #14
0
ファイル: add.py プロジェクト: Prateeba/Mini_memoire
#! /usr/bin/env python

import vcsn
from itertools import product
from test import *

## ----------------------- ##
## automaton + automaton.  ##
## ----------------------- ##


def std(ctx, exp):
    return vcsn.context(ctx).expression(exp).standard()


ctxbr = vcsn.context('lal_char(a), expressionset<lal_char(uv), b>')
ctxz = vcsn.context('lal_char(b), z')
ctxq = vcsn.context('lal_char(c), q')
ctxr = vcsn.context('lal_char(d), r')

ab = std('lal_char(ab), b', '(a+b)*')
bc = std('lal_char(bc), b', '(b+c)*')
CHECK_EQ(metext('ab+bc.gv'), ab.add(bc))

CHECK_EQ(metext('a1+b1.gv'), meaut('a1.gv').add(meaut('b1.gv')))

# Check join of contexts.
a = std('lal_char(a), expressionset<lal_char(x), b>', '<x>a*')
b = std('lal_char(b), q', '<1/2>b*')
CHECK_EQ(metext('join.gv'), a.add(b))
コード例 #15
0
check_aut(load('lal_char_z/b1.gv'), '(a+b)*a(a+b)*')
check_aut(load('lal_char_z/binary.gv'), '(0+1)*1(<2>0+<2>1)*')
check_aut(load('lal_char_z/c1.gv'), '(a+b)*b(<2>a+<2>b)*')
check_aut(load('lal_char_z/d1.gv'), '(a+b)*(a+<-1>b)(a+b)*')

check_aut(load('lal_char_zmin/minab.gv'), '(a+<1>b)*+(<1>a+b)*')
check_aut(load('lal_char_zmin/minblocka.gv'), '(a+b)*b(<1>a)*b(a+b)*')
check_aut(load('lal_char_zmin/slowgrow.gv'), '(a+b)*b(<1>a+<1>(ba*a))*ba*')
check_aut(load('lal_char_zmin/slowgrow.gv'),
          '(a+b)*b(<1>a)*b(a+<1>(a(<1>a)*b))*', 'naive')

## ------------------------------------ ##
## expression.standard().expression().  ##
## ------------------------------------ ##

ctx = vcsn.context("lal_char(abc), b")


# check_exp RAT [EXP-OUT = RAT]
# -----------------------------
# Check that to-expression(standard(RAT)) = EXP-OUT.
def check_exp(rat, exp=None):
    if exp is None:
        exp = rat
    check_aut(ctx.expression(rat).standard(), exp)


check_exp('a')
check_exp('ab')
check_exp('a*', r'\e+aa*')
check_exp('a+b')
コード例 #16
0
    # Laziness.
    if algo != "boolean" and not aut.is_empty():
        CHECK_NE(exp, aut.determinize(algo, lazy=True))
        CHECK_EQ(exp, aut.determinize(algo, lazy=True).accessible())

    # Codeterminization.
    codet = aut.transpose().strip().determinize().transpose().strip()
    CHECK_EQ(aut.codeterminize(), codet)
    CHECK(codet.is_codeterministic())


## -------------------- ##
## de bruijn/ladybird.  ##
## -------------------- ##

ctx = vcsn.context('lal_char(ab), b')
check(ctx.de_bruijn(3), 'de-bruijn-3')
check(ctx.de_bruijn(8), 'de-bruijn-8')

ctx = vcsn.context('lal_char(abc), b')
check(ctx.ladybird(4), 'ladybird-4')
check(ctx.ladybird(8), 'ladybird-8')

## ------------------------------- ##
## Simple deterministic automata.  ##
## ------------------------------- ##

for name in ['deterministic', 'empty', 'epsilon']:
    aut = meaut(name, 'gv')
    check(aut, name, deterministic=True)
    check(aut, name, deterministic=True, algo='weighted')
コード例 #17
0
ファイル: rat.py プロジェクト: pombredanne/vcsn
def context_update():
    global context, ctx  # pylint: disable=global-statement
    if context in contexts:
        context = contexts[context]
    ctx = vcsn.context(context)
    print("# context: {} ({})".format(context, ctx))
コード例 #18
0
ファイル: rat.py プロジェクト: pombredanne/vcsn
#! /usr/bin/env python

import os
import re
import sys
import vcsn

# Pylint makes the difference between local and global packages.
# Unfortunately "vcsn" is local in check and global in installcheck.
from test import *  # pylint: disable=wrong-import-order

# The name of the current context.
context = 'lal_char(abcd), b'
# The current context.
ctx = vcsn.context(context)
# Whether expressions or series.
identities = "associative"

# Compute the name of the context.
contexts = {
    'b':
    "law_char(a-h), b",
    'br':
    "law_char(a-h), expressionset<law_char(i-n), b>",
    'brr':
    "law_char(a-h), expressionset<law_char(i-n), expressionset<law_char(w-z), b>>",
    'q':
    "law_char(a-h), q",
    'qr':
    "law_char(a-h), expressionset<law_char(i-n), q>",
    'qrr':
コード例 #19
0
ファイル: zpc.py プロジェクト: Prateeba/Mini_memoire
#! /usr/bin/env python

import vcsn
from test import *

ctx_string = 'nullableset<letterset<char_letters(abc)>>, seriesset<letterset<char_letters(xyz)>, q>'

ctx = vcsn.context(ctx_string)


def check(exp, daut, v='auto'):
    # It compares automata as strings, then if zpc is isomorphic to standard.
    # At last it tests if it is epsilon acyclic.
    print("Check: {}.zpc({})".format(exp, v))
    e = ctx.expression(exp)
    zpc = e.zpc(v)
    std = e.standard()
    print(e)
    print('Check if zpc\'s daut expected format is correct.')
    CHECK_EQ(daut, zpc.format('daut'))
    print('Check if zpc is epsilon acyclic.')
    CHECK_IS_EPS_ACYCLIC(zpc)
    zpt = zpc.trim()
    if not zpt.is_empty():
        print('Check if trim and proper zpc is isomorphic to standard.')
        CHECK_ISOMORPHIC(zpt.proper(), std)


def xfail(re, err=None):
    r = ctx.expression(re)
    XFAIL(lambda: r.zpc(), err)
コード例 #20
0
ファイル: power.py プロジェクト: Prateeba/Mini_memoire
#! /usr/bin/env python

import vcsn
from test import *

z = vcsn.context('lal_char(01), z')

binary = load('lal_char_z/binary.gv')

# power 0.
CHECK_EQ(meaut('binary^0.gv'), binary & 0)

# power 1.
CHECK_EQ(meaut('binary^1.gv'), binary & 1)

# power 4.
binary4 = binary & 4
# 0^4 = 0.
CHECK_EQ(z.weight('0'), binary4('0'))
# 1^4 = 1.
CHECK_EQ(z.weight('1'), binary4('1'))
# 4^4 = 256.
CHECK_EQ(z.weight('256'), binary4('100'))

# Power 5.
binary5 = binary & 5
CHECK_EQ(z.weight('32'), binary5('10'))
#run 0 '' -vcsn power -o binary^5.gv -f $binary_gv 5
#run 0 32 -vcsn evaluate -f binary^5.gv 10

# Power 7.
コード例 #21
0
#! /usr/bin/env python

import vcsn
from test import *

## ---------- ##
## Automata.  ##
## ---------- ##

l4 = vcsn.context('lal_char(abc), b').ladybird(4)
CHECK_EQ(
    '''digraph
{
  vcsn_context = "lao, expressionset<letterset<char_letters(abc)>, b>"
  rankdir = LR
  edge [arrowhead = vee, arrowsize = .6]
  {
    node [shape = point, width = 0]
    I0
    F0
  }
  {
    node [shape = circle, style = rounded, width = 0.5]
    0
    1
    2
    3
  }
  I0 -> 0
  0 -> F0
  0 -> 1 [label = "<a>"]
コード例 #22
0
ファイル: add.py プロジェクト: Prateeba/Mini_memoire
def std(ctx, exp):
    return vcsn.context(ctx).expression(exp).standard()
コード例 #23
0
ファイル: minimize.py プロジェクト: Prateeba/Mini_memoire
check('brzozowski', a, z)
xfail('moore', a)
xfail('signature', a)
xfail('weighted', a)

## An automaton equal to redundant.exp, with no final states.  It must
## be minimized into an empty automaton.
a = meaut('no-final-states.gv')
check('brzozowski', a, z)
xfail('moore', a)
xfail('signature', a)
xfail('weighted', a)

## Non-regression testcase: ensure that moore works and produces a
## correct result even with no non-final states.
all_states_final = vcsn.context('lal_char(a), b').expression('a*').standard()
check('moore', all_states_final, all_states_final.minimize('signature'))

## Minimize an intricate automaton into a linear one.
a = vcsn.context('lal_char(a-k), b') \
        .expression('[a-k]{10}') \
        .standard()
exp = metext('intricate.exp.gv')
check('brzozowski', a, vcsn.automaton(exp))
check(algos, a, exp)

## Compute the quotient of a non-deterministic automaton, in this case
## yielding the minimal deterministic solution.
a = vcsn.context('lal_char(a), b') \
        .expression('a{2}*+a{2}*', 'trivial') \
        .standard()
コード例 #24
0
        gen = lhs.multiply(rhs, "general")

        print("deterministic")
        det = lhs.multiply(rhs, "deterministic")
        CHECK(det.is_deterministic(), det, "is deterministic")
        CHECK_EQUIV(gen, det)

        print("standard")
        std = lhs.multiply(rhs, "standard")
        if (lhs.is_standard() and
            (not isinstance(rhs, vcsn.automaton) or rhs.is_standard())):
            CHECK(std.is_standard(), std, " is standard")
        CHECK_EQUIV(gen, std)


ctx = vcsn.context('lal_char, q')
auts = [
    ctx.expression('a').standard(),
    ctx.expression('ab').standard(),
    ctx.expression('a+b').standard(),
    ctx.expression('a<2>', identities='none').standard()
]
check_mult(auts, [1, 3, (-1, 5), (2, 4), (2, -1)])

# We want the determinization to terminate.
ctx = vcsn.context('lal_char, b')
auts = [
    auts,
    ctx.expression('a(ba)*').automaton('derived_term'),
    ctx.expression('a+b').derived_term(breaking=True),
    ctx.expression('a*').derived_term()
コード例 #25
0
ファイル: proper.py プロジェクト: Prateeba/Mini_memoire
    0
    1
    2
  }
  I0 -> 0
  0 -> 1 [label = "(a,x)"]
  0 -> 2 [label = "(b,y)"]
  1 -> F1
  1 -> 2 [label = "(\\e,y)"]
  2 -> F2
}''')

## ------------------------- ##
## lan, polynomial<law, q>.  ##
## ------------------------- ##

check(metext('lan-poly.1.in.gv'), metext('lan-poly.1.out.gv'))
check_fail(metext('lan-poly.2.fail.gv'))
check_fail(metext('lan-poly.3.fail.gv'))

## ---------------------- ##
## Forward vs. backward.  ##
## ---------------------- ##

a = vcsn.context('lan_char(ab), b').expression('a*').thompson()
for algo in algos:
    for dir in ['backward', 'forward']:
        CHECK_EQ(
            meaut('astar-' + dir, 'gv').sort().strip(),
            a.proper(direction=dir, algo=algo).sort().strip())
コード例 #26
0
ファイル: star.py プロジェクト: Prateeba/Mini_memoire
        print("deterministic")
        det = input.star("deterministic")
        CHECK(det.is_deterministic(), det, "is_deterministic")
        CHECK_EQUIV(gen, det)


def check(input, exp):
    if isinstance(input, str):
        input = vcsn.automaton(input)
    if isinstance(exp, str):
        exp = vcsn.automaton(exp)
    CHECK_EQ(exp, input.star())
    check_algo(input)


ctx = vcsn.context('lal_char, q')

check_algo('a')
check_algo('ab')
check_algo('a+b')
check_algo(ctx.expression('a<2>', 'none'))
check_algo('<1/2>a*+<1/3>b*')

# This used to trigger an assert.
l_br = vcsn.context('lal_char(a), expressionset<lal_char(xy), b>')
check(
    l_br.expression('<y>a(<x>a)*').automaton('derived_term'), '''
digraph
{
  vcsn_context = "lal_char(a), expressionset<lal_char(xy), b>"
  rankdir = LR
コード例 #27
0
#! /usr/bin/env python

from re import match
import vcsn
from test import *

c = vcsn.context("lal_char(abc), expressionset<lal_char(xyz), q>")


def check(re, exp):
    '''Check that d(re) = exp.  Also check that both derived_term
    algorithms (`derivation` and `expansion`) compute the same result.
    '''
    if not isinstance(re, vcsn.expression):
        re = c.expression(re)
    eff = re.expansion()
    print("d: {:u} => {:u}".format(re, eff))
    CHECK_EQ(exp, str(eff))
    # Make sure we terminate.
    aut = re.automaton("expansion")
    # Check that if derived_term can do it, then it's the same
    # automaton.
    if match('^[^,]*wordset', re.context().format('sname')):
        XFAIL(
            lambda: re.automaton("derivation"),
            'derived_term: cannot use derivation on non-letterized labelsets')
    elif re.info('ldivide'):
        XFAIL(lambda: re.automaton("derivation"),
              'operator ldivide not supported')
    elif re.info('transposition'):
        XFAIL(lambda: re.automaton("derivation"),
コード例 #28
0
ファイル: infiltrate.py プロジェクト: Prateeba/Mini_memoire
#! /usr/bin/env python

import vcsn
from test import *

z = vcsn.context('lal_char(abcd), z')

set_medir(srcdir + '/tests/python/conjunction.dir')

## ---------------------- ##
## Existing transitions.  ##
## ---------------------- ##

# See the actual code of product to understand the point of this test
# (which is new_transition vs. add_transition).
a1 = z.expression('a*a').automaton()
CHECK_EQ('(<3>a)*(a+<4>(aa*a))', str(a1.infiltrate(a1).expression()))

## -------------------- ##
## Hand crafted tests.  ##
## -------------------- ##

# a infiltrate a
a = meaut("a.gv")
CHECK_EQ('''digraph
{
  vcsn_context = "letterset<char_letters(a)>, z"
  rankdir = LR
  edge [arrowhead = vee, arrowsize = .6]
  {
    node [shape = point, width = 0]
コード例 #29
0
ファイル: project.py プロジェクト: Prateeba/Mini_memoire
#! /usr/bin/env python

import vcsn
from test import *

# Tests are sorted per dependency: dependant types come after needed
# ones.


# Nullable labelsets to please expansions.
c = vcsn.context('lat<lan(abc), lan(efg), lan(xyz)>, q')

def check(v, *p):
    for i in range(3):
        CHECK_EQ(p[i], v.project(i))


## ---------- ##
## contexts.  ##
## ---------- ##

check(c,
      '{abc}? -> Q',
      '{efg}? -> Q',
      '{xyz}? -> Q')


## ------- ##
## label.  ##
## ------- ##
コード例 #30
0
#! /usr/bin/env python

import vcsn
from test import *

# We are checking the support for quotients, which requires the label
# one.
ctx = vcsn.context('lan, expressionset<lal, q>')
cexp = ctx.expression


# check INPUT [RESULT = INPUT]
# ----------------------------
# Check that the splitting of INPUT is RESULT.
def check(e, exp=None):
    if exp is None:
        exp = e
    if not isinstance(e, vcsn.expression):
        e = cexp(e)
    p = e.split()
    CHECK_EQ(exp, p)
    # The polynomial, turned into an expression, and the input
    # expression are equivalent.
    CHECK_EQUIV(cexp(str(p)), e)
    # Splitting polynomials is idempotent.
    CHECK_EQ(p, p.split())


check(r'\z')
check(r'<x>\e')
check('<x>a')