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