Browse Source

Intermediate commit to switch workplace.

Former-commit-id: 11932e19d7
tempestpy_adaptions
dehnert 12 years ago
parent
commit
abf6f85b63
  1. 2
      CMakeLists.txt
  2. 309
      src/modelchecker/prctl/GmmxxDtmcPrctlModelChecker.h
  3. 186
      src/modelchecker/prctl/GmmxxMdpPrctlModelChecker.h
  4. 69
      src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h
  5. 205
      src/modelchecker/prctl/SparseMdpPrctlModelChecker.h
  6. 17
      src/models/AtomicPropositionsLabeling.h
  7. 26
      src/solver/AbstractLinearEquationSolver.h
  8. 175
      src/solver/AbstractNondeterministicLinearEquationSolver.h
  9. 228
      src/solver/GmmxxLinearEquationSolver.h
  10. 122
      src/solver/GmmxxNondeterministicLinearEquationSolver.h
  11. 20
      src/storage/BitVector.h
  12. 9
      src/storm.cpp
  13. 10
      src/utility/Settings.cpp
  14. 10
      src/utility/Settings.h
  15. 17
      src/utility/vector.h

2
CMakeLists.txt

@ -141,6 +141,7 @@ file(GLOB_RECURSE STORM_STORAGE_FILES ${PROJECT_SOURCE_DIR}/src/storage/*.h ${PR
file(GLOB_RECURSE STORM_UTILITY_FILES ${PROJECT_SOURCE_DIR}/src/utility/*.h ${PROJECT_SOURCE_DIR}/src/utility/*.cpp)
file(GLOB STORM_IR_FILES ${PROJECT_SOURCE_DIR}/src/ir/*.h ${PROJECT_SOURCE_DIR}/src/ir/*.cpp)
file(GLOB_RECURSE STORM_IR_EXPRESSIONS_FILES ${PROJECT_SOURCE_DIR}/src/ir/expressions/*.h ${PROJECT_SOURCE_DIR}/src/ir/expressions/*.cpp)
file(GLOB_RECURSE STORM_SOLVER_FILES ${PROJECT_SOURCE_DIR}/src/solver/*.h ${PROJECT_SOURCE_DIR}/src/solver/*.cpp)
# Test Sources
# Note that the tests also need the source files, except for the main file
@ -164,6 +165,7 @@ source_group(storage FILES ${STORM_STORAGE_FILES})
source_group(utility FILES ${STORM_UTILITY_FILES})
source_group(ir FILES ${STORM_IR_FILES})
source_group(ir\\expressions FILES ${STORM_IR_EXPRESSIONS_FILES})
source_group(solver FILES ${STORM_SOLVER_FILES})
source_group(functional-test FILES ${STORM_FUNCTIONAL_TEST_FILES})
source_group(performance-test FILES ${STORM_PERFORMANCE_TEST_FILES})

309
src/modelchecker/prctl/GmmxxDtmcPrctlModelChecker.h

@ -1,309 +0,0 @@
/*
* GmmxxDtmcPrctlModelChecker.h
*
* Created on: 06.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_MODELCHECKER_PRCTL_GMMXXDTMCPRCTLMODELCHECKER_H_
#define STORM_MODELCHECKER_PRCTL_GMMXXDTMCPRCTLMODELCHECKER_H_
#include "src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h"
#include "src/adapters/GmmxxAdapter.h"
#include "src/storage/SparseMatrix.h"
#include "src/utility/ConstTemplates.h"
#include "src/utility/Settings.h"
#include "gmm/gmm_matrix.h"
#include "gmm/gmm_iter_solvers.h"
#include <cmath>
namespace storm {
namespace modelchecker {
namespace prctl {
/*
* An implementation of the SparseDtmcPrctlModelChecker interface that uses gmm++ as the solving backend.
*/
template <class Type>
class GmmxxDtmcPrctlModelChecker : public SparseDtmcPrctlModelChecker<Type> {
public:
/*!
* Constructs a GmmxxDtmcPrctlModelChecker with the given model.
*
* @param model The DTMC to be checked.
*/
explicit GmmxxDtmcPrctlModelChecker(storm::models::Dtmc<Type> const& dtmc) : SparseDtmcPrctlModelChecker<Type>(dtmc) {
// Intentionally left empty.
}
/*!
* Copy constructs a GmmxxDtmcPrctlModelChecker from the given model checker. In particular, this means that the newly
* constructed model checker will have the model of the given model checker as its associated model.
*/
explicit GmmxxDtmcPrctlModelChecker(storm::modelchecker::prctl::GmmxxDtmcPrctlModelChecker<Type> const& modelchecker) : SparseDtmcPrctlModelChecker<Type>(modelchecker) {
// Intentionally left empty.
}
/*!
* Virtual destructor. Needs to be virtual, because this class has virtual methods.
*/
virtual ~GmmxxDtmcPrctlModelChecker() {
// Intentionally left empty.
}
/*!
* Returns the name of this module.
* @returns The name of this module.
*/
static std::string getModuleName() {
return "gmm++det";
}
/*!
* Returns a trigger such that if the option "matrixlib" is set to "gmm++", this model checker
* is to be used.
* @returns An option trigger for this module.
*/
static std::pair<std::string, std::string> getOptionTrigger() {
return std::pair<std::string, std::string>("matrixlib", "gmm++");
}
/*!
* Registers all options associated with the gmm++ matrix library.
*/
static void putOptions(boost::program_options::options_description* desc) {
desc->add_options()("lemethod", boost::program_options::value<std::string>()->default_value("bicgstab")->notifier(&validateLeMethod), "Sets the method used for linear equation solving. Must be in {bicgstab, qmr, jacobi}.");
desc->add_options()("maxiter", boost::program_options::value<unsigned>()->default_value(10000), "Sets the maximal number of iterations for iterative equation solving.");
desc->add_options()("precision", boost::program_options::value<double>()->default_value(1e-6), "Sets the precision for iterative equation solving.");
desc->add_options()("precond", boost::program_options::value<std::string>()->default_value("ilu")->notifier(&validatePreconditioner), "Sets the preconditioning technique for linear equation solving. Must be in {ilu, diagonal, ildlt, none}.");
desc->add_options()("relative", boost::program_options::value<bool>()->default_value(true), "Sets whether the relative or absolute error is considered for detecting convergence.");
}
/*!
* Validates whether the given lemethod matches one of the available ones.
* Throws an exception of type InvalidSettings in case the selected method is illegal.
*/
static void validateLeMethod(const std::string& lemethod) {
if ((lemethod != "bicgstab") && (lemethod != "qmr") && (lemethod != "jacobi")) {
throw exceptions::InvalidSettingsException() << "Argument " << lemethod << " for option 'lemethod' is invalid.";
}
}
/*!
* Validates whether the given preconditioner matches one of the available ones.
* Throws an exception of type InvalidSettings in case the selected preconditioner is illegal.
*/
static void validatePreconditioner(const std::string& preconditioner) {
if ((preconditioner != "ilu") && (preconditioner != "diagonal") && (preconditioner != "ildlt") && (preconditioner != "none")) {
throw exceptions::InvalidSettingsException() << "Argument " << preconditioner << " for option 'precond' is invalid.";
}
}
private:
virtual void performMatrixVectorMultiplication(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type>* b, uint_fast64_t n = 1) const {
// Transform the transition probability A to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
// Set up some temporary variables so that we can just swap pointers instead of copying the result after each
// iteration.
std::vector<Type>* swap = nullptr;
std::vector<Type>* currentVector = &x;
std::vector<Type>* tmpVector = new std::vector<Type>(this->getModel().getNumberOfStates());
// Now perform matrix-vector multiplication as long as we meet the bound.
for (uint_fast64_t i = 0; i < n; ++i) {
gmm::mult(*gmmxxMatrix, *currentVector, *tmpVector);
swap = tmpVector;
tmpVector = currentVector;
currentVector = swap;
// If requested, add an offset to the current result vector.
if (b != nullptr) {
gmm::add(*b, *currentVector);
}
}
// If we performed an odd number of repetitions, we need to swap the contents of currentVector and x, because
// the output is supposed to be stored in x.
if (n % 2 == 1) {
std::swap(x, *currentVector);
delete currentVector;
} else {
delete tmpVector;
}
delete gmmxxMatrix;
}
virtual void solveEquationSystem(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b) const {
// Get the settings object to customize linear solving.
storm::settings::Settings* s = storm::settings::instance();
// Prepare an iteration object that determines the accuracy, maximum number of iterations
// and the like.
gmm::iteration iter(s->get<double>("precision"), 0, s->get<unsigned>("maxiter"));
// Print some information about the used preconditioner.
const std::string& precond = s->getString("precond");
LOG4CPLUS_INFO(logger, "Starting iterative solver.");
if (s->getString("lemethod") == "jacobi") {
if (precond != "none") {
LOG4CPLUS_WARN(logger, "Requested preconditioner '" << precond << "', which is unavailable for the Jacobi method. Dropping preconditioner.");
}
} else {
if (precond == "ilu") {
LOG4CPLUS_INFO(logger, "Using ILU preconditioner.");
} else if (precond == "diagonal") {
LOG4CPLUS_INFO(logger, "Using diagonal preconditioner.");
} else if (precond == "ildlt") {
LOG4CPLUS_INFO(logger, "Using ILDLT preconditioner.");
} else if (precond == "none") {
LOG4CPLUS_INFO(logger, "Using no preconditioner.");
}
}
// Now do the actual solving.
if (s->getString("lemethod") == "bicgstab") {
LOG4CPLUS_INFO(logger, "Using BiCGStab method.");
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmA = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
if (precond == "ilu") {
gmm::bicgstab(*gmmA, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "diagonal") {
gmm::bicgstab(*gmmA, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "ildlt") {
gmm::bicgstab(*gmmA, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "none") {
gmm::bicgstab(*gmmA, x, b, gmm::identity_matrix(), iter);
}
// Check if the solver converged and issue a warning otherwise.
if (iter.converged()) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iter.get_iteration() << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
delete gmmA;
} else if (s->getString("lemethod") == "qmr") {
LOG4CPLUS_INFO(logger, "Using QMR method.");
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmA = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
if (precond == "ilu") {
gmm::qmr(*gmmA, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "diagonal") {
gmm::qmr(*gmmA, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "ildlt") {
gmm::qmr(*gmmA, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "none") {
gmm::qmr(*gmmA, x, b, gmm::identity_matrix(), iter);
}
// Check if the solver converged and issue a warning otherwise.
if (iter.converged()) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iter.get_iteration() << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
delete gmmA;
} else if (s->getString("lemethod") == "jacobi") {
LOG4CPLUS_INFO(logger, "Using Jacobi method.");
uint_fast64_t iterations = solveLinearEquationSystemWithJacobi(A, x, b);
// Check if the solver converged and issue a warning otherwise.
if (iterations < s->get<unsigned>("maxiter")) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iterations << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
}
}
/*!
* Solves the linear equation system A*x = b given by the parameters using the Jacobi method.
*
* @param A The matrix specifying the coefficients of the linear equations.
* @param x The solution vector x. The initial values of x represent a guess of the real values to the solver, but
* may be ignored.
* @param b The right-hand side of the equation system.
* @returns The solution vector x of the system of linear equations as the content of the parameter x.
* @returns The number of iterations needed until convergence.
*/
uint_fast64_t solveLinearEquationSystemWithJacobi(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b) const {
// Get the settings object to customize linear solving.
storm::settings::Settings* s = storm::settings::instance();
double precision = s->get<double>("precision");
uint_fast64_t maxIterations = s->get<unsigned>("maxiter");
bool relative = s->get<bool>("relative");
// Get a Jacobi decomposition of the matrix A.
storm::storage::SparseMatrix<Type>::SparseJacobiDecomposition_t jacobiDecomposition = A.getJacobiDecomposition();
// Convert the (inverted) diagonal matrix to gmm++'s format.
gmm::csr_matrix<Type>* gmmxxDiagonalInverted = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(std::move(jacobiDecomposition.second));
// Convert the LU matrix to gmm++'s format.
gmm::csr_matrix<Type>* gmmxxLU = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(std::move(jacobiDecomposition.first));
LOG4CPLUS_INFO(logger, "Starting iterative Jacobi Solver.");
// x_(k + 1) = D^-1 * (b - R * x_k)
// In x we keep a copy of the result for swapping in the loop (e.g. less copy-back).
std::vector<Type>* xNext = new std::vector<Type>(x.size());
const std::vector<Type>* xCopy = xNext;
std::vector<Type>* xCurrent = &x;
// Target vector for precision calculation.
std::vector<Type>* residuum = new std::vector<Type>(x.size());
// Set up additional environment variables.
uint_fast64_t iterationCount = 0;
bool converged = false;
while (!converged && iterationCount < maxIterations) {
// R * x_k (xCurrent is x_k) -> xNext
gmm::mult(*gmmxxLU, *xCurrent, *xNext);
// b - R * x_k (xNext contains R * x_k) -> xNext
gmm::add(b, gmm::scaled(*xNext, -1.0), *xNext);
// D^-1 * (b - R * x_k) -> xNext
gmm::mult(*gmmxxDiagonalInverted, *xNext, *xNext);
// Swap xNext with xCurrent so that the next iteration can use xCurrent again without having to copy the
// vector.
std::vector<Type> *const swap = xNext;
xNext = xCurrent;
xCurrent = swap;
// Now check if the process already converged within our precision.
converged = storm::utility::vector::equalModuloPrecision(*xCurrent, *xNext, precision, relative);
// Increase iteration count so we can abort if convergence is too slow.
++iterationCount;
}
// If the last iteration did not write to the original x we have to swap the contents, because the output has to
// be written to the parameter x.
if (xCurrent == xCopy) {
std::swap(x, *xCurrent);
}
// As xCopy always points to the copy of x used for swapping, we can safely delete it.
delete xCopy;
// Also delete the other dynamically allocated variables.
delete residuum;
delete gmmxxDiagonalInverted;
delete gmmxxLU;
return iterationCount;
}
};
} // namespace prctl
} // namespace modelchecker
} // namespace storm
#endif /* STORM_MODELCHECKER_PRCTL_GMMXXDTMCPRCTLMODELCHECKER_H_ */

186
src/modelchecker/prctl/GmmxxMdpPrctlModelChecker.h

@ -1,186 +0,0 @@
/*
* GmmxxDtmcPrctlModelChecker.h
*
* Created on: 06.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_MODELCHECKER_PRCTL_GMMXXMDPPRCTLMODELCHECKER_H_
#define STORM_MODELCHECKER_PRCTL_GMMXXMDPPRCTLMODELCHECKER_H_
#include "src/modelchecker/prctl/SparseMdpPrctlModelChecker.h"
#include "src/adapters/GmmxxAdapter.h"
#include "gmm/gmm_matrix.h"
#include "gmm/gmm_iter_solvers.h"
#include <cmath>
namespace storm {
namespace modelchecker {
namespace prctl {
/*
* An implementation of the SparseMdpPrctlModelChecker interface that uses gmm++ as the solving backend.
*/
template <class Type>
class GmmxxMdpPrctlModelChecker : public SparseMdpPrctlModelChecker<Type> {
public:
/*!
* Constructs a GmmxxMdpPrctlModelChecker with the given model.
*
* @param model The MDP to be checked.
*/
explicit GmmxxMdpPrctlModelChecker(storm::models::Mdp<Type> const& model) : SparseMdpPrctlModelChecker<Type>(model) {
// Intentionally left empty.
}
/*!
* Copy constructs a GmmxxDtmcPrctlModelChecker from the given model checker. In particular, this means that the newly
* constructed model checker will have the model of the given model checker as its associated model.
*/
explicit GmmxxMdpPrctlModelChecker(storm::modelchecker::prctl::GmmxxMdpPrctlModelChecker<Type> const& modelchecker) : SparseMdpPrctlModelChecker<Type>(modelchecker) {
// Intentionally left empty.
}
/*!
* Virtual destructor. Needs to be virtual, because this class has virtual methods.
*/
virtual ~GmmxxMdpPrctlModelChecker() {
// Intentionally left empty.
}
private:
/*!
* Performs (repeated) matrix-vector multiplication with the given parameters, i.e. computes x[i+1] = A*x[i] + b
* until x[n], where x[0] = x.
*
* @param A The matrix that is to be multiplied against the vector.
* @param x The initial vector that is to be multiplied against the matrix. This is also the output parameter,
* i.e. after the method returns, this vector will contain the computed values.
* @param nondeterministicChoiceIndices The assignment of states to their rows in the matrix.
* @param b If not null, this vector is being added to the result after each matrix-vector multiplication.
* @param n Specifies the number of iterations the matrix-vector multiplication is performed.
* @returns The result of the repeated matrix-vector multiplication as the content of the parameter vector.
*/
virtual void performMatrixVectorMultiplication(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<Type>* b = nullptr, uint_fast64_t n = 1) const {
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
// Create vector for result of multiplication, which is reduced to the result vector after
// each multiplication.
std::vector<Type> multiplyResult(A.getRowCount());
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
for (uint_fast64_t i = 0; i < n; ++i) {
gmm::mult(*gmmxxMatrix, x, multiplyResult);
if (b != nullptr) {
gmm::add(*b, multiplyResult);
}
if (this->minimumOperatorStack.top()) {
storm::utility::vector::reduceVectorMin(multiplyResult, x, nondeterministicChoiceIndices);
} else {
storm::utility::vector::reduceVectorMax(multiplyResult, x, nondeterministicChoiceIndices);
}
}
// Delete intermediate results and return result.
delete gmmxxMatrix;
}
/*!
* Solves the given equation system under the given parameters using the power method.
*
* @param minimize If set, all choices are resolved such that the solution value becomes minimal and maximal otherwise.
* @param A The matrix A specifying the coefficients of the equations.
* @param x The vector x for which to solve the equations. The initial value of the elements of
* this vector are used as the initial guess and might thus influence performance and convergence.
* @param b The vector b specifying the values on the right-hand-sides of the equations.
* @return The solution of the system of linear equations in form of the elements of the vector
* x.
*/
void solveEquationSystem(bool minimize, storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<uint_fast64_t>* takenChoices = nullptr) const override {
// Get the settings object to customize solving.
storm::settings::Settings* s = storm::settings::instance();
// Get relevant user-defined settings for solving the equations.
double precision = s->get<double>("precision");
unsigned maxIterations = s->get<unsigned>("maxiter");
bool relative = s->get<bool>("relative");
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
// Set up the environment for the power method.
std::vector<Type> multiplyResult(A.getRowCount());
std::vector<Type>* currentX = &x;
std::vector<Type>* newX = new std::vector<Type>(x.size());
std::vector<Type>* swap = nullptr;
uint_fast64_t iterations = 0;
bool converged = false;
// Proceed with the iterations as long as the method did not converge or reach the user-specified maximum number
// of iterations.
while (!converged && iterations < maxIterations) {
std::cout << "iter: " << iterations << std::endl;
// Compute x' = A*x + b.
gmm::mult(*gmmxxMatrix, *currentX, multiplyResult);
gmm::add(b, multiplyResult);
// Reduce the vector x' by applying min/max for all non-deterministic choices.
if (minimize) {
storm::utility::vector::reduceVectorMin(multiplyResult, *newX, nondeterministicChoiceIndices);
} else {
storm::utility::vector::reduceVectorMax(multiplyResult, *newX, nondeterministicChoiceIndices);
}
// Determine whether the method converged.
converged = storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative);
if (!converged) {
for (uint_fast64_t i = 0; i < newX->size(); ++i) {
std::cout << (*currentX)[i] << " vs. " << (*newX)[i] << std::endl;
}
}
// Update environment variables.
swap = currentX;
currentX = newX;
newX = swap;
++iterations;
}
// If we were requested to record the taken choices, we have to construct the vector now.
if (takenChoices != nullptr) {
this->computeTakenChoices(minimize, multiplyResult, *takenChoices, nondeterministicChoiceIndices);
}
// If we performed an odd number of iterations, we need to swap the x and currentX, because the newest result
// is currently stored in currentX, but x is the output vector.
if (iterations % 2 == 1) {
std::swap(x, *currentX);
delete currentX;
} else {
delete newX;
}
delete gmmxxMatrix;
// Check if the solver converged and issue a warning otherwise.
if (converged) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iterations << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge after " << iterations << " iterations.");
}
}
};
} //namespace prctl
} //namespace modelchecker
} //namespace storm
#endif /* STORM_MODELCHECKER_PRCTL_GMMXXMDPPRCTLMODELCHECKER_H_ */

69
src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h

@ -10,6 +10,7 @@
#include "src/modelchecker/prctl/AbstractModelChecker.h"
#include "src/models/Dtmc.h"
#include "src/solver/AbstractLinearEquationSolver.h"
#include "src/utility/vector.h"
#include "src/utility/graph.h"
@ -26,21 +27,22 @@ namespace prctl {
template<class Type>
class SparseDtmcPrctlModelChecker : public AbstractModelChecker<Type> {
public:
/*!
* Constructs a SparseDtmcPrctlModelChecker with the given model.
*
* @param model The DTMC to be checked.
*/
explicit SparseDtmcPrctlModelChecker(storm::models::Dtmc<Type> const& model) : AbstractModelChecker<Type>(model) {
explicit SparseDtmcPrctlModelChecker(storm::models::Dtmc<Type> const& model, storm::solver::AbstractLinearEquationSolver<Type>* linearEquationSolver) : AbstractModelChecker<Type>(model), linearEquationSolver(linearEquationSolver) {
// Intentionally left empty.
}
public:
/*!
* Copy constructs a SparseDtmcPrctlModelChecker from the given model checker. In particular, this means that the newly
* constructed model checker will have the model of the given model checker as its associated model.
*/
explicit SparseDtmcPrctlModelChecker(storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<Type> const& modelChecker) : AbstractModelChecker<Type>(modelChecker) {
explicit SparseDtmcPrctlModelChecker(storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<Type> const& modelChecker) : AbstractModelChecker<Type>(modelChecker), linearEquationSolver(modelChecker.linearEquationSolver->clone()) {
// Intentionally left empty.
}
@ -120,7 +122,11 @@ public:
storm::utility::vector::setVectorValues(subresult, rightStatesInReducedSystem, storm::utility::constGetOne<Type>());
// Perform the matrix vector multiplication as often as required by the formula bound.
this->performMatrixVectorMultiplication(submatrix, subresult, nullptr, formula.getBound());
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(submatrix, subresult, nullptr, formula.getBound());
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Set the values of the resulting vector accordingly.
storm::utility::vector::setVectorValues(*result, statesWithProbabilityGreater0, subresult);
@ -156,7 +162,11 @@ public:
delete nextStates;
// Perform one single matrix-vector multiplication.
this->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result);
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result);
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Return result.
return result;
@ -282,7 +292,11 @@ public:
std::vector<Type> b = this->getModel().getTransitionMatrix().getConstrainedRowSumVector(maybeStates, statesWithProbability1);
// Now solve the created system of linear equations.
this->solveEquationSystem(submatrix, x, b);
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->solveEquationSystem(submatrix, x, b);
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Set values of resulting vector according to result.
storm::utility::vector::setVectorValues<Type>(*result, maybeStates, x);
@ -317,7 +331,11 @@ public:
std::vector<Type>* result = new std::vector<Type>(this->getModel().getStateRewardVector());
// Perform the actual matrix-vector multiplication as long as the bound of the formula is met.
this->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result, nullptr, formula.getBound());
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result, nullptr, formula.getBound());
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Return result.
return result;
@ -361,7 +379,11 @@ public:
}
// Perform the actual matrix-vector multiplication as long as the bound of the formula is met.
this->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result, &totalRewardVector, formula.getBound());
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result, &totalRewardVector, formula.getBound());
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Return result.
return result;
@ -448,7 +470,11 @@ public:
}
// Now solve the resulting equation system.
this->solveEquationSystem(submatrix, x, b);
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->solveEquationSystem(submatrix, x, b);
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Set values of resulting vector according to result.
storm::utility::vector::setVectorValues<Type>(*result, maybeStates, x);
@ -464,29 +490,8 @@ public:
}
private:
/*!
* Performs (repeated) matrix-vector multiplication with the given parameters, i.e. computes x[i+1] = A*x[i] + b
* until x[n], where x[0] = x.
*
* @param A The matrix that is to be multiplied against the vector.
* @param x The initial vector that is to be multiplied against the matrix. This is also the output parameter,
* i.e. after the method returns, this vector will contain the computed values.
* @param b If not null, this vector is being added to the result after each matrix-vector multiplication.
* @param n Specifies the number of iterations the matrix-vector multiplication is performed.
* @returns The result of the repeated matrix-vector multiplication as the content of the parameter vector.
*/
virtual void performMatrixVectorMultiplication(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type>* b = nullptr, uint_fast64_t n = 1) const = 0;
/*!
* Solves the equation system A*x = b given by the parameters.
*
* @param A The matrix specifying the coefficients of the linear equations.
* @param x The solution vector x. The initial values of x represent a guess of the real values to the solver, but
* may be ignored.
* @param b The right-hand side of the equation system.
* @returns The solution vector x of the system of linear equations as the content of the parameter x.
*/
virtual void solveEquationSystem(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b) const = 0;
// An object that is used for solving linear equations and performing matrix-vector multiplication.
std::unique_ptr<storm::solver::AbstractLinearEquationSolver<Type>> linearEquationSolver;
};
} // namespace prctl

205
src/modelchecker/prctl/SparseMdpPrctlModelChecker.h

@ -10,6 +10,7 @@
#include "src/modelchecker/prctl/AbstractModelChecker.h"
#include "src/modelchecker/prctl/GmmxxDtmcPrctlModelChecker.h"
#include "src/solver/AbstractNondeterministicLinearEquationSolver.h"
#include "src/models/Mdp.h"
#include "src/utility/vector.h"
#include "src/utility/graph.h"
@ -22,8 +23,7 @@ namespace modelchecker {
namespace prctl {
/*!
* @brief
* Interface for all model checkers that can verify PRCTL formulae over MDPs represented as a sparse matrix.
* This class represents the base class for all PRCTL model checkers for MDPs.
*/
template<class Type>
class SparseMdpPrctlModelChecker : public AbstractModelChecker<Type> {
@ -34,7 +34,7 @@ public:
*
* @param model The MDP to be checked.
*/
explicit SparseMdpPrctlModelChecker(storm::models::Mdp<Type> const& model) : AbstractModelChecker<Type>(model), minimumOperatorStack() {
explicit SparseMdpPrctlModelChecker(storm::models::Mdp<Type> const& model, storm::solver::AbstractNondeterministicLinearEquationSolver<Type>* linearEquationSolver) : AbstractModelChecker<Type>(model), minimumOperatorStack(), linearEquationSolver(linearEquationSolver) {
// Intentionally left empty.
}
@ -43,14 +43,7 @@ public:
* constructed model checker will have the model of the given model checker as its associated model.
*/
explicit SparseMdpPrctlModelChecker(storm::modelchecker::prctl::SparseMdpPrctlModelChecker<Type> const& modelchecker)
: AbstractModelChecker<Type>(modelchecker), minimumOperatorStack() {
// Intentionally left empty.
}
/*!
* Virtual destructor. Needs to be virtual, because this class has virtual methods.
*/
virtual ~SparseMdpPrctlModelChecker() {
: AbstractModelChecker<Type>(modelchecker), minimumOperatorStack(), linearEquationSolver(new storm::solver::AbstractNondeterministicLinearEquationSolver<Type>()) {
// Intentionally left empty.
}
@ -132,7 +125,11 @@ public:
std::vector<Type> subresult(statesWithProbabilityGreater0.getNumberOfSetBits());
storm::utility::vector::setVectorValues(subresult, rightStatesInReducedSystem, storm::utility::constGetOne<Type>());
this->performMatrixVectorMultiplication(submatrix, subresult, subNondeterministicChoiceIndices, nullptr, formula.getBound());
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(this->minimumOperatorStack.top(), submatrix, subresult, subNondeterministicChoiceIndices, nullptr, formula.getBound());
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Set the values of the resulting vector accordingly.
storm::utility::vector::setVectorValues(*result, statesWithProbabilityGreater0, subresult);
@ -167,7 +164,11 @@ public:
// Delete obsolete sub-result.
delete nextStates;
this->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result, this->getModel().getNondeterministicChoiceIndices());
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(this->minimumOperatorStack.top(), this->getModel().getTransitionMatrix(), *result, this->getModel().getNondeterministicChoiceIndices());
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Return result.
return result;
@ -315,10 +316,14 @@ public:
std::vector<Type> b = this->getModel().getTransitionMatrix().getConstrainedRowSumVector(maybeStates, this->getModel().getNondeterministicChoiceIndices(), statesWithProbability1, submatrix.getRowCount());
// Create vector for results for maybe states.
std::vector<Type> x = this->getInitialValueIterationValues(submatrix, formula);
std::vector<Type> x = this->getInitialValueIterationValues(submatrix, subNondeterministicChoiceIndices, b);
// Solve the corresponding system of equations.
this->solveEquationSystem(minimize, submatrix, x, b, subNondeterministicChoiceIndices);
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->solveEquationSystem(minimize, submatrix, x, b, subNondeterministicChoiceIndices);
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Set values of resulting vector according to result.
storm::utility::vector::setVectorValues<Type>(*result, maybeStates, x);
@ -328,6 +333,11 @@ public:
storm::utility::vector::setVectorValues<Type>(*result, statesWithProbability0, storm::utility::constGetZero<Type>());
storm::utility::vector::setVectorValues<Type>(*result, statesWithProbability1, storm::utility::constGetOne<Type>());
// If we were required to generate a scheduler, do so now.
if (scheduler != nullptr) {
this->computeTakenChoices(this->minimumOperatorStack.top(), *result, *scheduler, this->getModel().getNondeterministicChoiceIndices());
}
return result;
}
@ -352,7 +362,11 @@ public:
// Initialize result to state rewards of the model.
std::vector<Type>* result = new std::vector<Type>(this->getModel().getStateRewardVector());
this->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result, this->getModel().getNondeterministicChoiceIndices(), nullptr, formula.getBound());
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(this->minimumOperatorStack.top(), this->getModel().getTransitionMatrix(), *result, this->getModel().getNondeterministicChoiceIndices(), nullptr, formula.getBound());
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Return result.
return result;
@ -395,7 +409,11 @@ public:
result = new std::vector<Type>(this->getModel().getNumberOfStates());
}
this->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), *result, this->getModel().getNondeterministicChoiceIndices(), &totalRewardVector, formula.getBound());
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(this->minimumOperatorStack.top(), this->getModel().getTransitionMatrix(), *result, this->getModel().getNondeterministicChoiceIndices(), &totalRewardVector, formula.getBound());
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Delete temporary variables and return result.
return result;
@ -504,10 +522,14 @@ public:
}
// Create vector for results for maybe states.
std::vector<Type> x = this->getInitialValueIterationValues(submatrix, formula);
std::vector<Type> x = this->getInitialValueIterationValues(submatrix, subNondeterministicChoiceIndices, b);
// Solve the corresponding system of equations.
this->solveEquationSystem(minimize, submatrix, x, b, subNondeterministicChoiceIndices, scheduler);
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->solveEquationSystem(minimize, submatrix, x, b, subNondeterministicChoiceIndices);
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}
// Set values of resulting vector according to result.
storm::utility::vector::setVectorValues<Type>(*result, maybeStates, x);
@ -517,6 +539,11 @@ public:
storm::utility::vector::setVectorValues(*result, *targetStates, storm::utility::constGetZero<Type>());
storm::utility::vector::setVectorValues(*result, infinityStates, storm::utility::constGetInfinity<Type>());
// If we were required to generate a scheduler, do so now.
if (scheduler != nullptr) {
this->computeTakenChoices(this->minimumOperatorStack.top(), *result, *scheduler, this->getModel().getNondeterministicChoiceIndices());
}
// Delete temporary storages and return result.
delete targetStates;
return result;
@ -547,121 +574,6 @@ protected:
mutable std::stack<bool> minimumOperatorStack;
private:
/*!
* Performs (repeated) matrix-vector multiplication with the given parameters, i.e. computes x[i+1] = A*x[i] + b
* until x[n], where x[0] = x.
*
* @param A The matrix that is to be multiplied against the vector.
* @param x The initial vector that is to be multiplied against the matrix. This is also the output parameter,
* i.e. after the method returns, this vector will contain the computed values.
* @param nondeterministicChoiceIndices The assignment of states to their rows in the matrix.
* @param b If not null, this vector is being added to the result after each matrix-vector multiplication.
* @param n Specifies the number of iterations the matrix-vector multiplication is performed.
* @returns The result of the repeated matrix-vector multiplication as the content of the parameter vector.
*/
virtual void performMatrixVectorMultiplication(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<Type>* b = nullptr, uint_fast64_t n = 1) const {
// Create vector for result of multiplication, which is reduced to the result vector after
// each multiplication.
std::vector<Type> multiplyResult(A.getRowCount());
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
for (uint_fast64_t i = 0; i < n; ++i) {
A.multiplyWithVector(x, multiplyResult);
// Add b if it is non-null.
if (b != nullptr) {
storm::utility::vector::addVectorsInPlace(multiplyResult, *b);
}
// Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost
// element of the min/max operator stack.
if (this->minimumOperatorStack.top()) {
storm::utility::vector::reduceVectorMin(multiplyResult, x, nondeterministicChoiceIndices);
} else {
storm::utility::vector::reduceVectorMax(multiplyResult, x, nondeterministicChoiceIndices);
}
}
}
/*!
* Solves the equation system A*x = b given by the parameters.
*
* @param minimize If set, all choices are resolved such that the solution value becomes minimal and maximal otherwise.
* @param A The matrix specifying the coefficients of the linear equations.
* @param x The solution vector x. The initial values of x represent a guess of the real values to the solver, but
* may be ignored.
* @param b The right-hand side of the equation system.
* @param nondeterministicChoiceIndices The assignment of states to their rows in the matrix.
* @param takenChoices If not null, this vector will be filled with the nondeterministic choices taken by the states
* to achieve the solution of the equation system. This assumes that the given vector has at least as many elements
* as there are states in the MDP.
* @returns The solution vector x of the system of linear equations as the content of the parameter x.
*/
virtual void solveEquationSystem(bool minimize, storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<uint_fast64_t>* takenChoices = nullptr) const {
LOG4CPLUS_INFO(logger, "Starting iterative solver.");
// Get the settings object to customize solving.
storm::settings::Settings* s = storm::settings::instance();
// Get relevant user-defined settings for solving the equations.
double precision = s->get<double>("precision");
unsigned maxIterations = s->get<unsigned>("maxiter");
bool relative = s->get<bool>("relative");
// Set up the environment for the power method.
std::vector<Type> multiplyResult(A.getRowCount());
std::vector<Type>* currentX = &x;
std::vector<Type>* newX = new std::vector<Type>(x.size());
std::vector<Type>* swap = nullptr;
uint_fast64_t iterations = 0;
bool converged = false;
// Proceed with the iterations as long as the method did not converge or reach the
// user-specified maximum number of iterations.
while (!converged && iterations < maxIterations) {
// Compute x' = A*x + b.
A.multiplyWithVector(*currentX, multiplyResult);
storm::utility::vector::addVectorsInPlace(multiplyResult, b);
// Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost
// element of the min/max operator stack.
if (minimize) {
storm::utility::vector::reduceVectorMin(multiplyResult, *newX, nondeterministicChoiceIndices);
} else {
storm::utility::vector::reduceVectorMax(multiplyResult, *newX, nondeterministicChoiceIndices);
}
// Determine whether the method converged.
converged = storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative);
// Update environment variables.
swap = currentX;
currentX = newX;
newX = swap;
++iterations;
}
// If we were requested to record the taken choices, we have to construct the vector now.
if (takenChoices != nullptr) {
this->computeTakenChoices(minimize, multiplyResult, *takenChoices, nondeterministicChoiceIndices);
}
// If we performed an odd number of iterations, we need to swap the x and currentX, because the newest result
// is currently stored in currentX, but x is the output vector.
if (iterations % 2 == 1) {
std::swap(x, *currentX);
delete currentX;
} else {
delete newX;
}
// Check if the solver converged and issue a warning otherwise.
if (converged) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iterations << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
}
/*!
* Computes the nondeterministic choice indices vector resulting from reducing the full system to the states given
@ -701,24 +613,21 @@ private:
*
* @param submatrix The matrix that will be used for value iteration later.
*/
std::vector<Type> getInitialValueIterationValues(storm::storage::SparseMatrix<Type> const& submatrix, storm::property::prctl::AbstractPathFormula<Type> const& formula) const {
std::vector<Type> getInitialValueIterationValues(storm::storage::SparseMatrix<Type> const& submatrix, std::vector<uint_fast64_t> const& subNondeterministicChoiceIndices, std::vector<Type> const& rightHandSide) const {
// std::vector<uint_fast64_t> scheduler(submatrix.getColumnCount());
std::vector<uint_fast64_t> scheduler(this->getModel().getNumberOfStates());
storm::models::Dtmc<Type> dtmc(this->getModel().getTransitionMatrix().getSubmatrix(scheduler, this->getModel().getNondeterministicChoiceIndices()),
storm::models::AtomicPropositionsLabeling(this->getModel().getStateLabeling()),
this->getModel().hasStateRewards() ? boost::optional<std::vector<Type>>(this->getModel().getStateRewardVector()) : boost::optional<std::vector<Type>>(),
this->getModel().hasTransitionRewards() ? boost::optional<storm::storage::SparseMatrix<Type>>(this->getModel().getTransitionRewardMatrix().getSubmatrix(scheduler, this->getModel().getNondeterministicChoiceIndices(), false)) : boost::optional<storm::storage::SparseMatrix<Type>>());
storm::modelchecker::prctl::GmmxxDtmcPrctlModelChecker<Type> modelChecker(dtmc);
std::vector<Type>* modelCheckingResult = formula.check(modelChecker, false);
std::vector<Type> result(std::move(*modelCheckingResult));
delete modelCheckingResult;
// std::vector<Type> result(scheduler.size(), Type(0.5));
// std::vector<Type> b(scheduler.size());
// storm::utility::vector::selectVectorValues(b, scheduler, subNondeterministicChoiceIndices, rightHandSide);
// storm::storage::SparseMatrix<Type> A(submatrix.getSubmatrix(scheduler, subNondeterministicChoiceIndices));
// A.convertToEquationSystem();
// this->solveEquationSystem(A, result, b);
std::vector<Type> result(submatrix.getColumnCount());
return result;
}
// An object that is used for solving linear equations and performing matrix-vector multiplication.
std::unique_ptr<storm::solver::AbstractNondeterministicLinearEquationSolver<Type>> linearEquationSolver;
};
} // namespace prctl

