You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
14 KiB
277 lines
14 KiB
#include "storm/modelchecker/results/HybridQuantitativeCheckResult.h"
|
|
#include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h"
|
|
#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
|
|
#include "storm/storage/dd/DdManager.h"
|
|
#include "storm/storage/dd/cudd/CuddAddIterator.h"
|
|
|
|
#include "storm/exceptions/InvalidOperationException.h"
|
|
|
|
#include "storm/exceptions/NotImplementedException.h"
|
|
#include "storm/utility/macros.h"
|
|
#include "storm/utility/constants.h"
|
|
|
|
|
|
namespace storm {
|
|
namespace modelchecker {
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
HybridQuantitativeCheckResult<Type, ValueType>::HybridQuantitativeCheckResult(storm::dd::Bdd<Type> const& reachableStates, storm::dd::Bdd<Type> const& symbolicStates, storm::dd::Add<Type, ValueType> const& symbolicValues, storm::dd::Bdd<Type> const& explicitStates, storm::dd::Odd const& odd, std::vector<ValueType> const& explicitValues) : reachableStates(reachableStates), symbolicStates(symbolicStates), symbolicValues(symbolicValues), explicitStates(explicitStates), odd(odd), explicitValues(explicitValues) {
|
|
|
|
// Intentionally left empty.
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
std::unique_ptr<CheckResult> HybridQuantitativeCheckResult<Type, ValueType>::clone() const {
|
|
return std::make_unique<HybridQuantitativeCheckResult<Type, ValueType>>(this->reachableStates, this->symbolicStates, this->symbolicValues, this->explicitStates, this->odd, this->explicitValues);
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
std::unique_ptr<CheckResult> HybridQuantitativeCheckResult<Type, ValueType>::compareAgainstBound(storm::logic::ComparisonType comparisonType, ValueType const& bound) const {
|
|
storm::dd::Bdd<Type> symbolicResult = symbolicStates;
|
|
|
|
// First compute the symbolic part of the result.
|
|
if (comparisonType == storm::logic::ComparisonType::Less) {
|
|
symbolicResult &= symbolicValues.less(bound);
|
|
} else if (comparisonType == storm::logic::ComparisonType::LessEqual) {
|
|
symbolicResult &= symbolicValues.lessOrEqual(bound);
|
|
} else if (comparisonType == storm::logic::ComparisonType::Greater) {
|
|
symbolicResult &= symbolicValues.greater(bound);
|
|
} else if (comparisonType == storm::logic::ComparisonType::GreaterEqual) {
|
|
symbolicResult &= symbolicValues.greaterOrEqual(bound);
|
|
}
|
|
|
|
// Then translate the explicit part to a symbolic format and simultaneously to a qualitative result.
|
|
symbolicResult |= storm::dd::Bdd<Type>::template fromVector<ValueType>(this->reachableStates.getDdManager(), this->explicitValues, this->odd, this->symbolicValues.getContainedMetaVariables(), comparisonType, storm::utility::convertNumber<ValueType>(bound));
|
|
|
|
return std::unique_ptr<SymbolicQualitativeCheckResult<Type>>(new SymbolicQualitativeCheckResult<Type>(reachableStates, symbolicResult));
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
std::unique_ptr<CheckResult> HybridQuantitativeCheckResult<Type, ValueType>::toExplicitQuantitativeCheckResult() const {
|
|
storm::dd::Bdd<Type> allStates = symbolicStates || explicitStates;
|
|
storm::dd::Odd allStatesOdd = allStates.createOdd();
|
|
|
|
std::vector<ValueType> fullExplicitValues = symbolicValues.toVector(allStatesOdd);
|
|
this->odd.expandExplicitVector(allStatesOdd, this->explicitValues, fullExplicitValues);
|
|
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(fullExplicitValues)));
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
bool HybridQuantitativeCheckResult<Type, ValueType>::isHybrid() const {
|
|
return true;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
bool HybridQuantitativeCheckResult<Type, ValueType>::isResultForAllStates() const {
|
|
return (symbolicStates || explicitStates) == reachableStates;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
bool HybridQuantitativeCheckResult<Type, ValueType>::isHybridQuantitativeCheckResult() const {
|
|
return true;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
storm::dd::Bdd<Type> const& HybridQuantitativeCheckResult<Type, ValueType>::getSymbolicStates() const {
|
|
return symbolicStates;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
storm::dd::Add<Type, ValueType> const& HybridQuantitativeCheckResult<Type, ValueType>::getSymbolicValueVector() const {
|
|
return symbolicValues;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
storm::dd::Bdd<Type> const& HybridQuantitativeCheckResult<Type, ValueType>::getExplicitStates() const {
|
|
return explicitStates;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
storm::dd::Odd const& HybridQuantitativeCheckResult<Type, ValueType>::getOdd() const {
|
|
return odd;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
std::vector<ValueType> const& HybridQuantitativeCheckResult<Type, ValueType>::getExplicitValueVector() const {
|
|
return explicitValues;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
void print(std::ostream& out, ValueType const& value) {
|
|
if (value == storm::utility::infinity<ValueType>()) {
|
|
out << "inf";
|
|
} else {
|
|
out << value;
|
|
if (std::is_same<ValueType, storm::RationalNumber>::value) {
|
|
out << " (approx. " << storm::utility::convertNumber<double>(value) << ")";
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename ValueType>
|
|
void printRange(std::ostream& out, ValueType const& min, ValueType const& max) {
|
|
out << "[";
|
|
if (min == storm::utility::infinity<ValueType>()) {
|
|
out << "inf";
|
|
} else {
|
|
out << min;
|
|
}
|
|
out << ", ";
|
|
if (max == storm::utility::infinity<ValueType>()) {
|
|
out << "inf";
|
|
} else {
|
|
out << max;
|
|
}
|
|
out << "]";
|
|
if (std::is_same<ValueType, storm::RationalNumber>::value) {
|
|
out << " (approx. [";
|
|
if (min == storm::utility::infinity<ValueType>()) {
|
|
out << "inf";
|
|
} else {
|
|
out << storm::utility::convertNumber<double>(min);
|
|
}
|
|
out << ", ";
|
|
if (max == storm::utility::infinity<ValueType>()) {
|
|
out << "inf";
|
|
} else {
|
|
out << storm::utility::convertNumber<double>(max);
|
|
}
|
|
out << "])";
|
|
}
|
|
out << " (range)";
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
std::ostream& HybridQuantitativeCheckResult<Type, ValueType>::writeToStream(std::ostream& out) const {
|
|
uint64_t totalNumberOfStates = this->symbolicStates.getNonZeroCount() + this->explicitStates.getNonZeroCount();
|
|
bool minMaxSupported = std::is_same<ValueType, double>::value || std::is_same<ValueType, storm::RationalNumber>::value;
|
|
bool printAsRange = false;
|
|
|
|
if (totalNumberOfStates == 1) {
|
|
if (this->symbolicStates.isZero()) {
|
|
print(out, *this->explicitValues.begin());
|
|
} else {
|
|
print(out, this->symbolicValues.sumAbstract(this->symbolicValues.getContainedMetaVariables()).getValue());
|
|
}
|
|
} else if (totalNumberOfStates >= 10 && minMaxSupported) {
|
|
printAsRange = true;
|
|
} else {
|
|
out << "{";
|
|
bool first = true;
|
|
if (!this->symbolicStates.isZero()) {
|
|
if (this->symbolicValues.isZero()) {
|
|
out << "0";
|
|
first = false;
|
|
} else {
|
|
for (auto valuationValuePair : this->symbolicValues) {
|
|
if (!first) {
|
|
out << ", ";
|
|
} else {
|
|
first = false;
|
|
}
|
|
print(out, valuationValuePair.second);
|
|
}
|
|
if (symbolicStates.getNonZeroCount() != this->symbolicValues.getNonZeroCount()) {
|
|
out << ", 0";
|
|
}
|
|
}
|
|
}
|
|
if (!this->explicitStates.isZero()) {
|
|
for (auto const& element : this->explicitValues) {
|
|
if (!first) {
|
|
out << ", ";
|
|
} else {
|
|
first = false;
|
|
}
|
|
print(out, element);
|
|
}
|
|
}
|
|
out << "}";
|
|
}
|
|
|
|
if (printAsRange) {
|
|
ValueType min = this->getMin();
|
|
ValueType max = this->getMax();
|
|
printRange(out, min, max);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
void HybridQuantitativeCheckResult<Type, ValueType>::filter(QualitativeCheckResult const& filter) {
|
|
STORM_LOG_THROW(filter.isSymbolicQualitativeCheckResult(), storm::exceptions::InvalidOperationException, "Cannot filter hybrid check result with non-symbolic filter.");
|
|
|
|
// First, we filter the symbolic values.
|
|
this->symbolicStates = this->symbolicStates && filter.asSymbolicQualitativeCheckResult<Type>().getTruthValuesVector();
|
|
this->symbolicValues *= symbolicStates.template toAdd<ValueType>();
|
|
|
|
// Next, we filter the explicit values.
|
|
|
|
// Start by computing the new set of states that is stored explictly and the corresponding ODD.
|
|
this->explicitStates = this->explicitStates && filter.asSymbolicQualitativeCheckResult<Type>().getTruthValuesVector();
|
|
storm::dd::Odd newOdd = explicitStates.createOdd();
|
|
|
|
// Then compute the new vector of explicit values and set the new data fields.
|
|
this->explicitValues = explicitStates.filterExplicitVector(this->odd, explicitValues);
|
|
|
|
this->odd = newOdd;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
ValueType HybridQuantitativeCheckResult<Type, ValueType>::getMin() const {
|
|
// In order to not get false zeros, we need to set the values of all states whose values is not stored
|
|
// symbolically to infinity.
|
|
storm::dd::Add<Type, ValueType> tmp = symbolicStates.ite(this->symbolicValues, reachableStates.getDdManager().getConstant(storm::utility::infinity<ValueType>()));
|
|
ValueType min = tmp.getMin();
|
|
if (!explicitStates.isZero()) {
|
|
for (auto const& element : explicitValues) {
|
|
min = std::min(min, element);
|
|
}
|
|
}
|
|
return min;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
ValueType HybridQuantitativeCheckResult<Type, ValueType>::getMax() const {
|
|
ValueType max = this->symbolicValues.getMax();
|
|
if (!explicitStates.isZero()) {
|
|
for (auto const& element : explicitValues) {
|
|
max = std::max(max, element);
|
|
}
|
|
}
|
|
return max;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
ValueType HybridQuantitativeCheckResult<Type, ValueType>::sum() const {
|
|
ValueType sum = symbolicValues.sumAbstract(symbolicValues.getContainedMetaVariables()).getValue();
|
|
for (auto const& value : explicitValues) {
|
|
sum += value;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
ValueType HybridQuantitativeCheckResult<Type, ValueType>::average() const {
|
|
return this->sum() / storm::utility::convertNumber<ValueType>((symbolicStates || explicitStates).getNonZeroCount());
|
|
}
|
|
|
|
template<storm::dd::DdType Type, typename ValueType>
|
|
void HybridQuantitativeCheckResult<Type, ValueType>::oneMinus() {
|
|
storm::dd::Add<Type, ValueType> one = symbolicValues.getDdManager().template getAddOne<ValueType>();
|
|
storm::dd::Add<Type, ValueType> zero = symbolicValues.getDdManager().template getAddZero<ValueType>();
|
|
symbolicValues = symbolicStates.ite(one - symbolicValues, zero);
|
|
|
|
for (auto& element : explicitValues) {
|
|
element = storm::utility::one<ValueType>() - element;
|
|
}
|
|
}
|
|
|
|
|
|
// Explicitly instantiate the class.
|
|
template class HybridQuantitativeCheckResult<storm::dd::DdType::CUDD>;
|
|
template class HybridQuantitativeCheckResult<storm::dd::DdType::Sylvan>;
|
|
|
|
template class HybridQuantitativeCheckResult<storm::dd::DdType::Sylvan, storm::RationalNumber>;
|
|
template class HybridQuantitativeCheckResult<storm::dd::DdType::Sylvan, storm::RationalFunction>;
|
|
}
|
|
}
|