Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
EpochModel.cpp
Go to the documentation of this file.
3
7
10
11namespace storm {
12namespace modelchecker {
13namespace helper {
14namespace rewardbounded {
15
16template<typename ValueType>
17std::vector<ValueType> analyzeTrivialDtmcEpochModel(EpochModel<ValueType, true> &epochModel) {
18 std::vector<ValueType> epochResult;
19 epochResult.reserve(epochModel.epochInStates.getNumberOfSetBits());
20 auto stepSolutionIt = epochModel.stepSolutions.begin();
21 auto stepChoiceIt = epochModel.stepChoices.begin();
22 for (auto state : epochModel.epochInStates) {
23 while (*stepChoiceIt < state) {
24 ++stepChoiceIt;
25 ++stepSolutionIt;
26 }
27 if (epochModel.objectiveRewardFilter.front().get(state)) {
28 if (*stepChoiceIt == state) {
29 epochResult.push_back(epochModel.objectiveRewards.front()[state] + *stepSolutionIt);
30 } else {
31 epochResult.push_back(epochModel.objectiveRewards.front()[state]);
32 }
33 } else {
34 if (*stepChoiceIt == state) {
35 epochResult.push_back(*stepSolutionIt);
36 } else {
37 epochResult.push_back(storm::utility::zero<ValueType>());
38 }
39 }
40 }
41 return epochResult;
42}
43
44template<typename ValueType>
45std::vector<ValueType> analyzeNonTrivialDtmcEpochModel(Environment const &env, EpochModel<ValueType, true> &epochModel, std::vector<ValueType> &x,
46 std::vector<ValueType> &b, std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> &linEqSolver,
47 boost::optional<ValueType> const &lowerBound, boost::optional<ValueType> const &upperBound) {
48 // Update some data for the case that the Matrix has changed
49 if (epochModel.epochMatrixChanged) {
50 x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
52 // We only check for acyclic models if the equation problem has the fixedPointSystem format.
53 // We could also do this for other formats, however, this requires either matrix conversions or a different 'hasCycle' implementation.
54 // Also, we would have to match the equationProblemFormat of the acyclic solver.
57 Environment acyclicEnv;
58 if (epochMatrixAcyclic) {
59 acyclicEnv = env;
60 acyclicEnv.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Acyclic);
61 linEqSolver = linearEquationSolverFactory.create(acyclicEnv, epochModel.epochMatrix);
62 } else {
63 linEqSolver = linearEquationSolverFactory.create(env, epochModel.epochMatrix);
64 }
65 linEqSolver->setCachingEnabled(true);
66 auto req = linEqSolver->getRequirements(epochMatrixAcyclic ? acyclicEnv : env);
67 if (lowerBound) {
68 linEqSolver->setLowerBound(lowerBound.get());
69 req.clearLowerBounds();
70 }
71 if (upperBound) {
72 linEqSolver->setUpperBound(upperBound.get());
73 req.clearUpperBounds();
74 }
75 if (epochMatrixAcyclic) {
76 req.clearAcyclic();
77 }
78 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
79 "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
80 STORM_LOG_THROW(linEqSolver->getEquationProblemFormat(epochMatrixAcyclic ? acyclicEnv : env) == epochModel.equationSolverProblemFormat.get(),
81 storm::exceptions::UnexpectedException,
82 "The constructed solver uses a different equation problem format then the one that has been specified initially.");
83 }
84
85 // Prepare the right hand side of the equation system
86 b.assign(epochModel.epochMatrix.getRowCount(), storm::utility::zero<ValueType>());
87 std::vector<ValueType> const &objectiveValues = epochModel.objectiveRewards.front();
88 for (auto choice : epochModel.objectiveRewardFilter.front()) {
89 b[choice] = objectiveValues[choice];
90 }
91 auto stepSolutionIt = epochModel.stepSolutions.begin();
92 for (auto choice : epochModel.stepChoices) {
93 b[choice] += *stepSolutionIt;
94 ++stepSolutionIt;
95 }
96 assert(stepSolutionIt == epochModel.stepSolutions.end());
97
98 // Solve the minMax equation system
99 linEqSolver->solveEquations(env, x, b);
100
102}
103
104template<typename ValueType>
106 // Assert that the epoch model is indeed trivial
107 assert(epochModel.epochMatrix.getEntryCount() == 0);
108
109 std::vector<ValueType> epochResult;
110 epochResult.reserve(epochModel.epochInStates.getNumberOfSetBits());
111
112 auto stepSolutionIt = epochModel.stepSolutions.begin();
113 auto stepChoiceIt = epochModel.stepChoices.begin();
114 for (auto state : epochModel.epochInStates) {
115 // Obtain the best choice for this state
116 ValueType bestValue;
117 uint64_t lastChoice = epochModel.epochMatrix.getRowGroupIndices()[state + 1];
118 bool isFirstChoice = true;
119 for (uint64_t choice = epochModel.epochMatrix.getRowGroupIndices()[state]; choice < lastChoice; ++choice) {
120 while (*stepChoiceIt < choice) {
121 ++stepChoiceIt;
122 ++stepSolutionIt;
123 }
124
125 ValueType choiceValue = storm::utility::zero<ValueType>();
126 if (epochModel.objectiveRewardFilter.front().get(choice)) {
127 choiceValue += epochModel.objectiveRewards.front()[choice];
128 }
129 if (*stepChoiceIt == choice) {
130 choiceValue += *stepSolutionIt;
131 }
132
133 if (isFirstChoice) {
134 bestValue = std::move(choiceValue);
135 isFirstChoice = false;
136 } else {
137 if (storm::solver::minimize(dir)) {
138 if (choiceValue < bestValue) {
139 bestValue = std::move(choiceValue);
140 }
141 } else {
142 if (choiceValue > bestValue) {
143 bestValue = std::move(choiceValue);
144 }
145 }
146 }
147 }
148 // Insert the solution w.r.t. this choice
149 epochResult.push_back(std::move(bestValue));
150 }
151 return epochResult;
152}
153
154template<typename ValueType>
156 std::vector<ValueType> &x, std::vector<ValueType> &b,
157 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> &minMaxSolver,
158 boost::optional<ValueType> const &lowerBound, boost::optional<ValueType> const &upperBound) {
159 // Update some data for the case that the Matrix has changed
160 if (epochModel.epochMatrixChanged) {
161 x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
163 bool epochMatrixAcyclic = !storm::utility::graph::hasCycle(epochModel.epochMatrix);
164 Environment acyclicEnv;
165 if (epochMatrixAcyclic) {
166 acyclicEnv = env;
167 acyclicEnv.solver().minMax().setMethod(storm::solver::MinMaxMethod::Acyclic);
168 minMaxSolver = minMaxLinearEquationSolverFactory.create(acyclicEnv, epochModel.epochMatrix);
169 } else {
170 minMaxSolver = minMaxLinearEquationSolverFactory.create(env, epochModel.epochMatrix);
171 }
172 minMaxSolver->setHasUniqueSolution();
173 minMaxSolver->setHasNoEndComponents();
174 minMaxSolver->setOptimizationDirection(dir);
175 minMaxSolver->setCachingEnabled(true);
176 minMaxSolver->setTrackScheduler(!epochMatrixAcyclic); // only track the scheduler if there are cycles
177 auto req = minMaxSolver->getRequirements(epochMatrixAcyclic ? acyclicEnv : env, dir, false);
178 if (lowerBound) {
179 minMaxSolver->setLowerBound(lowerBound.get());
180 req.clearLowerBounds();
181 }
182 if (upperBound) {
183 minMaxSolver->setUpperBound(upperBound.get());
184 req.clearUpperBounds();
185 }
186 if (epochMatrixAcyclic) {
187 req.clearAcyclic();
188 }
189 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
190 "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
191 minMaxSolver->setRequirementsChecked();
192 } else {
193 if (minMaxSolver && minMaxSolver->isTrackSchedulerSet()) {
194 auto choicesTmp = minMaxSolver->getSchedulerChoices();
195 minMaxSolver->setInitialScheduler(std::move(choicesTmp));
196 }
197 }
198
199 // Prepare the right hand side of the equation system
200 b.assign(epochModel.epochMatrix.getRowCount(), storm::utility::zero<ValueType>());
201 std::vector<ValueType> const &objectiveValues = epochModel.objectiveRewards.front();
202 for (auto choice : epochModel.objectiveRewardFilter.front()) {
203 b[choice] = objectiveValues[choice];
204 }
205 auto stepSolutionIt = epochModel.stepSolutions.begin();
206 for (auto choice : epochModel.stepChoices) {
207 b[choice] += *stepSolutionIt;
208 ++stepSolutionIt;
209 }
210 assert(stepSolutionIt == epochModel.stepSolutions.end());
211
212 // Solve the minMax equation system
213 minMaxSolver->solveEquations(env, x, b);
214
216}
217
218template<>
219std::vector<double> EpochModel<double, true>::analyzeSingleObjective(const storm::Environment &env, std::vector<double> &x, std::vector<double> &b,
220 std::unique_ptr<storm::solver::LinearEquationSolver<double>> &linEqSolver,
221 const boost::optional<double> &lowerBound, const boost::optional<double> &upperBound) {
222 STORM_LOG_ASSERT(epochMatrix.hasTrivialRowGrouping(), "This operation is only allowed if no nondeterminism is present.");
223 STORM_LOG_ASSERT(equationSolverProblemFormat.is_initialized(), "Unknown equation problem format.");
224 // If the epoch matrix is empty we do not need to solve a linear equation system
225 bool convertToEquationSystem = (equationSolverProblemFormat == storm::solver::LinearEquationSolverProblemFormat::EquationSystem);
226 if ((convertToEquationSystem && epochMatrix.isIdentityMatrix()) || (!convertToEquationSystem && epochMatrix.getEntryCount() == 0)) {
227 return analyzeTrivialDtmcEpochModel<double>(*this);
228 } else {
229 return analyzeNonTrivialDtmcEpochModel<double>(env, *this, x, b, linEqSolver, lowerBound, upperBound);
230 }
231}
232
233template<>
235 std::vector<double> &b,
236 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<double>> &minMaxSolver,
237 const boost::optional<double> &lowerBound, const boost::optional<double> &upperBound) {
238 // If the epoch matrix is empty we do not need to solve a linear equation system
239 if (epochMatrix.getEntryCount() == 0) {
240 return analyzeTrivialMdpEpochModel<double>(dir, *this);
241 } else {
242 return analyzeNonTrivialMdpEpochModel<double>(env, dir, *this, x, b, minMaxSolver, lowerBound, upperBound);
243 }
244}
245
246template<>
248 const storm::Environment &env, std::vector<storm::RationalNumber> &x, std::vector<storm::RationalNumber> &b,
249 std::unique_ptr<storm::solver::LinearEquationSolver<storm::RationalNumber>> &linEqSolver, const boost::optional<storm::RationalNumber> &lowerBound,
250 const boost::optional<storm::RationalNumber> &upperBound) {
251 STORM_LOG_ASSERT(epochMatrix.hasTrivialRowGrouping(), "This operation is only allowed if no nondeterminism is present.");
252 STORM_LOG_ASSERT(equationSolverProblemFormat.is_initialized(), "Unknown equation problem format.");
253 // If the epoch matrix is empty we do not need to solve a linear equation system
254 bool convertToEquationSystem = (equationSolverProblemFormat == storm::solver::LinearEquationSolverProblemFormat::EquationSystem);
255 if ((convertToEquationSystem && epochMatrix.isIdentityMatrix()) || (!convertToEquationSystem && epochMatrix.getEntryCount() == 0)) {
256 return analyzeTrivialDtmcEpochModel<storm::RationalNumber>(*this);
257 } else {
258 return analyzeNonTrivialDtmcEpochModel<storm::RationalNumber>(env, *this, x, b, linEqSolver, lowerBound, upperBound);
259 }
260}
261
262template<>
264 const storm::Environment &env, storm::OptimizationDirection dir, std::vector<storm::RationalNumber> &x, std::vector<storm::RationalNumber> &b,
265 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<storm::RationalNumber>> &minMaxSolver, const boost::optional<storm::RationalNumber> &lowerBound,
266 const boost::optional<storm::RationalNumber> &upperBound) {
267 // If the epoch matrix is empty we do not need to solve a linear equation system
268 if (epochMatrix.getEntryCount() == 0) {
269 return analyzeTrivialMdpEpochModel<storm::RationalNumber>(dir, *this);
270 } else {
271 return analyzeNonTrivialMdpEpochModel<storm::RationalNumber>(env, dir, *this, x, b, minMaxSolver, lowerBound, upperBound);
272 }
273}
274
275template struct EpochModel<double, true>;
276template struct EpochModel<double, false>;
279} // namespace rewardbounded
280} // namespace helper
281} // namespace modelchecker
282} // namespace storm
SolverEnvironment & solver()
void setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault=false)
void setLinearEquationSolverType(storm::solver::EquationSolverType const &value, bool isSetFromDefault=false)
MinMaxSolverEnvironment & minMax()
virtual std::unique_ptr< LinearEquationSolver< ValueType > > create(Environment const &env) const override
Creates an equation solver with the current settings, but without a matrix.
virtual std::unique_ptr< MinMaxLinearEquationSolver< ValueType, SolutionType > > create(Environment const &env) const override
An interface that represents an abstract linear equation solver.
A class representing the interface that all min-max linear equation solvers shall implement.
const_iterator begin() const
Returns an iterator to the indices of the set bits in the bit vector.
uint_fast64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
std::vector< ValueType > analyzeNonTrivialMdpEpochModel(Environment const &env, OptimizationDirection dir, EpochModel< ValueType, true > &epochModel, std::vector< ValueType > &x, std::vector< ValueType > &b, std::unique_ptr< storm::solver::MinMaxLinearEquationSolver< ValueType > > &minMaxSolver, boost::optional< ValueType > const &lowerBound, boost::optional< ValueType > const &upperBound)
std::vector< ValueType > analyzeTrivialDtmcEpochModel(EpochModel< ValueType, true > &epochModel)
std::vector< ValueType > analyzeNonTrivialDtmcEpochModel(Environment const &env, EpochModel< ValueType, true > &epochModel, std::vector< ValueType > &x, std::vector< ValueType > &b, std::unique_ptr< storm::solver::LinearEquationSolver< ValueType > > &linEqSolver, boost::optional< ValueType > const &lowerBound, boost::optional< ValueType > const &upperBound)
std::vector< ValueType > analyzeTrivialMdpEpochModel(OptimizationDirection dir, EpochModel< ValueType, true > &epochModel)
bool constexpr minimize(OptimizationDirection d)
bool hasCycle(storm::storage::SparseMatrix< T > const &transitionMatrix, boost::optional< storm::storage::BitVector > const &subsystem)
Returns true if the graph represented by the given matrix has a cycle.
Definition graph.cpp:143
std::vector< Type > filterVector(std::vector< Type > const &in, storm::storage::BitVector const &filter)
Definition vector.h:1213
LabParser.cpp.
Definition cli.cpp:18
std::vector< storm::storage::BitVector > objectiveRewardFilter
Definition EpochModel.h:26
std::vector< ValueType > analyzeSingleObjective(Environment const &env, OptimizationDirection dir, std::vector< ValueType > &x, std::vector< ValueType > &b, std::unique_ptr< storm::solver::MinMaxLinearEquationSolver< ValueType > > &minMaxSolver, boost::optional< ValueType > const &lowerBound, boost::optional< ValueType > const &upperBound)
Analyzes the epoch model, i.e., solves the represented equation system.
storm::storage::SparseMatrix< ValueType > epochMatrix
Definition EpochModel.h:22
std::vector< std::vector< ValueType > > objectiveRewards
Definition EpochModel.h:25
boost::optional< storm::solver::LinearEquationSolverProblemFormat > equationSolverProblemFormat
In case of DTMCs we have different options for the equation problem format the epoch model will have.
Definition EpochModel.h:29