diff --git a/src/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp b/src/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp new file mode 100644 index 000000000..137c292b5 --- /dev/null +++ b/src/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp @@ -0,0 +1,54 @@ +#include "src/modelchecker/propositional/SymbolicPropositionalModelChecker.h" + +#include "src/models/symbolic/Dtmc.h" +#include "src/models/symbolic/Mdp.h" + +#include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" + +#include "src/utility/macros.h" +#include "src/exceptions/InvalidPropertyException.h" + +namespace storm { + namespace modelchecker { + template + SymbolicPropositionalModelChecker::SymbolicPropositionalModelChecker(storm::models::symbolic::Model const& model) : model(model) { + // Intentionally left empty. + } + + template + bool SymbolicPropositionalModelChecker::canHandle(storm::logic::Formula const& formula) const { + return formula.isPropositionalFormula(); + } + + template + std::unique_ptr SymbolicPropositionalModelChecker::checkBooleanLiteralFormula(storm::logic::BooleanLiteralFormula const& stateFormula) { + if (stateFormula.isTrueFormula()) { + return std::unique_ptr(new SymbolicQualitativeCheckResult(model.getReachableStates(), model.getReachableStates())); + } else { + return std::unique_ptr(new SymbolicQualitativeCheckResult(model.getReachableStates(), model.getManager().getZero())); + } + } + + template + std::unique_ptr SymbolicPropositionalModelChecker::checkAtomicLabelFormula(storm::logic::AtomicLabelFormula const& stateFormula) { + STORM_LOG_THROW(model.hasLabel(stateFormula.getLabel()), storm::exceptions::InvalidPropertyException, "The property refers to unknown label '" << stateFormula.getLabel() << "'."); + return std::unique_ptr(new SymbolicQualitativeCheckResult(model.getReachableStates(), model.getStates(stateFormula.getLabel()))); + } + + template + storm::models::symbolic::Model const& SymbolicPropositionalModelChecker::getModel() const { + return model; + } + + template + template + ModelType const& SymbolicPropositionalModelChecker::getModelAs() const { + return dynamic_cast(model); + } + + // Explicitly instantiate the template class. + template storm::models::symbolic::Dtmc const& SymbolicPropositionalModelChecker::getModelAs() const; + template storm::models::symbolic::Mdp const& SymbolicPropositionalModelChecker::getModelAs() const; + template class SymbolicPropositionalModelChecker; + } +} \ No newline at end of file diff --git a/src/modelchecker/propositional/SymbolicPropositionalModelChecker.h b/src/modelchecker/propositional/SymbolicPropositionalModelChecker.h new file mode 100644 index 000000000..9865d74b3 --- /dev/null +++ b/src/modelchecker/propositional/SymbolicPropositionalModelChecker.h @@ -0,0 +1,44 @@ +#ifndef STORM_MODELCHECKER_SYMBOLICPROPOSITIONALMODELCHECKER_H_ +#define STORM_MODELCHECKER_SYMBOLICPROPOSITIONALMODELCHECKER_H_ + +#include "src/modelchecker/AbstractModelChecker.h" + +#include "src/models/symbolic/Model.h" + +namespace storm { + namespace modelchecker { + + template + class SymbolicPropositionalModelChecker : public AbstractModelChecker { + public: + explicit SymbolicPropositionalModelChecker(storm::models::symbolic::Model const& model); + + // The implemented methods of the AbstractModelChecker interface. + virtual bool canHandle(storm::logic::Formula const& formula) const override; + virtual std::unique_ptr checkBooleanLiteralFormula(storm::logic::BooleanLiteralFormula const& stateFormula) override; + virtual std::unique_ptr checkAtomicLabelFormula(storm::logic::AtomicLabelFormula const& stateFormula) override; + + protected: + /*! + * Retrieves the model associated with this model checker instance. + * + * @return The model associated with this model checker instance. + */ + virtual storm::models::symbolic::Model const& getModel() const; + + /*! + * Retrieves the model associated with this model checker instance as the given template parameter type. + * + * @return The model associated with this model checker instance. + */ + template + ModelType const& getModelAs() const; + + private: + // The model that is to be analyzed by the model checker. + storm::models::symbolic::Model const& model; + }; + } +} + +#endif /* STORM_MODELCHECKER_SYMBOLICPROPOSITIONALMODELCHECKER_H_ */ \ No newline at end of file diff --git a/src/modelchecker/results/CheckResult.cpp b/src/modelchecker/results/CheckResult.cpp index 5f79e0d1e..b518b0667 100644 --- a/src/modelchecker/results/CheckResult.cpp +++ b/src/modelchecker/results/CheckResult.cpp @@ -73,6 +73,14 @@ namespace storm { return dynamic_cast const&>(*this); } + QualitativeCheckResult& CheckResult::asQualitativeCheckResult() { + return dynamic_cast(*this); + } + + QualitativeCheckResult const& CheckResult::asQualitativeCheckResult() const { + return dynamic_cast(*this); + } + QuantitativeCheckResult& CheckResult::asQuantitativeCheckResult() { return dynamic_cast(*this); } diff --git a/src/modelchecker/results/ExplicitQualitativeCheckResult.cpp b/src/modelchecker/results/ExplicitQualitativeCheckResult.cpp index 5606819db..79bb34885 100644 --- a/src/modelchecker/results/ExplicitQualitativeCheckResult.cpp +++ b/src/modelchecker/results/ExplicitQualitativeCheckResult.cpp @@ -30,7 +30,7 @@ namespace storm { } void ExplicitQualitativeCheckResult::performLogicalOperation(ExplicitQualitativeCheckResult& first, QualitativeCheckResult const& second, std::function const& function) { - STORM_LOG_THROW(typeid(second) == typeid(ExplicitQualitativeCheckResult), storm::exceptions::InvalidOperationException, "Cannot perform logical 'and' on check results of incompatible type."); + STORM_LOG_THROW(second.isExplicitQualitativeCheckResult(), storm::exceptions::InvalidOperationException, "Cannot perform logical 'and' on check results of incompatible type."); STORM_LOG_THROW(first.isResultForAllStates() == second.isResultForAllStates(), storm::exceptions::InvalidOperationException, "Cannot perform logical 'and' on check results of incompatible type."); ExplicitQualitativeCheckResult const& secondCheckResult = static_cast(second); if (first.isResultForAllStates()) { @@ -104,6 +104,7 @@ namespace storm { } std::ostream& ExplicitQualitativeCheckResult::writeToStream(std::ostream& out) const { + out << "["; if (this->isResultForAllStates()) { out << boost::get(truthValues); } else { @@ -111,27 +112,18 @@ namespace storm { out << std::boolalpha; map_type const& map = boost::get(truthValues); - -#ifndef WINDOWS - typename map_type::const_iterator it = map.begin(); - typename map_type::const_iterator itPlusOne = map.begin(); - ++itPlusOne; - typename map_type::const_iterator ite = map.end(); -#else - map_type::const_iterator it = map.begin(); - map_type::const_iterator itPlusOne = map.begin(); - ++itPlusOne; - map_type::const_iterator ite = map.end(); -#endif - - for (; it != ite; ++itPlusOne, ++it) { - out << it->second; - if (itPlusOne != ite) { + bool first = true; + for (auto const& element : map) { + if (!first) { out << ", "; + } else { + first = false; } + out << element.second; } std::cout.flags(oldflags); } + out << "]"; return out; } diff --git a/src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp b/src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp index 2f4ce34fb..6c5b4520f 100644 --- a/src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp +++ b/src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp @@ -83,29 +83,25 @@ namespace storm { out << "["; if (this->isResultForAllStates()) { vector_type const& valuesAsVector = boost::get(values); - typename vector_type::const_iterator it = valuesAsVector.begin(); - typename vector_type::const_iterator itPlusOne = valuesAsVector.begin(); - ++itPlusOne; - typename vector_type::const_iterator ite = valuesAsVector.end(); - - for (; it != ite; ++itPlusOne, ++it) { - out << *it; - if (itPlusOne != ite) { + bool first = true; + for (auto const& element : valuesAsVector) { + if (!first) { out << ", "; + } else { + first = false; } + out << element; } } else { map_type const& valuesAsMap = boost::get(values); - typename map_type::const_iterator it = valuesAsMap.begin(); - typename map_type::const_iterator itPlusOne = valuesAsMap.begin(); - ++itPlusOne; - typename map_type::const_iterator ite = valuesAsMap.end(); - - for (; it != ite; ++itPlusOne, ++it) { - out << it->second; - if (itPlusOne != ite) { + bool first = true; + for (auto const& element : valuesAsMap) { + if (!first) { out << ", "; + } else { + first = false; } + out << element.second; } } out << "]"; diff --git a/src/modelchecker/results/SymbolicQualitativeCheckResult.cpp b/src/modelchecker/results/SymbolicQualitativeCheckResult.cpp index f72ca929f..290da6884 100644 --- a/src/modelchecker/results/SymbolicQualitativeCheckResult.cpp +++ b/src/modelchecker/results/SymbolicQualitativeCheckResult.cpp @@ -1,55 +1,66 @@ -#include "src/modelcheckers/result/SymbolicQualitativeCheckResult.h" +#include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" + +#include "src/storage/dd/CuddDd.h" +#include "src/exceptions/InvalidOperationException.h" namespace storm { - namespace modelcheckers { + namespace modelchecker { template - SymbolicQualitativeCheckResult(storm::dd::Dd const& values) { - + SymbolicQualitativeCheckResult::SymbolicQualitativeCheckResult(storm::dd::Dd const& allStates, storm::dd::Dd const& truthValues) : allStates(allStates), truthValues(truthValues) { + // Intentionally left empty. } template - bool isSymbolic() const { - + bool SymbolicQualitativeCheckResult::isSymbolic() const { + return true; } template - bool isResultForAllStates() const { - + bool SymbolicQualitativeCheckResult::isResultForAllStates() const { + return true; } template - bool isSymbolicQualitativeCheckResult() const { - + bool SymbolicQualitativeCheckResult::isSymbolicQualitativeCheckResult() const { + return true; } template - QualitativeCheckResult& operator&=(QualitativeCheckResult const& other) { - + QualitativeCheckResult& SymbolicQualitativeCheckResult::operator&=(QualitativeCheckResult const& other) { + STORM_LOG_THROW(other.isSymbolicQualitativeCheckResult(), storm::exceptions::InvalidOperationException, "Cannot perform logical 'and' on check results of incompatible type."); + this->truthValues &= other.asSymbolicQualitativeCheckResult().getTruthValuesVector(); } template - QualitativeCheckResult& operator|=(QualitativeCheckResult const& other) { - + QualitativeCheckResult& SymbolicQualitativeCheckResult::operator|=(QualitativeCheckResult const& other) { + STORM_LOG_THROW(other.isSymbolicQualitativeCheckResult(), storm::exceptions::InvalidOperationException, "Cannot perform logical 'and' on check results of incompatible type."); + this->truthValues |= other.asSymbolicQualitativeCheckResult().getTruthValuesVector(); } template - void complement() { - + void SymbolicQualitativeCheckResult::complement() { + this->truthValues = !this->truthValues && allStates; } template - storm::dd::Dd const& getTruthValuesVector() const { - + storm::dd::Dd const& SymbolicQualitativeCheckResult::getTruthValuesVector() const { + return truthValues; } template - std::ostream& writeToStream(std::ostream& out) const { - + std::ostream& SymbolicQualitativeCheckResult::writeToStream(std::ostream& out) const { + if (this->truthValues.isZero()) { + out << "[false]" << std::endl; + } else { + out << "[true]" << std::endl; + } + return out; } template - void filter(QualitativeCheckResult const& filter) { - + void SymbolicQualitativeCheckResult::filter(QualitativeCheckResult const& filter) { + STORM_LOG_THROW(filter.isSymbolicQualitativeCheckResult(), storm::exceptions::InvalidOperationException, "Cannot filter symbolic check result with non-symbolic filter."); + this->truthValues &= filter.asSymbolicQualitativeCheckResult().getTruthValuesVector(); } } } \ No newline at end of file diff --git a/src/modelchecker/results/SymbolicQualitativeCheckResult.h b/src/modelchecker/results/SymbolicQualitativeCheckResult.h index b13c39029..83c49ab98 100644 --- a/src/modelchecker/results/SymbolicQualitativeCheckResult.h +++ b/src/modelchecker/results/SymbolicQualitativeCheckResult.h @@ -2,6 +2,7 @@ #define STORM_MODELCHECKER_SYMBOLICQUALITATIVECHECKRESULT_H_ #include "src/storage/dd/DdType.h" +#include "src/storage/dd/Dd.h" #include "src/modelchecker/results/QualitativeCheckResult.h" #include "src/utility/OsDetection.h" @@ -11,7 +12,7 @@ namespace storm { class SymbolicQualitativeCheckResult : public QualitativeCheckResult { public: SymbolicQualitativeCheckResult() = default; - SymbolicQualitativeCheckResult(storm::dd::Dd const& values); + SymbolicQualitativeCheckResult(storm::dd::Dd const& allStates, storm::dd::Dd const& truthValues); SymbolicQualitativeCheckResult(SymbolicQualitativeCheckResult const& other) = default; SymbolicQualitativeCheckResult& operator=(SymbolicQualitativeCheckResult const& other) = default; @@ -36,6 +37,9 @@ namespace storm { virtual void filter(QualitativeCheckResult const& filter) override; private: + // The set of all states. + storm::dd::Dd allStates; + // The values of the qualitative check result. storm::dd::Dd truthValues; }; diff --git a/src/modelchecker/results/SymbolicQuantitativeCheckResult.cpp b/src/modelchecker/results/SymbolicQuantitativeCheckResult.cpp index e69de29bb..b78df481d 100644 --- a/src/modelchecker/results/SymbolicQuantitativeCheckResult.cpp +++ b/src/modelchecker/results/SymbolicQuantitativeCheckResult.cpp @@ -0,0 +1,70 @@ +#include "src/modelchecker/results/SymbolicQuantitativeCheckResult.h" +#include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" + +#include "src/storage/dd/CuddDd.h" +#include "src/exceptions/InvalidOperationException.h" + +namespace storm { + namespace modelchecker { + template + SymbolicQuantitativeCheckResult::SymbolicQuantitativeCheckResult(storm::dd::Dd const& allStates, storm::dd::Dd const& values) : allStates(allStates), values(values) { + // Intentionally left empty. + } + + template + std::unique_ptr SymbolicQuantitativeCheckResult::compareAgainstBound(storm::logic::ComparisonType comparisonType, double bound) const { + std::unique_ptr> result; + if (comparisonType == storm::logic::ComparisonType::Less || comparisonType == storm::logic::ComparisonType::GreaterEqual) { + result = std::unique_ptr>(new SymbolicQualitativeCheckResult(allStates, values.greaterOrEqual(bound))); + } else { + result = std::unique_ptr>(new SymbolicQualitativeCheckResult(allStates, values.greater(bound))); + } + if (comparisonType == storm::logic::ComparisonType::Less || comparisonType == storm::logic::ComparisonType::LessEqual) { + result->complement(); + } + return result; + } + + template + bool SymbolicQuantitativeCheckResult::isSymbolic() const { + return true; + } + + template + bool SymbolicQuantitativeCheckResult::isResultForAllStates() const { + return true; + } + + template + bool SymbolicQuantitativeCheckResult::isSymbolicQuantitativeCheckResult() const { + return true; + } + + template + storm::dd::Dd const& SymbolicQuantitativeCheckResult::getValueVector() const { + return values; + } + + template + std::ostream& SymbolicQuantitativeCheckResult::writeToStream(std::ostream& out) const { + out << "["; + bool first = true; + for (auto valuationValuePair : this->values) { + if (!first) { + out << ", "; + } else { + first = false; + } + out << valuationValuePair.second; + } + out << "]"; + return out; + } + + template + void SymbolicQuantitativeCheckResult::filter(QualitativeCheckResult const& filter) { + STORM_LOG_THROW(filter.isSymbolicQualitativeCheckResult(), storm::exceptions::InvalidOperationException, "Cannot filter symbolic check result with non-symbolic filter."); + this->truthValues *= filter.asSymbolicQualitativeCheckResult().getTruthValuesVector().toMtbdd(); + } + } +} \ No newline at end of file diff --git a/src/modelchecker/results/SymbolicQuantitativeCheckResult.h b/src/modelchecker/results/SymbolicQuantitativeCheckResult.h index bb45fe090..0b1e331f4 100644 --- a/src/modelchecker/results/SymbolicQuantitativeCheckResult.h +++ b/src/modelchecker/results/SymbolicQuantitativeCheckResult.h @@ -2,6 +2,7 @@ #define STORM_MODELCHECKER_SYMBOLICQUANTITATIVECHECKRESULT_H_ #include "src/storage/dd/DdType.h" +#include "src/storage/dd/Dd.h" #include "src/modelchecker/results/QuantitativeCheckResult.h" #include "src/utility/OsDetection.h" @@ -10,8 +11,8 @@ namespace storm { template class SymbolicQuantitativeCheckResult : public QuantitativeCheckResult { public: - SymbolicQuantitativeCheckResult(); - SymbolicQuantitativeCheckResult(storm::dd::Dd const& values); + SymbolicQuantitativeCheckResult() = default; + SymbolicQuantitativeCheckResult(storm::dd::Dd const& allStates, storm::dd::Dd const& values); SymbolicQuantitativeCheckResult(SymbolicQuantitativeCheckResult const& other) = default; SymbolicQuantitativeCheckResult& operator=(SymbolicQuantitativeCheckResult const& other) = default; @@ -34,6 +35,9 @@ namespace storm { virtual void filter(QualitativeCheckResult const& filter) override; private: + // The set of all states. + storm::dd::Dd allStates; + // The values of the quantitative check result. storm::dd::Dd values; }; diff --git a/src/utility/cli.h b/src/utility/cli.h index 21622ac24..b24e57934 100644 --- a/src/utility/cli.h +++ b/src/utility/cli.h @@ -440,8 +440,8 @@ namespace storm { if (result) { std::cout << " done." << std::endl; std::cout << "Result (initial states): "; - result->writeToStream(std::cout, sparseModel->getInitialStates()); - std::cout << std::endl << std::endl; + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(sparseModel->getInitialStates())); + std::cout << *result << std::endl; } else { std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl; } @@ -470,8 +470,8 @@ namespace storm { if (result) { std::cout << " done." << std::endl; std::cout << "Result (initial states): "; - result->writeToStream(std::cout, model->getInitialStates()); - std::cout << std::endl << std::endl; + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(dtmc->getInitialStates())); + std::cout << *result << std::endl; } else { std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl; }