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

algos: provide more contexts to errors

See issue #62: sometimes our error are too terse.  Enrich them.  The
point here is first to look for a pattern that we could deploy
everywhere.

Before:

    In [2]: vcsn.Q.expression('a**').derivation('a')
    RuntimeError: q: star: invalid value: 1

    In [3]: vcsn.Q.expression('a**').constant_term()
    RuntimeError: q: star: invalid value: 1

    In [4]: vcsn.Q.expression('a**').derived_term('expansion')
    RuntimeError: q: star: invalid value: 1

    In [5]: vcsn.Q.expression('a**').derived_term('derivation')
    RuntimeError: q: star: invalid value: 1

After:

    In [2]: vcsn.Q.expression('a**').derivation('a')
    RuntimeError: q: star: invalid value: 1
      while computing derivative of: a**
                    with respect to: a

    In [3]: vcsn.Q.expression('a**').constant_term()
    RuntimeError: q: star: invalid value: 1
      while computing constant-term of: a**

    In [4]: vcsn.Q.expression('a**').derived_term('expansion')
    RuntimeError: q: star: invalid value: 1
      while computing expansion of: a**
      while computing derived-term of: a**

    In [5]: vcsn.Q.expression('a**').derived_term('derivation')
    RuntimeError: q: star: invalid value: 1
      while computing constant-term of: a**
      while computing derived-term of: a**

* vcsn/algos/constant-term.hh: Keep the expressionset, not
just the weightset.
Improve error messages.
Simplify tuple handling.
* vcsn/algos/derivation.hh: Improve error messages.
* vcsn/algos/derived-term.hh: Ditto.
(make_derived_term_automaton): Ditto.
* vcsn/algos/to-expansion.hh: Ditto.

