#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 HybridQuantitativeCheckResult::HybridQuantitativeCheckResult(storm::dd::Bdd const& reachableStates, storm::dd::Bdd const& symbolicStates, storm::dd::Add const& symbolicValues, storm::dd::Bdd const& explicitStates, storm::dd::Odd const& odd, std::vector const& explicitValues) : reachableStates(reachableStates), symbolicStates(symbolicStates), symbolicValues(symbolicValues), explicitStates(explicitStates), odd(odd), explicitValues(explicitValues) { // Intentionally left empty. } template std::unique_ptr HybridQuantitativeCheckResult::clone() const { return std::make_unique>(this->reachableStates, this->symbolicStates, this->symbolicValues, this->explicitStates, this->odd, this->explicitValues); } template std::unique_ptr HybridQuantitativeCheckResult::compareAgainstBound(storm::logic::ComparisonType comparisonType, ValueType const& bound) const { storm::dd::Bdd 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::template fromVector(this->reachableStates.getDdManager(), this->explicitValues, this->odd, this->symbolicValues.getContainedMetaVariables(), comparisonType, storm::utility::convertNumber(bound)); return std::unique_ptr>(new SymbolicQualitativeCheckResult(reachableStates, symbolicResult)); } template std::unique_ptr HybridQuantitativeCheckResult::toExplicitQuantitativeCheckResult() const { storm::dd::Bdd allStates = symbolicStates || explicitStates; storm::dd::Odd allStatesOdd = allStates.createOdd(); std::vector fullExplicitValues = symbolicValues.toVector(allStatesOdd); this->odd.expandExplicitVector(allStatesOdd, this->explicitValues, fullExplicitValues); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(fullExplicitValues))); } template bool HybridQuantitativeCheckResult::isHybrid() const { return true; } template bool HybridQuantitativeCheckResult::isResultForAllStates() const { return (symbolicStates || explicitStates) == reachableStates; } template bool HybridQuantitativeCheckResult::isHybridQuantitativeCheckResult() const { return true; } template storm::dd::Bdd const& HybridQuantitativeCheckResult::getSymbolicStates() const { return symbolicStates; } template storm::dd::Add const& HybridQuantitativeCheckResult::getSymbolicValueVector() const { return symbolicValues; } template storm::dd::Bdd const& HybridQuantitativeCheckResult::getExplicitStates() const { return explicitStates; } template storm::dd::Odd const& HybridQuantitativeCheckResult::getOdd() const { return odd; } template std::vector const& HybridQuantitativeCheckResult::getExplicitValueVector() const { return explicitValues; } template void print(std::ostream& out, ValueType const& value) { if (value == storm::utility::infinity()) { out << "inf"; } else { out << value; if (std::is_same::value) { out << " (approx. " << storm::utility::convertNumber(value) << ")"; } } } template void printRange(std::ostream& out, ValueType const& min, ValueType const& max) { out << "["; if (min == storm::utility::infinity()) { out << "inf"; } else { out << min; } out << ", "; if (max == storm::utility::infinity()) { out << "inf"; } else { out << max; } out << "]"; if (std::is_same::value) { out << " (approx. ["; if (min == storm::utility::infinity()) { out << "inf"; } else { out << storm::utility::convertNumber(min); } out << ", "; if (max == storm::utility::infinity()) { out << "inf"; } else { out << storm::utility::convertNumber(max); } out << "])"; } out << " (range)"; } template std::ostream& HybridQuantitativeCheckResult::writeToStream(std::ostream& out) const { uint64_t totalNumberOfStates = this->symbolicStates.getNonZeroCount() + this->explicitStates.getNonZeroCount(); bool minMaxSupported = std::is_same::value || std::is_same::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 void HybridQuantitativeCheckResult::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().getTruthValuesVector(); this->symbolicValues *= symbolicStates.template toAdd(); // 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().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 ValueType HybridQuantitativeCheckResult::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 tmp = symbolicStates.ite(this->symbolicValues, reachableStates.getDdManager().getConstant(storm::utility::infinity())); ValueType min = tmp.getMin(); if (!explicitStates.isZero()) { for (auto const& element : explicitValues) { min = std::min(min, element); } } return min; } template ValueType HybridQuantitativeCheckResult::getMax() const { ValueType max = this->symbolicValues.getMax(); if (!explicitStates.isZero()) { for (auto const& element : explicitValues) { max = std::max(max, element); } } return max; } template ValueType HybridQuantitativeCheckResult::sum() const { ValueType sum = symbolicValues.sumAbstract(symbolicValues.getContainedMetaVariables()).getValue(); for (auto const& value : explicitValues) { sum += value; } return sum; } template ValueType HybridQuantitativeCheckResult::average() const { return this->sum() / storm::utility::convertNumber((symbolicStates || explicitStates).getNonZeroCount()); } template void HybridQuantitativeCheckResult::oneMinus() { storm::dd::Add one = symbolicValues.getDdManager().template getAddOne(); storm::dd::Add zero = symbolicValues.getDdManager().template getAddZero(); symbolicValues = symbolicStates.ite(one - symbolicValues, zero); for (auto& element : explicitValues) { element = storm::utility::one() - element; } } // Explicitly instantiate the class. template class HybridQuantitativeCheckResult; template class HybridQuantitativeCheckResult; template class HybridQuantitativeCheckResult; template class HybridQuantitativeCheckResult; } }