Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseDerivativeInstantiationModelChecker.cpp
Go to the documentation of this file.
11#include "storm/logic/Formula.h"
22#include "storm/utility/graph.h"
25
26namespace storm {
27namespace derivative {
28
29template<typename FunctionType>
31template<typename FunctionType>
33
34template<typename FunctionType, typename ConstantType>
35std::unique_ptr<modelchecker::ExplicitQuantitativeCheckResult<ConstantType>> SparseDerivativeInstantiationModelChecker<FunctionType, ConstantType>::check(
37 boost::optional<std::vector<ConstantType>> const& valueVector) {
38 std::vector<ConstantType> reachabilityProbabilities;
39 if (!valueVector.is_initialized()) {
41 instantiationModelChecker.specifyFormula(*currentCheckTask);
42 std::unique_ptr<storm::modelchecker::CheckResult> result = instantiationModelChecker.check(env, valuation);
43 reachabilityProbabilities = result->asExplicitQuantitativeCheckResult<ConstantType>().getValueVector();
44 } else {
45 STORM_LOG_ASSERT(valueVector->size() == model.getNumberOfStates(), "Size of reachability probability vector must be equal to the size of the model.");
46 reachabilityProbabilities = *valueVector;
47 }
48
49 // Convert reachabilityProbabilities into our format - we only care for the states of which the
50 // bits are 1 in the next vector. The order is kept, so doing this is fine:
51 std::vector<ConstantType> interestingReachabilityProbabilities;
52 for (uint64_t i = 0; i < reachabilityProbabilities.size(); i++) {
53 if (next.get(i)) {
54 interestingReachabilityProbabilities.push_back(reachabilityProbabilities[i]);
55 }
56 }
57 // Instantiate the matrices with the given instantiation
58
59 instantiationWatch.start();
60
61 // STORM_PRINT_AND_LOG(valuation << "\n");
62
63 // Write results into the placeholders
64 for (auto& functionResult : this->functionsUnderived) {
65 functionResult.second = storm::utility::parametric::evaluate<ConstantType>(functionResult.first, valuation);
66 }
67 for (auto& functionResult : this->functionsDerived.at(parameter)) {
68 functionResult.second = storm::utility::parametric::evaluate<ConstantType>(functionResult.first, valuation);
69 }
70
71 auto deltaConstrainedMatrixInstantiated = deltaConstrainedMatricesInstantiated->at(parameter);
72
73 // Write the instantiated values to the matrices and vectors according to the stored mappings
74 for (auto& entryValuePair : this->matrixMappingUnderived) {
75 entryValuePair.first->setValue(*(entryValuePair.second));
76 }
77 for (auto& entryValuePair : this->matrixMappingsDerived.at(parameter)) {
78 entryValuePair.first->setValue(*(entryValuePair.second));
79 }
80
81 std::vector<ConstantType> instantiatedDerivedOutputVec(derivedOutputVecs->at(parameter).size());
82 for (uint_fast64_t i = 0; i < derivedOutputVecs->at(parameter).size(); i++) {
83 instantiatedDerivedOutputVec[i] = storm::utility::parametric::evaluate<ConstantType>(derivedOutputVecs->at(parameter)[i], valuation);
84 }
85
86 instantiationWatch.stop();
87
88 approximationWatch.start();
89
90 std::vector<ConstantType> resultVec(interestingReachabilityProbabilities.size());
91 deltaConstrainedMatrixInstantiated.multiplyWithVector(interestingReachabilityProbabilities, resultVec);
92 for (uint_fast64_t i = 0; i < instantiatedDerivedOutputVec.size(); ++i) {
93 resultVec[i] += instantiatedDerivedOutputVec[i];
94 }
95
96 // Here's where the real magic happens - the solver call!
98 auto solver = factory.create(env);
99
100 // Calculate (1-M)^-1 * resultVec
101 // STORM_PRINT_AND_LOG(constrainedMatrixInstantiated << "\n");
102 // STORM_PRINT_AND_LOG("calling solver\n");
103 solver->setMatrix(constrainedMatrixInstantiated);
104 std::vector<ConstantType> finalResult(resultVec.size());
105 solver->solveEquations(env, finalResult, resultVec);
106
107 approximationWatch.stop();
108
109 return std::make_unique<modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(finalResult);
110}
111
112template<typename FunctionType, typename ConstantType>
115 this->currentFormula = checkTask.getFormula().asSharedPointer();
116 this->currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, FunctionType>>(
117 checkTask.substituteFormula(*currentFormula).template convertValueType<FunctionType>());
118 this->parameters = storm::models::sparse::getProbabilityParameters(model);
119 if (checkTask.getFormula().isRewardOperatorFormula()) {
120 for (auto const& rewardParameter : storm::models::sparse::getRewardParameters(model)) {
121 this->parameters.insert(rewardParameter);
122 }
123 }
124 storm::logic::OperatorInformation opInfo(boost::none, boost::none);
125 if (checkTask.getFormula().isRewardOperatorFormula()) {
126 model.reduceToStateBasedRewards();
127 } else {
128 /* this->formulaWithoutBound = std::make_shared<storm::logic::ProbabilityOperatorFormula>( */
129 /* formula->asProbabilityOperatorFormula().getSubformula().asSharedPointer(), opInfo); */
130 }
131
132 generalSetupWatch.start();
133
135
137
138 std::map<VariableType<FunctionType>, storage::SparseMatrix<FunctionType>> equationSystems;
139 // Get initial and target states
141 storage::BitVector target;
142 storage::BitVector avoid(model.getNumberOfStates());
143 if (this->currentFormula->isRewardOperatorFormula()) {
145 this->currentFormula->asRewardOperatorFormula().getSubformula().asEventuallyFormula().getSubformula());
146 target = propositionalChecker.check(subformula)->asExplicitQualitativeCheckResult().getTruthValuesVector();
147 } else {
148 if (this->currentFormula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) {
150 this->currentFormula->asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula());
152 this->currentFormula->asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula());
153 target = propositionalChecker.check(rightSubformula)->asExplicitQualitativeCheckResult().getTruthValuesVector();
154 avoid = propositionalChecker.check(leftSubformula)->asExplicitQualitativeCheckResult().getTruthValuesVector();
155 avoid.complement();
156 } else {
158 this->currentFormula->asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula());
159 target = propositionalChecker.check(subformula)->asExplicitQualitativeCheckResult().getTruthValuesVector();
160 }
161 }
162 initialStateModel = model.getStates("init").getNextSetIndex(0);
163
164 if (!checkTask.getFormula().isRewardOperatorFormula()) {
165 next = target;
166 next.complement();
167
168 avoid.complement();
169 next &= avoid;
170
171 storm::storage::BitVector atSomePointTarget =
172 storm::utility::graph::performProbGreater0(model.getBackwardTransitions(), storm::storage::BitVector(model.getNumberOfStates(), true), target);
173 next &= atSomePointTarget;
174 } else {
175 next = target;
176 next.complement();
177
178 avoid.complement();
179 next &= avoid;
180
181 storm::storage::BitVector targetProbOne =
182 storm::utility::graph::performProb1(model.getBackwardTransitions(), storm::storage::BitVector(model.getNumberOfStates(), true), target);
183 next &= targetProbOne;
184 }
185
186 auto transitionMatrix = model.getTransitionMatrix();
187 std::map<uint_fast64_t, uint_fast64_t> stateNumToEquationSystemRow;
188 uint_fast64_t newRow = 0;
189 for (uint_fast64_t row = 0; row < transitionMatrix.getRowCount(); ++row) {
190 if (!next.get(row))
191 continue;
192 stateNumToEquationSystemRow[row] = newRow;
193 newRow++;
194 }
195 initialStateEqSystem = stateNumToEquationSystemRow[initialStateModel];
196 storage::SparseMatrix<FunctionType> constrainedMatrix = transitionMatrix.getSubmatrix(false, next, next, true);
197 // If necessary, convert the matrix from the fixpoint notation to the form needed for the equation system.
198 this->constrainedMatrixEquationSystem = constrainedMatrix;
199 if (convertToEquationSystem) {
200 // go from x = A*x + b to (I-A)x = b.
201 constrainedMatrixEquationSystem.convertToEquationSystem();
202 }
203
204 // Setup instantiated constrained matrix
205 storage::SparseMatrixBuilder<ConstantType> instantiatedSystemBuilder;
206 const ConstantType dummyValue = storm::utility::one<ConstantType>();
207 for (uint_fast64_t row = 0; row < constrainedMatrixEquationSystem.getRowCount(); ++row) {
208 for (auto const& entry : constrainedMatrixEquationSystem.getRow(row)) {
209 instantiatedSystemBuilder.addNextValue(row, entry.getColumn(), dummyValue);
210 }
211 }
212 constrainedMatrixInstantiated = instantiatedSystemBuilder.build();
213 initializeInstantiatedMatrix(constrainedMatrixEquationSystem, constrainedMatrixInstantiated, matrixMappingUnderived, functionsUnderived);
214 // The resulting equation systems
215 this->deltaConstrainedMatrices = std::make_unique<std::map<VariableType<FunctionType>, storage::SparseMatrix<FunctionType>>>();
216 this->deltaConstrainedMatricesInstantiated = std::make_unique<std::map<VariableType<FunctionType>, storage::SparseMatrix<ConstantType>>>();
217 this->derivedOutputVecs = std::make_unique<std::map<VariableType<FunctionType>, std::vector<FunctionType>>>();
218
219 // The following is a nessecary optimization for deriving the constrainedMatrix w.r.t. all parameters.
220 // We will traverse the constrainedMatrix once and inspect all entries, counting their number of parameters.
221 // Then, we will insert the correct polynomials into the correct matrix builders.
222 std::map<VariableType<FunctionType>, storage::SparseMatrixBuilder<FunctionType>> matrixBuilders;
223 std::map<VariableType<FunctionType>, storage::SparseMatrixBuilder<ConstantType>> instantiatedMatrixBuilders;
224 for (auto const& var : this->parameters) {
225 matrixBuilders[var] = storage::SparseMatrixBuilder<FunctionType>(constrainedMatrix.getRowCount());
226 instantiatedMatrixBuilders[var] = storage::SparseMatrixBuilder<ConstantType>(constrainedMatrix.getRowCount());
227 }
228
229 for (uint_fast64_t row = 0; row < constrainedMatrix.getRowCount(); ++row) {
230 for (storage::MatrixEntry<uint_fast64_t, storm::RationalFunction> const& entry : constrainedMatrix.getRow(row)) {
231 const storm::RationalFunction rationalFunction = entry.getValue();
232 auto variables = rationalFunction.gatherVariables();
233 for (auto const& var : variables) {
234 matrixBuilders.at(var).addNextValue(row, entry.getColumn(), rationalFunction.derivative(var));
235 instantiatedMatrixBuilders.at(var).addNextValue(row, entry.getColumn(), dummyValue);
236 }
237 }
238 }
239
240 for (auto const& var : this->parameters) {
241 auto builtMatrix = matrixBuilders[var].build();
242 auto builtMatrixInstantiated = instantiatedMatrixBuilders[var].build();
243 initializeInstantiatedMatrix(builtMatrix, builtMatrixInstantiated, matrixMappingsDerived[var], functionsDerived[var]);
244 deltaConstrainedMatrices->emplace(var, std::move(builtMatrix));
245 deltaConstrainedMatricesInstantiated->emplace(var, std::move(builtMatrixInstantiated));
246 }
247
248 for (auto const& var : this->parameters) {
249 (*derivedOutputVecs)[var] = std::vector<FunctionType>(constrainedMatrix.getRowCount());
250 }
251
252 // storage::BitVector constrainedTarget(next.size());
253 // for (uint_fast64_t i = 0; i < transitionMatrix.getRowCount(); i++) {
254 // if (!stateNumToEquationSystemRow.count(i)) continue;
255 // constrainedTarget.set(stateNumToEquationSystemRow[i], target[i]);
256 // }
257
258 for (uint_fast64_t state = 0; state < transitionMatrix.getRowCount(); ++state) {
259 if (!stateNumToEquationSystemRow.count(state))
260 continue;
261 uint_fast64_t row = stateNumToEquationSystemRow[state];
262 // PROBABILITY -> For every state, the one-step probability to reach the target goes into the output vector
263 // REWARD -> For every state, the reward goes into the output vector
264 FunctionType rationalFunction;
265 if (!checkTask.getFormula().isRewardOperatorFormula()) {
266 FunctionType vectorValue = utility::zero<FunctionType>();
267 for (auto const& entry : transitionMatrix.getRow(state)) {
268 if (target.get(entry.getColumn())) {
269 vectorValue += entry.getValue();
270 }
271 }
272 rationalFunction = vectorValue;
273 } else {
274 std::vector<FunctionType> stateRewards;
275 if (checkTask.isRewardModelSet()) {
276 stateRewards = model.getRewardModel(checkTask.getRewardModel()).getStateRewardVector();
277 } else {
278 stateRewards = model.getRewardModel("").getStateRewardVector();
279 }
280
281 rationalFunction = stateRewards[state];
282 }
283 for (auto const& var : rationalFunction.gatherVariables()) {
284 (*derivedOutputVecs)[var][row] = rationalFunction.derivative(var);
285 }
286 }
287
288 generalSetupWatch.stop();
289
290 // for (auto const& param : this->parameters) {
291 // this->linearEquationSolvers[param] = factory.create(env);
292 // // this->linearEquationSolvers[param]->setCachingEnabled(true);
293 // // std::unique_ptr<solver::TerminationCondition<ConstantType>> terminationCondition =
294 // // std::make_unique<SignedGradientDescentTerminationCondition<ConstantType>>(initialState);
295 // // this->linearEquationSolvers[param]->setTerminationCondition(std::move(terminationCondition));
296 // }
297}
298
299template<typename FunctionType, typename ConstantType>
302 std::vector<std::pair<typename storm::storage::SparseMatrix<ConstantType>::iterator, ConstantType*>>& matrixMapping,
303 std::unordered_map<FunctionType, ConstantType>& functions) {
304 ConstantType dummyValue = storm::utility::one<ConstantType>();
305 auto constantEntryIt = matrixInstantiated.begin();
306 auto parametricEntryIt = matrix.begin();
307 while (parametricEntryIt != matrix.end()) {
308 STORM_LOG_ASSERT(parametricEntryIt->getColumn() == constantEntryIt->getColumn(),
309 "Entries of parametric and constant matrix are not at the same position");
310 if (storm::utility::isConstant(parametricEntryIt->getValue())) {
311 // Constant entries can be inserted directly
312 constantEntryIt->setValue(storm::utility::convertNumber<ConstantType>(parametricEntryIt->getValue()));
313 // STORM_PRINT_AND_LOG("Setting constant entry\n");
314 } else {
315 // insert the new function and store that the current constantMatrix entry needs to be set to the value of this function
316 auto functionsIt = functions.insert(std::make_pair(parametricEntryIt->getValue(), dummyValue)).first;
317 matrixMapping.emplace_back(std::make_pair(constantEntryIt, &(functionsIt->second)));
318 // Note that references to elements of an unordered map remain valid after calling unordered_map::insert.
319 // STORM_PRINT_AND_LOG("Setting non-constant entry\n");
320 }
321 ++constantEntryIt;
322 ++parametricEntryIt;
323 }
324 STORM_LOG_ASSERT(constantEntryIt == matrixInstantiated.end(), "Parametric matrix seems to have more or less entries then the constant matrix");
325}
326
327template class SparseDerivativeInstantiationModelChecker<RationalFunction, RationalNumber>;
328template class SparseDerivativeInstantiationModelChecker<RationalFunction, double>;
329} // namespace derivative
330} // namespace storm
std::unique_ptr< modelchecker::ExplicitQuantitativeCheckResult< ConstantType > > check(Environment const &env, storm::utility::parametric::Valuation< FunctionType > const &valuation, typename utility::parametric::VariableType< FunctionType >::type const &parameter, boost::optional< std::vector< ConstantType > > const &valueVector=boost::none)
check calculates the deriative of the model w.r.t.
void specifyFormula(Environment const &env, modelchecker::CheckTask< logic::Formula, FunctionType > const &checkTask)
specifyFormula specifies a CheckTask.
virtual std::unique_ptr< CheckResult > check(Environment const &env, CheckTask< storm::logic::Formula, SolutionType > const &checkTask)
Checks the provided formula.
CheckTask< NewFormulaType, ValueType > substituteFormula(NewFormulaType const &newFormula) const
Copies the check task from the source while replacing the formula with the new one.
Definition CheckTask.h:52
bool isRewardModelSet() const
Retrieves whether a reward model was set.
Definition CheckTask.h:190
std::string const & getRewardModel() const
Retrieves the reward model over which to perform the checking (if set).
Definition CheckTask.h:197
FormulaType const & getFormula() const
Retrieves the formula from this task.
Definition CheckTask.h:140
Class to efficiently check a formula on a parametric model with different parameter instantiations.
virtual std::unique_ptr< CheckResult > check(Environment const &env, storm::utility::parametric::Valuation< typename SparseModelType::ValueType > const &valuation) override
void specifyFormula(CheckTask< storm::logic::Formula, typename SparseModelType::ValueType > const &checkTask)
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 LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const &env) const
Retrieves the problem format that the solver expects if it was created with the current settings.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
void complement()
Negates all bits in the bit vector.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
A class that can be used to build a sparse matrix by adding value by value.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
void convertToEquationSystem()
Transforms the matrix into an equation system.
const_rows getRow(index_type row) const
Returns an object representing the given row.
SparseMatrix getSubmatrix(bool useGroups, storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint, bool insertDiagonalEntries=false, storm::storage::BitVector const &makeZeroColumns=storm::storage::BitVector()) const
Creates a submatrix of the current matrix by dropping all rows and columns whose bits are not set to ...
const_iterator begin(index_type row) const
Retrieves an iterator that points to the beginning of the given row.
const_iterator end(index_type row) const
Retrieves an iterator that points past the end of the given row.
std::vector< MatrixEntry< index_type, value_type > >::iterator iterator
index_type getRowCount() const
Returns the number of rows of the matrix.
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
typename utility::parametric::VariableType< FunctionType >::type VariableType
typename utility::parametric::CoefficientType< FunctionType >::type CoefficientType
std::set< storm::RationalFunctionVariable > getRewardParameters(Model< storm::RationalFunction > const &model)
Get all parameters occurring in rewards.
Definition Model.cpp:707
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:703
storm::storage::BitVector performProbGreater0(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Performs a backward depth-first search trough the underlying graph structure of the given model to de...
Definition graph.cpp:322
storm::storage::BitVector performProb1(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &, storm::storage::BitVector const &psiStates, storm::storage::BitVector const &statesWithProbabilityGreater0)
Computes the set of states of the given model for which all paths lead to the given set of target sta...
Definition graph.cpp:383
std::map< typename VariableType< FunctionType >::type, typename CoefficientType< FunctionType >::type > Valuation
Definition parametric.h:38
bool isConstant(ValueType const &)
Definition constants.cpp:66
LabParser.cpp.
Definition cli.cpp:18