Browse Source

Started implementation of LRA for MDPs

- adapted storm::utility::graph::getReachableStates to work for non-deterministic matrices


Former-commit-id: cd7e469757
tempestpy_adaptions
David_Korzeniewski 10 years ago
parent
commit
7e672cddd9
  1. 151
      src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp
  2. 4
      src/modelchecker/prctl/SparseMdpPrctlModelChecker.h
  3. 2
      src/utility/graph.h

151
src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp

@ -12,6 +12,9 @@
#include "src/exceptions/InvalidPropertyException.h"
#include "src/storage/MaximalEndComponentDecomposition.h"
#include "src/storage/MaximalEndComponent.h"
namespace storm {
namespace modelchecker {
template<typename ValueType>
@ -313,6 +316,154 @@ namespace storm {
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(this->computeReachabilityRewardsHelper(optimalityType.get() == storm::logic::OptimalityType::Minimize, subResult.getTruthValuesVector(), qualitative)));
}
template<typename ValueType>
std::vector<ValueType> SparseMdpPrctlModelChecker<ValueType>::computeLongRunAverageHelper(bool minimize, storm::storage::BitVector const& psiStates, bool qualitative) const {
// If there are no goal states, we avoid the computation and directly return zero.
if (psiStates.empty()) {
return std::vector<ValueType>(model.getNumberOfStates(), storm::utility::zero<ValueType>());
}
// Likewise, if all bits are set, we can avoid the computation and set.
if ((~psiStates).empty()) {
return std::vector<ValueType>(model.getNumberOfStates(), storm::utility::one<ValueType>());
}
// Start by decomposing the MDP into its MECs.
storm::storage::MaximalEndComponentDecomposition<double> mecDecomposition(model);
// Get some data members for convenience.
typename storm::storage::SparseMatrix<ValueType> const& transitionMatrix = model.getTransitionMatrix();
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = model.getNondeterministicChoiceIndices();
// Now start with compute the long-run average for all end components in isolation.
std::vector<ValueType> lraValuesForEndComponents;
// While doing so, we already gather some information for the following steps.
std::vector<uint_fast64_t> stateToMecIndexMap(model.getNumberOfStates());
storm::storage::BitVector statesInMecs(model.getNumberOfStates());
for (uint_fast64_t currentMecIndex = 0; currentMecIndex < mecDecomposition.size(); ++currentMecIndex) {
storm::storage::MaximalEndComponent const& mec = mecDecomposition[currentMecIndex];
// Gather information for later use.
for (auto const& stateChoicesPair : mec) {
uint_fast64_t state = stateChoicesPair.first;
statesInMecs.set(state);
stateToMecIndexMap[state] = currentMecIndex;
}
// Compute the LRA value for the current MEC.
lraValuesForEndComponents.push_back(this->computeLraForMaximalEndComponent(minimize, transitionMatrix, psiStates, mec));
}
// For fast transition rewriting, we build some auxiliary data structures.
storm::storage::BitVector statesNotContainedInAnyMec = ~statesInMecs;
// Prepare result vector.
std::vector<ValueType> result(model.getNumberOfStates());
//Set the values for all states in MECs.
for (auto state : statesInMecs) {
result[state] = lraValuesForEndComponents[stateToMecIndexMap[state]];
}
//for all states not in any mec set the result to the minimal/maximal value of the reachable MECs
//there might be a more efficient way to do this...
for (auto state : statesNotContainedInAnyMec){
//calculate what result values the reachable states in MECs have
storm::storage::BitVector currentState(model.getNumberOfStates);
currentState.set(state);
storm::storage::BitVector reachableStates = storm::utility::graph::getReachableStates(
transitionMatrix, currentState, storm::storage::BitVector(model.getNumberOfStates, true), statesInMecs
);
storm::storage::BitVector reachableMecStates = statesInMecs & reachableStates;
std::vector<ValueType> reachableResults(reachableMecStates.getNumberOfSetBits());
storm::utility::vector::selectVectorValues(reachableResults, reachableMecStates, result);
//now select the minimal/maximal element
if (minimize){
result[state] = *std::min_element(reachableResults.begin(), reachableResults.end());
} else {
result[state] = *std::max_element(reachableResults.begin(), reachableResults.end());
}
}
return result;
}
template<typename ValueType>
std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<ValueType>::computeLongRunAverage(storm::logic::StateFormula const& stateFormula, bool qualitative, boost::optional<storm::logic::OptimalityType> const& optimalityType) {
STORM_LOG_THROW(optimalityType, storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
std::unique_ptr<CheckResult> subResultPointer = this->check(stateFormula);
ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult();
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(this->computeLongRunAverageHelper(optimalityType.get() == storm::logic::OptimalityType::Minimize, subResult.getTruthValuesVector(), qualitative)));
}
template<typename ValueType>
ValueType SparseMarkovAutomatonCslModelChecker<ValueType>::computeLraForMaximalEndComponent(bool minimize, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& psiStates, storm::storage::MaximalEndComponent const& mec) {
std::shared_ptr<storm::solver::LpSolver> solver = storm::utility::solver::getLpSolver("LRA for MEC");
solver->setModelSense(minimize ? storm::solver::LpSolver::ModelSense::Maximize : storm::solver::LpSolver::ModelSense::Minimize);
//// First, we need to create the variables for the problem.
//std::map<uint_fast64_t, storm::expressions::Variable> stateToVariableMap;
//for (auto const& stateChoicesPair : mec) {
// std::string variableName = "x" + std::to_string(stateChoicesPair.first);
// stateToVariableMap[stateChoicesPair.first] = solver->addUnboundedContinuousVariable(variableName);
//}
//storm::expressions::Variable k = solver->addUnboundedContinuousVariable("k", 1);
//solver->update();
//// Now we encode the problem as constraints.
//for (auto const& stateChoicesPair : mec) {
// uint_fast64_t state = stateChoicesPair.first;
// // Now, based on the type of the state, create a suitable constraint.
// if (markovianStates.get(state)) {
// storm::expressions::Expression constraint = stateToVariableMap.at(state);
// for (auto element : transitionMatrix.getRow(nondeterministicChoiceIndices[state])) {
// constraint = constraint - stateToVariableMap.at(element.getColumn()) * solver->getConstant(element.getValue());
// }
// constraint = constraint + solver->getConstant(storm::utility::one<ValueType>() / exitRates[state]) * k;
// storm::expressions::Expression rightHandSide = psiStates.get(state) ? solver->getConstant(storm::utility::one<ValueType>() / exitRates[state]) : solver->getConstant(0);
// if (minimize) {
// constraint = constraint <= rightHandSide;
// } else {
// constraint = constraint >= rightHandSide;
// }
// solver->addConstraint("state" + std::to_string(state), constraint);
// } else {
// // For probabilistic states, we want to add the constraint x_s <= sum P(s, a, s') * x_s' where a is the current action
// // and the sum ranges over all states s'.
// for (auto choice : stateChoicesPair.second) {
// storm::expressions::Expression constraint = stateToVariableMap.at(state);
// for (auto element : transitionMatrix.getRow(choice)) {
// constraint = constraint - stateToVariableMap.at(element.getColumn()) * solver->getConstant(element.getValue());
// }
// storm::expressions::Expression rightHandSide = solver->getConstant(storm::utility::zero<ValueType>());
// if (minimize) {
// constraint = constraint <= rightHandSide;
// } else {
// constraint = constraint >= rightHandSide;
// }
// solver->addConstraint("state" + std::to_string(state), constraint);
// }
// }
//}
//solver->optimize();
//return solver->getContinuousValue(k);
}
template<typename ValueType>
storm::models::Mdp<ValueType> const& SparseMdpPrctlModelChecker<ValueType>::getModel() const {
return this->template getModelAs<storm::models::Mdp<ValueType>>();

4
src/modelchecker/prctl/SparseMdpPrctlModelChecker.h

@ -39,6 +39,7 @@ namespace storm {
virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::CumulativeRewardFormula const& rewardPathFormula, bool qualitative = false, boost::optional<storm::logic::OptimalityType> const& optimalityType = boost::optional<storm::logic::OptimalityType>()) override;
virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::InstantaneousRewardFormula const& rewardPathFormula, bool qualitative = false, boost::optional<storm::logic::OptimalityType> const& optimalityType = boost::optional<storm::logic::OptimalityType>()) override;
virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::ReachabilityRewardFormula const& rewardPathFormula, bool qualitative = false, boost::optional<storm::logic::OptimalityType> const& optimalityType = boost::optional<storm::logic::OptimalityType>()) override;
virtual std::unique_ptr<CheckResult> computeLongRunAverage(storm::logic::StateFormula const& stateFormula, bool qualitative = false, boost::optional<storm::logic::OptimalityType> const& optimalityType = boost::optional<storm::logic::OptimalityType>()) override;
protected:
storm::models::Mdp<ValueType> const& getModel() const override;
@ -52,7 +53,10 @@ namespace storm {
std::vector<ValueType> computeInstantaneousRewardsHelper(bool minimize, uint_fast64_t stepCount) const;
std::vector<ValueType> computeCumulativeRewardsHelper(bool minimize, uint_fast64_t stepBound) const;
std::vector<ValueType> computeReachabilityRewardsHelper(bool minimize, storm::storage::BitVector const& targetStates, bool qualitative) const;
std::vector<ValueType> computeLongRunAverageHelper(bool minimize, storm::storage::BitVector const& psiStates, bool qualitative) const;
static ValueType computeLraForMaximalEndComponent(bool minimize, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec);
// A solver that is used for solving systems of linear equations that are the result of nondeterministic choices.
std::shared_ptr<storm::solver::NondeterministicLinearEquationSolver<ValueType>> nondeterministicLinearEquationSolver;
};

2
src/utility/graph.h

@ -51,7 +51,7 @@ namespace storm {
currentState = stack.back();
stack.pop_back();
for (auto const& successor : transitionMatrix.getRow(currentState)) {
for (auto const& successor : transitionMatrix.getRowGroup(currentState)) {
// Only explore the state if the transition was actually there and the successor has not yet
// been visited.
if (successor.getValue() != storm::utility::zero<T>() && !reachableStates.get(successor.getColumn())) {

Loading…
Cancel
Save