118 ValuationsStorage(uint64_t numEntities, std::vector<ValuationClassDescription>
const& descriptions, std::vector<char> valuations,
119 std::vector<uint64_t> stringMapping, std::vector<char> strings, std::optional<std::vector<uint32_t>> classes = {},
120 std::vector<std::shared_ptr<storm::expressions::ExpressionManager const>> expressionManagers = {});
131 ValuationsStorage(uint64_t numEntities, ValuationClassDescription
const& description, std::vector<char> valuations,
132 std::shared_ptr<storm::expressions::ExpressionManager const> expressionManager = {});
141 std::vector<std::shared_ptr<storm::expressions::ExpressionManager const>> expressionManagers = {});
149 ValuationsStorage(ValuationClassDescription
const& description, std::shared_ptr<storm::expressions::ExpressionManager const> expressionManager = {});
154 uint64_t
size()
const;
191 storm::expressions::ExpressionManager
const&
getManager()
const;
197 storm::expressions::ExpressionManager
const&
getManager(uint64_t classIndex)
const;
207 bool entityHasVariable(uint64_t entity, storm::expressions::Variable
const& variable)
const;
228 typename storm::umb::UmbModel::Valuation
getRawUmbData()
const;
238 void resize(uint64_t newEntityCount, uint64_t classIndex = 0);
252 template<
bool AllowOptional =
false,
typename... AllowedTypes, ValuationWriteCallback Callback>
255 "Class index " << classIndex <<
" out of bounds. Only " << variableClasses.size() <<
"classes known.");
256 valuations.resize(valuations.size() + variableClasses[classIndex].sizeInBytes, 0);
257 if (entityClassMappings) {
258 entityClassMappings->toClassMapping.push_back(classIndex);
259 entityClassMappings->toValuationsMapping.push_back(valuations.size());
274 STORM_LOG_ASSERT(variableClasses.size() == 1,
"Trying to add a valuation but the class is not unique.");
275 emplaceBack<AllowOptional, AllowedTypes...>(0, callback);
298 for (
auto const& varInfo : info(entity).variables) {
299 read<AllowedTypes...>(entity, varInfo, callback);
329 for (uint64_t entity = 0; entity <
size(); ++entity) {
330 read<AllowedTypes...>(entity, varInfo, callback);
333 for (uint64_t entity = 0; entity <
size(); ++entity) {
334 readCallback<AllowedTypes...>(entity, variable, callback);
348 for (uint64_t entity = 0; entity <
size(); ++entity) {
362 template<
typename ValueType>
375 template<
typename RationalValueType>
393 template<
bool InitializeWithCurrent =
false,
bool AllowOptional =
false,
typename... AllowedTypes,
ValuationWriteCallback Callback>
395 for (
auto const& varInfo : info(entity).variables) {
396 write<InitializeWithCurrent, AllowOptional, AllowedTypes...>(entity, varInfo, callback);
410 template<
bool InitializeWithCurrent =
false,
bool AllowOptional =
false,
typename... AllowedTypes,
ValuationWriteCallback Callback>
412 write<InitializeWithCurrent, AllowOptional, AllowedTypes...>(entity,
getVariableInformation(entity, variable), callback);
424 template<
bool InitializeWithCurrent =
false,
bool AllowOptional =
false,
typename... AllowedTypes,
ValuationWriteCallback Callback>
426 for (uint64_t entity = 0; entity <
size(); ++entity) {
427 writeCallback<InitializeWithCurrent, AllowOptional, AllowedTypes...>(entity, callback);
440 template<
typename ValueType>
442 if constexpr (std::is_same_v<ValueType, std::nullopt_t>) {
444 }
else if constexpr (std::is_same_v<ValueType, std::string_view>) {
456 std::size_t
hash()
const;
464 static std::string typeName() {
465 if constexpr (std::is_same_v<T, bool>) {
467 }
else if constexpr (std::is_same_v<T, int64_t>) {
469 }
else if constexpr (std::is_same_v<T, uint64_t>) {
471 }
else if constexpr (std::is_same_v<T, double>) {
473 }
else if constexpr (std::is_same_v<T, storm::RationalNumber>) {
474 return "storm::RationalNumber";
475 }
else if constexpr (std::is_same_v<T, Integer>) {
476 return "Integer (arbitrary-precision)";
477 }
else if constexpr (std::is_same_v<T, std::string>) {
478 return "std::string";
479 }
else if constexpr (std::is_same_v<T, std::string_view>) {
480 return "std::string_view";
481 }
else if constexpr (std::is_same_v<T, std::nullopt_t>) {
482 return "std::nullopt_t";
484 return typeid(T).name();
492 template<
typename... Types>
493 static std::string typeNames() {
494 std::ostringstream oss;
495 [[maybe_unused]]
bool first =
true;
496 ((oss << (first ?
"" :
", ") << typeName<Types>(), first =
false), ...);
500 uint64_t numEntities;
501 std::vector<VariablesInformation> variableClasses;
504 std::vector<uint32_t> toClassMapping;
505 std::vector<uint64_t> toValuationsMapping;
507 std::optional<ClassData> entityClassMappings;
509 std::vector<char> valuations;
510 std::vector<uint64_t> stringMapping;
511 std::vector<char> strings;
513 explicit ValuationsStorage(std::vector<VariablesInformation>
const& variableClasses);
516 std::span<char const> getRawBytes(uint64_t entity)
const;
517 std::span<char> getRawBytes(uint64_t entity);
519 bool readBit(std::span<char const> bytes, uint64_t position)
const;
520 void writeBit(std::span<char> bytes, uint64_t position,
bool value)
const;
521 uint64_t readUint64(std::span<char const> bytes, uint64_t bitOffset, uint64_t bitSize)
const;
522 void writeUint64(std::span<char> bytes, uint64_t bitOffset, uint64_t bitSize, uint64_t value)
const;
524 template<
bool Signed>
525 Integer readInteger(std::span<char const> bytes, uint64_t bitOffset, uint64_t bitSize)
const;
527 template<
bool Signed>
528 void writeInteger(std::span<char> bytes, uint64_t bitOffset, uint64_t bitSize,
Integer const& value)
const;
530 template<
typename ValueType>
531 void writeValue(std::span<char> bytes, uint64_t bitOffset, uint64_t bitSize, ValueType
const& value);
540 template<
typename... AllowedTypes, ValuationReadCallback Callback>
541 void read(uint64_t entity,
VariableInformation const& varInfo, Callback
const& callback)
const {
542 auto invokeCallback = [&entity, &varInfo, &callback](
auto&& value) ->
bool {
543 using ValueType = std::remove_cvref_t<
decltype(value)>;
544 bool constexpr IsAllowed = (
sizeof...(AllowedTypes) == 0) || std::disjunction_v<std::is_same<ValueType, AllowedTypes>...>;
545 if constexpr (IsAllowed) {
546 callback(entity, varInfo.expressionVariable, std::forward<
decltype(value)>(value));
551 if (varInfo.description.isOptional.value_or(
false)) {
552 STORM_LOG_ASSERT(varInfo.bitOffset > 0,
"Invalid variable information: optional variable must have a preceding presence bit.");
553 if (
bool const hasValue = readBit(getRawBytes(entity), varInfo.bitOffset - 1); !hasValue) {
554 if (invokeCallback(std::nullopt)) {
559 auto const bitSize = varInfo.description.type.bitSize();
561 if (varInfo.fits64Bit) {
563 uint64_t
const rawContent = readUint64(getRawBytes(entity), varInfo.bitOffset, bitSize);
564 switch (varInfo.description.type.type) {
566 if (invokeCallback(rawContent != 0)) {
571 if (int64_t offset = varInfo.description.offset.value_or(0); offset < 0) {
573 if (invokeCallback(
static_cast<int64_t
>(rawContent) + offset)) {
578 uint64_t
const value = rawContent + offset;
579 uint64_t
constexpr maxInt64 = std::numeric_limits<int64_t>::max();
580 if (invokeCallback(value) || (value <= maxInt64 && invokeCallback(
static_cast<int64_t
>(value)))) {
586 uint64_t
const mostSignificantBitMask = 1ull << (bitSize - 1);
587 bool const isNegative = rawContent & mostSignificantBitMask;
589 int64_t
const value =
590 isNegative ? (-
static_cast<int64_t
>(~rawContent & (mostSignificantBitMask - 1)) - 1) : static_cast<int64_t>(rawContent);
591 if (invokeCallback(value)) {
597 if (invokeCallback(std::bit_cast<double>(rawContent))) {
603 STORM_LOG_ASSERT(
false,
"Handling of rational values in 64 bit fast path is not implemented.");
609 invokeCallback(sv) || invokeCallback(std::string(sv))) {
615 "ValuationsStorage for variable type '" << varInfo.description.type.toString() <<
"' are not supported.");
619 switch (varInfo.description.type.type) {
622 if (invokeCallback(readInteger<false>(getRawBytes(entity), varInfo.bitOffset, bitSize) !=
Integer(0))) {
628 Integer value = varInfo.description.type.type ==
Int ? readInteger<true>(getRawBytes(entity), varInfo.bitOffset, bitSize)
629 : readInteger<false>(getRawBytes(entity), varInfo.bitOffset, bitSize);
631 if (invokeCallback(value)) {
645 STORM_LOG_ASSERT(varInfo.fits64Bit,
"Double variables with more than 64 bits are not compliant.");
648 STORM_LOG_ASSERT(bitSize % 2 == 0,
"Rational number bit size must be even.");
649 uint64_t
const b = bitSize / 2;
650 storm::RationalNumber
const numerator = readInteger<true>(getRawBytes(entity), varInfo.bitOffset, b);
651 storm::RationalNumber
const denominator = readInteger<false>(getRawBytes(entity), varInfo.bitOffset + b, b);
652 if (invokeCallback(storm::RationalNumber(numerator / denominator))) {
661 STORM_LOG_ASSERT(varInfo.fits64Bit,
"String variables with more than 64 bits are not compliant.");
665 "ValuationsStorage for variable type '" << varInfo.description.type.toString() <<
"' are not supported.");
669 "Variable " << varInfo.description.name <<
" is stored as " << varInfo.description.type.toString()
670 <<
", which cannot be read as any of the requested C++ type(s) [" << typeNames<AllowedTypes...>()
671 <<
"]. Check that you are using the accessor matching the variable's declared storage type (e.g. "
672 "getDoubleValue instead of getRationalValue for a variable added via addDoubleVariable).");
675 template<
bool InitializeWithCurrent =
false,
bool AllowOptional =
false,
typename... AllowedTypes, ValuationWriteCallback Callback>
676 void write(uint64_t entity,
VariableInformation const& varInfo, Callback
const& callback) {
677 auto invokeCallback = [
this, &entity, &varInfo, &callback]<
typename ValueType>() ->
bool {
678 bool constexpr IsAllowed = (
sizeof...(AllowedTypes) == 0) || std::disjunction_v<std::is_same<ValueType, AllowedTypes>...>;
679 if constexpr (IsAllowed) {
681 bool isOptional = varInfo.description.isOptional.value_or(
false);
682 bool initializeAsUnsetOptional =
false;
683 if constexpr (InitializeWithCurrent) {
685 read<std::nullopt_t, ValueType>(entity, varInfo, [&value, &initializeAsUnsetOptional](
auto...,
auto&& currentValue) {
686 using CurrentVT = std::remove_cvref_t<
decltype(currentValue)>;
687 if constexpr (std::is_same_v<CurrentVT, ValueType>) {
688 value = currentValue;
690 static_assert(std::is_same_v<CurrentVT, std::nullopt_t>);
691 initializeAsUnsetOptional =
true;
695 initializeAsUnsetOptional = isOptional;
696 if constexpr (std::is_same_v<ValueType, uint64_t> || std::is_same_v<ValueType, int64_t> || std::is_same_v<ValueType, Integer>) {
698 if (varInfo.description.lower && (!std::is_same_v<ValueType, uint64_t> || varInfo.description.lower.value() >= 0)) {
700 }
else if (!varInfo.description.upper || varInfo.description.upper >= 0) {
708 bool haveToWriteValue =
false;
710 if constexpr (AllowOptional) {
711 std::optional<ValueType> optionalValue = initializeAsUnsetOptional ? std::optional<ValueType>() : value;
712 callback(entity, varInfo.expressionVariable, optionalValue);
713 if (optionalValue.has_value()) {
714 value = std::move(optionalValue.value());
715 haveToWriteValue =
true;
717 STORM_LOG_ASSERT(varInfo.bitOffset > 0,
"Invalid variable information: optional variable must have a preceding presence bit.");
718 writeBit(getRawBytes(entity), varInfo.bitOffset - 1, optionalValue.has_value());
721 "Writing to optional variable " << varInfo.description.name <<
" was not expected.");
724 callback(entity, varInfo.expressionVariable, value);
725 haveToWriteValue =
true;
727 if (haveToWriteValue) {
729 if constexpr (std::is_same_v<ValueType, uint64_t> || std::is_same_v<ValueType, int64_t> || std::is_same_v<ValueType, Integer>) {
730 if constexpr (std::is_same_v<ValueType, uint64_t> || std::is_same_v<ValueType, int64_t>) {
731 STORM_LOG_THROW(!varInfo.description.lower || std::cmp_greater_equal(value, varInfo.description.lower.value()),
732 storm::exceptions::OutOfRangeException,
733 "Value " << value <<
" is out of range for variable " << varInfo.description.name
734 <<
": value is smaller than lower bound " << varInfo.description.lower.value() <<
".");
735 STORM_LOG_THROW(!varInfo.description.upper || std::cmp_less_equal(value, varInfo.description.upper.value()),
736 storm::exceptions::OutOfRangeException,
737 "Value " << value <<
" is out of range for variable " << varInfo.description.name
738 <<
": value is greater than upper bound " << varInfo.description.upper.value() <<
".");
740 if (varInfo.description.lower) {
742 storm::exceptions::OutOfRangeException,
743 "Value " << value <<
" is out of range for variable " << varInfo.description.name
744 <<
": value is smaller than lower bound " << varInfo.description.lower.value() <<
".");
746 if (varInfo.description.upper) {
748 storm::exceptions::OutOfRangeException,
749 "Value " << value <<
" is out of range for variable " << varInfo.description.name
750 <<
": value is greater than upper bound " << varInfo.description.upper.value() <<
".");
753 if (
auto offset = varInfo.description.offset.value_or(0); offset != 0) {
754 if constexpr (std::is_same_v<ValueType, uint64_t>) {
756 "Set negative value " << value <<
"-" << offset <<
" to unsigned variable.");
764 writeValue(getRawBytes(entity), varInfo.bitOffset, varInfo.description.type.bitSize(), value);
771 switch (varInfo.description.type.type) {
773 if (invokeCallback.template
operator()<
bool>()) {
778 if (varInfo.fits64Bit) {
779 if (varInfo.description.offset.value_or(0) >= 0) {
781 if (invokeCallback.template
operator()<uint64_t>()) {
786 if (invokeCallback.template
operator()<int64_t>()) {
791 if (invokeCallback.template
operator()<
Integer>()) {
797 if ((varInfo.fits64Bit && invokeCallback.template
operator()<int64_t>()) || invokeCallback.template
operator()<
Integer>()) {
802 if (invokeCallback.template
operator()<
double>()) {
807 if (invokeCallback.template
operator()<storm::RationalNumber>()) {
812 if (invokeCallback.template
operator()<std::string>()) {
818 "ValuationsStorage for variable type '" << varInfo.description.type.toString() <<
"' are not supported.");
821 "Variable " << varInfo.description.name <<
" is stored as " << varInfo.description.type.toString()
822 <<
", which cannot be written as any of the requested C++ type(s) [" << typeNames<AllowedTypes...>()
823 <<
"]. Check that you are using the accessor matching the variable's declared storage type (e.g. "
824 "writeDoubleValue instead of writeRationalValue for a variable added via addDoubleVariable).");