* tests/bin/test.py (XFAIL): Also accept re patterns.
* tests/python/constant-term.py, tests/python/derivation.py,
* tests/python/expansion.py: Check error messages.
parent 5c72a8a0
......@@ -131,7 +131,9 @@ def XFAIL(fun, exp=None):
try:
fun()
except RuntimeError as e:
if exp is None or exp in str(e):
if (exp is None
or isinstance(exp, re._pattern_type) and re.match(exp, str(e))
or isinstance(exp, str) and exp in str(e)):
PASS()
else:
FAIL('Unexpected error message')
......
......@@ -51,6 +51,9 @@ check('xy', '<x>a*&:<y>b*')
# star.
check(r'\e', '(<x>a)*')
check('x*', r'(<x>\e)*')
XFAIL(lambda: vcsn.Q.expression('a**').constant_term(),
r'''q: star: invalid value: 1
while computing constant-term of: a**''')
# complement.
check(r'\e', '(<x>a){c}')
......
......@@ -126,6 +126,21 @@ check('<x>(<y>a)*', 'a', '<xy>(<y>a)*')
check('(<x>a)*<y>', 'a', '<x>(<x>a)*<y>')
check('(<x>a)*<y>', 'aa', '<xx>(<x>a)*<y>')
XFAIL(lambda: vcsn.Q.expression('a**').derivation('a'),
r'''q: star: invalid value: 1
while computing derivative of: a**
with respect to: a''')
XFAIL(lambda: vcsn.Q.expression('a**').derived_term(),
r'''q: star: invalid value: 1
while computing expansion of: a**
while computing derived-term of: a**''')
XFAIL(lambda: vcsn.Q.expression('a**').derived_term('derivation'),
r'''q: star: invalid value: 1
while computing constant-term of: a**
while computing derived-term of: a**''')
# Complement.
check(r'\z{c}', 'a', r'\z{c}')
......
......@@ -11,6 +11,16 @@ def expr(e, *args):
e = ctx.expression(e, *args)
return e
## ------ ##
## Star. ##
## ------ ##
XFAIL(lambda: vcsn.Q.expression('a**').expansion(),
r'''q: star: invalid value: 1
while computing expansion of: a**''')
## ------------ ##
## Complement. ##
## ------------ ##
......
#pragma once
#include <vcsn/algos/project.hh>
#include <vcsn/ctx/fwd.hh>
#include <vcsn/ctx/traits.hh>
#include <vcsn/core/rat/visitor.hh>
......@@ -8,6 +9,11 @@
namespace vcsn
{
/// The constant term of \a e.
template <typename ExpSet>
weight_t_of<ExpSet>
constant_term(const ExpSet& rs, const typename ExpSet::value_t& e);
namespace rat
{
......@@ -35,17 +41,23 @@ namespace vcsn
/// Name of this algorithm, for error messages.
constexpr static const char* me() { return "constant_term"; }
constant_term_visitor(const weightset_t& ws)
: ws_(ws)
{}
constant_term_visitor(const expressionset_t& rs)
: constant_term_visitor(*rs.weightset())
: rs_{rs}
, ws_{*rs_.weightset()}
{}
weight_t operator()(const expression_t& v)
{
return constant_term(v);
try
{
return constant_term(v);
}
catch (const std::runtime_error& e)
{
raise(e.what(), "\n",
" while computing constant-term of: ", to_string(rs_, v));
}
}
private:
......@@ -146,9 +158,8 @@ namespace vcsn
template <size_t I>
weight_t work_(const tuple_t& v)
{
using rs_t = typename expressionset_t::template project_t<I>;
auto constant_term = constant_term_visitor<rs_t>{visitor_.ws_};
return constant_term(std::get<I>(v.sub()));
return ::vcsn::constant_term(visitor_.rs_.template project<I>(),
std::get<I>(v.sub()));
}
/// Product of the constant-terms of all tapes.
......@@ -182,12 +193,12 @@ namespace vcsn
}
private:
expressionset_t rs_;
weightset_t ws_;
weight_t res_;
};
} // rat::
/// The constant term of \a e.
template <typename ExpSet>
weight_t_of<ExpSet>
constant_term(const ExpSet& rs, const typename ExpSet::value_t& e)
......
......@@ -58,9 +58,19 @@ namespace vcsn
polynomial_t
operator()(const expression_t& v, label_t var)
{
variable_ = var;
v->accept(*this);
return std::move(res_);
try
{
variable_ = var;
v->accept(*this);
return std::move(res_);
}
catch (const std::runtime_error& e)
{
raise(e.what(), "\n",
" while computing derivative of: ", to_string(rs_, v), "\n"
" with respect to: ",
to_string(*rs_.labelset(), var));
}
}
private:
......
......@@ -169,18 +169,26 @@ namespace vcsn
{}
/// Compute the derived-term automaton.
automaton_t operator()(const expression_t& expression)
automaton_t operator()(const expression_t& exp)
{
if (algo_.algo == derived_term_algo::derivation)
return via_derivation(expression);
else
return via_expansion(expression);
try
{
if (algo_.algo == derived_term_algo::derivation)
return via_derivation(exp);
else
return via_expansion(exp);
}
catch (const std::runtime_error& e)
{
raise(e.what(), "\n",
" while computing derived-term of: ", to_string(rs_, exp));
}
}
/// Compute the derived-term automaton via derivation.
automaton_t via_derivation(const expression_t& expression)
automaton_t via_derivation(const expression_t& exp)
{
init_(expression);
init_(exp);
while (!aut_->todo_.empty())
{
auto p = std::move(aut_->todo_.top());
......@@ -191,9 +199,9 @@ namespace vcsn
}
/// Compute the derived-term automaton via expansion.
automaton_t via_expansion(const expression_t& expression)
automaton_t via_expansion(const expression_t& exp)
{
init_(expression);
init_(exp);
while (!aut_->todo_.empty())
{
auto p = std::move(aut_->todo_.top());
......@@ -208,13 +216,13 @@ namespace vcsn
using super_t::aut_;
/// Initialize the computation: build the initial states.
void init_(const expression_t& expression)
void init_(const expression_t& exp)
{
if (algo_.breaking)
for (const auto& p: split(rs_, expression))
for (const auto& p: split(rs_, exp))
aut_->set_initial(label_of(p), weight_of(p));
else
aut_->set_initial(expression, ws_.one());
aut_->set_initial(exp, ws_.one());
}
/// Complete a state: find its outgoing transitions.
......@@ -366,7 +374,7 @@ namespace vcsn
const auto& e = exp->as<ExpSet>();
const auto& rs = e.valueset();
const auto& r = e.value();
if (boost::starts_with(algo, "lazy"))
if (boost::starts_with(algo, "lazy,"))
{
auto a = vcsn::detail::derived_term_algo(algo);
require(a.algo == vcsn::detail::derived_term_algo::expansion,
......
......@@ -66,9 +66,17 @@ namespace vcsn
/// From an expression, build its expansion.
expansion_t operator()(const expression_t& v)
{
res_ = es_.zero();
v->accept(*this);
return res_;
try
{
res_ = es_.zero();
v->accept(*this);
return res_;
}
catch (const std::runtime_error& e)
{
raise(e.what(), "\n",
" while computing expansion of: ", to_string(rs_, v));
}
}
private:
......
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