TimQu
7 years ago
8 changed files with 487 additions and 136 deletions
-
103src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveMemoryIncorporation.cpp
-
33src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveMemoryIncorporation.h
-
76src/storm/storage/memorystructure/NondeterministicMemoryStructure.cpp
-
25src/storm/storage/memorystructure/NondeterministicMemoryStructure.h
-
115src/storm/storage/memorystructure/NondeterministicMemoryStructureBuilder.cpp
-
47src/storm/storage/memorystructure/NondeterministicMemoryStructureBuilder.h
-
187src/storm/storage/memorystructure/SparseModelNondeterministicMemoryProduct.cpp
-
37src/storm/storage/memorystructure/SparseModelNondeterministicMemoryProduct.h
@ -1,103 +0,0 @@ |
|||
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveMemoryIncorporation.h"
|
|||
|
|||
#include "storm/models/sparse/Mdp.h"
|
|||
#include "storm/models/sparse/MarkovAutomaton.h"
|
|||
#include "storm/models/sparse/StandardRewardModel.h"
|
|||
#include "storm/storage/memorystructure/MemoryStructureBuilder.h"
|
|||
#include "storm/storage/memorystructure/SparseModelMemoryProduct.h"
|
|||
#include "storm/logic/Formulas.h"
|
|||
#include "storm/logic/FragmentSpecification.h"
|
|||
#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
|
|||
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
|
|||
|
|||
#include "storm/utility/macros.h"
|
|||
|
|||
#include "storm/exceptions/NotImplementedException.h"
|
|||
#include "storm/exceptions/NotSupportedException.h"
|
|||
namespace storm { |
|||
namespace modelchecker { |
|||
namespace multiobjective { |
|||
namespace preprocessing { |
|||
|
|||
template <class SparseModelType> |
|||
storm::storage::MemoryStructure getGoalMemory(SparseModelType const& model, storm::logic::Formula const& propositionalGoalStateFormula) { |
|||
STORM_LOG_THROW(propositionalGoalStateFormula.isInFragment(storm::logic::propositional()), storm::exceptions::NotSupportedException, "The subformula " << propositionalGoalStateFormula << " should be propositional."); |
|||
|
|||
storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(model); |
|||
storm::storage::BitVector goalStates = mc.check(propositionalGoalStateFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); |
|||
|
|||
// Check if the formula is already satisfied for all initial states. In such a case the trivial memory structure suffices.
|
|||
if (model.getInitialStates().isSubsetOf(goalStates)) { |
|||
STORM_LOG_INFO("One objective is already satisfied for all initial states."); |
|||
return storm::storage::MemoryStructureBuilder<typename SparseModelType::ValueType, typename SparseModelType::RewardModelType>::buildTrivialMemoryStructure(model); |
|||
} |
|||
|
|||
|
|||
// Create a memory structure that stores whether a goal state has already been reached
|
|||
storm::storage::MemoryStructureBuilder<typename SparseModelType::ValueType, typename SparseModelType::RewardModelType> builder(2, model); |
|||
builder.setTransition(0, 0, ~goalStates); |
|||
builder.setTransition(0, 1, goalStates); |
|||
builder.setTransition(1, 1, storm::storage::BitVector(model.getNumberOfStates(), true)); |
|||
for (auto const& initState : model.getInitialStates()) { |
|||
builder.setInitialMemoryState(initState, goalStates.get(initState) ? 1 : 0); |
|||
} |
|||
return builder.build(); |
|||
} |
|||
|
|||
template <class SparseModelType> |
|||
storm::storage::MemoryStructure getUntilFormulaMemory(SparseModelType const& model, storm::logic::Formula const& leftSubFormula, storm::logic::Formula const& rightSubFormula) { |
|||
auto notLeftOrRight = std::make_shared<storm::logic::BinaryBooleanStateFormula>(storm::logic::BinaryBooleanStateFormula::OperatorType::Or, |
|||
std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, leftSubFormula.asSharedPointer()), |
|||
rightSubFormula.asSharedPointer()); |
|||
return getGoalMemory<SparseModelType>(model, *notLeftOrRight); |
|||
|
|||
} |
|||
|
|||
template <class SparseModelType> |
|||
std::shared_ptr<SparseModelType> SparseMultiObjectiveMemoryIncorporation<SparseModelType>::incorporateGoalMemory(SparseModelType const& model, storm::logic::MultiObjectiveFormula const& formula) { |
|||
storm::storage::MemoryStructure memory = storm::storage::MemoryStructureBuilder<ValueType, RewardModelType>::buildTrivialMemoryStructure(model); |
|||
|
|||
for (auto const& subFormula : formula.getSubformulas()) { |
|||
STORM_LOG_THROW(subFormula->isOperatorFormula(), storm::exceptions::NotSupportedException, "The given Formula " << *subFormula << " is not supported."); |
|||
auto const& subsubFormula = subFormula->asOperatorFormula().getSubformula(); |
|||
if (subsubFormula.isEventuallyFormula()) { |
|||
memory = memory.product(getGoalMemory(model, subsubFormula.asEventuallyFormula().getSubformula())); |
|||
} else if (subsubFormula.isUntilFormula()) { |
|||
memory = memory.product(getUntilFormulaMemory(model, subsubFormula.asUntilFormula().getLeftSubformula(), subsubFormula.asUntilFormula().getRightSubformula())); |
|||
} else if (subsubFormula.isBoundedUntilFormula()) { |
|||
// For bounded formulas it is only reasonable to add the goal memory if it considers a single upper step/time bound.
|
|||
auto const& buf = subsubFormula.asBoundedUntilFormula(); |
|||
if (!buf.isMultiDimensional() && !buf.getTimeBoundReference().isRewardBound() && (!buf.hasLowerBound() || (!buf.isLowerBoundStrict() && storm::utility::isZero(buf.template getLowerBound<storm::RationalNumber>())))) { |
|||
memory = memory.product(getUntilFormulaMemory(model, buf.getLeftSubformula(), buf.getRightSubformula())); |
|||
} |
|||
} else if (subsubFormula.isGloballyFormula()) { |
|||
auto notPhi = std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, subsubFormula.asGloballyFormula().getSubformula().asSharedPointer()); |
|||
memory = memory.product(getGoalMemory(model, *notPhi)); |
|||
} else { |
|||
STORM_LOG_THROW(subFormula->isOperatorFormula(), storm::exceptions::NotSupportedException, "The given Formula " << subsubFormula << " is not supported."); |
|||
} |
|||
} |
|||
|
|||
storm::storage::SparseModelMemoryProduct<ValueType> product = memory.product(model); |
|||
return std::dynamic_pointer_cast<SparseModelType>(product.build()); |
|||
} |
|||
|
|||
template <class SparseModelType> |
|||
std::shared_ptr<SparseModelType> SparseMultiObjectiveMemoryIncorporation<SparseModelType>::incorporateFullMemory(SparseModelType const& model, uint64_t memoryStates) { |
|||
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "not implemented"); |
|||
return nullptr; |
|||
} |
|||
|
|||
|
|||
template class SparseMultiObjectiveMemoryIncorporation<storm::models::sparse::Mdp<double>>; |
|||
template class SparseMultiObjectiveMemoryIncorporation<storm::models::sparse::MarkovAutomaton<double>>; |
|||
|
|||
template class SparseMultiObjectiveMemoryIncorporation<storm::models::sparse::Mdp<storm::RationalNumber>>; |
|||
template class SparseMultiObjectiveMemoryIncorporation<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>; |
|||
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
@ -1,33 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
|
|||
#include "storm/storage/memorystructure/MemoryStructure.h" |
|||
#include "storm/logic/MultiObjectiveFormula.h" |
|||
#include "storm/logic/Formula.h" |
|||
|
|||
namespace storm { |
|||
namespace modelchecker { |
|||
namespace multiobjective { |
|||
|
|||
namespace preprocessing { |
|||
|
|||
template <class SparseModelType> |
|||
class SparseMultiObjectiveMemoryIncorporation { |
|||
|
|||
typedef typename SparseModelType::ValueType ValueType; |
|||
typedef typename SparseModelType::RewardModelType RewardModelType; |
|||
|
|||
|
|||
|
|||
public: |
|||
static std::shared_ptr<SparseModelType> incorporateGoalMemory(SparseModelType const& model, storm::logic::MultiObjectiveFormula const& formula); |
|||
static std::shared_ptr<SparseModelType> incorporateFullMemory(SparseModelType const& model, uint64_t memoryStates); |
|||
|
|||
}; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
@ -0,0 +1,76 @@ |
|||
#include "storm/storage/memorystructure/NondeterministicMemoryStructure.h"
|
|||
#include "storm/storage/memorystructure/NondeterministicMemoryStructureBuilder.h"
|
|||
|
|||
#include "storm/utility/macros.h"
|
|||
#include "storm/exceptions/InvalidArgumentException.h"
|
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
|
|||
NondeterministicMemoryStructure::NondeterministicMemoryStructure(std::vector<storm::storage::BitVector> const& transitions, uint64_t initialState) : transitions(transitions), initialState(initialState) { |
|||
STORM_LOG_THROW(this->initialState < this->transitions.size(), storm::exceptions::InvalidArgumentException, "Initial state " << this->initialState << " of nondeterministic memory structure is invalid."); |
|||
for (auto const& t : this->transitions) { |
|||
STORM_LOG_THROW(t.size() == this->transitions.size(), storm::exceptions::InvalidArgumentException, "Invalid dimension of transition matrix of nondeterministic memory structure."); |
|||
STORM_LOG_THROW(!t.empty(), storm::exceptions::InvalidArgumentException, "Invalid transition matrix of nondeterministic memory structure: No deadlock states allowed."); |
|||
} |
|||
} |
|||
|
|||
uint64_t NondeterministicMemoryStructure::getNumberOfStates() const { |
|||
return transitions.size(); |
|||
} |
|||
|
|||
uint64_t NondeterministicMemoryStructure::getInitialState() const { |
|||
return initialState; |
|||
} |
|||
|
|||
storm::storage::BitVector const& NondeterministicMemoryStructure::getTransitions(uint64_t state) const { |
|||
return transitions.at(state); |
|||
} |
|||
|
|||
uint64_t NondeterministicMemoryStructure::getNumberOfOutgoingTransitions(uint64_t state) const { |
|||
return getTransitions(state).getNumberOfSetBits(); |
|||
} |
|||
|
|||
std::vector<storm::storage::BitVector> const& NondeterministicMemoryStructure::getTransitions() const { |
|||
return transitions; |
|||
} |
|||
|
|||
std::string NondeterministicMemoryStructure::toString() const { |
|||
std::string result = "NondeterministicMemoryStructure with " + std::to_string(getNumberOfStates()) + " states.\n"; |
|||
result += "Initial state is " + std::to_string(getInitialState()) + ". Transitions are \n"; |
|||
|
|||
// header
|
|||
result += " |"; |
|||
for (uint64_t state = 0; state < getNumberOfStates(); ++state) { |
|||
if (state < 10) { |
|||
result += " "; |
|||
} |
|||
result += std::to_string(state); |
|||
} |
|||
result += "\n"; |
|||
result += "--|"; |
|||
for (uint64_t state = 0; state < getNumberOfStates(); ++state) { |
|||
result += "--"; |
|||
} |
|||
result += "\n"; |
|||
|
|||
// transition matrix entries
|
|||
for (uint64_t state = 0; state < getNumberOfStates(); ++state) { |
|||
if (state < 10) { |
|||
result += " "; |
|||
} |
|||
result += std::to_string(state) + "|"; |
|||
for (uint64_t statePrime = 0; statePrime < getNumberOfStates(); ++statePrime) { |
|||
result += " "; |
|||
if (getTransitions(state).get(statePrime)) { |
|||
result += "1"; |
|||
} else { |
|||
result += "0"; |
|||
} |
|||
} |
|||
result += "\n"; |
|||
} |
|||
return result; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include "storm/storage/BitVector.h" |
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
|
|||
class NondeterministicMemoryStructure { |
|||
|
|||
public: |
|||
NondeterministicMemoryStructure(std::vector<storm::storage::BitVector> const& transitions, uint64_t initialState); |
|||
uint64_t getNumberOfStates() const; |
|||
uint64_t getInitialState() const; |
|||
storm::storage::BitVector const& getTransitions(uint64_t state) const; |
|||
uint64_t getNumberOfOutgoingTransitions(uint64_t state) const; |
|||
std::vector<storm::storage::BitVector> const& getTransitions() const; |
|||
std::string toString() const; |
|||
private: |
|||
std::vector<storm::storage::BitVector> transitions; |
|||
uint64_t initialState; |
|||
}; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,115 @@ |
|||
#include "storm/storage/memorystructure/NondeterministicMemoryStructure.h"
|
|||
#include "storm/storage/memorystructure/NondeterministicMemoryStructureBuilder.h"
|
|||
|
|||
#include "storm/utility/macros.h"
|
|||
#include "storm/exceptions/InvalidArgumentException.h"
|
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
|
|||
std::string toString(NondeterministicMemoryStructurePattern const& pattern) { |
|||
switch (pattern) { |
|||
case NondeterministicMemoryStructurePattern::Trivial: |
|||
return "trivial"; |
|||
case NondeterministicMemoryStructurePattern::FixedCounter: |
|||
return "fixedcounter"; |
|||
case NondeterministicMemoryStructurePattern::SelectiveCounter: |
|||
return "selectivecounter"; |
|||
case NondeterministicMemoryStructurePattern::FixedRing: |
|||
return "fixedring"; |
|||
case NondeterministicMemoryStructurePattern::SelectiveRing: |
|||
return "ring"; |
|||
case NondeterministicMemoryStructurePattern::SettableBits: |
|||
return "settablebits"; |
|||
case NondeterministicMemoryStructurePattern::Full: |
|||
return "full"; |
|||
} |
|||
return "unknown"; |
|||
} |
|||
|
|||
NondeterministicMemoryStructure NondeterministicMemoryStructureBuilder::build(NondeterministicMemoryStructurePattern pattern, uint64_t numStates) const { |
|||
switch (pattern) { |
|||
case NondeterministicMemoryStructurePattern::Trivial: |
|||
STORM_LOG_ERROR_COND(numStates == 1, "Invoked building trivial nondeterministic memory structure with " << numStates << " states. However, trivial nondeterministic memory structure always has one state."); |
|||
return buildTrivialMemory(); |
|||
case NondeterministicMemoryStructurePattern::FixedCounter: |
|||
return buildFixedCountingMemory(numStates); |
|||
case NondeterministicMemoryStructurePattern::SelectiveCounter: |
|||
return buildSelectiveCountingMemory(numStates); |
|||
case NondeterministicMemoryStructurePattern::FixedRing: |
|||
return buildFixedRingMemory(numStates); |
|||
case NondeterministicMemoryStructurePattern::SelectiveRing: |
|||
return buildSelectiveRingMemory(numStates); |
|||
case NondeterministicMemoryStructurePattern::SettableBits: |
|||
return buildSettableBitsMemory(numStates); |
|||
case NondeterministicMemoryStructurePattern::Full: |
|||
return buildFullyConnectedMemory(numStates); |
|||
} |
|||
} |
|||
|
|||
NondeterministicMemoryStructure NondeterministicMemoryStructureBuilder::buildTrivialMemory() const { |
|||
return buildFullyConnectedMemory(1); |
|||
} |
|||
|
|||
NondeterministicMemoryStructure NondeterministicMemoryStructureBuilder::buildFixedCountingMemory(uint64_t numStates) const { |
|||
std::vector<storm::storage::BitVector> transitions(numStates, storm::storage::BitVector(numStates, false)); |
|||
for (uint64_t state = 0; state < numStates; ++state) { |
|||
transitions[state].set(std::min(state + 1, numStates - 1)); |
|||
} |
|||
return NondeterministicMemoryStructure(transitions, 0); |
|||
} |
|||
|
|||
NondeterministicMemoryStructure NondeterministicMemoryStructureBuilder::buildSelectiveCountingMemory(uint64_t numStates) const { |
|||
std::vector<storm::storage::BitVector> transitions(numStates, storm::storage::BitVector(numStates, false)); |
|||
for (uint64_t state = 0; state < numStates; ++state) { |
|||
transitions[state].set(state); |
|||
transitions[state].set(std::min(state + 1, numStates - 1)); |
|||
} |
|||
return NondeterministicMemoryStructure(transitions, 0); |
|||
} |
|||
|
|||
NondeterministicMemoryStructure NondeterministicMemoryStructureBuilder::buildFixedRingMemory(uint64_t numStates) const { |
|||
std::vector<storm::storage::BitVector> transitions(numStates, storm::storage::BitVector(numStates, false)); |
|||
for (uint64_t state = 0; state < numStates; ++state) { |
|||
transitions[state].set((state + 1) % numStates); |
|||
} |
|||
return NondeterministicMemoryStructure(transitions, 0); |
|||
} |
|||
|
|||
NondeterministicMemoryStructure NondeterministicMemoryStructureBuilder::buildSelectiveRingMemory(uint64_t numStates) const { |
|||
std::vector<storm::storage::BitVector> transitions(numStates, storm::storage::BitVector(numStates, false)); |
|||
for (uint64_t state = 0; state < numStates; ++state) { |
|||
transitions[state].set(state); |
|||
transitions[state].set((state + 1) % numStates); |
|||
} |
|||
return NondeterministicMemoryStructure(transitions, 0); |
|||
} |
|||
|
|||
NondeterministicMemoryStructure NondeterministicMemoryStructureBuilder::buildSettableBitsMemory(uint64_t numStates) const { |
|||
// compute the number of bits, i.e., floor(log(numStates))
|
|||
uint64_t numBits = 0; |
|||
uint64_t actualNumStates = 1; |
|||
while (actualNumStates * 2 <= numStates) { |
|||
actualNumStates *= 2; |
|||
++numBits; |
|||
} |
|||
|
|||
STORM_LOG_WARN_COND(actualNumStates == numStates, "The number of memory states for the settable bits pattern has to be a power of 2. Shrinking the number of memory states to " << actualNumStates << "."); |
|||
|
|||
std::vector<storm::storage::BitVector> transitions(actualNumStates, storm::storage::BitVector(actualNumStates, false)); |
|||
for (uint64_t state = 0; state < actualNumStates; ++state) { |
|||
transitions[state].set(state); |
|||
for (uint64_t bit = 0; bit < numBits; ++bit) { |
|||
uint64_t bitMask = 1u << bit; |
|||
transitions[state].set(state | bitMask); |
|||
} |
|||
} |
|||
return NondeterministicMemoryStructure(transitions, 0); |
|||
} |
|||
|
|||
NondeterministicMemoryStructure NondeterministicMemoryStructureBuilder::buildFullyConnectedMemory(uint64_t numStates) const { |
|||
std::vector<storm::storage::BitVector> transitions(numStates, storm::storage::BitVector(numStates, true)); |
|||
return NondeterministicMemoryStructure(transitions, 0); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,47 @@ |
|||
#pragma once |
|||
|
|||
#include "storm/storage/memorystructure/NondeterministicMemoryStructure.h" |
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
|
|||
enum class NondeterministicMemoryStructurePattern { |
|||
Trivial, FixedCounter, SelectiveCounter, FixedRing, SelectiveRing, SettableBits, Full |
|||
}; |
|||
|
|||
std::string toString(NondeterministicMemoryStructurePattern const& pattern); |
|||
|
|||
class NondeterministicMemoryStructureBuilder { |
|||
public: |
|||
// Builds a memory structure with the given pattern and the given number of states. |
|||
NondeterministicMemoryStructure build(NondeterministicMemoryStructurePattern pattern, uint64_t numStates) const; |
|||
|
|||
// Builds a memory structure that consists of just a single memory state |
|||
NondeterministicMemoryStructure buildTrivialMemory() const; |
|||
|
|||
// Builds a memory structure that consists of a chain of the given number of states. |
|||
// Every state has exactly one transition to the next state. The last state has just a selfloop. |
|||
NondeterministicMemoryStructure buildFixedCountingMemory(uint64_t numStates) const; |
|||
|
|||
// Builds a memory structure that consists of a chain of the given number of states. |
|||
// Every state has a selfloop and a transition to the next state. The last state just has a selfloop. |
|||
NondeterministicMemoryStructure buildSelectiveCountingMemory(uint64_t numStates) const; |
|||
|
|||
// Builds a memory structure that consists of a ring of the given number of states. |
|||
// Every state has a transition to the successor state |
|||
NondeterministicMemoryStructure buildFixedRingMemory(uint64_t numStates) const; |
|||
|
|||
// Builds a memory structure that consists of a ring of the given number of states. |
|||
// Every state has a transition to the successor state and a selfloop |
|||
NondeterministicMemoryStructure buildSelectiveRingMemory(uint64_t numStates) const; |
|||
|
|||
// Builds a memory structure that represents floor(log(numStates)) bits that can only be set from zero to one or from zero to zero. |
|||
NondeterministicMemoryStructure buildSettableBitsMemory(uint64_t numStates) const; |
|||
|
|||
// Builds a memory structure that consists of the given number of states which are fully connected. |
|||
NondeterministicMemoryStructure buildFullyConnectedMemory(uint64_t numStates) const; |
|||
|
|||
}; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,187 @@ |
|||
#include "storm/storage/memorystructure/SparseModelNondeterministicMemoryProduct.h"
|
|||
|
|||
#include <limits>
|
|||
#include "storm/storage/sparse/ModelComponents.h"
|
|||
#include "storm/utility/graph.h"
|
|||
#include "storm/models/sparse/Mdp.h"
|
|||
#include "storm/models/sparse/MarkovAutomaton.h"
|
|||
#include "storm/models/sparse/StandardRewardModel.h"
|
|||
|
|||
#include "storm/exceptions/NotSupportedException.h"
|
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
|
|||
template<typename SparseModelType> |
|||
SparseModelNondeterministicMemoryProduct<SparseModelType>::SparseModelNondeterministicMemoryProduct(SparseModelType const& model, storm::storage::NondeterministicMemoryStructure const& memory) : model(model), memory(memory) { |
|||
// intentionally left empty
|
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
std::shared_ptr<SparseModelType> SparseModelNondeterministicMemoryProduct<SparseModelType>::build() const { |
|||
// For simplicity we first build the 'full' product of model and memory (with model.numStates * memory.numStates states).
|
|||
storm::storage::sparse::ModelComponents<ValueType> components; |
|||
components.transitionMatrix = buildTransitions(); |
|||
components.stateLabeling = buildStateLabeling(); |
|||
|
|||
// Now delete unreachable states.
|
|||
storm::storage::BitVector allStates(components.transitionMatrix.getRowGroupCount(), true); |
|||
auto reachableStates = storm::utility::graph::getReachableStates(components.transitionMatrix, components.stateLabeling.getStates("init"), allStates, ~allStates); |
|||
components.transitionMatrix = components.transitionMatrix.getSubmatrix(true, reachableStates, reachableStates); |
|||
components.stateLabeling = components.stateLabeling.getSubLabeling(reachableStates); |
|||
|
|||
// build the remaining components
|
|||
for (auto const& rewModel : model.getRewardModels()) { |
|||
components.rewardModels.emplace(rewModel.first, buildRewardModel(rewModel.second, reachableStates)); |
|||
} |
|||
if (model.isOfType(storm::models::ModelType::MarkovAutomaton)) { |
|||
STORM_LOG_ASSERT((std::is_same<SparseModelType, storm::models::sparse::MarkovAutomaton<ValueType>>::value), "Model has unexpected type."); |
|||
auto ma = model.template as<storm::models::sparse::MarkovAutomaton<ValueType>>(); |
|||
components.exitRates = buildExitRateVector(*ma, reachableStates); |
|||
components.markovianStates = buildMarkovianStateLabeling(*ma, reachableStates); |
|||
} |
|||
return std::make_shared<SparseModelType>(std::move(components)); |
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
storm::storage::SparseMatrix<typename SparseModelNondeterministicMemoryProduct<SparseModelType>::ValueType> SparseModelNondeterministicMemoryProduct<SparseModelType>::buildTransitions() const { |
|||
storm::storage::SparseMatrix<ValueType> const& origTransitions = model.getTransitionMatrix(); |
|||
uint64_t numRows = 0; |
|||
uint64_t numEntries = 0; |
|||
for (uint64_t modelState = 0; modelState < model.getNumberOfStates(); ++modelState) { |
|||
for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) { |
|||
numRows += origTransitions.getRowGroupSize(modelState) * memory.getNumberOfOutgoingTransitions(memState); |
|||
numEntries += origTransitions.getRowGroup(modelState).getNumberOfEntries() * memory.getNumberOfOutgoingTransitions(memState); |
|||
} |
|||
} |
|||
storm::storage::SparseMatrixBuilder<ValueType> builder(numRows, |
|||
model.getNumberOfStates() * memory.getNumberOfStates(), |
|||
numEntries, |
|||
true, |
|||
true, |
|||
model.getNumberOfStates() * memory.getNumberOfStates()); |
|||
|
|||
uint64_t row = 0; |
|||
for (uint64_t modelState = 0; modelState < model.getNumberOfStates(); ++modelState) { |
|||
for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) { |
|||
builder.newRowGroup(row); |
|||
for (uint64_t origRow = origTransitions.getRowGroupIndices()[modelState]; origRow < origTransitions.getRowGroupIndices()[modelState + 1]; ++origRow) { |
|||
for (auto const& memStatePrime : memory.getTransitions(memState)) { |
|||
for (auto const& entry : origTransitions.getRow(origRow)) { |
|||
builder.addNextValue(row, getProductState(entry.getColumn(), memStatePrime), entry.getValue()); |
|||
} |
|||
++row; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return builder.build(); |
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
storm::models::sparse::StateLabeling SparseModelNondeterministicMemoryProduct<SparseModelType>::buildStateLabeling() const { |
|||
storm::models::sparse::StateLabeling labeling(model.getNumberOfStates() * memory.getNumberOfStates()); |
|||
for (auto const& labelName : model.getStateLabeling().getLabels()) { |
|||
storm::storage::BitVector newStates(model.getNumberOfStates() * memory.getNumberOfStates(), false); |
|||
|
|||
// The init label is only assigned to Product states with the initial memory state
|
|||
if (labelName == "init") { |
|||
for (auto const& modelState : model.getStateLabeling().getStates(labelName)) { |
|||
newStates.set(getProductState(modelState, memory.getInitialState())); |
|||
} |
|||
} else { |
|||
for (auto const& modelState : model.getStateLabeling().getStates(labelName)) { |
|||
for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) { |
|||
newStates.set(getProductState(modelState, memState)); |
|||
} |
|||
} |
|||
} |
|||
labeling.addLabel(labelName, std::move(newStates)); |
|||
} |
|||
return labeling; |
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
storm::models::sparse::StandardRewardModel<typename SparseModelNondeterministicMemoryProduct<SparseModelType>::ValueType> SparseModelNondeterministicMemoryProduct<SparseModelType>::buildRewardModel(storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel, storm::storage::BitVector const& reachableStates) const { |
|||
boost::optional<std::vector<ValueType>> stateRewards, actionRewards; |
|||
if (rewardModel.hasStateRewards()) { |
|||
stateRewards = std::vector<ValueType>(); |
|||
stateRewards->reserve(model.getNumberOfStates() * memory.getNumberOfStates()); |
|||
for (uint64_t modelState = 0; modelState < model.getNumberOfStates(); ++modelState) { |
|||
for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) { |
|||
if (reachableStates.get(getProductState(modelState, memState))) { |
|||
stateRewards->push_back(rewardModel.getStateReward(modelState)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if (rewardModel.hasStateActionRewards()) { |
|||
actionRewards = std::vector<ValueType>(); |
|||
for (uint64_t modelState = 0; modelState < model.getNumberOfStates(); ++modelState) { |
|||
for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) { |
|||
if (reachableStates.get(getProductState(modelState, memState))) { |
|||
for (uint64_t origRow = model.getTransitionMatrix().getRowGroupIndices()[modelState]; origRow < model.getTransitionMatrix().getRowGroupIndices()[modelState + 1]; ++origRow) { |
|||
ValueType const& actionReward = rewardModel.getStateActionReward(origRow); |
|||
actionRewards->insert(actionRewards->end(), memory.getNumberOfOutgoingTransitions(memState), actionReward); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotSupportedException, "Transition rewards are currently not supported."); |
|||
return storm::models::sparse::StandardRewardModel<ValueType>(std::move(stateRewards), std::move(actionRewards)); |
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
std::vector<typename SparseModelNondeterministicMemoryProduct<SparseModelType>::ValueType> SparseModelNondeterministicMemoryProduct<SparseModelType>::buildExitRateVector(storm::models::sparse::MarkovAutomaton<ValueType> const& modelAsMA, storm::storage::BitVector const& reachableStates) const { |
|||
std::vector<ValueType> res; |
|||
res.reserve(model.getNumberOfStates() * memory.getNumberOfStates()); |
|||
for (uint64_t modelState = 0; modelState < model.getNumberOfStates(); ++modelState) { |
|||
for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) { |
|||
if (reachableStates.get(getProductState(modelState, memState))) { |
|||
res.push_back(modelAsMA.getExitRate(modelState)); |
|||
} |
|||
} |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
storm::storage::BitVector SparseModelNondeterministicMemoryProduct<SparseModelType>::buildMarkovianStateLabeling(storm::models::sparse::MarkovAutomaton<ValueType> const& modelAsMA, storm::storage::BitVector const& reachableStates) const { |
|||
storm::storage::BitVector res(reachableStates.getNumberOfSetBits(), false); |
|||
uint64_t currReachableState = 0; |
|||
for (uint64_t modelState = 0; modelState < model.getNumberOfStates(); ++modelState) { |
|||
for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) { |
|||
if (reachableStates.get(getProductState(modelState, memState))) { |
|||
if (modelAsMA.isMarkovianState(modelState)) { |
|||
res.set(currReachableState, true); |
|||
} |
|||
++currReachableState; |
|||
} |
|||
} |
|||
} |
|||
assert(currReachableState == reachableStates.getNumberOfSetBits()); |
|||
return res; |
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
uint64_t SparseModelNondeterministicMemoryProduct<SparseModelType>::getProductState(uint64_t modelState, uint64_t memoryState) const { |
|||
return modelState * memory.getNumberOfStates() + memoryState; |
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
uint64_t SparseModelNondeterministicMemoryProduct<SparseModelType>::getModelState(uint64_t productState) const { |
|||
return productState / memory.getNumberOfStates(); |
|||
} |
|||
|
|||
template<typename SparseModelType> |
|||
uint64_t SparseModelNondeterministicMemoryProduct<SparseModelType>::getMemoryState(uint64_t productState) const { |
|||
return productState % memory.getNumberOfStates(); |
|||
} |
|||
|
|||
template class SparseModelNondeterministicMemoryProduct<storm::models::sparse::Mdp<double>>; |
|||
template class SparseModelNondeterministicMemoryProduct<storm::models::sparse::Mdp<storm::RationalNumber>>; |
|||
template class SparseModelNondeterministicMemoryProduct<storm::models::sparse::MarkovAutomaton<double>>; |
|||
template class SparseModelNondeterministicMemoryProduct<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>; |
|||
} |
|||
} |
@ -0,0 +1,37 @@ |
|||
#pragma once |
|||
|
|||
#include "storm/storage/memorystructure/NondeterministicMemoryStructure.h" |
|||
#include "storm/models/sparse/MarkovAutomaton.h" |
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
|
|||
|
|||
template<typename SparseModelType> |
|||
class SparseModelNondeterministicMemoryProduct { |
|||
public: |
|||
|
|||
typedef typename SparseModelType::ValueType ValueType; |
|||
|
|||
SparseModelNondeterministicMemoryProduct(SparseModelType const& model, storm::storage::NondeterministicMemoryStructure const& memory); |
|||
|
|||
std::shared_ptr<SparseModelType> build() const; |
|||
|
|||
private: |
|||
storm::storage::SparseMatrix<ValueType> buildTransitions() const; |
|||
storm::models::sparse::StateLabeling buildStateLabeling() const; |
|||
storm::models::sparse::StandardRewardModel<ValueType> buildRewardModel(storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel, storm::storage::BitVector const& reachableStates) const; |
|||
|
|||
// Markov automaton specific components |
|||
std::vector<ValueType> buildExitRateVector(storm::models::sparse::MarkovAutomaton<ValueType> const& modelAsMA, storm::storage::BitVector const& reachableStates) const; |
|||
storm::storage::BitVector buildMarkovianStateLabeling(storm::models::sparse::MarkovAutomaton<ValueType> const& modelAsMA, storm::storage::BitVector const& reachableStates) const; |
|||
|
|||
uint64_t getProductState(uint64_t modelState, uint64_t memoryState) const; |
|||
uint64_t getModelState(uint64_t productState) const; |
|||
uint64_t getMemoryState(uint64_t productState) const; |
|||
|
|||
SparseModelType const& model; |
|||
storm::storage::NondeterministicMemoryStructure const& memory; |
|||
}; |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue