ltlsynt rewrite
Introducing the new game interface to ltlsynt. ltlsynt now also uses direct strategy deduction and formula decomposition. * bin/ltlsynt.cc: Here * spot/twaalgos/aiger.cc , spot/twaalgos/aiger.hh: Use strategy_like * spot/twaalgos/game.hh: Minor adaption * spot/twaalgos/mealy_machine.cc: Use new interface * spot/twaalgos/synthesis.cc , spot/twaalgos/synthesis.hh: Spezialised split * tests/core/ltlsynt.test , tests/python/games.ipynb: Adapting
This commit is contained in:
parent
a5185c2123
commit
7d908b9320
9 changed files with 2809 additions and 2004 deletions
|
|
@ -34,7 +34,7 @@
|
|||
#include <spot/twa/twagraph.hh>
|
||||
#include <spot/misc/bddlt.hh>
|
||||
#include <spot/misc/minato.hh>
|
||||
#include <spot/twaalgos/game.hh>
|
||||
#include <spot/twaalgos/synthesis.hh>
|
||||
|
||||
#define STR(x) #x
|
||||
#define STR_(x) STR(x)
|
||||
|
|
@ -1893,7 +1893,47 @@ namespace spot
|
|||
return auts_to_aiger(new_vec, mode);
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
aig_ptr
|
||||
strategies_to_aig(const std::vector<strategy_like_t>& strat_vec,
|
||||
const char *mode,
|
||||
const std::vector<std::string>& ins,
|
||||
const std::vector<std::vector<std::string>>& outs)
|
||||
{
|
||||
// todo extend to TGBA and possibly others
|
||||
const unsigned ns = strat_vec.size();
|
||||
std::vector<twa_graph_ptr> strategies;
|
||||
strategies.reserve(ns);
|
||||
std::vector<std::vector<std::string>> outs_used;
|
||||
outs_used.reserve(ns);
|
||||
|
||||
for (unsigned i = 0; i < ns; ++i)
|
||||
{
|
||||
switch (strat_vec[i].success)
|
||||
{
|
||||
case -1:
|
||||
throw std::runtime_error("strategies_to_aig(): Partial strat is "
|
||||
"not feasible!");
|
||||
case 0:
|
||||
throw std::runtime_error("strategies_to_aig(): Partial strat has "
|
||||
"unknown status!");
|
||||
case 1:
|
||||
{
|
||||
strategies.push_back(strat_vec[i].strat_like);
|
||||
outs_used.push_back(outs[i]);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
throw std::runtime_error("strategies_to_aig(): TGBA not "
|
||||
"yet supported.");
|
||||
default:
|
||||
throw std::runtime_error("strategies_to_aig(): Unknown "
|
||||
"success identifier.");
|
||||
}
|
||||
}
|
||||
return strategies_to_aig(strategies, mode, ins, outs_used);
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
print_aiger(std::ostream &os, const_aig_ptr circuit)
|
||||
{
|
||||
if (not circuit)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@
|
|||
|
||||
namespace spot
|
||||
{
|
||||
// Forward for synthesis
|
||||
struct strategy_like_t;
|
||||
|
||||
class aig;
|
||||
|
||||
typedef std::shared_ptr<aig> aig_ptr;
|
||||
|
|
@ -453,6 +456,13 @@ namespace spot
|
|||
const std::vector<std::string>& ins,
|
||||
const std::vector<std::vector<std::string>>& outs);
|
||||
|
||||
/// \brief Like above, but works on strategy_like elements
|
||||
SPOT_API aig_ptr
|
||||
strategies_to_aig(const std::vector<strategy_like_t>& strat_vec,
|
||||
const char* mode,
|
||||
const std::vector<std::string>& ins,
|
||||
const std::vector<std::vector<std::string>>& outs);
|
||||
|
||||
/// \brief Print the aig to stream in AIGER format
|
||||
SPOT_API std::ostream&
|
||||
print_aiger(std::ostream& os, const_aig_ptr circuit);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <ostream>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include <bddx.h>
|
||||
#include <spot/misc/optionmap.hh>
|
||||
|
|
@ -92,10 +93,9 @@ namespace spot
|
|||
/// \brief Benchmarking and options structure for games and synthesis
|
||||
///
|
||||
/// \note This structure is designed to interface with the algorithms
|
||||
/// found in spot/twaalgos/synthesis.hh
|
||||
/// found in spot/twaalgos/synthesis.hh and spot/twaalgos/game.hh
|
||||
struct SPOT_API game_info
|
||||
{
|
||||
|
||||
enum class solver
|
||||
{
|
||||
DET_SPLIT=0,
|
||||
|
|
@ -116,7 +116,6 @@ namespace spot
|
|||
double aig_time = 0.0;
|
||||
unsigned nb_states_arena = 0;
|
||||
unsigned nb_states_arena_env = 0;
|
||||
unsigned nb_states_parity_game = 0;
|
||||
unsigned nb_strat_states = 0;
|
||||
unsigned nb_strat_edges = 0;
|
||||
unsigned nb_latches = 0;
|
||||
|
|
@ -128,7 +127,6 @@ namespace spot
|
|||
: force_sbacc{false},
|
||||
s{solver::LAR},
|
||||
minimize_lvl{0},
|
||||
out_choice{0},
|
||||
bv{},
|
||||
verbose_stream{nullptr},
|
||||
dict(make_bdd_dict())
|
||||
|
|
@ -138,7 +136,6 @@ namespace spot
|
|||
bool force_sbacc;
|
||||
solver s;
|
||||
int minimize_lvl;
|
||||
int out_choice;
|
||||
std::optional<bench_var> bv;
|
||||
std::ostream* verbose_stream;
|
||||
option_map opt;
|
||||
|
|
|
|||
|
|
@ -3456,6 +3456,16 @@ namespace spot
|
|||
if (!mm->acc().is_t())
|
||||
throw std::runtime_error("Mealy machine needs true acceptance!\n");
|
||||
|
||||
auto orig_spref = get_state_players(mm);
|
||||
if (orig_spref.size() != mm->num_states())
|
||||
throw std::runtime_error("Inconsistent \"state-player\"");
|
||||
|
||||
if (std::any_of(mm->edges().begin(), mm->edges().end(),
|
||||
[&](const auto& e){return orig_spref[e.src]
|
||||
== orig_spref[e.dst]; }))
|
||||
throw std::runtime_error("Arena is not alternating!");
|
||||
|
||||
|
||||
// Check if finite traces exist
|
||||
// If so, deactivate fast minimization
|
||||
// todo : this is overly conservative
|
||||
|
|
@ -3479,10 +3489,7 @@ namespace spot
|
|||
if (premin == -1)
|
||||
return mm;
|
||||
else
|
||||
{
|
||||
auto mm_res = minimize_mealy_fast(mm, premin == 1);
|
||||
return mm_res;
|
||||
}
|
||||
return minimize_mealy_fast(mm, premin == 1);
|
||||
};
|
||||
|
||||
const_twa_graph_ptr mmw = do_premin();
|
||||
|
|
@ -3490,11 +3497,7 @@ namespace spot
|
|||
|
||||
// 0 -> "Env" next is input props
|
||||
// 1 -> "Player" next is output prop
|
||||
auto spptr =
|
||||
mmw->get_named_prop<std::vector<bool>>("state-player");
|
||||
if (!spptr)
|
||||
throw std::runtime_error("\"state-player\" must be defined!");
|
||||
const auto& spref = *spptr;
|
||||
const auto& spref = get_state_players(mmw);
|
||||
assert((spref.size() == mmw->num_states())
|
||||
&& "Inconsistent state players");
|
||||
|
||||
|
|
|
|||
|
|
@ -193,14 +193,18 @@ namespace spot
|
|||
|
||||
// If a completion is demanded we might have to create sinks
|
||||
// Sink controlled by player
|
||||
auto get_sink_con_state = [&split, um = unsat_mark](bool create = true)
|
||||
unsigned sink_con = -1u;
|
||||
unsigned sink_env = -1u;
|
||||
auto get_sink_con_state = [&split, &sink_con, &sink_env,
|
||||
um = unsat_mark]
|
||||
(bool create = true)
|
||||
{
|
||||
static unsigned sink_con=-1u;
|
||||
if (SPOT_UNLIKELY((sink_con == -1u) && create))
|
||||
{
|
||||
sink_con = split->new_states(2);
|
||||
split->new_edge(sink_con, sink_con+1, bddtrue, um);
|
||||
split->new_edge(sink_con+1, sink_con, bddtrue, um);
|
||||
sink_con = split->new_state();
|
||||
sink_env = split->new_state();
|
||||
split->new_edge(sink_con, sink_env, bddtrue, um);
|
||||
split->new_edge(sink_env, sink_con, bddtrue, um);
|
||||
}
|
||||
return sink_con;
|
||||
};
|
||||
|
|
@ -331,14 +335,95 @@ namespace spot
|
|||
// All "new" states belong to the player
|
||||
std::fill(owner->begin()+aut->num_states(), owner->end(), true);
|
||||
// Check if sinks have been created
|
||||
if (get_sink_con_state(false) != -1u)
|
||||
owner->at(get_sink_con_state(false)) = false;
|
||||
if (sink_env != -1u)
|
||||
owner->at(sink_env) = false;
|
||||
split->set_named_prop("state-player", owner);
|
||||
|
||||
// Done
|
||||
return split;
|
||||
}
|
||||
|
||||
void
|
||||
split_2step_fast_here(const twa_graph_ptr& aut, const bdd& output_bdd)
|
||||
{
|
||||
struct dst_cond_color_t
|
||||
{
|
||||
std::pair<unsigned, int> dst_cond;
|
||||
acc_cond::mark_t color;
|
||||
};
|
||||
|
||||
auto hasher = [](const dst_cond_color_t& dcc) noexcept
|
||||
{
|
||||
return dcc.color.hash() ^ pair_hash()(dcc.dst_cond);
|
||||
};
|
||||
auto equal = [](const dst_cond_color_t& dcc1,
|
||||
const dst_cond_color_t& dcc2) noexcept
|
||||
{
|
||||
return (dcc1.dst_cond == dcc2.dst_cond)
|
||||
&& (dcc1.color == dcc2.color);
|
||||
};
|
||||
|
||||
std::unordered_map<dst_cond_color_t, unsigned,
|
||||
decltype(hasher),
|
||||
decltype(equal)> player_map(aut->num_edges(),
|
||||
hasher, equal);
|
||||
|
||||
auto get_ps = [&](unsigned dst, const bdd& ocond,
|
||||
acc_cond::mark_t color)
|
||||
{
|
||||
dst_cond_color_t key{std::make_pair(dst, ocond.id()),
|
||||
color};
|
||||
auto [it, inserted] =
|
||||
player_map.try_emplace(key, aut->num_states() + 1);
|
||||
if (!inserted)
|
||||
return it->second;
|
||||
unsigned ns = aut->new_state();
|
||||
assert(ns == it->second);
|
||||
aut->new_edge(ns, dst, ocond, color);
|
||||
return ns;
|
||||
};
|
||||
|
||||
std::vector<unsigned> to_treat(aut->num_edges());
|
||||
std::transform(aut->edges().begin(), aut->edges().end(),
|
||||
to_treat.begin(), [&](const auto& e)
|
||||
{ return aut->edge_number(e); });
|
||||
|
||||
std::for_each(to_treat.begin(), to_treat.end(),
|
||||
[&](unsigned eidx)
|
||||
{
|
||||
const auto& e = aut->edge_storage(eidx);
|
||||
bdd incond = bdd_exist(e.cond, output_bdd);
|
||||
bdd outcond = bdd_existcomp(e.cond, output_bdd);
|
||||
assert(((incond&outcond) == e.cond)
|
||||
&& "Precondition violated");
|
||||
// Modify
|
||||
// Create new state and trans
|
||||
unsigned new_dst = get_ps(e.dst, outcond, e.acc);
|
||||
// redirect
|
||||
aut->edge_storage(eidx).dst = new_dst;
|
||||
aut->edge_storage(eidx).cond = incond;
|
||||
});
|
||||
|
||||
auto* sp_ptr =
|
||||
aut->get_or_set_named_prop<std::vector<bool>>("state-player");
|
||||
|
||||
sp_ptr->resize(aut->num_states());
|
||||
std::fill(sp_ptr->begin(), sp_ptr->end(), false);
|
||||
for (auto& eit : player_map)
|
||||
(*sp_ptr)[eit.second] = true;
|
||||
//Done
|
||||
}
|
||||
|
||||
twa_graph_ptr
|
||||
split_2step_fast(const const_twa_graph_ptr& aut, const bdd& output_bdd)
|
||||
{
|
||||
auto aut2 = make_twa_graph(aut, twa::prop_set::all());
|
||||
aut2->copy_acceptance_of(aut);
|
||||
aut2->set_named_prop<bdd>("synthesis-output", new bdd(output_bdd));
|
||||
split_2step_fast_here(aut2, output_bdd);
|
||||
return aut2;
|
||||
}
|
||||
|
||||
twa_graph_ptr
|
||||
unsplit_2step(const const_twa_graph_ptr& aut)
|
||||
{
|
||||
|
|
@ -423,9 +508,13 @@ namespace spot
|
|||
assert((sp[arena->get_init_state_number()] == false)
|
||||
&& "Env needs to have first turn!");
|
||||
|
||||
assert(std::all_of(arena->edges().begin(), arena->edges().end(),
|
||||
assert(std::none_of(arena->edges().begin(), arena->edges().end(),
|
||||
[&sp](const auto& e)
|
||||
{ return sp.at(e.src) != sp.at(e.dst); }));
|
||||
{ bool same_player = sp.at(e.src) == sp.at(e.dst);
|
||||
if (same_player)
|
||||
std::cerr << e.src << " and " << e.dst << " belong to same "
|
||||
<< "player, arena not alternating!\n";
|
||||
return same_player; }));
|
||||
|
||||
auto strat_split = spot::make_twa_graph(arena->get_dict());
|
||||
strat_split->copy_ap_of(arena);
|
||||
|
|
@ -445,7 +534,7 @@ namespace spot
|
|||
size_t operator()(const dca& d) const noexcept
|
||||
{
|
||||
return pair_hash()(std::make_pair(d.dst, d.condvar))
|
||||
^ d.acc.hash();
|
||||
^ wang32_hash(d.acc.hash());
|
||||
}
|
||||
};
|
||||
struct dca_equal
|
||||
|
|
@ -453,7 +542,7 @@ namespace spot
|
|||
bool operator()(const dca& d1, const dca& d2) const noexcept
|
||||
{
|
||||
return std::tie(d1.dst, d1.condvar, d1.acc)
|
||||
== std::tie(d2.dst, d2.condvar, d2.acc);
|
||||
== std::tie(d2.dst, d2.condvar, d2.acc);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -482,16 +571,16 @@ namespace spot
|
|||
// Check if there exists already a local player state
|
||||
// that has the same dst, cond and (if keep_acc is true) acc
|
||||
auto get_spl = [&](unsigned dst, const bdd& cond, acc_cond::mark_t acc)
|
||||
{
|
||||
dca d{dst, (unsigned) cond.id(), acc};
|
||||
auto it = p_map.find(d);
|
||||
if (it != p_map.end())
|
||||
return it->second;
|
||||
unsigned ns = strat_split->new_state();
|
||||
p_map[d] = ns;
|
||||
strat_split->new_edge(ns, dst, cond, acc);
|
||||
return ns;
|
||||
};
|
||||
{
|
||||
dca d{dst, (unsigned) cond.id(), acc};
|
||||
auto it = p_map.find(d);
|
||||
if (it != p_map.end())
|
||||
return it->second;
|
||||
unsigned ns = strat_split->new_state();
|
||||
p_map[d] = ns;
|
||||
strat_split->new_edge(ns, dst, cond, acc);
|
||||
return ns;
|
||||
};
|
||||
|
||||
while (!todo.empty())
|
||||
{
|
||||
|
|
@ -522,10 +611,10 @@ namespace spot
|
|||
|
||||
// Sorting edges in place
|
||||
auto comp_edge = [](const auto& e1, const auto& e2)
|
||||
{
|
||||
return std::tuple(e1.dst, e1.acc, e1.cond.id())
|
||||
< std::tuple(e2.dst, e2.acc, e2.cond.id());
|
||||
};
|
||||
{
|
||||
return std::tuple(e1.dst, e1.acc, e1.cond.id())
|
||||
< std::tuple(e2.dst, e2.acc, e2.cond.id());
|
||||
};
|
||||
auto sort_edges_of =
|
||||
[&, &split_graph = strat_split->get_graph()](unsigned s)
|
||||
{
|
||||
|
|
@ -597,8 +686,6 @@ namespace spot
|
|||
});
|
||||
};
|
||||
|
||||
// print_hoa(std::cout, strat_split) << '\n';
|
||||
|
||||
const unsigned n_sstrat = strat_split->num_states();
|
||||
std::vector<unsigned> remap(n_sstrat, -1u);
|
||||
bool changed_any;
|
||||
|
|
@ -633,10 +720,6 @@ namespace spot
|
|||
}
|
||||
}
|
||||
|
||||
// std::for_each(remap.begin(), remap.end(),
|
||||
// [](auto e){std::cout << e << ' ';});
|
||||
// std::cout << std::endl;
|
||||
|
||||
if (!changed_any)
|
||||
break;
|
||||
// Redirect changed targets and set possibly mergeable states
|
||||
|
|
@ -671,10 +754,6 @@ namespace spot
|
|||
}
|
||||
}
|
||||
|
||||
// std::for_each(remap.begin(), remap.end(), [](auto e)
|
||||
// {std::cout << e << ' '; });
|
||||
// std::cout << std::endl;
|
||||
|
||||
if (!changed_any)
|
||||
break;
|
||||
// Redirect changed targets and set possibly mergeable states
|
||||
|
|
@ -688,8 +767,6 @@ namespace spot
|
|||
}
|
||||
}
|
||||
|
||||
// print_hoa(std::cout, strat_split) << std::endl;
|
||||
|
||||
// Defrag and alternate
|
||||
if (remap[strat_split->get_init_state_number()] != -1u)
|
||||
strat_split->set_init_state(remap[strat_split->get_init_state_number()]);
|
||||
|
|
@ -702,16 +779,7 @@ namespace spot
|
|||
|
||||
strat_split->defrag_states(remap, st);
|
||||
|
||||
// unsigned n_old;
|
||||
// do
|
||||
// {
|
||||
// n_old = strat_split->num_edges();
|
||||
// strat_split->merge_edges();
|
||||
// strat_split->merge_states();
|
||||
// } while (n_old != strat_split->num_edges());
|
||||
|
||||
alternate_players(strat_split, false, false);
|
||||
// print_hoa(std::cout, strat_split) << std::endl;
|
||||
// What we do now depends on whether we unsplit or not
|
||||
if (unsplit)
|
||||
{
|
||||
|
|
@ -1164,6 +1232,34 @@ namespace spot
|
|||
const std::vector<std::string>& output_aps,
|
||||
game_info &gi)
|
||||
{
|
||||
auto vs = gi.verbose_stream;
|
||||
|
||||
if (vs)
|
||||
*vs << "trying to create strategy directly\n";
|
||||
|
||||
auto ret_sol_maybe = [&vs]()
|
||||
{
|
||||
if (vs)
|
||||
*vs << "direct strategy might exist but was not found.\n";
|
||||
return strategy_like_t{0, nullptr, bddfalse};
|
||||
};
|
||||
auto ret_sol_none = [&vs]()
|
||||
{
|
||||
if (vs)
|
||||
*vs << "no direct strategy exists.\n";
|
||||
return strategy_like_t{-1, nullptr, bddfalse};
|
||||
};
|
||||
auto ret_sol_exists = [&vs](auto strat)
|
||||
{
|
||||
if (vs)
|
||||
{
|
||||
*vs << "direct strategy was found.\n"
|
||||
<< "direct strat has " << strat->num_states()
|
||||
<< " states and " << strat->num_sets() << " colors\n";
|
||||
}
|
||||
return strategy_like_t{1, strat, bddfalse};
|
||||
};
|
||||
|
||||
// We need a lot of look-ups
|
||||
auto output_aps_set = std::set<std::string>(output_aps.begin(),
|
||||
output_aps.end());
|
||||
|
|
@ -1174,7 +1270,7 @@ namespace spot
|
|||
if (is_and)
|
||||
{
|
||||
if (f.size() != 2)
|
||||
return {0, nullptr, bddfalse};
|
||||
return ret_sol_maybe();
|
||||
if (f[1].is(op::G))
|
||||
f = formula::And({f[1], f[0]});
|
||||
f_equiv = f[1];
|
||||
|
|
@ -1188,7 +1284,7 @@ namespace spot
|
|||
|
||||
if (!f_equiv.is(op::Equiv) || (!f_g.is_tt() && (!f_g.is(op::G)
|
||||
|| !f_g[0].is_boolean())))
|
||||
return {0, nullptr, bddfalse};
|
||||
return ret_sol_maybe();
|
||||
// stopwatch sw;
|
||||
twa_graph_ptr res;
|
||||
|
||||
|
|
@ -1215,7 +1311,7 @@ namespace spot
|
|||
}
|
||||
// We need to have f(inputs) <-> f(outputs)
|
||||
if (has_right_ins || has_left_outs || !has_right_outs)
|
||||
return {0, nullptr, bddfalse};
|
||||
return ret_sol_maybe();
|
||||
|
||||
bool is_gf_bool_right = right.is({op::G, op::F});
|
||||
bool is_fg_bool_right = right.is({op::F, op::G});
|
||||
|
|
@ -1234,7 +1330,7 @@ namespace spot
|
|||
{
|
||||
bool right_bool = right[0][0].is_boolean();
|
||||
if (!right_bool)
|
||||
return {0, nullptr, bddfalse};
|
||||
return ret_sol_maybe();
|
||||
auto trans = create_translator(gi);
|
||||
trans.set_type(postprocessor::Buchi);
|
||||
trans.set_pref(postprocessor::Deterministic | postprocessor::Complete);
|
||||
|
|
@ -1246,12 +1342,17 @@ namespace spot
|
|||
sw.start();
|
||||
res = trans.run(left);
|
||||
if (bv)
|
||||
bv->trans_time = sw.stop();
|
||||
{
|
||||
auto delta = sw.stop();
|
||||
bv->trans_time += delta;
|
||||
if (vs)
|
||||
*vs << "tanslating formula done in " << delta << " seconds\n";
|
||||
}
|
||||
|
||||
for (auto& out : right_outs)
|
||||
res->register_ap(out.ap_name());
|
||||
if (!is_deterministic(res))
|
||||
return {0, nullptr, bddfalse};
|
||||
return ret_sol_maybe();
|
||||
bdd form_bdd = bddtrue;
|
||||
if (is_and)
|
||||
{
|
||||
|
|
@ -1262,7 +1363,7 @@ namespace spot
|
|||
formula_to_bdd(f_g[0],
|
||||
res->get_dict(), res);
|
||||
if (bdd_exist(form_bdd, output_bdd) != bddtrue)
|
||||
return {0, nullptr, bddfalse};
|
||||
return ret_sol_maybe();
|
||||
}
|
||||
bdd right_bdd = formula_to_bdd(right_sub, res->get_dict(), res);
|
||||
bdd neg_right_bdd = bdd_not(right_bdd);
|
||||
|
|
@ -1283,25 +1384,11 @@ namespace spot
|
|||
}
|
||||
// form_bdd has to be true all the time. So we cannot only do it
|
||||
// between SCCs.
|
||||
e.cond &= form_bdd;
|
||||
if (e.cond == bddfalse)
|
||||
return {-1, nullptr, bddfalse};
|
||||
if (!bdd_have_common_assignment(e.cond, form_bdd))
|
||||
return ret_sol_none();
|
||||
e.acc = {};
|
||||
}
|
||||
|
||||
if (bv)
|
||||
{
|
||||
auto& vs = gi.verbose_stream;
|
||||
if (vs)
|
||||
{
|
||||
*vs << "translating formula into strategy done in "
|
||||
<< bv->trans_time << " seconds\n";
|
||||
*vs << "automaton has " << res->num_states()
|
||||
<< " states and " << res->num_sets() << " colors\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bdd output_bdd = bddtrue;
|
||||
for (auto &out : output_aps_set)
|
||||
output_bdd &= bdd_ithvar(res->register_ap(out));
|
||||
|
|
@ -1310,9 +1397,9 @@ namespace spot
|
|||
res->set_acceptance(acc_cond::acc_code::t());
|
||||
|
||||
res->prop_complete(trival::maybe());
|
||||
return {1, res, bddfalse};
|
||||
return ret_sol_exists(res);
|
||||
}
|
||||
return {0, nullptr, bddfalse};
|
||||
return ret_sol_maybe();
|
||||
}
|
||||
|
||||
} // spot
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
namespace spot
|
||||
{
|
||||
/// \brief make each transition (conditionally, see do__simpify)
|
||||
/// \brief make each transition (conditionally, see do_simplify)
|
||||
/// a 2-step transition
|
||||
///
|
||||
/// Given a set of atomic propositions I, split each transition
|
||||
|
|
@ -56,6 +56,22 @@ namespace spot
|
|||
split_2step(const const_twa_graph_ptr& aut,
|
||||
const bdd& output_bdd, bool complete_env, bool do_simplify);
|
||||
|
||||
|
||||
/// \brief make each transition a 2-step transition.
|
||||
/// This algorithm is only applicable if all transitions of the
|
||||
/// graph have the form p -- ins & outs --> q.
|
||||
/// That is they are a conjunction of a condition over the input
|
||||
/// propositions ins and a condition over the output propositions outs
|
||||
/// \param aut automaton to be transformed
|
||||
/// \param output_bdd conjunction of all output AP, all APs not present
|
||||
/// are treated as inputs
|
||||
SPOT_API void
|
||||
split_2step_fast_here(const twa_graph_ptr& aut, const bdd& output_bdd);
|
||||
|
||||
SPOT_API twa_graph_ptr
|
||||
split_2step_fast(const const_twa_graph_ptr& aut, const bdd& output_bdd);
|
||||
|
||||
|
||||
/// \brief the reverse of split_2step
|
||||
///
|
||||
/// \note: This function relies on the named property "state-player"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue