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);
523 template<
typename ValueType>
524 requires(std::is_same_v<ValueType, int64_t> || std::is_same_v<ValueType, uint64_t> || std::is_same_v<ValueType, Integer>)
527 std::span<char const> getRawBytes(uint64_t entity)
const;
528 std::span<char> getRawBytes(uint64_t entity);
530 bool readBit(std::span<char const> bytes, uint64_t position)
const;
531 void writeBit(std::span<char> bytes, uint64_t position,
bool value)
const;
532 uint64_t readUint64(std::span<char const> bytes, uint64_t bitOffset, uint64_t bitSize)
const;
533 void writeUint64(std::span<char> bytes, uint64_t bitOffset, uint64_t bitSize, uint64_t value)
const;
535 template<
bool Signed>
536 Integer readInteger(std::span<char const> bytes, uint64_t bitOffset, uint64_t bitSize)
const;
538 template<
bool Signed>
539 void writeInteger(std::span<char> bytes, uint64_t bitOffset, uint64_t bitSize,
Integer const& value)
const;
541 template<
typename ValueType>
542 void writeValue(std::span<char> bytes, uint64_t bitOffset, uint64_t bitSize, ValueType
const& value);
551 template<
typename... AllowedTypes, ValuationReadCallback Callback>
552 void read(uint64_t entity,
VariableInformation const& varInfo, Callback
const& callback)
const {
553 auto invokeCallback = [&entity, &varInfo, &callback](
auto&& value) ->
bool {
554 using ValueType = std::remove_cvref_t<
decltype(value)>;
555 bool constexpr IsAllowed = (
sizeof...(AllowedTypes) == 0) || std::disjunction_v<std::is_same<ValueType, AllowedTypes>...>;
556 if constexpr (IsAllowed) {
557 callback(entity, varInfo.expressionVariable, std::forward<
decltype(value)>(value));
562 if (varInfo.description.isOptional.value_or(
false)) {
563 STORM_LOG_ASSERT(varInfo.bitOffset > 0,
"Invalid variable information: optional variable must have a preceding presence bit.");
564 if (
bool const hasValue = readBit(getRawBytes(entity), varInfo.bitOffset - 1); !hasValue) {
565 if (invokeCallback(std::nullopt)) {
570 auto const bitSize = varInfo.description.type.bitSize();
572 if (varInfo.fits64Bit) {
574 uint64_t
const rawContent = readUint64(getRawBytes(entity), varInfo.bitOffset, bitSize);
575 switch (varInfo.description.type.type) {
577 if (invokeCallback(rawContent != 0)) {
582 if (int64_t offset = varInfo.description.offset.value_or(0); offset < 0) {
584 if (invokeCallback(
static_cast<int64_t
>(rawContent) + offset)) {
589 uint64_t
const value = rawContent + offset;
590 uint64_t
constexpr maxInt64 = std::numeric_limits<int64_t>::max();
591 if (invokeCallback(value) || (value <= maxInt64 && invokeCallback(
static_cast<int64_t
>(value)))) {
597 uint64_t
const mostSignificantBitMask = 1ull << (bitSize - 1);
598 bool const isNegative = rawContent & mostSignificantBitMask;
600 int64_t
const value =
601 isNegative ? (-
static_cast<int64_t
>(~rawContent & (mostSignificantBitMask - 1)) - 1) : static_cast<int64_t>(rawContent);
602 if (invokeCallback(value)) {
608 if (invokeCallback(std::bit_cast<double>(rawContent))) {
614 STORM_LOG_ASSERT(
false,
"Handling of rational values in 64 bit fast path is not implemented.");
620 invokeCallback(sv) || invokeCallback(std::string(sv))) {
626 "ValuationsStorage for variable type '" << varInfo.description.type.toString() <<
"' are not supported.");
630 switch (varInfo.description.type.type) {
633 if (invokeCallback(readInteger<false>(getRawBytes(entity), varInfo.bitOffset, bitSize) !=
Integer(0))) {
639 Integer value = varInfo.description.type.type ==
Int ? readInteger<true>(getRawBytes(entity), varInfo.bitOffset, bitSize)
640 : readInteger<false>(getRawBytes(entity), varInfo.bitOffset, bitSize);
642 if (invokeCallback(value)) {
656 STORM_LOG_ASSERT(varInfo.fits64Bit,
"Double variables with more than 64 bits are not compliant.");
659 STORM_LOG_ASSERT(bitSize % 2 == 0,
"Rational number bit size must be even.");
660 uint64_t
const b = bitSize / 2;
661 storm::RationalNumber
const numerator = readInteger<true>(getRawBytes(entity), varInfo.bitOffset, b);
662 storm::RationalNumber
const denominator = readInteger<false>(getRawBytes(entity), varInfo.bitOffset + b, b);
663 if (invokeCallback(storm::RationalNumber(numerator / denominator))) {
672 STORM_LOG_ASSERT(varInfo.fits64Bit,
"String variables with more than 64 bits are not compliant.");
676 "ValuationsStorage for variable type '" << varInfo.description.type.toString() <<
"' are not supported.");
680 "Variable " << varInfo.description.name <<
" is stored as " << varInfo.description.type.toString()
681 <<
", which cannot be read as any of the requested C++ type(s) [" << typeNames<AllowedTypes...>()
682 <<
"]. Check that you are using the accessor matching the variable's declared storage type (e.g. "
683 "getDoubleValue instead of getRationalValue for a variable added via addDoubleVariable).");
686 template<
bool InitializeWithCurrent =
false,
bool AllowOptional =
false,
typename... AllowedTypes, ValuationWriteCallback Callback>
687 void write(uint64_t entity,
VariableInformation const& varInfo, Callback
const& callback) {
688 auto invokeCallback = [
this, &entity, &varInfo, &callback]<
typename ValueType>() ->
bool {
689 bool constexpr IsAllowed = (
sizeof...(AllowedTypes) == 0) || std::disjunction_v<std::is_same<ValueType, AllowedTypes>...>;
690 if constexpr (IsAllowed) {
692 bool isOptional = varInfo.description.isOptional.value_or(
false);
693 bool initializeAsUnsetOptional =
false;
694 if constexpr (InitializeWithCurrent) {
696 read<std::nullopt_t, ValueType>(entity, varInfo, [&value, &initializeAsUnsetOptional](
auto...,
auto&& currentValue) {
697 using CurrentVT = std::remove_cvref_t<
decltype(currentValue)>;
698 if constexpr (std::is_same_v<CurrentVT, ValueType>) {
699 value = currentValue;
701 static_assert(std::is_same_v<CurrentVT, std::nullopt_t>);
702 initializeAsUnsetOptional =
true;
706 initializeAsUnsetOptional = isOptional;
707 if constexpr (std::is_same_v<ValueType, uint64_t> || std::is_same_v<ValueType, int64_t> || std::is_same_v<ValueType, Integer>) {
709 if (varInfo.description.lower && (!std::is_same_v<ValueType, uint64_t> || varInfo.description.lower.value() >= 0)) {
711 }
else if (!varInfo.description.upper || varInfo.description.upper >= 0) {
719 bool haveToWriteValue =
false;
720 bool setPresenceBit =
false;
722 if constexpr (AllowOptional) {
723 std::optional<ValueType> optionalValue = initializeAsUnsetOptional ? std::optional<ValueType>() : value;
724 callback(entity, varInfo.expressionVariable, optionalValue);
725 if (optionalValue.has_value()) {
726 value = std::move(optionalValue.value());
727 haveToWriteValue =
true;
728 setPresenceBit =
true;
730 STORM_LOG_ASSERT(varInfo.bitOffset > 0,
"Invalid variable information: optional variable must have a preceding presence bit.");
731 if (!optionalValue.has_value()) {
732 writeBit(getRawBytes(entity), varInfo.bitOffset - 1,
false);
736 "Writing to optional variable " << varInfo.description.name <<
" was not expected.");
739 callback(entity, varInfo.expressionVariable, value);
740 haveToWriteValue =
true;
742 if (haveToWriteValue) {
744 if constexpr (std::is_same_v<ValueType, uint64_t> || std::is_same_v<ValueType, int64_t> || std::is_same_v<ValueType, Integer>) {
745 if constexpr (std::is_same_v<ValueType, uint64_t> || std::is_same_v<ValueType, int64_t>) {
746 STORM_LOG_THROW(!varInfo.description.lower || std::cmp_greater_equal(value, varInfo.description.lower.value()),
747 storm::exceptions::OutOfRangeException,
748 "Value " << value <<
" is out of range for variable " << varInfo.description.name
749 <<
": value is smaller than lower bound " << varInfo.description.lower.value() <<
".");
750 STORM_LOG_THROW(!varInfo.description.upper || std::cmp_less_equal(value, varInfo.description.upper.value()),
751 storm::exceptions::OutOfRangeException,
752 "Value " << value <<
" is out of range for variable " << varInfo.description.name
753 <<
": value is greater than upper bound " << varInfo.description.upper.value() <<
".");
755 if (varInfo.description.lower) {
757 storm::exceptions::OutOfRangeException,
758 "Value " << value <<
" is out of range for variable " << varInfo.description.name
759 <<
": value is smaller than lower bound " << varInfo.description.lower.value() <<
".");
761 if (varInfo.description.upper) {
763 storm::exceptions::OutOfRangeException,
764 "Value " << value <<
" is out of range for variable " << varInfo.description.name
765 <<
": value is greater than upper bound " << varInfo.description.upper.value() <<
".");
768 if (
auto offset = varInfo.description.offset.value_or(0); offset != 0) {
769 if constexpr (std::is_same_v<ValueType, uint64_t>) {
771 "Set negative value " << value <<
"-" << offset <<
" to unsigned variable.");
777 STORM_LOG_THROW(fitsIntoStoredType(value, varInfo), storm::exceptions::OutOfRangeException,
778 "Value " << value <<
" does not fit into the " << varInfo.description.type.toString() <<
" variable "
779 << varInfo.description.name <<
".");
782 if (setPresenceBit) {
783 writeBit(getRawBytes(entity), varInfo.bitOffset - 1,
true);
785 writeValue(getRawBytes(entity), varInfo.bitOffset, varInfo.description.type.bitSize(), value);
792 switch (varInfo.description.type.type) {
794 if (invokeCallback.template
operator()<
bool>()) {
799 if (varInfo.fits64Bit) {
800 if (varInfo.description.offset.value_or(0) >= 0) {
802 if (invokeCallback.template
operator()<uint64_t>()) {
807 if (invokeCallback.template
operator()<int64_t>()) {
812 if (invokeCallback.template
operator()<
Integer>()) {
818 if ((varInfo.fits64Bit && invokeCallback.template
operator()<int64_t>()) || invokeCallback.template
operator()<
Integer>()) {
823 if (invokeCallback.template
operator()<
double>()) {
828 if (invokeCallback.template
operator()<storm::RationalNumber>()) {
833 if (invokeCallback.template
operator()<std::string>()) {
839 "ValuationsStorage for variable type '" << varInfo.description.type.toString() <<
"' are not supported.");
842 "Variable " << varInfo.description.name <<
" is stored as " << varInfo.description.type.toString()
843 <<
", which cannot be written as any of the requested C++ type(s) [" << typeNames<AllowedTypes...>()
844 <<
"]. Check that you are using the accessor matching the variable's declared storage type (e.g. "
845 "writeDoubleValue instead of writeRationalValue for a variable added via addDoubleVariable).");