20namespace lexicographic {
22template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
23std::pair<std::shared_ptr<storm::transformer::DAProduct<SparseModelType>>, std::vector<uint64_t>>
27 std::vector<uint64_t> acceptanceConditions;
30 std::shared_ptr<storm::automata::DeterministicAutomaton> productAutomaton =
spothelper::ltl2daSpotProduct(this->formula, extracted, acceptanceConditions);
33 std::map<std::string, storm::storage::BitVector> apSatSets = computeApSets(extracted, formulaChecker);
35 std::vector<storm::storage::BitVector> statesForAP;
36 for (
const std::string& ap : apSet.
getAPs()) {
37 auto it = apSatSets.find(ap);
38 STORM_LOG_THROW(it != apSatSets.end(), storm::exceptions::InvalidOperationException,
39 "Deterministic automaton has AP " << ap <<
", does not appear in formula");
41 statesForAP.push_back(std::move(it->second));
46 if (this->hasRelevantStates()) {
47 statesOfInterest = this->getRelevantStates();
55 std::shared_ptr<storm::transformer::DAProduct<SparseModelType>> product =
56 productBuilder.
build<SparseModelType>(model.getTransitionMatrix(), statesOfInterest);
58 return std::make_pair(product, acceptanceConditions);
61template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
62std::pair<storm::storage::MaximalEndComponentDecomposition<ValueType>, std::vector<std::vector<bool>>>
68 productModel->getProductModel().getBackwardTransitions(), allowed);
70 std::vector<std::vector<bool>> bscc_satisfaction;
74 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> acceptancePairs = getStreettPairs(acceptance->getAcceptanceExpression());
75 STORM_LOG_ASSERT(!acceptancePairs.empty(),
"There are no accepting pairs, maybe you have a parity automaton?");
77 std::reverse(acceptancePairs.begin(), acceptancePairs.end());
81 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> sprime;
82 std::vector<bool> bsccAccepting;
83 for (uint64_t i = 0; i < acceptanceConditions.size() - 1; i++) {
85 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> sprimeTemp(sprime);
87 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> sub = {acceptancePairs.begin() + acceptanceConditions[i],
88 acceptancePairs.begin() + acceptanceConditions[i + 1]};
89 sprimeTemp.insert(sprimeTemp.end(), sub.begin(), sub.end());
92 bool accepts = isAcceptingStreettConditions(mec, sprimeTemp, acceptance, productModel->getProductModel());
96 bsccAccepting.push_back(
true);
97 sprime.insert(sprime.end(), sub.begin(), sub.end());
99 bsccAccepting.push_back(
false);
102 bscc_satisfaction.push_back(bsccAccepting);
104 return std::pair<storm::storage::MaximalEndComponentDecomposition<ValueType>&, std::vector<std::vector<bool>>&>(mecs, bscc_satisfaction);
107template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
113 auto stStateResult = addSinkStates(mecs, productModel);
115 std::map<uint64_t, uint64_t> bccToStStateMapping = stStateResult.second;
120 auto compressionResult =
124 std::vector<std::vector<bool>> bccLexArrayCurrent(mecLexArray);
127 std::vector<uint64_t> compressedToReducedMapping(compressionResult.matrix.getColumnCount());
128 std::iota(std::begin(compressedToReducedMapping), std::end(compressedToReducedMapping), 0);
132 for (uint64_t condition = 0; condition < mecLexArray[0].size(); condition++) {
134 storm::storage::BitVector psiStates = getGoodStates(mecs, bccLexArrayCurrent, compressionResult.oldToNewStateMapping, condition,
135 transitionMatrix.
getColumnCount(), compressedToReducedMapping, bccToStStateMapping);
137 retResult.
values[condition] = 0;
142 std::vector<uint64_t> newInitalStates;
144 solveOneReachability(newInitalStates, psiStates, transitionMatrix, originalMdp, compressedToReducedMapping, compressionResult.oldToNewStateMapping);
145 if (newInitalStates.empty()) {
146 retResult.
values[condition] = 0;
149 retResult.
values[condition] = res.values[newInitalStates[0]];
152 auto subsystem = getReducedSubsystem(transitionMatrix, res, newInitalStates, psiStates);
153 std::vector<uint64_t> compressedToReducedMappingTemp;
154 compressedToReducedMappingTemp.reserve(compressedToReducedMapping.size());
156 for (uint64_t newState : subsystem.newToOldStateIndexMapping) {
157 compressedToReducedMappingTemp.push_back(compressedToReducedMapping[newState]);
159 compressedToReducedMapping = compressedToReducedMappingTemp;
160 transitionMatrix = subsystem.model->getTransitionMatrix();
165template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
166std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr>
168 storm::automata::AcceptanceCondition::acceptance_expr::ptr
const& current) {
169 std::vector<storm::automata::AcceptanceCondition::acceptance_expr::ptr> accConds;
170 if (current->isOR()) {
171 accConds.push_back(current);
172 }
else if (current->isAND()) {
173 auto leftAccConds = getStreettPairs(current->getLeft());
174 accConds.reserve(accConds.size() + distance(leftAccConds.begin(), leftAccConds.end()));
175 accConds.insert(accConds.end(), leftAccConds.begin(), leftAccConds.end());
176 auto rightAccConds = getStreettPairs(current->getRight());
177 accConds.reserve(accConds.size() + distance(rightAccConds.begin(), rightAccConds.end()));
178 accConds.insert(accConds.end(), rightAccConds.begin(), rightAccConds.end());
180 STORM_LOG_THROW(
true, storm::exceptions::NotImplementedException,
"Finding StreettPairs - unknown type " + current->toString());
186 storm::automata::AcceptanceCondition::acceptance_expr::ptr
const& setPointer) {
187 STORM_LOG_THROW(setPointer->isAtom(), storm::exceptions::NotImplementedException,
"Not an Atom!");
188 const cpphoafparser::AtomAcceptance& atom = setPointer->getAtom();
193template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
194bool LexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::isAcceptingStreettConditions(
199 std::for_each(scc.
begin(), scc.
end(), [&mecStates](
auto const& state) { mecStates.set(state.first); });
200 auto mecChoices = model.getTransitionMatrix().getRowFilter(mecStates, mecStates);
202 if (mecChoices.empty()) {
206 auto incomingChoicesMatrix = model.getTransitionMatrix().transpose();
207 auto incomingStatesMatrix = model.getBackwardTransitions();
208 bool changedSomething =
true;
209 while (changedSomething) {
211 changedSomething =
false;
213 auto subMecDecomposition =
218 for (storm::automata::AcceptanceCondition::acceptance_expr::ptr
const& streettPair : acceptancePairs) {
221 auto infSet =
getStreettSet(acceptance, streettPair->getRight());
222 auto finSet =
getStreettSet(acceptance, streettPair->getLeft());
223 if (mec.containsAnyState(infSet)) {
229 for (
auto const& stateToChoice : mec) {
230 StateType state = stateToChoice.first;
231 if (finSet.get(state)) {
233 mecStates.
set(state,
false);
235 auto incChoices = incomingChoicesMatrix.getRow(state);
236 std::for_each(incChoices.begin(), incChoices.end(), [&mecChoices](
auto const& entry) { mecChoices.set(entry.getColumn(), false); });
237 changedSomething =
true;
245 auto subMecDecomposition =
247 if (subMecDecomposition.empty()) {
256template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
259 std::vector<uint64_t>
const& oldToNewStateMapping, uint64_t
const& condition, uint64_t
const numStates,
260 std::vector<uint64_t>
const& compressedToReducedMapping, std::map<uint64_t, uint64_t>
const& bccToStStateMapping) {
262 STORM_LOG_ASSERT(condition < bccLexArray[0].size(),
"Condition is not in Lex-Array!");
263 std::vector<uint64_t> goodStates;
264 for (uint64_t i = 0;
i < bcc.
size();
i++) {
265 std::vector<bool>
const& bccLex = bccLexArray[
i];
266 if (bccLex[condition]) {
267 uint64_t bccStateOld = bccToStStateMapping.at(i);
268 uint64_t bccState = oldToNewStateMapping[bccStateOld];
269 auto pointer = std::find(compressedToReducedMapping.begin(), compressedToReducedMapping.end(), bccState);
270 if (pointer != compressedToReducedMapping.end()) {
272 uint64_t bccStateReduced = pointer - compressedToReducedMapping.begin();
273 goodStates.push_back(bccStateReduced);
277 return {numStates, goodStates};
280template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
281MDPSparseModelCheckingHelperReturnType<ValueType> LexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::solveOneReachability(
283 SparseModelType
const& originalMdp, std::vector<uint64_t>
const& compressedToReducedMapping, std::vector<uint64_t>
const& oldToNewStateMapping) {
296 auto pointer = std::find(compressedToReducedMapping.begin(), compressedToReducedMapping.end(), oldToNewStateMapping[pos - 1]);
297 if (pointer != compressedToReducedMapping.end()) {
298 newInitalStates.push_back(pointer - compressedToReducedMapping.begin());
303 ModelCheckerHint hint;
306 phiStates, psiStates,
false,
true, hint);
310template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
312LexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::getReducedSubsystem(
315 std::vector<std::vector<uint64_t>> optimalActions;
316 std::vector<uint64_t> keptActions;
320 for (uint64_t currentState = 0; currentState < reachabilityResult.values.size(); currentState++) {
321 std::vector<uint64_t> goodActionsForState;
322 uint64_t bestAction = reachabilityResult.scheduler->getChoice(currentState).getDeterministicChoice();
326 bestActionValue += rowEntry.getValue() * reachabilityResult.values[rowEntry.getColumn()];
328 uint64_t lastAction = rowGroupIndices[currentState] + transitionMatrix.
getRowGroupSize(currentState);
330 for (uint64_t action = rowGroupIndices[currentState]; action < lastAction; action++) {
332 for (
const auto& rowEntry : transitionMatrix.getRow(action)) {
333 actionValue += rowEntry.getValue() * reachabilityResult.values[rowEntry.getColumn()];
335 if (actionValue == bestActionValue) {
336 goodActionsForState.push_back(action);
337 keptActions.push_back(action);
340 optimalActions.push_back(goodActionsForState);
344 transformer::SubsystemBuilderOptions sbo;
345 sbo.fixDeadlocks =
true;
347 stateLabelling.addLabel(
"init");
348 for (
auto const& state : newInitalStates) {
349 stateLabelling.addLabelToState(
"init", state);
353 return subsystemReturn;
356template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
357std::pair<storm::storage::SparseMatrix<ValueType>, std::map<uint64_t, uint64_t>>
358LexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::addSinkStates(
362 uint64_t countNewRows = 0;
363 std::map<uint64_t, uint64_t> stateToMEC;
364 for (uint64_t i = 0;
i < mecs.
size();
i++) {
366 countNewRows += bcc.
size() + 1;
367 for (
auto const& stateAndChoices : bcc) {
369 uint64_t bccState = stateAndChoices.first;
370 stateToMEC[bccState] =
i;
377 std::map<uint64_t, uint64_t> sTstatesForBCC;
380 uint64_t oldRowCounting = 0;
383 for (uint64_t newRowGroup = 0; newRowGroup < matrix.
getColumnCount(); ++newRowGroup) {
385 builder.newRowGroup(newRow);
387 for (; oldRowCounting < oldRowGroupIndices[newRowGroup + 1]; oldRowCounting++) {
388 for (
auto const& entry : matrix.getRow(oldRowCounting)) {
390 builder.addNextValue(newRow, entry.getColumn(), entry.getValue());
395 if (stateToMEC.find(newRowGroup) != stateToMEC.end()) {
396 if (sTstatesForBCC.find(stateToMEC[newRowGroup]) == sTstatesForBCC.end()) {
397 sTstatesForBCC[stateToMEC[newRowGroup]] = newestRowGroup;
400 builder.addNextValue(newRow, sTstatesForBCC[stateToMEC[newRowGroup]], storm::utility::one<ValueType>());
406 for (uint64_t newRowGroup = matrix.
getColumnCount(); newRowGroup < numRowGroups; newRowGroup++) {
407 builder.newRowGroup(newRow);
408 builder.addNextValue(newRow, newRowGroup, storm::utility::one<ValueType>());
412 return {newMatrix, sTstatesForBCC};
415template<
typename SparseModelType,
typename ValueType,
bool Nondeterministic>
416std::map<std::string, storm::storage::BitVector> LexicographicModelCheckerHelper<SparseModelType, ValueType, Nondeterministic>::computeApSets(
417 std::map<std::string, std::shared_ptr<storm::logic::Formula const>>
const& extracted, CheckFormulaCallback
const& formulaChecker) {
418 std::map<std::string, storm::storage::BitVector> apSets;
419 for (
auto& p : extracted) {
420 STORM_LOG_DEBUG(
" Computing satisfaction set for atomic proposition \"" << p.first <<
"\" <=> " << *p.second <<
"...");
421 apSets[p.first] = formulaChecker(*p.second);
426template class lexicographic::LexicographicModelCheckerHelper<storm::models::sparse::Mdp<double>, double,
true>;
427template class lexicographic::LexicographicModelCheckerHelper<storm::models::sparse::Mdp<double>, double,
false>;
428template class lexicographic::LexicographicModelCheckerHelper<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber,
true>;
429template class lexicographic::LexicographicModelCheckerHelper<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber,
false>;