24template<
typename ValueType>
27 std::vector<std::shared_ptr<const storm::logic::Formula>>
const& properties,
34 STORM_LOG_THROW(wellFormedResult.first, storm::exceptions::InvalidModelException,
35 "DFT is not well-formed for analysis: " << wellFormedResult.second <<
".");
49 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = buildModelViaComposition(env,
dft, properties, relevantEvents);
51 std::vector<ExtendedValueType> resultsValue =
checkModel(env, model, properties);
52 for (
auto& result : resultsValue) {
53 results.push_back(std::move(result));
56 results = checkHelper(env,
dft, properties, relevantEvents);
62template<
typename ValueType>
65 property_vector
const& properties,
68 std::vector<storm::dft::storage::DFT<ValueType>> dfts;
69 bool invResults =
false;
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;
119 storm::exceptions::NotSupportedException,
"Combining modularisation with the partial state space generation is not supported.");
120 for (
auto const& ft : dfts) {
121 dft_results ftResults = checkHelper(env, ft, {
property}, relevantEvents);
127 STORM_LOG_TRACE(
"Combining all results... K=" << nrK <<
"; M=" << nrM <<
"; invResults=" << (invResults ?
"On" :
"Off"));
129 int limK = invResults ? -1 : nrM + 1;
130 int chK = invResults ? -1 : 1;
131 for (
int cK = nrK; cK != limK; cK += chK) {
137 for (
size_t i = 0;
i < res.size(); ++
i) {
138 if (permutation & (1ul << i)) {
139 permResult *= res[
i];
146 result += permResult;
147 }
while (permutation < (1ul << nrM) && permutation != 0);
152 results.push_back(result);
158 return checkDFT(env, dft, properties, relevantEvents);
163template<
typename ValueType>
164auto getBisimOptions() {
165 storm::bisimulation::Options bisimOptions;
167 if constexpr (std::is_same_v<ValueType, double>) {
174template<
typename ValueType>
175std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> DFTModelChecker<ValueType>::buildModelViaComposition(
176 storm::dft::DftEnvironment
const& env, storm::dft::storage::DFT<ValueType>
const& dft, property_vector
const& properties,
177 storm::dft::utility::RelevantEvents
const& relevantEvents) {
180 std::vector<storm::dft::storage::DFT<ValueType>> dfts;
189 STORM_LOG_TRACE(
"Modularisation into " << dfts.size() <<
" submodules.");
195 STORM_LOG_TRACE(
"Modularisation into " << dfts.size() <<
" submodules.");
207 if (dfts.size() > 1) {
209 bool firstTime =
true;
210 std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> composedModel;
211 for (
auto const& ft : dfts) {
213 explorationTimer.start();
217 storm::dft::storage::DftSymmetries symmetries;
225 STORM_LOG_DEBUG(
"Building Model from DFT with top level element " << *ft.getElement(ft.getTopLevelIndex()) <<
" ...");
226 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(env, ft, symmetries);
227 builder.buildModel(0, 0.0);
228 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
229 explorationTimer.stop();
232 "Parallel composition only applicable for CTMCs.");
233 std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> ctmc = model->template as<storm::models::sparse::Ctmc<ValueType>>();
236 bisimulationTimer.start();
238 ->template as<storm::models::sparse::Ctmc<ValueType>>();
239 bisimulationTimer.stop();
242 composedModel = ctmc;
249 bisimulationTimer.start();
251 ->template as<storm::models::sparse::Ctmc<ValueType>>();
252 bisimulationTimer.stop();
254 STORM_LOG_DEBUG(
"No. states (Composed): " << composedModel->getNumberOfStates());
255 STORM_LOG_DEBUG(
"No. transitions (Composed): " << composedModel->getNumberOfTransitions());
256 if (composedModel->getNumberOfStates() <= 15) {
257 STORM_LOG_TRACE(
"Transition matrix: \n" << composedModel->getTransitionMatrix());
263 composedModel->printModelInformationToStream(std::cout);
265 return composedModel;
268 explorationTimer.start();
273 storm::dft::storage::DftSymmetries symmetries;
282 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(env, dft, symmetries);
283 builder.buildModel(0, 0.0);
284 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
286 model->printModelInformationToStream(std::cout);
288 explorationTimer.stop();
290 "Parallel composition only applicable for CTMCs.");
291 return model->template as<storm::models::sparse::Ctmc<ValueType>>();
295template<
typename ValueType>
297 storm::dft::storage::DFT<ValueType>
const& dft,
298 property_vector
const& properties,
299 storm::dft::utility::RelevantEvents
const& relevantEvents) {
300 explorationTimer.start();
307 storm::dft::storage::DftSymmetries symmetries;
314 if (approximationError > 0.0) {
322 storm::utility::ConstantsComparator<ValueType> comparator(precision);
326 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
327 std::vector<ExtendedValueType> newResult;
328 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(env, dft, symmetries);
331 std::shared_ptr<const storm::logic::Formula>
property = properties[0];
332 if (properties.size() > 1) {
333 STORM_LOG_WARN(
"Computing approximation only for first property: " << *property);
336 bool probabilityFormula =
property->isProbabilityOperatorFormula();
337 STORM_LOG_ASSERT((property->isTimeOperatorFormula() && !probabilityFormula) || (!property->isTimeOperatorFormula() && probabilityFormula),
338 "Probability formula not initialized correctly.");
339 size_t iteration = 0;
343 explorationTimer.start();
348 explorationTimer.stop();
349 buildingTimer.start();
355 model = builder.getModelApproximation(
true, !probabilityFormula);
358 std::cout <<
"Model in iteration " << (iteration + 1) <<
":\n";
359 model->printModelInformationToStream(std::cout);
361 buildingTimer.stop();
363 if (exportCallback) {
364 exportCallback(model,
false);
368 newResult =
checkModel(env, model, {
property});
371 "Approximation does not work if result might be infinity.");
373 STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(lowerBound, approxResult.first),
374 "New under-approximation " << lowerBound <<
" is smaller than old result " << approxResult.first);
375 approxResult.first = std::move(lowerBound);
379 buildingTimer.start();
380 model = builder.getModelApproximation(
false, !probabilityFormula);
381 buildingTimer.stop();
383 newResult =
checkModel(env, model, {
property});
386 "Approximation does not work if result might be infinity.");
388 STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(approxResult.second, upperBound),
389 "New over-approximation " << upperBound <<
" is greater than old result " << approxResult.second);
390 approxResult.second = std::move(upperBound);
392 STORM_LOG_ASSERT(comparator.isLess(approxResult.first, approxResult.second) || comparator.isEqual(approxResult.first, approxResult.second),
393 "Under-approximation " << approxResult.first <<
" is greater than over-approximation " << approxResult.second);
396 out <<
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")\n";
400 STORM_LOG_DEBUG(
"Result after iteration " << (iteration + 1) <<
": (" << approxResult.first <<
", " << approxResult.second <<
")");
404 }
while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula));
408 model->printModelInformationToStream(std::cout);
411 if (exportCallback) {
412 exportCallback(model,
true);
415 results.push_back(approximation_result(std::move(approxResult.first), std::move(approxResult.second)));
420 storm::dft::builder::ExplicitDFTModelBuilder<ValueType> builder(env, dft, symmetries);
421 builder.buildModel(0, 0.0);
422 std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
424 auto ma = std::static_pointer_cast<storm::models::sparse::MarkovAutomaton<ValueType>>(model);
427 explorationTimer.stop();
431 model->printModelInformationToStream(std::cout);
435 if (exportCallback) {
436 exportCallback(model,
true);
440 std::vector<ExtendedValueType> resultsValue =
checkModel(env, model, properties);
442 for (
auto& result : resultsValue) {
443 results.push_back(std::move(result));
449template<
typename ValueType>
450std::vector<typename DFTModelChecker<ValueType>::ExtendedValueType> DFTModelChecker<ValueType>::checkModel(
451 storm::dft::DftEnvironment
const& env, std::shared_ptr<storm::models::sparse::Model<ValueType>>& model, property_vector
const& properties) {
454 bisimulationTimer.start();
457 STORM_LOG_DEBUG(
"No. states (Bisimulation): " << model->getNumberOfStates());
458 STORM_LOG_DEBUG(
"No. transitions (Bisimulation): " << model->getNumberOfTransitions());
459 bisimulationTimer.stop();
464 modelCheckingTimer.start();
465 std::vector<ExtendedValueType> results;
468 storm::utility::Stopwatch singleModelCheckingTimer;
469 for (
auto property : properties) {
470 singleModelCheckingTimer.
reset();
471 singleModelCheckingTimer.
start();
473 std::unique_ptr<storm::modelchecker::CheckResult> result(
477 result->filter(storm::modelchecker::ExplicitQualitativeCheckResult<ValueType>(model->getInitialStates()));
478 results.push_back(result->asExplicitQuantitativeCheckResult<
ValueType>().getValueVector().front());
480 STORM_LOG_WARN(
"The property '" << *property <<
"' could not be checked with the current settings.");
484 singleModelCheckingTimer.
stop();
487 modelCheckingTimer.stop();
492template<
typename ValueType>
493bool DFTModelChecker<ValueType>::isApproximationSufficient(
ValueType,
ValueType,
double,
bool) {
494 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Approximation works only for double.");
498bool DFTModelChecker<double>::isApproximationSufficient(
double lowerBound,
double upperBound,
double approximationError,
bool relative) {
499 STORM_LOG_THROW(!std::isnan(lowerBound) && !std::isnan(upperBound), storm::exceptions::NotSupportedException,
500 "Approximation does not work if result is NaN.");
502 return upperBound - lowerBound <= approximationError;
504 return upperBound - lowerBound <= approximationError * (lowerBound + upperBound) / 2;
508template<
typename ValueType>
511 os <<
"Exploration:\t" << explorationTimer <<
'\n';
512 os <<
"Building:\t" << buildingTimer <<
'\n';
513 os <<
"Bisimulation:\t" << bisimulationTimer <<
'\n';
514 os <<
"Modelchecking:\t" << modelCheckingTimer <<
'\n';
515 os <<
"Total:\t\t" << totalTimer <<
'\n';
518template<
typename ValueType>
522 for (
auto result : results) {
528 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)
SolverEnvironment & solver()
storm::solver::EquationSolverType const & getLinearEquationSolverType() const
std::pair< boost::optional< storm::RationalNumber >, boost::optional< bool > > getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const &solverType) const
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)
bool isApproximationErrorSet() const
bool isUseModularisation() const
double getApproximationError() const
storm::dft::builder::ApproximationHeuristic getApproximationHeuristic() const
Environment for storm-dft.
AnalysisEnvironment & analysis()
ModelBuilderEnvironment & modelBuilder()
TransformationEnvironment & transformation()
storm::Environment & core()
bool isAllowDCForRelevantEvents() const
bool isUseSymmetryReduction() const
dft_results check(storm::dft::DftEnvironment const &env, storm::dft::storage::DFT< ValueType > const &origDft, property_vector const &properties, storm::dft::utility::RelevantEvents const &relevantEvents={})
Main method for checking DFTs.
std::vector< boost::variant< ExtendedValueType, approximation_result > > dft_results
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_STATISTICS_LAZY(...)
#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)
std::shared_ptr< storm::models::sparse::Model< ValueType > > performBisimulationMinimization(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas={}, storm::bisimulation::Options const &options={})
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, bool preferEliminationChecker=false)
std::pair< bool, std::string > isWellFormed(storm::dft::storage::DFT< ValueType > const &dft, bool validForMarkovianAnalysis)
Check whether the DFT is well-formed.
SFTBDDChecker::ValueType ValueType
bool isFinite(ExtendedNumber< ValueType > const &value)
ValueType narrow(ExtendedValueType< ValueType > const &value)
Narrows an extended value back into the plain value type, for the interfaces that cannot hold an infi...
TargetType convertNumber(SourceType const &number)
BisimulationType bisimulationType
std::optional< storm::RationalNumber > tolerance