Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SpotProduct.cpp
Go to the documentation of this file.
2
3#include <deque>
4
11
13
14typedef std::pair<unsigned, unsigned> product_state;
15
17#ifdef STORM_HAVE_SPOT
18 size_t operator()(product_state s) const noexcept {
19 return spot::wang32_hash(s.first ^ spot::wang32_hash(s.second));
20 }
21#else
22 size_t operator()(product_state) const {
23 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException, "Storm is compiled without Spot support.");
24 }
25#endif
26};
27
29typedef std::vector<std::pair<unsigned, unsigned>> product_states;
30
31std::shared_ptr<storm::automata::DeterministicAutomaton> ltl2daSpotProduct(storm::logic::MultiObjectiveFormula const& formula,
33 std::vector<uint64_t>& acceptanceConditions) {
34#ifdef STORM_HAVE_SPOT
35 bool first = true;
36 spot::twa_graph_ptr productAutomaton;
37 spot::bdd_dict_ptr dict = spot::make_bdd_dict();
38 uint64_t countAccept = 0;
39 // iterate over all subformulae
40 for (const std::shared_ptr<const storm::logic::Formula>& subFormula : formula.getSubformulas()) {
41 // get the formula in the right format
42 STORM_LOG_ASSERT(subFormula->isProbabilityOperatorFormula(), "Subformula " << *subFormula << " has unexpected type.");
43 auto const& pathFormula = subFormula->asProbabilityOperatorFormula().getSubformula().asPathFormula();
44
45 // get map of state-expressions to propositions
46 std::shared_ptr<storm::logic::Formula> ltlFormula1 = storm::logic::ExtractMaximalStateFormulasVisitor::extract(pathFormula, extracted);
47
48 // parse the formula in spot-format
49 std::string prefixLtl = ltlFormula1->toPrefixString();
50 spot::parsed_formula spotPrefixLtl = spot::parse_prefix_ltl(prefixLtl);
51 if (!spotPrefixLtl.errors.empty()) {
52 std::ostringstream errorMsg;
53 spotPrefixLtl.format_errors(errorMsg);
54 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
55 "Spot could not parse formula: " << prefixLtl << ": " << errorMsg.str() << ".");
56 }
57 spot::formula spotFormula = spotPrefixLtl.f;
58
59 // Request a deterministic, complete automaton with state-based acceptance with parity-acceptance condition (should result in Streett)
60 spot::translator trans = spot::translator(dict);
61 trans.set_type(spot::postprocessor::Parity);
62 trans.set_pref(spot::postprocessor::Deterministic | spot::postprocessor::SBAcc | spot::postprocessor::Complete | spot::postprocessor::Colored);
63 // aut contains the Spot-automaton
64 auto aut = trans.run(spotFormula);
65
66 acceptanceConditions.push_back(countAccept);
67 countAccept += aut->get_acceptance().top_conjuncts().size();
68 if (first) {
69 // the first automaton does not need to be merged with the product automaton
70 productAutomaton = aut;
71 first = false;
72 continue;
73 } else {
74 // create a product of the the new automaton and the already existing product automaton
75 spot::const_twa_graph_ptr left = aut;
76 spot::const_twa_graph_ptr right = productAutomaton;
77 unsigned left_state = left->get_init_state_number();
78 unsigned right_state = right->get_init_state_number();
79
80 auto res = spot::make_twa_graph(left->get_dict());
81 res->copy_ap_of(left);
82 res->copy_ap_of(right);
83
84 auto left_num = left->num_sets();
85 auto& left_acc = left->get_acceptance();
86 auto right_acc = right->get_acceptance() << left_num;
87 right_acc &= left_acc;
88
89 res->set_acceptance(left_num + right->num_sets(), right_acc);
90
91 auto merge_acc = [&](spot::acc_cond::mark_t ml, spot::acc_cond::mark_t mr) { return ml | (mr << left_num); };
92 std::unordered_map<product_state, unsigned, product_state_hash> s2n;
93 std::deque<std::pair<product_state, unsigned>> todo;
94
95 auto v = new product_states;
96 res->set_named_prop("product-states", v);
97
98 auto new_state = [&](unsigned left_state, unsigned right_state) -> unsigned {
99 product_state x(left_state, right_state);
100 auto p = s2n.emplace(x, 0);
101 if (p.second) // This is a new state
102 {
103 p.first->second = res->new_state();
104 todo.emplace_back(x, p.first->second);
105 STORM_LOG_ASSERT(p.first->second == v->size(), "State size mismatch.");
106 v->emplace_back(x);
107 }
108 return p.first->second;
109 };
110
111 res->set_init_state(new_state(left_state, right_state));
112 while (!todo.empty()) {
113 auto top = todo.front();
114 todo.pop_front();
115 for (auto& l : left->out(top.first.first)) {
116 for (auto& r : right->out(top.first.second)) {
117 auto cond = l.cond & r.cond;
118 if (cond == bddfalse) {
119 continue;
120 }
121 auto dst = new_state(l.dst, r.dst);
122 res->new_edge(top.second, dst, cond, merge_acc(l.acc, r.acc));
123 // If right is deterministic, we can abort immediately!
124 }
125 }
126 }
127
128 if (res->acc().is_f()) {
129 STORM_LOG_ASSERT(res->num_edges() == 0, "Expected no edges.");
130 res->prop_universal(true);
131 res->prop_complete(false);
132 res->prop_stutter_invariant(true);
133 res->prop_terminal(true);
134 res->prop_state_acc(true);
135 } else {
136 // The product of two non-deterministic automata could be
137 // deterministic. Likewise for non-complete automata.
138 if (left->prop_universal() && right->prop_universal()) {
139 res->prop_universal(true);
140 }
141 if (left->prop_complete() && right->prop_complete()) {
142 res->prop_complete(true);
143 }
144 if (left->prop_stutter_invariant() && right->prop_stutter_invariant()) {
145 res->prop_stutter_invariant(true);
146 }
147 if (left->prop_inherently_weak() && right->prop_inherently_weak()) {
148 res->prop_inherently_weak(true);
149 }
150 if (left->prop_weak() && right->prop_weak()) {
151 res->prop_weak(true);
152 }
153 if (left->prop_terminal() && right->prop_terminal()) {
154 res->prop_terminal(true);
155 }
156 res->prop_state_acc(left->prop_state_acc() && right->prop_state_acc());
157 }
158 productAutomaton = res;
159 }
160 }
161 acceptanceConditions.push_back(countAccept);
162
163 if (!(productAutomaton->get_acceptance().is_cnf())) {
164 // Transform the acceptance condition in disjunctive normal form and merge all the Fin-sets of each clause
165 productAutomaton = to_generalized_streett(productAutomaton, true);
166 }
167 std::stringstream autStream;
168 // Print reachable states in HOA format, implicit edges (i), state-based acceptance (s)
169 spot::print_hoa(autStream, productAutomaton, "is");
170
171 // parse the automaton into storm-format
173
174 return da;
175#else
176 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException, "Storm is compiled without Spot support.");
177 (void)formula;
178 (void)extracted;
179 (void)acceptanceConditions;
180#endif
181}
182
183} // namespace storm::modelchecker::helper::lexicographic::spothelper
std::shared_ptr< DeterministicAutomaton > ptr
static DeterministicAutomaton::ptr parse(std::istream &in)
static std::shared_ptr< Formula > extract(PathFormula const &f, ApToFormulaMap &extractedFormulas)
Finds state subformulae in f and replaces them by atomic propositions.
std::map< std::string, std::shared_ptr< Formula const > > ApToFormulaMap
std::vector< std::shared_ptr< Formula const > > const & getSubformulas() const
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
std::vector< std::pair< unsigned, unsigned > > product_states
std::shared_ptr< storm::automata::DeterministicAutomaton > ltl2daSpotProduct(storm::logic::MultiObjectiveFormula const &formula, storm::logic::ExtractMaximalStateFormulasVisitor::ApToFormulaMap &extracted, std::vector< uint64_t > &acceptanceConditions)
Function that creates a determinitistic automaton with Streett-acceptance condition.