Commit eb9626ce authored by Akim Demaille's avatar Akim Demaille
Browse files

is-partial-identity: publish it

* vcsn/algos/is-partial-identity.hh: New, extracted from...
* vcsn/algos/is-functional.hh: here.
(is_identity): Rename as...
(is_partial_identity): this.
* lib/vcsn/algos/is-functional.cc, vcsn/dyn/algos.hh, vcsn/local.mk: Adjust.
parent 1909189a
Vcsn 2 news
===========
Vcsn news
=========
This file describes user visible changes in the course of the development of
Vaucanson 2, in reverse chronological order. On occasions, significant
changes in the internal API may also be documented.
Vcsn, in reverse chronological order. On occasions, significant changes in
the internal API may also be documented.
## 2014-11-18
......
#include <vcsn/core/mutable-automaton.hh>
#include <vcsn/dyn/algos.hh>
#include <vcsn/algos/is-functional.hh>
#include <vcsn/algos/is-partial-identity.hh>
#include <lib/vcsn/algos/registry.hh>
namespace vcsn
{
/*----------------.
| is-functional. |
`----------------*/
namespace dyn
{
REGISTER_DEFINE(is_functional);
bool is_functional(const automaton& aut)
{
return detail::is_functional_registry().call(aut);
}
REGISTER_DEFINE(is_partial_identity);
bool is_partial_identity(const automaton& aut)
{
return detail::is_partial_identity_registry().call(aut);
}
}
}
......@@ -312,6 +312,11 @@ struct automaton
return vcsn::dyn::is_functional(val_);
}
bool is_partial_identity() const
{
return vcsn::dyn::is_partial_identity(val_);
}
bool is_isomorphic(const automaton& rhs) const
{
return vcsn::dyn::are_isomorphic(val_, rhs.val_);
......@@ -1026,6 +1031,7 @@ BOOST_PYTHON_MODULE(vcsn_cxx)
.def("is_eps_acyclic", &automaton::is_eps_acyclic)
.def("is_equivalent", &automaton::is_equivalent)
.def("is_functional", &automaton::is_functional)
.def("is_partial_identity", &automaton::is_partial_identity)
.def("is_isomorphic", &automaton::is_isomorphic)
.def("is_normalized", &automaton::is_normalized)
.def("is_proper", &automaton::is_proper)
......
......@@ -122,6 +122,13 @@ def XFAIL(fun, exp = None):
else:
FAIL('did not raise an exception', str(fun))
def CHECK(effective, loc = None):
"Check that `effective` is `True`."
if effective:
PASS(loc=loc)
else:
FAIL("assertion failed", loc=loc)
def CHECK_EQ(expected, effective, loc = None):
"Check that `effective` is equal to `expected`."
if isinstance(expected, str) and not isinstance(effective, str):
......
......@@ -3,9 +3,9 @@
import vcsn
from test import *
## ----------- ##
## LAL x LAL. ##
## ----------- ##
## ----- ##
## LAL. ##
## ----- ##
a = vcsn.automaton('''digraph {
vcsn_context = "lat<lal_char(abc), lal_char(xyz)>, z"
......
#! /usr/bin/env python
import vcsn
from test import *
## ----- ##
## LAL. ##
## ----- ##
a = vcsn.automaton('''digraph {
vcsn_context = "lat<lal_char(abc), lal_char>, z"
I0 -> 0
0 -> 1 [label = "(a, a)"]
1 -> 2 [label = "(b, b)"]
2 -> F2
}''')
CHECK(a.is_partial_identity())
a = vcsn.automaton('''digraph {
vcsn_context = "lat<lal_char(abc), lal_char>, z"
I0 -> 0
0 -> 1 [label = "(a, a)"]
1 -> 2 [label = "(b, c)"]
2 -> F2
}''')
CHECK(not a.is_partial_identity())
## ----- ##
## LAW. ##
## ----- ##
a = vcsn.automaton(r'''digraph {
vcsn_context = "lat<law_char(abc),law_char(abc)>, b"
I -> 0
0 -> 1 [label = "(aaa, a)"]
1 -> 0 [label = "(a, aaa)"]
0 -> 2 [label = "(bb, \\e)"]
2 -> 0 [label = "(bb, bbbb)"]
0 -> F
}''')
CHECK(a.is_partial_identity())
a = vcsn.automaton(r'''digraph {
vcsn_context = "lat<law_char(abc),law_char(abcd)>, b"
I -> 0
0 -> 1 [label = "(aaa, a)"]
1 -> 0 [label = "(a, aaa)"]
0 -> 2 [label = "(bb, \\e)"]
2 -> 0 [label = "(bb, bbb)"]
0 -> F
}''')
CHECK(not a.is_partial_identity())
......@@ -46,6 +46,7 @@ PY_LOG_DRIVER = $(TAP_DRIVER)
%D%/is-equivalent.py \
%D%/is-functional.py \
%D%/is-isomorphic.py \
%D%/is-partial-identity.py \
%D%/is-proper.py \
%D%/is-valid.py \
%D%/kmul.py \
......
#ifndef VCSN_ALGOS_IS_FUNCTIONAL_HH
# define VCSN_ALGOS_IS_FUNCTIONAL_HH
#pragma once
# include <queue>
# include <utility>
# include <vcsn/algos/accessible.hh>
# include <vcsn/algos/compose.hh>
# include <vcsn/dyn/automaton.hh>
# include <vcsn/dyn/fwd.hh>
# include <vcsn/labelset/tupleset.hh>
# include <vcsn/misc/unordered_map.hh>
#include <vcsn/algos/compose.hh>
#include <vcsn/algos/is-partial-identity.hh>
#include <vcsn/dyn/automaton.hh>
#include <vcsn/dyn/fwd.hh>
namespace vcsn
{
......@@ -17,64 +11,6 @@ namespace vcsn
| is-functional. |
`---------------*/
/// Whether transducer \a aut is equivalent to the identity function
/// on all successful path.
///
/// This automaton is expected to be two-tape, both tapes having the
/// same labelset.
template <typename Aut>
bool is_identity(const Aut& aut)
{
using state_t = state_t_of<Aut>;
using labelset_t = labelset_t_of<Aut>;
/// Words of the k-tape automaton: k-tuples of words.
using wordset_t = detail::law_t<labelset_t>;
using word_t = typename wordset_t::value_t;
wordset_t ls = make_wordset(*aut->labelset());
/// Common labelset for both tapes.
auto ls1 = ls.template set<0>();
/// Residue of input and output path of states by eliminate
/// longest common prefix.
std::unordered_map<state_t, word_t> rs;
auto coaccessibles = coaccessible_states(aut);
std::queue<state_t> todo;
auto pre = aut->pre();
todo.push(pre);
rs.emplace(pre, ls.one());
// When reaching the final state, there must be no residue.
// Instead of checking this case especially, just make sure
// that when we reach post, we only collected (\e, \e).
rs.emplace(aut->post(), ls.one());
while (!todo.empty())
{
auto s = todo.front();
todo.pop();
for (auto t : aut->all_out(s))
{
auto l = aut->label_of(t);
auto dst = aut->dst_of(t);
if (has(coaccessibles, dst))
{
auto p = rs[s];
p = ls.concat(p, l);
// Eliminate longest common prefix.
ls.lnormalize_here(p);
if (!has(rs, dst))
{
rs.emplace(dst, p);
todo.emplace(dst);
}
else if (!ls.equal(p, rs[dst]))
return false;
}
}
}
return true;
}
/// Whether \a aut is functional.
/// \pre \a aut is a transducer.
template <typename Aut>
......@@ -85,7 +21,7 @@ namespace vcsn
auto r = insplit(focus<0>(aut));
detail::composer<decltype(l), decltype(r)> compose(l, r);
auto c = compose.compose();
return is_identity(c);
return is_partial_identity(c);
}
namespace dyn
......@@ -104,5 +40,3 @@ namespace vcsn
}
}
}
#endif // !VCSN_ALGOS_IS_FUNCTIONAL_HH
#pragma once
#include <queue>
#include <utility>
#include <vcsn/algos/accessible.hh>
#include <vcsn/dyn/automaton.hh>
#include <vcsn/dyn/fwd.hh>
#include <vcsn/labelset/tupleset.hh>
#include <vcsn/misc/unordered_map.hh>
namespace vcsn
{
/// Whether transducer \a aut is equivalent to a partial identity
/// function on all successful paths.
///
/// This automaton is expected to be two-tape, both tapes having the
/// same labelset.
template <typename Aut>
bool is_partial_identity(const Aut& aut)
{
using state_t = state_t_of<Aut>;
using labelset_t = labelset_t_of<Aut>;
/// Words of the k-tape automaton: k-tuples of words.
using wordset_t = detail::law_t<labelset_t>;
using word_t = typename wordset_t::value_t;
wordset_t ls = make_wordset(*aut->labelset());
/// Common labelset for both tapes.
auto ls1 = ls.template set<0>();
/// Residue of input and output paths arriving to a given state,
/// with longest common prefix eliminated.
std::unordered_map<state_t, word_t> rs;
auto coaccessibles = coaccessible_states(aut);
std::queue<state_t> todo;
auto pre = aut->pre();
todo.push(pre);
rs.emplace(pre, ls.one());
// When reaching the final state, there must be no residue.
// Instead of checking this case especially, just make sure
// that when we reach post, we only collected (\e, \e).
rs.emplace(aut->post(), ls.one());
while (!todo.empty())
{
auto s = todo.front();
todo.pop();
for (auto t : aut->all_out(s))
{
auto dst = aut->dst_of(t);
if (has(coaccessibles, dst))
{
// Compute the new residue.
auto r = ls.concat(rs[s], aut->label_of(t));
// Eliminate longest common prefix.
ls.lnormalize_here(r);
if (!has(rs, dst))
{
rs.emplace(dst, r);
todo.emplace(dst);
}
else if (!ls.equal(r, rs[dst]))
{
return false;
}
}
}
}
return true;
}
namespace dyn
{
namespace detail
{
/// Bridge.
template <class Aut>
bool is_partial_identity(const automaton& aut)
{
return is_partial_identity(aut->as<Aut>());
}
REGISTER_DECLARE(is_partial_identity,
(const automaton&) -> bool);
}
}
}
......@@ -290,6 +290,10 @@ namespace vcsn
/// \pre \a aut is a transducer.
bool is_functional(const automaton& aut);
/// Whether \a aut realizes a partial identity.
/// \pre \a aut is a transducer.
bool is_partial_identity(const automaton& aut);
/// Whether is normalized (in the Thompson sense), i.e., standard
/// and co-standard.
bool is_normalized(const automaton& aut);
......
......@@ -49,6 +49,7 @@ nobase_include_HEADERS = \
%D%/algos/is-deterministic.hh \
%D%/algos/is-eps-acyclic.hh \
%D%/algos/is-functional.hh \
%D%/algos/is-partial-identity.hh \
%D%/algos/is-proper.hh \
%D%/algos/is-valid-expression.hh \
%D%/algos/is-valid.hh \
......
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