Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
GmmxxMultiplier.cpp
Go to the documentation of this file.
1#include "GmmxxMultiplier.h"
2
7
10
12
13namespace storm {
14namespace solver {
15
16template<typename ValueType>
18 // Intentionally left empty.
19}
20
21template<typename ValueType>
23 if (gmmMatrix.nrows() == 0) {
24 gmmMatrix = std::move(*storm::adapters::GmmxxAdapter<ValueType>().toGmmxxSparseMatrix(this->matrix));
25 }
26}
27
28template<typename ValueType>
30 gmmMatrix = gmm::csr_matrix<ValueType>();
32}
33
34template<typename ValueType>
36 return false;
37}
38
39template<typename ValueType>
40void GmmxxMultiplier<ValueType>::multiply(Environment const& env, std::vector<ValueType> const& x, std::vector<ValueType> const* b,
41 std::vector<ValueType>& result) const {
42 initialize();
43 std::vector<ValueType>* target = &result;
44 if (&x == &result) {
45 if (this->cachedVector) {
46 this->cachedVector->resize(x.size());
47 } else {
48 this->cachedVector = std::make_unique<std::vector<ValueType>>(x.size());
49 }
50 target = this->cachedVector.get();
51 }
52 if (parallelize(env)) {
53 multAddParallel(x, b, *target);
54 } else {
55 multAdd(x, b, *target);
56 }
57 if (&x == &result) {
58 std::swap(result, *this->cachedVector);
59 }
60}
61
62template<typename ValueType>
63void GmmxxMultiplier<ValueType>::multiplyGaussSeidel(Environment const& env, std::vector<ValueType>& x, std::vector<ValueType> const* b, bool backwards) const {
64 initialize();
65 STORM_LOG_ASSERT(gmmMatrix.nr == gmmMatrix.nc, "Expecting square matrix.");
66 if (backwards) {
67 if (b) {
68 gmm::mult_add_by_row_bwd(gmmMatrix, x, *b, x, gmm::abstract_dense());
69 } else {
70 gmm::mult_by_row_bwd(gmmMatrix, x, x, gmm::abstract_dense());
71 }
72 } else {
73 if (b) {
74 gmm::mult_add_by_row(gmmMatrix, x, *b, x, gmm::abstract_dense());
75 } else {
76 gmm::mult_by_row(gmmMatrix, x, x, gmm::abstract_dense());
77 }
78 }
79}
80
81template<typename ValueType>
82void GmmxxMultiplier<ValueType>::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
83 std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result,
84 std::vector<uint_fast64_t>* choices) const {
85 initialize();
86 std::vector<ValueType>* target = &result;
87 if (&x == &result) {
88 if (this->cachedVector) {
89 this->cachedVector->resize(x.size());
90 } else {
91 this->cachedVector = std::make_unique<std::vector<ValueType>>(x.size());
92 }
93 target = this->cachedVector.get();
94 }
95 if (parallelize(env)) {
96 multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices);
97 } else {
98 multAddReduceHelper(dir, rowGroupIndices, x, b, *target, choices, false);
99 }
100 if (&x == &result) {
101 std::swap(result, *this->cachedVector);
102 }
103}
104
105template<typename ValueType>
107 std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType>& x,
108 std::vector<ValueType> const* b, std::vector<uint_fast64_t>* choices, bool backwards) const {
109 initialize();
110 multAddReduceHelper(dir, rowGroupIndices, x, b, x, choices, backwards);
111}
112
113template<typename ValueType>
114void GmmxxMultiplier<ValueType>::multiplyRow(uint64_t const& rowIndex, std::vector<ValueType> const& x, ValueType& value) const {
115 initialize();
116 value += vect_sp(gmm::mat_const_row(gmmMatrix, rowIndex), x, typename gmm::linalg_traits<gmm::csr_matrix<ValueType>>::storage_type(),
117 typename gmm::linalg_traits<std::vector<ValueType>>::storage_type());
118}
119
120template<typename ValueType>
121void GmmxxMultiplier<ValueType>::multAdd(std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result) const {
122 if (b) {
123 if (b == &result) {
124 gmm::mult_add(gmmMatrix, x, result);
125 } else {
126 gmm::mult_add(gmmMatrix, x, *b, result);
127 }
128 } else {
129 gmm::mult(gmmMatrix, x, result);
130 }
131}
132
133template<typename ValueType>
134void GmmxxMultiplier<ValueType>::multAddReduceHelper(OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
135 std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result,
136 std::vector<uint64_t>* choices, bool backwards) const {
137 if (dir == storm::OptimizationDirection::Minimize) {
138 if (backwards) {
139 multAddReduceHelper<storm::utility::ElementLess<ValueType>, true>(rowGroupIndices, x, b, result, choices);
140 } else {
141 multAddReduceHelper<storm::utility::ElementLess<ValueType>, false>(rowGroupIndices, x, b, result, choices);
142 }
143 } else {
144 if (backwards) {
145 multAddReduceHelper<storm::utility::ElementGreater<ValueType>, true>(rowGroupIndices, x, b, result, choices);
146 } else {
147 multAddReduceHelper<storm::utility::ElementGreater<ValueType>, false>(rowGroupIndices, x, b, result, choices);
148 }
149 }
150}
151
152template<typename ValueType>
153template<typename Compare, bool backwards>
154void GmmxxMultiplier<ValueType>::multAddReduceHelper(std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType> const& x,
155 std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint64_t>* choices) const {
156 Compare compare;
157 typedef std::vector<ValueType> VectorType;
158 typedef gmm::csr_matrix<ValueType> MatrixType;
159
160 typename gmm::linalg_traits<VectorType>::const_iterator add_it, add_ite;
161 if (b) {
162 add_it = backwards ? gmm::vect_end(*b) - 1 : gmm::vect_begin(*b);
163 add_ite = backwards ? gmm::vect_begin(*b) - 1 : gmm::vect_end(*b);
164 }
165 typename gmm::linalg_traits<VectorType>::iterator target_it = backwards ? gmm::vect_end(result) - 1 : gmm::vect_begin(result);
166 typename gmm::linalg_traits<MatrixType>::const_row_iterator itr = backwards ? mat_row_const_end(gmmMatrix) - 1 : mat_row_const_begin(gmmMatrix);
167 typename std::vector<uint64_t>::iterator choice_it;
168 if (choices) {
169 choice_it = backwards ? choices->end() - 1 : choices->begin();
170 }
171
172 // Variables for correctly tracking choices (only update if new choice is strictly better).
173 ValueType oldSelectedChoiceValue;
174 uint64_t selectedChoice;
175
176 uint64_t currentRow = backwards ? gmmMatrix.nrows() - 1 : 0;
177 auto row_group_it = backwards ? rowGroupIndices.end() - 2 : rowGroupIndices.begin();
178 auto row_group_ite = backwards ? rowGroupIndices.begin() - 1 : rowGroupIndices.end() - 1;
179 while (row_group_it != row_group_ite) {
180 ValueType currentValue = storm::utility::zero<ValueType>();
181
182 // Only multiply and reduce if the row group is not empty.
183 if (*row_group_it != *(row_group_it + 1)) {
184 // Process the (backwards ? last : first) row of the current row group
185 if (b) {
186 currentValue = *add_it;
187 }
188
189 currentValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
190
191 if (choices) {
192 selectedChoice = currentRow - *row_group_it;
193 if (*choice_it == selectedChoice) {
194 oldSelectedChoiceValue = currentValue;
195 }
196 }
197
198 // move row-based iterators to the next row
199 if (backwards) {
200 --itr;
201 --currentRow;
202 --add_it;
203 } else {
204 ++itr;
205 ++currentRow;
206 ++add_it;
207 }
208
209 // Process the (rowGroupSize-1) remaining rows within the current row Group
210 uint64_t rowGroupSize = *(row_group_it + 1) - *row_group_it;
211 for (uint64_t i = 1; i < rowGroupSize; ++i) {
212 ValueType newValue = b ? *add_it : storm::utility::zero<ValueType>();
213 newValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
214
215 if (choices && currentRow == *choice_it + *row_group_it) {
216 oldSelectedChoiceValue = newValue;
217 }
218
219 if (compare(newValue, currentValue)) {
220 currentValue = newValue;
221 if (choices) {
222 selectedChoice = currentRow - *row_group_it;
223 }
224 }
225 // move row-based iterators to the next row
226 if (backwards) {
227 --itr;
228 --currentRow;
229 --add_it;
230 } else {
231 ++itr;
232 ++currentRow;
233 ++add_it;
234 }
235 }
236
237 // Finally write value to target vector.
238 *target_it = currentValue;
239 if (choices && compare(currentValue, oldSelectedChoiceValue)) {
240 *choice_it = selectedChoice;
241 }
242 }
243
244 // move rowGroup-based iterators to the next row group
245 if (backwards) {
246 --row_group_it;
247 --choice_it;
248 --target_it;
249 } else {
250 ++row_group_it;
251 ++choice_it;
252 ++target_it;
253 }
254 }
255}
256
257template<>
258template<typename Compare, bool backwards>
259void GmmxxMultiplier<storm::RationalFunction>::multAddReduceHelper(std::vector<uint64_t> const& rowGroupIndices, std::vector<storm::RationalFunction> const& x,
260 std::vector<storm::RationalFunction> const* b, std::vector<storm::RationalFunction>& result,
261 std::vector<uint64_t>* choices) const {
262 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported for this data type.");
263}
264
265template<typename ValueType>
266void GmmxxMultiplier<ValueType>::multAddParallel(std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result) const {
267#ifdef STORM_HAVE_INTELTBB
268 if (b) {
269 if (b == &result) {
270 gmm::mult_add_parallel(gmmMatrix, x, result);
271 } else {
272 gmm::mult_add_parallel(gmmMatrix, x, *b, result);
273 }
274 } else {
275 gmm::mult_parallel(gmmMatrix, x, result);
276 }
277#else
278 STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version.");
279 multAdd(x, b, result);
280#endif
281}
282
283#ifdef STORM_HAVE_INTELTBB
284template<typename ValueType, typename Compare>
285class TbbMultAddReduceFunctor {
286 public:
287 TbbMultAddReduceFunctor(std::vector<uint64_t> const& rowGroupIndices, gmm::csr_matrix<ValueType> const& matrix, std::vector<ValueType> const& x,
288 std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint64_t>* choices)
289 : rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) {
290 // Intentionally left empty.
291 }
292
293 void operator()(tbb::blocked_range<unsigned long> const& range) const {
294 typedef std::vector<ValueType> VectorType;
295 typedef gmm::csr_matrix<ValueType> MatrixType;
296
297 auto groupIt = rowGroupIndices.begin() + range.begin();
298 auto groupIte = rowGroupIndices.begin() + range.end();
299
300 auto itr = mat_row_const_begin(matrix) + *groupIt;
301 typename std::vector<ValueType>::const_iterator bIt;
302 if (b) {
303 bIt = b->begin() + *groupIt;
304 }
305 typename std::vector<uint64_t>::iterator choiceIt;
306 if (choices) {
307 choiceIt = choices->begin() + range.begin();
308 }
309
310 auto resultIt = result.begin() + range.begin();
311
312 // Variables for correctly tracking choices (only update if new choice is strictly better).
313 ValueType oldSelectedChoiceValue;
314 uint64_t selectedChoice;
315
316 uint64_t currentRow = *groupIt;
317 for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) {
318 ValueType currentValue = storm::utility::zero<ValueType>();
319
320 // Only multiply and reduce if the row group is not empty.
321 if (*groupIt != *(groupIt + 1)) {
322 if (b) {
323 currentValue = *bIt;
324 ++bIt;
325 }
326
327 currentValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
328
329 if (choices) {
330 selectedChoice = currentRow - *groupIt;
331 if (*choiceIt == selectedChoice) {
332 oldSelectedChoiceValue = currentValue;
333 }
334 }
335
336 ++itr;
337 ++currentRow;
338
339 for (auto itre = mat_row_const_begin(matrix) + *(groupIt + 1); itr != itre; ++itr, ++bIt, ++currentRow) {
340 ValueType newValue = b ? *bIt : storm::utility::zero<ValueType>();
341 newValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
342
343 if (compare(newValue, currentValue)) {
344 currentValue = newValue;
345 if (choices) {
346 selectedChoice = currentRow - *groupIt;
347 }
348 }
349 }
350 }
351
352 // Finally write value to target vector.
353 *resultIt = currentValue;
354 if (choices && compare(currentValue, oldSelectedChoiceValue)) {
355 *choiceIt = selectedChoice;
356 }
357 }
358 }
359
360 private:
361 Compare compare;
362 std::vector<uint64_t> const& rowGroupIndices;
363 gmm::csr_matrix<ValueType> const& matrix;
364 std::vector<ValueType> const& x;
365 std::vector<ValueType> const* b;
366 std::vector<ValueType>& result;
367 std::vector<uint64_t>* choices;
368};
369#endif
370
371template<typename ValueType>
372void GmmxxMultiplier<ValueType>::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
373 std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result,
374 std::vector<uint64_t>* choices) const {
375#ifdef STORM_HAVE_INTELTBB
376 if (dir == storm::OptimizationDirection::Minimize) {
377 tbb::parallel_for(tbb::blocked_range<unsigned long>(0, rowGroupIndices.size() - 1, 100),
378 TbbMultAddReduceFunctor<ValueType, storm::utility::ElementLess<ValueType>>(rowGroupIndices, this->gmmMatrix, x, b, result, choices));
379 } else {
380 tbb::parallel_for(
381 tbb::blocked_range<unsigned long>(0, rowGroupIndices.size() - 1, 100),
382 TbbMultAddReduceFunctor<ValueType, storm::utility::ElementGreater<ValueType>>(rowGroupIndices, this->gmmMatrix, x, b, result, choices));
383 }
384#else
385 STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version.");
386 multAddReduceHelper(dir, rowGroupIndices, x, b, result, choices);
387#endif
388}
389
390template<>
391void GmmxxMultiplier<storm::RationalFunction>::multAddReduceParallel(storm::solver::OptimizationDirection const& dir,
392 std::vector<uint64_t> const& rowGroupIndices,
393 std::vector<storm::RationalFunction> const& x,
394 std::vector<storm::RationalFunction> const* b,
395 std::vector<storm::RationalFunction>& result, std::vector<uint64_t>* choices) const {
396 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported.");
397}
398
399template class GmmxxMultiplier<double>;
400
401#ifdef STORM_HAVE_CARL
402template class GmmxxMultiplier<storm::RationalNumber>;
403template class GmmxxMultiplier<storm::RationalFunction>;
404#endif
405
406} // namespace solver
407} // namespace storm
virtual void multiplyAndReduceGaussSeidel(Environment const &env, OptimizationDirection const &dir, std::vector< uint64_t > const &rowGroupIndices, std::vector< ValueType > &x, std::vector< ValueType > const *b, std::vector< uint_fast64_t > *choices=nullptr, bool backwards=true) const override
virtual void multiply(Environment const &env, std::vector< ValueType > const &x, std::vector< ValueType > const *b, std::vector< ValueType > &result) const override
Performs a matrix-vector multiplication x' = A*x + b.
virtual void multiplyGaussSeidel(Environment const &env, std::vector< ValueType > &x, std::vector< ValueType > const *b, bool backwards=true) const override
Performs a matrix-vector multiplication in gauss-seidel style.
GmmxxMultiplier(storm::storage::SparseMatrix< ValueType > const &matrix)
virtual void clearCache() const override
virtual void multiplyAndReduce(Environment const &env, OptimizationDirection const &dir, std::vector< uint64_t > const &rowGroupIndices, std::vector< ValueType > const &x, std::vector< ValueType > const *b, std::vector< ValueType > &result, std::vector< uint_fast64_t > *choices=nullptr) const override
virtual void multiplyRow(uint64_t const &rowIndex, std::vector< ValueType > const &x, ValueType &value) const override
Multiplies the row with the given index with x and adds the result to the provided value.
virtual void clearCache() const
A class that holds a possibly non-square matrix in the compressed row storage format.
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SFTBDDChecker::ValueType ValueType
typename detail::ElementLess< ValueType >::type ElementLess
Definition constants.h:69
typename detail::ElementGreater< ValueType >::type ElementGreater
Definition constants.h:72
LabParser.cpp.
Definition cli.cpp:18