Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
ParameterLifter.cpp
Go to the documentation of this file.
2
7
8namespace storm {
9namespace transformer {
10
11template<typename ParametricType, typename ConstantType>
13 std::vector<ParametricType> const& pVector, storm::storage::BitVector const& selectedRows,
14 storm::storage::BitVector const& selectedColumns, bool generateRowLabels,
15 bool useMonotonicityInFuture) {
16 // get a mapping from old column indices to new ones
17 oldToNewColumnIndexMapping = std::vector<uint_fast64_t>(selectedColumns.size(), selectedColumns.size());
18 uint_fast64_t newIndex = 0;
19 for (auto const& oldColumn : selectedColumns) {
20 oldToNewColumnIndexMapping[oldColumn] = newIndex++;
21 }
22
23 // create vector, such that the occuringVariables for all states can be stored
24 occurringVariablesAtState = std::vector<std::set<VariableType>>(pMatrix.getColumnCount());
25
26 // Stores which entries of the original matrix/vector are non-constant. Entries for non-selected rows/columns are omitted
27 auto nonConstMatrixEntries = storm::storage::BitVector(pMatrix.getEntryCount(), false); // this vector has to be resized later
28 auto nonConstVectorEntries = storm::storage::BitVector(selectedRows.getNumberOfSetBits(), false);
29 // Counters for selected entries in the pMatrix and the pVector
30 uint_fast64_t pMatrixEntryCount = 0;
31 uint_fast64_t pVectorEntryCount = 0;
32
33 // The matrix builder for the new matrix. The correct number of rows and entries is not known yet.
34 storm::storage::SparseMatrixBuilder<ConstantType> builder(0, selectedColumns.getNumberOfSetBits(), 0, true, true, selectedRows.getNumberOfSetBits());
35 rowGroupToStateNumber = std::vector<uint_fast64_t>();
36 uint_fast64_t newRowIndex = 0;
37 for (auto const& rowIndex : selectedRows) {
38 builder.newRowGroup(newRowIndex);
39 rowGroupToStateNumber.push_back(rowIndex);
40
41 // Gather the occurring variables within this row and set which entries are non-constant
42 std::set<VariableType> occurringVariables;
43 for (auto const& entry : pMatrix.getRow(rowIndex)) {
44 if (selectedColumns.get(entry.getColumn())) {
45 if (!storm::utility::isConstant(entry.getValue())) {
46 storm::utility::parametric::gatherOccurringVariables(entry.getValue(), occurringVariables);
47 nonConstMatrixEntries.set(pMatrixEntryCount, true);
48 }
49 ++pMatrixEntryCount;
50 } else {
51 if (!storm::utility::isConstant(entry.getValue())) {
52 storm::utility::parametric::gatherOccurringVariables(entry.getValue(), occurringVariables);
53 }
54 }
55 }
56
57 ParametricType const& pVectorEntry = pVector[rowIndex];
58 std::set<VariableType> vectorEntryVariables;
59 if (!storm::utility::isConstant(pVectorEntry)) {
60 storm::utility::parametric::gatherOccurringVariables(pVectorEntry, vectorEntryVariables);
61 if (generateRowLabels) {
62 // If row labels are to be generated, we do not allow unspecified valuations.
63 // Therefore, we also 'lift' parameters that only occurr on a vector.
64 occurringVariables.insert(vectorEntryVariables.begin(), vectorEntryVariables.end());
65 }
66 nonConstVectorEntries.set(pVectorEntryCount, true);
67 }
68 ++pVectorEntryCount;
69 // Compute the (abstract) valuation for each row
70 auto rowValuations = getVerticesOfAbstractRegion(occurringVariables);
71 for (auto const& val : rowValuations) {
72 if (generateRowLabels) {
73 rowLabels.push_back(val);
74 }
75
76 // Insert matrix entries for each valuation. For non-constant entries, a dummy value is inserted and the function and the valuation are collected.
77 // The placeholder for the collected function/valuation are stored in the matrixAssignment. The matrixAssignment is completed after the matrix is
78 // finished
79 for (auto const& entry : pMatrix.getRow(rowIndex)) {
80 if (selectedColumns.get(entry.getColumn())) {
81 if (storm::utility::isConstant(entry.getValue())) {
82 builder.addNextValue(newRowIndex, oldToNewColumnIndexMapping[entry.getColumn()],
83 storm::utility::convertNumber<ConstantType>(entry.getValue()));
84 } else {
85 builder.addNextValue(newRowIndex, oldToNewColumnIndexMapping[entry.getColumn()], storm::utility::one<ConstantType>());
86 ConstantType& placeholder = functionValuationCollector.add(entry.getValue(), val);
87 matrixAssignment.push_back(std::pair<typename storm::storage::SparseMatrix<ConstantType>::iterator, ConstantType&>(
89 }
90 }
91 }
92
93 // Insert the vector entry for this row
94 if (storm::utility::isConstant(pVectorEntry)) {
95 vector.push_back(storm::utility::convertNumber<ConstantType>(pVectorEntry));
96 } else {
97 vector.push_back(storm::utility::one<ConstantType>());
98 AbstractValuation vectorVal(val);
99 for (auto const& vectorVar : vectorEntryVariables) {
100 if (occurringVariables.find(vectorVar) == occurringVariables.end()) {
101 assert(!generateRowLabels);
102 vectorVal.addParameterUnspecified(vectorVar);
103 }
104 }
105 ConstantType& placeholder = functionValuationCollector.add(pVectorEntry, vectorVal);
106 vectorAssignment.push_back(
107 std::pair<typename std::vector<ConstantType>::iterator, ConstantType&>(typename std::vector<ConstantType>::iterator(), placeholder));
108 }
109
110 ++newRowIndex;
111 }
112 if (useMonotonicityInFuture) {
113 // Save the occuringVariables of a state, needed if we want to use monotonicity
114 for (auto& var : occurringVariables) {
115 occuringStatesAtVariable[var].insert(rowIndex);
116 }
117 occurringVariablesAtState[rowIndex] = std::move(occurringVariables);
118 }
119 }
120
121 // Matrix and vector are now filled with constant results from constant functions and place holders for non-constant functions.
122 matrix = builder.build(newRowIndex);
123 vector.shrink_to_fit();
124 matrixAssignment.shrink_to_fit();
125 vectorAssignment.shrink_to_fit();
126 nonConstMatrixEntries.resize(pMatrixEntryCount);
127
128 // Now insert the correct iterators for the matrix and vector assignment
129 auto matrixAssignmentIt = matrixAssignment.begin();
130 uint_fast64_t startEntryOfRow = 0;
131 for (uint_fast64_t group = 0; group < matrix.getRowGroupCount(); ++group) {
132 uint_fast64_t startEntryOfNextRow = startEntryOfRow + matrix.getRow(group, 0).getNumberOfEntries();
133 for (uint_fast64_t matrixRow = matrix.getRowGroupIndices()[group]; matrixRow < matrix.getRowGroupIndices()[group + 1]; ++matrixRow) {
134 auto matrixEntryIt = matrix.getRow(matrixRow).begin();
135 for (uint_fast64_t nonConstEntryIndex = nonConstMatrixEntries.getNextSetIndex(startEntryOfRow); nonConstEntryIndex < startEntryOfNextRow;
136 nonConstEntryIndex = nonConstMatrixEntries.getNextSetIndex(nonConstEntryIndex + 1)) {
137 matrixAssignmentIt->first = matrixEntryIt + (nonConstEntryIndex - startEntryOfRow);
138 ++matrixAssignmentIt;
139 }
140 }
141 startEntryOfRow = startEntryOfNextRow;
142 }
143 STORM_LOG_ASSERT(matrixAssignmentIt == matrixAssignment.end(), "Unexpected number of entries in the matrix assignment.");
144
145 auto vectorAssignmentIt = vectorAssignment.begin();
146 for (auto const& nonConstVectorEntry : nonConstVectorEntries) {
147 for (uint_fast64_t vectorIndex = matrix.getRowGroupIndices()[nonConstVectorEntry]; vectorIndex != matrix.getRowGroupIndices()[nonConstVectorEntry + 1];
148 ++vectorIndex) {
149 vectorAssignmentIt->first = vector.begin() + vectorIndex;
150 ++vectorAssignmentIt;
151 }
152 }
153 STORM_LOG_ASSERT(vectorAssignmentIt == vectorAssignment.end(), "Unexpected number of entries in the vector assignment.");
154}
155
156template<typename ParametricType, typename ConstantType>
158 storm::solver::OptimizationDirection const& dirForParameters) {
159 // write the evaluation result of each function,evaluation pair into the placeholders
160 functionValuationCollector.evaluateCollectedFunctions(region, dirForParameters);
161
162 // apply the matrix and vector assignments to write the contents of the placeholder into the matrix/vector
163 for (auto& assignment : matrixAssignment) {
165 !storm::utility::isZero(assignment.second),
166 "Parameter lifting on region "
167 << region.toString()
168 << " affects the underlying graph structure (the region is not strictly well defined). The result for this region might be incorrect.");
169 assignment.first->setValue(assignment.second);
170 }
171
172 for (auto& assignment : vectorAssignment) {
173 *assignment.first = assignment.second;
174 }
175}
176
177template<typename ParametricType, typename ConstantType>
178uint_fast64_t ParameterLifter<ParametricType, ConstantType>::getRowGroupIndex(uint_fast64_t originalState) const {
179 return matrix.getRowGroupIndices()[oldToNewColumnIndexMapping[originalState]];
180}
181
182template<typename ParametricType, typename ConstantType>
184 return rowGroupToStateNumber[newState];
185}
186
187template<typename ParametricType, typename ConstantType>
188uint_fast64_t ParameterLifter<ParametricType, ConstantType>::getRowGroupSize(uint_fast64_t originalState) const {
189 return matrix.getRowGroupSize(oldToNewColumnIndexMapping[originalState]);
190}
191template<typename ParametricType, typename ConstantType>
193 return matrix.getRowGroupCount();
194}
195
196template<typename ParametricType, typename ConstantType>
200
201template<typename ParametricType, typename ConstantType>
202std::vector<ConstantType> const& ParameterLifter<ParametricType, ConstantType>::getVector() const {
203 return vector;
204}
205
206template<typename ParametricType, typename ConstantType>
207std::vector<typename ParameterLifter<ParametricType, ConstantType>::AbstractValuation> const& ParameterLifter<ParametricType, ConstantType>::getRowLabels()
208 const {
209 return rowLabels;
210}
211
212template<typename ParametricType, typename ConstantType>
213std::vector<typename ParameterLifter<ParametricType, ConstantType>::AbstractValuation>
214ParameterLifter<ParametricType, ConstantType>::getVerticesOfAbstractRegion(std::set<VariableType> const& variables) const {
215 std::size_t const numOfVertices = std::pow(2, variables.size());
216 std::vector<AbstractValuation> result(numOfVertices);
217
218 for (uint_fast64_t vertexId = 0; vertexId < numOfVertices; ++vertexId) {
219 // interprete vertexId as a bit sequence
220 // the consideredVariables.size() least significant bits of vertex will always represent the next vertex
221 //(00...0 = lower boundaries for all variables, 11...1 = upper boundaries for all variables)
222 uint_fast64_t variableIndex = 0;
223 for (auto const& variable : variables) {
224 if ((vertexId >> variableIndex) % 2 == 0) {
225 result[vertexId].addParameterLower(variable);
226 } else {
227 result[vertexId].addParameterUpper(variable);
228 }
229 ++variableIndex;
230 }
231 }
232 return result;
233}
234
235template<typename ParametricType, typename ConstantType>
236const std::vector<std::set<typename ParameterLifter<ParametricType, ConstantType>::VariableType>>&
238 return occurringVariablesAtState;
239}
240
241template<typename ParametricType, typename ConstantType>
242std::map<typename ParameterLifter<ParametricType, ConstantType>::VariableType, std::set<uint_fast64_t>>
244 return occuringStatesAtVariable;
245}
246
247template<typename ParametricType, typename ConstantType>
249 return this->lowerPars == other.lowerPars && this->upperPars == other.upperPars && this->unspecifiedPars == other.unspecifiedPars;
250}
251
252template<typename ParametricType, typename ConstantType>
256
257template<typename ParametricType, typename ConstantType>
261
262template<typename ParametricType, typename ConstantType>
266
267template<typename ParametricType, typename ConstantType>
269 std::size_t seed = 0;
270 for (auto const& p : lowerPars) {
271 carl::hash_add(seed, p);
272 }
273 for (auto const& p : upperPars) {
274 carl::hash_add(seed, p);
275 }
276 for (auto const& p : unspecifiedPars) {
277 carl::hash_add(seed, p);
278 }
279 return seed;
280}
281
282template<typename ParametricType, typename ConstantType>
284 std::set<VariableType> const& pars) const {
285 AbstractValuation result;
286 for (auto const& p : pars) {
287 if (std::find(lowerPars.begin(), lowerPars.end(), p) != lowerPars.end()) {
288 result.addParameterLower(p);
289 } else if (std::find(upperPars.begin(), upperPars.end(), p) != upperPars.end()) {
290 result.addParameterUpper(p);
291 } else if (std::find(unspecifiedPars.begin(), unspecifiedPars.end(), p) != unspecifiedPars.end()) {
292 result.addParameterUnspecified(p);
293 } else {
294 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException,
295 "Tried to obtain a subvaluation for parameters that are not specified by this valuation");
296 }
297 }
298 return result;
299}
300
301template<typename ParametricType, typename ConstantType>
302std::set<typename ParameterLifter<ParametricType, ConstantType>::VariableType> const&
306
307template<typename ParametricType, typename ConstantType>
308std::set<typename ParameterLifter<ParametricType, ConstantType>::VariableType> const&
312
313template<typename ParametricType, typename ConstantType>
314std::set<typename ParameterLifter<ParametricType, ConstantType>::VariableType> const&
318
319template<typename ParametricType, typename ConstantType>
320std::vector<storm::utility::parametric::Valuation<ParametricType>> ParameterLifter<ParametricType, ConstantType>::AbstractValuation::getConcreteValuations(
322 auto result = region.getVerticesOfRegion(unspecifiedPars);
323 for (auto& valuation : result) {
324 for (auto const& lowerPar : lowerPars) {
325 valuation.insert(std::pair<VariableType, CoefficientType>(lowerPar, region.getLowerBoundary(lowerPar)));
326 }
327 for (auto const& upperPar : upperPars) {
328 valuation.insert(std::pair<VariableType, CoefficientType>(upperPar, region.getUpperBoundary(upperPar)));
329 }
330 }
331 return result;
332}
333
334template<typename ParametricType, typename ConstantType>
336 AbstractValuation const& valuation) {
337 ParametricType simplifiedFunction = function;
338 storm::utility::simplify(simplifiedFunction);
339 std::set<VariableType> variablesInFunction;
340 storm::utility::parametric::gatherOccurringVariables(simplifiedFunction, variablesInFunction);
341 AbstractValuation simplifiedValuation = valuation.getSubValuation(variablesInFunction);
342 // insert the function and the valuation
343 // Note that references to elements of an unordered map remain valid after calling unordered_map::insert.
344 auto insertionRes = collectedFunctions.insert(std::pair<FunctionValuation, ConstantType>(
345 FunctionValuation(std::move(simplifiedFunction), std::move(simplifiedValuation)), storm::utility::one<ConstantType>()));
346 return insertionRes.first->second;
347}
348
349template<typename ParametricType, typename ConstantType>
351 storm::storage::ParameterRegion<ParametricType> const& region, storm::solver::OptimizationDirection const& dirForUnspecifiedParameters) {
352 for (auto& collectedFunctionValuationPlaceholder : collectedFunctions) {
353 ParametricType const& function = collectedFunctionValuationPlaceholder.first.first;
354 AbstractValuation const& abstrValuation = collectedFunctionValuationPlaceholder.first.second;
355 ConstantType& placeholder = collectedFunctionValuationPlaceholder.second;
356 auto concreteValuations = abstrValuation.getConcreteValuations(region);
357 auto concreteValuationIt = concreteValuations.begin();
358 placeholder = storm::utility::convertNumber<ConstantType>(storm::utility::parametric::evaluate(function, *concreteValuationIt));
359 for (++concreteValuationIt; concreteValuationIt != concreteValuations.end(); ++concreteValuationIt) {
360 ConstantType currentResult = storm::utility::convertNumber<ConstantType>(storm::utility::parametric::evaluate(function, *concreteValuationIt));
361 if (storm::solver::minimize(dirForUnspecifiedParameters)) {
362 placeholder = std::min(placeholder, currentResult);
363 } else {
364 placeholder = std::max(placeholder, currentResult);
365 }
366 }
367 }
368}
369
370template class ParameterLifter<storm::RationalFunction, double>;
371template class ParameterLifter<storm::RationalFunction, storm::RationalNumber>;
372} // namespace transformer
373} // namespace storm
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
size_t size() const
Retrieves the number of bits this bit vector can store.
uint_fast64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
std::string toString(bool boundariesAsDouble=false) const
CoefficientType const & getLowerBoundary(VariableType const &variable) const
CoefficientType const & getUpperBoundary(VariableType const &variable) const
std::vector< Valuation > getVerticesOfRegion(std::set< VariableType > const &consideredVariables) const
Returns a vector of all possible combinations of lower and upper bounds of the given variables.
A class that can be used to build a sparse matrix by adding value by value.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
const_rows getRow(index_type row) const
Returns an object representing the given row.
index_type getEntryCount() const
Returns the number of entries in the matrix.
index_type getColumnCount() const
Returns the number of columns of the matrix.
std::vector< MatrixEntry< index_type, value_type > >::iterator iterator
std::set< VariableType > const & getUnspecifiedParameters() const
std::vector< storm::utility::parametric::Valuation< ParametricType > > getConcreteValuations(storm::storage::ParameterRegion< ParametricType > const &region) const
Returns the concrete valuation(s) (w.r.t.
std::set< VariableType > const & getUpperParameters() const
AbstractValuation getSubValuation(std::set< VariableType > const &pars) const
bool operator==(AbstractValuation const &other) const
std::set< VariableType > const & getLowerParameters() const
This class lifts parameter choices to nondeterminism: For each row in the given matrix that considerd...
uint_fast64_t getRowGroupSize(uint_fast64_t originalState) const
uint_fast64_t getOriginalStateNumber(uint_fast64_t newState) const
void specifyRegion(storm::storage::ParameterRegion< ParametricType > const &region, storm::solver::OptimizationDirection const &dirForParameters)
storm::storage::SparseMatrix< ConstantType > const & getMatrix() const
std::vector< AbstractValuation > const & getRowLabels() const
uint_fast64_t getRowGroupIndex(uint_fast64_t originalState) const
std::vector< ConstantType > const & getVector() const
storm::utility::parametric::VariableType< ParametricType >::type VariableType
std::vector< std::set< VariableType > > const & getOccurringVariablesAtState() const
std::map< VariableType, std::set< uint_fast64_t > > getOccuringStatesAtVariable() const
ParameterLifter(storm::storage::SparseMatrix< ParametricType > const &pMatrix, std::vector< ParametricType > const &pVector, storm::storage::BitVector const &selectedRows, storm::storage::BitVector const &selectedColumns, bool generateRowLabels=false, bool useMonotonicity=false)
Lifts the parameter choices to nondeterminisim.
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
bool constexpr minimize(OptimizationDirection d)
void gatherOccurringVariables(FunctionType const &function, std::set< typename VariableType< FunctionType >::type > &variableSet)
Add all variables that occur in the given function to the the given set.
CoefficientType< FunctionType >::type evaluate(FunctionType const &function, Valuation< FunctionType > const &valuation)
Evaluates the given function wrt.
bool isConstant(ValueType const &)
Definition constants.cpp:66
ValueType simplify(ValueType value)
bool isZero(ValueType const &a)
Definition constants.cpp:41
LabParser.cpp.
Definition cli.cpp:18