partial_degeneralize: a support for disjunction of Fin

* spot/twaalgos/degen.cc, spot/twaalgos/degen.hh: Implement this.
Also throw a runtime error in case were todegen does not match any
subformula.
* tests/python/pdegen.py: Add tests.
This commit is contained in:
Alexandre Duret-Lutz 2020-02-03 11:01:01 +01:00
parent f1008c156b
commit f9e75de647
4 changed files with 120 additions and 26 deletions

View file

@ -29,6 +29,7 @@
#include <memory>
#include <spot/twaalgos/sccinfo.hh>
#include <spot/twa/bddprint.hh>
#include <spot/twaalgos/isdet.hh>
//#define DEGEN_DEBUG
@ -738,7 +739,8 @@ namespace spot
namespace
{
static acc_cond::mark_t
to_strip(const acc_cond::acc_code& code, acc_cond::mark_t todegen)
to_strip(const acc_cond::acc_code& code, acc_cond::mark_t todegen,
bool also_fin)
{
if (code.empty())
return todegen;
@ -753,38 +755,42 @@ namespace spot
case acc_cond::acc_op::Or:
--pos;
break;
case acc_cond::acc_op::Fin:
case acc_cond::acc_op::FinNeg:
if (!also_fin)
{
pos -= 2;
tostrip -= code[pos].mark;
break;
}
// Handle Fin and Inf in the same way
SPOT_FALLTHROUGH;
case acc_cond::acc_op::Inf:
case acc_cond::acc_op::InfNeg:
pos -= 2;
if (code[pos].mark != todegen)
tostrip -= code[pos].mark;
break;
case acc_cond::acc_op::Fin:
case acc_cond::acc_op::FinNeg:
pos -= 2;
tostrip -= code[pos].mark;
break;
}
}
while (pos > 0);
return tostrip;
}
static void
static bool
update_acc_for_partial_degen(acc_cond::acc_code& code,
acc_cond::mark_t todegen,
acc_cond::mark_t tostrip,
acc_cond::mark_t accmark)
acc_cond::mark_t accmark,
bool also_fin)
{
if (!todegen)
if (!todegen || code.empty())
{
code &= acc_cond::acc_code::inf(accmark);
return;
return true;
}
if (code.empty())
return;
bool updated = false;
unsigned pos = code.size();
do
{
@ -794,26 +800,46 @@ namespace spot
case acc_cond::acc_op::Or:
--pos;
break;
case acc_cond::acc_op::Fin:
case acc_cond::acc_op::FinNeg:
if (!also_fin)
{
pos -= 2;
code[pos].mark = code[pos].mark.strip(tostrip);
break;
}
// Handle Fin and Inf in the same way
SPOT_FALLTHROUGH;
case acc_cond::acc_op::Inf:
case acc_cond::acc_op::InfNeg:
pos -= 2;
if (code[pos].mark == todegen)
code[pos].mark = accmark;
{
code[pos].mark = accmark;
updated = true;
}
else
code[pos].mark = code[pos].mark.strip(tostrip);
break;
case acc_cond::acc_op::Fin:
case acc_cond::acc_op::FinNeg:
pos -= 2;
code[pos].mark = code[pos].mark.strip(tostrip);
{
code[pos].mark = code[pos].mark.strip(tostrip);
}
break;
}
}
while (pos > 0);
return updated;
}
[[noreturn]] static void
report_invalid_partial_degen_arg(acc_cond::mark_t todegen,
acc_cond::acc_code& cond)
{
std::ostringstream err;
err << "partial_degeneralize(): " << todegen
<< " does not match any degeneralizable subformula of "
<< cond << '.';
throw std::runtime_error(err.str());
}
}
@ -825,11 +851,17 @@ namespace spot
res->copy_ap_of(a);
acc_cond::acc_code acc = a->get_acceptance();
acc_cond::mark_t tostrip = to_strip(acc, todegen);
// We can also degeneralize disjunctions of Fin if the input is
// deterministic.
bool also_fin = a->acc().uses_fin_acceptance() && is_deterministic(a);
acc_cond::mark_t tostrip = to_strip(acc, todegen, also_fin);
acc_cond::mark_t keep = a->acc().all_sets() - tostrip;
acc_cond::mark_t degenmark = {keep.count()};
update_acc_for_partial_degen(acc, todegen, tostrip, degenmark);
if (!update_acc_for_partial_degen(acc, todegen, tostrip, degenmark,
also_fin))
report_invalid_partial_degen_arg(todegen, acc);
res->set_acceptance(acc);
// auto* names = new std::vector<std::string>;

View file

@ -99,7 +99,14 @@ namespace spot
/// Fin(2).
///
/// Cases where the sets listed in \a todegen also occur outside
/// of the Inf-conjunction are also supported.
/// of the Inf-conjunction are also supported. Subformulas that
/// are disjunctions of Fin(.) terms (e.g., Fin(1)|Fin(2)) can
/// 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.
SPOT_API twa_graph_ptr
partial_degeneralize(const const_twa_graph_ptr& a,
acc_cond::mark_t todegen);