17 changed files with 676 additions and 102 deletions
-
4src/storm/environment/SubEnvironment.cpp
-
4src/storm/environment/solver/MinMaxSolverEnvironment.cpp
-
2src/storm/environment/solver/MinMaxSolverEnvironment.h
-
12src/storm/environment/solver/SolverEnvironment.cpp
-
10src/storm/environment/solver/SolverEnvironment.h
-
37src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp
-
24src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h
-
56src/storm/environment/solver/TopologicalSolverEnvironment.cpp
-
31src/storm/environment/solver/TopologicalSolverEnvironment.h
-
2src/storm/solver/MinMaxLinearEquationSolver.cpp
-
38src/storm/solver/TopologicalLinearEquationSolver.cpp
-
434src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp
-
73src/storm/solver/TopologicalMinMaxLinearEquationSolver.h
-
4src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp
-
39src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp
-
4src/test/storm/solver/LinearEquationSolverTest.cpp
-
4src/test/storm/solver/MinMaxLinearEquationSolverTest.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; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
} |
|
@ -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; |
|
||||
}; |
|
||||
} |
|
||||
|
|
@ -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; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -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; |
||||
|
}; |
||||
|
} |
||||
|
|
@ -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
|
||||
|
} |
||||
|
} |
@ -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; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
} |
Reference in new issue
xxxxxxxxxx