20 template<
bool Signed, std::ranges::input_range InputRange>
21 requires std::same_as<std::ranges::range_value_t<InputRange>, uint64_t>
26 STORM_LOG_ASSERT(std::ranges::size(input) > 0,
"Input range must not be empty.");
28 auto reverse_input = std::ranges::reverse_view(std::forward<InputRange>(input));
31 auto decodeFromUnsignedRange = [](
auto&& input) ->
IntegerType {
33 auto inputIt = std::ranges::begin(input);
34 auto const inputEnd = std::ranges::end(input);
36 for (++inputIt; inputIt != inputEnd; ++inputIt) {
43 if constexpr (Signed) {
45 uint64_t
constexpr mostSignificantBitMask = 1ull << 63;
46 if (*std::ranges::begin(reverse_input) & mostSignificantBitMask) {
48 return -decodeFromUnsignedRange(reverse_input | std::ranges::views::transform([](uint64_t value) {
return ~value; })) - 1;
52 return decodeFromUnsignedRange(reverse_input);
55 template<std::ranges::input_range InputRange>
56 requires std::same_as<std::ranges::range_value_t<InputRange>, uint64_t>
58 STORM_LOG_ASSERT(numberSize % 128ull == 0ull && numberSize > 0ull,
"Type size must be a positive multiple of 128 for rational representation.");
59 auto const uint64ValuesPerNumber = numberSize / 64ull;
60 auto const size = std::ranges::size(input) / uint64ValuesPerNumber;
61 return std::ranges::iota_view(0ull, size) | std::ranges::views::transform([&input, uint64ValuesPerNumber](
auto i) -> storm::RationalNumber {
62 auto const left = uint64ValuesPerNumber * i;
63 auto const right = left + uint64ValuesPerNumber;
64 auto mid = left + uint64ValuesPerNumber / 2;
66 std::ranges::subrange numeratorRange{std::ranges::begin(input) + left, std::ranges::begin(input) + mid};
69 std::ranges::subrange denominatorRange{std::ranges::begin(input) + mid, std::ranges::begin(input) + right};
72 return numerator / denominator;
76 template<std::ranges::input_range InputRange>
77 requires std::same_as<std::ranges::range_value_t<InputRange>, uint64_t>
80 "Type size must be a positive multiple of 256 for rational interval representation.");
82 return std::ranges::iota_view(0ull, std::ranges::size(rationalView) / 2) | std::views::transform([rationalView](
auto i) ->
storm::RationalInterval {
90 if constexpr (Signed) {
103 template<std::ranges::input_range InputRange>
104 requires std::same_as<std::ranges::range_value_t<InputRange>, storm::RationalNumber>
107 static_assert(storm::RationalNumberDenominatorAlwaysPositive);
108 uint64_t minimalIntegerSize = 1;
109 for (
auto const& r : input) {
115 minimalIntegerSize = ((minimalIntegerSize + 63ull) / 64ull) * 64ull;
118 return minimalIntegerSize * 2ull;
121 template<std::ranges::input_range InputRange>
127 template<
bool Signed>
129 uint64_t uint64BucketsPerInteger) {
130 if constexpr (Signed) {
136 for (
auto& v : std::span<uint64_t>(result.end() - uint64BucketsPerInteger, result.end())) {
144 "Encoding error for positive signed integer: most significant bit is set. Not enough uint64 buckets allocated?");
151 STORM_LOG_ASSERT(value >= 0,
"Value must be non-negative for unsigned encoding.");
154 uint64_t buckets = 1;
155 while (divisionResult.first != 0) {
161 result.resize(result.size() + (uint64BucketsPerInteger - buckets), 0ull);
165 static void appendEncodedRational(std::vector<uint64_t>& result, storm::RationalNumber
const& value, uint64_t uint64BucketsPerInteger) {
167 static_assert(storm::RationalNumberDenominatorAlwaysPositive);
172 template<std::ranges::input_range InputRange>
173 requires std::same_as<std::ranges::range_value_t<InputRange>, storm::RationalNumber>
175 STORM_LOG_ASSERT(numberSize % 128ull == 0ull && numberSize > 0ull,
"Type size must be a positive multiple of 128 for rational representation.");
176 auto const uint64BucketsPerNumber = numberSize / 64ull;
177 auto const size = std::ranges::size(input) * uint64BucketsPerNumber;
179 std::vector<uint64_t> values;
180 values.reserve(size);
181 for (
auto const& r : input) {
184 values.shrink_to_fit();
185 STORM_LOG_ASSERT(values.size() == size,
"Unexpected size of encoded rational values: " << values.size() <<
" vs. " << size);
189 template<std::ranges::input_range InputRange>
193 "Type size must be a positive multiple of 256 for rational interval representation.");
197 template<std::ranges::input_range InputRange>
198 requires std::same_as<std::ranges::range_value_t<InputRange>,
double>
200 STORM_LOG_ASSERT(std::ranges::size(input) % 2 == 0,
"Input size is not even: " << std::ranges::size(input));
201 return std::ranges::iota_view(0ull, std::ranges::size(input) / 2) |
205 template<
typename BaseType, std::ranges::input_range InputRange>
208 return std::ranges::iota_view(0ull, std::ranges::size(input) * 2) | std::views::transform([&input](
auto i) -> BaseType {
225 template<
typename ValueType>
228 auto conversionView = [](
auto&& input) {
229 using SourceType = std::ranges::range_value_t<
decltype(input)>;
230 if constexpr (std::same_as<ValueType, SourceType>) {
233 return input | std::ranges::views::transform(
241 switch (sourceType.
type) {
245 "Some values are given in type double but will be converted to an exact (arbitrary precision) type. Rounding errors may occur.");
246 STORM_LOG_ASSERT(input.template isType<double>(),
"Unexpected type for values. Expected double.");
247 STORM_LOG_ASSERT(sourceType.
bitSize() == 64,
"Unexpected source type size for double representation. Expected 64.");
248 return func(conversionView(input.template get<double>()));
251 "Some values are given in an exact type but converted to an inexact type. Rounding errors may occur.");
252 if (input.template isType<storm::RationalNumber>()) {
253 return func(conversionView(input.template get<storm::RationalNumber>()));
255 STORM_LOG_ASSERT(input.template isType<uint64_t>(),
"Unexpected type for rational representation. Expected uint64.");
262 "Some values are given as double intervals but a model with a non-interval type is requested.");
263 return func(std::ranges::empty_view<ValueType>{});
267 "Some values are given in type double but will be converted to an exact (arbitrary precision) type. Rounding errors may occur.");
268 STORM_LOG_ASSERT(sourceType.
bitSize() == 128ull,
"Unexpected source type size for double interval representation. Expected 128.");
269 if (input.template isType<storm::Interval>()) {
270 return func(conversionView(input.template get<storm::Interval>()));
272 STORM_LOG_ASSERT(input.template isType<double>(),
"Unexpected type for double interval representation. Expected double.");
280 "Some values are given as rational intervals but a model with a non-interval type is requested.");
281 return func(std::ranges::empty_view<ValueType>{});
284 "Some values are given in an exact type but converted to an inexact type. Rounding errors may occur.");
285 if (input.template isType<storm::RationalInterval>()) {
286 return func(conversionView(input.template get<storm::RationalInterval>()));
288 STORM_LOG_ASSERT(input.template isType<uint64_t>(),
"Unexpected type for rational interval representation. Expected uint64.");
293 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"Values have unsupported type " << sourceType.
toString() <<
".");
297 template<
typename ValueType>
300 [](
auto&& decodedInput) {
301 std::vector<ValueType> v;
302 v.reserve(std::ranges::size(decodedInput));
303 for (
auto&& value : decodedInput) {
static auto applyDecodedVector(auto &&func, storm::umb::GenericVector const &input, storm::umb::SizedType const &sourceType)
returns func(<decoded_input>) where <decoded_input> is a range that (if necessary) decodes and conver...
static uint64_t getMinimalRationalSize(InputRange &&input, bool multiplesOf64)
static auto intervalToBaseRangeView(InputRange &&input)
static uint64_t getMinimalRationalIntervalSize(InputRange &&input, bool multiplesOf64)
static void appendEncodedInteger(std::vector< uint64_t > &result, typename storm::NumberTraits< storm::RationalNumber >::IntegerType const &value, uint64_t uint64BucketsPerInteger)
static void appendEncodedRational(std::vector< uint64_t > &result, storm::RationalNumber const &value, uint64_t uint64BucketsPerInteger)
static std::vector< uint64_t > createUint64FromRationalRange(InputRange &&input, uint64_t const numberSize)
static storm::NumberTraits< storm::RationalNumber >::IntegerType decodeArbitraryPrecisionInteger(InputRange &&input)
static auto doubleToIntervalRangeView(InputRange &&input)
static std::vector< ValueType > createDecodedVector(storm::umb::GenericVector const &input, storm::umb::SizedType const &sourceType)
static auto uint64ToRationalIntervalRangeView(InputRange &&input, uint64_t const numberSize)
static auto uint64ToRationalRangeView(InputRange &&input, uint64_t const numberSize)
static uint64_t getSizeOfIntegerEncoding(typename storm::NumberTraits< storm::RationalNumber >::IntegerType const &value)
static std::vector< uint64_t > createUint64FromRationalIntervalRange(InputRange &&input, uint64_t const numberSize)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
NumberTraits< RationalType >::IntegerType denominator(RationalType const &number)
NumberTraits< RationalType >::IntegerType numerator(RationalType const &number)
std::pair< IntegerType, IntegerType > divide(IntegerType const ÷nd, IntegerType const &divisor)
(Integer-)Divides the dividend by the divisor and returns the result plus the remainder.
ValueType pow(ValueType const &value, int_fast64_t exponent)
uint64_t bitsize(ValueType const &number)
Returns the minimum number of bits to represent the given number.
TargetType convertNumber(SourceType const &number)
carl::Interval< storm::RationalNumber > RationalInterval
carl::Interval< double > Interval
Interval type.
constexpr bool IsIntervalType
Helper to check if a type is an interval.
static const bool IsExact
std::string toString() const
storm::SerializedEnum< storm::umb::TypeDeclaration > type