17namespace modelchecker {
20template<
typename ValueType,
bool Nondeterministic>
22 : _transitionMatrix(transitionMatrix) {
26template<
typename ValueType,
bool Nondeterministic>
29 STORM_LOG_ASSERT(this->isProduceSchedulerSet(),
"Trying to get the produced optimal choices although no scheduler was requested.");
31 "Trying to get the produced optimal choices but none were available. Was there a computation call before?");
33 return this->_schedulerHelper.get().extractScheduler(model, this->hasRelevantStates());
36template<
typename ValueType,
bool Nondeterministic>
45 auto apSets = computeApSets(extracted, formulaChecker);
47 STORM_LOG_INFO(
"Computing LTL probabilities for formula with " << apSets.size() <<
" atomic proposition(s).");
50 return computeLTLProbabilities(env, ltlFormula->asPathFormula(), apSets);
53template<
typename ValueType,
bool Nondeterministic>
55 std::map<std::string, std::shared_ptr<storm::logic::Formula const>>
const& extracted,
CheckFormulaCallback const& formulaChecker) {
56 std::map<std::string, storm::storage::BitVector> apSets;
57 for (
auto& p : extracted) {
58 STORM_LOG_DEBUG(
" Computing satisfaction set for atomic proposition \"" << p.first <<
"\" <=> " << *p.second <<
"...");
59 apSets[p.first] = formulaChecker(*p.second);
64template<
typename ValueType,
bool Nondeterministic>
71 STORM_LOG_INFO(
" TRUE -> all states accepting (assumes no deadlock in the model)");
78 std::vector<std::vector<automata::AcceptanceCondition::acceptance_expr::ptr>> dnf = acceptance.
extractFromDNF();
82 std::size_t accMECs = 0;
83 std::size_t allMECs = 0;
89 std::vector<uint64_t> stateToMec(transitionMatrix.
getRowGroupCount(), std::numeric_limits<uint64_t>::max());
92 for (uint64_t mec_counter = 0;
auto const& mec : mecs) {
93 for (
auto const& [state, _] : mec) {
94 stateToMec[state] = mec_counter;
95 mecStates.set(state,
true);
100 for (
auto const& conjunction : dnf) {
104 if (allowed.
empty()) {
109 if (literal->isTRUE()) {
111 }
else if (literal->isFALSE()) {
114 }
else if (literal->isAtom()) {
115 const cpphoafparser::AtomAcceptance& atom = literal->getAtom();
116 if (atom.getType() == cpphoafparser::AtomAcceptance::TEMPORAL_FIN) {
119 if (atom.isNegated()) {
130 if (allowed.
empty()) {
137 allMECs += allowedECs.size();
138 for (
const auto& ec : allowedECs) {
139 auto const representativeEcState = ec.begin()->first;
140 if (acceptingStates.get(representativeEcState)) {
145 bool accepting =
true;
147 if (literal->isTRUE()) {
150 }
else if (literal->isFALSE()) {
153 }
else if (literal->isAtom()) {
154 const cpphoafparser::AtomAcceptance& atom = literal->getAtom();
156 if (atom.getType() == cpphoafparser::AtomAcceptance::TEMPORAL_INF) {
157 if (atom.isNegated()) {
158 if (!ec.containsAnyState(~accSet)) {
163 if (!ec.containsAnyState(accSet)) {
169 }
else if (atom.getType() == cpphoafparser::AtomAcceptance::TEMPORAL_FIN) {
171 STORM_LOG_ASSERT(atom.isNegated() ? !ec.containsAnyState(~accSet) : !ec.containsAnyState(accSet),
172 "EC contains Fin-states, which should have been removed");
181 auto const mec_index = stateToMec[representativeEcState];
183 auto const& mec = mecs[mec_index];
186 for (
auto const& [state, _] : mec) {
187 acceptingStates.set(state);
190 if (this->isProduceSchedulerSet()) {
192 this->_schedulerHelper.get().saveProductEcChoices(acceptance, ec, mec, conjunction, product);
198 STORM_LOG_INFO(
"Found " << acceptingStates.getNumberOfSetBits() <<
" states in " << accMECs <<
" accepting MECs (considered " << allMECs <<
" MECs).");
200 return acceptingStates;
203template<
typename ValueType,
bool Nondeterministic>
204storm::storage::BitVector SparseLTLHelper<ValueType, Nondeterministic>::computeAcceptingBCCs(automata::AcceptanceCondition
const& acceptance,
207 transitionMatrix, storage::StronglyConnectedComponentDecompositionOptions().onlyBottomSccs().dropNaiveSccs());
210 std::size_t checkedBSCCs = 0, acceptingBSCCs = 0, acceptingBSCCStates = 0;
211 for (
auto& scc : bottomSccs) {
213 if (acceptance.isAccepting(scc)) {
215 for (
auto& state : scc) {
216 acceptingStates.set(state);
217 acceptingBSCCStates++;
221 STORM_LOG_INFO(
"BSCC analysis: " << acceptingBSCCs <<
" of " << checkedBSCCs <<
" BSCCs were acceptingStates (" << acceptingBSCCStates
222 <<
" states in acceptingStates BSCCs).");
223 return acceptingStates;
226template<
typename ValueType,
bool Nondeterministic>
231 std::vector<storm::storage::BitVector> statesForAP;
232 for (
const std::string& ap : apSet.
getAPs()) {
233 auto it = apSatSets.find(ap);
234 STORM_LOG_THROW(it != apSatSets.end(), storm::exceptions::InvalidOperationException,
235 "Deterministic automaton has AP " << ap <<
", does not appear in formula");
237 statesForAP.push_back(std::move(it->second));
242 if (this->hasRelevantStates()) {
243 statesOfInterest = this->getRelevantStates();
249 STORM_LOG_INFO(
"Building " + (Nondeterministic ? std::string(
"MDP-DA") : std::string(
"DTMC-DA")) +
" product with deterministic automaton, starting from "
253 auto product = productBuilder.build<
productModelType>(this->_transitionMatrix, statesOfInterest);
255 STORM_LOG_INFO(
"Product " + (Nondeterministic ? std::string(
"MDP-DA") : std::string(
"DTMC-DA")) +
" has "
260 if (this->isProduceSchedulerSet()) {
261 STORM_LOG_THROW(Nondeterministic, storm::exceptions::InvalidOperationException,
"Scheduler export only supported for nondeterministic models.");
262 this->_schedulerHelper.emplace(product->
getProductModel().getNumberOfStates());
267 if (Nondeterministic) {
277 if (acceptingStates.
empty()) {
278 STORM_LOG_INFO(
"No accepting states, skipping probability computation.");
279 if (this->isProduceSchedulerSet()) {
280 this->_schedulerHelper.get().setRandom();
282 std::vector<ValueType> numericResult(this->_transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
283 return numericResult;
286 STORM_LOG_INFO(
"Computing probabilities for reaching accepting components...");
293 if (this->isValueThresholdSet()) {
295 this->getValueThresholdValue(), std::move(soiProduct));
301 std::vector<ValueType> prodNumericResult;
303 if (Nondeterministic) {
307 acceptingStates, this->isQualitativeSet(),
308 this->isProduceSchedulerSet()
310 prodNumericResult = std::move(prodCheckResult.
values);
312 if (this->isProduceSchedulerSet()) {
313 this->_schedulerHelper.get().prepareScheduler(da.
getNumberOfStates(), acceptingStates, std::move(prodCheckResult.
scheduler), productBuilder,
314 product, statesOfInterest, this->_transitionMatrix);
320 acceptingStates, this->isQualitativeSet());
323 std::vector<ValueType> numericResult = product->
projectToOriginalModel(this->_transitionMatrix.getRowGroupCount(), prodNumericResult);
325 return numericResult;
328template<
typename ValueType,
bool Nondeterministic>
330 std::map<std::string, storm::storage::BitVector>& apSatSets) {
331 std::shared_ptr<storm::logic::Formula const> ltlFormula;
332 STORM_LOG_THROW((!Nondeterministic) || this->isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException,
333 "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
334 if (Nondeterministic && this->getOptimizationDirection() == OptimizationDirection::Minimize) {
337 STORM_LOG_INFO(
"Computing Pmin, proceeding with negated LTL formula.");
342 STORM_LOG_INFO(
"Resulting LTL path formula: " << ltlFormula->toString());
343 STORM_LOG_INFO(
" in prefix format: " << ltlFormula->toPrefixString());
346 std::shared_ptr<storm::automata::DeterministicAutomaton> da;
356 STORM_LOG_INFO(
"Deterministic automaton for LTL formula has " << da->getNumberOfStates() <<
" states, " << da->getAPSet().size()
357 <<
" atomic propositions and " << *da->getAcceptance()->getAcceptanceExpression()
358 <<
" as acceptance condition.\n");
360 std::vector<ValueType> numericResult = computeDAProductProbabilities(env, *da, apSatSets);
362 if (Nondeterministic && this->getOptimizationDirection() == OptimizationDirection::Minimize) {
364 for (
auto& value : numericResult) {
365 value = storm::utility::one<ValueType>() - value;
369 return numericResult;
375#ifdef STORM_HAVE_CARL
ModelCheckerEnvironment & modelchecker()
bool isLtl2daToolSet() const
std::string const & getLtl2daTool() const
const std::vector< std::string > & getAPs() const
storm::storage::BitVector & getAcceptanceSet(unsigned int index)
std::vector< std::vector< acceptance_expr::ptr > > extractFromDNF() const
acceptance_expr::ptr getAcceptanceExpression() const
const APSet & getAPSet() const
std::size_t getNumberOfStates() const
static std::shared_ptr< DeterministicAutomaton > ltl2daExternalTool(storm::logic::Formula const &f, std::string ltl2daTool)
Converts an LTL formula into a deterministic omega-automaton using an external LTL2DA tool.
static std::shared_ptr< DeterministicAutomaton > ltl2daSpot(storm::logic::Formula const &f, bool dnf)
Converts an LTL formula into a deterministic omega-automaton using the internal LTL2DA tool "Spot".
static std::vector< ValueType > computeUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool qualitative, ModelCheckerHint const &hint=ModelCheckerHint())
Helper class for LTL model checking.
std::function< storm::storage::BitVector(storm::logic::Formula const &)> CheckFormulaCallback
std::vector< ValueType > computeLTLProbabilities(Environment const &env, storm::logic::PathFormula const &formula, CheckFormulaCallback const &formulaChecker)
Computes the LTL probabilities.
SparseLTLHelper(storm::storage::SparseMatrix< ValueType > const &transitionMatrix)
Initializes the helper for a discrete time model (i.e.
static std::map< std::string, storm::storage::BitVector > computeApSets(std::map< std::string, std::shared_ptr< storm::logic::Formula const > > const &extracted, CheckFormulaCallback const &formulaChecker)
Computes the states that are satisfying the AP.
std::vector< ValueType > computeDAProductProbabilities(Environment const &env, storm::automata::DeterministicAutomaton const &da, std::map< std::string, storm::storage::BitVector > &apSatSets)
Computes the (maximizing) probabilities for the constructed DA product.
typename std::conditional< Nondeterministic, storm::models::sparse::Mdp< ValueType >, storm::models::sparse::Dtmc< ValueType > >::type productModelType
The type of the product model (DTMC or MDP) that is used during the computation.
static MDPSparseModelCheckingHelperReturnType< SolutionType > computeUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const &hint=ModelCheckerHint())
Base class for all sparse models.
void setRelevantValues(storm::storage::BitVector &&values)
A bit vector that is internally represented as a vector of 64-bit values.
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
void clear()
Removes all set bits from the bit vector.
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
This class represents the decomposition of a nondeterministic model into its maximal end components.
This class defines which action is chosen in a particular state of a non-deterministic model.
A class that holds a possibly non-square matrix in the compressed row storage format.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
This class represents the decomposition of a graph-like structure into its strongly connected compone...
#define STORM_LOG_INFO(message)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
Expression conjunction(std::vector< storm::expressions::Expression > const &expressions)
std::unique_ptr< storm::storage::Scheduler< ValueType > > scheduler
std::vector< ValueType > values