209 lines
11 KiB
209 lines
11 KiB
#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"
|
|
|
|
namespace storm {
|
|
namespace modelchecker {
|
|
namespace helper {
|
|
namespace internal {
|
|
|
|
template <typename ValueType>
|
|
GameViHelper<ValueType>::GameViHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector statesOfCoalition) : _transitionMatrix(transitionMatrix), _statesOfCoalition(statesOfCoalition) {
|
|
// Intentionally left empty.
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void GameViHelper<ValueType>::prepareSolversAndMultipliers(const Environment& env) {
|
|
_multiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _transitionMatrix);
|
|
_x1IsCurrent = false;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void GameViHelper<ValueType>::performValueIteration(Environment const& env, std::vector<ValueType>& x, std::vector<ValueType> b, storm::solver::OptimizationDirection const dir, std::vector<ValueType>& constrainedChoiceValues) {
|
|
prepareSolversAndMultipliers(env);
|
|
// Get precision for convergence check.
|
|
ValueType precision = storm::utility::convertNumber<ValueType>(env.solver().game().getPrecision());
|
|
uint64_t maxIter = env.solver().game().getMaximalNumberOfIterations();
|
|
_b = b;
|
|
//_x1.assign(_transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
|
|
_x1 = x;
|
|
_x2 = _x1;
|
|
|
|
if (this->isProduceSchedulerSet()) {
|
|
if (!this->_producedOptimalChoices.is_initialized()) {
|
|
this->_producedOptimalChoices.emplace();
|
|
}
|
|
this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount());
|
|
}
|
|
|
|
uint64_t iter = 0;
|
|
constrainedChoiceValues = std::vector<ValueType>(b.size(), storm::utility::zero<ValueType>());
|
|
|
|
while (iter < maxIter) {
|
|
if(iter == maxIter - 1) {
|
|
_multiplier->multiply(env, xNew(), &_b, constrainedChoiceValues);
|
|
auto rowGroupIndices = this->_transitionMatrix.getRowGroupIndices();
|
|
rowGroupIndices.erase(rowGroupIndices.begin());
|
|
_multiplier->reduce(env, dir, constrainedChoiceValues, rowGroupIndices, xNew());
|
|
break;
|
|
}
|
|
performIterationStep(env, dir);
|
|
if (checkConvergence(precision)) {
|
|
_multiplier->multiply(env, xNew(), &_b, constrainedChoiceValues);
|
|
break;
|
|
}
|
|
if (storm::utility::resources::isTerminate()) {
|
|
break;
|
|
}
|
|
++iter;
|
|
}
|
|
x = xNew();
|
|
|
|
if (isProduceSchedulerSet()) {
|
|
// We will be doing one more iteration step and track scheduler choices this time.
|
|
performIterationStep(env, dir, &_producedOptimalChoices.get());
|
|
}
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void GameViHelper<ValueType>::performIterationStep(Environment const& env, storm::solver::OptimizationDirection const dir, std::vector<uint64_t>* choices) {
|
|
if (!_multiplier) {
|
|
prepareSolversAndMultipliers(env);
|
|
}
|
|
_x1IsCurrent = !_x1IsCurrent;
|
|
|
|
if (choices == nullptr) {
|
|
_multiplier->multiplyAndReduce(env, dir, xOld(), &_b, xNew(), nullptr, &_statesOfCoalition);
|
|
} else {
|
|
_multiplier->multiplyAndReduce(env, dir, xOld(), &_b, xNew(), choices, &_statesOfCoalition);
|
|
}
|
|
}
|
|
|
|
template <typename ValueType>
|
|
bool GameViHelper<ValueType>::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<ValueType>(), "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;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void GameViHelper<ValueType>::setProduceScheduler(bool value) {
|
|
_produceScheduler = value;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
bool GameViHelper<ValueType>::isProduceSchedulerSet() const {
|
|
return _produceScheduler;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void GameViHelper<ValueType>::updateTransitionMatrix(storm::storage::SparseMatrix<ValueType> newTransitionMatrix) {
|
|
_transitionMatrix = newTransitionMatrix;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void GameViHelper<ValueType>::updateStatesOfCoalition(storm::storage::BitVector newStatesOfCoalition) {
|
|
_statesOfCoalition = newStatesOfCoalition;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
std::vector<uint64_t> const& GameViHelper<ValueType>::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 <typename ValueType>
|
|
std::vector<uint64_t>& GameViHelper<ValueType>::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 <typename ValueType>
|
|
storm::storage::Scheduler<ValueType> GameViHelper<ValueType>::extractScheduler() const{
|
|
auto const& optimalChoices = getProducedOptimalChoices();
|
|
storm::storage::Scheduler<ValueType> scheduler(optimalChoices.size());
|
|
for (uint64_t state = 0; state < optimalChoices.size(); ++state) {
|
|
scheduler.setChoice(optimalChoices[state], state);
|
|
}
|
|
return scheduler;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void GameViHelper<ValueType>::getChoiceValues(Environment const& env, std::vector<ValueType> const& x, std::vector<ValueType>& choiceValues) {
|
|
_multiplier->multiply(env, x, &_b, choiceValues);
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void GameViHelper<ValueType>::fillChoiceValuesVector(std::vector<ValueType>& choiceValues, storm::storage::BitVector psiStates, std::vector<storm::storage::SparseMatrix<double>::index_type> rowGroupIndices) {
|
|
std::vector<ValueType> allChoices = std::vector<ValueType>(rowGroupIndices.at(rowGroupIndices.size() - 1), storm::utility::zero<ValueType>());
|
|
auto choice_it = choiceValues.begin();
|
|
for(uint state = 0; state < rowGroupIndices.size() - 1; state++) {
|
|
uint rowGroupSize = rowGroupIndices[state + 1] - rowGroupIndices[state];
|
|
if (psiStates.get(state)) {
|
|
for(uint choice = 0; choice < rowGroupSize; choice++, choice_it++) {
|
|
allChoices.at(rowGroupIndices.at(state) + choice) = *choice_it;
|
|
}
|
|
}
|
|
}
|
|
choiceValues = allChoices;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
std::vector<ValueType>& GameViHelper<ValueType>::xNew() {
|
|
return _x1IsCurrent ? _x1 : _x2;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
std::vector<ValueType> const& GameViHelper<ValueType>::xNew() const {
|
|
return _x1IsCurrent ? _x1 : _x2;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
std::vector<ValueType>& GameViHelper<ValueType>::xOld() {
|
|
return _x1IsCurrent ? _x2 : _x1;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
std::vector<ValueType> const& GameViHelper<ValueType>::xOld() const {
|
|
return _x1IsCurrent ? _x2 : _x1;
|
|
}
|
|
|
|
template class GameViHelper<double>;
|
|
#ifdef STORM_HAVE_CARL
|
|
template class GameViHelper<storm::RationalNumber>;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|