Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
LinearEquationSolverTest.cpp
Go to the documentation of this file.
1#include "storm-config.h"
2#include "test/storm_gtest.h"
3
12
13namespace {
14
15class NativeDoublePowerEnvironment {
16 public:
17 typedef double ValueType;
18 static const bool isExact = false;
19 static storm::Environment createEnvironment() {
20 storm::Environment env;
21 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
22 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power);
24 return env;
25 }
26};
27
28class NativeDoublePowerRegMultEnvironment {
29 public:
30 typedef double ValueType;
31 static const bool isExact = false;
32 static storm::Environment createEnvironment() {
33 storm::Environment env;
34 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
35 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power);
38 return env;
39 }
40};
41
42class NativeDoubleSoundValueIterationEnvironment {
43 public:
44 typedef double ValueType;
45 static const bool isExact = false;
46 static storm::Environment createEnvironment() {
47 storm::Environment env;
48 env.solver().setForceSoundness(true);
49 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
50 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SoundValueIteration);
53 return env;
54 }
55};
56
57class NativeDoubleOptimisticValueIterationEnvironment {
58 public:
59 typedef double ValueType;
60 static const bool isExact = false;
61 static storm::Environment createEnvironment() {
62 storm::Environment env;
63 env.solver().setForceSoundness(true);
64 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
65 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::OptimisticValueIteration);
68 return env;
69 }
70};
71
72class NativeDoubleIntervalIterationEnvironment {
73 public:
74 typedef double ValueType;
75 static const bool isExact = false;
76 static storm::Environment createEnvironment() {
77 storm::Environment env;
78 env.solver().setForceSoundness(true);
79 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
80 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::IntervalIteration);
83 return env;
84 }
85};
86
87class NativeDoubleGuessingViEnvironment {
88 public:
89 typedef double ValueType;
90 static const bool isExact = false;
91 static storm::Environment createEnvironment() {
92 storm::Environment env;
93 env.solver().setForceSoundness(true);
94 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
95 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::GuessingValueIteration);
98 return env;
99 }
100};
101
102class NativeDoubleJacobiEnvironment {
103 public:
104 typedef double ValueType;
105 static const bool isExact = false;
106 static storm::Environment createEnvironment() {
107 storm::Environment env;
108 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
109 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Jacobi);
111 return env;
112 }
113};
114
115class NativeDoubleGaussSeidelEnvironment {
116 public:
117 typedef double ValueType;
118 static const bool isExact = false;
119 static storm::Environment createEnvironment() {
120 storm::Environment env;
121 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
122 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::GaussSeidel);
124 return env;
125 }
126};
127
128class NativeDoubleSorEnvironment {
129 public:
130 typedef double ValueType;
131 static const bool isExact = false;
132 static storm::Environment createEnvironment() {
133 storm::Environment env;
134 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
135 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SOR);
137 return env;
138 }
139};
140
141class NativeDoubleWalkerChaeEnvironment {
142 public:
143 typedef double ValueType;
144 static const bool isExact = false;
145 static storm::Environment createEnvironment() {
146 storm::Environment env;
147 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
148 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::WalkerChae);
151 return env;
152 }
153};
154
155class NativeRationalRationalSearchEnvironment {
156 public:
157 typedef storm::RationalNumber ValueType;
158 static const bool isExact = true;
159 static storm::Environment createEnvironment() {
160 storm::Environment env;
161 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
162 env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::RationalSearch);
163 return env;
164 }
165};
166
167class EliminationRationalEnvironment {
168 public:
169 typedef storm::RationalNumber ValueType;
170 static const bool isExact = true;
171 static storm::Environment createEnvironment() {
172 storm::Environment env;
173 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Elimination);
174 return env;
175 }
176};
177
178#ifdef STORM_HAVE_GMM
179class GmmGmresIluEnvironment {
180 public:
181 typedef double ValueType;
182 static const bool isExact = false;
183 static storm::Environment createEnvironment() {
184 storm::Environment env;
185 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
186 env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres);
187 env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Ilu);
189 return env;
190 }
191};
192
193class GmmGmresDiagonalEnvironment {
194 public:
195 typedef double ValueType;
196 static const bool isExact = false;
197 static storm::Environment createEnvironment() {
198 storm::Environment env;
199 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
200 env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres);
201 env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Diagonal);
203 return env;
204 }
205};
206
207class GmmGmresNoneEnvironment {
208 public:
209 typedef double ValueType;
210 static const bool isExact = false;
211 static storm::Environment createEnvironment() {
212 storm::Environment env;
213 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
214 env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres);
215 env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::None);
217 return env;
218 }
219};
220
221class GmmBicgstabIluEnvironment {
222 public:
223 typedef double ValueType;
224 static const bool isExact = false;
225 static storm::Environment createEnvironment() {
226 storm::Environment env;
227 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
228 env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Bicgstab);
229 env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Ilu);
231 return env;
232 }
233};
234
235class GmmQmrDiagonalEnvironment {
236 public:
237 typedef double ValueType;
238 static const bool isExact = false;
239 static storm::Environment createEnvironment() {
240 storm::Environment env;
241 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
242 env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Qmr);
243 env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Diagonal);
245 return env;
246 }
247};
248#endif
249
250class EigenDGmresDiagonalEnvironment {
251 public:
252 typedef double ValueType;
253 static const bool isExact = false;
254 static storm::Environment createEnvironment() {
255 storm::Environment env;
256 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
257 env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::DGmres);
258 env.solver().eigen().setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner::Diagonal);
260 return env;
261 }
262};
263
264class EigenGmresIluEnvironment {
265 public:
266 typedef double ValueType;
267 static const bool isExact = false;
268 static storm::Environment createEnvironment() {
269 storm::Environment env;
270 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
271 env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::Gmres);
272 env.solver().eigen().setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner::Ilu);
274 return env;
275 }
276};
277
278class EigenBicgstabNoneEnvironment {
279 public:
280 typedef double ValueType;
281 static const bool isExact = false;
282 static storm::Environment createEnvironment() {
283 storm::Environment env;
284 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
285 env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::Bicgstab);
286 env.solver().eigen().setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner::None);
288 return env;
289 }
290};
291
292class EigenDoubleLUEnvironment {
293 public:
294 typedef double ValueType;
295 static const bool isExact = false;
296 static storm::Environment createEnvironment() {
297 storm::Environment env;
298 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
299 env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU);
300 return env;
301 }
302};
303
304class EigenRationalLUEnvironment {
305 public:
306 typedef storm::RationalNumber ValueType;
307 static const bool isExact = true;
308 static storm::Environment createEnvironment() {
309 storm::Environment env;
310 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
311 env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU);
312 return env;
313 }
314};
315
316class TopologicalEigenRationalLUEnvironment {
317 public:
318 typedef storm::RationalNumber ValueType;
319 static const bool isExact = true;
320 static storm::Environment createEnvironment() {
321 storm::Environment env;
322 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Topological);
323 env.solver().topological().setUnderlyingEquationSolverType(storm::solver::EquationSolverType::Eigen);
324 env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU);
325 return env;
326 }
327};
328
329template<typename TestType>
330class LinearEquationSolverTest : public ::testing::Test {
331 public:
332 typedef typename TestType::ValueType ValueType;
333 LinearEquationSolverTest() : _environment(TestType::createEnvironment()) {}
334 storm::Environment const& env() const {
335 return _environment;
336 }
337 ValueType precision() const {
338 return TestType::isExact ? parseNumber("0") : parseNumber("1e-6");
339 }
340 ValueType parseNumber(std::string const& input) const {
342 }
343
344 private:
345 storm::Environment _environment;
346};
347
348typedef ::testing::Types<NativeDoublePowerEnvironment, NativeDoublePowerRegMultEnvironment, NativeDoubleSoundValueIterationEnvironment,
349 NativeDoubleOptimisticValueIterationEnvironment, NativeDoubleGuessingViEnvironment, NativeDoubleIntervalIterationEnvironment,
350 NativeDoubleJacobiEnvironment, NativeDoubleGaussSeidelEnvironment, NativeDoubleSorEnvironment, NativeDoubleWalkerChaeEnvironment,
351 NativeRationalRationalSearchEnvironment, EliminationRationalEnvironment,
352#ifdef STORM_HAVE_GMM
353 GmmGmresIluEnvironment, GmmGmresDiagonalEnvironment, GmmGmresNoneEnvironment, GmmBicgstabIluEnvironment, GmmQmrDiagonalEnvironment,
354#endif
355 EigenDGmresDiagonalEnvironment, EigenGmresIluEnvironment, EigenBicgstabNoneEnvironment, EigenDoubleLUEnvironment,
356 EigenRationalLUEnvironment, TopologicalEigenRationalLUEnvironment>
358
359TYPED_TEST_SUITE(LinearEquationSolverTest, TestingTypes, );
360
361TYPED_TEST(LinearEquationSolverTest, solveEquationSystem) {
362 typedef typename TestFixture::ValueType ValueType;
363 ASSERT_NO_THROW(storm::storage::SparseMatrixBuilder<ValueType> builder);
365 ASSERT_NO_THROW(builder.addNextValue(0, 0, this->parseNumber("1/5")));
366 ASSERT_NO_THROW(builder.addNextValue(0, 1, this->parseNumber("2/5")));
367 ASSERT_NO_THROW(builder.addNextValue(0, 2, this->parseNumber("2/5")));
368 ASSERT_NO_THROW(builder.addNextValue(1, 0, this->parseNumber("1/50")));
369 ASSERT_NO_THROW(builder.addNextValue(1, 1, this->parseNumber("48/50")));
370 ASSERT_NO_THROW(builder.addNextValue(1, 2, this->parseNumber("1/50")));
371 ASSERT_NO_THROW(builder.addNextValue(2, 0, this->parseNumber("4/10")));
372 ASSERT_NO_THROW(builder.addNextValue(2, 1, this->parseNumber("3/10")));
373 ASSERT_NO_THROW(builder.addNextValue(2, 2, this->parseNumber("0")));
374
376 ASSERT_NO_THROW(A = builder.build());
377
378 std::vector<ValueType> x(3);
379 std::vector<ValueType> b = {this->parseNumber("3"), this->parseNumber("-0.01"), this->parseNumber("12")};
380
382 if (factory.getEquationProblemFormat(this->env()) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem) {
384 }
385
386 auto requirements = factory.getRequirements(this->env());
387 requirements.clearUpperBounds();
388 requirements.clearLowerBounds();
389 ASSERT_FALSE(requirements.hasEnabledRequirement());
390 auto solver = factory.create(this->env(), A);
391 solver->setBounds(this->parseNumber("-100"), this->parseNumber("100"));
392 ASSERT_NO_THROW(solver->solveEquations(this->env(), x, b));
393 EXPECT_NEAR(x[0], this->parseNumber("481/9"), this->precision());
394 EXPECT_NEAR(x[1], this->parseNumber("457/9"), this->precision());
395 EXPECT_NEAR(x[2], this->parseNumber("875/18"), this->precision());
396}
397
398template<typename ValueType>
399void testEliminationWithAbsorbingStates(std::vector<std::vector<std::pair<uint64_t, ValueType>>> const& rows, std::vector<ValueType> const& b,
400 std::vector<ValueType> const& expected) {
401 storm::storage::SparseMatrixBuilder<ValueType> builder(rows.size(), rows.size(), 0);
402 for (uint64_t row = 0; row < rows.size(); ++row) {
403 for (auto const& entry : rows[row]) {
404 builder.addNextValue(row, entry.first, entry.second);
405 }
406 }
407 auto matrix = builder.build();
408
410 env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Elimination);
412 std::vector<ValueType> x(b.size());
413 ASSERT_NO_THROW(solver.solveEquations(env, x, b));
414 ASSERT_EQ(expected.size(), x.size());
415 for (uint64_t i = 0; i < x.size(); ++i) {
416 EXPECT_EQ(expected[i], x[i]);
417 }
418}
419
420TEST(EliminationLinearEquationSolver, AbsorbingState) {
421 // Regression test for issue #86: the elimination-based solver must handle a single absorbing state
422 // (a one on the diagonal), for which the least fixed point is zero.
424 testEliminationWithAbsorbingStates<storm::RationalNumber>({{{0, storm::utility::one<storm::RationalNumber>()}}}, {zero}, {zero});
425}
426
427TEST(EliminationLinearEquationSolver, AbsorbingTwoCycle) {
428 // Regression test for issue #86: when eliminating one state of a probability-1 cycle, the remaining state
429 // obtains a one on the diagonal (i.e., it becomes absorbing) and must be handled by the eliminator.
432 testEliminationWithAbsorbingStates<storm::RationalNumber>({{{1, one}}, {{0, one}}}, {zero, zero}, {zero, zero});
433
434 // Also check the double instantiation.
435 testEliminationWithAbsorbingStates<double>({{{1, 1.0}}, {{0, 1.0}}}, {0.0, 0.0}, {0.0, 0.0});
436}
437
438TEST(EliminationLinearEquationSolver, AbsorbingSinkReachability) {
439 // A transient state can either reach the target with probability one half or fall into an absorbing sink.
443 testEliminationWithAbsorbingStates<storm::RationalNumber>({{{1, half}}, {{2, one}}, {{1, one}}}, {half, zero, zero}, {half, zero, zero});
444}
445} // namespace
TEST(OrderTest, Simple)
Definition OrderTest.cpp:15
void setPrecision(storm::RationalNumber value)
void setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner value)
void setMethod(storm::solver::EigenLinearEquationSolverMethod value)
SolverEnvironment & solver()
void setMethod(storm::solver::GmmxxLinearEquationSolverMethod value)
void setPrecision(storm::RationalNumber value)
void setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner value)
void setPowerMethodMultiplicationStyle(storm::solver::MultiplicationStyle value)
void setMaximalNumberOfIterations(uint64_t value)
void setMethod(storm::solver::NativeLinearEquationSolverMethod value)
void setPrecision(storm::RationalNumber value)
TopologicalSolverEnvironment & topological()
void setLinearEquationSolverType(storm::solver::EquationSolverType const &value, bool isSetFromDefault=false)
EigenSolverEnvironment & eigen()
NativeSolverEnvironment & native()
GmmxxSolverEnvironment & gmmxx()
void setUnderlyingEquationSolverType(storm::solver::EquationSolverType value)
A class that uses gaussian elimination to implement the LinearEquationSolver interface.
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.
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.
void convertToEquationSystem()
Transforms the matrix into an equation system.
SFTBDDChecker::ValueType ValueType
NumberType parseNumber(std::string const &value)
Parse number from string.
ValueType zero()
Definition constants.cpp:24
ValueType one()
Definition constants.cpp:19
TargetType convertNumber(SourceType const &number)
TYPED_TEST(GraphTestAR, SymbolicProb01StochasticGameDieSmall)
Definition GraphTest.cpp:64
TYPED_TEST_SUITE(GraphTestAR, TestingTypes,)
::testing::Types< Cudd, Sylvan > TestingTypes
Definition GraphTest.cpp:61