17
src/models/AtomicPropositionsLabeling.h

@ -59,6 +59,23 @@ public:
// Intentionally left empty.
}
/*!
* Copy constructor that performs a deep copy of the given atomic proposition labeling while restricting to the states
* given by the bit vector.
*
* @param atomicPropositionsLabeling The atomic propositions labeling to copy.
* @param substates A subset of the states that is to be copied.
*/
AtomicPropositionsLabeling(AtomicPropositionsLabeling const& atomicPropositionsLabeling, storm::storage::BitVector const& substates)
: stateCount(substates.getNumberOfSetBits()), apCountMax(atomicPropositionsLabeling.apCountMax), apsCurrent(atomicPropositionsLabeling.apsCurrent),
nameToLabelingMap(atomicPropositionsLabeling.nameToLabelingMap) {
// Now we need to copy the fraction of the single labelings given by the substates.
singleLabelings.reserve(apCountMax);
for (auto const& labeling : atomicPropositionsLabeling.singleLabelings) {
singleLabelings.emplace_back(labeling, substates);
}
}
/*!
* Move Constructor that performs a move copy on the given atomic proposition labeling.
*

26
src/solver/AbstractLinearEquationSolver.h

@ -0,0 +1,26 @@
#ifndef STORM_SOLVER_ABSTRACTLINEAREQUATIONSOLVER_H_
#define STORM_SOLVER_ABSTRACTLINEAREQUATIONSOLVER_H_
#include "src/storage/SparseMatrix.h"
#include <vector>
namespace storm {
namespace solver {
template<class Type>
class AbstractLinearEquationSolver {
public:
virtual AbstractLinearEquationSolver<Type>* clone() const = 0;
virtual void solveEquationSystem(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b) const = 0;
virtual void performMatrixVectorMultiplication(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type>* b = nullptr, uint_fast64_t n = 1) const = 0;
};
} // namespace solver
} // namespace storm
#endif /* STORM_SOLVER_ABSTRACTLINEAREQUATIONSOLVER_H_ */

