19namespace lexicographic {
21template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
22std::pair<std::shared_ptr<storm::transformer::DAProduct<SparseModelType>>, std::vector<uint>>
26 std::vector<uint> acceptanceConditions;
29 std::shared_ptr<storm::automata::DeterministicAutomaton> productAutomaton =
spothelper::ltl2daSpotProduct(this->formula, extracted, acceptanceConditions);
32 std::map<std::string, storm::storage::BitVector> apSatSets = computeApSets(extracted, formulaChecker);
34 std::vector<storm::storage::BitVector> statesForAP;
35 for (
const std::string& ap : apSet.
getAPs()) {
36 auto it = apSatSets.find(ap);
37 STORM_LOG_THROW(it != apSatSets.end(), storm::exceptions::InvalidOperationException,
38 "Deterministic automaton has AP " << ap <<
", does not appear in formula");
40 statesForAP.push_back(std::move(it->second));
45 if (this->hasRelevantStates()) {
46 statesOfInterest = this->getRelevantStates();
54 std::shared_ptr<storm::transformer::DAProduct<SparseModelType>> product =
55 productBuilder.
build<SparseModelType>(model.getTransitionMatrix(), statesOfInterest);
57 return std::make_pair(product, acceptanceConditions);
60template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
61std::pair<storm::storage::MaximalEndComponentDecomposition<ValueType>, std::vector<std::vector<bool>>>
67 productModel->getProductModel().getBackwardTransitions(), allowed);
69 std::vector<std::vector<bool>> bscc_satisfaction;
73 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> acceptancePairs = getStreettPairs(acceptance->getAcceptanceExpression());
74 STORM_LOG_ASSERT(!acceptancePairs.empty(),
"There are no accepting pairs, maybe you have a parity automaton?");
76 std::reverse(acceptancePairs.begin(), acceptancePairs.end());
80 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> sprime;
81 std::vector<bool> bsccAccepting;
82 for (uint i = 0; i < acceptanceConditions.size() - 1; i++) {
84 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> sprimeTemp(sprime);
86 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> sub = {acceptancePairs.begin() + acceptanceConditions[i],
87 acceptancePairs.begin() + acceptanceConditions[i + 1]};
88 sprimeTemp.insert(sprimeTemp.end(), sub.begin(), sub.end());
91 bool accepts = isAcceptingStreettConditions(mec, sprimeTemp, acceptance, productModel->getProductModel());
95 bsccAccepting.push_back(
true);
96 sprime.insert(sprime.end(), sub.begin(), sub.end());
98 bsccAccepting.push_back(
false);
101 bscc_satisfaction.push_back(bsccAccepting);
103 return std::pair<storm::storage::MaximalEndComponentDecomposition<ValueType>&, std::vector<std::vector<bool>>&>(mecs, bscc_satisfaction);
106template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
112 auto stStateResult = addSinkStates(mecs, productModel);
114 std::map<uint, uint_fast64_t> bccToStStateMapping = stStateResult.second;
119 auto compressionResult =
123 std::vector<std::vector<bool>> bccLexArrayCurrent(mecLexArray);
126 std::vector<uint_fast64_t> compressedToReducedMapping(compressionResult.matrix.getColumnCount());
127 std::iota(std::begin(compressedToReducedMapping), std::end(compressedToReducedMapping), 0);
131 for (uint condition = 0; condition < mecLexArray[0].size(); condition++) {
133 storm::storage::BitVector psiStates = getGoodStates(mecs, bccLexArrayCurrent, compressionResult.oldToNewStateMapping, condition,
134 transitionMatrix.
getColumnCount(), compressedToReducedMapping, bccToStStateMapping);
136 retResult.
values[condition] = 0;
141 std::vector<uint_fast64_t> newInitalStates;
143 solveOneReachability(newInitalStates, psiStates, transitionMatrix, originalMdp, compressedToReducedMapping, compressionResult.oldToNewStateMapping);
144 if (newInitalStates.empty()) {
145 retResult.
values[condition] = 0;
148 retResult.
values[condition] = res.values[newInitalStates[0]];
151 auto subsystem = getReducedSubsystem(transitionMatrix, res, newInitalStates, psiStates);
152 std::vector<uint_fast64_t> compressedToReducedMappingTemp;
153 compressedToReducedMappingTemp.reserve(compressedToReducedMapping.size());
155 for (uint_fast64_t newState : subsystem.newToOldStateIndexMapping) {
156 compressedToReducedMappingTemp.push_back(compressedToReducedMapping[newState]);
158 compressedToReducedMapping = compressedToReducedMappingTemp;
159 transitionMatrix = subsystem.model->getTransitionMatrix();
164template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
165std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr>
167 storm::automata::AcceptanceCondition::acceptance_expr::ptr
const& current) {
168 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> accConds;
169 if (current->isOR()) {
170 accConds.push_back(current);
171 }
else if (current->isAND()) {
172 auto leftAccConds = getStreettPairs(current->getLeft());
173 accConds.reserve(accConds.size() + distance(leftAccConds.begin(), leftAccConds.end()));
174 accConds.insert(accConds.end(), leftAccConds.begin(), leftAccConds.end());
175 auto rightAccConds = getStreettPairs(current->getRight());
176 accConds.reserve(accConds.size() + distance(rightAccConds.begin(), rightAccConds.end()));
177 accConds.insert(accConds.end(), rightAccConds.begin(), rightAccConds.end());
179 STORM_LOG_THROW(
true, storm::exceptions::NotImplementedException,
"Finding StreettPairs - unknown type " + current->toString());
185 storm::automata::AcceptanceCondition::acceptance_expr::ptr
const& setPointer) {
186 STORM_LOG_THROW(setPointer->isAtom(), storm::exceptions::NotImplementedException,
"Not an Atom!");
187 const cpphoafparser::AtomAcceptance& atom = setPointer->getAtom();
192template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
193bool lexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::isAcceptingStreettConditions(
198 std::for_each(scc.
begin(), scc.
end(), [&mecStates](
auto const& state) { mecStates.set(state.first); });
199 auto mecChoices = model.getTransitionMatrix().getRowFilter(mecStates, mecStates);
201 if (mecChoices.empty()) {
205 auto incomingChoicesMatrix = model.getTransitionMatrix().transpose();
206 auto incomingStatesMatrix = model.getBackwardTransitions();
207 bool changedSomething =
true;
208 while (changedSomething) {
210 changedSomething =
false;
212 auto subMecDecomposition =
217 for (storm::automata::AcceptanceCondition::acceptance_expr::ptr
const& streettPair : acceptancePairs) {
220 auto infSet =
getStreettSet(acceptance, streettPair->getRight());
221 auto finSet =
getStreettSet(acceptance, streettPair->getLeft());
222 if (mec.containsAnyState(infSet)) {
228 for (
auto const& stateToChoice : mec) {
229 StateType state = stateToChoice.first;
230 if (finSet.get(state)) {
232 mecStates.
set(state,
false);
234 auto incChoices = incomingChoicesMatrix.getRow(state);
235 std::for_each(incChoices.begin(), incChoices.end(), [&mecChoices](
auto const& entry) { mecChoices.set(entry.getColumn(), false); });
236 changedSomething =
true;
244 auto subMecDecomposition =
246 if (subMecDecomposition.empty()) {
255template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
258 std::vector<uint_fast64_t>
const& oldToNewStateMapping, uint
const& condition, uint
const numStates,
259 std::vector<uint_fast64_t>
const& compressedToReducedMapping, std::map<uint, uint_fast64_t>
const& bccToStStateMapping) {
261 STORM_LOG_ASSERT(condition < bccLexArray[0].size(),
"Condition is not in Lex-Array!");
262 std::vector<uint_fast64_t> goodStates;
263 for (uint i = 0;
i < bcc.
size();
i++) {
264 std::vector<bool>
const& bccLex = bccLexArray[
i];
265 if (bccLex[condition]) {
266 uint_fast64_t bccStateOld = bccToStStateMapping.at(i);
267 uint_fast64_t bccState = oldToNewStateMapping[bccStateOld];
268 auto pointer = std::find(compressedToReducedMapping.begin(), compressedToReducedMapping.end(), bccState);
269 if (pointer != compressedToReducedMapping.end()) {
271 uint_fast64_t bccStateReduced = pointer - compressedToReducedMapping.begin();
272 goodStates.push_back(bccStateReduced);
276 return {numStates, goodStates};
279template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
280MDPSparseModelCheckingHelperReturnType<ValueType> lexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::solveOneReachability(
282 SparseModelType
const& originalMdp, std::vector<uint_fast64_t>
const& compressedToReducedMapping, std::vector<uint_fast64_t>
const& oldToNewStateMapping) {
295 auto pointer = std::find(compressedToReducedMapping.begin(), compressedToReducedMapping.end(), oldToNewStateMapping[pos - 1]);
296 if (pointer != compressedToReducedMapping.end()) {
297 newInitalStates.push_back(pointer - compressedToReducedMapping.begin());
302 ModelCheckerHint hint;
305 phiStates, psiStates,
false,
true, hint);
309template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
311lexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::getReducedSubsystem(
314 std::vector<std::vector<uint>> optimalActions;
315 std::vector<uint_fast64_t> keptActions;
316 std::vector<uint_fast64_t>
const& rowGroupIndices = transitionMatrix.
getRowGroupIndices();
319 for (uint currentState = 0; currentState < reachabilityResult.values.size(); currentState++) {
320 std::vector<uint> goodActionsForState;
321 uint_fast64_t bestAction = reachabilityResult.scheduler->getChoice(currentState).getDeterministicChoice();
325 bestActionValue += rowEntry.getValue() * reachabilityResult.values[rowEntry.getColumn()];
327 uint lastAction = rowGroupIndices[currentState] + transitionMatrix.
getRowGroupSize(currentState);
329 for (uint action = rowGroupIndices[currentState]; action < lastAction; action++) {
331 for (
const auto& rowEntry : transitionMatrix.getRow(action)) {
332 actionValue += rowEntry.getValue() * reachabilityResult.values[rowEntry.getColumn()];
334 if (actionValue == bestActionValue) {
335 goodActionsForState.push_back(action);
336 keptActions.push_back(action);
339 optimalActions.push_back(goodActionsForState);
343 transformer::SubsystemBuilderOptions sbo;
344 sbo.fixDeadlocks =
true;
346 stateLabelling.addLabel(
"init");
347 for (
auto const& state : newInitalStates) {
348 stateLabelling.addLabelToState(
"init", state);
352 return subsystemReturn;
355template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
356std::pair<storm::storage::SparseMatrix<ValueType>, std::map<uint, uint_fast64_t>>
357lexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::addSinkStates(
361 uint countNewRows = 0;
362 std::map<uint_fast64_t, uint> stateToMEC;
363 for (uint i = 0;
i < mecs.
size();
i++) {
365 countNewRows += bcc.
size() + 1;
366 for (
auto const& stateAndChoices : bcc) {
368 uint_fast64_t bccState = stateAndChoices.first;
369 stateToMEC[bccState] =
i;
376 std::map<uint, uint_fast64_t> sTstatesForBCC;
378 uint_fast64_t newRow = 0;
379 uint_fast64_t oldRowCounting = 0;
382 for (uint_fast64_t newRowGroup = 0; newRowGroup < matrix.
getColumnCount(); ++newRowGroup) {
384 builder.newRowGroup(newRow);
386 for (; oldRowCounting < oldRowGroupIndices[newRowGroup + 1]; oldRowCounting++) {
387 for (
auto const& entry : matrix.getRow(oldRowCounting)) {
389 builder.addNextValue(newRow, entry.getColumn(), entry.getValue());
394 if (stateToMEC.find(newRowGroup) != stateToMEC.end()) {
395 if (sTstatesForBCC.find(stateToMEC[newRowGroup]) == sTstatesForBCC.end()) {
396 sTstatesForBCC[stateToMEC[newRowGroup]] = newestRowGroup;
399 builder.addNextValue(newRow, sTstatesForBCC[stateToMEC[newRowGroup]], storm::utility::one<ValueType>());
405 for (uint_fast64_t newRowGroup = matrix.
getColumnCount(); newRowGroup < numRowGroups; newRowGroup++) {
406 builder.newRowGroup(newRow);
407 builder.addNextValue(newRow, newRowGroup, storm::utility::one<ValueType>());
411 return {newMatrix, sTstatesForBCC};
414template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
415std::map<std::string, storm::storage::BitVector> lexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::computeApSets(
416 std::map<std::string, std::shared_ptr<storm::logic::Formula const>>
const& extracted, CheckFormulaCallback
const& formulaChecker) {
417 std::map<std::string, storm::storage::BitVector> apSets;
418 for (
auto& p : extracted) {
419 STORM_LOG_DEBUG(
" Computing satisfaction set for atomic proposition \"" << p.first <<
"\" <=> " << *p.second <<
"...");
420 apSets[p.first] = formulaChecker(*p.second);
425template class lexicographic::lexicographicModelCheckerHelper<storm::models::sparse::Mdp<double>, double,
true>;
426template class lexicographic::lexicographicModelCheckerHelper<storm::models::sparse::Mdp<double>, double,
false>;
427template class lexicographic::lexicographicModelCheckerHelper<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber,
true>;
428template class lexicographic::lexicographicModelCheckerHelper<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber,
false>;