Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
sampling.h
Go to the documentation of this file.
1
2#pragma once
5
7
11
17
23
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 verifyPropertiesAtSamplePoints(ModelType const& model, cli::SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
79 // When samples are provided, we create an instantiation model checker.
80 ModelCheckerType<ModelType, SolveValueType> modelchecker(model);
81
82 for (auto const& property : input.properties) {
84
85 modelchecker.specifyFormula(storm::api::createTask<ValueType>(property.getRawFormula(), true));
86 modelchecker.setInstantiationsAreGraphPreserving(samples.graphPreserving);
87
89
90 std::vector<typename storm::utility::parametric::VariableType<ValueType>::type> parameters;
91 std::vector<typename std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iterators;
92 std::vector<typename std::vector<typename storm::utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iteratorEnds;
93
94 storm::utility::Stopwatch watch(true);
95 for (auto const& product : samples.cartesianProducts) {
96 parameters.clear();
97 iterators.clear();
98 iteratorEnds.clear();
99
100 for (auto const& entry : product) {
101 parameters.push_back(entry.first);
102 iterators.push_back(entry.second.cbegin());
103 iteratorEnds.push_back(entry.second.cend());
104 }
105
106 bool done = false;
107 while (!done) {
108 // Read off valuation.
109 for (uint64_t i = 0; i < parameters.size(); ++i) {
110 valuation[parameters[i]] = *iterators[i];
111 }
112
113 storm::utility::Stopwatch valuationWatch(true);
114 std::unique_ptr<storm::modelchecker::CheckResult> result = modelchecker.check(Environment(), valuation);
115 valuationWatch.stop();
116
117 if (result) {
118 result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model.getInitialStates()));
119 }
120 printInitialStatesResult<ValueType>(result, &valuationWatch, &valuation);
121
122 for (uint64_t i = 0; i < parameters.size(); ++i) {
123 ++iterators[i];
124 if (iterators[i] == iteratorEnds[i]) {
125 // Reset iterator and proceed to move next iterator.
126 iterators[i] = product.at(parameters[i]).cbegin();
127
128 // If the last iterator was removed, we are done.
129 if (i == parameters.size() - 1) {
130 done = true;
131 }
132 } else {
133 // If an iterator was moved but not reset, we have another valuation to check.
134 break;
135 }
136 }
137 }
138 }
139
140 watch.stop();
141 STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << "\n\n");
142 }
143}
144
145template<typename ValueType, typename SolveValueType = double>
147 SampleInformation<ValueType> const& samples) {
148 if (model->isOfType(storm::models::ModelType::Dtmc)) {
149 verifyPropertiesAtSamplePoints<storm::modelchecker::SparseDtmcInstantiationModelChecker, storm::models::sparse::Dtmc<ValueType>, ValueType,
150 SolveValueType>(*model->template as<storm::models::sparse::Dtmc<ValueType>>(), input, samples);
151 } else if (model->isOfType(storm::models::ModelType::Ctmc)) {
152 verifyPropertiesAtSamplePoints<storm::modelchecker::SparseCtmcInstantiationModelChecker, storm::models::sparse::Ctmc<ValueType>, ValueType,
153 SolveValueType>(*model->template as<storm::models::sparse::Ctmc<ValueType>>(), input, samples);
154 } else if (model->isOfType(storm::models::ModelType::Mdp)) {
155 verifyPropertiesAtSamplePoints<storm::modelchecker::SparseMdpInstantiationModelChecker, storm::models::sparse::Mdp<ValueType>, ValueType,
156 SolveValueType>(*model->template as<storm::models::sparse::Mdp<ValueType>>(), input, samples);
157 } else {
158 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs.");
159 }
160}
161
162template<typename ValueType>
163SampleInformation<ValueType> parseSamples(std::shared_ptr<storm::models::ModelBase> const& model, std::string const& sampleString, bool graphPreserving) {
164 STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models.");
165
166 SampleInformation<ValueType> sampleInfo(graphPreserving);
167 if (sampleString.empty()) {
168 return sampleInfo;
169 }
170
171 // Get all parameters from the model.
172 std::set<typename storm::utility::parametric::VariableType<ValueType>::type> modelParameters;
173 auto const& sparseModel = *model->as<storm::models::sparse::Model<ValueType>>();
174 modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel);
175 auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel);
176 modelParameters.insert(rewParameters.begin(), rewParameters.end());
177
178 std::vector<std::string> cartesianProducts;
179 boost::split(cartesianProducts, sampleString, boost::is_any_of(";"));
180 for (auto& product : cartesianProducts) {
181 boost::trim(product);
182
183 // Get the values string for each variable.
184 std::vector<std::string> valuesForVariables;
185 boost::split(valuesForVariables, product, boost::is_any_of(","));
186 for (auto& values : valuesForVariables) {
187 boost::trim(values);
188 }
189
190 std::set<typename storm::utility::parametric::VariableType<ValueType>::type> encounteredParameters;
191 sampleInfo.cartesianProducts.emplace_back();
192 auto& newCartesianProduct = sampleInfo.cartesianProducts.back();
193 for (auto const& varValues : valuesForVariables) {
194 auto equalsPosition = varValues.find("=");
195 STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples.");
196 std::string variableName = varValues.substr(0, equalsPosition);
197 boost::trim(variableName);
198 std::string values = varValues.substr(equalsPosition + 1);
199 boost::trim(values);
200
201 bool foundParameter = false;
203 for (auto const& parameter : modelParameters) {
204 std::stringstream parameterStream;
205 parameterStream << parameter;
206 if (parameterStream.str() == variableName) {
207 foundParameter = true;
208 theParameter = parameter;
209 encounteredParameters.insert(parameter);
210 }
211 }
212 STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'.");
213
214 std::vector<std::string> splitValues;
215 boost::split(splitValues, values, boost::is_any_of(":"));
216 STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter.");
217
218 auto& list = newCartesianProduct[theParameter];
219
220 for (auto& value : splitValues) {
221 boost::trim(value);
223 }
224 }
225
226 STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException,
227 "Variables for all parameters are required when providing samples.");
228 }
229
230 return sampleInfo;
231}
232
233template<typename ValueType>
235 std::string const& instantiationString) {
236 STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotSupportedException,
237 "Gradient descent is currently only supported for DTMCs.");
238 std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> dtmc = model->template as<storm::models::sparse::Dtmc<ValueType>>();
239
240 std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(input.properties);
241 auto formula = formulas[0];
242
243 STORM_LOG_THROW(formula->isProbabilityOperatorFormula() || formula->isRewardOperatorFormula(), storm::exceptions::NotSupportedException,
244 "Input formula needs to be either a probability operator formula or a reward operator formula.");
245
247
248 boost::optional<std::string> rewardModel = boost::none;
249 if (formula->isRewardOperatorFormula()) {
250 if (formula->asRewardOperatorFormula().hasRewardModelName()) {
251 rewardModel = std::string(formula->asRewardOperatorFormula().getRewardModelName());
252 } else {
253 rewardModel = std::string("");
254 }
255 for (auto const& rewardParameter : storm::models::sparse::getRewardParameters(*dtmc)) {
256 vars.insert(rewardParameter);
257 }
258 }
259 // Use the SparseDerivativeInstantiationModelChecker to retrieve the derivative at an instantiation that is input by the user
260
261 std::unordered_map<std::string, std::string> keyValue = storm::parser::parseKeyValueString(instantiationString);
262 std::map<typename storm::utility::parametric::VariableType<ValueType>::type, typename storm::utility::parametric::CoefficientType<ValueType>::type>
263 instantiation;
264 for (auto const& pair : keyValue) {
265 auto variable = carl::VariablePool::getInstance().findVariableWithName(pair.first);
266 auto value = storm::utility::convertNumber<typename storm::utility::parametric::CoefficientType<ValueType>::type>(pair.second);
267 instantiation.emplace(variable, value);
268 }
269
271
273 std::shared_ptr<storm::logic::Formula> formulaWithoutBound;
274 if (!referenceCheckTask.isRewardModelSet()) {
275 formulaWithoutBound = std::make_shared<storm::logic::ProbabilityOperatorFormula>(
276 formulas[0]->asProbabilityOperatorFormula().getSubformula().asSharedPointer(), storm::logic::OperatorInformation(boost::none, boost::none));
277 } else {
278 // No worries, this works as intended, the API is just weird.
279 formulaWithoutBound = std::make_shared<storm::logic::RewardOperatorFormula>(formulas[0]->asRewardOperatorFormula().getSubformula().asSharedPointer());
280 }
283 modelChecker.specifyFormula(Environment(), checkTask);
284
285 for (auto const& parameter : vars) {
286 std::cout << "Derivative w.r.t. " << parameter << ": ";
287
288 auto result = modelChecker.check(Environment(), instantiation, parameter);
289 std::cout << *result << '\n';
290 }
291 return;
292}
293} // 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:190
Base class for all sparse models.
Definition Model.h:33
A class that provides convenience operations to display run times.
Definition Stopwatch.h:14
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:30
#define STORM_PRINT_AND_LOG(message)
Definition macros.h:68
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:707
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:703
SampleInformation< ValueType > parseSamples(std::shared_ptr< storm::models::ModelBase > const &model, std::string const &sampleString, bool graphPreserving)
Definition sampling.h:163
void sampleDerivatives(std::shared_ptr< storm::models::sparse::Model< ValueType > > model, cli::SymbolicInput const &input, std::string const &instantiationString)
Definition sampling.h:234
void verifyPropertiesAtSamplePointsWithSparseEngine(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:146
void verifyPropertiesAtSamplePoints(ModelType const &model, cli::SymbolicInput const &input, SampleInformation< ValueType > const &samples)
Definition sampling.h:78
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:41
TargetType convertNumber(SourceType const &number)
Definition constants.cpp:98
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