Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
UmbImport.cpp
Go to the documentation of this file.
2
4
8
12
13namespace storm::umb {
14
15namespace internal {
16template<typename T>
17concept HasFileNames = requires { T::FileNames.size(); };
18
19template<typename T>
20concept FileNameMap = std::same_as<std::remove_cvref_t<typename T::key_type>, std::string>;
21
22template<typename T>
23concept IsOptional = std::same_as<std::remove_cvref_t<T>, std::optional<typename T::value_type>>;
24
25template<typename T>
27
28void parseIndexFromString(std::string const& indexFileString, storm::umb::ModelIndex& index) {
29 storm::json<storm::RationalNumber>::parse(indexFileString).get_to(index);
30}
31
36 if (!umbModel.index.annotations.has_value()) {
37 return;
38 }
39 for (auto const& [annotationType, annotationMap] : umbModel.index.annotations.value()) {
40 for (auto const& [annotationName, annotationIndex] : annotationMap) {
41 umbModel.annotations[annotationType][annotationName]; // ensure that the map keys exist
42 }
43 }
44}
45
46std::filesystem::path getFilePath(typename storm::io::ArchiveReader::ArchiveReadEntry const& src) {
47 return src.name();
48}
49
50template<typename VecT>
51 requires std::same_as<VecT, std::vector<typename VecT::value_type>>
53 return src.template toVector<typename VecT::value_type>();
54}
55
56template<typename VecT>
57 requires std::same_as<VecT, storm::storage::BitVector>
59 return src.template toVector<bool>();
60}
61
62template<typename VecT>
63void importVector(typename storm::io::ArchiveReader::ArchiveReadEntry& src, std::optional<VecT>& target) {
64 target = importVector<VecT>(src);
65}
66
67template<typename VecT>
68 requires(!IsOptional<VecT>)
70 target = importVector<VecT>(src);
71}
72
73template<typename ValueType>
75 target.template set<ValueType>(importVector<typename GenericVector::template Vec<ValueType>>(src));
76}
77
79 using enum Type;
80 switch (type.type) {
81 case Bool:
82 STORM_LOG_ASSERT(type.bitSize() == 1, "Boolean types must have size 1.");
83 importGenericVector<bool>(src, target);
84 break;
85 case Int:
86 case IntInterval:
87 STORM_LOG_ASSERT(type.bitSize() % 64 == 0, "int-based types must have size multiple of 64.");
89 break;
90 case Uint:
91 case UintInterval:
92 case Rational:
94 case String:
95 STORM_LOG_ASSERT(type.bitSize() % 64 == 0, "uint-based types must have size multiple of 64.");
97 break;
98 case Double:
99 case DoubleInterval:
100 STORM_LOG_ASSERT(type.bitSize() % 64 == 0, "Double-based types must have size 64.");
101 importGenericVector<double>(src, target);
102 break;
103 default:
104 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException,
105 "Type " << type.toString() << " for vector located in '" << getFilePath(src) << "' is not handled");
106 }
107}
108
110 // Find type information in the index that matches the given src.
111 auto srcPath = getFilePath(src);
112 std::vector<std::string> srcPathVec(srcPath.begin(), srcPath.end());
113 if (srcPath == "branch-to-probability.bin") {
114 STORM_LOG_THROW(index.transitionSystem.branchProbabilityType.has_value(), storm::exceptions::WrongFormatException,
115 "Found branch probabilities but no type specified.");
117 } else if (srcPath == "state-to-exit-rate.bin") {
118 STORM_LOG_THROW(index.transitionSystem.exitRateType.has_value(), storm::exceptions::WrongFormatException, "Found exit rates but no type specified.");
119 importGenericVector(src, index.transitionSystem.exitRateType.value(), target);
120 } else if (srcPathVec.size() == 3 && srcPathVec[0] == "observations" && srcPathVec[2] == "probabilities.bin") {
121 STORM_LOG_THROW(index.transitionSystem.observationProbabilityType.has_value(), storm::exceptions::WrongFormatException,
122 "Found observation probabilities but no type specified.");
124 } else {
125 // Reaching this point means that we must have annotation values.
126 // We expect a path of the form "annotations/<annotationType>/<annotationId>/<entity>/[values|probabilities].bin"
128 srcPathVec.size() == 5 && srcPathVec[0] == "annotations" && (srcPathVec[4] == "values.bin" || srcPathVec[4] == "probabilities.bin"),
129 storm::exceptions::WrongFormatException,
130 "Unexpected file path '" << srcPath << "'. Expected 'annotations/<annotationType>/<annotationId>/<entity>/[values|probabilities].bin'.");
131 auto annotationMap = index.annotation(srcPathVec[1]);
132 STORM_LOG_THROW(annotationMap.has_value(), storm::exceptions::WrongFormatException,
133 "Annotation type '" << srcPathVec[1] << "' referenced in files but not found in index.");
134 auto annotationIt = annotationMap->find(srcPathVec[2]);
135 STORM_LOG_THROW(annotationIt != annotationMap->end(), storm::exceptions::WrongFormatException,
136 "Annotation id '" << srcPathVec[2] << "' for type '" << srcPathVec[1] << "' referenced in files but not found in index.");
137 auto const& annotation = annotationIt->second;
138 if (srcPathVec[4] == "values.bin") {
139 importGenericVector(src, annotation.type, target);
140 } else {
142 annotation.probabilityType.has_value(), storm::exceptions::WrongFormatException,
143 "Found probabilities for annotation '" << srcPathVec[2] << "' of type '" << srcPathVec[1] << "' but no probability type specified.");
144 importGenericVector(src, annotation.probabilityType.value(), target);
145 }
146 }
147}
148
149// Forward declare function so that it can be called recursively
150template<typename UmbStructure>
151 requires HasFileNames<UmbStructure>
152bool importVector(typename storm::io::ArchiveReader::ArchiveReadEntry& src, storm::umb::ModelIndex const& index, UmbStructure& umbStructure,
153 std::filesystem::path const& context);
154
156 std::filesystem::path const& context) {
157 // Assumes that the file name maps are pre-filled (see prepareAnnotations).
158 for (auto& [key, value] : umbStructure) {
159 if (importVector(src, index, value, context / key)) {
160 return true;
161 }
162 }
163 return false;
164}
165
166template<typename UmbStructure>
167 requires HasFileNames<UmbStructure>
168bool importVector(typename storm::io::ArchiveReader::ArchiveReadEntry& src, storm::umb::ModelIndex const& index, UmbStructure& umbStructure,
169 std::filesystem::path const& context) {
170 static_assert(UmbStructure::FileNames.size() == boost::pfr::tuple_size_v<UmbStructure>, "Number of file names does not match number of fields in struct.");
171
172 // helper to check if src is in the given path
173 auto containsSrc = [&src](auto const& other) {
174 auto srcPath = getFilePath(src);
175 auto srcIt = srcPath.begin();
176 for (auto const& o : other) {
177 if (srcIt == srcPath.end() || (*srcIt != o && !o.empty())) {
178 return false;
179 }
180 ++srcIt;
181 }
182 return true;
183 };
184
185 // check if the src is in the given context
186 if (!containsSrc(context)) {
187 return false;
188 }
189 bool found = false;
190 boost::pfr::for_each_field(umbStructure, [&](auto& field, std::size_t fieldIndex) {
191 auto fieldPath = context / std::data(UmbStructure::FileNames)[fieldIndex];
192 // handle the case that we already found the subfield or that this is not the right subfield
193 if (found || !containsSrc(fieldPath)) {
194 return;
195 }
196
197 // load the file into this field, either with a recursive call or directly if the field points to a file
198 using FieldType = std::remove_cvref_t<decltype(field)>;
199 if constexpr (HasFileNames<FieldType>) {
200 found = importVector(src, index, field, fieldPath);
201 } else if constexpr (IsOptionalWithFileNames<FieldType>) {
202 if (!field.has_value()) {
203 field.emplace();
204 }
205 found = importVector(src, index, field.value(), fieldPath);
206 } else if constexpr (FileNameMap<FieldType>) {
207 found = importVector(src, index, field, fieldPath);
208 } else if constexpr (std::is_same_v<FieldType, decltype(UmbModel::nonStandardFiles)>) {
209 // The following assumes that we have tried all other fields first as it matches any file.
210 STORM_LOG_ASSERT(fieldIndex + 1 == UmbStructure::FileNames.size(), "The field for non-standard files must be the last field in the struct.");
211 found = true;
212 field.emplace(fieldPath / getFilePath(src), importVector<std::vector<char>>(src));
213 } else {
214 // reaching this point means that we have found the right field
215 STORM_LOG_THROW(fieldPath == getFilePath(src), storm::exceptions::WrongFormatException,
216 "Unexpected file paths: " << fieldPath << " != " << getFilePath(src));
217 found = true;
218 if constexpr (std::is_same_v<FieldType, GenericVector>) {
219 importGenericVector(src, index, field);
220 } else if constexpr (!std::is_same_v<FieldType, storm::umb::ModelIndex>) {
221 importVector(src, field);
222 }
223 }
224 });
225 return found;
226}
227
228storm::umb::UmbModel fromArchive(std::filesystem::path const& umbArchive, ImportOptions const& /* options */) {
229 storm::umb::UmbModel umbModel;
230 // First pass: find the index file
231 bool indexFound = false;
232 for (auto entry : storm::io::openArchive(umbArchive)) {
233 if (entry.name() == "index.json") {
234 parseIndexFromString(entry.toString(), umbModel.index);
235 indexFound = true;
236 break;
237 }
238 }
239 STORM_LOG_THROW(indexFound, storm::exceptions::FileIoException, "File 'index.json' not found in UMB archive.");
240 STORM_LOG_TRACE("Index file found in umb archive " << umbArchive << ": \n" << storm::dumpJson(storm::json<storm::RationalNumber>(umbModel.index)));
241 // Second pass: load the bin files
242 prepareAnnotations(umbModel);
243 for (auto entry : storm::io::openArchive(umbArchive)) {
244 if (entry.name() == "index.json" || entry.isDir()) {
245 continue; // skip the index file and directories
246 }
247 STORM_LOG_TRACE("Loading file " << getFilePath(entry) << " in UMB archive " << umbArchive << "'.");
248 bool const found = importVector(entry, umbModel.index, umbModel, "");
249 // At this point, we must have found a matching field, even for non-standard files.
250 STORM_LOG_THROW(found, storm::exceptions::UnexpectedException,
251 "File " << getFilePath(entry) << " in UMB archive " << umbArchive << " could not be matched to any UMB field.");
252 }
253 return umbModel;
254}
255
256} // namespace internal
257
258storm::umb::UmbModel importUmb(std::filesystem::path const& umbLocation, ImportOptions const& options) {
259 STORM_LOG_THROW(std::filesystem::exists(umbLocation), storm::exceptions::FileIoException, "The given path '" << umbLocation << "' does not exist.");
260 return internal::fromArchive(umbLocation, options);
261}
262
263} // namespace storm::umb
Object that reads the archive entry.
std::filesystem::path name() const
Get the current entry’s path (filename) inside the archive.
Represents a model in the UMB format.
Definition UmbModel.h:21
std::map< std::filesystem::path, std::vector< char > > nonStandardFiles
Definition UmbModel.h:81
std::map< std::string, Annotation > annotations
Definition UmbModel.h:67
ModelIndex index
Definition UmbModel.h:24
#define STORM_LOG_TRACE(message)
Definition logging.h:12
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
ArchiveReader openArchive(std::filesystem::path const &file)
Reads an archive file.
void prepareAnnotations(storm::umb::UmbModel &umbModel)
Prepares annotations so that all fields are available according to the index.
Definition UmbImport.cpp:35
storm::umb::UmbModel fromArchive(std::filesystem::path const &umbArchive, ImportOptions const &)
VecT importVector(typename storm::io::ArchiveReader::ArchiveReadEntry &src)
Definition UmbImport.cpp:52
void importGenericVector(typename storm::io::ArchiveReader::ArchiveReadEntry &src, GenericVector &target)
Definition UmbImport.cpp:74
void parseIndexFromString(std::string const &indexFileString, storm::umb::ModelIndex &index)
Definition UmbImport.cpp:28
std::filesystem::path getFilePath(typename storm::io::ArchiveReader::ArchiveReadEntry const &src)
Definition UmbImport.cpp:46
storm::umb::UmbModel importUmb(std::filesystem::path const &umbLocation, ImportOptions const &options)
carl::Interval< storm::RationalNumber > RationalInterval
nlohmann::basic_json< std::map, std::vector, std::string, bool, int64_t, uint64_t, ValueType > json
Definition JsonForward.h:10
std::string dumpJson(storm::json< ValueType > const &j, bool compact)
Dumps the given json object, producing a String.
std::optional< SizedType > exitRateType
Definition ModelIndex.h:58
std::optional< SizedType > branchProbabilityType
Definition ModelIndex.h:58
std::optional< SizedType > observationProbabilityType
Definition ModelIndex.h:58
struct storm::umb::ModelIndex::TransitionSystem transitionSystem
std::optional< std::map< std::string, AnnotationMap > > annotations
Definition ModelIndex.h:109
storm::OptionalRef< AnnotationMap > annotation(std::string const &annotationsType, bool createIfMissing=false)
uint64_t bitSize() const
Definition Type.cpp:87
std::string toString() const
Definition Type.cpp:91
storm::SerializedEnum< storm::umb::TypeDeclaration > type
Definition Type.h:59