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'))
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)
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())
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
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)
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)
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)
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))
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))
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())
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)
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'])
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)
#! /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))
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')
# 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')
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))
#! /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':
#! /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)
#! /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.
#! /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>"]
def std(ctx, exp): return vcsn.context(ctx).expression(exp).standard()
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()
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()
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())
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
#! /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"),
#! /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]
#! /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. ## ## ------- ##
#! /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')