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();
289 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
290 auto dftIOSettings = storm::settings::getModule<storm::dft::settings::modules::DftIOSettings>();
302 auto const& generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>();
303 ValueType const precision = std::is_same<ValueType, storm::RationalFunction>::value
304 ? storm::utility::zero<ValueType>()
306 if (approximationError > 0.0) {
311 approximation_result approxResult = std::make_pair(storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
312 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
313 std::vector<ValueType> newResult;
317 std::shared_ptr<const storm::logic::Formula>
property = properties[0];
318 if (properties.size() > 1) {
319 STORM_LOG_WARN(
"Computing approximation only for first property: " << *property);
322 bool probabilityFormula =
property->isProbabilityOperatorFormula();
323 STORM_LOG_ASSERT((property->isTimeOperatorFormula() && !probabilityFormula) || (!property->isTimeOperatorFormula() && probabilityFormula),
324 "Probability formula not initialized correctly");
325 size_t iteration = 0;
329 explorationTimer.start();
333 builder.buildModel(iteration, approximationError, approximationHeuristic);
334 explorationTimer.stop();
335 buildingTimer.start();
341 model = builder.getModelApproximation(
true, !probabilityFormula);
343 if (printInfo && dftIOSettings.isShowDftStatisticsSet()) {
344 std::cout <<
"Model in iteration " << (iteration + 1) <<
":\n";
345 model->printModelInformationToStream(std::cout);
347 buildingTimer.stop();
349 if (ioSettings.isExportExplicitSet()) {
350 std::vector<std::string> parameterNames;
353 !ioSettings.isExplicitExportPlaceholdersDisabled());
359 STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(newResult[0], approxResult.first),
360 "New under-approximation " << newResult[0] <<
" is smaller than old result " << approxResult.first);
361 approxResult.first = newResult[0];
365 buildingTimer.start();
366 model = builder.getModelApproximation(
false, !probabilityFormula);
367 buildingTimer.stop();
371 STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(approxResult.second, newResult[0]),
372 "New over-approximation " << newResult[0] <<
" is greater than old result " << approxResult.second);
373 approxResult.second = newResult[0];
375 STORM_LOG_ASSERT(comparator.isLess(approxResult.first, approxResult.second) || comparator.isEqual(approxResult.first, approxResult.second),
376 "Under-approximation " << approxResult.first <<
" is greater than over-approximation " << approxResult.second);
378 if (printInfo && dftIOSettings.isShowDftStatisticsSet()) {
379 std::cout <<
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")\n";
383 STORM_LOG_DEBUG(
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")");
387 STORM_LOG_THROW(!storm::utility::isInfinity<ValueType>(approxResult.first) && !storm::utility::isInfinity<ValueType>(approxResult.second),
388 storm::exceptions::NotSupportedException,
"Approximation does not work if result might be infinity.");
390 }
while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula));
394 model->printModelInformationToStream(std::cout);
397 results.push_back(approxResult);
401 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
404 builder.buildModel(0, 0.0);
405 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
407 auto ma = std::static_pointer_cast<storm::models::sparse::MarkovAutomaton<ValueType>>(model);
410 explorationTimer.stop();
414 model->printModelInformationToStream(std::cout);
419 if (ioSettings.isExportExplicitSet()) {
420 std::vector<std::string> parameterNames;
423 !ioSettings.isExplicitExportPlaceholdersDisabled());
425 if (ioSettings.isExportDotSet()) {
430 std::vector<ValueType> resultsValue =
checkModel(model, properties);
433 results.push_back(result);
439template<
typename ValueType>
441 property_vector
const& properties) {
443 if (model->isOfType(
storm::models::ModelType::Ctmc) && storm::settings::getModule<storm::settings::modules::GeneralSettings>().isBisimulationSet()) {
444 bisimulationTimer.start();
446 model = storm::api::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(
448 ->template as<storm::models::sparse::Ctmc<ValueType>>();
449 STORM_LOG_DEBUG(
"No. states (Bisimulation): " << model->getNumberOfStates());
450 STORM_LOG_DEBUG(
"No. transitions (Bisimulation): " << model->getNumberOfTransitions());
451 bisimulationTimer.stop();
456 modelCheckingTimer.start();
457 std::vector<ValueType> results;
461 for (
auto property : properties) {
462 singleModelCheckingTimer.
reset();
463 singleModelCheckingTimer.
start();
465 std::unique_ptr<storm::modelchecker::CheckResult> result(
466 storm::api::verifyWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(property,
true)));
470 ValueType resultValue = result->asExplicitQuantitativeCheckResult<
ValueType>().getValueMap().begin()->second;
471 results.push_back(resultValue);
473 STORM_LOG_WARN(
"The property '" << *property <<
"' could not be checked with the current settings.");
474 results.push_back(-storm::utility::one<ValueType>());
477 singleModelCheckingTimer.
stop();
480 modelCheckingTimer.stop();
485template<
typename ValueType>
486bool DFTModelChecker<ValueType>::isApproximationSufficient(
ValueType,
ValueType,
double,
bool) {
487 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Approximation works only for double.");
491bool DFTModelChecker<double>::isApproximationSufficient(
double lowerBound,
double upperBound,
double approximationError,
bool relative) {
492 STORM_LOG_THROW(!std::isnan(lowerBound) && !std::isnan(upperBound), storm::exceptions::NotSupportedException,
493 "Approximation does not work if result is NaN.");
495 return upperBound - lowerBound <= approximationError;
497 return upperBound - lowerBound <= approximationError * (lowerBound + upperBound) / 2;
501template<
typename ValueType>
504 os <<
"Exploration:\t" << explorationTimer <<
'\n';
505 os <<
"Building:\t" << buildingTimer <<
'\n';
506 os <<
"Bisimulation:\t" << bisimulationTimer <<
'\n';
507 os <<
"Modelchecking:\t" << modelCheckingTimer <<
'\n';
508 os <<
"Total:\t\t" << totalTimer <<
'\n';
511template<
typename ValueType>
515 for (
auto result : results) {
521 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.
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
TargetType convertNumber(SourceType const &number)