Commit 7a75bb3a authored by Akim Demaille's avatar Akim Demaille
Browse files

tuple: use it in inductive

See #44 and #57.

* vcsn/core/automatonset.hh, vcsn/algos/inductive.hh: Support tuple.
(complement): We don't know how to complement on a multitape automata,
so disable for the time being.
* tests/python/standard.py: Check it.
* bin/vcsn.in, libexec/vcsn-tafkit.cc (inductive): Bind it.
* tests/bin/test.py (can_check_equivalence): We can't on tuples.
parent 01e9071b
......@@ -64,12 +64,12 @@ TAF-Kit program:
accessible are-equivalent are-isomorphic cat coaccessible complement
complete compose constant-term conjunction derivation derived-term
de-bruijn divkbaseb determinize difference divkbaseb double-ring
eliminate-state enumerate evaluate expand infiltration is-ambiguous
is-complete is-deterministic is-empty is-eps-acyclic is-normalized
is-proper is-standard is-trim is-useless is-valid ladybird left-mult
lift minimize multiply proper quotkbaseb right-mult shortest shuffle split
standard star star-normal-form sum thompson to-expression transpose
trim u union universal
eliminate-state enumerate evaluate expand inductive infiltration
is-ambiguous is-complete is-deterministic is-empty is-eps-acyclic
is-normalized is-proper is-standard is-trim is-useless is-valid
ladybird left-mult lift minimize multiply proper quotkbaseb
right-mult shortest shuffle split standard star star-normal-form sum
thompson to-expression transpose trim u union universal
For more information, run:
......
......@@ -128,6 +128,7 @@ DEFINE_EXP_FUNCTION(constant_term);
DEFINE_AUT_VARIADIC_FUNCTION(difference);
DEFINE_INT_INT_FUNCTION(divkbaseb);
DEFINE_EXP_FUNCTION(expand);
DEFINE_EXP_FUNCTION(inductive);
DEFINE_AUT_VARIADIC_FUNCTION(infiltration);
DEFINE_AUT_FUNCTION(is_ambiguous);
DEFINE_AUT_FUNCTION(is_complete);
......@@ -650,6 +651,7 @@ try
ALGO(eliminate_state);
ALGO(evaluate);
ALGO(expand);
ALGO(inductive);
ALGO(infiltration);
ALGO(is_ambiguous);
ALGO(is_complete);
......@@ -681,10 +683,10 @@ try
if (f)
return vcsn_main(argc - 1, argv + 1, *f);
}
vcsn::raise("unknown command: " + cmd);
vcsn::raise("unknown command: ", cmd);
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}
......@@ -206,8 +206,16 @@ def normalize(a):
def can_test_equivalence(a):
ctx = a.context().format('sname')
expressionset_ws = re.match('.*expressionset<.*>', ctx) is None
return not(ctx.endswith('min')) and expressionset_ws
# Cannot check on Zmin and the like.
if ctx.endswith('min'):
return False
# Cannot check on expressionset as weightset.
if 'expressionset<' in ctx:
return False
# Cannot check equivalence on labelset.
if 'lat<' in ctx:
return False
return True
def CHECK_EQUIV(a1, a2):
......
......@@ -275,6 +275,9 @@ EXTRA_DIST += \
%D%/standard.dir/rdiv-1.gv \
%D%/standard.dir/shuffle-1.gv \
%D%/standard.dir/transposition-1.gv \
%D%/standard.dir/tuple-1.gv \
%D%/standard.dir/tuple-2.gv \
%D%/standard.dir/tuple-3.gv \
%D%/synchronize.dir/bool.gv \
%D%/synchronize.dir/bool_delay.gv \
%D%/synchronize.dir/bool_min.gv \
......
digraph
{
vcsn_context = "lat<nullableset<letterset<char_letters(abc)>>, nullableset<letterset<char_letters(xyz)>>>, q"
rankdir = LR
edge [arrowhead = vee, arrowsize = .6]
{
node [shape = point, width = 0]
I0
F3
}
{
node [shape = circle, style = rounded, width = 0.5]
0
1
2
3
}
I0 -> 0
0 -> 1 [label = "a|x"]
1 -> 2 [label = "b|y"]
2 -> 3 [label = "c|z"]
3 -> F3
}
digraph
{
vcsn_context = "lat<nullableset<letterset<char_letters(abc)>>, nullableset<letterset<char_letters(xy)>>>, q"
rankdir = LR
edge [arrowhead = vee, arrowsize = .6]
{
node [shape = point, width = 0]
I0
F3
}
{
node [shape = circle, style = rounded, width = 0.5]
0
1
2
3
}
I0 -> 0
0 -> 1 [label = "a|x"]
1 -> 2 [label = "b|y"]
2 -> 3 [label = "c|\\e"]
3 -> F3
}
digraph
{
vcsn_context = "lat<nullableset<letterset<char_letters(ab)>>, nullableset<letterset<char_letters(cd)>>, nullableset<letterset<char_letters(ef)>>>, q"
rankdir = LR
edge [arrowhead = vee, arrowsize = .6]
{
node [shape = point, width = 0]
I0
F1
F2
F3
F4
F5
F6
F7
F8
}
{
node [shape = circle, style = rounded, width = 0.5]
0
1
2
3
4
5
6
7
8
}
I0 -> 0
0 -> 1 [label = "a|c|e"]
1 -> F1
1 -> 2 [label = "b|d|f"]
1 -> 3 [label = "b|d|\\e"]
1 -> 4 [label = "b|\\e|f"]
1 -> 5 [label = "b|\\e|\\e"]
1 -> 6 [label = "\\e|d|f"]
1 -> 7 [label = "\\e|d|\\e"]
1 -> 8 [label = "\\e|\\e|f"]
2 -> F2
2 -> 2 [label = "b|d|f"]
2 -> 3 [label = "b|d|\\e"]
2 -> 4 [label = "b|\\e|f"]
2 -> 5 [label = "b|\\e|\\e"]
2 -> 6 [label = "\\e|d|f"]
2 -> 7 [label = "\\e|d|\\e"]
2 -> 8 [label = "\\e|\\e|f"]
3 -> F3
3 -> 3 [label = "b|d|\\e"]
3 -> 5 [label = "b|\\e|\\e"]
3 -> 7 [label = "\\e|d|\\e"]
4 -> F4
4 -> 4 [label = "b|\\e|f"]
4 -> 5 [label = "b|\\e|\\e"]
4 -> 8 [label = "\\e|\\e|f"]
5 -> F5
5 -> 5 [label = "b|\\e|\\e"]
6 -> F6
6 -> 6 [label = "\\e|d|f"]
6 -> 7 [label = "\\e|d|\\e"]
6 -> 8 [label = "\\e|\\e|f"]
7 -> F7
7 -> 7 [label = "\\e|d|\\e"]
8 -> F8
8 -> 8 [label = "\\e|\\e|f"]
}
......@@ -973,3 +973,11 @@ check(qexp('abcd & (dcba){T}'), file='transposition-1')
# Left and right divisions.
check(qexp('<2>abc {\} <4>abcd*'), file='ldiv-1')
check(qexp('<4>a*bcd {/} <2>bcd'), file='rdiv-1')
# Tupling.
def tuple(*exps):
return vcsn.expression._tuple([vcsn.context('lan, q').expression(e)
for e in exps])
check(tuple('abc', 'xyz'), file='tuple-1')
check(tuple('abc', 'xy'), file='tuple-2')
check(tuple('ab*', 'cd*', 'ef*'), file='tuple-3')
#pragma once
#include <set>
#include <vcsn/core/rat/visitor.hh>
#include <vcsn/core/automatonset.hh>
#include <vcsn/dyn/automaton.hh>
......@@ -14,6 +12,16 @@ namespace vcsn
| inductive(expression). |
`-------------------------*/
/// Build a inductive automaton from an expression.
///
/// \tparam Aut the type of the generated automaton.
/// \tparam ExpSet the expressionset.
/// \tparam Tag the nature of the operations (standard_tag, etc.).
template <Automaton Aut, typename ExpSet, typename Tag>
Aut
inductive(const ExpSet& rs, const typename ExpSet::value_t& r,
Tag = {});
namespace rat
{
/// Build an automaton by induction from an expression.
......@@ -29,7 +37,9 @@ namespace vcsn
using automaton_t = Aut;
using expressionset_t = ExpSet;
using tag_t = Tag;
using self_t = inductive_visitor;
using context_t = context_t_of<expressionset_t>;
using automatonset_t = automatonset<context_t_of<automaton_t>, tag_t>;
using expression_t = typename expressionset_t::value_t;
using weightset_t = weightset_t_of<expressionset_t>;
......@@ -42,7 +52,8 @@ namespace vcsn
constexpr static const char* me() { return "inductive"; }
inductive_visitor(const expressionset_t& rs)
: as_{automatonset_t{rs.context()}}
: rs_{rs}
, as_{rs_.context()}
{}
automaton_t operator()(const expression_t& v)
......@@ -59,9 +70,50 @@ namespace vcsn
}
using tuple_t = typename super_t::tuple_t;
virtual void visit(const tuple_t&, std::true_type) override
template <bool = context_t::is_lat,
typename Dummy = void>
struct visit_tuple
{
/// One tape.
template <size_t I>
auto tape_(const tuple_t& v)
{
const auto& rs = project<I>(visitor_.rs_);
using automaton_t =
vcsn::mutable_automaton<context_t_of<decltype(rs)>>;
return ::vcsn::inductive<automaton_t>(rs,
std::get<I>(v.sub()),
tag_t{});
}
/// Sum of sizes for all tapes.
template <size_t... I>
auto tape_(const tuple_t& v, detail::index_sequence<I...>)
{
return visitor_.as_.tuple(tape_<I>(v)...);
}
/// Entry point.
auto operator()(const tuple_t& v)
{
visitor_.res_ = tape_(v, labelset_t_of<context_t>::indices);
}
self_t& visitor_;
};
template <typename Dummy>
struct visit_tuple<false, Dummy>
{
void operator()(const tuple_t&)
{
BUILTIN_UNREACHABLE();
}
self_t& visitor_;
};
virtual void visit(const tuple_t& v, std::true_type) override
{
raise(me(), ": tuple is not supported");
visit_tuple<>{*this}(v);
}
VCSN_RAT_VISIT(zero,)
......@@ -153,21 +205,16 @@ namespace vcsn
}
private:
expressionset_t rs_;
automatonset_t as_;
automaton_t res_ = nullptr;
};
} // rat::
/// Build a inductive automaton from an expression.
///
/// \tparam Aut the type of the generated automaton.
/// \tparam ExpSet the expressionset.
/// \tparam Tag the nature of the operations (standard_tag, etc.).
template <Automaton Aut, typename ExpSet, typename Tag>
Aut
inductive(const ExpSet& rs, const typename ExpSet::value_t& r,
Tag = {})
inductive(const ExpSet& rs, const typename ExpSet::value_t& r, Tag)
{
auto ind = rat::inductive_visitor<Aut, ExpSet, Tag>{rs};
return ind(r);
......
......@@ -8,6 +8,7 @@
#include <vcsn/algos/multiply.hh>
#include <vcsn/algos/proper.hh>
#include <vcsn/algos/sum.hh>
#include <vcsn/algos/tuple-automaton.hh>
#include <vcsn/core/mutable-automaton.hh>
#include <vcsn/ctx/context.hh>
......@@ -141,7 +142,10 @@ namespace vcsn
/// Build a tuple: `e | f | ...`.
template <typename... Value>
auto tuple(Value&&... v) const -> value_t;
auto tuple(Value&&... v) const -> value_t
{
return ::vcsn::tuple(v...)->strip();
}
/// Add a power operator: `e{n}`.
auto power(const value_t& e, unsigned n) const -> value_t
......@@ -187,14 +191,15 @@ namespace vcsn
}
/// Add a complement operator: `e{c}`.
auto complement(const value_t& e) const -> value_t
auto complement(const value_t& e, std::true_type) const -> value_t
{
namespace v = ::vcsn;
// The automaton for e does not have spontaneous transitions,
// but we call proper because determinize needs the labelset to
// be free. But then the result is free too, we might have to
// restore the context.
auto a = v::coaccessible(v::complement(v::complete(v::determinize(v::proper(e)))));
auto a =
v::coaccessible(v::complement(v::complete(v::determinize(v::proper(e)))));
if (v::is_empty(a))
return zero();
else
......@@ -205,6 +210,18 @@ namespace vcsn
}
}
/// Add a complement operator: `e{c}`.
auto complement(const value_t& e, std::false_type) const -> value_t
{
raise("inductive: cannot complement on multitape: ", ctx_);
}
/// Add a complement operator: `e{c}`.
auto complement(const value_t& e) const -> value_t
{
return complement(e, bool_constant<!detail::is_multitape<context_t>{}>{});
}
/// Add a transposition operator.
auto transposition(const value_t& e) const -> value_t
{
......
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