partial_degeneralize: add a version that takes no "todegen" argument
* spot/twaalgos/degen.cc, spot/twaalgos/degen.hh (is_partially_degeneralizable): New function. (partial_degeneralize): New version without todegen argument. * tests/python/pdegen.py: Add test cases.
This commit is contained in:
parent
8df616ee0d
commit
bf4a0ccffd
3 changed files with 149 additions and 4 deletions
|
|
@ -837,7 +837,6 @@ namespace spot
|
|||
return updated;
|
||||
}
|
||||
|
||||
|
||||
[[noreturn]] static void
|
||||
report_invalid_partial_degen_arg(acc_cond::mark_t todegen,
|
||||
acc_cond::acc_code& cond)
|
||||
|
|
@ -850,10 +849,67 @@ namespace spot
|
|||
}
|
||||
}
|
||||
|
||||
acc_cond::mark_t
|
||||
is_partially_degeneralizable(const const_twa_graph_ptr& aut,
|
||||
bool allow_inf, bool allow_fin)
|
||||
{
|
||||
auto& code = aut->get_acceptance();
|
||||
|
||||
if (code.empty())
|
||||
return {};
|
||||
|
||||
if (allow_fin)
|
||||
allow_fin = is_deterministic(aut);
|
||||
|
||||
acc_cond::mark_t res = {};
|
||||
unsigned res_sz = -1U;
|
||||
auto update = [&](const acc_cond::mark_t& m)
|
||||
{
|
||||
unsigned sz = m.count();
|
||||
if (sz > 1 && sz < res_sz)
|
||||
{
|
||||
res_sz = sz;
|
||||
res = m;
|
||||
}
|
||||
// If we have found a pair to degeneralize, we
|
||||
// won't find
|
||||
return res_sz == 2;
|
||||
};
|
||||
|
||||
unsigned pos = code.size();
|
||||
do
|
||||
{
|
||||
switch (code[pos - 1].sub.op)
|
||||
{
|
||||
case acc_cond::acc_op::And:
|
||||
case acc_cond::acc_op::Or:
|
||||
--pos;
|
||||
break;
|
||||
case acc_cond::acc_op::Fin:
|
||||
case acc_cond::acc_op::FinNeg:
|
||||
pos -= 2;
|
||||
if (allow_fin)
|
||||
if (update(code[pos].mark))
|
||||
return res;
|
||||
break;
|
||||
case acc_cond::acc_op::Inf:
|
||||
case acc_cond::acc_op::InfNeg:
|
||||
pos -= 2;
|
||||
if (allow_inf)
|
||||
if (update(code[pos].mark))
|
||||
return res;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (pos > 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
twa_graph_ptr
|
||||
partial_degeneralize(const const_twa_graph_ptr& a,
|
||||
acc_cond::mark_t todegen)
|
||||
|
||||
{
|
||||
auto res = make_twa_graph(a->get_dict());
|
||||
res->copy_ap_of(a);
|
||||
|
|
@ -1023,6 +1079,14 @@ namespace spot
|
|||
return res;
|
||||
}
|
||||
|
||||
twa_graph_ptr
|
||||
partial_degeneralize(twa_graph_ptr a)
|
||||
{
|
||||
while (acc_cond::mark_t m = is_partially_degeneralizable(a))
|
||||
a = partial_degeneralize(a, m);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
std::vector<acc_cond::mark_t>
|
||||
propagate_marks_vector(const const_twa_graph_ptr& aut,
|
||||
|
|
|
|||
|
|
@ -104,12 +104,47 @@ namespace spot
|
|||
/// also be degeneralized if the input automaton is deterministic.
|
||||
///
|
||||
/// If this functions is called with a value of \a todegen that does
|
||||
/// not match a (complete) conjunction of Inf(.), or in a
|
||||
/// deterministic automaton a (complete) disjunction of Fin(.), an
|
||||
/// std::runtime_error exception is thrown.
|
||||
/// not match a conjunction of Inf(.), or in a deterministic
|
||||
/// automaton a disjunction of Fin(.), an std::runtime_error
|
||||
/// exception is thrown.
|
||||
///
|
||||
/// The version of the function that has no \a todegen argument will
|
||||
/// perform all possible partial degeneralizations, and may return
|
||||
/// the input automaton unmodified if no partial degeneralization is
|
||||
/// possible.
|
||||
///
|
||||
/// @{
|
||||
SPOT_API twa_graph_ptr
|
||||
partial_degeneralize(const const_twa_graph_ptr& a,
|
||||
acc_cond::mark_t todegen);
|
||||
SPOT_API twa_graph_ptr
|
||||
partial_degeneralize(twa_graph_ptr a);
|
||||
/// @}
|
||||
|
||||
/// \brief Is the automaton partially degeneralizable?
|
||||
///
|
||||
/// Return a mark `M={m₁, m₂, ..., mₙ}` such that either (1)
|
||||
/// `Inf(m₁)&Inf(m₂)&...&Inf(mₙ)` appears in the acceptance
|
||||
/// condition of \a aut, or (2) \a aut is deterministic and
|
||||
/// `Inf(m₁)|Inf(m₂)|...|Fin(mₙ)` appear in its conditions.
|
||||
///
|
||||
/// If multiple such marks exist the smallest such mark is returned.
|
||||
/// (This is important in case of overlapping options. E.g., in the
|
||||
/// formula `Inf(0)&Inf(1)&Inf(3) | (Inf(0)&Inf(1))&Fin(2)` we have
|
||||
/// two possible degeneralizations options `{0,1,3}`, and `{0,1}`.
|
||||
/// Degeneralizing for `{0,1,3}` and then `{0,1}` could enlarge the
|
||||
/// automaton by a factor 6, while degeneralizing by `{0,1}` and
|
||||
/// then some `{x,y}` may enlarge the automaton only by a factor 4.)
|
||||
///
|
||||
/// Return an empty mark otherwise if the automaton is not partially
|
||||
/// degeneralizable.
|
||||
///
|
||||
/// The optional arguments \a allow_inf and \a allow_fin, can be set
|
||||
/// to false to disallow one type of match.
|
||||
SPOT_API acc_cond::mark_t
|
||||
is_partially_degeneralizable(const const_twa_graph_ptr& aut,
|
||||
bool allow_inf = true,
|
||||
bool allow_fin = true);
|
||||
|
||||
/// \ingroup twa_algorithms
|
||||
/// \brief Propagate marks around the automaton
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue