You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
350 lines
16 KiB
350 lines
16 KiB
#include "gtest/gtest.h"
|
|
#include "storm-config.h"
|
|
#include "test/storm_gtest.h"
|
|
|
|
#include "storm/solver/LinearEquationSolver.h"
|
|
#include "storm/environment/solver/NativeSolverEnvironment.h"
|
|
#include "storm/environment/solver/GmmxxSolverEnvironment.h"
|
|
#include "storm/environment/solver/EigenSolverEnvironment.h"
|
|
|
|
#include "storm/utility/vector.h"
|
|
namespace {
|
|
|
|
class NativeDoublePowerEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
|
|
env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power);
|
|
env.solver().native().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-10"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class NativeDoubleSoundPowerEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setForceSoundness(true);
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
|
|
env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power);
|
|
env.solver().native().setRelativeTerminationCriterion(false);
|
|
env.solver().native().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-6"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class NativeDoubleJacobiEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
|
|
env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Jacobi);
|
|
env.solver().native().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-10"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class NativeDoubleGaussSeidelEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
|
|
env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::GaussSeidel);
|
|
env.solver().native().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-10"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class NativeDoubleSorEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
|
|
env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SOR);
|
|
env.solver().native().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-10"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class NativeDoubleWalkerChaeEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
|
|
env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::WalkerChae);
|
|
env.solver().native().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
env.solver().native().setMaximalNumberOfIterations(500000);
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class NativeRationalRationalSearchEnvironment {
|
|
public:
|
|
typedef storm::RationalNumber ValueType;
|
|
static const bool isExact = true;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native);
|
|
env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::RationalSearch);
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class EliminationRationalEnvironment {
|
|
public:
|
|
typedef storm::RationalNumber ValueType;
|
|
static const bool isExact = true;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Elimination);
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class GmmGmresIluEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
|
|
env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres);
|
|
env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Ilu);
|
|
env.solver().gmmxx().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class GmmGmresDiagonalEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
|
|
env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres);
|
|
env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Diagonal);
|
|
env.solver().gmmxx().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class GmmGmresNoneEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
|
|
env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres);
|
|
env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::None);
|
|
env.solver().gmmxx().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class GmmBicgstabIluEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
|
|
env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Bicgstab);
|
|
env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Ilu);
|
|
env.solver().gmmxx().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class GmmQmrDiagonalEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx);
|
|
env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Qmr);
|
|
env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Diagonal);
|
|
env.solver().gmmxx().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class EigenDGmresDiagonalEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
|
|
env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::DGmres);
|
|
env.solver().eigen().setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner::Diagonal);
|
|
env.solver().eigen().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class EigenGmresIluEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
|
|
env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::Gmres);
|
|
env.solver().eigen().setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner::Ilu);
|
|
env.solver().eigen().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class EigenBicgstabNoneEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
|
|
env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::Bicgstab);
|
|
env.solver().eigen().setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner::None);
|
|
env.solver().eigen().setPrecision(storm::utility::convertNumber<storm::RationalNumber, std::string>("1e-8"));
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class EigenDoubleLUEnvironment {
|
|
public:
|
|
typedef double ValueType;
|
|
static const bool isExact = false;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
|
|
env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU);
|
|
return env;
|
|
}
|
|
};
|
|
|
|
class EigenRationalLUEnvironment {
|
|
public:
|
|
typedef storm::RationalNumber ValueType;
|
|
static const bool isExact = true;
|
|
static storm::Environment createEnvironment() {
|
|
storm::Environment env;
|
|
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen);
|
|
env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU);
|
|
return env;
|
|
}
|
|
};
|
|
|
|
template<typename TestType>
|
|
class LinearEquationSolverTest : public ::testing::Test {
|
|
public:
|
|
typedef typename TestType::ValueType ValueType;
|
|
LinearEquationSolverTest() : _environment(TestType::createEnvironment()) {}
|
|
storm::Environment const& env() const { return _environment; }
|
|
ValueType precision() const { return TestType::isExact ? parseNumber("0") : parseNumber("1e-6");}
|
|
ValueType parseNumber(std::string const& input) const { return storm::utility::convertNumber<ValueType>(input);}
|
|
private:
|
|
storm::Environment _environment;
|
|
};
|
|
|
|
typedef ::testing::Types<
|
|
NativeDoublePowerEnvironment,
|
|
NativeDoubleSoundPowerEnvironment,
|
|
NativeDoubleJacobiEnvironment,
|
|
NativeDoubleGaussSeidelEnvironment,
|
|
NativeDoubleSorEnvironment,
|
|
NativeDoubleWalkerChaeEnvironment,
|
|
NativeRationalRationalSearchEnvironment,
|
|
EliminationRationalEnvironment,
|
|
GmmGmresIluEnvironment,
|
|
GmmGmresDiagonalEnvironment,
|
|
GmmGmresNoneEnvironment,
|
|
GmmBicgstabIluEnvironment,
|
|
GmmQmrDiagonalEnvironment,
|
|
EigenDGmresDiagonalEnvironment,
|
|
EigenGmresIluEnvironment,
|
|
EigenBicgstabNoneEnvironment,
|
|
EigenDoubleLUEnvironment,
|
|
EigenRationalLUEnvironment
|
|
> TestingTypes;
|
|
|
|
TYPED_TEST_CASE(LinearEquationSolverTest, TestingTypes);
|
|
|
|
|
|
TYPED_TEST(LinearEquationSolverTest, solveEquationSystem) {
|
|
typedef typename TestFixture::ValueType ValueType;
|
|
ASSERT_NO_THROW(storm::storage::SparseMatrixBuilder<ValueType> builder);
|
|
storm::storage::SparseMatrixBuilder<ValueType> builder;
|
|
ASSERT_NO_THROW(builder.addNextValue(0, 0, this->parseNumber("1/5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(0, 1, this->parseNumber("2/5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(0, 2, this->parseNumber("2/5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(1, 0, this->parseNumber("1/50")));
|
|
ASSERT_NO_THROW(builder.addNextValue(1, 1, this->parseNumber("48/50")));
|
|
ASSERT_NO_THROW(builder.addNextValue(1, 2, this->parseNumber("1/50")));
|
|
ASSERT_NO_THROW(builder.addNextValue(2, 0, this->parseNumber("4/10")));
|
|
ASSERT_NO_THROW(builder.addNextValue(2, 1, this->parseNumber("3/10")));
|
|
ASSERT_NO_THROW(builder.addNextValue(2, 2, this->parseNumber("0")));
|
|
|
|
storm::storage::SparseMatrix<ValueType> A;
|
|
ASSERT_NO_THROW(A = builder.build());
|
|
|
|
std::vector<ValueType> x(3);
|
|
std::vector<ValueType> b = {this->parseNumber("3"), this->parseNumber("-0.01"), this->parseNumber("12")};
|
|
|
|
auto factory = storm::solver::GeneralLinearEquationSolverFactory<ValueType>();
|
|
if (factory.getEquationProblemFormat(this->env()) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem) {
|
|
A.convertToEquationSystem();
|
|
}
|
|
|
|
auto requirements = factory.getRequirements(this->env());
|
|
requirements.clearUpperBounds();
|
|
requirements.clearLowerBounds();
|
|
ASSERT_TRUE(requirements.empty());
|
|
auto solver = factory.create(this->env(), A);
|
|
solver->setBounds(this->parseNumber("-100"), this->parseNumber("100"));
|
|
ASSERT_NO_THROW(solver->solveEquations(this->env(), x, b));
|
|
EXPECT_NEAR(x[0], this->parseNumber("481/9"), this->precision());
|
|
EXPECT_NEAR(x[1], this->parseNumber("457/9"), this->precision());
|
|
EXPECT_NEAR(x[2], this->parseNumber("875/18"), this->precision());
|
|
}
|
|
|
|
TYPED_TEST(LinearEquationSolverTest, MatrixVectorMultiplication) {
|
|
typedef typename TestFixture::ValueType ValueType;
|
|
ASSERT_NO_THROW(storm::storage::SparseMatrixBuilder<ValueType> builder);
|
|
storm::storage::SparseMatrixBuilder<ValueType> builder;
|
|
ASSERT_NO_THROW(builder.addNextValue(0, 1, this->parseNumber("0.5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(0, 4, this->parseNumber("0.5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(1, 2, this->parseNumber("0.5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(1, 4, this->parseNumber("0.5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(2, 3, this->parseNumber("0.5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(2, 4, this->parseNumber("0.5")));
|
|
ASSERT_NO_THROW(builder.addNextValue(3, 4, this->parseNumber("1")));
|
|
ASSERT_NO_THROW(builder.addNextValue(4, 4, this->parseNumber("1")));
|
|
|
|
storm::storage::SparseMatrix<ValueType> A;
|
|
ASSERT_NO_THROW(A = builder.build());
|
|
|
|
std::vector<ValueType> x(5);
|
|
x[4] = this->parseNumber("1");
|
|
|
|
auto factory = storm::solver::GeneralLinearEquationSolverFactory<ValueType>();
|
|
auto solver = factory.create(this->env(), A);
|
|
ASSERT_NO_THROW(solver->repeatedMultiply(x, nullptr, 4));
|
|
EXPECT_NEAR(x[0], this->parseNumber("1"), this->precision());
|
|
}
|
|
}
|