Browse Source

Introduced new topological min max solver

tempestpy_adaptions
TimQu 7 years ago
parent
commit
2d910b79ed
  1. 4
      src/storm/environment/SubEnvironment.cpp
  2. 4
      src/storm/environment/solver/MinMaxSolverEnvironment.cpp
  3. 2
      src/storm/environment/solver/MinMaxSolverEnvironment.h
  4. 12
      src/storm/environment/solver/SolverEnvironment.cpp
  5. 10
      src/storm/environment/solver/SolverEnvironment.h
  6. 37
      src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp
  7. 24
      src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h
  8. 56
      src/storm/environment/solver/TopologicalSolverEnvironment.cpp
  9. 31
      src/storm/environment/solver/TopologicalSolverEnvironment.h
  10. 2
      src/storm/solver/MinMaxLinearEquationSolver.cpp
  11. 38
      src/storm/solver/TopologicalLinearEquationSolver.cpp
  12. 434
      src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp
  13. 73
      src/storm/solver/TopologicalMinMaxLinearEquationSolver.h
  14. 4
      src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp
  15. 39
      src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp
  16. 4
      src/test/storm/solver/LinearEquationSolverTest.cpp
  17. 4
      src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp

4
src/storm/environment/SubEnvironment.cpp

@ -5,7 +5,7 @@
#include "storm/environment/solver/NativeSolverEnvironment.h"
#include "storm/environment/solver/MinMaxSolverEnvironment.h"
#include "storm/environment/solver/GameSolverEnvironment.h"
#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h"
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
namespace storm {
@ -41,7 +41,7 @@ namespace storm {
template class SubEnvironment<NativeSolverEnvironment>;
template class SubEnvironment<MinMaxSolverEnvironment>;
template class SubEnvironment<GameSolverEnvironment>;
template class SubEnvironment<TopologicalLinearEquationSolverEnvironment>;
template class SubEnvironment<TopologicalSolverEnvironment>;
}

4
src/storm/environment/solver/MinMaxSolverEnvironment.cpp

@ -34,8 +34,8 @@ namespace storm {
return methodSetFromDefault;
}
void MinMaxSolverEnvironment::setMethod(storm::solver::MinMaxMethod value) {
methodSetFromDefault = false;
void MinMaxSolverEnvironment::setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault) {
methodSetFromDefault = isSetFromDefault;
minMaxMethod = value;
}

2
src/storm/environment/solver/MinMaxSolverEnvironment.h

@ -16,7 +16,7 @@ namespace storm {
storm::solver::MinMaxMethod const& getMethod() const;
bool const& isMethodSetFromDefault() const;
void setMethod(storm::solver::MinMaxMethod value);
void setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault = false);
uint64_t const& getMaximalNumberOfIterations() const;
void setMaximalNumberOfIterations(uint64_t value);
storm::RationalNumber const& getPrecision() const;

12
src/storm/environment/solver/SolverEnvironment.cpp

@ -5,7 +5,7 @@
#include "storm/environment/solver/GmmxxSolverEnvironment.h"
#include "storm/environment/solver/NativeSolverEnvironment.h"
#include "storm/environment/solver/GameSolverEnvironment.h"
#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h"
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/GeneralSettings.h"
@ -68,11 +68,11 @@ namespace storm {
return gameSolverEnvironment.get();
}
TopologicalLinearEquationSolverEnvironment& SolverEnvironment::topological() {
TopologicalSolverEnvironment& SolverEnvironment::topological() {
return topologicalSolverEnvironment.get();
}
TopologicalLinearEquationSolverEnvironment const& SolverEnvironment::topological() const {
TopologicalSolverEnvironment const& SolverEnvironment::topological() const {
return topologicalSolverEnvironment.get();
}
@ -88,8 +88,8 @@ namespace storm {
return linearEquationSolverType;
}
void SolverEnvironment::setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool assumeSetFromDefault) {
linearEquationSolverTypeSetFromDefault = assumeSetFromDefault;
void SolverEnvironment::setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool isSetFromDefault) {
linearEquationSolverTypeSetFromDefault = isSetFromDefault;
linearEquationSolverType = value;
}
@ -113,7 +113,7 @@ namespace storm {
case storm::solver::EquationSolverType::Elimination:
break;
case storm::solver::EquationSolverType::Topological:
result = getPrecisionOfLinearEquationSolver(topological().getUnderlyingSolverType());
result = getPrecisionOfLinearEquationSolver(topological().getUnderlyingEquationSolverType());
break;
default:
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "The selected solver type is unknown.");

10
src/storm/environment/solver/SolverEnvironment.h

@ -16,7 +16,7 @@ namespace storm {
class NativeSolverEnvironment;
class MinMaxSolverEnvironment;
class GameSolverEnvironment;
class TopologicalLinearEquationSolverEnvironment;
class TopologicalSolverEnvironment;
class SolverEnvironment {
public:
@ -34,14 +34,14 @@ namespace storm {
MinMaxSolverEnvironment const& minMax() const;
GameSolverEnvironment& game();
GameSolverEnvironment const& game() const;
TopologicalLinearEquationSolverEnvironment& topological();
TopologicalLinearEquationSolverEnvironment const& topological() const;
TopologicalSolverEnvironment& topological();
TopologicalSolverEnvironment const& topological() const;
bool isForceSoundness() const;
void setForceSoundness(bool value);
storm::solver::EquationSolverType const& getLinearEquationSolverType() const;
void setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool assumeSetFromDefault = false);
void setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool isSetFromDefault = false);
bool isLinearEquationSolverTypeSetFromDefaultValue() const;
std::pair<boost::optional<storm::RationalNumber>, boost::optional<bool>> getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const& solverType) const;
@ -52,7 +52,7 @@ namespace storm {
SubEnvironment<GmmxxSolverEnvironment> gmmxxSolverEnvironment;
SubEnvironment<NativeSolverEnvironment> nativeSolverEnvironment;
SubEnvironment<GameSolverEnvironment> gameSolverEnvironment;
SubEnvironment<TopologicalLinearEquationSolverEnvironment> topologicalSolverEnvironment;
SubEnvironment<TopologicalSolverEnvironment> topologicalSolverEnvironment;
SubEnvironment<MinMaxSolverEnvironment> minMaxSolverEnvironment;
storm::solver::EquationSolverType linearEquationSolverType;

37
src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp

@ -1,37 +0,0 @@
#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/TopologicalEquationSolverSettings.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidArgumentException.h"
namespace storm {
TopologicalLinearEquationSolverEnvironment::TopologicalLinearEquationSolverEnvironment() {
auto const& topologicalSettings = storm::settings::getModule<storm::settings::modules::TopologicalEquationSolverSettings>();
underlyingSolverType = topologicalSettings.getUnderlyingEquationSolverType();
underlyingSolverTypeSetFromDefault = topologicalSettings.isUnderlyingEquationSolverTypeSetFromDefaultValue();
}
TopologicalLinearEquationSolverEnvironment::~TopologicalLinearEquationSolverEnvironment() {
// Intentionally left empty
}
storm::solver::EquationSolverType const& TopologicalLinearEquationSolverEnvironment::getUnderlyingSolverType() const {
return underlyingSolverType;
}
bool const& TopologicalLinearEquationSolverEnvironment::isUnderlyingSolverTypeSetFromDefault() const {
return underlyingSolverTypeSetFromDefault;
}
void TopologicalLinearEquationSolverEnvironment::setUnderlyingSolverType(storm::solver::EquationSolverType value) {
STORM_LOG_THROW(value != storm::solver::EquationSolverType::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver.");
underlyingSolverTypeSetFromDefault = false;
underlyingSolverType = value;
}
}

24
src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h

@ -1,24 +0,0 @@
#pragma once
#include "storm/environment/solver/SolverEnvironment.h"
#include "storm/solver/SolverSelectionOptions.h"
namespace storm {
class TopologicalLinearEquationSolverEnvironment {
public:
TopologicalLinearEquationSolverEnvironment();
~TopologicalLinearEquationSolverEnvironment();
storm::solver::EquationSolverType const& getUnderlyingSolverType() const;
bool const& isUnderlyingSolverTypeSetFromDefault() const;
void setUnderlyingSolverType(storm::solver::EquationSolverType value);
private:
storm::solver::EquationSolverType underlyingSolverType;
bool underlyingSolverTypeSetFromDefault;
};
}

56
src/storm/environment/solver/TopologicalSolverEnvironment.cpp

@ -0,0 +1,56 @@
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/TopologicalEquationSolverSettings.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidArgumentException.h"
namespace storm {
TopologicalSolverEnvironment::TopologicalSolverEnvironment() {
auto const& topologicalSettings = storm::settings::getModule<storm::settings::modules::TopologicalEquationSolverSettings>();
underlyingEquationSolverType = topologicalSettings.getUnderlyingEquationSolverType();
underlyingEquationSolverTypeSetFromDefault = topologicalSettings.isUnderlyingEquationSolverTypeSetFromDefaultValue();
std::cout << "Get topo env minmax from settings!!" << std::endl;
underlyingMinMaxMethod = storm::solver::MinMaxMethod::ValueIteration;
underlyingEquationSolverTypeSetFromDefault = false;
}
TopologicalSolverEnvironment::~TopologicalSolverEnvironment() {
// Intentionally left empty
}
storm::solver::EquationSolverType const& TopologicalSolverEnvironment::getUnderlyingEquationSolverType() const {
return underlyingEquationSolverType;
}
bool const& TopologicalSolverEnvironment::isUnderlyingEquationSolverTypeSetFromDefault() const {
return underlyingEquationSolverTypeSetFromDefault;
}
void TopologicalSolverEnvironment::setUnderlyingEquationSolverType(storm::solver::EquationSolverType value) {
STORM_LOG_THROW(value != storm::solver::EquationSolverType::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver.");
underlyingEquationSolverTypeSetFromDefault = false;
underlyingEquationSolverType = value;
}
storm::solver::MinMaxMethod const& TopologicalSolverEnvironment::getUnderlyingMinMaxMethod() const {
return underlyingMinMaxMethod;
}
bool const& TopologicalSolverEnvironment::isUnderlyingMinMaxMethodSetFromDefault() const {
return underlyingMinMaxMethodSetFromDefault;
}
void TopologicalSolverEnvironment::setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod value) {
STORM_LOG_THROW(value != storm::solver::MinMaxMethod::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver.");
underlyingMinMaxMethodSetFromDefault = false;
underlyingMinMaxMethod = value;
}
}

31
src/storm/environment/solver/TopologicalSolverEnvironment.h

@ -0,0 +1,31 @@
#pragma once
#include "storm/environment/solver/SolverEnvironment.h"
#include "storm/solver/SolverSelectionOptions.h"
namespace storm {
class TopologicalSolverEnvironment {
public:
TopologicalSolverEnvironment();
~TopologicalSolverEnvironment();
storm::solver::EquationSolverType const& getUnderlyingEquationSolverType() const;
bool const& isUnderlyingEquationSolverTypeSetFromDefault() const;
void setUnderlyingEquationSolverType(storm::solver::EquationSolverType value);
storm::solver::MinMaxMethod const& getUnderlyingMinMaxMethod() const;
bool const& isUnderlyingMinMaxMethodSetFromDefault() const;
void setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod value);
private:
storm::solver::EquationSolverType underlyingEquationSolverType;
bool underlyingEquationSolverTypeSetFromDefault;
storm::solver::MinMaxMethod underlyingMinMaxMethod;
bool underlyingMinMaxMethodSetFromDefault;
};
}

2
src/storm/solver/MinMaxLinearEquationSolver.cpp

@ -199,6 +199,8 @@ namespace storm {
auto method = env.solver().minMax().getMethod();
if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) {
result = std::make_unique<IterativeMinMaxLinearEquationSolver<ValueType>>(std::make_unique<GeneralLinearEquationSolverFactory<ValueType>>());
} else if (method == MinMaxMethod::Topological) {
result = std::make_unique<TopologicalMinMaxLinearEquationSolver<ValueType>>();
} else if (method == MinMaxMethod::TopologicalCuda) {
result = std::make_unique<TopologicalCudaMinMaxLinearEquationSolver<ValueType>>();
} else if (method == MinMaxMethod::LinearProgramming) {

38
src/storm/solver/TopologicalLinearEquationSolver.cpp

@ -1,6 +1,6 @@
#include "storm/solver/TopologicalLinearEquationSolver.h"
#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h"
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
#include "storm/utility/constants.h"
#include "storm/utility/vector.h"
@ -43,7 +43,7 @@ namespace storm {
template<typename ValueType>
storm::Environment TopologicalLinearEquationSolver<ValueType>::getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision) const {
storm::Environment subEnv(env);
subEnv.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingSolverType(), env.solver().topological().isUnderlyingSolverTypeSetFromDefault());
subEnv.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingEquationSolverType(), env.solver().topological().isUnderlyingEquationSolverTypeSetFromDefault());
if (adaptPrecision) {
STORM_LOG_ASSERT(this->longestSccChainSize, "Did not compute the longest SCC chain size although it is needed.");
auto subEnvPrec = subEnv.solver().getPrecisionOfLinearEquationSolver(subEnv.solver().getLinearEquationSolverType());
@ -54,14 +54,9 @@ namespace storm {
template<typename ValueType>
bool TopologicalLinearEquationSolver<ValueType>::internalSolveEquations(Environment const& env, std::vector<ValueType>& x, std::vector<ValueType> const& b) const {
//std::cout << "Solving equation system with fixpoint characterization " << std::endl;
//std::cout << *this->A << std::endl;
//std::cout << storm::utility::vector::toString(b) << std::endl;
//std::cout << "Initial solution vector: " << std::endl;
//std::cout << storm::utility::vector::toString(x) << std::endl;
// For sound computations we need to increase the precision in each SCC
bool needAdaptPrecision = env.solver().isForceSoundness() && env.solver().getPrecisionOfLinearEquationSolver(env.solver().topological().getUnderlyingSolverType()).first.is_initialized();
bool needAdaptPrecision = env.solver().isForceSoundness() && env.solver().getPrecisionOfLinearEquationSolver(env.solver().topological().getUnderlyingEquationSolverType()).first.is_initialized();
if (!this->sortedSccDecomposition || (needAdaptPrecision && !this->longestSccChainSize)) {
STORM_LOG_TRACE("Creating SCC decomposition.");
@ -88,21 +83,21 @@ namespace storm {
}
// Handle the case where there is just one large SCC
if (this->sortedSccDecomposition->size() == 1) {
return solveFullyConnectedEquationSystem(sccSolverEnvironment, x, b);
}
storm::storage::BitVector sccAsBitVector(x.size(), false);
bool returnValue = true;
for (auto const& scc : *this->sortedSccDecomposition) {
if (scc.isTrivial()) {
returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue;
} else {
sccAsBitVector.clear();
for (auto const& state : scc) {
sccAsBitVector.set(state, true);
if (this->sortedSccDecomposition->size() == 1) {
returnValue = solveFullyConnectedEquationSystem(sccSolverEnvironment, x, b);
} else {
storm::storage::BitVector sccAsBitVector(x.size(), false);
for (auto const& scc : *this->sortedSccDecomposition) {
if (scc.isTrivial()) {
returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue;
} else {
sccAsBitVector.clear();
for (auto const& state : scc) {
sccAsBitVector.set(state, true);
}
returnValue = solveScc(sccSolverEnvironment, sccAsBitVector, x, b) && returnValue;
}
returnValue = solveScc(sccSolverEnvironment, sccAsBitVector, x, b) && returnValue;
}
}
@ -373,6 +368,7 @@ namespace storm {
template<typename ValueType>
void TopologicalLinearEquationSolver<ValueType>::clearCache() const {
sortedSccDecomposition.reset();
longestSccChainSize = boost::none;
sccSolver.reset();
LinearEquationSolver<ValueType>::clearCache();
}

434
src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp

@ -0,0 +1,434 @@
#include "storm/solver/TopologicalMinMaxLinearEquationSolver.h"
#include "storm/environment/solver/MinMaxSolverEnvironment.h"
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
#include "storm/utility/constants.h"
#include "storm/utility/vector.h"
#include "storm/exceptions/InvalidStateException.h"
#include "storm/exceptions/InvalidEnvironmentException.h"
#include "storm/exceptions/UnexpectedException.h"
#include "storm/exceptions/UnmetRequirementException.h"
namespace storm {
namespace solver {
template<typename ValueType>
TopologicalMinMaxLinearEquationSolver<ValueType>::TopologicalMinMaxLinearEquationSolver() : localA(nullptr), A(nullptr) {
// Intentionally left empty.
}
template<typename ValueType>
TopologicalMinMaxLinearEquationSolver<ValueType>::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix<ValueType> const& A) : localA(nullptr), A(nullptr) {
this->setMatrix(A);
}
template<typename ValueType>
TopologicalMinMaxLinearEquationSolver<ValueType>::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix<ValueType>&& A) : localA(nullptr), A(nullptr) {
this->setMatrix(std::move(A));
}
template<typename ValueType>
void TopologicalMinMaxLinearEquationSolver<ValueType>::setMatrix(storm::storage::SparseMatrix<ValueType> const& A) {
localA.reset();
this->A = &A;
clearCache();
}
template<typename ValueType>
void TopologicalMinMaxLinearEquationSolver<ValueType>::setMatrix(storm::storage::SparseMatrix<ValueType>&& A) {
localA = std::make_unique<storm::storage::SparseMatrix<ValueType>>(std::move(A));
this->A = localA.get();
clearCache();
}
template<typename ValueType>
storm::Environment TopologicalMinMaxLinearEquationSolver<ValueType>::getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision) const {
storm::Environment subEnv(env);
subEnv.solver().minMax().setMethod(env.solver().topological().getUnderlyingMinMaxMethod(), env.solver().topological().isUnderlyingMinMaxMethodSetFromDefault());
if (adaptPrecision) {
STORM_LOG_ASSERT(this->longestSccChainSize, "Did not compute the longest SCC chain size although it is needed.");
storm::RationalNumber subEnvPrec = subEnv.solver().minMax().getPrecision() / storm::utility::convertNumber<storm::RationalNumber>(this->longestSccChainSize.get());
subEnv.solver().minMax().setPrecision(subEnvPrec);
}
return subEnv;
}
template<typename ValueType>
bool TopologicalMinMaxLinearEquationSolver<ValueType>::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const {
STORM_LOG_ASSERT(x.size() == this->A->getRowGroupCount(), "Provided x-vector has invalid size.");
STORM_LOG_ASSERT(b.size() == this->A->getRowCount(), "Provided b-vector has invalid size.");
//std::cout << "Solving equation system with fixpoint characterization " << std::endl;
//std::cout << *this->A << std::endl;
//std::cout << storm::utility::vector::toString(b) << std::endl;
//std::cout << "Initial solution vector: " << std::endl;
//std::cout << storm::utility::vector::toString(x) << std::endl;
// For sound computations we need to increase the precision in each SCC
bool needAdaptPrecision = env.solver().isForceSoundness();
if (!this->sortedSccDecomposition || (needAdaptPrecision && !this->longestSccChainSize)) {
STORM_LOG_TRACE("Creating SCC decomposition.");
createSortedSccDecomposition(needAdaptPrecision);
}
//std::cout << "Sorted SCC decomposition: " << std::endl;
//for (auto const& scc : *this->sortedSccDecomposition) {
//std::cout << "SCC: ";
// for (auto const& row : scc) {
//std::cout << row << " ";
// }
//std::cout << std::endl;
//}
// We do not need to adapt the precision if all SCCs are trivial (i.e., the system is acyclic)
needAdaptPrecision = needAdaptPrecision && (this->sortedSccDecomposition->size() != this->A->getRowGroupCount());
storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision);
std::cout << "Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast<double>(this->A->getRowGroupCount()) / static_cast<double>(this->sortedSccDecomposition->size()) << "." << std::endl;
if (this->longestSccChainSize) {
std::cout << "Longest SCC chain size is " << this->longestSccChainSize.get() << std::endl;
}
bool returnValue = true;
if (this->sortedSccDecomposition->size() == 1) {
// Handle the case where there is just one large SCC
returnValue = solveFullyConnectedEquationSystem(sccSolverEnvironment, dir, x, b);
} else {
if (this->isTrackSchedulerSet()) {
if (this->schedulerChoices) {
this->schedulerChoices.get().resize(x.size());
} else {
this->schedulerChoices = std::vector<uint64_t>(x.size());
}
}
storm::storage::BitVector sccRowGroupsAsBitVector(x.size(), false);
storm::storage::BitVector sccRowsAsBitVector(b.size(), false);
for (auto const& scc : *this->sortedSccDecomposition) {
if (scc.isTrivial()) {
returnValue = solveTrivialScc(*scc.begin(), dir, x, b) && returnValue;
} else {
sccRowGroupsAsBitVector.clear();
sccRowsAsBitVector.clear();
for (auto const& group : scc) {
sccRowGroupsAsBitVector.set(group, true);
for (uint64_t row = this->A->getRowGroupIndices()[group]; row < this->A->getRowGroupIndices()[group + 1]; ++row) {
sccRowsAsBitVector.set(row, true);
}
}
returnValue = solveScc(sccSolverEnvironment, dir, sccRowGroupsAsBitVector, sccRowsAsBitVector, x, b) && returnValue;
}
}
// If requested, we store the scheduler for retrieval.
if (this->isTrackSchedulerSet()) {
if (!auxiliaryRowGroupVector) {
auxiliaryRowGroupVector = std::make_unique<std::vector<ValueType>>(this->A->getRowGroupCount());
}
this->schedulerChoices = std::vector<uint_fast64_t>(this->A->getRowGroupCount());
this->A->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *auxiliaryRowGroupVector.get(), &this->schedulerChoices.get());
}
}
if (!this->isCachingEnabled()) {
clearCache();
}
return returnValue;
}
template<typename ValueType>
void TopologicalMinMaxLinearEquationSolver<ValueType>::createSortedSccDecomposition(bool needLongestChainSize) const {
// Obtain the scc decomposition
auto sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition<ValueType>(*this->A);
// Get a mapping from matrix row to the corresponding scc
STORM_LOG_THROW(sccDecomposition.size() < std::numeric_limits<uint32_t>::max(), storm::exceptions::UnexpectedException, "The number of SCCs is too large.");
std::vector<uint32_t> sccIndices(this->A->getRowCount(), std::numeric_limits<uint32_t>::max());
uint32_t sccIndex = 0;
for (auto const& scc : sccDecomposition) {
for (auto const& row : scc) {
sccIndices[row] = sccIndex;
}
++sccIndex;
}
// Prepare the resulting set of sorted sccs
this->sortedSccDecomposition = std::make_unique<std::vector<storm::storage::StronglyConnectedComponent>>();
std::vector<storm::storage::StronglyConnectedComponent>& sortedSCCs = *this->sortedSccDecomposition;
sortedSCCs.reserve(sccDecomposition.size());
// Find a topological sort via DFS.
storm::storage::BitVector unsortedSCCs(sccDecomposition.size(), true);
std::vector<uint32_t> sccStack, chainSizes;
if (needLongestChainSize) {
chainSizes.resize(sccDecomposition.size(), 1u);
}
uint32_t longestChainSize = 0;
uint32_t const token = std::numeric_limits<uint32_t>::max();
std::set<uint64_t> successorSCCs;
for (uint32_t firstUnsortedScc = 0; firstUnsortedScc < unsortedSCCs.size(); firstUnsortedScc = unsortedSCCs.getNextSetIndex(firstUnsortedScc + 1)) {
sccStack.push_back(firstUnsortedScc);
while (!sccStack.empty()) {
uint32_t currentSccIndex = sccStack.back();
if (currentSccIndex != token) {
// Check whether the SCC is still unprocessed
if (unsortedSCCs.get(currentSccIndex)) {
// Explore the successors of the scc.
storm::storage::StronglyConnectedComponent const& currentScc = sccDecomposition.getBlock(currentSccIndex);
// We first push a token on the stack in order to recognize later when all successors of this SCC have been explored already.
sccStack.push_back(token);
// Now add all successors that are not already sorted.
// Successors should only be added once, so we first prepare a set of them and add them afterwards.
successorSCCs.clear();
for (auto const& row : currentScc) {
for (auto const& entry : this->A->getRow(row)) {
auto const& successorSCC = sccIndices[entry.getColumn()];
if (successorSCC != currentSccIndex && unsortedSCCs.get(successorSCC)) {
successorSCCs.insert(successorSCC);
}
}
}
sccStack.insert(sccStack.end(), successorSCCs.begin(), successorSCCs.end());
}
} else {
// all successors of the current scc have already been explored.
sccStack.pop_back(); // pop the token
currentSccIndex = sccStack.back();
storm::storage::StronglyConnectedComponent& scc = sccDecomposition.getBlock(currentSccIndex);
// Compute the longest chain size for this scc
if (needLongestChainSize) {
uint32_t& currentChainSize = chainSizes[currentSccIndex];
for (auto const& row : scc) {
for (auto const& entry : this->A->getRow(row)) {
auto const& successorSCC = sccIndices[entry.getColumn()];
if (successorSCC != currentSccIndex) {
currentChainSize = std::max(currentChainSize, chainSizes[successorSCC] + 1);
}
}
}
longestChainSize = std::max(longestChainSize, currentChainSize);
}
unsortedSCCs.set(currentSccIndex, false);
sccStack.pop_back(); // pop the current scc index
sortedSCCs.push_back(std::move(scc));
}
}
}
if (longestChainSize > 0) {
this->longestSccChainSize = longestChainSize;
}
}
template<typename ValueType>
bool TopologicalMinMaxLinearEquationSolver<ValueType>::solveTrivialScc(uint64_t const& sccState, OptimizationDirection dir, std::vector<ValueType>& globalX, std::vector<ValueType> const& globalB) const {
ValueType& xi = globalX[sccState];
bool firstRow = true;
uint64_t bestRow;
for (uint64_t row = this->A->getRowGroupIndices()[sccState]; row < this->A->getRowGroupIndices()[sccState + 1]; ++row) {
ValueType rowValue = globalB[sccState];
bool hasDiagonalEntry = false;
ValueType denominator;
for (auto const& entry : this->A->getRow(sccState)) {
if (entry.getColumn() == sccState) {
STORM_LOG_ASSERT(!storm::utility::isOne(entry.getValue()), "Diagonal entry of fix point system has value 1.");
hasDiagonalEntry = true;
denominator = storm::utility::one<ValueType>() - entry.getValue();
} else {
rowValue += entry.getValue() * globalX[entry.getColumn()];
}
}
if (hasDiagonalEntry) {
rowValue /= denominator;
}
if (firstRow) {
xi = std::move(rowValue);
bestRow = row;
firstRow = false;
} else {
if (minimize(dir)) {
if (rowValue < xi) {
xi = std::move(rowValue);
bestRow = row;
}
} else {
if (rowValue > xi) {
xi = std::move(rowValue);
bestRow = row;
}
}
}
}
if (this->isTrackSchedulerSet()) {
this->schedulerChoices.get()[sccState] = bestRow - this->A->getRowGroupIndices()[sccState];
}
//std::cout << "Solved trivial scc " << sccState << " with result " << globalX[sccState] << std::endl;
return true;
}
template<typename ValueType>
bool TopologicalMinMaxLinearEquationSolver<ValueType>::solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const {
if (!this->sccSolver) {
this->sccSolver = GeneralMinMaxLinearEquationSolverFactory<ValueType>().create(sccSolverEnvironment);
this->sccSolver->setCachingEnabled(true);
}
this->sccSolver->setMatrix(*this->A);
this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution());
this->sccSolver->setBoundsFromOtherSolver(*this);
this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet());
if (this->hasInitialScheduler()) {
auto choices = this->getInitialScheduler();
this->sccSolver->setInitialScheduler(std::move(choices));
}
auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir);
if (req.requiresUpperBounds() && this->hasUpperBound()) {
req.clearUpperBounds();
}
if (req.requiresLowerBounds() && this->hasLowerBound()) {
req.clearLowerBounds();
}
STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met.");
bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, x, b);
if (this->isTrackSchedulerSet()) {
this->schedulerChoices = this->sccSolver->getSchedulerChoices();
}
return res;
}
template<typename ValueType>
bool TopologicalMinMaxLinearEquationSolver<ValueType>::solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection dir, storm::storage::BitVector const& sccRowGroups, storm::storage::BitVector const& sccRows, std::vector<ValueType>& globalX, std::vector<ValueType> const& globalB) const {
// Set up the SCC solver
if (!this->sccSolver) {
this->sccSolver = GeneralMinMaxLinearEquationSolverFactory<ValueType>().create(sccSolverEnvironment);
this->sccSolver->setCachingEnabled(true);
}
this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution());
this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet());
// Requirements
auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir);
if (req.requiresUpperBounds() && this->hasUpperBound()) {
req.clearUpperBounds();
}
if (req.requiresLowerBounds() && this->hasLowerBound()) {
req.clearLowerBounds();
}
if (req.requiresValidInitialScheduler() && this->hasInitialScheduler()) {
req.clearValidInitialScheduler();
}
STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met.");
// SCC Matrix
storm::storage::SparseMatrix<ValueType> sccA = this->A->getSubmatrix(true, sccRowGroups, sccRowGroups);
this->sccSolver->setMatrix(std::move(sccA));
// x Vector
auto sccX = storm::utility::vector::filterVector(globalX, sccRowGroups);
// b Vector
std::vector<ValueType> sccB;
sccB.reserve(sccRows.getNumberOfSetBits());
for (auto const& row : sccRows) {
ValueType bi = globalB[row];
for (auto const& entry : this->A->getRow(row)) {
if (!sccRowGroups.get(entry.getColumn())) {
bi += entry.getValue() * globalX[entry.getColumn()];
}
}
sccB.push_back(std::move(bi));
}
// initial scheduler
if (this->hasInitialScheduler()) {
auto sccInitChoices = storm::utility::vector::filterVector(this->getInitialScheduler(), sccRowGroups);
this->sccSolver->setInitialScheduler(std::move(sccInitChoices));
}
// lower/upper bounds
if (this->hasLowerBound(storm::solver::AbstractEquationSolver<ValueType>::BoundType::Global)) {
this->sccSolver->setLowerBound(this->getLowerBound());
} else if (this->hasLowerBound(storm::solver::AbstractEquationSolver<ValueType>::BoundType::Local)) {
this->sccSolver->setLowerBounds(storm::utility::vector::filterVector(this->getLowerBounds(), sccRowGroups));
}
if (this->hasUpperBound(storm::solver::AbstractEquationSolver<ValueType>::BoundType::Global)) {
this->sccSolver->setUpperBound(this->getUpperBound());
} else if (this->hasUpperBound(storm::solver::AbstractEquationSolver<ValueType>::BoundType::Local)) {
this->sccSolver->setUpperBounds(storm::utility::vector::filterVector(this->getUpperBounds(), sccRowGroups));
}
// Invoke scc solver
bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, sccX, sccB);
//std::cout << "rhs is " << storm::utility::vector::toString(sccB) << std::endl;
//std::cout << "x is " << storm::utility::vector::toString(sccX) << std::endl;
// Set Scheduler choices
if (this->isTrackSchedulerSet()) {
storm::utility::vector::setVectorValues(this->schedulerChoices.get(), sccRowGroups, this->sccSolver->getSchedulerChoices());
}
// Set solution
storm::utility::vector::setVectorValues(globalX, sccRowGroups, sccX);
return res;
}
template<typename ValueType>
void TopologicalMinMaxLinearEquationSolver<ValueType>::repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector<ValueType>& x, std::vector<ValueType> const* b, uint_fast64_t n) const {
storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env);
// Set up the SCC solver
if (!this->sccSolver) {
this->sccSolver = GeneralMinMaxLinearEquationSolverFactory<ValueType>().create(sccSolverEnvironment);
this->sccSolver->setCachingEnabled(true);
}
this->sccSolver->setMatrix(*this->A);
this->sccSolver->repeatedMultiply(sccSolverEnvironment, d, x, b, n);
if (!this->isCachingEnabled()) {
clearCache();
}
}
template<typename ValueType>
MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver<ValueType>::getRequirements(Environment const& env, boost::optional<storm::solver::OptimizationDirection> const& direction, bool const& assumeNoInitialScheduler) const {
// Return the requirements of the underlying solver
return GeneralMinMaxLinearEquationSolverFactory<ValueType>().getRequirements(getEnvironmentForUnderlyingSolver(env), this->hasUniqueSolution(), direction, assumeNoInitialScheduler);
}
template<typename ValueType>
void TopologicalMinMaxLinearEquationSolver<ValueType>::clearCache() const {
sortedSccDecomposition.reset();
longestSccChainSize = boost::none;
sccSolver.reset();
auxiliaryRowGroupVector.reset();
MinMaxLinearEquationSolver<ValueType>::clearCache();
}
template<typename ValueType>
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> TopologicalMinMaxLinearEquationSolverFactory<ValueType>::create(Environment const& env) const {
return std::make_unique<storm::solver::TopologicalMinMaxLinearEquationSolver<ValueType>>();
}
// Explicitly instantiate the min max linear equation solver.
template class TopologicalMinMaxLinearEquationSolver<double>;
template class TopologicalMinMaxLinearEquationSolverFactory<double>;
#ifdef STORM_HAVE_CARL
template class TopologicalMinMaxLinearEquationSolver<storm::RationalNumber>;
template class TopologicalMinMaxLinearEquationSolverFactory<storm::RationalNumber>;
#endif
}
}

