20namespace modelchecker {
22template<
typename ValueType>
32 STORM_LOG_THROW(wellFormedResult.first, storm::exceptions::InvalidModelException,
"DFT is not well-formed for analysis: " << wellFormedResult.second);
36 if (allowModularisation) {
44 if (properties[0]->isTimeOperatorFormula() && allowModularisation) {
46 std::shared_ptr<storm::models::sparse::Model<ValueType>> model =
47 buildModelViaComposition(dft, properties, symred,
true, relevantEvents, allowDCForRelevant);
49 std::vector<ValueType> resultsValue =
checkModel(model, properties);
51 results.push_back(result);
54 results = checkHelper(dft, properties, symred, allowModularisation, relevantEvents, allowDCForRelevant, approximationError, approximationHeuristic,
55 eliminateChains, labelBehavior);
61template<
typename ValueType>
67 std::vector<storm::dft::storage::DFT<ValueType>> dfts;
68 bool invResults =
false;
73 if (allowModularisation) {
91 nrK = std::static_pointer_cast<storm::dft::storage::elements::DFTVot<ValueType>
const>(dft.
getTopLevelElement())->threshold();
105 if (dfts.size() > 1) {
109 for (
auto property : properties) {
110 if (!property->isProbabilityOperatorFormula()) {
114 std::vector<ValueType> res;
115 for (
auto const& ft : dfts) {
117 dft_results ftResults = checkHelper(ft, {
property}, symred,
true, relevantEvents, allowDCForRelevant, 0.0);
119 res.push_back(boost::get<ValueType>(ftResults[0]));
123 STORM_LOG_TRACE(
"Combining all results... K=" << nrK <<
"; M=" << nrM <<
"; invResults=" << (invResults ?
"On" :
"Off"));
124 ValueType result = storm::utility::zero<ValueType>();
125 int limK = invResults ? -1 : nrM + 1;
126 int chK = invResults ? -1 : 1;
127 for (
int cK = nrK; cK != limK; cK += chK) {
132 ValueType permResult = storm::utility::one<ValueType>();
133 for (
size_t i = 0;
i < res.size(); ++
i) {
134 if (permutation & (1ul << i)) {
135 permResult *= res[
i];
137 permResult *= storm::utility::one<ValueType>() - res[
i];
142 result += permResult;
143 }
while (permutation < (1ul << nrM) && permutation != 0);
146 result = storm::utility::one<ValueType>() - result;
148 results.push_back(result);
154 return checkDFT(dft, properties, symred, relevantEvents, allowDCForRelevant, approximationError, approximationHeuristic, eliminateChains,
159template<
typename ValueType>
160std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> DFTModelChecker<ValueType>::buildModelViaComposition(
165 std::vector<storm::dft::storage::DFT<ValueType>> dfts;
169 if (allowModularisation) {
174 STORM_LOG_TRACE(
"Modularisation into " << dfts.size() <<
" submodules.");
180 STORM_LOG_TRACE(
"Modularsation into " << dfts.size() <<
" submodules.");
193 if (dfts.size() > 1) {
195 bool firstTime =
true;
196 std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> composedModel;
197 for (
auto const& ft : dfts) {
199 explorationTimer.start();
201 ft.setRelevantEvents(relevantEvents, allowDCForRelevant);
211 STORM_LOG_DEBUG(
"Building Model from DFT with top level element " << *ft.getElement(ft.getTopLevelIndex()) <<
" ...");
213 builder.buildModel(0, 0.0);
214 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
215 explorationTimer.stop();
218 "Parallel composition only applicable for CTMCs");
219 std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> ctmc = model->template as<storm::models::sparse::Ctmc<ValueType>>();
222 bisimulationTimer.start();
223 ctmc = storm::api::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(
226 bisimulationTimer.stop();
229 composedModel = ctmc;
236 bisimulationTimer.start();
237 composedModel = storm::api::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(
240 bisimulationTimer.stop();
242 STORM_LOG_DEBUG(
"No. states (Composed): " << composedModel->getNumberOfStates());
243 STORM_LOG_DEBUG(
"No. transitions (Composed): " << composedModel->getNumberOfTransitions());
244 if (composedModel->getNumberOfStates() <= 15) {
245 STORM_LOG_TRACE(
"Transition matrix: \n" << composedModel->getTransitionMatrix());
251 composedModel->printModelInformationToStream(std::cout);
253 return composedModel;
256 explorationTimer.start();
271 builder.buildModel(0, 0.0);
272 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
274 model->printModelInformationToStream(std::cout);
276 explorationTimer.stop();
278 "Parallel composition only applicable for CTMCs");
279 return model->template as<storm::models::sparse::Ctmc<ValueType>>();
283template<
typename ValueType>
288 explorationTimer.start();
302 if (approximationError > 0.0) {
306 approximation_result approxResult = std::make_pair(storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
307 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
308 std::vector<ValueType> newResult;
312 std::shared_ptr<const storm::logic::Formula>
property = properties[0];
313 if (properties.size() > 1) {
314 STORM_LOG_WARN(
"Computing approximation only for first property: " << *property);
317 bool probabilityFormula =
property->isProbabilityOperatorFormula();
318 STORM_LOG_ASSERT((property->isTimeOperatorFormula() && !probabilityFormula) || (!property->isTimeOperatorFormula() && probabilityFormula),
319 "Probability formula not initialized correctly");
320 size_t iteration = 0;
324 explorationTimer.start();
328 builder.buildModel(iteration, approximationError, approximationHeuristic);
329 explorationTimer.stop();
330 buildingTimer.start();
336 model = builder.getModelApproximation(
true, !probabilityFormula);
338 if (printInfo && dftIOSettings.isShowDftStatisticsSet()) {
339 std::cout <<
"Model in iteration " << (iteration + 1) <<
":\n";
340 model->printModelInformationToStream(std::cout);
342 buildingTimer.stop();
344 if (ioSettings.isExportExplicitSet()) {
345 std::vector<std::string> parameterNames;
348 !ioSettings.isExplicitExportPlaceholdersDisabled());
355 "New under-approximation " << newResult[0] <<
" is smaller than old result " << approxResult.first);
356 approxResult.first = newResult[0];
360 buildingTimer.start();
361 model = builder.getModelApproximation(
false, !probabilityFormula);
362 buildingTimer.stop();
367 "New over-approximation " << newResult[0] <<
" is greater than old result " << approxResult.second);
368 approxResult.second = newResult[0];
371 "Under-approximation " << approxResult.first <<
" is greater than over-approximation " << approxResult.second);
373 if (printInfo && dftIOSettings.isShowDftStatisticsSet()) {
374 std::cout <<
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")\n";
378 STORM_LOG_DEBUG(
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")");
382 STORM_LOG_THROW(!storm::utility::isInfinity<ValueType>(approxResult.first) && !storm::utility::isInfinity<ValueType>(approxResult.second),
383 storm::exceptions::NotSupportedException,
"Approximation does not work if result might be infinity.");
385 }
while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula));
389 model->printModelInformationToStream(std::cout);
392 results.push_back(approxResult);
399 builder.buildModel(0, 0.0);
400 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
402 auto ma = std::static_pointer_cast<storm::models::sparse::MarkovAutomaton<ValueType>>(model);
405 explorationTimer.stop();
409 model->printModelInformationToStream(std::cout);
414 if (ioSettings.isExportExplicitSet()) {
415 std::vector<std::string> parameterNames;
418 !ioSettings.isExplicitExportPlaceholdersDisabled());
420 if (ioSettings.isExportDotSet()) {
425 std::vector<ValueType> resultsValue =
checkModel(model, properties);
428 results.push_back(result);
434template<
typename ValueType>
436 property_vector
const& properties) {
439 bisimulationTimer.start();
441 model = storm::api::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(
443 ->template as<storm::models::sparse::Ctmc<ValueType>>();
444 STORM_LOG_DEBUG(
"No. states (Bisimulation): " << model->getNumberOfStates());
445 STORM_LOG_DEBUG(
"No. transitions (Bisimulation): " << model->getNumberOfTransitions());
446 bisimulationTimer.stop();
451 modelCheckingTimer.start();
452 std::vector<ValueType> results;
456 for (
auto property : properties) {
457 singleModelCheckingTimer.
reset();
458 singleModelCheckingTimer.
start();
460 std::unique_ptr<storm::modelchecker::CheckResult> result(
461 storm::api::verifyWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(property,
true)));
465 ValueType resultValue = result->asExplicitQuantitativeCheckResult<
ValueType>().getValueMap().begin()->second;
466 results.push_back(resultValue);
468 STORM_LOG_WARN(
"The property '" << *property <<
"' could not be checked with the current settings.");
469 results.push_back(-storm::utility::one<ValueType>());
472 singleModelCheckingTimer.
stop();
475 modelCheckingTimer.stop();
480template<
typename ValueType>
481bool DFTModelChecker<ValueType>::isApproximationSufficient(
ValueType,
ValueType,
double,
bool) {
482 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Approximation works only for double.");
486bool DFTModelChecker<double>::isApproximationSufficient(
double lowerBound,
double upperBound,
double approximationError,
bool relative) {
487 STORM_LOG_THROW(!std::isnan(lowerBound) && !std::isnan(upperBound), storm::exceptions::NotSupportedException,
488 "Approximation does not work if result is NaN.");
490 return upperBound - lowerBound <= approximationError;
492 return upperBound - lowerBound <= approximationError * (lowerBound + upperBound) / 2;
496template<
typename ValueType>
499 os <<
"Exploration:\t" << explorationTimer <<
'\n';
500 os <<
"Building:\t" << buildingTimer <<
'\n';
501 os <<
"Bisimulation:\t" << bisimulationTimer <<
'\n';
502 os <<
"Modelchecking:\t" << modelCheckingTimer <<
'\n';
503 os <<
"Total:\t\t" << totalTimer <<
'\n';
506template<
typename ValueType>
510 for (
auto result : results) {
516 boost::variant<std::ostream&> stream(os);
void checkModel(std::string const &path, std::string const &formulaString, double maxmin, double maxmax, double minmax, double minmin, bool produceScheduler)
uint64_t nextBitPermutation(uint64_t v)
The next bit permutation in a lexicographical sense.
uint64_t smallestIntWithNBitsSet(uint64_t n)
static std::shared_ptr< storm::models::sparse::Ctmc< ValueType > > compose(std::shared_ptr< storm::models::sparse::Ctmc< ValueType > > const &ctmcA, std::shared_ptr< storm::models::sparse::Ctmc< ValueType > > const &ctmcB, bool labelAnd)
Build a Markov chain from DFT.
void printTimings(std::ostream &os=std::cout)
Print timings of all operations to stream.
void printResults(dft_results const &results, std::ostream &os=std::cout)
Print result to stream.
std::vector< boost::variant< ValueType, approximation_result > > dft_results
dft_results check(storm::dft::storage::DFT< ValueType > const &origDft, property_vector const &properties, bool symred=true, bool allowModularisation=true, storm::dft::utility::RelevantEvents const &relevantEvents={}, bool allowDCForRelevant=false, double approximationError=0.0, storm::dft::builder::ApproximationHeuristic approximationHeuristic=storm::dft::builder::ApproximationHeuristic::DEPTH, bool eliminateChains=false, storm::transformer::EliminationLabelBehavior labelBehavior=storm::transformer::EliminationLabelBehavior::KeepLabels)
Main method for checking DFTs.
Represents a Dynamic Fault Tree.
void setRelevantEvents(storm::dft::utility::RelevantEvents const &relevantEvents, bool const allowDCForRelevant) const
Set the relevance flag for all elements according to the given relevant events.
storm::dft::storage::elements::DFTElementType getTopLevelType() const
DFTElementCPointer getTopLevelElement() const
std::vector< DFT< ValueType > > topModularisation() const
DFT< ValueType > optimize() const
size_t nrSymmetries() const
static storm::dft::storage::DftSymmetries findSymmetries(storm::dft::storage::DFT< ValueType > const &dft)
Find symmetries in the given DFT.
This class represents a continuous-time Markov chain.
Base class for all sparse models.
bool isEqual(ValueType const &value1, ValueType const &value2) const
bool isLess(ValueType const &value1, ValueType const &value2) const
A class that provides convenience operations to display run times.
void start()
Start stopwatch (again) and start measuring time.
void reset()
Reset the stopwatch.
void stop()
Stop stopwatch and add measured time to total time.
#define STORM_LOG_WARN(message)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
void exportSparseModelAsDrn(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::string const &filename, std::vector< std::string > const ¶meterNames={}, bool allowPlaceholders=true)
void exportSparseModelAsDot(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::string const &filename, size_t maxWidth=30)
std::pair< bool, std::string > isWellFormed(storm::dft::storage::DFT< ValueType > const &dft, bool validForMarkovianAnalysis=true)
Check whether the DFT is well-formed.
ApproximationHeuristic
Enum representing the heuristic used for deciding which states to expand.
SFTBDDChecker::ValueType ValueType
SettingsType const & getModule()
Get module.