diff --git a/src/storm/utility/constants.cpp b/src/storm/utility/constants.cpp index 67ac0a6b8..e393fe6e6 100644 --- a/src/storm/utility/constants.cpp +++ b/src/storm/utility/constants.cpp @@ -295,6 +295,11 @@ namespace storm { ClnRationalNumber convertNumber(std::string const& number) { return carl::parse(number); } + + template<> + std::pair asFraction(ClnRationalNumber const& number) { + return std::make_pair(carl::getNum(number), carl::getDenom(number)); + } template<> ClnRationalNumber sqrt(ClnRationalNumber const& number) { @@ -426,6 +431,11 @@ namespace storm { return carl::parse(number); } + template<> + std::pair asFraction(GmpRationalNumber const& number) { + return std::make_pair(carl::getNum(number), carl::getDenom(number)); + } + template<> GmpRationalNumber sqrt(GmpRationalNumber const& number) { return carl::sqrt(number); diff --git a/src/storm/utility/constants.h b/src/storm/utility/constants.h index 69d253e81..5ade5e8f8 100644 --- a/src/storm/utility/constants.h +++ b/src/storm/utility/constants.h @@ -51,6 +51,9 @@ namespace storm { template TargetType convertNumber(SourceType const& number); + + template + std::pair asFraction(ValueType const& number); template ValueType simplify(ValueType value); diff --git a/src/storm/utility/vector.h b/src/storm/utility/vector.h index ddac7bd2c..b8f305a1c 100644 --- a/src/storm/utility/vector.h +++ b/src/storm/utility/vector.h @@ -19,6 +19,8 @@ #include "storm/utility/macros.h" #include "storm/solver/OptimizationDirection.h" +#include "storm/exceptions/NotImplementedException.h" + namespace storm { namespace utility { namespace vector { @@ -868,7 +870,62 @@ namespace storm { } return resultVector; } + + template + typename std::enable_if::value, std::pair, ValueType>>::type + toIntegralVector(std::vector const& vec) { + + // Collect the numbers occurring in the input vector + std::set occurringNonZeroNumbers; + for (auto const& v : vec) { + if (!storm::utility::isZero(v)) { + occurringNonZeroNumbers.insert(v); + } + } + + // Compute the scaling factor + ValueType factor; + if (occurringNonZeroNumbers.empty()) { + factor = storm::utility::one(); + } else if (occurringNonZeroNumbers.size() == 1) { + factor = storm::utility::one() / (*occurringNonZeroNumbers.begin()); + } else { + // Obtain the least common multiple of the denominators of the occurring numbers. + // We can then multiply the numbers with the lcm to obtain integers. + auto numberIt = occurringNonZeroNumbers.begin(); + ValueType lcm = storm::utility::asFraction(*numberIt).second; + for (++numberIt; numberIt != occurringNonZeroNumbers.end(); ++numberIt) { + lcm = carl::lcm(lcm, storm::utility::asFraction(*numberIt).second); + } + // Multiply all values with the lcm. To reduce the range of considered integers, we also obtain the gcd of the results. + numberIt = occurringNonZeroNumbers.begin(); + ValueType gcd = *numberIt * lcm; + for (++numberIt; numberIt != occurringNonZeroNumbers.end(); ++numberIt) { + gcd = carl::gcd(gcd, static_cast(*numberIt * lcm)); + } + + factor = gcd / lcm; + + } + + // Build the result + std::vector result; + result.resize(vec.size()); + for (auto const& v : vec) { + result.push_back(storm::utility::convertNumber(v / factor)); + STORM_LOG_ASSERT(storm::utility::isInteger(result.back()), "Resulting number '" << result.back() << "' is not integral."); + } + return std::make_pair(std::move(result), std::move(factor)); + + } + template + typename std::enable_if::value, std::pair, ValueType>>::type + toIntegralVector(std::vector const& vec) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Functionality not implemented."); + return std::pair, ValueType>(); + } + template std::vector filterVector(std::vector const& in, storm::storage::BitVector const& filter) { std::vector result;