73
src/storm/solver/TopologicalMinMaxLinearEquationSolver.h

@ -0,0 +1,73 @@
#pragma once
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/solver/SolverSelectionOptions.h"
#include "storm/storage/StronglyConnectedComponentDecomposition.h"
namespace storm {
class Environment;
namespace solver {
template<typename ValueType>
class TopologicalMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver<ValueType> {
public:
TopologicalMinMaxLinearEquationSolver();
TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix<ValueType> const& A);
TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix<ValueType>&& A);
virtual void setMatrix(storm::storage::SparseMatrix<ValueType> const& A) override;
virtual void setMatrix(storm::storage::SparseMatrix<ValueType>&& A) override;
virtual void clearCache() const override;
virtual void repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector<ValueType>& x, std::vector<ValueType> const* b, uint_fast64_t n = 1) const override;
virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const override ;
protected:
virtual bool internalSolveEquations(storm::Environment const& env, OptimizationDirection d, std::vector<ValueType>& x, std::vector<ValueType> const& b) const override;
private:
storm::Environment getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision = false) const;
// Creates an SCC decomposition and sorts the SCCs according to a topological sort.
void createSortedSccDecomposition(bool needLongestChainSize) const;
// Solves the SCC with the given index
// ... for the case that the SCC is trivial
bool solveTrivialScc(uint64_t const& sccState, OptimizationDirection d, std::vector<ValueType>& globalX, std::vector<ValueType> const& globalB) const;
// ... for the case that there is just one large SCC
bool solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, std::vector<ValueType>& x, std::vector<ValueType> const& b) const;
// ... for the remaining cases (1 < scc.size() < x.size())
bool solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, storm::storage::BitVector const& sccRowGroups, storm::storage::BitVector const& sccRows, std::vector<ValueType>& globalX, std::vector<ValueType> const& globalB) const;
// If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted
// when the solver is destructed.
std::unique_ptr<storm::storage::SparseMatrix<ValueType>> localA;
// A pointer to the original sparse matrix given to this solver. If the solver takes posession of the matrix
// the pointer refers to localA.
storm::storage::SparseMatrix<ValueType> const* A;
// cached auxiliary data
mutable std::unique_ptr<std::vector<storm::storage::StronglyConnectedComponent>> sortedSccDecomposition;
mutable boost::optional<uint64_t> longestSccChainSize;
mutable std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> sccSolver;
mutable std::unique_ptr<std::vector<ValueType>> auxiliaryRowGroupVector; // A.rowGroupCount() entries
};
template<typename ValueType>
class TopologicalMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory<ValueType> {
public:
using MinMaxLinearEquationSolverFactory<ValueType>::create;
virtual std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> create(Environment const& env) const override;
};
}
}

