Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
VariableInformation.cpp
Go to the documentation of this file.
2
5
11
16
17#include <cmath>
18
19namespace storm {
20namespace generator {
21
22BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, uint_fast64_t bitOffset, bool global, bool observable)
23 : variable(variable), bitOffset(bitOffset), global(global), observable(observable) {
24 // Intentionally left empty.
25}
26
27IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t lowerBound, int_fast64_t upperBound,
28 uint_fast64_t bitOffset, uint_fast64_t bitWidth, bool global, bool observable,
29 bool forceOutOfBoundsCheck)
30 : variable(variable),
31 lowerBound(lowerBound),
32 upperBound(upperBound),
33 bitOffset(bitOffset),
34 bitWidth(bitWidth),
35 global(global),
36 observable(observable),
37 forceOutOfBoundsCheck(forceOutOfBoundsCheck) {
38 // Intentionally left empty.
39}
40
41LocationVariableInformation::LocationVariableInformation(storm::expressions::Variable const& variable, uint64_t highestValue, uint_fast64_t bitOffset,
42 uint_fast64_t bitWidth, bool observable)
43 : variable(variable), highestValue(highestValue), bitOffset(bitOffset), bitWidth(bitWidth), observable(observable) {
44 // Intentionally left empty.
45}
46
47ObservationLabelInformation::ObservationLabelInformation(const std::string& name) : name(name) {
48 // Intentionally left empty.
49}
50
63uint64_t getBitWidthLowerUpperBound(bool const& hasLowerBound, int64_t& lowerBound, bool const& hasUpperBound, int64_t& upperBound,
64 uint64_t const& reservedBitsForUnboundedVariables) {
65 if (hasLowerBound) {
66 if (hasUpperBound) {
67 STORM_LOG_THROW(lowerBound <= upperBound, storm::exceptions::WrongFormatException, "Lower bound must not be above upper bound");
68 // We do not have to set any bounds in this case.
69 // Return the number of bits required to store all the values between lower and upper bound
70 return static_cast<uint64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
71 } else {
72 // We only have a lower bound. Find the largest upper bound we can store with the given number of bits.
73 upperBound = lowerBound + ((1ll << reservedBitsForUnboundedVariables) - 1);
74 }
75 } else {
76 if (hasUpperBound) {
77 // We only have an upper bound. Find the smallest lower bound we can store with the given number of bits
78 lowerBound = upperBound - ((1ll << reservedBitsForUnboundedVariables) - 1);
79 } else {
80 // We neither have a lower nor an upper bound. Take the usual n-bit integer values for lower/upper bounds
81 lowerBound = -(1ll << (reservedBitsForUnboundedVariables - 1)); // = -2^(reservedBits-1)
82 upperBound = (1ll << (reservedBitsForUnboundedVariables - 1)) - 1; // = 2^(reservedBits-1) - 1
83 }
84 }
85 // If we reach this point, it means that the variable is unbounded.
86 // Lets check for potential overflows.
87 STORM_LOG_THROW(lowerBound <= upperBound, storm::exceptions::WrongFormatException,
88 "Lower bound must not be above upper bound. Has there been an integer over-/underflow?");
89 // By choice of the lower/upper bound, the number of reserved bits must coincide with the bitwidth
90 STORM_LOG_ASSERT(reservedBitsForUnboundedVariables == static_cast<uint64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))),
91 "Unexpected bitwidth for unbounded variable.");
92 return reservedBitsForUnboundedVariables;
93}
94
95VariableInformation::VariableInformation(storm::prism::Program const& program, uint64_t reservedBitsForUnboundedVariables, bool outOfBoundsState)
96 : totalBitOffset(0) {
97 if (outOfBoundsState) {
98 outOfBoundsBit = 0;
100 } else {
101 outOfBoundsBit = boost::none;
102 }
103
104 for (auto const& booleanVariable : program.getGlobalBooleanVariables()) {
105 booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), totalBitOffset, true, booleanVariable.isObservable());
107 }
108 for (auto const& integerVariable : program.getGlobalIntegerVariables()) {
109 int64_t lowerBound, upperBound;
110 if (integerVariable.hasLowerBoundExpression()) {
111 lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt();
112 }
113 if (integerVariable.hasUpperBoundExpression()) {
114 upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt();
115 }
116 uint64_t bitwidth = getBitWidthLowerUpperBound(integerVariable.hasLowerBoundExpression(), lowerBound, integerVariable.hasUpperBoundExpression(),
117 upperBound, reservedBitsForUnboundedVariables);
118 integerVariables.emplace_back(integerVariable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, true,
119 integerVariable.isObservable(), !integerVariable.hasLowerBoundExpression() || !integerVariable.hasUpperBoundExpression());
120 totalBitOffset += bitwidth;
121 }
122 for (auto const& module : program.getModules()) {
123 for (auto const& booleanVariable : module.getBooleanVariables()) {
124 booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), totalBitOffset, false, booleanVariable.isObservable());
126 }
127 for (auto const& integerVariable : module.getIntegerVariables()) {
128 int64_t lowerBound, upperBound;
129 if (integerVariable.hasLowerBoundExpression()) {
130 lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt();
131 }
132 if (integerVariable.hasUpperBoundExpression()) {
133 upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt();
134 }
135 uint64_t bitwidth = getBitWidthLowerUpperBound(integerVariable.hasLowerBoundExpression(), lowerBound, integerVariable.hasUpperBoundExpression(),
136 upperBound, reservedBitsForUnboundedVariables);
137 integerVariables.emplace_back(integerVariable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, false,
138 integerVariable.isObservable(),
139 !integerVariable.hasLowerBoundExpression() || !integerVariable.hasUpperBoundExpression());
140 totalBitOffset += bitwidth;
141 }
142 }
143 for (auto const& oblab : program.getObservationLabels()) {
144 observationLabels.emplace_back(oblab.getName());
145 }
146
147 sortVariables();
148}
149
150VariableInformation::VariableInformation(storm::jani::Model const& model,
151 std::vector<std::reference_wrapper<storm::jani::Automaton const>> const& parallelAutomata,
152 uint64_t reservedBitsForUnboundedVariables, bool outOfBoundsState)
153 : totalBitOffset(0) {
154 // Check that the model does not contain non-transient real variables.
155 STORM_LOG_THROW(!model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException,
156 "Cannot build model from JANI model that contains global non-transient real variables.");
157 for (auto const& automaton : model.getAutomata()) {
158 STORM_LOG_THROW(!automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException,
159 "Cannot build model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() << "'.");
160 }
161
162 if (outOfBoundsState) {
163 outOfBoundsBit = 0;
165 } else {
166 outOfBoundsBit = boost::none;
167 }
168
169 createVariablesForVariableSet(model.getGlobalVariables(), reservedBitsForUnboundedVariables, true);
170
171 for (auto const& automatonRef : parallelAutomata) {
172 createVariablesForAutomaton(automatonRef.get(), reservedBitsForUnboundedVariables);
173 }
174
175 sortVariables();
176}
177
180 // Find for each replaced array variable the corresponding references in this variable information
181 for (auto const& arrayVariable : arrayEliminatorData.eliminatedArrayVariables) {
182 if (!arrayVariable->isTransient()) {
183 auto findRes = arrayEliminatorData.replacements.find(arrayVariable->getExpressionVariable());
184 STORM_LOG_ASSERT(findRes != arrayEliminatorData.replacements.end(), "No replacement for array variable.");
185 auto const& replacements = findRes->second;
186 auto const& innerType = arrayVariable->getType().asArrayType().getBaseTypeRecursive();
187 if (innerType.isBasicType() && innerType.asBasicType().isBooleanType()) {
188 auto replInfo = convertArrayReplacement(replacements, booleanVariables);
189 this->arrayVariableToElementInformations.emplace(arrayVariable->getExpressionVariable(), std::move(replInfo));
190 } else if ((innerType.isBasicType() && innerType.asBasicType().isIntegerType()) ||
191 (innerType.isBoundedType() && innerType.asBoundedType().isIntegerType())) {
192 auto replInfo = convertArrayReplacement(replacements, integerVariables);
193 this->arrayVariableToElementInformations.emplace(arrayVariable->getExpressionVariable(), std::move(replInfo));
194 } else {
195 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled type of base variable.");
196 }
197 }
198 }
199}
200
202 std::vector<uint64_t> const& arrayIndexVector) const {
203 return booleanVariables[arrayVariableToElementInformations.at(arrayVariable).getVariableInformationIndex(arrayIndexVector)];
204}
205
207 std::vector<uint64_t> const& arrayIndexVector) const {
208 return integerVariables[arrayVariableToElementInformations.at(arrayVariable).getVariableInformationIndex(arrayIndexVector)];
209}
210
211void VariableInformation::createVariablesForAutomaton(storm::jani::Automaton const& automaton, uint64_t reservedBitsForUnboundedVariables) {
212 uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(automaton.getNumberOfLocations())));
213 locationVariables.emplace_back(automaton.getLocationExpressionVariable(), automaton.getNumberOfLocations() - 1, totalBitOffset, bitwidth, true);
214 totalBitOffset += bitwidth;
215
216 createVariablesForVariableSet(automaton.getVariables(), reservedBitsForUnboundedVariables, false);
217}
218
219void VariableInformation::createVariablesForVariableSet(storm::jani::VariableSet const& variableSet, uint64_t reservedBitsForUnboundedVariables, bool global) {
220 for (auto const& variable : variableSet.getBooleanVariables()) {
221 if (!variable.isTransient()) {
222 booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset, global, true);
224 }
225 }
226 for (auto const& variable : variableSet.getBoundedIntegerVariables()) {
227 if (!variable.isTransient()) {
228 int64_t lowerBound, upperBound;
229 auto const& type = variable.getType().asBoundedType();
230 STORM_LOG_ASSERT(type.hasLowerBound() || type.hasUpperBound(), "Bounded integer variable has neither a lower nor an upper bound.");
231 if (type.hasLowerBound()) {
232 lowerBound = type.getLowerBound().evaluateAsInt();
233 }
234 if (type.hasUpperBound()) {
235 upperBound = type.getUpperBound().evaluateAsInt();
236 }
237 uint64_t bitwidth =
238 getBitWidthLowerUpperBound(type.hasLowerBound(), lowerBound, type.hasUpperBound(), upperBound, reservedBitsForUnboundedVariables);
239 integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, global, true,
240 !type.hasLowerBound() || !type.hasUpperBound());
241 totalBitOffset += bitwidth;
242 }
243 }
244 for (auto const& variable : variableSet.getUnboundedIntegerVariables()) {
245 if (!variable.isTransient()) {
246 int64_t lowerBound, upperBound;
247 uint64_t bitwidth = getBitWidthLowerUpperBound(false, lowerBound, false, upperBound, reservedBitsForUnboundedVariables);
248 integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, global, true, true);
249 totalBitOffset += reservedBitsForUnboundedVariables;
250 }
251 }
252}
253
254uint_fast64_t VariableInformation::getTotalBitOffset(bool roundTo64Bit) const {
255 uint_fast64_t result = totalBitOffset;
256 if (roundTo64Bit & ((result & ((1ull << 6) - 1)) != 0)) {
257 result = ((result >> 6) + 1) << 6;
258 }
259 return result;
260}
261
263 return outOfBoundsBit != boost::none;
264}
265
267 assert(hasOutOfBoundsBit());
268 return outOfBoundsBit.get();
269}
270
271void VariableInformation::sortVariables() {
272 // Sort the variables so we can make some assumptions when iterating over them (in the next-state generators).
273 std::sort(booleanVariables.begin(), booleanVariables.end(),
274 [](BooleanVariableInformation const& a, BooleanVariableInformation const& b) { return a.variable < b.variable; });
275 std::sort(integerVariables.begin(), integerVariables.end(),
276 [](IntegerVariableInformation const& a, IntegerVariableInformation const& b) { return a.variable < b.variable; });
277}
278} // namespace generator
279} // namespace storm
VariableSet & getVariables()
Retrieves the variables of this automaton.
Definition Automaton.cpp:59
storm::expressions::Variable const & getLocationExpressionVariable() const
Retrieves the expression variable that represents the location of this automaton.
uint64_t getNumberOfLocations() const
Retrieves the number of locations.
VariableSet & getGlobalVariables()
Retrieves the variables of this automaton.
Definition Model.cpp:721
std::vector< Automaton > & getAutomata()
Retrieves the automata of the model.
Definition Model.cpp:872
bool containsNonTransientRealVariables() const
Retrieves whether the set of variables contains a non-transient real variable.
std::vector< BooleanVariable > const & getGlobalBooleanVariables() const
Retrieves the global boolean variables of the program.
Definition Program.cpp:482
std::vector< Module > const & getModules() const
Retrieves all modules of the program.
Definition Program.cpp:629
std::vector< IntegerVariable > const & getGlobalIntegerVariables() const
Retrieves the global integer variables of the program.
Definition Program.cpp:486
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
uint64_t getBitWidthLowerUpperBound(bool const &hasLowerBound, int64_t &lowerBound, bool const &hasUpperBound, int64_t &upperBound, uint64_t const &reservedBitsForUnboundedVariables)
Small helper function that sets unspecified lower/upper bounds for an integer variable based on the p...
ArrayVariableReplacementInformation convertArrayReplacement(typename storm::jani::ArrayEliminatorData::Replacement const &replacement, InfoType const &relevantVariableInfo)
LabParser.cpp.
Definition cli.cpp:18
BooleanVariableInformation(storm::expressions::Variable const &variable, uint_fast64_t bitOffset, bool global, bool observable)
IntegerVariableInformation(storm::expressions::Variable const &variable, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth, bool global=false, bool observable=true, bool forceOutOfBoundsCheck=false)
LocationVariableInformation(storm::expressions::Variable const &variable, uint64_t highestValue, uint_fast64_t bitOffset, uint_fast64_t bitWidth, bool observable)
uint_fast64_t getTotalBitOffset(bool roundTo64Bit=false) const
std::unordered_map< storm::expressions::Variable, ArrayVariableReplacementInformation > arrayVariableToElementInformations
Replacements for each array variable.
uint_fast64_t totalBitOffset
The total bit offset over all variables.
void registerArrayVariableReplacements(storm::jani::ArrayEliminatorData const &arrayEliminatorData)
std::vector< IntegerVariableInformation > integerVariables
The integer variables.
BooleanVariableInformation const & getBooleanArrayVariableReplacement(storm::expressions::Variable const &arrayVariable, std::vector< uint64_t > const &arrayIndexVector) const
std::vector< LocationVariableInformation > locationVariables
The location variables.
IntegerVariableInformation const & getIntegerArrayVariableReplacement(storm::expressions::Variable const &arrayVariable, std::vector< uint64_t > const &arrayIndexVector) const
std::vector< BooleanVariableInformation > booleanVariables
The boolean variables.
std::unordered_map< storm::expressions::Variable, Replacement > replacements
std::vector< std::shared_ptr< Variable > > eliminatedArrayVariables