175
src/solver/AbstractNondeterministicLinearEquationSolver.h

@ -0,0 +1,175 @@
#ifndef STORM_SOLVER_ABSTRACTNONDETERMINISTICLINEAREQUATIONSOLVER_H_
#define STORM_SOLVER_ABSTRACTNONDETERMINISTICLINEAREQUATIONSOLVER_H_
#include "src/storage/SparseMatrix.h"
#include <vector>
namespace storm {
namespace solver {
template<class Type>
class AbstractNondeterministicLinearEquationSolver {
public:
virtual AbstractNondeterministicLinearEquationSolver<Type>* clone() const {
return new AbstractNondeterministicLinearEquationSolver<Type>();
}
/*!
* Solves the equation system A*x = b given by the parameters.
*
* @param minimize If set, all choices are resolved such that the solution value becomes minimal and maximal otherwise.
* @param A The matrix specifying the coefficients of the linear equations.
* @param x The solution vector x. The initial values of x represent a guess of the real values to the solver, but
* may be ignored.
* @param b The right-hand side of the equation system.
* @param nondeterministicChoiceIndices The assignment of states to their rows in the matrix.
* @param takenChoices If not null, this vector will be filled with the nondeterministic choices taken by the states
* to achieve the solution of the equation system. This assumes that the given vector has at least as many elements
* as there are states in the MDP.
* @returns The solution vector x of the system of linear equations as the content of the parameter x.
*/
virtual void solveEquationSystem(bool minimize, storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices) const {
LOG4CPLUS_INFO(logger, "Starting iterative solver.");
// Get the settings object to customize solving.
storm::settings::Settings* s = storm::settings::instance();
// Get relevant user-defined settings for solving the equations.
double precision = s->get<double>("precision");
unsigned maxIterations = s->get<unsigned>("maxiter");
bool relative = s->get<bool>("relative");
// Set up the environment for the power method.
std::vector<Type> multiplyResult(A.getRowCount());
std::vector<Type>* currentX = &x;
std::vector<Type>* newX = new std::vector<Type>(x.size());
std::vector<Type>* swap = nullptr;
uint_fast64_t iterations = 0;
bool converged = false;
// Proceed with the iterations as long as the method did not converge or reach the
// user-specified maximum number of iterations.
while (!converged && iterations < maxIterations) {
// Compute x' = A*x + b.
A.multiplyWithVector(*currentX, multiplyResult);
storm::utility::vector::addVectorsInPlace(multiplyResult, b);
// Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost
// element of the min/max operator stack.
if (minimize) {
storm::utility::vector::reduceVectorMin(multiplyResult, *newX, nondeterministicChoiceIndices);
} else {
storm::utility::vector::reduceVectorMax(multiplyResult, *newX, nondeterministicChoiceIndices);
}
// Determine whether the method converged.
converged = storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative);
// Update environment variables.
swap = currentX;
currentX = newX;
newX = swap;
++iterations;
}
// If we performed an odd number of iterations, we need to swap the x and currentX, because the newest result
// is currently stored in currentX, but x is the output vector.
if (iterations % 2 == 1) {
std::swap(x, *currentX);
delete currentX;
} else {
delete newX;
}
// Check if the solver converged and issue a warning otherwise.
if (converged) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iterations << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
}
/*!
* Performs (repeated) matrix-vector multiplication with the given parameters, i.e. computes x[i+1] = A*x[i] + b
* until x[n], where x[0] = x.
*
* @param minimize If set, all choices are resolved such that the solution value becomes minimal and maximal otherwise.
* @param A The matrix that is to be multiplied against the vector.
* @param x The initial vector that is to be multiplied against the matrix. This is also the output parameter,
* i.e. after the method returns, this vector will contain the computed values.
* @param nondeterministicChoiceIndices The assignment of states to their rows in the matrix.
* @param b If not null, this vector is being added to the result after each matrix-vector multiplication.
* @param n Specifies the number of iterations the matrix-vector multiplication is performed.
* @returns The result of the repeated matrix-vector multiplication as the content of the parameter vector.
*/
virtual void performMatrixVectorMultiplication(bool minimize, storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<Type>* b = nullptr, uint_fast64_t n = 1) const {
// Create vector for result of multiplication, which is reduced to the result vector after
// each multiplication.
std::vector<Type> multiplyResult(A.getRowCount());
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
for (uint_fast64_t i = 0; i < n; ++i) {
A.multiplyWithVector(x, multiplyResult);
// Add b if it is non-null.
if (b != nullptr) {
storm::utility::vector::addVectorsInPlace(multiplyResult, *b);
}
// Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost
// element of the min/max operator stack.
if (minimize) {
storm::utility::vector::reduceVectorMin(multiplyResult, x, nondeterministicChoiceIndices);
} else {
storm::utility::vector::reduceVectorMax(multiplyResult, x, nondeterministicChoiceIndices);
}
}
}
/*!
* Returns the name of this solver.
*
* @returns The name of this solver.
*/
static std::string getName() {
return "native";
}
/*!
* Registers all options associated with the gmm++ matrix library.
*/
static void putOptions(boost::program_options::options_description* desc) {
desc->add_options()("lemethod", boost::program_options::value<std::string>()->default_value("bicgstab")->notifier(&validateLeMethod), "Sets the method used for linear equation solving. Must be in {bicgstab, qmr, jacobi}.");
desc->add_options()("maxiter", boost::program_options::value<unsigned>()->default_value(10000), "Sets the maximal number of iterations for iterative equation solving.");
desc->add_options()("precision", boost::program_options::value<double>()->default_value(1e-6), "Sets the precision for iterative equation solving.");
desc->add_options()("precond", boost::program_options::value<std::string>()->default_value("ilu")->notifier(&validatePreconditioner), "Sets the preconditioning technique for linear equation solving. Must be in {ilu, diagonal, ildlt, none}.");
desc->add_options()("relative", boost::program_options::value<bool>()->default_value(true), "Sets whether the relative or absolute error is considered for detecting convergence.");
}
/*!
* Validates whether the given lemethod matches one of the available ones.
* Throws an exception of type InvalidSettings in case the selected method is illegal.
*/
static void validateLeMethod(const std::string& lemethod) {
if ((lemethod != "bicgstab") && (lemethod != "qmr") && (lemethod != "jacobi")) {
throw exceptions::InvalidSettingsException() << "Argument " << lemethod << " for option 'lemethod' is invalid.";
}
}
/*!
* Validates whether the given preconditioner matches one of the available ones.
* Throws an exception of type InvalidSettings in case the selected preconditioner is illegal.
*/
static void validatePreconditioner(const std::string& preconditioner) {
if ((preconditioner != "ilu") && (preconditioner != "diagonal") && (preconditioner != "ildlt") && (preconditioner != "none")) {
throw exceptions::InvalidSettingsException() << "Argument " << preconditioner << " for option 'precond' is invalid.";
}
}
};
} // namespace solver
} // namespace storm
#endif /* STORM_SOLVER_ABSTRACTNONDETERMINISTICLINEAREQUATIONSOLVER_H_ */

