#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidOperationException.h" namespace storm { namespace modelchecker { ExplicitQualitativeCheckResult::ExplicitQualitativeCheckResult() : truthValues(map_type()) { // Intentionally left empty. } ExplicitQualitativeCheckResult::ExplicitQualitativeCheckResult(map_type const& map) : truthValues(map) { // Intentionally left empty. } ExplicitQualitativeCheckResult::ExplicitQualitativeCheckResult(map_type&& map) : truthValues(map) { // Intentionally left empty. } ExplicitQualitativeCheckResult::ExplicitQualitativeCheckResult(storm::storage::sparse::state_type state, bool value) : truthValues(map_type()) { boost::get(truthValues)[state] = value; } ExplicitQualitativeCheckResult::ExplicitQualitativeCheckResult(storm::storage::BitVector const& truthValues) : truthValues(truthValues) { // Intentionally left empty. } ExplicitQualitativeCheckResult::ExplicitQualitativeCheckResult(storm::storage::BitVector&& truthValues) : truthValues(std::move(truthValues)) { // Intentionally left empty. } ExplicitQualitativeCheckResult::ExplicitQualitativeCheckResult(boost::variant const& truthValues) : truthValues(truthValues) { // Intentionally left empty. } ExplicitQualitativeCheckResult::ExplicitQualitativeCheckResult(boost::variant&& truthValues) : truthValues(std::move(truthValues)) { // Intentionally left empty. } std::unique_ptr ExplicitQualitativeCheckResult::clone() const { return std::make_unique(this->truthValues); } void ExplicitQualitativeCheckResult::performLogicalOperation(ExplicitQualitativeCheckResult& first, QualitativeCheckResult const& second, bool logicalAnd) { 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()) { if (logicalAnd) { boost::get(first.truthValues) &= boost::get(secondCheckResult.truthValues); } else { boost::get(first.truthValues) |= boost::get(secondCheckResult.truthValues); } } else { std::function function = logicalAnd ? std::function([] (bool a, bool b) { return a && b; }) : std::function([] (bool a, bool b) { return a || b; }); map_type& map1 = boost::get(first.truthValues); map_type const& map2 = boost::get(secondCheckResult.truthValues); for (auto& element1 : map1) { auto const& keyValuePair = map2.find(element1.first); STORM_LOG_THROW(keyValuePair != map2.end(), storm::exceptions::InvalidOperationException, "Cannot perform logical 'and' on check results of incompatible type."); element1.second = function(element1.second, keyValuePair->second); } // Double-check that there are no entries in map2 that the current result does not have. for (auto const& element2 : map2) { auto const& keyValuePair = map1.find(element2.first); STORM_LOG_THROW(keyValuePair != map1.end(), storm::exceptions::InvalidOperationException, "Cannot perform logical 'and' on check results of incompatible type."); } } } QualitativeCheckResult& ExplicitQualitativeCheckResult::operator&=(QualitativeCheckResult const& other) { performLogicalOperation(*this, other, true); return *this; } QualitativeCheckResult& ExplicitQualitativeCheckResult::operator|=(QualitativeCheckResult const& other) { performLogicalOperation(*this, other, false); return *this; } bool ExplicitQualitativeCheckResult::existsTrue() const { if (this->isResultForAllStates()) { return !boost::get(truthValues).empty(); } else { for (auto& element : boost::get(truthValues)) { if(element.second) { return true; } } return false; } } bool ExplicitQualitativeCheckResult::forallTrue() const { if (this->isResultForAllStates()) { return boost::get(truthValues).full(); } else { for (auto& element : boost::get(truthValues)) { if(!element.second) { return false; } } return true; } } uint64_t ExplicitQualitativeCheckResult::count() const { if (this->isResultForAllStates()) { return boost::get(truthValues).getNumberOfSetBits(); } else { uint64_t result = 0; for (auto& element : boost::get(truthValues)) { if(element.second) { ++result; } } return result; } } bool ExplicitQualitativeCheckResult::operator[](storm::storage::sparse::state_type state) const { if (this->isResultForAllStates()) { return boost::get(truthValues).get(state); } else { map_type const& map = boost::get(truthValues); auto const& keyValuePair = map.find(state); STORM_LOG_THROW(keyValuePair != map.end(), storm::exceptions::InvalidOperationException, "Unknown key '" << state << "'."); return keyValuePair->second; } } ExplicitQualitativeCheckResult::vector_type const& ExplicitQualitativeCheckResult::getTruthValuesVector() const { return boost::get(truthValues); } ExplicitQualitativeCheckResult::map_type const& ExplicitQualitativeCheckResult::getTruthValuesMap() const { return boost::get(truthValues); } void ExplicitQualitativeCheckResult::complement() { if (this->isResultForAllStates()) { boost::get(truthValues).complement(); } else { for (auto& element : boost::get(truthValues)) { element.second = !element.second; } } } bool ExplicitQualitativeCheckResult::isExplicit() const { return true; } bool ExplicitQualitativeCheckResult::isResultForAllStates() const { return truthValues.which() == 0; } bool ExplicitQualitativeCheckResult::isExplicitQualitativeCheckResult() const { return true; } std::ostream& ExplicitQualitativeCheckResult::writeToStream(std::ostream& out) const { if (this->isResultForAllStates()) { vector_type const& vector = boost::get(truthValues); bool allTrue = vector.full(); bool allFalse = !allTrue && vector.empty(); if (allTrue) { out << "{true}"; } else if (allFalse) { out << "{false}"; } else { out << "{true, false}"; } } else { std::ios::fmtflags oldflags(std::cout.flags()); out << std::boolalpha; map_type const& map = boost::get(truthValues); if (map.size() == 1) { out << map.begin()->second; } else { bool allTrue = true; bool allFalse = true; for (auto const& entry : map) { if (entry.second) { allFalse = false; } else { allTrue = false; } } if (allTrue) { out << "{true}"; } else if (allFalse) { out << "{false}"; } else { out << "{true, false}"; } } std::cout.flags(oldflags); } return out; } void ExplicitQualitativeCheckResult::filter(QualitativeCheckResult const& filter) { STORM_LOG_THROW(filter.isExplicitQualitativeCheckResult(), storm::exceptions::InvalidOperationException, "Cannot filter explicit check result with non-explicit filter."); STORM_LOG_THROW(filter.isResultForAllStates(), storm::exceptions::InvalidOperationException, "Cannot filter check result with non-complete filter."); ExplicitQualitativeCheckResult const& explicitFilter = filter.asExplicitQualitativeCheckResult(); vector_type const& filterTruthValues = explicitFilter.getTruthValuesVector(); if (this->isResultForAllStates()) { map_type newMap; for (auto element : filterTruthValues) { newMap.emplace(element, this->getTruthValuesVector().get(element)); } this->truthValues = newMap; } else { map_type const& map = boost::get(truthValues); map_type newMap; for (auto const& element : map) { if (filterTruthValues.get(element.first)) { newMap.insert(element); } } STORM_LOG_THROW(newMap.size() == filterTruthValues.getNumberOfSetBits(), storm::exceptions::InvalidOperationException, "The check result fails to contain some results referred to by the filter."); this->truthValues = newMap; } } template void insertJsonEntry(storm::json& json, uint64_t const& id, bool value, boost::optional const& stateValuations = boost::none) { storm::json entry; if (stateValuations) { entry["s"] = stateValuations->template toJson(id); } else { entry["s"] = id; } entry["v"] = value; json.push_back(std::move(entry)); } template storm::json ExplicitQualitativeCheckResult::toJson(boost::optional const& stateValuations) const { storm::json result; if (this->isResultForAllStates()) { vector_type const& valuesAsVector = boost::get(truthValues); for (uint64_t state = 0; state < valuesAsVector.size(); ++state) { insertJsonEntry(result, state, valuesAsVector.get(state), stateValuations); } } else { map_type const& valuesAsMap = boost::get(truthValues); for (auto const& stateValue : valuesAsMap) { insertJsonEntry(result, stateValue.first, stateValue.second, stateValuations); } } return result; } template storm::json ExplicitQualitativeCheckResult::toJson(boost::optional const&) const; template storm::json ExplicitQualitativeCheckResult::toJson(boost::optional const&) const; } }