reduce_parity: expose the internal vectors of colors

* spot/twaalgos/parity.cc, spot/twaalgos/parity.hh: Add a
reduce_parity_data class for access to the vectors of colors
computed by reduce_parity.
* python/spot/impl.i: Add bindings for std::vector<int>.
This commit is contained in:
Alexandre Duret-Lutz 2022-10-14 17:55:36 +02:00
parent b0c299b9e9
commit 67722db78f
3 changed files with 64 additions and 35 deletions

View file

@ -520,6 +520,7 @@ namespace std {
%template(vectorbdd) vector<bdd>; %template(vectorbdd) vector<bdd>;
%template(aliasvector) vector<pair<string, bdd>>; %template(aliasvector) vector<pair<string, bdd>>;
%template(vectorstring) vector<string>; %template(vectorstring) vector<string>;
%template(vectorint) vector<int>;
%template(pair_formula_vectorstring) pair<spot::formula, vector<string>>; %template(pair_formula_vectorstring) pair<spot::formula, vector<string>>;
%template(atomic_prop_set) set<spot::formula>; %template(atomic_prop_set) set<spot::formula>;
%template(relabeling_map) map<spot::formula, spot::formula>; %template(relabeling_map) map<spot::formula, spot::formula>;

View file

@ -387,27 +387,15 @@ namespace spot
return aut; return aut;
} }
twa_graph_ptr reduce_parity_data::reduce_parity_data(const const_twa_graph_ptr& aut,
reduce_parity(const const_twa_graph_ptr& aut, bool colored, bool layered) bool layered)
{ {
return reduce_parity_here(make_twa_graph(aut, twa::prop_set::all()), if (!aut->acc().is_parity(parity_max, parity_odd, true))
colored, layered); input_is_not_parity("reduce_parity_data");
}
twa_graph_ptr
reduce_parity_here(twa_graph_ptr aut, bool colored, bool layered)
{
unsigned num_sets = aut->num_sets();
if (!colored && num_sets == 0)
return aut;
bool current_max;
bool current_odd;
if (!aut->acc().is_parity(current_max, current_odd, true))
input_is_not_parity("reduce_parity");
if (!aut->is_existential()) if (!aut->is_existential())
throw std::runtime_error throw std::runtime_error
("reduce_parity_here() does not support alternation"); ("reduce_parity_data() does not support alternation");
unsigned num_sets = aut->num_sets();
// The algorithm assumes "max odd" or "max even" parity. "min" // The algorithm assumes "max odd" or "max even" parity. "min"
// parity is handled by converting it to "max" while the algorithm // parity is handled by converting it to "max" while the algorithm
@ -466,8 +454,8 @@ namespace spot
// //
// -2 means the edge was never assigned a color. // -2 means the edge was never assigned a color.
unsigned evs = aut->edge_vector().size(); unsigned evs = aut->edge_vector().size();
std::vector<int> piprime1(evs, -2); // k=1 piprime1.resize(evs, -2); // k=1
std::vector<int> piprime2(evs, -2); // k=0 piprime2.resize(evs, -2); // k=0
bool sba = aut->prop_state_acc().is_true(); bool sba = aut->prop_state_acc().is_true();
auto rec = auto rec =
@ -481,7 +469,7 @@ namespace spot
{ {
int piri; // π(Rᵢ) int piri; // π(Rᵢ)
int color; // corresponding color, to deal with "min" kind int color; // corresponding color, to deal with "min" kind
if (current_max) if (parity_max)
{ {
piri = color = si.acc_sets_of(scc).max_set() - 1; piri = color = si.acc_sets_of(scc).max_set() - 1;
} }
@ -538,11 +526,28 @@ namespace spot
}; };
scc_and_mark_filter filter1(aut, {}); scc_and_mark_filter filter1(aut, {});
rec(filter1, rec); rec(filter1, rec);
}
twa_graph_ptr
reduce_parity(const const_twa_graph_ptr& aut, bool colored, bool layered)
{
return reduce_parity_here(make_twa_graph(aut, twa::prop_set::all()),
colored, layered);
}
twa_graph_ptr
reduce_parity_here(twa_graph_ptr aut, bool colored, bool layered)
{
unsigned num_sets = aut->num_sets();
if (!colored && num_sets == 0)
return aut;
reduce_parity_data pd(aut, layered);
// compute the used range for each vector. // compute the used range for each vector.
int min1 = num_sets; int min1 = num_sets;
int max1 = -2; int max1 = -2;
for (int m : piprime1) for (int m : pd.piprime1)
{ {
if (m <= -2) if (m <= -2)
continue; continue;
@ -559,7 +564,7 @@ namespace spot
} }
int min2 = num_sets; int min2 = num_sets;
int max2 = -2; int max2 = -2;
for (int m : piprime2) for (int m : pd.piprime2)
{ {
if (m <= -2) if (m <= -2)
continue; continue;
@ -575,13 +580,13 @@ namespace spot
{ {
std::swap(size1, size2); std::swap(size1, size2);
std::swap(min1, min2); std::swap(min1, min2);
std::swap(piprime1, piprime2); std::swap(pd.piprime1, pd.piprime2);
} }
unsigned new_num_sets = size1; unsigned new_num_sets = size1;
if (current_max) if (pd.parity_max)
{ {
for (int& m : piprime1) for (int& m : pd.piprime1)
if (m > -2) if (m > -2)
m -= min1; m -= min1;
else else
@ -589,7 +594,7 @@ namespace spot
} }
else else
{ {
for (int& m : piprime1) for (int& m : pd.piprime1)
if (m > -2) if (m > -2)
m = new_num_sets - (m - min1) - 1; m = new_num_sets - (m - min1) - 1;
else else
@ -597,8 +602,8 @@ namespace spot
} }
// The parity style changes if we shift colors by an odd number. // The parity style changes if we shift colors by an odd number.
bool new_odd = current_odd ^ (min1 & 1); bool new_odd = pd.parity_odd ^ (min1 & 1);
if (!current_max) if (!pd.parity_max)
// Switching from min<->max changes the parity style every time // Switching from min<->max changes the parity style every time
// the number of colors is even. If the input was "min", we // the number of colors is even. If the input was "min", we
// switched once to "max" to apply the reduction and once again // switched once to "max" to apply the reduction and once again
@ -607,7 +612,7 @@ namespace spot
new_odd ^= !(num_sets & 1) ^ !(new_num_sets & 1); new_odd ^= !(num_sets & 1) ^ !(new_num_sets & 1);
if (!colored) if (!colored)
{ {
new_odd ^= current_max; new_odd ^= pd.parity_max;
new_num_sets -= 1; new_num_sets -= 1;
// It seems we have nothing to win by changing automata with a // It seems we have nothing to win by changing automata with a
@ -617,18 +622,18 @@ namespace spot
} }
aut->set_acceptance(new_num_sets, aut->set_acceptance(new_num_sets,
acc_cond::acc_code::parity(current_max, new_odd, acc_cond::acc_code::parity(pd.parity_max, new_odd,
new_num_sets)); new_num_sets));
if (colored) if (colored)
for (auto& e: aut->edges()) for (auto& e: aut->edges())
{ {
unsigned n = aut->edge_number(e); unsigned n = aut->edge_number(e);
e.acc = acc_cond::mark_t({unsigned(piprime1[n])}); e.acc = acc_cond::mark_t({unsigned(pd.piprime1[n])});
} }
else if (current_max) else if (pd.parity_max)
for (auto& e: aut->edges()) for (auto& e: aut->edges())
{ {
unsigned n = piprime1[aut->edge_number(e)]; unsigned n = pd.piprime1[aut->edge_number(e)];
if (n == 0) if (n == 0)
e.acc = acc_cond::mark_t({}); e.acc = acc_cond::mark_t({});
else else
@ -637,7 +642,7 @@ namespace spot
else else
for (auto& e: aut->edges()) for (auto& e: aut->edges())
{ {
unsigned n = piprime1[aut->edge_number(e)]; unsigned n = pd.piprime1[aut->edge_number(e)];
if (n >= new_num_sets) if (n >= new_num_sets)
e.acc = acc_cond::mark_t({}); e.acc = acc_cond::mark_t({});
else else

View file

@ -21,6 +21,7 @@
#include <spot/misc/common.hh> #include <spot/misc/common.hh>
#include <spot/twa/fwd.hh> #include <spot/twa/fwd.hh>
#include <vector>
namespace spot namespace spot
{ {
@ -194,5 +195,27 @@ namespace spot
SPOT_API twa_graph_ptr SPOT_API twa_graph_ptr
reduce_parity_here(twa_graph_ptr aut, reduce_parity_here(twa_graph_ptr aut,
bool colored = false, bool layered = false); bool colored = false, bool layered = false);
/// @}
/// \brief Internal data computed by the reduce_parity function
///
/// `piprime1` and `piprime2` have the size of `aut`'s edge vector,
/// represent two possible colorations of the edges. piprime1 assumes
/// that terminal cases of the recursion are odd, and piprime2 assumes
/// they are even.
///
/// reduce_parity() actually compare the range of values in these
/// two vectors to limit the number of colors.
struct SPOT_API reduce_parity_data
{
bool parity_max; ///< Whether the input automaton is parity max
bool parity_odd; ///< Whether the input automaton is parity odd
std::vector<int> piprime1;
std::vector<int> piprime2;
reduce_parity_data(const const_twa_graph_ptr& aut, bool layered = false);
};
/// @} /// @}
} }