#include "GameViHelper.h" #include "storm/environment/Environment.h" #include "storm/environment/solver/SolverEnvironment.h" #include "storm/environment/solver/GameSolverEnvironment.h" #include "storm/utility/SignalHandler.h" #include "storm/utility/vector.h" // TODO this will undergo major refactoring as soon as we implement model checking of further properties namespace storm { namespace modelchecker { namespace helper { namespace internal { template GameViHelper::GameViHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector statesOfCoalition) : _transitionMatrix(transitionMatrix), _statesOfCoalition(statesOfCoalition) { } template void GameViHelper::prepareSolversAndMultipliersReachability(const Environment& env) { // TODO we get whole transitionmatrix and psistates DONE IN smgrpatlhelper // -> clip statesofcoalition // -> compute b vector from psiStates // -> clip transitionmatrix and create multiplier _multiplier = storm::solver::MultiplierFactory().create(env, _transitionMatrix); _x1IsCurrent = false; } template void GameViHelper::performValueIteration(Environment const& env, std::vector& x, std::vector b, storm::solver::OptimizationDirection const dir) { prepareSolversAndMultipliersReachability(env); ValueType precision = storm::utility::convertNumber(env.solver().game().getPrecision()); uint64_t maxIter = env.solver().game().getMaximalNumberOfIterations(); _b = b; _x1.assign(_transitionMatrix.getRowGroupCount(), storm::utility::zero()); _x2 = _x1; if (this->isProduceSchedulerSet()) { if (!this->_producedOptimalChoices.is_initialized()) { this->_producedOptimalChoices.emplace(); } this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount()); } uint64_t iter = 0; std::vector result = x; while (iter < maxIter) { ++iter; performIterationStep(env, dir); if (checkConvergence(precision)) { break; } if (storm::utility::resources::isTerminate()) { break; } } x = xNew(); if (isProduceSchedulerSet()) { // We will be doing one more iteration step and track scheduler choices this time. performIterationStep(env, dir, &_producedOptimalChoices.get()); } } template void GameViHelper::performIterationStep(Environment const& env, storm::solver::OptimizationDirection const dir, std::vector* choices) { if (!_multiplier) { prepareSolversAndMultipliersReachability(env); } _x1IsCurrent = !_x1IsCurrent; // multiplyandreducegaussseidel // Ax + b if (choices == nullptr) { //STORM_LOG_DEBUG("\n" << _transitionMatrix); //STORM_LOG_DEBUG("xOld = " << storm::utility::vector::toString(xOld())); //STORM_LOG_DEBUG("b = " << storm::utility::vector::toString(_b)); //STORM_LOG_DEBUG("xNew = " << storm::utility::vector::toString(xNew())); _multiplier->multiplyAndReduce(env, dir, xOld(), &_b, xNew(), nullptr, &_statesOfCoalition); //std::cin.get(); } else { // Also keep track of the choices made. _multiplier->multiplyAndReduce(env, dir, xOld(), &_b, xNew(), choices, &_statesOfCoalition); } // compare applyPointwise storm::utility::vector::applyPointwise(xOld(), xNew(), xNew(), [&dir] (ValueType const& a, ValueType const& b) -> ValueType { if(storm::solver::maximize(dir)) { if(a > b) return a; else return b; } else { if(a > b) return a; else return b; } }); } template bool GameViHelper::checkConvergence(ValueType threshold) const { STORM_LOG_ASSERT(_multiplier, "tried to check for convergence without doing an iteration first."); // Now check whether the currently produced results are precise enough STORM_LOG_ASSERT(threshold > storm::utility::zero(), "Did not expect a non-positive threshold."); auto x1It = xOld().begin(); auto x1Ite = xOld().end(); auto x2It = xNew().begin(); ValueType maxDiff = (*x2It - *x1It); ValueType minDiff = maxDiff; // The difference between maxDiff and minDiff is zero at this point. Thus, it doesn't make sense to check the threshold now. for (++x1It, ++x2It; x1It != x1Ite; ++x1It, ++x2It) { ValueType diff = (*x2It - *x1It); // Potentially update maxDiff or minDiff bool skipCheck = false; if (maxDiff < diff) { maxDiff = diff; } else if (minDiff > diff) { minDiff = diff; } else { skipCheck = true; } // Check convergence if (!skipCheck && (maxDiff - minDiff) > threshold) { return false; } } // TODO needs checking return true; } template void GameViHelper::fillResultVector(std::vector& result, storm::storage::BitVector relevantStates, storm::storage::BitVector psiStates) { std::vector filledVector = std::vector(relevantStates.size(), storm::utility::zero()); uint bitIndex = 0; for(uint i = 0; i < filledVector.size(); i++) { if (relevantStates.get(i)) { filledVector.at(i) = result.at(bitIndex); bitIndex++; } else if (psiStates.get(i)) { filledVector.at(i) = 1; } } result = filledVector; } template void GameViHelper::setProduceScheduler(bool value) { _produceScheduler = value; } template bool GameViHelper::isProduceSchedulerSet() const { return _produceScheduler; } template std::vector const& GameViHelper::getProducedOptimalChoices() const { STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested."); STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?"); return this->_producedOptimalChoices.get(); } template std::vector& GameViHelper::getProducedOptimalChoices() { STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested."); STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?"); return this->_producedOptimalChoices.get(); } template storm::storage::Scheduler GameViHelper::extractScheduler() const{ auto const& optimalChoices = getProducedOptimalChoices(); storm::storage::Scheduler scheduler(optimalChoices.size()); for (uint64_t state = 0; state < optimalChoices.size(); ++state) { scheduler.setChoice(optimalChoices[state], state); } return scheduler; } template std::vector& GameViHelper::xNew() { return _x1IsCurrent ? _x1 : _x2; } template std::vector const& GameViHelper::xNew() const { return _x1IsCurrent ? _x1 : _x2; } template std::vector& GameViHelper::xOld() { return _x1IsCurrent ? _x2 : _x1; } template std::vector const& GameViHelper::xOld() const { return _x1IsCurrent ? _x2 : _x1; } template class GameViHelper; #ifdef STORM_HAVE_CARL template class GameViHelper; #endif } } } }