Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
JaniBeliefSupportMdpGenerator.cpp
Go to the documentation of this file.
3#include "storm/api/builder.h"
5#include "storm/io/file.h"
12
13namespace storm {
14namespace pomdp {
15namespace qualitative {
16namespace detail {
17struct ObsActPair {
19
20 uint64_t observation;
21 uint64_t action;
22};
23
24bool operator<(ObsActPair const& o1, ObsActPair const& o2) {
25 if (o1.observation == o2.observation) {
26 return o1.action < o2.action;
27 }
28 return o1.observation < o2.observation;
29}
30} // namespace detail
31
32template<typename ValueType>
34 : pomdp(pomdp), model("beliefsupport", jani::ModelType::MDP) {
35 // Intentionally left empty.
36}
37
38template<typename ValueType>
40 //
41 std::map<uint64_t, std::map<detail::ObsActPair, std::vector<uint64_t>>> predecessorInfo;
42 std::map<detail::ObsActPair, std::map<uint64_t, std::set<uint64_t>>> obsPredInfo;
43 std::set<detail::ObsActPair> obsactpairs;
44 // Initialize predecessorInfo for clean steps.
45 for (uint64_t state = 0; state < pomdp.getNumberOfStates(); ++state) {
46 predecessorInfo[state] = {};
47 }
48
49 // Fill predecessorInfo
50 for (uint64_t state = 0; state < pomdp.getNumberOfStates(); ++state) {
51 uint64_t curObs = pomdp.getObservation(state);
52 for (uint64_t act = 0; act < pomdp.getNumberOfChoices(state); ++act) {
53 detail::ObsActPair oap(curObs, act);
54 obsactpairs.insert(oap);
55 if (obsPredInfo.count(oap) == 0) {
56 obsPredInfo[oap] = std::map<uint64_t, std::set<uint64_t>>();
57 }
58 for (auto const& entry : pomdp.getTransitionMatrix().getRow(state, act)) {
59 if (predecessorInfo[entry.getColumn()].count(oap) == 0) {
60 predecessorInfo[entry.getColumn()][oap] = {state};
61 } else {
62 predecessorInfo[entry.getColumn()][oap].push_back(state);
63 }
64 uint64_t newObs = pomdp.getObservation(entry.getColumn());
65 if (obsPredInfo[oap].count(newObs) == 0) {
66 obsPredInfo[oap][newObs] = {state};
67 } else {
68 obsPredInfo[oap][newObs].insert(state);
69 }
70 }
71 }
72 }
73 uint64_t initialObs = pomdp.getObservation(*(pomdp.getInitialStates().begin()));
74
75 expressions::ExpressionManager& exprManager = model.getManager();
76 storm::expressions::Variable posProbVar = exprManager.declareRationalVariable("posProb");
77 model.addConstant(jani::Constant("posProb", posProbVar));
78 std::map<uint64_t, const jani::Variable*> stateVariables;
79 const jani::Variable* obsVar =
80 &model.addVariable(*storm::jani::Variable::makeBoundedIntegerVariable("obs", exprManager.declareIntegerVariable("obs"), exprManager.integer(initialObs),
81 false, exprManager.integer(0), exprManager.integer(pomdp.getNrObservations())));
82 const jani::Variable* oldobsActVar =
83 &model.addVariable(*storm::jani::Variable::makeBoundedIntegerVariable("prevact", exprManager.declareIntegerVariable("prevact"), exprManager.integer(0),
84 false, exprManager.integer(0), exprManager.integer(obsactpairs.size())));
85
86 for (uint64_t i = 0; i < pomdp.getNumberOfStates(); ++i) {
87 std::string name = "s" + std::to_string(i);
88 bool isInitial = pomdp.getInitialStates().get(i);
89 stateVariables.emplace(i, &model.addVariable(*storm::jani::Variable::makeBooleanVariable(name, exprManager.declareBooleanVariable(name),
90 exprManager.boolean(isInitial), false)));
91 }
92
93 std::map<detail::ObsActPair, uint64_t> actionIndices;
94 for (auto const& oap : obsactpairs) {
95 std::string actname = "act" + std::to_string(oap.action) + "from" + std::to_string(oap.observation);
96 uint64_t actindex = model.addAction(jani::Action(actname));
97 actionIndices[oap] = actindex;
98 }
99
100 for (uint64_t i = 0; i < pomdp.getNumberOfStates(); ++i) {
101 std::string name = "aut-s" + std::to_string(i);
102 jani::Automaton aut(name, exprManager.declareIntegerVariable(name));
103 uint64_t primeloc = aut.addLocation(jani::Location("default"));
104 aut.addInitialLocation(primeloc);
105 for (auto const& oaps : actionIndices) {
106 if (obsPredInfo[oaps.first].count(pomdp.getObservation(i)) == 0 && pomdp.getObservation(i) != oaps.first.observation) {
107 continue;
108 }
109 std::shared_ptr<jani::TemplateEdge> tedge = std::make_shared<jani::TemplateEdge>(exprManager.boolean(true));
111 std::vector<storm::expressions::Expression> exprVec;
112 for (auto const& pred : predecessorInfo[i][oaps.first]) {
113 exprVec.push_back(stateVariables.at(pred)->getExpressionVariable().getExpression());
114 }
115 if (exprVec.empty()) {
116 edgedest.addAssignment(jani::Assignment(storm::jani::LValue(*stateVariables.at(i)), exprManager.boolean(false)));
117 } else {
118 edgedest.addAssignment(jani::Assignment(storm::jani::LValue(*stateVariables.at(i)),
119 (exprManager.integer(pomdp.getObservation(i)) == obsVar->getExpressionVariable().getExpression()) &&
121 }
122 tedge->addDestination(edgedest);
123 aut.addEdge(jani::Edge(primeloc, oaps.second, boost::none, tedge, {primeloc}, {exprManager.rational(1.0)}));
124 }
125 model.addAutomaton(aut);
126 }
127 jani::Automaton obsAut("obsAut", exprManager.declareIntegerVariable("obsAut"));
128 auto const& targetVar = model.addVariable(
129 *storm::jani::Variable::makeBooleanVariable("target", exprManager.declareBooleanVariable("target"), exprManager.boolean(false), true));
130 std::vector<storm::expressions::Expression> notTargetExpression;
131 for (auto const state : ~targetStates) {
132 notTargetExpression.push_back(!stateVariables.at(state)->getExpressionVariable().getExpression());
133 }
134 auto const& badVar =
135 model.addVariable(*storm::jani::Variable::makeBooleanVariable("bad", exprManager.declareBooleanVariable("bad"), exprManager.boolean(false), true));
136 std::vector<storm::expressions::Expression> badExpression;
137 for (auto const state : badStates) {
138 badExpression.push_back(stateVariables.at(state)->getExpressionVariable().getExpression());
139 }
140
141 auto primeLocation = jani::Location("primary");
142 primeLocation.addTransientAssignment(jani::Assignment(targetVar, expressions::conjunction(notTargetExpression)));
143 primeLocation.addTransientAssignment(
144 jani::Assignment(badVar, badExpression.empty() ? exprManager.boolean(false) : expressions::disjunction(badExpression)));
145 uint64_t primeloc = obsAut.addLocation(primeLocation);
146 obsAut.addInitialLocation(primeloc);
147 uint64_t secloc = obsAut.addLocation(jani::Location("secondary"));
148 // First edges, select observation
149 for (auto const& oaps : actionIndices) {
150 std::shared_ptr<jani::TemplateEdge> tedge =
151 std::make_shared<jani::TemplateEdge>(exprManager.integer(oaps.first.observation) == obsVar->getExpressionVariable().getExpression());
152 std::vector<uint64_t> destLocs;
153 std::vector<storm::expressions::Expression> probs;
154
155 for (auto const& obsAndPredStates : obsPredInfo[oaps.first]) {
157 tedgedest.addAssignment(jani::Assignment(jani::LValue(*obsVar), exprManager.integer(obsAndPredStates.first)), true);
158 tedgedest.addAssignment(jani::Assignment(jani::LValue(*oldobsActVar), exprManager.integer(oaps.second)), true);
159
160 tedge->addDestination(tedgedest);
161
162 destLocs.push_back(secloc);
163 std::vector<storm::expressions::Expression> predExpressions;
164 for (auto predstate : obsAndPredStates.second) {
165 predExpressions.push_back(stateVariables.at(predstate)->getExpressionVariable().getExpression());
166 }
167 probs.push_back(storm::expressions::ite(storm::expressions::disjunction(predExpressions), posProbVar.getExpression(), exprManager.rational(0)));
168 }
169 jani::Edge edge(primeloc, jani::Model::SILENT_ACTION_INDEX, boost::none, tedge, destLocs, probs);
170 obsAut.addEdge(edge);
171 }
172 // Back edges
173 for (auto const& oaps : obsactpairs) {
174 std::shared_ptr<jani::TemplateEdge> tedge =
175 std::make_shared<jani::TemplateEdge>(oldobsActVar->getExpressionVariable() == exprManager.integer(actionIndices[oaps]));
176
178 tedgedest.addAssignment(jani::Assignment(jani::LValue(*oldobsActVar), exprManager.integer(0)));
179 tedge->addDestination(tedgedest);
180 jani::Edge edge(secloc, actionIndices[oaps], boost::none, tedge, {primeloc}, {exprManager.rational(1.0)});
181 obsAut.addEdge(edge);
182 }
183 model.addAutomaton(obsAut);
184 model.setStandardSystemComposition();
185 model.finalize();
186}
187
188template<typename ValueType>
191 // This trick only works because we do not explictly check that the model is stochastic!
192 symdesc = symdesc.preprocess("posProb=0.1");
193 auto property = storm::api::parsePropertiesForJaniModel("Pmax>=1 [!\"bad\" U \"target\"]", model)[0];
194 auto mdp = storm::api::buildSymbolicModel<storm::dd::DdType::Sylvan, ValueType>(symdesc, {property.getRawFormula()});
196 std::unique_ptr<modelchecker::CheckResult> result =
197 storm::api::verifyWithDdEngine(env, mdp, storm::api::createTask<ValueType>(property.getRawFormula(), onlyInitial));
198 std::unique_ptr<storm::modelchecker::CheckResult> filter;
199
200 if (onlyInitial) {
201 filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<storm::dd::DdType::Sylvan>>(mdp->getReachableStates(),
202 mdp->getInitialStates());
203 } else {
204 auto relstates = storm::api::parsePropertiesForJaniModel("prevact=0", model)[0];
205 filter =
206 storm::api::verifyWithDdEngine<storm::dd::DdType::Sylvan, ValueType>(env, mdp, storm::api::createTask<ValueType>(relstates.getRawFormula(), false));
207 }
208 if (result && filter) {
209 result->filter(filter->asQualitativeCheckResult());
210 }
211
212 if (result && !onlyInitial) {
213 auto vars = result->asSymbolicQualitativeCheckResult<storm::dd::DdType::Sylvan>().getTruthValuesVector().getContainedMetaVariables();
214 // TODO Export these results.
215 } else if (result) {
216 initialIsWinning = result->asQualitativeCheckResult().existsTrue();
217 }
218}
219
220template<typename ValueType>
222 return initialIsWinning;
223}
224
228
229} // namespace qualitative
230} // namespace pomdp
231} // 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:18
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)
LabParser.cpp.
Definition cli.cpp:18