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
29
31
33#include "storm/api/storm.h"
34
38
40
42
44
47
48#include "storm/io/file.h"
53
59
60namespace storm::pars {
61
62template<typename ValueType>
65 // Intentionally left empty.
66 }
67
68 bool empty() const {
69 return cartesianProducts.empty();
70 }
71
72 std::vector<std::map<typename storm::utility::parametric::VariableType<ValueType>::type,
73 std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>>>
76 bool exact;
77};
78
79template<template<typename, typename> class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double>
80void verifyPropertiesAtSamplePointsDerivative(ModelType const& model, cli::SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
81 // When samples are provided, we create an instantiation model checker.
82 ModelCheckerType<ValueType, SolveValueType> derivativeModelchecker(model);
84
85 for (auto const& property : input.properties) {
87
88 auto checkTask = storm::api::createTask<ValueType>(property.getRawFormula(), true);
89 derivativeModelchecker.specifyFormula(Environment(), checkTask);
90 originalModelchecker.specifyFormula(checkTask);
91
93
94 std::vector<typename storm::utility::parametric::VariableType<ValueType>::type> parameters;
95 std::vector<typename std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iterators;
96 std::vector<typename std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iteratorEnds;
97
98 storm::utility::Stopwatch watch(true);
99 for (auto const& product : samples.cartesianProducts) {
100 parameters.clear();
101 iterators.clear();
102 iteratorEnds.clear();
103
104 for (auto const& entry : product) {
105 parameters.push_back(entry.first);
106 iterators.push_back(entry.second.cbegin());
107 iteratorEnds.push_back(entry.second.cend());
108 }
109
110 bool done = false;
111 while (!done) {
112 // Read off valuation.
113 for (uint64_t i = 0; i < parameters.size(); ++i) {
114 valuation[parameters[i]] = *iterators[i];
115 }
116
117 storm::utility::Stopwatch valuationWatch(true);
118 std::unique_ptr<storm::modelchecker::CheckResult> originalResult = originalModelchecker.check(Environment(), valuation);
119 valuationWatch.stop();
120
121 boost::optional<std::vector<SolveValueType>> valueVector = boost::none;
122 if (originalResult) {
123 valueVector = originalResult->template asExplicitQuantitativeCheckResult<SolveValueType>().getValueVector();
124 originalResult->filter(storm::modelchecker::ExplicitQualitativeCheckResult<SolveValueType>(model.getInitialStates()));
125 }
126 STORM_PRINT_AND_LOG("Model checking result:\n");
127 printInitialStatesResult<ValueType>(originalResult, &valuationWatch, &valuation);
128
129 for (auto const& parameter : parameters) {
130 valuationWatch.restart();
131 std::unique_ptr<storm::modelchecker::CheckResult> result = derivativeModelchecker.check(Environment(), valuation, parameter, valueVector);
132 valuationWatch.stop();
133
134 if (result) {
135 result->filter(storm::modelchecker::ExplicitQualitativeCheckResult<SolveValueType>(model.getInitialStates()));
136 }
137 STORM_PRINT_AND_LOG("Derivative w.r.t. " << parameter << ":\n");
138 printInitialStatesResult<ValueType>(result, &valuationWatch, &valuation);
139 }
140
141 for (uint64_t i = 0; i < parameters.size(); ++i) {
142 ++iterators[i];
143 if (iterators[i] == iteratorEnds[i]) {
144 // Reset iterator and proceed to move next iterator.
145 iterators[i] = product.at(parameters[i]).cbegin();
146
147 // If the last iterator was removed, we are done.
148 if (i == parameters.size() - 1) {
149 done = true;
150 }
151 } else {
152 // If an iterator was moved but not reset, we have another valuation to check.
153 break;
154 }
155 }
156 }
157 }
158
159 watch.stop();
160 STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << "\n\n");
161 }
162}
163
164template<template<typename, typename> class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double, bool Derivative = false>
165void verifyPropertiesAtSamplePoints(ModelType const& model, cli::SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
166 // When samples are provided, we create an instantiation model checker.
167 ModelCheckerType<ModelType, SolveValueType> modelchecker(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(Environment(), 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 cli::SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
235 if (model->isOfType(storm::models::ModelType::Dtmc)) {
237 ValueType, SolveValueType>(*model->template as<storm::models::sparse::Dtmc<ValueType>>(), input, samples);
238 } else {
239 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling the derivative is currently only supported for DTMCs.");
240 }
241}
242
243template<typename ValueType, typename SolveValueType = double>
245 SampleInformation<ValueType> const& samples) {
246 if (model->isOfType(storm::models::ModelType::Dtmc)) {
248 SolveValueType>(*model->template as<storm::models::sparse::Dtmc<ValueType>>(), input, samples);
249 } else if (model->isOfType(storm::models::ModelType::Ctmc)) {
251 SolveValueType>(*model->template as<storm::models::sparse::Ctmc<ValueType>>(), input, samples);
252 } else if (model->isOfType(storm::models::ModelType::Mdp)) {
254 SolveValueType>(*model->template as<storm::models::sparse::Mdp<ValueType>>(), input, samples);
255 } else {
256 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs.");
257 }
258}
259
260template<typename ValueType>
261SampleInformation<ValueType> parseSamples(std::shared_ptr<storm::models::ModelBase> const& model, std::string const& sampleString, bool graphPreserving) {
262 STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models.");
263
264 SampleInformation<ValueType> sampleInfo(graphPreserving);
265 if (sampleString.empty()) {
266 return sampleInfo;
267 }
268
269 // Get all parameters from the model.
270 std::set<typename storm::utility::parametric::VariableType<ValueType>::type> modelParameters;
271 auto const& sparseModel = *model->as<storm::models::sparse::Model<ValueType>>();
272 modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel);
273 auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel);
274 modelParameters.insert(rewParameters.begin(), rewParameters.end());
275
276 std::vector<std::string> cartesianProducts;
277 boost::split(cartesianProducts, sampleString, boost::is_any_of(";"));
278 for (auto& product : cartesianProducts) {
279 boost::trim(product);
280
281 // Get the values string for each variable.
282 std::vector<std::string> valuesForVariables;
283 boost::split(valuesForVariables, product, boost::is_any_of(","));
284 for (auto& values : valuesForVariables) {
285 boost::trim(values);
286 }
287
288 std::set<typename storm::utility::parametric::VariableType<ValueType>::type> encounteredParameters;
289 sampleInfo.cartesianProducts.emplace_back();
290 auto& newCartesianProduct = sampleInfo.cartesianProducts.back();
291 for (auto const& varValues : valuesForVariables) {
292 auto equalsPosition = varValues.find("=");
293 STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples.");
294 std::string variableName = varValues.substr(0, equalsPosition);
295 boost::trim(variableName);
296 std::string values = varValues.substr(equalsPosition + 1);
297 boost::trim(values);
298
299 bool foundParameter = false;
301 for (auto const& parameter : modelParameters) {
302 std::stringstream parameterStream;
303 parameterStream << parameter;
304 if (parameterStream.str() == variableName) {
305 foundParameter = true;
306 theParameter = parameter;
307 encounteredParameters.insert(parameter);
308 }
309 }
310 STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'.");
311
312 std::vector<std::string> splitValues;
313 boost::split(splitValues, values, boost::is_any_of(":"));
314 STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter.");
315
316 auto& list = newCartesianProduct[theParameter];
317
318 for (auto& value : splitValues) {
319 boost::trim(value);
321 }
322 }
323
324 STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException,
325 "Variables for all parameters are required when providing samples.");
326 }
327
328 return sampleInfo;
329}
330
331template<typename ValueType>
333 std::string const& instantiationString) {
334 STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotSupportedException,
335 "Gradient descent is currently only supported for DTMCs.");
336 std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> dtmc = model->template as<storm::models::sparse::Dtmc<ValueType>>();
337
338 std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(input.properties);
339 auto formula = formulas[0];
340
341 STORM_LOG_THROW(formula->isProbabilityOperatorFormula() || formula->isRewardOperatorFormula(), storm::exceptions::NotSupportedException,
342 "Input formula needs to be either a probability operator formula or a reward operator formula.");
343
345
346 boost::optional<std::string> rewardModel = boost::none;
347 if (formula->isRewardOperatorFormula()) {
348 if (formula->asRewardOperatorFormula().hasRewardModelName()) {
349 rewardModel = std::string(formula->asRewardOperatorFormula().getRewardModelName());
350 } else {
351 rewardModel = std::string("");
352 }
353 for (auto const& rewardParameter : storm::models::sparse::getRewardParameters(*dtmc)) {
354 vars.insert(rewardParameter);
355 }
356 }
357 // Use the SparseDerivativeInstantiationModelChecker to retrieve the derivative at an instantiation that is input by the user
358
359 std::unordered_map<std::string, std::string> keyValue = storm::parser::parseKeyValueString(instantiationString);
360 std::map<typename storm::utility::parametric::VariableType<ValueType>::type, typename storm::utility::parametric::CoefficientType<ValueType>::type>
361 instantiation;
362 for (auto const& pair : keyValue) {
363 auto variable = carl::VariablePool::getInstance().findVariableWithName(pair.first);
365 instantiation.emplace(variable, value);
366 }
367
369
371 std::shared_ptr<storm::logic::Formula> formulaWithoutBound;
372 if (!referenceCheckTask.isRewardModelSet()) {
373 formulaWithoutBound = std::make_shared<storm::logic::ProbabilityOperatorFormula>(
374 formulas[0]->asProbabilityOperatorFormula().getSubformula().asSharedPointer(), storm::logic::OperatorInformation(boost::none, boost::none));
375 } else {
376 // No worries, this works as intended, the API is just weird.
377 formulaWithoutBound = std::make_shared<storm::logic::RewardOperatorFormula>(formulas[0]->asRewardOperatorFormula().getSubformula().asSharedPointer());
378 }
381 modelChecker.specifyFormula(Environment(), checkTask);
382
383 for (auto const& parameter : vars) {
384 std::cout << "Derivative w.r.t. " << parameter << ": ";
385
386 auto result = modelChecker.check(Environment(), instantiation, parameter);
387 std::cout << *result << '\n';
388 }
389}
390} // 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
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:30
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:28
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:698
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:694
void verifyPropertiesAtSamplePoints(ModelType const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:165
SampleInformation< ValueType > parseSamples(std::shared_ptr< storm::models::ModelBase > const &model, std::string const &sampleString, bool graphPreserving)
Definition sampling.h:261
void verifyPropertiesAtSamplePointsWithSparseEngineDerivatives(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:233
void sampleDerivatives(std::shared_ptr< storm::models::sparse::Model< ValueType > > model, cli::SymbolicInput const &input, std::string const &instantiationString)
Definition sampling.h:332
void verifyPropertiesAtSamplePointsWithSparseEngine(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:244
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 verifyPropertiesAtSamplePointsDerivative(ModelType const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:80
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)
#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:64
std::vector< std::map< typename storm::utility::parametric::VariableType< ValueType >::type, std::vector< typename storm::utility::parametric::CoefficientType< ValueType >::type > > > cartesianProducts
Definition sampling.h:74