Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
sampling.h
Go to the documentation of this file.
1
2#pragma once
5
8
12
19
25
27
29
31#include "storm/api/storm.h"
32
36
38
40
42
45
46#include "storm/io/file.h"
51
57
58namespace storm::pars {
59
60template<typename ValueType>
63 // Intentionally left empty.
64 }
65
66 bool empty() const {
67 return cartesianProducts.empty();
68 }
69
70 std::vector<std::map<typename storm::utility::parametric::VariableType<ValueType>::type,
71 std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>>>
74 bool exact;
75};
76
77template<template<typename, typename> class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double>
78void verifyPropertiesAtSamplePointsDerivative(storm::Environment const& env, ModelType const& model, cli::SymbolicInput const& input,
79 SampleInformation<ValueType> const& samples) {
80 // When samples are provided, we create an instantiation model checker.
81 ModelCheckerType<ValueType, SolveValueType> derivativeModelchecker(model);
83
84 for (auto const& property : input.properties) {
86
87 auto checkTask = storm::api::createTask<ValueType>(property.getRawFormula(), true);
88 derivativeModelchecker.specifyFormula(env, checkTask);
89 originalModelchecker.specifyFormula(checkTask);
90
92
93 std::vector<typename storm::utility::parametric::VariableType<ValueType>::type> parameters;
94 std::vector<typename std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iterators;
95 std::vector<typename std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iteratorEnds;
96
97 storm::utility::Stopwatch watch(true);
98 for (auto const& product : samples.cartesianProducts) {
99 parameters.clear();
100 iterators.clear();
101 iteratorEnds.clear();
102
103 for (auto const& entry : product) {
104 parameters.push_back(entry.first);
105 iterators.push_back(entry.second.cbegin());
106 iteratorEnds.push_back(entry.second.cend());
107 }
108
109 bool done = false;
110 while (!done) {
111 // Read off valuation.
112 for (uint64_t i = 0; i < parameters.size(); ++i) {
113 valuation[parameters[i]] = *iterators[i];
114 }
115
116 storm::utility::Stopwatch valuationWatch(true);
117 std::unique_ptr<storm::modelchecker::CheckResult> originalResult = originalModelchecker.check(env, valuation);
118 valuationWatch.stop();
119
120 boost::optional<std::vector<SolveValueType>> valueVector = boost::none;
121 if (originalResult) {
122 valueVector = originalResult->template asExplicitQuantitativeCheckResult<SolveValueType>().getFiniteValueVector();
123 originalResult->filter(storm::modelchecker::ExplicitQualitativeCheckResult<SolveValueType>(model.getInitialStates()));
124 }
125 STORM_PRINT_AND_LOG("Model checking result:\n");
126 printInitialStatesResult<ValueType>(originalResult, &valuationWatch, &valuation);
127
128 for (auto const& parameter : parameters) {
129 valuationWatch.restart();
130 std::unique_ptr<storm::modelchecker::CheckResult> result = derivativeModelchecker.check(env, valuation, parameter, valueVector);
131 valuationWatch.stop();
132
133 if (result) {
134 result->filter(storm::modelchecker::ExplicitQualitativeCheckResult<SolveValueType>(model.getInitialStates()));
135 }
136 STORM_PRINT_AND_LOG("Derivative w.r.t. " << parameter << ":\n");
137 printInitialStatesResult<ValueType>(result, &valuationWatch, &valuation);
138 }
139
140 for (uint64_t i = 0; i < parameters.size(); ++i) {
141 ++iterators[i];
142 if (iterators[i] == iteratorEnds[i]) {
143 // Reset iterator and proceed to move next iterator.
144 iterators[i] = product.at(parameters[i]).cbegin();
145
146 // If the last iterator was removed, we are done.
147 if (i == parameters.size() - 1) {
148 done = true;
149 }
150 } else {
151 // If an iterator was moved but not reset, we have another valuation to check.
152 break;
153 }
154 }
155 }
156 }
157
158 watch.stop();
159 STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << "\n\n");
160 }
161}
162
163template<template<typename, typename> class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double, bool Derivative = false>
164void verifyPropertiesAtSamplePoints(storm::Environment const& env, ModelType const& model, cli::SymbolicInput const& input,
165 SampleInformation<ValueType> const& samples) {
166 // When samples are provided, we create an instantiation model checker.
167 ModelCheckerType<ModelType, SolveValueType> modelchecker(env, model);
168
169 for (auto const& property : input.properties) {
171
172 modelchecker.specifyFormula(storm::api::createTask<ValueType>(property.getRawFormula(), true));
173 modelchecker.setInstantiationsAreGraphPreserving(samples.graphPreserving);
174
176
177 std::vector<typename storm::utility::parametric::VariableType<ValueType>::type> parameters;
178 std::vector<typename std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iterators;
179 std::vector<typename std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iteratorEnds;
180
181 storm::utility::Stopwatch watch(true);
182 for (auto const& product : samples.cartesianProducts) {
183 parameters.clear();
184 iterators.clear();
185 iteratorEnds.clear();
186
187 for (auto const& entry : product) {
188 parameters.push_back(entry.first);
189 iterators.push_back(entry.second.cbegin());
190 iteratorEnds.push_back(entry.second.cend());
191 }
192
193 bool done = false;
194 while (!done) {
195 // Read off valuation.
196 for (uint64_t i = 0; i < parameters.size(); ++i) {
197 valuation[parameters[i]] = *iterators[i];
198 }
199
200 storm::utility::Stopwatch valuationWatch(true);
201 std::unique_ptr<storm::modelchecker::CheckResult> result = modelchecker.check(env, valuation);
202 valuationWatch.stop();
203
204 if (result) {
205 result->filter(storm::modelchecker::ExplicitQualitativeCheckResult<SolveValueType>(model.getInitialStates()));
206 }
207 printInitialStatesResult<ValueType>(result, &valuationWatch, &valuation);
208
209 for (uint64_t i = 0; i < parameters.size(); ++i) {
210 ++iterators[i];
211 if (iterators[i] == iteratorEnds[i]) {
212 // Reset iterator and proceed to move next iterator.
213 iterators[i] = product.at(parameters[i]).cbegin();
214
215 // If the last iterator was removed, we are done.
216 if (i == parameters.size() - 1) {
217 done = true;
218 }
219 } else {
220 // If an iterator was moved but not reset, we have another valuation to check.
221 break;
222 }
223 }
224 }
225 }
226
227 watch.stop();
228 STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << "\n\n");
229 }
230}
231
232template<typename ValueType, typename SolveValueType = double>
234 std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model,
235 cli::SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
236 if (model->isOfType(storm::models::ModelType::Dtmc)) {
238 ValueType, SolveValueType>(env, *model->template as<storm::models::sparse::Dtmc<ValueType>>(), input, samples);
239 } else {
240 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling the derivative is currently only supported for DTMCs.");
241 }
242}
243
244template<typename ValueType, typename SolveValueType = double>
246 cli::SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
247 if (model->isOfType(storm::models::ModelType::Dtmc)) {
249 SolveValueType>(env, *model->template as<storm::models::sparse::Dtmc<ValueType>>(), input, samples);
250 } else if (model->isOfType(storm::models::ModelType::Ctmc)) {
252 SolveValueType>(env, *model->template as<storm::models::sparse::Ctmc<ValueType>>(), input, samples);
253 } else if (model->isOfType(storm::models::ModelType::Mdp)) {
255 SolveValueType>(env, *model->template as<storm::models::sparse::Mdp<ValueType>>(), input, samples);
256 } else {
257 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs.");
258 }
259}
260
261template<typename ValueType>
262SampleInformation<ValueType> parseSamples(std::shared_ptr<storm::models::ModelBase> const& model, std::string const& sampleString, bool graphPreserving) {
263 STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models.");
264
265 SampleInformation<ValueType> sampleInfo(graphPreserving);
266 if (sampleString.empty()) {
267 return sampleInfo;
268 }
269
270 // Get all parameters from the model.
271 std::set<typename storm::utility::parametric::VariableType<ValueType>::type> modelParameters;
272 auto const& sparseModel = *model->as<storm::models::sparse::Model<ValueType>>();
273 modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel);
274 auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel);
275 modelParameters.insert(rewParameters.begin(), rewParameters.end());
276
277 std::vector<std::string> cartesianProducts;
278 boost::split(cartesianProducts, sampleString, boost::is_any_of(";"));
279 for (auto& product : cartesianProducts) {
280 boost::trim(product);
281
282 // Get the values string for each variable.
283 std::vector<std::string> valuesForVariables;
284 boost::split(valuesForVariables, product, boost::is_any_of(","));
285 for (auto& values : valuesForVariables) {
286 boost::trim(values);
287 }
288
289 std::set<typename storm::utility::parametric::VariableType<ValueType>::type> encounteredParameters;
290 sampleInfo.cartesianProducts.emplace_back();
291 auto& newCartesianProduct = sampleInfo.cartesianProducts.back();
292 for (auto const& varValues : valuesForVariables) {
293 auto equalsPosition = varValues.find("=");
294 STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples.");
295 std::string variableName = varValues.substr(0, equalsPosition);
296 boost::trim(variableName);
297 std::string values = varValues.substr(equalsPosition + 1);
298 boost::trim(values);
299
300 bool foundParameter = false;
302 for (auto const& parameter : modelParameters) {
303 std::stringstream parameterStream;
304 parameterStream << parameter;
305 if (parameterStream.str() == variableName) {
306 foundParameter = true;
307 theParameter = parameter;
308 encounteredParameters.insert(parameter);
309 }
310 }
311 STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'.");
312
313 std::vector<std::string> splitValues;
314 boost::split(splitValues, values, boost::is_any_of(":"));
315 STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter.");
316
317 auto& list = newCartesianProduct[theParameter];
318
319 for (auto& value : splitValues) {
320 boost::trim(value);
322 }
323 }
324
325 STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException,
326 "Variables for all parameters are required when providing samples.");
327 }
328
329 return sampleInfo;
330}
331
332template<typename ValueType>
334 std::string const& instantiationString) {
335 STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotSupportedException,
336 "Gradient descent is currently only supported for DTMCs.");
337 std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> dtmc = model->template as<storm::models::sparse::Dtmc<ValueType>>();
338
339 std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(input.properties);
340 auto formula = formulas[0];
341
342 STORM_LOG_THROW(formula->isProbabilityOperatorFormula() || formula->isRewardOperatorFormula(), storm::exceptions::NotSupportedException,
343 "Input formula needs to be either a probability operator formula or a reward operator formula.");
344
346
347 boost::optional<std::string> rewardModel = boost::none;
348 if (formula->isRewardOperatorFormula()) {
349 if (formula->asRewardOperatorFormula().hasRewardModelName()) {
350 rewardModel = std::string(formula->asRewardOperatorFormula().getRewardModelName());
351 } else {
352 rewardModel = std::string("");
353 }
354 for (auto const& rewardParameter : storm::models::sparse::getRewardParameters(*dtmc)) {
355 vars.insert(rewardParameter);
356 }
357 }
358 // Use the SparseDerivativeInstantiationModelChecker to retrieve the derivative at an instantiation that is input by the user
359
360 std::unordered_map<std::string, std::string> keyValue = storm::parser::parseKeyValueString(instantiationString);
361 std::map<typename storm::utility::parametric::VariableType<ValueType>::type, typename storm::utility::parametric::CoefficientType<ValueType>::type>
362 instantiation;
363 for (auto const& pair : keyValue) {
364 auto variable = storm::findRFVariable(pair.first);
365 STORM_LOG_THROW(variable != storm::RationalFunctionVariable::NO_VARIABLE, storm::exceptions::WrongFormatException,
366 "Parameter '" << pair.first << "' does not exist in the model.");
368 instantiation.emplace(variable, value);
369 }
370
372
374 std::shared_ptr<storm::logic::Formula> formulaWithoutBound;
375 if (!referenceCheckTask.isRewardModelSet()) {
376 formulaWithoutBound = std::make_shared<storm::logic::ProbabilityOperatorFormula>(
377 formulas[0]->asProbabilityOperatorFormula().getSubformula().asSharedPointer(), storm::logic::OperatorInformation(boost::none, boost::none));
378 } else {
379 // No worries, this works as intended, the API is just weird.
380 formulaWithoutBound = std::make_shared<storm::logic::RewardOperatorFormula>(formulas[0]->asRewardOperatorFormula().getSubformula().asSharedPointer());
381 }
384 modelChecker.specifyFormula(env, checkTask);
385
386 for (auto const& parameter : vars) {
387 std::cout << "Derivative w.r.t. " << parameter << ": ";
388
389 auto result = modelChecker.check(env, instantiation, parameter);
390 std::cout << *result << '\n';
391 }
392}
393} // namespace storm::pars
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.
bool isRewardModelSet() const
Retrieves whether a reward model was set.
Definition CheckTask.h:191
A qualitative check result over the states of a sparse model.
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)
Base class for all sparse models.
Definition Model.h:34
A class that provides convenience operations to display run times.
Definition Stopwatch.h:13
void restart()
Reset the stopwatch and immediately start it.
Definition Stopwatch.cpp:59
void stop()
Stop stopwatch and add measured time to total time.
Definition Stopwatch.cpp:42
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > createTask(std::shared_ptr< const storm::logic::Formula > const &formula, bool onlyInitialStatesRelevant=false)
std::vector< std::shared_ptr< storm::logic::Formula const > > extractFormulasFromProperties(std::vector< storm::jani::Property > const &properties)
void printModelCheckingProperty(storm::jani::Property const &property)
std::set< storm::RationalFunctionVariable > getRewardParameters(Model< storm::RationalFunction > const &model)
Get all parameters occurring in rewards.
Definition Model.cpp:736
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:732
void verifyPropertiesAtSamplePoints(storm::Environment const &env, ModelType const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:164
void sampleDerivatives(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Model< ValueType > > model, cli::SymbolicInput const &input, std::string const &instantiationString)
Definition sampling.h:333
void verifyPropertiesAtSamplePointsWithSparseEngineDerivatives(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:233
SampleInformation< ValueType > parseSamples(std::shared_ptr< storm::models::ModelBase > const &model, std::string const &sampleString, bool graphPreserving)
Definition sampling.h:262
void verifyPropertiesAtSamplePointsDerivative(storm::Environment const &env, ModelType const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:78
void printInitialStatesResult(std::unique_ptr< storm::modelchecker::CheckResult > const &result, storm::utility::Stopwatch *watch, const storm::utility::parametric::Valuation< ValueType > *valuation)
Definition print.cpp:11
void verifyPropertiesAtSamplePointsWithSparseEngine(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:245
std::unordered_map< std::string, std::string > parseKeyValueString(std::string const &keyValueString)
std::map< typename VariableType< FunctionType >::type, typename CoefficientType< FunctionType >::type > Valuation
Definition parametric.h:43
TargetType convertNumber(SourceType const &number)
RationalFunctionVariable findRFVariable(std::string const &name)
Retrieves the (already existing) rational-function variable with the given name.
#define STORM_PRINT_AND_LOG(message)
Definition print.h:20
std::vector< storm::jani::Property > properties
SampleInformation(bool graphPreserving=false, bool exact=false)
Definition sampling.h:62
std::vector< std::map< typename storm::utility::parametric::VariableType< ValueType >::type, std::vector< typename storm::utility::parametric::CoefficientType< ValueType >::type > > > cartesianProducts
Definition sampling.h:72