Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
JaniBeliefSupportMdpGenerator.cpp
Go to the documentation of this file.
4#include "storm/api/builder.h"
6#include "storm/io/file.h"
13
14namespace storm {
15namespace pomdp {
16namespace qualitative {
17namespace detail {
18struct ObsActPair {
20
21 uint64_t observation;
22 uint64_t action;
23};
24
25bool operator<(ObsActPair const& o1, ObsActPair const& o2) {
26 if (o1.observation == o2.observation) {
27 return o1.action < o2.action;
28 }
29 return o1.observation < o2.observation;
30}
31} // namespace detail
32
33template<typename ValueType>
35 : pomdp(pomdp), model("beliefsupport", jani::ModelType::MDP) {
36 // Intentionally left empty.
37}
38
39template<typename ValueType>
41 //
42 std::map<uint64_t, std::map<detail::ObsActPair, std::vector<uint64_t>>> predecessorInfo;
43 std::map<detail::ObsActPair, std::map<uint64_t, std::set<uint64_t>>> obsPredInfo;
44 std::set<detail::ObsActPair> obsactpairs;
45 // Initialize predecessorInfo for clean steps.
46 for (uint64_t state = 0; state < pomdp.getNumberOfStates(); ++state) {
47 predecessorInfo[state] = {};
48 }
49
50 // Fill predecessorInfo
51 for (uint64_t state = 0; state < pomdp.getNumberOfStates(); ++state) {
52 uint64_t curObs = pomdp.getObservation(state);
53 for (uint64_t act = 0; act < pomdp.getNumberOfChoices(state); ++act) {
54 detail::ObsActPair oap(curObs, act);
55 obsactpairs.insert(oap);
56 if (obsPredInfo.count(oap) == 0) {
57 obsPredInfo[oap] = std::map<uint64_t, std::set<uint64_t>>();
58 }
59 for (auto const& entry : pomdp.getTransitionMatrix().getRow(state, act)) {
60 if (predecessorInfo[entry.getColumn()].count(oap) == 0) {
61 predecessorInfo[entry.getColumn()][oap] = {state};
62 } else {
63 predecessorInfo[entry.getColumn()][oap].push_back(state);
64 }
65 uint64_t newObs = pomdp.getObservation(entry.getColumn());
66 if (obsPredInfo[oap].count(newObs) == 0) {
67 obsPredInfo[oap][newObs] = {state};
68 } else {
69 obsPredInfo[oap][newObs].insert(state);
70 }
71 }
72 }
73 }
74 uint64_t initialObs = pomdp.getObservation(*(pomdp.getInitialStates().begin()));
75
76 expressions::ExpressionManager& exprManager = model.getManager();
77 storm::expressions::Variable posProbVar = exprManager.declareRationalVariable("posProb");
78 model.addConstant(jani::Constant("posProb", posProbVar));
79 std::map<uint64_t, const jani::Variable*> stateVariables;
80 const jani::Variable* obsVar =
81 &model.addVariable(*storm::jani::Variable::makeBoundedIntegerVariable("obs", exprManager.declareIntegerVariable("obs"), exprManager.integer(initialObs),
82 false, exprManager.integer(0), exprManager.integer(pomdp.getNrObservations())));
83 const jani::Variable* oldobsActVar =
84 &model.addVariable(*storm::jani::Variable::makeBoundedIntegerVariable("prevact", exprManager.declareIntegerVariable("prevact"), exprManager.integer(0),
85 false, exprManager.integer(0), exprManager.integer(obsactpairs.size())));
86
87 for (uint64_t i = 0; i < pomdp.getNumberOfStates(); ++i) {
88 std::string name = "s" + std::to_string(i);
89 bool isInitial = pomdp.getInitialStates().get(i);
90 stateVariables.emplace(i, &model.addVariable(*storm::jani::Variable::makeBooleanVariable(name, exprManager.declareBooleanVariable(name),
91 exprManager.boolean(isInitial), false)));
92 }
93
94 std::map<detail::ObsActPair, uint64_t> actionIndices;
95 for (auto const& oap : obsactpairs) {
96 std::string actname = "act" + std::to_string(oap.action) + "from" + std::to_string(oap.observation);
97 uint64_t actindex = model.addAction(jani::Action(actname));
98 actionIndices[oap] = actindex;
99 }
100
101 for (uint64_t i = 0; i < pomdp.getNumberOfStates(); ++i) {
102 std::string name = "aut-s" + std::to_string(i);
103 jani::Automaton aut(name, exprManager.declareIntegerVariable(name));
104 uint64_t primeloc = aut.addLocation(jani::Location("default"));
105 aut.addInitialLocation(primeloc);
106 for (auto const& oaps : actionIndices) {
107 if (obsPredInfo[oaps.first].count(pomdp.getObservation(i)) == 0 && pomdp.getObservation(i) != oaps.first.observation) {
108 continue;
109 }
110 std::shared_ptr<jani::TemplateEdge> tedge = std::make_shared<jani::TemplateEdge>(exprManager.boolean(true));
112 std::vector<storm::expressions::Expression> exprVec;
113 for (auto const& pred : predecessorInfo[i][oaps.first]) {
114 exprVec.push_back(stateVariables.at(pred)->getExpressionVariable().getExpression());
115 }
116 if (exprVec.empty()) {
117 edgedest.addAssignment(jani::Assignment(storm::jani::LValue(*stateVariables.at(i)), exprManager.boolean(false)));
118 } else {
119 edgedest.addAssignment(jani::Assignment(storm::jani::LValue(*stateVariables.at(i)),
120 (exprManager.integer(pomdp.getObservation(i)) == obsVar->getExpressionVariable().getExpression()) &&
122 }
123 tedge->addDestination(edgedest);
124 aut.addEdge(jani::Edge(primeloc, oaps.second, boost::none, tedge, {primeloc}, {exprManager.rational(1.0)}));
125 }
126 model.addAutomaton(aut);
127 }
128 jani::Automaton obsAut("obsAut", exprManager.declareIntegerVariable("obsAut"));
129 auto const& targetVar = model.addVariable(
130 *storm::jani::Variable::makeBooleanVariable("target", exprManager.declareBooleanVariable("target"), exprManager.boolean(false), true));
131 std::vector<storm::expressions::Expression> notTargetExpression;
132 for (auto const state : ~targetStates) {
133 notTargetExpression.push_back(!stateVariables.at(state)->getExpressionVariable().getExpression());
134 }
135 auto const& badVar =
136 model.addVariable(*storm::jani::Variable::makeBooleanVariable("bad", exprManager.declareBooleanVariable("bad"), exprManager.boolean(false), true));
137 std::vector<storm::expressions::Expression> badExpression;
138 for (auto const state : badStates) {
139 badExpression.push_back(stateVariables.at(state)->getExpressionVariable().getExpression());
140 }
141
142 auto primeLocation = jani::Location("primary");
143 primeLocation.addTransientAssignment(jani::Assignment(targetVar, expressions::conjunction(notTargetExpression)));
144 primeLocation.addTransientAssignment(
145 jani::Assignment(badVar, badExpression.empty() ? exprManager.boolean(false) : expressions::disjunction(badExpression)));
146 uint64_t primeloc = obsAut.addLocation(primeLocation);
147 obsAut.addInitialLocation(primeloc);
148 uint64_t secloc = obsAut.addLocation(jani::Location("secondary"));
149 // First edges, select observation
150 for (auto const& oaps : actionIndices) {
151 std::shared_ptr<jani::TemplateEdge> tedge =
152 std::make_shared<jani::TemplateEdge>(exprManager.integer(oaps.first.observation) == obsVar->getExpressionVariable().getExpression());
153 std::vector<uint64_t> destLocs;
154 std::vector<storm::expressions::Expression> probs;
155
156 for (auto const& obsAndPredStates : obsPredInfo[oaps.first]) {
158 tedgedest.addAssignment(jani::Assignment(jani::LValue(*obsVar), exprManager.integer(obsAndPredStates.first)), true);
159 tedgedest.addAssignment(jani::Assignment(jani::LValue(*oldobsActVar), exprManager.integer(oaps.second)), true);
160
161 tedge->addDestination(tedgedest);
162
163 destLocs.push_back(secloc);
164 std::vector<storm::expressions::Expression> predExpressions;
165 for (auto predstate : obsAndPredStates.second) {
166 predExpressions.push_back(stateVariables.at(predstate)->getExpressionVariable().getExpression());
167 }
168 probs.push_back(storm::expressions::ite(storm::expressions::disjunction(predExpressions), posProbVar.getExpression(), exprManager.rational(0)));
169 }
170 jani::Edge edge(primeloc, jani::Model::SILENT_ACTION_INDEX, boost::none, tedge, destLocs, probs);
171 obsAut.addEdge(edge);
172 }
173 // Back edges
174 for (auto const& oaps : obsactpairs) {
175 std::shared_ptr<jani::TemplateEdge> tedge =
176 std::make_shared<jani::TemplateEdge>(oldobsActVar->getExpressionVariable() == exprManager.integer(actionIndices[oaps]));
177
179 tedgedest.addAssignment(jani::Assignment(jani::LValue(*oldobsActVar), exprManager.integer(0)));
180 tedge->addDestination(tedgedest);
181 jani::Edge edge(secloc, actionIndices[oaps], boost::none, tedge, {primeloc}, {exprManager.rational(1.0)});
182 obsAut.addEdge(edge);
183 }
184 model.addAutomaton(obsAut);
185 model.setStandardSystemComposition();
186 model.finalize();
187}
188
189template<typename ValueType>
192 // This trick only works because we do not explictly check that the model is stochastic!
193 symdesc = symdesc.preprocess("posProb=0.1");
194 auto property = storm::api::parsePropertiesForJaniModel("Pmax>=1 [!\"bad\" U \"target\"]", model)[0];
195 auto mdp = storm::api::buildSymbolicModel<storm::dd::DdType::Sylvan, ValueType>(symdesc, {property.getRawFormula()});
197 std::unique_ptr<modelchecker::CheckResult> result =
198 storm::api::verifyWithDdEngine(env, mdp, storm::api::createTask<ValueType>(property.getRawFormula(), onlyInitial));
199 std::unique_ptr<storm::modelchecker::CheckResult> filter;
200
201 if (onlyInitial) {
202 filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<storm::dd::DdType::Sylvan>>(mdp->getReachableStates(),
203 mdp->getInitialStates());
204 } else {
205 auto relstates = storm::api::parsePropertiesForJaniModel("prevact=0", model)[0];
206 filter =
207 storm::api::verifyWithDdEngine<storm::dd::DdType::Sylvan, ValueType>(env, mdp, storm::api::createTask<ValueType>(relstates.getRawFormula(), false));
208 }
209 if (result && filter) {
210 result->filter(filter->asQualitativeCheckResult());
211 }
212
213 if (result && !onlyInitial) {
214 auto vars = result->asSymbolicQualitativeCheckResult<storm::dd::DdType::Sylvan>().getTruthValuesVector().getContainedMetaVariables();
215 // TODO Export these results.
216 } else if (result) {
217 initialIsWinning = result->asQualitativeCheckResult().existsTrue();
218 }
219}
220
221template<typename ValueType>
223 return initialIsWinning;
224}
225
229
230} // namespace qualitative
231} // namespace pomdp
232} // namespace storm
This class is responsible for managing a set of typed variables and all expressions using these varia...
Variable declareRationalVariable(std::string const &name, bool auxiliary=false)
Declares a new rational variable with a name that must not yet exist and its corresponding type.
Variable declareBooleanVariable(std::string const &name, bool auxiliary=false)
Declares a new boolean variable with a name that must not yet exist and its corresponding type.
Expression integer(int_fast64_t value) const
Creates an expression that characterizes the given integer literal.
Variable declareIntegerVariable(std::string const &name, bool auxiliary=false)
Declares a new integer variable with a name that must not yet exist and its corresponding type.
Expression rational(double value) const
Creates an expression that characterizes the given rational literal.
Expression boolean(bool value) const
Creates an expression that characterizes the given boolean literal.
storm::expressions::Expression getExpression() const
Retrieves an expression that represents the variable.
Definition Variable.cpp:34
void addEdge(Edge const &edge)
Adds an edge to the automaton.
void addInitialLocation(std::string const &name)
Adds the location with the given name to the initial locations.
uint64_t addLocation(Location const &location)
Adds the given location to the automaton.
Jani Location:
Definition Location.h:15
static const uint64_t SILENT_ACTION_INDEX
The index of the silent action.
Definition Model.h:642
void addAssignment(Assignment const &assignment, bool addToExisting=false)
static std::shared_ptr< Variable > makeBooleanVariable(std::string const &name, storm::expressions::Variable const &variable, boost::optional< storm::expressions::Expression > const &initValue, bool transient)
Definition Variable.cpp:110
static std::shared_ptr< Variable > makeBoundedIntegerVariable(std::string const &name, storm::expressions::Variable const &variable, boost::optional< storm::expressions::Expression > const &initValue, bool transient, boost::optional< storm::expressions::Expression > const &lowerBound, boost::optional< storm::expressions::Expression > const &upperBound)
Definition Variable.cpp:136
storm::expressions::Variable const & getExpressionVariable() const
Retrieves the associated expression variable.
Definition Variable.cpp:26
This class represents a partially observable Markov decision process.
Definition Pomdp.h:15
uint32_t getObservation(uint64_t state) const
Definition Pomdp.cpp:63
void generate(storm::storage::BitVector const &targetStates, storm::storage::BitVector const &badStates)
JaniBeliefSupportMdpGenerator(storm::models::sparse::Pomdp< ValueType > const &pomdp)
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
SymbolicModelDescription preprocess(std::string const &constantDefinitionString="") const
std::unique_ptr< storm::modelchecker::CheckResult > verifyWithDdEngine(storm::Environment const &env, std::shared_ptr< storm::models::symbolic::Dtmc< DdType, ValueType > > const &dtmc, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task)
std::vector< storm::jani::Property > parsePropertiesForJaniModel(std::string const &inputString, storm::jani::Model const &model, boost::optional< std::set< std::string > > const &propertyFilter)
Expression ite(Expression const &condition, Expression const &thenExpression, Expression const &elseExpression)
Expression conjunction(std::vector< storm::expressions::Expression > const &expressions)
Expression disjunction(std::vector< storm::expressions::Expression > const &expressions)
bool operator<(ObsActPair const &o1, ObsActPair const &o2)
std::pair< storm::RationalNumber, storm::RationalNumber > count(std::vector< storm::storage::BitVector > const &origSets, std::vector< storm::storage::BitVector > const &intersects, std::vector< storm::storage::BitVector > const &intersectsInfo, storm::RationalNumber val, bool plus, uint64_t remdepth)