228
src/solver/GmmxxLinearEquationSolver.h

@ -0,0 +1,228 @@
#ifndef STORM_SOLVER_GMMXXLINEAREQUATIONSOLVER_H_
#define STORM_SOLVER_GMMXXLINEAREQUATIONSOLVER_H_
#include "AbstractLinearEquationSolver.h"
#include "src/adapters/GmmxxAdapter.h"
#include "src/utility/ConstTemplates.h"
#include "src/utility/Settings.h"
#include "gmm/gmm_matrix.h"
#include "gmm/gmm_iter_solvers.h"
#include <cmath>
namespace storm {
namespace solver {
template<class Type>
class GmmxxLinearEquationSolver : public AbstractLinearEquationSolver<Type> {
public:
virtual AbstractLinearEquationSolver<Type>* clone() const {
return new GmmxxLinearEquationSolver<Type>();
}
virtual void solveEquationSystem(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b) const {
// Get the settings object to customize linear solving.
storm::settings::Settings* s = storm::settings::instance();
// Prepare an iteration object that determines the accuracy, maximum number of iterations
// and the like.
gmm::iteration iter(s->get<double>("precision"), 0, s->get<unsigned>("maxiter"));
// Print some information about the used preconditioner.
const std::string& precond = s->getString("precond");
LOG4CPLUS_INFO(logger, "Starting iterative solver.");
if (s->getString("lemethod") == "jacobi") {
if (precond != "none") {
LOG4CPLUS_WARN(logger, "Requested preconditioner '" << precond << "', which is unavailable for the Jacobi method. Dropping preconditioner.");
}
} else {
if (precond == "ilu") {
LOG4CPLUS_INFO(logger, "Using ILU preconditioner.");
} else if (precond == "diagonal") {
LOG4CPLUS_INFO(logger, "Using diagonal preconditioner.");
} else if (precond == "ildlt") {
LOG4CPLUS_INFO(logger, "Using ILDLT preconditioner.");
} else if (precond == "none") {
LOG4CPLUS_INFO(logger, "Using no preconditioner.");
}
}
// Now do the actual solving.
if (s->getString("lemethod") == "bicgstab") {
LOG4CPLUS_INFO(logger, "Using BiCGStab method.");
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmA = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
if (precond == "ilu") {
gmm::bicgstab(*gmmA, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "diagonal") {
gmm::bicgstab(*gmmA, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "ildlt") {
gmm::bicgstab(*gmmA, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "none") {
gmm::bicgstab(*gmmA, x, b, gmm::identity_matrix(), iter);
}
// Check if the solver converged and issue a warning otherwise.
if (iter.converged()) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iter.get_iteration() << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
delete gmmA;
} else if (s->getString("lemethod") == "qmr") {
LOG4CPLUS_INFO(logger, "Using QMR method.");
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmA = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
if (precond == "ilu") {
gmm::qmr(*gmmA, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "diagonal") {
gmm::qmr(*gmmA, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "ildlt") {
gmm::qmr(*gmmA, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(*gmmA), iter);
} else if (precond == "none") {
gmm::qmr(*gmmA, x, b, gmm::identity_matrix(), iter);
}
// Check if the solver converged and issue a warning otherwise.
if (iter.converged()) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iter.get_iteration() << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
delete gmmA;
} else if (s->getString("lemethod") == "jacobi") {
LOG4CPLUS_INFO(logger, "Using Jacobi method.");
uint_fast64_t iterations = solveLinearEquationSystemWithJacobi(A, x, b);
// Check if the solver converged and issue a warning otherwise.
if (iterations < s->get<unsigned>("maxiter")) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iterations << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
}
}
virtual void performMatrixVectorMultiplication(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type>* b, uint_fast64_t n = 1) const {
// Transform the transition probability A to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
// Set up some temporary variables so that we can just swap pointers instead of copying the result after each
// iteration.
std::vector<Type>* swap = nullptr;
std::vector<Type>* currentVector = &x;
std::vector<Type>* tmpVector = new std::vector<Type>(A.getRowCount());
// Now perform matrix-vector multiplication as long as we meet the bound.
for (uint_fast64_t i = 0; i < n; ++i) {
gmm::mult(*gmmxxMatrix, *currentVector, *tmpVector);
swap = tmpVector;
tmpVector = currentVector;
currentVector = swap;
// If requested, add an offset to the current result vector.
if (b != nullptr) {
gmm::add(*b, *currentVector);
}
}
// If we performed an odd number of repetitions, we need to swap the contents of currentVector and x, because
// the output is supposed to be stored in x.
if (n % 2 == 1) {
std::swap(x, *currentVector);
delete currentVector;
} else {
delete tmpVector;
}
delete gmmxxMatrix;
}
private:
/*!
* Solves the linear equation system A*x = b given by the parameters using the Jacobi method.
*
* @param A The matrix specifying the coefficients of the linear equations.
* @param x The solution vector x. The initial values of x represent a guess of the real values to the solver, but
* may be ignored.
* @param b The right-hand side of the equation system.
* @returns The solution vector x of the system of linear equations as the content of the parameter x.
* @returns The number of iterations needed until convergence.
*/
uint_fast64_t solveLinearEquationSystemWithJacobi(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b) const {
// Get the settings object to customize linear solving.
storm::settings::Settings* s = storm::settings::instance();
double precision = s->get<double>("precision");
uint_fast64_t maxIterations = s->get<unsigned>("maxiter");
bool relative = s->get<bool>("relative");
// Get a Jacobi decomposition of the matrix A.
typename storm::storage::SparseMatrix<Type>::SparseJacobiDecomposition_t jacobiDecomposition = A.getJacobiDecomposition();
// Convert the (inverted) diagonal matrix to gmm++'s format.
gmm::csr_matrix<Type>* gmmxxDiagonalInverted = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(std::move(jacobiDecomposition.second));
// Convert the LU matrix to gmm++'s format.
gmm::csr_matrix<Type>* gmmxxLU = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(std::move(jacobiDecomposition.first));
LOG4CPLUS_INFO(logger, "Starting iterative Jacobi Solver.");
// x_(k + 1) = D^-1 * (b - R * x_k)
// In x we keep a copy of the result for swapping in the loop (e.g. less copy-back).
std::vector<Type>* xNext = new std::vector<Type>(x.size());
const std::vector<Type>* xCopy = xNext;
std::vector<Type>* xCurrent = &x;
// Target vector for precision calculation.
std::vector<Type>* residuum = new std::vector<Type>(x.size());
// Set up additional environment variables.
uint_fast64_t iterationCount = 0;
bool converged = false;
while (!converged && iterationCount < maxIterations) {
// R * x_k (xCurrent is x_k) -> xNext
gmm::mult(*gmmxxLU, *xCurrent, *xNext);
// b - R * x_k (xNext contains R * x_k) -> xNext
gmm::add(b, gmm::scaled(*xNext, -1.0), *xNext);
// D^-1 * (b - R * x_k) -> xNext
gmm::mult(*gmmxxDiagonalInverted, *xNext, *xNext);
// Swap xNext with xCurrent so that the next iteration can use xCurrent again without having to copy the
// vector.
std::vector<Type> *const swap = xNext;
xNext = xCurrent;
xCurrent = swap;
// Now check if the process already converged within our precision.
converged = storm::utility::vector::equalModuloPrecision(*xCurrent, *xNext, precision, relative);
// Increase iteration count so we can abort if convergence is too slow.
++iterationCount;
}
// If the last iteration did not write to the original x we have to swap the contents, because the output has to
// be written to the parameter x.
if (xCurrent == xCopy) {
std::swap(x, *xCurrent);
}
// As xCopy always points to the copy of x used for swapping, we can safely delete it.
delete xCopy;
// Also delete the other dynamically allocated variables.
delete residuum;
delete gmmxxDiagonalInverted;
delete gmmxxLU;
return iterationCount;
}
};
} // namespace solver
} // namespace storm
#endif /* STORM_SOLVER_GMMXXLINEAREQUATIONSOLVER_H_ */

122
src/solver/GmmxxNondeterministicLinearEquationSolver.h

@ -0,0 +1,122 @@
#ifndef STORM_SOLVER_GMMXXNONDETERMINISTICLINEAREQUATIONSOLVER_H_
#define STORM_SOLVER_GMMXXNONDETERMINISTICLINEAREQUATIONSOLVER_H_
#include "AbstractLinearEquationSolver.h"
#include "src/adapters/GmmxxAdapter.h"
#include "src/storage/SparseMatrix.h"
#include "gmm/gmm_matrix.h"
#include <vector>
namespace storm {
namespace solver {
template<class Type>
class GmmxxNondeterministicLinearEquationSolver : public AbstractNondeterministicLinearEquationSolver<Type> {
public:
virtual AbstractLinearEquationSolver<Type>* clone() const {
return new GmmxxNondeterministicLinearEquationSolver<Type>();
}
virtual void performMatrixVectorMultiplication(storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<Type>* b = nullptr, uint_fast64_t n = 1) const {
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
// Create vector for result of multiplication, which is reduced to the result vector after
// each multiplication.
std::vector<Type> multiplyResult(A.getRowCount());
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
for (uint_fast64_t i = 0; i < n; ++i) {
gmm::mult(*gmmxxMatrix, x, multiplyResult);
if (b != nullptr) {
gmm::add(*b, multiplyResult);
}
if (this->minimumOperatorStack.top()) {
storm::utility::vector::reduceVectorMin(multiplyResult, x, nondeterministicChoiceIndices);
} else {
storm::utility::vector::reduceVectorMax(multiplyResult, x, nondeterministicChoiceIndices);
}
}
// Delete intermediate results and return result.
delete gmmxxMatrix;
}
void solveEquationSystem(bool minimize, storm::storage::SparseMatrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<uint_fast64_t>* takenChoices = nullptr) const override {
// Get the settings object to customize solving.
storm::settings::Settings* s = storm::settings::instance();
// Get relevant user-defined settings for solving the equations.
double precision = s->get<double>("precision");
unsigned maxIterations = s->get<unsigned>("maxiter");
bool relative = s->get<bool>("relative");
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(A);
// Set up the environment for the power method.
std::vector<Type> multiplyResult(A.getRowCount());
std::vector<Type>* currentX = &x;
std::vector<Type>* newX = new std::vector<Type>(x.size());
std::vector<Type>* swap = nullptr;
uint_fast64_t iterations = 0;
bool converged = false;
// Proceed with the iterations as long as the method did not converge or reach the user-specified maximum number
// of iterations.
while (!converged && iterations < maxIterations) {
// Compute x' = A*x + b.
gmm::mult(*gmmxxMatrix, *currentX, multiplyResult);
gmm::add(b, multiplyResult);
// Reduce the vector x' by applying min/max for all non-deterministic choices.
if (minimize) {
storm::utility::vector::reduceVectorMin(multiplyResult, *newX, nondeterministicChoiceIndices);
} else {
storm::utility::vector::reduceVectorMax(multiplyResult, *newX, nondeterministicChoiceIndices);
}
// Determine whether the method converged.
converged = storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative);
// Update environment variables.
swap = currentX;
currentX = newX;
newX = swap;
++iterations;
}
// If we were requested to record the taken choices, we have to construct the vector now.
if (takenChoices != nullptr) {
this->computeTakenChoices(minimize, multiplyResult, *takenChoices, nondeterministicChoiceIndices);
}
// If we performed an odd number of iterations, we need to swap the x and currentX, because the newest result
// is currently stored in currentX, but x is the output vector.
if (iterations % 2 == 1) {
std::swap(x, *currentX);
delete currentX;
} else {
delete newX;
}
delete gmmxxMatrix;
// Check if the solver converged and issue a warning otherwise.
if (converged) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iterations << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge after " << iterations << " iterations.");
}
}
};
} // namespace solver
} // namespace storm
#endif /* STORM_SOLVER_GMMXXNONDETERMINISTICLINEAREQUATIONSOLVER_H_ */

20
src/storage/BitVector.h

@ -149,6 +149,26 @@ public:
std::copy(bv.bucketArray, bv.bucketArray + this->bucketCount, this->bucketArray);
}
/*!
* Copy Constructor. Performs a deep copy of the bits in the given bit vector that are given by the filter.
* @param bv A reference to the bit vector to be copied.
* @param filter The filter to apply for copying.
*/
BitVector(BitVector const& other, BitVector const& filter) : bitCount(filter.getNumberOfSetBits()), endIterator(*this, bitCount, bitCount, false), truncateMask((1ll << (bitCount & mod64mask)) - 1ll) {
// Determine the number of buckets we need for the given bit count and create bucket array.
bucketCount = bitCount >> 6;
if ((bitCount & mod64mask) != 0) {
++bucketCount;
}
this->bucketArray = new uint64_t[bucketCount]();
// Now copy over all bits given by the filter.
uint_fast64_t nextPosition = 0;
for (auto position : filter) {
this->set(nextPosition, other.get(position));
}
}
/*!
* Move constructor. Move constructs the bit vector from the given bit vector.
*

9
src/storm.cpp

@ -23,8 +23,6 @@
#include "src/storage/SparseMatrix.h"
#include "src/models/AtomicPropositionsLabeling.h"
#include "src/modelchecker/prctl/EigenDtmcPrctlModelChecker.h"
#include "src/modelchecker/prctl/GmmxxDtmcPrctlModelChecker.h"
#include "src/modelchecker/prctl/GmmxxMdpPrctlModelChecker.h"
#include "src/parser/AutoParser.h"
#include "src/parser/PrctlParser.h"
//#include "src/solver/GraphAnalyzer.h"
@ -144,7 +142,6 @@ void printHeader(const int argc, const char* argv[]) {
bool parseOptions(const int argc, const char* argv[]) {
storm::settings::Settings* s = nullptr;
try {
storm::settings::Settings::registerModule<storm::modelchecker::prctl::GmmxxDtmcPrctlModelChecker<double>>();
s = storm::settings::newInstance(argc, argv, nullptr);
} catch (storm::exceptions::InvalidSettingsException& e) {
std::cout << "Could not recover from settings error: " << e.what() << "." << std::endl;
@ -202,7 +199,7 @@ storm::modelchecker::prctl::AbstractModelChecker<double>* createPrctlModelChecke
// Create the appropriate model checker.
storm::settings::Settings* s = storm::settings::instance();
if (s->getString("matrixlib") == "gmm++") {
return new storm::modelchecker::prctl::GmmxxDtmcPrctlModelChecker<double>(dtmc);
return new storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double>(dtmc, new storm::solver::AbstractLinearEquationSolver<double>());
}
// The control flow should never reach this point, as there is a default setting for matrixlib.
@ -221,9 +218,9 @@ storm::modelchecker::prctl::AbstractModelChecker<double>* createPrctlModelChecke
// Create the appropriate model checker.
storm::settings::Settings* s = storm::settings::instance();
if (s->getString("matrixlib") == "gmm++") {
return new storm::modelchecker::prctl::GmmxxMdpPrctlModelChecker<double>(mdp);
return new storm::modelchecker::prctl::SparseMdpPrctlModelChecker<double>(mdp, new storm::solver::GmmxxNondeterministicEquationSolver<double>());
} else if (s->getString("matrixlib") == "native") {
return new storm::modelchecker::prctl::SparseMdpPrctlModelChecker<double>(mdp);
return new storm::modelchecker::prctl::SparseMdpPrctlModelChecker<double>(mdp, new storm::solver::AbstractNondeterministicEquationSolver<double>());
}
// The control flow should never reach this point, as there is a default setting for matrixlib.

10
src/utility/Settings.cpp

@ -100,20 +100,20 @@ Settings::Settings(int const argc, char const * const argv[], char const * const
}
LOG4CPLUS_DEBUG(logger, "Finished loading config.");
}
catch (bpo::reading_file e) {
catch (bpo::reading_file const& e) {
std::cerr << "Could not read config file " << filename << std::endl;
LOG4CPLUS_ERROR(logger, "Could not read config file");
}
catch (bpo::required_option e) {
catch (bpo::required_option const& e) {
throw storm::exceptions::InvalidSettingsException() << "Required option missing";
}
catch (bpo::validation_error e) {
catch (bpo::validation_error const& e) {
throw storm::exceptions::InvalidSettingsException() << "Validation failed: " << e.what();
}
catch (bpo::invalid_command_line_syntax e) {
catch (bpo::invalid_command_line_syntax const& e) {
throw storm::exceptions::InvalidSettingsException() << e.what();
}
catch (bpo::error e) {
catch (bpo::error const& e) {
throw storm::exceptions::InvalidSettingsException() << e.what();
}
}

10
src/utility/Settings.h

@ -125,17 +125,17 @@ namespace settings {
* @endcode
*/
template <typename T>
static void registerModule() {
static void registerSolver() {
// Get trigger values.
std::pair< std::string, std::string > trigger = T::getOptionTrigger();
std::string const& name = T::getName();
// Build description name.
std::stringstream str;
str << "Options for " << T::getModuleName() << " (" << trigger.first << " = " << trigger.second << ")";
str << "Options for " << name << ":";
std::shared_ptr<bpo::options_description> desc = std::shared_ptr<bpo::options_description>(new bpo::options_description(str.str()));
// Put options into description.
T::putOptions(desc.get());
// Store module.
Settings::modules[ trigger ] = desc;
Settings::modules[name] = desc;
}
friend std::ostream& help(std::ostream& os);
@ -185,7 +185,7 @@ namespace settings {
/*!
* @brief Contains option descriptions for all modules.
*/
static std::map< std::pair< std::string, std::string >, std::shared_ptr<bpo::options_description> > modules;
static std::map<std::string, std::shared_ptr<bpo::options_description>> modules;
/*!
* @brief option mapping.

17
src/utility/vector.h

@ -100,6 +100,23 @@ void selectVectorValues(std::vector<T>& vector, storm::storage::BitVector const&
}
}
/*!
* Selects one element out of each row group and writes it to the target vector.
*
* @param vector The target vector to which the values are written.
* @param rowGroupToRowIndexMapping A mapping from row group indices to an offset that specifies which of the values to
* take from the row group.
* @param rowGrouping A vector that specifies the begin and end of each group of elements in the values vector.
* @param values The vector from which to select the values.
*/
template<class T>
void selectVectorValues(std::vector<T>& vector, std::vector<uint_fast64_t> const& rowGroupToRowIndexMapping, std::vector<uint_fast64_t> const& rowGrouping, std::vector<T> const& values) {
uint_fast64_t oldPosition = 0;
for (uint_fast64_t i = 0; i < vector.size(); ++i) {
vector[i] = values[rowGrouping[i] + rowGroupToRowIndexMapping[i]];
}
}
/*!
* Selects values from a vector at the specified positions and writes them into another vector as often as given by
* the size of the corresponding group of elements.

Loading…
Cancel
Save