4
src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp

@ -25,7 +25,7 @@
#include "storm/environment/solver/NativeSolverEnvironment.h"
#include "storm/environment/solver/GmmxxSolverEnvironment.h"
#include "storm/environment/solver/EigenSolverEnvironment.h"
#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h"
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
namespace {
@ -266,7 +266,7 @@ namespace {
static storm::Environment createEnvironment() {
storm::Environment env;
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Topological);
env.solver().topological().setUnderlyingSolverType(storm::solver::EquationSolverType::Eigen);
env.solver().topological().setUnderlyingEquationSolverType(storm::solver::EquationSolverType::Eigen);
env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU);
return env;
}

39
src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp

@ -19,6 +19,7 @@
#include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h"
#include "storm/modelchecker/results/QualitativeCheckResult.h"
#include "storm/environment/solver/MinMaxSolverEnvironment.h"
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
#include "storm/settings/modules/CoreSettings.h"
#include "storm/logic/Formulas.h"
#include "storm/storage/jani/Property.h"
@ -71,6 +72,42 @@ namespace {
return env;
}
};
class SparseDoubleTopologicalValueIterationEnvironment {
public:
static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models
static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse;
static const bool isExact = false;
typedef double ValueType;
typedef storm::models::sparse::Mdp<ValueType> ModelType;
static storm::Environment createEnvironment() {
storm::Environment env;
env.solver().minMax().setMethod(storm::solver::MinMaxMethod::Topological);
env.solver().topological().setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod::ValueIteration);
env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-8));
env.solver().minMax().setRelativeTerminationCriterion(false);
return env;
}
};
class SparseDoubleTopologicalSoundValueIterationEnvironment {
public:
static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models
static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse;
static const bool isExact = false;
typedef double ValueType;
typedef storm::models::sparse::Mdp<ValueType> ModelType;
static storm::Environment createEnvironment() {
storm::Environment env;
env.solver().setForceSoundness(true);
env.solver().minMax().setMethod(storm::solver::MinMaxMethod::Topological);
env.solver().topological().setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod::ValueIteration);
env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-6));
env.solver().minMax().setRelativeTerminationCriterion(false);
return env;
}
};
class SparseRationalPolicyIterationEnvironment {
public:
static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models
@ -300,6 +337,8 @@ namespace {
SparseDoubleValueIterationEnvironment,
SparseDoubleSoundValueIterationEnvironment,
SparseDoubleQuickValueIterationEnvironment,
SparseDoubleTopologicalValueIterationEnvironment,
SparseDoubleTopologicalSoundValueIterationEnvironment,
SparseRationalPolicyIterationEnvironment,
SparseRationalRationalSearchEnvironment,
HybridCuddDoubleValueIterationEnvironment,

4
src/test/storm/solver/LinearEquationSolverTest.cpp

@ -6,7 +6,7 @@
#include "storm/environment/solver/NativeSolverEnvironment.h"
#include "storm/environment/solver/GmmxxSolverEnvironment.h"
#include "storm/environment/solver/EigenSolverEnvironment.h"
#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h"
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
#include "storm/utility/vector.h"
namespace {
@ -273,7 +273,7 @@ namespace {
static storm::Environment createEnvironment() {
storm::Environment env;
env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Topological);
env.solver().topological().setUnderlyingSolverType(storm::solver::EquationSolverType::Eigen);
env.solver().topological().setUnderlyingEquationSolverType(storm::solver::EquationSolverType::Eigen);
env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU);
return env;
}

4
src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp

@ -6,6 +6,7 @@
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/environment/solver/MinMaxSolverEnvironment.h"
#include "storm/environment/solver/NativeSolverEnvironment.h"
#include "storm/environment/solver/TopologicalSolverEnvironment.h"
#include "storm/solver/SolverSelectionOptions.h"
#include "storm/storage/SparseMatrix.h"
@ -34,6 +35,7 @@ namespace {
return env;
}
};
class DoubleTopologicalViEnvironment {
public:
typedef double ValueType;
@ -41,10 +43,12 @@ namespace {
static storm::Environment createEnvironment() {
storm::Environment env;
env.solver().minMax().setMethod(storm::solver::MinMaxMethod::Topological);
env.solver().topological().setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod::ValueIteration);
env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-8));
return env;
}
};
class DoubleTopologicalCudaViEnvironment {
public:
typedef double ValueType;

Loading…
Cancel
Save