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) {
71 switch (
dft.getTopLevelType()) {
74 dfts =
dft.topModularisation();
80 dfts =
dft.topModularisation();
87 dfts =
dft.topModularisation();
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"));
122 int limK = invResults ? -1 : nrM + 1;
123 int chK = invResults ? -1 : 1;
124 for (
int cK = nrK; cK != limK; cK += chK) {
130 for (
size_t i = 0;
i < res.size(); ++
i) {
131 if (permutation & (1ul << i)) {
132 permResult *= res[
i];
139 result += permResult;
140 }
while (permutation < (1ul << nrM) && permutation != 0);
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(
158 storm::dft::storage::DFT<ValueType>
const& dft, property_vector
const& properties,
bool symred,
bool allowModularisation,
159 storm::dft::utility::RelevantEvents
const& relevantEvents,
bool allowDCForRelevant) {
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);
200 storm::dft::storage::DftSymmetries symmetries;
208 STORM_LOG_DEBUG(
"Building Model from DFT with top level element " << *ft.getElement(ft.getTopLevelIndex()) <<
" ...");
209 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(ft, symmetries);
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();
222 ->
template as<storm::models::sparse::Ctmc<ValueType>>();
223 bisimulationTimer.stop();
226 composedModel = ctmc;
233 bisimulationTimer.start();
236 ->
template as<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();
258 storm::dft::storage::DftSymmetries symmetries;
267 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries);
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>
282 storm::dft::storage::DFT<ValueType>
const& dft, property_vector
const& properties,
bool symred, storm::dft::utility::RelevantEvents
const& relevantEvents,
285 explorationTimer.start();
292 storm::dft::storage::DftSymmetries symmetries;
300 ValueType const precision = std::is_same<ValueType, storm::RationalFunction>::value
303 if (approximationError > 0.0) {
305 storm::utility::ConstantsComparator<ValueType> comparator(precision);
309 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
310 std::vector<ValueType> newResult;
311 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries);
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 <<
")");
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);
400 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries);
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>
437std::vector<ValueType> DFTModelChecker<ValueType>::checkModel(std::shared_ptr<storm::models::sparse::Model<ValueType>>& model,
438 property_vector
const& properties) {
441 bisimulationTimer.start();
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;
457 storm::utility::Stopwatch singleModelCheckingTimer;
458 for (
auto property : properties) {
459 singleModelCheckingTimer.
reset();
460 singleModelCheckingTimer.
start();
462 std::unique_ptr<storm::modelchecker::CheckResult> result(
466 result->filter(storm::modelchecker::ExplicitQualitativeCheckResult<ValueType>(model->getInitialStates()));
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.");
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)
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.
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)
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)
void exportSparseModelAsDot(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::string const &filename, size_t maxWidth=30)
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=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.
bool isInfinity(ValueType const &a)
TargetType convertNumber(SourceType const &number)