#include "storm/solver/AcyclicMinMaxLinearEquationSolver.h" #include "storm/solver/helper/AcyclicSolverHelper.cpp" #include "storm/utility/vector.h" namespace storm { namespace solver { template AcyclicMinMaxLinearEquationSolver::AcyclicMinMaxLinearEquationSolver() { // Intentionally left empty. } template AcyclicMinMaxLinearEquationSolver::AcyclicMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : StandardMinMaxLinearEquationSolver(A) { // Intentionally left empty. } template AcyclicMinMaxLinearEquationSolver::AcyclicMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) : StandardMinMaxLinearEquationSolver(std::move(A)) { // Intentionally left empty. } template bool AcyclicMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector 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."); if (!multiplier) { // We have not allocated cache memory, yet rowGroupOrdering = helper::computeTopologicalGroupOrdering(*this->A); if (!rowGroupOrdering) { // It is not required to reorder the elements. this->multiplier = storm::solver::MultiplierFactory().create(env, *this->A); } else { bFactors.clear(); orderedMatrix = helper::createReorderedMatrix(*this->A, *rowGroupOrdering, bFactors); this->multiplier = storm::solver::MultiplierFactory().create(env, *orderedMatrix); } auxiliaryRowVector = std::vector(this->A->getRowCount()); auxiliaryRowGroupVector = std::vector(this->A->getRowGroupCount()); } std::vector* xPtr = &x; std::vector const* bPtr = &b; if (rowGroupOrdering) { STORM_LOG_ASSERT(rowGroupOrdering->size() == x.size(), "x-vector has unexpected size."); STORM_LOG_ASSERT(auxiliaryRowGroupVector->size() == x.size(), "x-vector has unexpected size."); STORM_LOG_ASSERT(auxiliaryRowVector->size() == b.size(), "b-vector has unexpected size."); for (uint64_t newGroupIndex = 0; newGroupIndex < x.size(); ++newGroupIndex) { uint64_t newRow = orderedMatrix->getRowGroupIndices()[newGroupIndex]; uint64_t newRowGroupEnd = orderedMatrix->getRowGroupIndices()[newGroupIndex + 1]; uint64_t oldRow = this->A->getRowGroupIndices()[(*rowGroupOrdering)[newGroupIndex]]; for (; newRow < newRowGroupEnd; ++newRow, ++oldRow) { (*auxiliaryRowVector)[newRow] = b[oldRow]; } } for (auto const& bFactor : bFactors) { (*auxiliaryRowVector)[bFactor.first] *= bFactor.second; } xPtr = &auxiliaryRowGroupVector.get(); bPtr = &auxiliaryRowVector.get(); } // Allocate memory for the scheduler (if required) std::vector* choicesPtr = nullptr; if (this->isTrackSchedulerSet()) { if (this->schedulerChoices) { this->schedulerChoices->resize(this->A->getRowGroupCount()); } else { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); } if (rowGroupOrdering) { if (auxiliaryRowGroupIndexVector) { auxiliaryRowGroupIndexVector->resize(this->A->getRowGroupCount()); } else { auxiliaryRowGroupIndexVector = std::vector(this->A->getRowGroupCount()); } choicesPtr = &(auxiliaryRowGroupIndexVector.get()); } else { choicesPtr = &(this->schedulerChoices.get()); } } // Since a topological ordering is guaranteed, we can solve the equations with a single matrix-vector Multiplication step. this->multiplier->multiplyAndReduceGaussSeidel(env, dir, *xPtr, bPtr, choicesPtr); if (rowGroupOrdering) { // Restore the correct input-order for the output vector for (uint64_t newGroupIndex = 0; newGroupIndex < x.size(); ++newGroupIndex) { x[(*rowGroupOrdering)[newGroupIndex]] = (*xPtr)[newGroupIndex]; } if (this->isTrackSchedulerSet()) { // Do the same for the scheduler choices for (uint64_t newGroupIndex = 0; newGroupIndex < x.size(); ++newGroupIndex) { this->schedulerChoices.get()[(*rowGroupOrdering)[newGroupIndex]] = (*choicesPtr)[newGroupIndex]; } } } if (!this->isCachingEnabled()) { this->clearCache(); } return true; } template MinMaxLinearEquationSolverRequirements AcyclicMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { // Return the requirements of the underlying solver MinMaxLinearEquationSolverRequirements requirements; requirements.requireAcyclic(); return requirements; } template void AcyclicMinMaxLinearEquationSolver::clearCache() const { multiplier.reset(); orderedMatrix = boost::none; rowGroupOrdering = boost::none; auxiliaryRowVector = boost::none; auxiliaryRowGroupVector = boost::none; auxiliaryRowGroupIndexVector = boost::none; bFactors.clear(); } // Explicitly instantiate the min max linear equation solver. template class AcyclicMinMaxLinearEquationSolver; #ifdef STORM_HAVE_CARL template class AcyclicMinMaxLinearEquationSolver; #endif } }