22template<
typename ValueType>
32 STORM_LOG_THROW(wellFormedResult.first, storm::exceptions::InvalidModelException,
33 "DFT is not well-formed for analysis: " << wellFormedResult.second <<
".");
37 if (allowModularisation) {
45 if (properties[0]->isTimeOperatorFormula() && allowModularisation) {
47 std::shared_ptr<storm::models::sparse::Model<ValueType>> model =
48 buildModelViaComposition(
dft, properties, symred,
true, relevantEvents, allowDCForRelevant);
50 std::vector<ValueType> resultsValue =
checkModel(model, properties);
52 results.push_back(result);
55 results = checkHelper(
dft, properties, symred, allowModularisation, relevantEvents, allowDCForRelevant, approximationError, approximationHeuristic,
56 eliminateChains, labelBehavior);
62template<
typename ValueType>
68 std::vector<storm::dft::storage::DFT<ValueType>> dfts;
69 bool invResults =
false;
74 if (allowModularisation) {
75 switch (
dft.getTopLevelType()) {
78 dfts =
dft.topModularisation();
84 dfts =
dft.topModularisation();
91 dfts =
dft.topModularisation();
92 nrK = std::static_pointer_cast<storm::dft::storage::elements::DFTVot<ValueType>
const>(
dft.getTopLevelElement())->threshold();
106 if (dfts.size() > 1) {
110 for (
auto property : properties) {
111 if (!property->isProbabilityOperatorFormula()) {
115 std::vector<ValueType> res;
116 for (
auto const& ft : dfts) {
118 dft_results ftResults = checkHelper(ft, {
property}, symred,
true, relevantEvents, allowDCForRelevant, 0.0);
120 res.push_back(boost::get<ValueType>(ftResults[0]));
124 STORM_LOG_TRACE(
"Combining all results... K=" << nrK <<
"; M=" << nrM <<
"; invResults=" << (invResults ?
"On" :
"Off"));
126 int limK = invResults ? -1 : nrM + 1;
127 int chK = invResults ? -1 : 1;
128 for (
int cK = nrK; cK != limK; cK += chK) {
134 for (
size_t i = 0;
i < res.size(); ++
i) {
135 if (permutation & (1ul << i)) {
136 permResult *= res[
i];
143 result += permResult;
144 }
while (permutation < (1ul << nrM) && permutation != 0);
149 results.push_back(result);
155 return checkDFT(dft, properties, symred, relevantEvents, allowDCForRelevant, approximationError, approximationHeuristic, eliminateChains,
160template<
typename ValueType>
161std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> DFTModelChecker<ValueType>::buildModelViaComposition(
162 storm::dft::storage::DFT<ValueType>
const& dft, property_vector
const& properties,
bool symred,
bool allowModularisation,
163 storm::dft::utility::RelevantEvents
const& relevantEvents,
bool allowDCForRelevant) {
166 std::vector<storm::dft::storage::DFT<ValueType>> dfts;
170 if (allowModularisation) {
175 STORM_LOG_TRACE(
"Modularisation into " << dfts.size() <<
" submodules.");
181 STORM_LOG_TRACE(
"Modularisation into " << dfts.size() <<
" submodules.");
194 if (dfts.size() > 1) {
196 bool firstTime =
true;
197 std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> composedModel;
198 for (
auto const& ft : dfts) {
200 explorationTimer.start();
202 ft.setRelevantEvents(relevantEvents, allowDCForRelevant);
204 storm::dft::storage::DftSymmetries symmetries;
212 STORM_LOG_DEBUG(
"Building Model from DFT with top level element " << *ft.getElement(ft.getTopLevelIndex()) <<
" ...");
213 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(ft, symmetries);
214 builder.buildModel(0, 0.0);
215 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
216 explorationTimer.stop();
219 "Parallel composition only applicable for CTMCs.");
220 std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> ctmc = model->template as<storm::models::sparse::Ctmc<ValueType>>();
223 bisimulationTimer.start();
226 ->
template as<storm::models::sparse::Ctmc<ValueType>>();
227 bisimulationTimer.stop();
230 composedModel = ctmc;
237 bisimulationTimer.start();
240 ->
template as<storm::models::sparse::Ctmc<ValueType>>();
241 bisimulationTimer.stop();
243 STORM_LOG_DEBUG(
"No. states (Composed): " << composedModel->getNumberOfStates());
244 STORM_LOG_DEBUG(
"No. transitions (Composed): " << composedModel->getNumberOfTransitions());
245 if (composedModel->getNumberOfStates() <= 15) {
246 STORM_LOG_TRACE(
"Transition matrix: \n" << composedModel->getTransitionMatrix());
252 composedModel->printModelInformationToStream(std::cout);
254 return composedModel;
257 explorationTimer.start();
262 storm::dft::storage::DftSymmetries symmetries;
271 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries);
272 builder.buildModel(0, 0.0);
273 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
275 model->printModelInformationToStream(std::cout);
277 explorationTimer.stop();
279 "Parallel composition only applicable for CTMCs.");
280 return model->template as<storm::models::sparse::Ctmc<ValueType>>();
284template<
typename ValueType>
286 storm::dft::storage::DFT<ValueType>
const& dft, property_vector
const& properties,
bool symred, storm::dft::utility::RelevantEvents
const& relevantEvents,
289 explorationTimer.start();
296 storm::dft::storage::DftSymmetries symmetries;
304 ValueType const precision = std::is_same<ValueType, storm::RationalFunction>::value
307 if (approximationError > 0.0) {
309 storm::utility::ConstantsComparator<ValueType> comparator(precision);
313 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
314 std::vector<ValueType> newResult;
315 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries);
318 std::shared_ptr<const storm::logic::Formula>
property = properties[0];
319 if (properties.size() > 1) {
320 STORM_LOG_WARN(
"Computing approximation only for first property: " << *property);
323 bool probabilityFormula =
property->isProbabilityOperatorFormula();
324 STORM_LOG_ASSERT((property->isTimeOperatorFormula() && !probabilityFormula) || (!property->isTimeOperatorFormula() && probabilityFormula),
325 "Probability formula not initialized correctly.");
326 size_t iteration = 0;
330 explorationTimer.start();
334 builder.buildModel(iteration, approximationError, approximationHeuristic);
335 explorationTimer.stop();
336 buildingTimer.start();
342 model = builder.getModelApproximation(
true, !probabilityFormula);
344 if (printInfo && dftIOSettings.isShowDftStatisticsSet()) {
345 std::cout <<
"Model in iteration " << (iteration + 1) <<
":\n";
346 model->printModelInformationToStream(std::cout);
348 buildingTimer.stop();
350 if (ioSettings.isExportExplicitSet()) {
351 std::vector<std::string> parameterNames;
354 !ioSettings.isExplicitExportPlaceholdersDisabled());
360 STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(newResult[0], approxResult.first),
361 "New under-approximation " << newResult[0] <<
" is smaller than old result " << approxResult.first);
362 approxResult.first = newResult[0];
366 buildingTimer.start();
367 model = builder.getModelApproximation(
false, !probabilityFormula);
368 buildingTimer.stop();
372 STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(approxResult.second, newResult[0]),
373 "New over-approximation " << newResult[0] <<
" is greater than old result " << approxResult.second);
374 approxResult.second = newResult[0];
376 STORM_LOG_ASSERT(comparator.isLess(approxResult.first, approxResult.second) || comparator.isEqual(approxResult.first, approxResult.second),
377 "Under-approximation " << approxResult.first <<
" is greater than over-approximation " << approxResult.second);
379 if (printInfo && dftIOSettings.isShowDftStatisticsSet()) {
380 std::cout <<
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")\n";
384 STORM_LOG_DEBUG(
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")");
389 storm::exceptions::NotSupportedException,
"Approximation does not work if result might be infinity.");
391 }
while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula));
395 model->printModelInformationToStream(std::cout);
398 results.push_back(approxResult);
403 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries);
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>
440std::vector<ValueType> DFTModelChecker<ValueType>::checkModel(std::shared_ptr<storm::models::sparse::Model<ValueType>>& model,
441 property_vector
const& properties) {
444 bisimulationTimer.start();
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;
460 storm::utility::Stopwatch singleModelCheckingTimer;
461 for (
auto property : properties) {
462 singleModelCheckingTimer.
reset();
463 singleModelCheckingTimer.
start();
465 std::unique_ptr<storm::modelchecker::CheckResult> result(
469 result->filter(storm::modelchecker::ExplicitQualitativeCheckResult<ValueType>(model->getInitialStates()));
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.");
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)
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.
void printResults(dft_results const &results, std::ostream &os=std::cout) const
Print result to stream.
void printTimings(std::ostream &os=std::cout) const
Print timings of all operations to stream.
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.
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)
storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > createTask(std::shared_ptr< const storm::logic::Formula > const &formula, bool onlyInitialStatesRelevant=false)
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::shared_ptr< ModelType > performDeterministicSparseBisimulationMinimization(std::shared_ptr< ModelType > model, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas, storm::storage::BisimulationType type, bool graphPreserving=true, std::optional< double > const &tolerance=std::nullopt)
std::unique_ptr< storm::modelchecker::CheckResult > verifyWithSparseEngine(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Dtmc< ValueType > > const &dtmc, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task)
std::pair< bool, std::string > isWellFormed(storm::dft::storage::DFT< ValueType > const &dft, bool validForMarkovianAnalysis)
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.
bool isInfinity(ValueType const &a)
TargetType convertNumber(SourceType const &number)