17namespace modelchecker {
19template<
typename ValueType>
29 STORM_LOG_THROW(wellFormedResult.first, storm::exceptions::InvalidModelException,
"DFT is not well-formed for analysis: " << wellFormedResult.second);
33 if (allowModularisation) {
41 if (properties[0]->isTimeOperatorFormula() && allowModularisation) {
43 std::shared_ptr<storm::models::sparse::Model<ValueType>> model =
44 buildModelViaComposition(dft, properties, symred,
true, relevantEvents, allowDCForRelevant);
46 std::vector<ValueType> resultsValue =
checkModel(model, properties);
48 results.push_back(result);
51 results = checkHelper(dft, properties, symred, allowModularisation, relevantEvents, allowDCForRelevant, approximationError, approximationHeuristic,
52 eliminateChains, labelBehavior);
58template<
typename ValueType>
64 std::vector<storm::dft::storage::DFT<ValueType>> dfts;
65 bool invResults =
false;
70 if (allowModularisation) {
88 nrK = std::static_pointer_cast<storm::dft::storage::elements::DFTVot<ValueType>
const>(dft.
getTopLevelElement())->threshold();
102 if (dfts.size() > 1) {
106 for (
auto property : properties) {
107 if (!property->isProbabilityOperatorFormula()) {
111 std::vector<ValueType> res;
112 for (
auto const& ft : dfts) {
114 dft_results ftResults = checkHelper(ft, {
property}, symred,
true, relevantEvents, allowDCForRelevant, 0.0);
116 res.push_back(boost::get<ValueType>(ftResults[0]));
120 STORM_LOG_TRACE(
"Combining all results... K=" << nrK <<
"; M=" << nrM <<
"; invResults=" << (invResults ?
"On" :
"Off"));
121 ValueType result = storm::utility::zero<ValueType>();
122 int limK = invResults ? -1 : nrM + 1;
123 int chK = invResults ? -1 : 1;
124 for (
int cK = nrK; cK != limK; cK += chK) {
129 ValueType permResult = storm::utility::one<ValueType>();
130 for (
size_t i = 0;
i < res.size(); ++
i) {
131 if (permutation & (1ul << i)) {
132 permResult *= res[
i];
134 permResult *= storm::utility::one<ValueType>() - res[
i];
139 result += permResult;
140 }
while (permutation < (1ul << nrM) && permutation != 0);
143 result = storm::utility::one<ValueType>() - result;
145 results.push_back(result);
151 return checkDFT(dft, properties, symred, relevantEvents, allowDCForRelevant, approximationError, approximationHeuristic, eliminateChains,
156template<
typename ValueType>
157std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> DFTModelChecker<ValueType>::buildModelViaComposition(
162 std::vector<storm::dft::storage::DFT<ValueType>> dfts;
166 if (allowModularisation) {
171 STORM_LOG_TRACE(
"Modularisation into " << dfts.size() <<
" submodules.");
177 STORM_LOG_TRACE(
"Modularsation into " << dfts.size() <<
" submodules.");
190 if (dfts.size() > 1) {
192 bool firstTime =
true;
193 std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> composedModel;
194 for (
auto const& ft : dfts) {
196 explorationTimer.start();
198 ft.setRelevantEvents(relevantEvents, allowDCForRelevant);
208 STORM_LOG_DEBUG(
"Building Model from DFT with top level element " << *ft.getElement(ft.getTopLevelIndex()) <<
" ...");
210 builder.buildModel(0, 0.0);
211 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
212 explorationTimer.stop();
215 "Parallel composition only applicable for CTMCs");
216 std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> ctmc = model->template as<storm::models::sparse::Ctmc<ValueType>>();
219 bisimulationTimer.start();
220 ctmc = storm::api::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(
223 bisimulationTimer.stop();
226 composedModel = ctmc;
233 bisimulationTimer.start();
234 composedModel = storm::api::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(
237 bisimulationTimer.stop();
239 STORM_LOG_DEBUG(
"No. states (Composed): " << composedModel->getNumberOfStates());
240 STORM_LOG_DEBUG(
"No. transitions (Composed): " << composedModel->getNumberOfTransitions());
241 if (composedModel->getNumberOfStates() <= 15) {
242 STORM_LOG_TRACE(
"Transition matrix: \n" << composedModel->getTransitionMatrix());
248 composedModel->printModelInformationToStream(std::cout);
250 return composedModel;
253 explorationTimer.start();
268 builder.buildModel(0, 0.0);
269 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
271 model->printModelInformationToStream(std::cout);
273 explorationTimer.stop();
275 "Parallel composition only applicable for CTMCs");
276 return model->template as<storm::models::sparse::Ctmc<ValueType>>();
280template<
typename ValueType>
285 explorationTimer.start();
286 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
287 auto dftIOSettings = storm::settings::getModule<storm::dft::settings::modules::DftIOSettings>();
299 auto const& generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>();
300 ValueType const precision = std::is_same<ValueType, storm::RationalFunction>::value
301 ? storm::utility::zero<ValueType>()
303 if (approximationError > 0.0) {
308 approximation_result approxResult = std::make_pair(storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
309 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
310 std::vector<ValueType> newResult;
314 std::shared_ptr<const storm::logic::Formula>
property = properties[0];
315 if (properties.size() > 1) {
316 STORM_LOG_WARN(
"Computing approximation only for first property: " << *property);
319 bool probabilityFormula =
property->isProbabilityOperatorFormula();
320 STORM_LOG_ASSERT((property->isTimeOperatorFormula() && !probabilityFormula) || (!property->isTimeOperatorFormula() && probabilityFormula),
321 "Probability formula not initialized correctly");
322 size_t iteration = 0;
326 explorationTimer.start();
330 builder.buildModel(iteration, approximationError, approximationHeuristic);
331 explorationTimer.stop();
332 buildingTimer.start();
338 model = builder.getModelApproximation(
true, !probabilityFormula);
340 if (printInfo && dftIOSettings.isShowDftStatisticsSet()) {
341 std::cout <<
"Model in iteration " << (iteration + 1) <<
":\n";
342 model->printModelInformationToStream(std::cout);
344 buildingTimer.stop();
346 if (ioSettings.isExportExplicitSet()) {
347 std::vector<std::string> parameterNames;
350 !ioSettings.isExplicitExportPlaceholdersDisabled());
356 STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(newResult[0], approxResult.first),
357 "New under-approximation " << newResult[0] <<
" is smaller than old result " << approxResult.first);
358 approxResult.first = newResult[0];
362 buildingTimer.start();
363 model = builder.getModelApproximation(
false, !probabilityFormula);
364 buildingTimer.stop();
368 STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(approxResult.second, newResult[0]),
369 "New over-approximation " << newResult[0] <<
" is greater than old result " << approxResult.second);
370 approxResult.second = newResult[0];
372 STORM_LOG_ASSERT(comparator.isLess(approxResult.first, approxResult.second) || comparator.isEqual(approxResult.first, approxResult.second),
373 "Under-approximation " << approxResult.first <<
" is greater than over-approximation " << approxResult.second);
375 if (printInfo && dftIOSettings.isShowDftStatisticsSet()) {
376 std::cout <<
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")\n";
380 STORM_LOG_DEBUG(
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")");
384 STORM_LOG_THROW(!storm::utility::isInfinity<ValueType>(approxResult.first) && !storm::utility::isInfinity<ValueType>(approxResult.second),
385 storm::exceptions::NotSupportedException,
"Approximation does not work if result might be infinity.");
387 }
while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula));
391 model->printModelInformationToStream(std::cout);
394 results.push_back(approxResult);
398 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
401 builder.buildModel(0, 0.0);
402 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
404 auto ma = std::static_pointer_cast<storm::models::sparse::MarkovAutomaton<ValueType>>(model);
407 explorationTimer.stop();
411 model->printModelInformationToStream(std::cout);
416 if (ioSettings.isExportExplicitSet()) {
417 std::vector<std::string> parameterNames;
420 !ioSettings.isExplicitExportPlaceholdersDisabled());
422 if (ioSettings.isExportDotSet()) {
427 std::vector<ValueType> resultsValue =
checkModel(model, properties);
430 results.push_back(result);
436template<
typename ValueType>
438 property_vector
const& properties) {
440 if (model->isOfType(
storm::models::ModelType::Ctmc) && storm::settings::getModule<storm::settings::modules::GeneralSettings>().isBisimulationSet()) {
441 bisimulationTimer.start();
443 model = storm::api::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(
445 ->template as<storm::models::sparse::Ctmc<ValueType>>();
446 STORM_LOG_DEBUG(
"No. states (Bisimulation): " << model->getNumberOfStates());
447 STORM_LOG_DEBUG(
"No. transitions (Bisimulation): " << model->getNumberOfTransitions());
448 bisimulationTimer.stop();
453 modelCheckingTimer.start();
454 std::vector<ValueType> results;
458 for (
auto property : properties) {
459 singleModelCheckingTimer.
reset();
460 singleModelCheckingTimer.
start();
462 std::unique_ptr<storm::modelchecker::CheckResult> result(
463 storm::api::verifyWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(property,
true)));
467 ValueType resultValue = result->asExplicitQuantitativeCheckResult<
ValueType>().getValueMap().begin()->second;
468 results.push_back(resultValue);
470 STORM_LOG_WARN(
"The property '" << *property <<
"' could not be checked with the current settings.");
471 results.push_back(-storm::utility::one<ValueType>());
474 singleModelCheckingTimer.
stop();
477 modelCheckingTimer.stop();
482template<
typename ValueType>
483bool DFTModelChecker<ValueType>::isApproximationSufficient(
ValueType,
ValueType,
double,
bool) {
484 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Approximation works only for double.");
488bool DFTModelChecker<double>::isApproximationSufficient(
double lowerBound,
double upperBound,
double approximationError,
bool relative) {
489 STORM_LOG_THROW(!std::isnan(lowerBound) && !std::isnan(upperBound), storm::exceptions::NotSupportedException,
490 "Approximation does not work if result is NaN.");
492 return upperBound - lowerBound <= approximationError;
494 return upperBound - lowerBound <= approximationError * (lowerBound + upperBound) / 2;
498template<
typename ValueType>
501 os <<
"Exploration:\t" << explorationTimer <<
'\n';
502 os <<
"Building:\t" << buildingTimer <<
'\n';
503 os <<
"Bisimulation:\t" << bisimulationTimer <<
'\n';
504 os <<
"Modelchecking:\t" << modelCheckingTimer <<
'\n';
505 os <<
"Total:\t\t" << totalTimer <<
'\n';
508template<
typename ValueType>
512 for (
auto result : results) {
518 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)