26 Valuations(std::vector<ValuationClassDescription>
const& descriptions, std::vector<char> valuations, std::vector<uint64_t> stringMapping,
27 std::vector<char> strings, std::optional<std::vector<uint32_t>> classes = {},
28 std::vector<std::shared_ptr<storm::expressions::ExpressionManager>> expressionManagers = {})
29 : valuations(
std::move(valuations)), stringMapping(
std::move(stringMapping)), strings(
std::move(strings)) {
30 if (expressionManagers.empty()) {
31 expressionManagers.emplace_back(std::make_shared<storm::expressions::ExpressionManager>());
33 STORM_LOG_ASSERT(descriptions.size() == expressionManagers.size() || expressionManagers.size() == 1,
34 "Mismatch between number of descriptions and expression managers.");
35 for (uint64_t i = 0; i < descriptions.size(); ++i) {
38 auto& manager = expressionManagers.size() == 1 ? *expressionManagers.front() : *expressionManagers[i];
39 variableClasses.push_back(createVariablesInformation(manager, descriptions[i]));
41 if (classes.has_value()) {
42 STORM_LOG_ASSERT(classes->size() == descriptions.size(),
"Mismatch between number of descriptions and class mapping.");
43 uniqueSizeInBytes = std::numeric_limits<uint64_t>::max();
44 this->classes = {std::move(*classes), std::vector<uint64_t>{1, 0}};
45 std::vector<uint64_t> classSizesInBytes;
46 for (
auto const& descr : descriptions) {
47 classSizesInBytes.push_back(descr.sizeInBits() / 8);
50 this->classes->toValuationsMapping.reserve(this->classes->toClassMapping.size() + 1);
51 for (uint64_t entity = 0; entity < this->classes->toClassMapping.size(); ++entity) {
52 pos += classSizesInBytes[this->classes->toClassMapping[entity]];
53 this->classes->toValuationsMapping.push_back(pos);
55 STORM_LOG_ASSERT(valuations.size() == pos,
"Valuation data size does not match class mapping.");
57 STORM_LOG_ASSERT(descriptions.size() == 1,
"Valuation descriptions must be unique if no class mapping is given.");
58 uniqueSizeInBytes = descriptions.front().sizeInBits() / 8;
59 STORM_LOG_ASSERT(valuations.size() % uniqueSizeInBytes == 0,
"Valuation data size is not a multiple of the unique valuation size.");
63 Valuations(std::vector<ValuationClassDescription> descriptions, std::vector<char> valuations, std::optional<std::vector<uint32_t>> classes = {},
64 std::vector<std::shared_ptr<storm::expressions::ExpressionManager>> expressionManagers = {})
65 : Valuations(
std::move(descriptions),
std::move(valuations), {}, {}, std::move(classes), std::move(expressionManagers)) {
71 return classes->toClassMapping.size();
73 return valuations.size() / uniqueSizeInBytes;
78 return stringMapping.size() > 0 ? stringMapping.size() - 1 : 0;
81 void read(uint64_t entity,
auto const& callback)
const {
82 for (
auto const& varInfo : info(entity).variables) {
83 read(entity, varInfo, callback);
87 void read(
auto const& callback)
const {
88 for (uint64_t entity = 0; entity <
size(); ++entity) {
89 read(entity, callback);
97 struct VariableInformation {
100 uint64_t
const bitOffset;
102 bool const fits64Bit;
104 struct VariablesInformation {
105 std::vector<VariableInformation> variables;
106 std::shared_ptr<storm::expressions::ExpressionManager> expressionManager;
108 std::vector<VariablesInformation> variableClasses;
112 std::vector<uint32_t> toClassMapping;
113 std::vector<uint64_t> toValuationsMapping;
115 std::optional<ClassData> classes;
116 uint64_t uniqueSizeInBytes;
119 std::vector<char> valuations;
120 std::vector<uint64_t> stringMapping;
121 std::vector<char> strings;
129 if (varDesc.type.bitSize() > 64) {
132 switch (varDesc.type.type) {
136 if (varDesc.offset.value_or(0) == 0) {
140 uint64_t
const maxValue = varDesc.upper.has_value() ?
static_cast<uint64_t
>(varDesc.upper.value())
141 : (varDesc.type.bitSize() == 64) ? std::numeric_limits<uint64_t>::max()
142 : (static_cast<uint64_t>(1) << varDesc.type.bitSize()) - 1;
144 if (varDesc.offset.value() < 0) {
146 return maxValue - static_cast<uint64_t>(-varDesc.offset.value()) <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max());
149 return maxValue <= std::numeric_limits<uint64_t>::max() - static_cast<uint64_t>(varDesc.offset.value());
153 if (varDesc.offset.value_or(0) == 0) {
157 int64_t
const maxValue = varDesc.upper.value_or(varDesc.type.bitSize() == 64 ? std::numeric_limits<int64_t>::max()
158 : (
static_cast<int64_t
>(1) << (varDesc.type.bitSize() - 1)) - 1);
159 int64_t
const minValue = varDesc.lower.value_or(varDesc.type.bitSize() == 64 ? std::numeric_limits<int64_t>::min()
160 : -(
static_cast<int64_t
>(1) << (varDesc.type.bitSize() - 1)));
161 if (varDesc.offset.value() < 0) {
163 return minValue >= std::numeric_limits<int64_t>::min() - varDesc.offset.value();
166 return maxValue <= std::numeric_limits<int64_t>::max() - varDesc.offset.value();
177 "Valuations for variable type '" << varDesc.type.toString() <<
"' are not supported.");
181 static VariablesInformation createVariablesInformation(storm::expressions::ExpressionManager& expressionManager,
183 VariablesInformation result{.variables = {}, .expressionManager = expressionManager.shared_from_this()};
184 uint64_t currentOffset = 0;
185 for (
auto const& varVariant : description.variables) {
186 if (std::holds_alternative<ValuationClassDescription::Variable>(varVariant)) {
187 auto const& varDesc = std::get<ValuationClassDescription::Variable>(varVariant);
188 storm::expressions::Type variableType;
190 switch (varDesc.type.type) {
207 "Valuations for variable type '" << varDesc.type.toString() <<
"' are not supported.");
209 if (varDesc.isOptional.value_or(
false)) {
212 result.variables.emplace_back(VariableInformation{.expressionVariable = expressionManager.
declareOrGetVariable(varDesc.name, variableType),
213 .description = varDesc,
214 .bitOffset = currentOffset,
215 .fits64Bit = fits64Bit(varDesc)});
216 currentOffset += result.variables.back().description.type.bitSize();
218 auto const& padding = std::get<ValuationClassDescription::Padding>(varVariant);
219 currentOffset += padding.padding;
222 STORM_LOG_ASSERT(currentOffset == description.sizeInBits(),
"Computed size does not match description size.");
223 STORM_LOG_ASSERT(currentOffset % 8 == 0,
"Invalid valuation description detected: size in bits must be a multiple of 8.");
227 VariablesInformation
const& info(uint64_t entity)
const {
228 STORM_LOG_ASSERT(entity < size(),
"Entity index out of bounds: " << entity <<
" >= " << size() <<
".");
230 return variableClasses[classes->toClassMapping[entity]];
232 return variableClasses.front();
236 std::span<char const> bytes(uint64_t entity)
const {
237 STORM_LOG_ASSERT(entity < size(),
"Entity index out of bounds: " << entity <<
" >= " << size() <<
".");
239 auto const start = classes->toValuationsMapping[entity];
240 auto const end = classes->toValuationsMapping[entity + 1];
241 return std::span<char const>(&valuations[start], end - start);
243 auto const start = entity * uniqueSizeInBytes;
244 return std::span<char const>(&valuations[start], uniqueSizeInBytes);
248 std::span<char> bytes(uint64_t entity) {
250 auto const start = classes->toValuationsMapping[entity];
251 auto const end = classes->toValuationsMapping[entity + 1];
252 return std::span<char>(&valuations[start], end - start);
254 auto const start = entity * uniqueSizeInBytes;
255 return std::span<char>(&valuations[start], uniqueSizeInBytes);
259 uint64_t readUint64(std::span<char const> bytes, uint64_t
const bitOffset, uint64_t
const bitSize)
const {
260 STORM_LOG_ASSERT(bitOffset < bytes.size() * 8,
"Variable offset exceeds valuation size.");
262 auto const firstByte = bitOffset / 8;
263 auto const bitOffsetWithinByte = bitOffset % 8;
264 auto const numBytes = (bitOffsetWithinByte + bitSize + 7) / 8;
265 STORM_LOG_ASSERT(numBytes <= 9,
"Invalid number of bytes computed: " << numBytes);
268 std::memcpy(&result, &bytes[firstByte], std::min<uint64_t>(numBytes, 8ull));
269 result >>= bitOffsetWithinByte;
271 if (numBytes == 9ull) {
272 uint64_t upperBits = std::bit_cast<uint8_t>(bytes[firstByte + 8]);
273 upperBits <<= (64 - bitOffsetWithinByte);
278 uint64_t
const relevantBitMask = (1ull << bitSize) - 1;
279 result &= relevantBitMask;
284 template<
bool Signed>
285 Integer readInteger(std::span<char const> bytes, uint64_t
const bitOffset, uint64_t
const bitSize)
const {
286 auto const num64BitChunks = (bitSize + 63) / 64;
288 std::ranges::iota_view(0ull, num64BitChunks) | std::ranges::views::transform([
this, &bytes, &bitOffset, &bitSize](
auto i) -> uint64_t {
289 return readUint64(bytes, bitOffset + i * 64, std::min<uint64_t>(64, bitSize - i * 64));
292 if constexpr (Signed) {
301 template<
typename... AllowedTypes>
302 void read(uint64_t entity, VariableInformation
const& varInfo,
auto const& callback)
const {
303 bool constexpr allowAny = (
sizeof...(AllowedTypes) == 0);
304 bool constexpr allowNullopt = allowAny || std::disjunction_v<std::is_same<std::nullopt_t, AllowedTypes>...>;
305 bool constexpr allowBool = allowAny || std::disjunction_v<std::is_same<bool, AllowedTypes>...>;
306 bool constexpr allowUint64 = allowAny || std::disjunction_v<std::is_same<uint64_t, AllowedTypes>...>;
307 bool constexpr allowInt64 = allowAny || std::disjunction_v<std::is_same<int64_t, AllowedTypes>...>;
308 bool constexpr allowDouble = allowAny || std::disjunction_v<std::is_same<double, AllowedTypes>...>;
309 bool constexpr allowRational = allowAny || std::disjunction_v<std::is_same<storm::RationalNumber, AllowedTypes>...>;
310 bool constexpr allowInteger = allowAny || std::disjunction_v<std::is_same<Integer, AllowedTypes>...>;
311 bool constexpr allowString = allowAny || std::disjunction_v<std::is_same<std::string_view, AllowedTypes>...>;
313 if (varInfo.description.isOptional.value_or(
false)) {
314 if constexpr (allowNullopt) {
315 callback(entity, varInfo.expressionVariable, std::nullopt);
318 auto const bitSize = varInfo.description.type.bitSize();
320 if (varInfo.fits64Bit) {
322 uint64_t rawContent = readUint64(bytes(entity), varInfo.bitOffset, bitSize);
323 switch (varInfo.description.type.type) {
325 if constexpr (allowBool) {
326 callback(entity, varInfo.expressionVariable, rawContent != 0);
330 if (int64_t offset = varInfo.description.offset.value_or(0); offset < 0) {
332 if constexpr (allowInt64) {
333 callback(entity, varInfo.expressionVariable,
static_cast<int64_t
>(rawContent) + offset);
338 uint64_t value = rawContent + offset;
339 if constexpr (allowUint64) {
340 callback(entity, varInfo.expressionVariable, value);
342 }
else if constexpr (allowInt64) {
343 if (value <=
static_cast<uint64_t
>(std::numeric_limits<int64_t>::max())) {
344 callback(entity, varInfo.expressionVariable,
static_cast<int64_t
>(value));
350 if constexpr (allowInt64) {
351 uint64_t
const mostSignificantBitMask = 1ull << (bitSize - 1);
352 if (rawContent & mostSignificantBitMask) {
354 callback(entity, varInfo.expressionVariable, -
static_cast<int64_t
>(~rawContent & (mostSignificantBitMask - 1)) - 1);
358 callback(entity, varInfo.expressionVariable,
static_cast<int64_t
>(rawContent));
363 if constexpr (allowDouble) {
364 callback(entity, varInfo.expressionVariable,
static_cast<double>(std::bit_cast<double>(rawContent)));
369 STORM_LOG_ASSERT(
false,
"Handling of rational values in 64 bit fast path is not implemented.");
371 if constexpr (allowString) {
372 callback(entity, varInfo.expressionVariable,
stringVectorView(strings, stringMapping)[rawContent]);
377 "Valuations for variable type '" << varInfo.description.type.toString() <<
"' are not supported.");
381 switch (varInfo.description.type.type) {
383 if constexpr (allowBool) {
385 callback(entity, varInfo.expressionVariable, readInteger<false>(bytes(entity), varInfo.bitOffset, bitSize) !=
Integer(0));
390 if constexpr (allowInteger) {
391 Integer value = varInfo.description.type.type ==
Int ? readInteger<true>(bytes(entity), varInfo.bitOffset, bitSize)
392 : readInteger<false>(bytes(entity), varInfo.bitOffset, bitSize);
394 callback(entity, varInfo.expressionVariable, value);
399 STORM_LOG_ASSERT(
false,
"double variables with more than 64 bits are not compliant.");
401 if constexpr (allowRational) {
402 STORM_LOG_ASSERT(bitSize % 2 == 0,
"Rational number bit size must be even.");
403 uint64_t b = bitSize / 2;
404 storm::RationalNumber
numerator = readInteger<true>(bytes(entity), varInfo.bitOffset, b);
405 storm::RationalNumber
denominator = readInteger<false>(bytes(entity), varInfo.bitOffset + b, b);
406 callback(entity, varInfo.expressionVariable, storm::RationalNumber(numerator / denominator));
411 STORM_LOG_ASSERT(
false,
"String variables with more than 64 bits are not compliant.");
415 "Valuations for variable type '" << varInfo.description.type.toString() <<
"' are not supported.");
419 "Variable " << varInfo.description.name <<
" of type " << varInfo.description.type.toString() <<
" is not handled.");