Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
Validation.cpp
Go to the documentation of this file.
2
3#include <sstream>
4#include <string_view>
5
8
11
12namespace storm::umb {
13
14namespace validation {
15bool validateCsr(auto const& csr, std::string_view const name, uint64_t numMappedElements, std::optional<uint64_t> expectedlastEntry, std::ostream& err) {
16 std::stringstream err_reason;
17 if (csr) {
18 // Check if csr has expected length and the form {0, ..., expectedlastEntry}
19 if (csr->size() != numMappedElements + 1) {
20 err_reason << "CSR has unexpected size: " << csr->size() << " != " << (numMappedElements + 1) << ".";
21 }
22 if (csr.value()[0] != 0) {
23 err_reason << "CSR has unexpected first entry: " << csr.value()[0] << " != 0" << ".";
24 }
25 if (expectedlastEntry.has_value() && csr.value()[numMappedElements] != expectedlastEntry.value()) {
26 err_reason << "CSR has unexpected last entry: " << csr.value()[numMappedElements] << " != " << expectedlastEntry.value() << ".";
27 }
28 } else if (expectedlastEntry.has_value() && numMappedElements != expectedlastEntry.value()) { // we assume a 1:1 mapping
29 err_reason << "CSR is not given and the default 1:1 mapping {0, ... ," << numMappedElements << "} does not match. Expected the mapping to end with '"
30 << expectedlastEntry.value() << "'" << ".";
31 }
32 if (!err_reason.view().empty()) {
33 err << "Validation error in CSR mapping '" << name << "':\n\t" << err_reason.str() << "\n";
34 return false;
35 }
36 return true;
37}
38
39bool validateTypeDeclaration(storm::umb::SizedType const& type, bool requireStandardSize, std::ostream& err) {
40 using enum storm::umb::Type;
41 uint64_t const size = type.bitSize();
42 if (size == 0) {
43 err << "Type declaration " << type.toString() << " has size 0.\n";
44 return false;
45 }
46 uint64_t const defaultSize = defaultBitSize(type.type);
47 bool sizeError = false;
48 switch (type.type) {
49 case Double:
50 case DoubleInterval:
51 case String:
52 // types that always must be their default size
53 sizeError = size != defaultSize;
54 break;
55 case Bool:
56 case Int:
57 case Uint:
58 case IntInterval:
59 case UintInterval:
60 // types that occasionally must be their default size
61 sizeError = requireStandardSize && (size != defaultSize);
62 break;
63 // types that occasionally must be a multiple of their default size
64 case Rational:
66 // types that occasionally must be their default size
67 sizeError = requireStandardSize && ((size % defaultSize) != 0);
68 }
69 if (isIntervalType(type.type)) {
70 // interval type sizes must be multiples of four or two
71 sizeError = sizeError || (size % (type.type == RationalInterval ? 4 : 2) != 0);
72 }
73 if (sizeError) {
74 err << "Type declaration " << type.toString() << " has invalid bit size: " << size << " (default size is " << defaultSize << ").\n";
75 return false;
76 }
77 return true;
78}
79
81 if (!vector.hasValue()) {
82 return true; // no values are given so nothing wrong with the vector.
83 }
84
85 using enum storm::umb::Type;
86 switch (type.type) {
87 case Bool:
88 return vector.isType<bool>();
89 case Int:
90 case IntInterval:
91 return vector.isType<int64_t>();
92 case Uint:
93 case UintInterval:
94 return vector.isType<uint64_t>();
95 case Double:
96 return vector.isType<double>();
97 case DoubleInterval:
98 return vector.isType<double>() || vector.isType<storm::Interval>();
99 case Rational:
100 return vector.isType<storm::RationalNumber>() || vector.isType<uint64_t>(); // rationals might be encoded as uint64_t
101 case RationalInterval:
102 return vector.isType<storm::RationalInterval>() || vector.isType<uint64_t>(); // rationals might be encoded as uint64_t
103 case String:
104 return vector.isType<uint64_t>(); // strings are encoded by their indices
105 }
106 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled type.");
107}
108} // namespace validation
109
110bool validate(storm::umb::UmbModel const& umbModel, std::ostream& err) {
112 // Index
114 auto const& index = umbModel.index;
115 auto const& tsIndex = index.transitionSystem;
116 bool isValid = true;
117
118 // validate counts
119 auto checkNum = [&err](uint64_t num, auto&& name, uint64_t lowerBound = 0) {
121 err << "Number of " << name << " is not set.\n";
122 return false;
123 } else if (num < lowerBound) {
124 err << "Number of " << name << " is " << num << " which is below lower bound " << lowerBound << ".\n";
125 return false;
126 }
127 return true;
128 };
129 isValid &= checkNum(tsIndex.numPlayers, "players");
130 isValid &= checkNum(tsIndex.numStates, "states", 1u);
131 isValid &= checkNum(tsIndex.numInitialStates, "initial-states");
132 isValid &= checkNum(tsIndex.numChoices, "choices");
133 isValid &= checkNum(tsIndex.numChoiceActions, "choice-actions");
134 isValid &= checkNum(tsIndex.numBranches, "branches");
135 isValid &= checkNum(tsIndex.numBranchActions, "branch-actions");
136 isValid &= checkNum(tsIndex.numObservations, "observations");
137
138 // validate types
139 if (tsIndex.branchProbabilityType) {
140 isValid &= validation::validateTypeDeclaration(tsIndex.branchProbabilityType.value(), true, err);
141 if (!isContinuousNumericType(tsIndex.branchProbabilityType->type)) {
142 err << "Branch probability type must be a continuous numeric type.\n";
143 isValid = false;
144 }
145 }
146 if (tsIndex.exitRateType) {
147 isValid &= validation::validateTypeDeclaration(tsIndex.exitRateType.value(), true, err);
148 if (!isContinuousNumericType(tsIndex.exitRateType->type)) {
149 err << "Exit rate type must be a continuous numeric type.\n";
150 isValid = false;
151 }
152 }
153 if (tsIndex.observationProbabilityType) {
154 isValid &= validation::validateTypeDeclaration(tsIndex.observationProbabilityType.value(), true, err);
155 if (!isContinuousNumericType(tsIndex.observationProbabilityType->type)) {
156 err << "Observation probability type must be a continuous numeric type.\n";
157 isValid = false;
158 }
159 }
160
161 if (bool const hasObservations = tsIndex.numObservations > 0; hasObservations != tsIndex.observationsApplyTo.has_value()) {
162 err << "observations-apply-to is " << (tsIndex.observationsApplyTo.has_value() ? "set" : "not set") << " although the number of observations is "
163 << tsIndex.numObservations << ".\n";
164 isValid = false;
165 }
166
167 if (index.annotations) {
168 for (auto const& [annotationType, annotationMap] : index.annotations.value()) {
169 for (auto const& [name, annotation] : annotationMap) {
170 isValid &= validation::validateTypeDeclaration(annotation.type, true, err);
171 if (annotation.probabilityType) {
172 isValid &= validation::validateTypeDeclaration(annotation.probabilityType.value(), true, err);
173 if (!isContinuousNumericType(annotation.probabilityType->type)) {
174 err << "Probability type for annotation '" << name << "' must be a continuous numeric type.\n";
175 isValid = false;
176 }
177 }
178 if (annotationType == "aps") {
179 if (!isBooleanType(annotation.type.type)) {
180 err << "Atomic proposition annotation '" << name << "' must be of boolean type.\n";
181 isValid = false;
182 }
183 } else if (annotationType == "rewards") {
184 if (!isNumericType(annotation.type.type)) {
185 err << "Reward annotation '" << name << "' must have numeric type.\n";
186 isValid = false;
187 }
188 }
189 }
190 }
191 }
192
193 if (index.valuations) {
194 boost::pfr::for_each_field(index.valuations.value(), [&isValid, &err](auto const& description) {
195 if (!description.has_value()) {
196 return;
197 }
198 if (description->classes.empty()) {
199 err << "A valuation description has no classes.\n";
200 isValid = false;
201 }
202 for (auto const& descr : description->classes) {
203 for (auto const& var : descr.variables) {
204 if (std::holds_alternative<ValuationClassDescription::Variable>(var)) {
205 auto const& variable = std::get<ValuationClassDescription::Variable>(var);
206 if (variable.name.empty()) {
207 err << "A valuation description has a variable with an empty name.\n";
208 isValid = false;
209 }
210 isValid &= validation::validateTypeDeclaration(variable.type, false, err);
211 }
212 }
213 if (descr.sizeInBits() % 8 != 0) {
214 err << "A valuation description has size " << descr.sizeInBits() << " bits which is not a multiple of 8.\n";
215 isValid = false;
216 }
217 }
218 });
219 }
220
222 // Files
224
225 // Validate the expected size of TO1<..> and SEQ<..> vectors.
226 auto isExpectedBoolVectorSize = [](uint64_t const actual, uint64_t const expected) {
227 return actual == expected || actual == ((expected + 63) / 64) * 64; // size might be rounded up to the nearest multiple of 64
228 };
229 auto isExpectedTypedVectorSize = [](uint64_t const actual, storm::umb::SizedType const& type, uint64_t const expected) {
230 // Either the size matches exactly or we have a type-dependend encoding where other sizes are possible, too.
231 if (actual == expected) {
232 return true;
233 } else {
234 using enum storm::umb::Type;
235 switch (type.type) {
236 case Bool:
237 // size might be rounded up to the nearest multiple of 64
238 return actual == ((expected + 63) / 64) * 64;
239 case IntInterval:
240 case UintInterval:
241 case DoubleInterval:
242 // vector might be encoded by storing lower and upper separately
243 return actual == 2 * expected;
244 case Rational:
245 // might be encoded as uint64
246 return actual == expected * type.bitSize() / 64;
247 case RationalInterval:
248 // might be encoded as uint64
249 return actual == (expected * type.bitSize() / 64);
250 default:
251 // for all other types, the size must match exactly which we have checked above already
252 return false;
253 }
254 }
255 };
256
257 // States
258 isValid &= validation::validateCsr(umbModel.stateToChoices, "state-to-choice", tsIndex.numStates, tsIndex.numChoices, err);
259 if (umbModel.stateToPlayer.has_value()) {
260 if (tsIndex.numPlayers == 0) {
261 err << "state-to-player mapping is given but the model has no players.\n";
262 isValid = false;
263 } else if (umbModel.stateToPlayer->size() != tsIndex.numStates) {
264 err << "state-to-player mapping has invalid size: " << umbModel.stateToPlayer->size() << " != #states=" << tsIndex.numStates << ".\n";
265 isValid = false;
266 }
267 }
268 if (umbModel.stateIsInitial.has_value() && !isExpectedBoolVectorSize(umbModel.stateIsInitial->size(), tsIndex.numStates)) {
269 err << "state-is-initial has invalid size: " << umbModel.stateIsInitial->size() << " != #states=" << tsIndex.numStates << ".\n";
270 isValid = false;
271 }
272 if (umbModel.stateIsMarkovian.has_value()) {
273 if (tsIndex.time != ModelIndex::TransitionSystem::Time::UrgentStochastic) {
274 err << "state-is-markovian is given but the model does not have urgent-stochastic time.\n";
275 isValid = false;
276 } else if (!isExpectedBoolVectorSize(umbModel.stateIsMarkovian->size(), tsIndex.numStates)) {
277 err << "state-is-markovian has invalid size: " << umbModel.stateIsMarkovian->size() << " != #states=" << tsIndex.numStates << ".\n";
278 isValid = false;
279 }
280 }
281 if (umbModel.stateToExitRate.hasValue()) {
282 if (tsIndex.time == ModelIndex::TransitionSystem::Time::Discrete) {
283 err << "state-to-exit-rate mapping is given but the model has discrete time.\n";
284 isValid = false;
285 }
286 if (!tsIndex.exitRateType.has_value()) {
287 err << "state-to-exit-rate mapping is given but exit rate type is not declared.\n";
288 isValid = false;
289 } else if (!validation::vectorMatchesType(umbModel.stateToExitRate, tsIndex.exitRateType.value())) {
290 err << "state-to-exit-rate mapping has values that do not match the declared exit rate type " << tsIndex.exitRateType->toString() << ".\n";
291 isValid = false;
292 } else if (!isExpectedTypedVectorSize(umbModel.stateToExitRate.size(), tsIndex.exitRateType.value(), tsIndex.numStates)) {
293 err << "state-to-exit-rate mapping has invalid size: " << umbModel.stateToExitRate.size() << " != #states=" << tsIndex.numStates << ".\n";
294 isValid = false;
295 }
296 }
297
298 // Choices
299 isValid &= validation::validateCsr(umbModel.choiceToBranches, "choice-to-branch", tsIndex.numChoices, tsIndex.numBranches, err);
300
301 // Branches
302 if (umbModel.branchToTarget.has_value() && umbModel.branchToTarget->size() != tsIndex.numBranches) {
303 err << "branch-to-target mapping has invalid size: " << umbModel.branchToTarget->size() << " != #branches=" << tsIndex.numBranches << ".\n";
304 isValid = false;
305 }
306 if (umbModel.branchToProbability.hasValue()) {
307 if (!tsIndex.branchProbabilityType.has_value()) {
308 err << "branch-to-probability mapping is given but branch probability type is not declared.\n";
309 isValid = false;
310 } else if (!validation::vectorMatchesType(umbModel.branchToProbability, tsIndex.branchProbabilityType.value())) {
311 err << "branch-to-probability mapping has values that do not match the declared branch probability type "
312 << tsIndex.branchProbabilityType->toString() << ".\n";
313 isValid = false;
314 } else if (!isExpectedTypedVectorSize(umbModel.branchToProbability.size(), tsIndex.branchProbabilityType.value(), tsIndex.numBranches)) {
315 err << "branch-to-probability mapping has invalid size: " << umbModel.branchToProbability.size() << " != #branches=" << tsIndex.numBranches
316 << ".\n";
317 isValid = false;
318 }
319 }
320
321 // Action labels
322 auto validateActionLabels = [&isValid, &err](storm::umb::UmbModel::ActionLabels const& al, auto const& entityName, uint64_t const numEntity,
323 uint64_t const numEntityActions) {
324 if (al.values.has_value()) {
325 if (numEntityActions == 0) {
326 err << "actions/" << entityName << "/values given but the number of " << entityName << "-actions is zero.\n";
327 isValid = false;
328 } else if (al.values->size() != numEntity) {
329 err << "actions/" << entityName << "/values has invalid size: " << al.values->size() << " != #" << entityName << "=" << numEntity << ".\n";
330 isValid = false;
331 }
332 }
333 if (al.stringMapping.has_value() && numEntityActions == 0) {
334 err << "actions/" << entityName << "/string-mapping given but the number of " << entityName << "-actions is zero.\n";
335 isValid = false;
336 }
337 if (al.stringMapping.has_value() != al.strings.has_value()) {
338 err << "actions/" << entityName << "/string-mapping is " << (al.stringMapping.has_value() ? "set" : "not set") << " although actions/" << entityName
339 << "/strings is " << (al.strings.has_value() ? "set" : "not set") << ".\n";
340 isValid = false;
341 }
342 if (al.stringMapping.has_value()) {
343 isValid &=
344 validation::validateCsr(al.stringMapping, std::string("actions/") + entityName + "/string-mapping", numEntityActions, al.strings->size(), err);
345 }
346 };
347 if (umbModel.choiceActions.has_value()) {
348 validateActionLabels(umbModel.choiceActions.value(), "choices", tsIndex.numChoices, tsIndex.numChoiceActions);
349 }
350 if (umbModel.branchActions.has_value()) {
351 validateActionLabels(umbModel.branchActions.value(), "branches", tsIndex.numBranches, tsIndex.numBranchActions);
352 }
353
354 // Observations
355 auto validateObservations = [&isValid, &err, &isExpectedTypedVectorSize](storm::umb::UmbModel::Observations const& obs, auto const& entityName,
356 uint64_t const numEntity, uint64_t const numObservations,
357 std::optional<storm::umb::SizedType> const& obsProbType) {
358 if (obs.values.has_value()) {
359 if (numObservations == 0) {
360 err << "observations/" << entityName << "/values given but the number of observations is zero.\n";
361 isValid = false;
362 } else if (obs.probabilities.hasValue() || obs.values->size() != numEntity) {
363 err << "observations/" << entityName << "/values has invalid size: " << obs.values->size() << " != #" << entityName
364 << "-observation-values=" << numEntity << ".\n";
365 isValid = false;
366 }
367 isValid &= validation::validateCsr(obs.distributionMapping, std::string("observations/") + entityName + "/distribution-mapping", numEntity,
368 obs.values->size(), err);
369 if (obs.probabilities.hasValue()) {
370 if (!obsProbType.has_value()) {
371 err << "observations/" << entityName << "/probabilities given but observation probability type is not declared.\n";
372 isValid = false;
373 } else if (!validation::vectorMatchesType(obs.probabilities, obsProbType.value())) {
374 err << "observations/" << entityName << "/probabilities has values that do not match the declared observation probability type "
375 << obsProbType->toString() << ".\n";
376 isValid = false;
377 } else if (!isExpectedTypedVectorSize(obs.probabilities.size(), obsProbType.value(), numObservations)) {
378 err << "observations/" << entityName << "/probabilities has invalid size: " << obs.probabilities.size()
379 << " != #observations=" << numObservations << ".\n";
380 isValid = false;
381 }
382 }
383 }
384 };
385 if (umbModel.stateObservations.has_value()) {
386 validateObservations(umbModel.stateObservations.value(), "states", tsIndex.numStates, tsIndex.numObservations, tsIndex.observationProbabilityType);
387 }
388 if (umbModel.branchObservations.has_value()) {
389 validateObservations(umbModel.branchObservations.value(), "branches", tsIndex.numBranches, tsIndex.numObservations, tsIndex.observationProbabilityType);
390 }
391
392 // Annotations
393 auto validateAnnotationValues = [&isValid, &err, &isExpectedTypedVectorSize](storm::umb::UmbModel::AnnotationValues const& av, auto const& group,
394 auto const& id, auto const& entityName, uint64_t const numEntity,
396 auto const context = std::string("annotations/") + group + "/" + id + "/" + entityName;
397 uint64_t const numAnnotationValues = ai.numProbabilities.value_or(numEntity);
398 if (av.values.hasValue()) {
399 if (!validation::vectorMatchesType(av.values, ai.type)) {
400 err << context << "/values has values that do not match the declared annotation type " << ai.type.toString() << ".\n";
401 isValid = false;
402 } else if (!isExpectedTypedVectorSize(av.values.size(), ai.type, numAnnotationValues)) {
403 err << context << "/values has invalid size: " << av.values.size() << " != #" << entityName << "-annotation-values=" << numAnnotationValues;
404 isValid = false;
405 }
406 }
407 if (isStringType(ai.type.type) != av.stringMapping.has_value()) {
408 err << context << "/string-mapping is " << (av.stringMapping.has_value() ? "set" : "not set") << " although the annotation type is "
409 << ai.type.toString() << ".\n";
410 isValid = false;
411 }
412 if (av.stringMapping.has_value() && ai.numStrings.value_or(0) == 0) {
413 err << context << "/string-mapping given but the number of strings is zero.\n";
414 isValid = false;
415 }
416 if (av.stringMapping.has_value() != av.strings.has_value()) {
417 err << context << "/string-mapping is " << (av.stringMapping.has_value() ? "set" : "not set") << " although " << context << "/strings is "
418 << (av.strings.has_value() ? "set" : "not set") << ".\n";
419 isValid = false;
420 }
421 if (av.stringMapping.has_value()) {
422 isValid &= validation::validateCsr(av.stringMapping, context + "/string-mapping", ai.numStrings.value(), av.strings->size(), err);
423 }
424 isValid &= validation::validateCsr(av.distributionMapping, context + "/distribution-mapping", numEntity, numAnnotationValues, err);
425 if (av.probabilities.hasValue()) {
426 if (!ai.probabilityType.has_value()) {
427 err << context << "/probabilities given but annotation probability type is not declared.\n";
428 isValid = false;
429 } else if (!validation::vectorMatchesType(av.probabilities, ai.probabilityType.value())) {
430 err << context << "/probabilities has values that do not match the declared annotation probability type " << ai.probabilityType->toString()
431 << ".\n";
432 isValid = false;
433 } else if (!isExpectedTypedVectorSize(av.probabilities.size(), ai.probabilityType.value(), numAnnotationValues)) {
434 err << context << "/probabilities has invalid size: " << av.probabilities.size() << " != #" << entityName
435 << "-annotation-values=" << numAnnotationValues << ".\n";
436 isValid = false;
437 }
438 }
439 };
440 for (auto const& [annotationType, annotationMap] : umbModel.annotations) {
441 if (!umbModel.index.annotations.has_value() || !umbModel.index.annotations->contains(annotationType)) {
442 err << "Annotation '" << annotationType << "' is given but not declared in the index.\n";
443 isValid = false;
444 continue;
445 }
446 for (auto const& [annotationId, annotationValues] : annotationMap) {
447 if (!umbModel.index.annotations->at(annotationType).contains(annotationId)) {
448 err << "Annotation '" << annotationId << "' of type '" << annotationType << "' is given but not declared in the index.\n";
449 isValid = false;
450 continue;
451 }
452 auto const& annotationIndex = index.annotations->at(annotationType).at(annotationId);
453 if (annotationValues.states.has_value()) {
454 if (!annotationIndex.appliesToStates()) {
455 err << "Annotation '" << annotationId << "' of type '" << annotationType
456 << "' has states values but does not apply to states according to the index.\n";
457 isValid = false;
458 }
459 validateAnnotationValues(annotationValues.states.value(), annotationType, annotationId, "states", tsIndex.numStates, annotationIndex);
460 }
461 if (annotationValues.choices.has_value()) {
462 if (!annotationIndex.appliesToChoices()) {
463 err << "Annotation '" << annotationId << "' of type '" << annotationType
464 << "' has choices values but does not apply to choices according to the index.\n";
465 isValid = false;
466 }
467 validateAnnotationValues(annotationValues.choices.value(), annotationType, annotationId, "choices", tsIndex.numChoices, annotationIndex);
468 }
469 if (annotationValues.branches.has_value()) {
470 if (!annotationIndex.appliesToBranches()) {
471 err << "Annotation '" << annotationId << "' of type '" << annotationType
472 << "' has branches values but does not apply to branches according to the index.\n";
473 isValid = false;
474 }
475 validateAnnotationValues(annotationValues.branches.value(), annotationType, annotationId, "branches", tsIndex.numBranches, annotationIndex);
476 }
477 if (annotationValues.observations.has_value()) {
478 if (!annotationIndex.appliesToObservations()) {
479 err << "Annotation '" << annotationId << "' of type '" << annotationType
480 << "' has observations values but does not apply to observations according to the index.\n";
481 isValid = false;
482 }
483 validateAnnotationValues(annotationValues.observations.value(), annotationType, annotationId, "observations", tsIndex.numObservations,
484 annotationIndex);
485 }
486 if (annotationValues.players.has_value()) {
487 if (!annotationIndex.appliesToPlayers()) {
488 err << "Annotation '" << annotationId << "' of type '" << annotationType
489 << "' has players values but does not apply to players according to the index.\n";
490 isValid = false;
491 }
492 validateAnnotationValues(annotationValues.players.value(), annotationType, annotationId, "players", tsIndex.numPlayers, annotationIndex);
493 }
494 }
495 }
496
497 // Valuations
498 auto validateValuation = [&isValid, &err](storm::umb::UmbModel::Valuation const& v, auto const& entityName, uint64_t const numEntity,
500 auto const context = std::string("valuations/") + entityName;
501 if (v.valuationToClass.has_value() && v.valuationToClass->size() != numEntity) {
502 err << context << "/valuation-to-class has invalid size: " << v.valuationToClass->size() << " != #" << entityName << "=" << numEntity << ".\n";
503 isValid = false;
504 }
505 if ((!v.valuationToClass.has_value() && !descr.classes.empty()) || descr.classes.size() == 1) {
506 // common case: all entities have the same valuation class
507 auto const& classDescr = descr.classes.front();
508 if (v.valuations.has_value() && v.valuations->size() * 8 < classDescr.sizeInBits() * numEntity) {
509 err << context << "/valuations has invalid size: " << v.valuations->size() << " != size of one valuation class (" << classDescr.sizeInBits()
510 << " bits) * 8 * #entities=" << (classDescr.sizeInBits() * 8 * numEntity) << ".\n";
511 isValid = false;
512 }
513 }
514 if (v.stringMapping.has_value() && descr.numStrings.value_or(0) == 0) {
515 err << context << "/string-mapping given but the number of strings is zero.\n";
516 isValid = false;
517 }
518 if (v.stringMapping.has_value() != v.strings.has_value()) {
519 err << context << "/string-mapping is " << (v.stringMapping.has_value() ? "set" : "not set") << " although " << context << "/strings is "
520 << (v.strings.has_value() ? "set" : "not set") << ".\n";
521 isValid = false;
522 }
523 if (v.stringMapping.has_value()) {
524 isValid &= validation::validateCsr(v.stringMapping, context + "/string-mapping", descr.numStrings.value(), v.strings->size(), err);
525 }
526 };
527 if (umbModel.valuations.states.has_value()) {
528 if (!umbModel.index.valuations.has_value() || !umbModel.index.valuations->states.has_value()) {
529 err << "State valuations are given but no valuation descriptions are declared in the index.\n";
530 isValid = false;
531 } else {
532 validateValuation(umbModel.valuations.states.value(), "states", tsIndex.numStates, umbModel.index.valuations->states.value());
533 }
534 }
535 if (umbModel.valuations.choices.has_value()) {
536 if (!umbModel.index.valuations.has_value() || !umbModel.index.valuations->choices.has_value()) {
537 err << "Choice valuations are given but no valuation descriptions are declared in the index.\n";
538 isValid = false;
539 } else {
540 validateValuation(umbModel.valuations.choices.value(), "choices", tsIndex.numChoices, umbModel.index.valuations->choices.value());
541 }
542 }
543 if (umbModel.valuations.branches.has_value()) {
544 if (!umbModel.index.valuations.has_value() || !umbModel.index.valuations->branches.has_value()) {
545 err << "Branch valuations are given but no valuation descriptions are declared in the index.\n";
546 isValid = false;
547 } else {
548 validateValuation(umbModel.valuations.branches.value(), "branches", tsIndex.numBranches, umbModel.index.valuations->branches.value());
549 }
550 }
551 if (umbModel.valuations.observations.has_value()) {
552 if (!umbModel.index.valuations.has_value() || !umbModel.index.valuations->observations.has_value()) {
553 err << "Observation valuations are given but no valuation descriptions are declared in the index.\n";
554 isValid = false;
555 } else {
556 validateValuation(umbModel.valuations.observations.value(), "observations", tsIndex.numObservations,
557 umbModel.index.valuations->observations.value());
558 }
559 }
560 if (umbModel.valuations.players.has_value()) {
561 if (!umbModel.index.valuations.has_value() || !umbModel.index.valuations->players.has_value()) {
562 err << "Player valuations are given but no valuation descriptions are declared in the index.\n";
563 isValid = false;
564 } else {
565 validateValuation(umbModel.valuations.players.value(), "players", tsIndex.numPlayers, umbModel.index.valuations->players.value());
566 }
567 }
568
569 return isValid;
570}
571
573 std::stringstream errors;
574 if (!validate(umbModel, errors)) {
575 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException,
576 "UMB model " << umbModel.getShortModelInformation() << " is invalid:\n"
577 << errors.str());
578 }
579}
580
581} // namespace storm::umb
Represents a model in the UMB format.
Definition UmbModel.h:21
std::string getShortModelInformation() const
Retrieves a short string that can be used to refer to the model in user output.
Definition UmbModel.cpp:11
ModelIndex index
Definition UmbModel.h:24
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
bool validateCsr(auto const &csr, std::string_view const name, uint64_t numMappedElements, std::optional< uint64_t > expectedlastEntry, std::ostream &err)
bool validateTypeDeclaration(storm::umb::SizedType const &type, bool requireStandardSize, std::ostream &err)
bool vectorMatchesType(storm::umb::GenericVector const &vector, storm::umb::SizedType const &type)
bool isIntervalType(Type const type)
Definition Type.cpp:42
bool isNumericType(Type const type)
Definition Type.cpp:38
bool isBooleanType(Type const type)
Definition Type.cpp:8
uint64_t defaultBitSize(Type const type)
Returns the default size (in bits) of a type, if available.
Definition Type.cpp:59
bool isStringType(Type const type)
Definition Type.cpp:55
bool isContinuousNumericType(Type const type)
Definition Type.cpp:25
bool validate(storm::umb::UmbModel const &umbModel, std::ostream &err)
Validates the given UMB model and writes potential errors to the given output stream.
void validateOrThrow(storm::umb::UmbModel const &umbModel)
Validates the given UMB model.
carl::Interval< storm::RationalNumber > RationalInterval
carl::Interval< double > Interval
Interval type.
struct storm::umb::ModelIndex::TransitionSystem transitionSystem
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