Commit 70b9f903 authored by Akim Demaille's avatar Akim Demaille
Browse files

python: enhance automaton constructor to load from files

Well, it took me a while to figure out the proper use of Boost.Python
(these pages were useful:
http://stackoverflow.com/questions/16660049/,
http://www.boost.org/doc/libs/1_55_0/libs/python/doc/v2/init.html),
but it does work.

* python/vcsn_cxx.cc (automaton): Support automaton(filename = ...).
* python/vcsn/automaton.py (automaton.load): Remove.
Adjust dependencies.
parent 2100f3cc
......@@ -7,6 +7,13 @@ changes in the internal API may also be documented.
## 2014-10-20
### Python: loading automata from files
The `vcsn.automaton` constructor now support a `filename` named argument
to load an automaton from a file.
vcsn.automaton(filename = 'a.gv')
vcsn.automaton(filename = 'a.efsm', format = 'efsm')
### minimize: default algorithm is "auto"
Now minimize and cominimize both support the "auto" algorithm, which is
the default value. It uses the "signature" algorithm for the Boolean
......
......@@ -65,12 +65,15 @@ def _automaton_display(self, mode, engine = "dot"):
# the original, C++ based, implementation of __init__ as _init,
# and then provide a new __init__.
automaton._init = automaton.__init__
def _automaton_init(self, text, fmt = "dot"):
if fmt == "daut":
self._init(to_dot(text), "dot")
def _automaton_init(self, data = '', format = '', filename = ''):
if format == "daut":
if filename:
data = open(filename).read()
data = to_dot(data)
self._init(data = data, format = 'dot')
else:
self._init(text, fmt)
automaton.__init__ = lambda *args: _automaton_init(*args)
self._init(data = data, format = format, filename = filename)
automaton.__init__ = _automaton_init
def _automaton_interact(self):
'''Display automaton `self` with a local menu to the select
......@@ -187,10 +190,6 @@ def _lan_to_lal(a):
return automaton(dot, 'dot')
automaton.lan_to_lal = _lan_to_lal
def _automaton_load(file, format = "dot"):
return automaton(open(file, "r").read(), format)
automaton.load = staticmethod(_automaton_load)
# Somewhat cheating: in Python, proper returns a LAL, not a LAN.
# _proper is the genuine binding to dyn::proper.
def _automaton_proper(self, *args, **kwargs):
......
......@@ -91,12 +91,20 @@ struct automaton
automaton(const ratexp& r);
automaton(const std::string& s, const std::string& format = "default")
{
std::istringstream is(s);
val_ = vcsn::dyn::read_automaton(is, format);
if (is.peek() != -1)
vcsn::fail_reading(is, "unexpected trailing characters");
automaton(const std::string& data = "",
const std::string& format = "default",
const std::string& filename = "")
{
std::shared_ptr<std::istream> is;
if (!data.empty())
is = std::make_shared<std::istringstream>(data);
else if (!filename.empty())
is = vcsn::open_input_file(filename);
else
throw "cannot provide both data and filename";
val_ = vcsn::dyn::read_automaton(*is, format);
if (is->peek() != -1)
vcsn::fail_reading(*is, "unexpected trailing characters");
}
automaton accessible() const
......@@ -936,8 +944,8 @@ BOOST_PYTHON_MODULE(vcsn_cxx)
bp::class_<automaton>
("automaton",
bp::init<const ratexp&>())
.def(bp::init<const std::string&, bp::optional<const std::string&>>())
.def(bp::init<const std::string&, const std::string&, const std::string&>
((arg("data") = "", arg("format") = "default", arg("filename") = "")))
.def("accessible", &automaton::accessible)
.def("ambiguous_word", &automaton::ambiguous_word)
.def("blind", &automaton::blind)
......
......@@ -70,7 +70,7 @@ def rst_diff(expected, effective):
def load(fname):
"Load the library automaton file `fname`."
import vcsn
return vcsn.automaton.load(vcsn.datadir + "/" + fname)
return vcsn.automaton(filename = vcsn.datadir + "/" + fname)
def here():
# Find the top-level call.
......
......@@ -390,7 +390,7 @@ CHECK_EQ('''digraph
import glob
for fn in glob.glob(os.path.join(medir, '*.in.gv')):
print(fn)
a = vcsn.automaton.load(fn)
a = vcsn.automaton(filename = fn)
exp = open(fn.replace('.in.gv', '.out.gv')).read().strip()
CHECK_EQ(exp, a.format('dot'))
......@@ -414,7 +414,7 @@ CHECK_EQ(exp, a.format('tikz'))
from vcsn.dot import to_dot, from_dot
for fn in glob.glob(os.path.join(medir, '*.in.gv')):
a = vcsn.automaton.load(fn)
a = vcsn.automaton(filename = fn)
# Check output.
daut = a.format('daut')
......@@ -449,8 +449,8 @@ def check_fado(aut):
SKIP("FAdo not installed")
for fn in glob.glob(os.path.join(medir, '*.fado')):
a = vcsn.automaton.load(fn, 'fado')
exp = vcsn.automaton.load(fn.replace('.fado', '.gv'))
a = vcsn.automaton(filename = fn, format = 'fado')
exp = vcsn.automaton(filename = fn.replace('.fado', '.gv'))
# Check that we can read FAdo.
CHECK_EQ(exp, a)
......@@ -477,7 +477,7 @@ def check_grail(aut):
SKIP("FAdo not installed")
for fn in glob.glob(os.path.join(medir, '*.grail')):
a = vcsn.automaton.load(fn.replace('.grail', '.gv'))
a = vcsn.automaton(filename = fn.replace('.grail', '.gv'))
# Check that we can print Grail.
grail = open(fn).read().strip()
CHECK_EQ(grail, a.format('grail'))
......
......@@ -196,6 +196,6 @@ check(c_r.ratexp("<3.1>'(a, x)'").standard(), c2.ratexp("'(x, d)'").standard(),
## Fibonacci normalizer ##
##########################
check(vcsn.automaton.load(medir + "/left.gv"),
vcsn.automaton.load(medir + "/right.gv"),
check(vcsn.automaton(filename = medir + "/left.gv"),
vcsn.automaton(filename = medir + "/right.gv"),
open(medir + "/result.gv").read().strip())
......@@ -54,7 +54,7 @@ a = load('lal_char_z/binary.gv')
check(a, 'binary.efsm')
for f in ["lal-char-z", "lat-z"]:
a = vcsn.automaton.load(medir + "/" + f + '.gv')
a = vcsn.automaton(filename = medir + "/" + f + '.gv')
check(a, f + '.efsm')
# Check the case of an automaton without any transition.
......
......@@ -4,7 +4,7 @@ import vcsn
from test import *
# Eliminate state 0, or 1, or 2.
a = vcsn.automaton.load(medir + '/lao.gv')
a = vcsn.automaton(filename = medir + '/lao.gv')
for i in [0, 1, 2]:
CHECK_EQ(open(medir + '/lao-elim-{}.gv'.format(i)).read().strip(),
str(a.eliminate_state(i)))
......@@ -11,17 +11,17 @@ from test import *
a = vcsn.context('lal_char(abc)_b').cerny(6)
CHECK_EQ(a.info()['number of states'], 6)
CHECK_EQ(vcsn.automaton.load(medir + '/cerny-6.gv'), a)
CHECK_EQ(vcsn.automaton(filename = medir + '/cerny-6.gv'), a)
## ----------- ##
## de_bruijn. ##
## ----------- ##
CHECK_EQ(vcsn.automaton.load(medir + '/de-bruijn-2.gv'),
CHECK_EQ(vcsn.automaton(filename = medir + '/de-bruijn-2.gv'),
vcsn.context('lal_char(ab)_b').de_bruijn(2))
CHECK_EQ(vcsn.automaton.load(medir + '/de-bruijn-3.gv'),
CHECK_EQ(vcsn.automaton(filename = medir + '/de-bruijn-3.gv'),
vcsn.context('lal_char(xyz)_b').de_bruijn(3))
## ----------- ##
......@@ -61,10 +61,10 @@ digraph
'''))
CHECK_EQ(ctx.double_ring(1, [0]),
vcsn.automaton.load(medir + '/double-ring-1-0.gv'))
vcsn.automaton(filename = medir + '/double-ring-1-0.gv'))
CHECK_EQ(ctx.double_ring(4, [2, 3]),
vcsn.automaton.load(medir + '/double-ring-4-2-3.gv'))
vcsn.automaton(filename = medir + '/double-ring-4-2-3.gv'))
## ---------- ##
......@@ -74,12 +74,12 @@ vcsn.automaton.load(medir + '/double-ring-4-2-3.gv'))
b = vcsn.context('lal_char(abc)_b')
z = vcsn.context('lal_char(abc)_z')
exp = vcsn.automaton.load(medir + '/ladybird-2.gv')
exp = vcsn.automaton(filename = medir + '/ladybird-2.gv')
CHECK_EQ(exp, b.ladybird(2))
CHECK_EQ(vcsn.automaton(str(exp).replace('_b', '_z')), z.ladybird(2))
exp = vcsn.automaton.load(medir + '/ladybird-2-zmin.gv')
exp = vcsn.automaton(filename = medir + '/ladybird-2-zmin.gv')
CHECK_EQ(exp,
vcsn.context('lal_char(abc)_zmin').ladybird(2))
......@@ -90,7 +90,7 @@ CHECK_EQ(exp,
# Expect a clique.
c1 = vcsn.context('lal_char(a)_b').random(4, 1, 4, 4)
c2 = vcsn.automaton.load(medir + '/clique-a-4.gv')
c2 = vcsn.automaton(filename = medir + '/clique-a-4.gv')
CHECK_EQ(c1, c2)
# Expect the right number of states.
......@@ -117,5 +117,5 @@ CHECK_EQ(a.is_complete(), True)
## u. ##
## --- ##
CHECK_EQ(vcsn.automaton.load(medir + '/u-5.gv'),
CHECK_EQ(vcsn.automaton(filename = medir + '/u-5.gv'),
vcsn.context('lal_char(abc)_b').u(5))
......@@ -22,7 +22,7 @@ a1 = b.ratexp('a*a').derived_term()
## -------------------- ##
# a infiltration a
a = vcsn.automaton.load(medir + "/a.gv")
a = vcsn.automaton(filename = medir + "/a.gv")
CHECK_EQ('''digraph
{
vcsn_context = "lal_char(a)_z"
......@@ -50,7 +50,7 @@ CHECK_EQ('''digraph
}''', a.infiltration(a))
# abc infiltration abc
abc = vcsn.automaton.load(medir + "/abc.gv")
abc = vcsn.automaton(filename = medir + "/abc.gv")
CHECK_EQ('''digraph
{
vcsn_context = "lal_char(abc)_z"
......@@ -112,7 +112,7 @@ CHECK_EQ('''digraph
}''', abc.infiltration(abc))
# abc infiltration xy
xy = vcsn.automaton.load(medir + "/xy.gv")
xy = vcsn.automaton(filename = medir + "/xy.gv")
CHECK_EQ('''digraph
{
vcsn_context = "lal_char(abcxy)_z"
......
......@@ -5,7 +5,7 @@ import vcsn
from test import *
def aut(file):
return vcsn.automaton.load(medir + "/" + file)
return vcsn.automaton(filename = medir + "/" + file)
def file_to_string(file):
return open(medir + "/" + file, "r").read().strip()
......
......@@ -10,11 +10,11 @@ z = vcsn.context('lal_char(01)_z')
binary = load('lal_char_z/binary.gv')
# power 0.
CHECK_EQ(vcsn.automaton.load(medir + '/binary^0.gv'),
CHECK_EQ(vcsn.automaton(filename = medir + '/binary^0.gv'),
binary ** 0)
# power 1.
CHECK_EQ(vcsn.automaton.load(medir + '/binary^1.gv'),
CHECK_EQ(vcsn.automaton(filename = medir + '/binary^1.gv'),
binary ** 1)
# power 4.
......
......@@ -14,7 +14,7 @@ def check_aut(aut, exp):
CHECK_EQ(exp, str(aut.ratexp()))
# Check the associativity of the product.
check_aut(vcsn.automaton.load(medir + "/a.gv"), '<x>a(<y>b)*<z>c')
check_aut(vcsn.automaton(filename = medir + "/a.gv"), '<x>a(<y>b)*<z>c')
check_aut(load('lal_char_b/a1.gv'), '(a+b)*ab(a+b)*')
check_aut(load('lal_char_b/b1.gv'), '(a+b)*a(a+b)*')
......
......@@ -5,7 +5,7 @@ from test import *
ab = vcsn.context('lal_char(ab)_b').ratexp('(a+b)*').standard()
bc = vcsn.context('lal_char(bc)_b').ratexp('(b+c)*').standard()
CHECK_EQ(vcsn.automaton.load(medir + '/abc.gv'), ab | bc)
CHECK_EQ(vcsn.automaton(filename = medir + '/abc.gv'), ab | bc)
## ------------ ##
## lal_char_z. ##
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment