4 changed files with 476 additions and 444 deletions
			
			
		- 
					417src/storm/modelchecker/multiobjective/rewardbounded/MultiDimensionalRewardUnfolding.cpp
- 
					51src/storm/modelchecker/multiobjective/rewardbounded/MultiDimensionalRewardUnfolding.h
- 
					388src/storm/modelchecker/multiobjective/rewardbounded/ProductModel.cpp
- 
					64src/storm/modelchecker/multiobjective/rewardbounded/ProductModel.h
| @ -0,0 +1,388 @@ | |||||
|  | #include "storm/modelchecker/multiobjective/rewardbounded/ProductModel.h"
 | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | #include "storm/utility/macros.h"
 | ||||
|  | #include "storm/logic/Formulas.h"
 | ||||
|  | #include "storm/logic/CloneVisitor.h"
 | ||||
|  | #include "storm/storage/memorystructure/SparseModelMemoryProduct.h"
 | ||||
|  | 
 | ||||
|  | #include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
 | ||||
|  | #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
 | ||||
|  | 
 | ||||
|  | #include "storm/exceptions/UnexpectedException.h"
 | ||||
|  | #include "storm/exceptions/NotSupportedException.h"
 | ||||
|  | 
 | ||||
|  | namespace storm { | ||||
|  |     namespace modelchecker { | ||||
|  |         namespace multiobjective { | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             ProductModel<ValueType>::ProductModel(storm::models::sparse::Mdp<ValueType> const& model, storm::storage::MemoryStructure const& memory, std::vector<storm::storage::BitVector> const& objectiveDimensions, EpochManager const& epochManager, std::vector<storm::storage::BitVector>&& memoryStateMap, std::vector<Epoch> const& originalModelSteps) : objectiveDimensions(objectiveDimensions), epochManager(epochManager), memoryStateMap(std::move(memoryStateMap)) { | ||||
|  |                  | ||||
|  |                 storm::storage::SparseModelMemoryProduct<ValueType> productBuilder(memory.product(model)); | ||||
|  |                  | ||||
|  |                 setReachableStates(productBuilder, originalModelSteps); | ||||
|  |                 product = productBuilder.build()->template as<storm::models::sparse::Mdp<ValueType>>(); | ||||
|  |                  | ||||
|  |                 uint64_t numModelStates = productBuilder.getOriginalModel().getNumberOfStates(); | ||||
|  |                 uint64_t numMemoryStates = productBuilder.getMemory().getNumberOfStates(); | ||||
|  |                 uint64_t numProductStates = getProduct().getNumberOfStates(); | ||||
|  |                  | ||||
|  |                 // Compute a mappings from product states to model/memory states and back
 | ||||
|  |                 modelMemoryToProductStateMap.resize(numMemoryStates * numModelStates, std::numeric_limits<uint64_t>::max()); | ||||
|  |                 productToModelStateMap.resize(numProductStates, std::numeric_limits<uint64_t>::max()); | ||||
|  |                 productToMemoryStateMap.resize(numProductStates, std::numeric_limits<uint64_t>::max()); | ||||
|  |                 for (uint64_t modelState = 0; modelState < numModelStates; ++modelState) { | ||||
|  |                     for (uint64_t memoryState = 0; memoryState < numMemoryStates; ++memoryState) { | ||||
|  |                         if (productBuilder.isStateReachable(modelState, memoryState)) { | ||||
|  |                             uint64_t productState = productBuilder.getResultState(modelState, memoryState); | ||||
|  |                             modelMemoryToProductStateMap[modelState * numMemoryStates + memoryState] = productState; | ||||
|  |                             productToModelStateMap[productState] = modelState; | ||||
|  |                             productToMemoryStateMap[productState] = memoryState; | ||||
|  |                         } | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |                  | ||||
|  |                 // Map choice indices of the product to the state where it origins
 | ||||
|  |                 choiceToStateMap.reserve(getProduct().getNumberOfChoices()); | ||||
|  |                 for (uint64_t productState = 0; productState < numProductStates; ++productState) { | ||||
|  |                     uint64_t groupSize = getProduct().getTransitionMatrix().getRowGroupSize(productState); | ||||
|  |                     for (uint64_t i = 0; i < groupSize; ++i) { | ||||
|  |                         choiceToStateMap.push_back(productState); | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |                  | ||||
|  |                 // Compute the epoch steps for the product
 | ||||
|  |                 steps.resize(getProduct().getNumberOfChoices(), 0); | ||||
|  |                 for (uint64_t modelState = 0; modelState < numModelStates; ++modelState) { | ||||
|  |                     uint64_t numChoices = productBuilder.getOriginalModel().getTransitionMatrix().getRowGroupSize(modelState); | ||||
|  |                     uint64_t firstChoice = productBuilder.getOriginalModel().getTransitionMatrix().getRowGroupIndices()[modelState]; | ||||
|  |                     for (uint64_t choiceOffset = 0; choiceOffset < numChoices; ++choiceOffset) { | ||||
|  |                         Epoch const& step  = originalModelSteps[firstChoice + choiceOffset]; | ||||
|  |                         if (step != 0) { | ||||
|  |                             for (uint64_t memState = 0; memState < numMemoryStates; ++memState) { | ||||
|  |                                 if (productStateExists(modelState, memState)) { | ||||
|  |                                     uint64_t productState = getProductState(modelState, memState); | ||||
|  |                                     uint64_t productChoice = getProduct().getTransitionMatrix().getRowGroupIndices()[productState] + choiceOffset; | ||||
|  |                                     assert(productChoice < getProduct().getTransitionMatrix().getRowGroupIndices()[productState + 1]); | ||||
|  |                                     steps[productChoice] = step; | ||||
|  |                                 } | ||||
|  |                             } | ||||
|  |                         } | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             void ProductModel<ValueType>::setReachableStates(storm::storage::SparseModelMemoryProduct<ValueType>& productBuilder, std::vector<Epoch> const& originalModelSteps) const { | ||||
|  |                  | ||||
|  |                 std::vector<storm::storage::BitVector> additionalReachableStates(memoryStateMap.size(), storm::storage::BitVector(productBuilder.getOriginalModel().getNumberOfStates(), false)); | ||||
|  |                 for (uint64_t memState = 0; memState < memoryStateMap.size(); ++memState) { | ||||
|  |                     auto const& memStateBv = memoryStateMap[memState]; | ||||
|  |                     storm::storage::BitVector consideredObjectives(objectiveDimensions.size(), false); | ||||
|  |                     do { | ||||
|  |                         storm::storage::BitVector memStatePrimeBv = memStateBv; | ||||
|  |                         for (auto const& objIndex : consideredObjectives) { | ||||
|  |                             memStatePrimeBv &= ~objectiveDimensions[objIndex]; | ||||
|  |                         } | ||||
|  |                         if (memStatePrimeBv != memStateBv) { | ||||
|  |                             for (uint64_t choice = 0; choice < productBuilder.getOriginalModel().getTransitionMatrix().getRowCount(); ++choice) { | ||||
|  |                                 bool consideredChoice = true; | ||||
|  |                                 for (auto const& objIndex : consideredObjectives) { | ||||
|  |                                     bool objectiveHasStep = false; | ||||
|  |                                     for (auto const& dim : objectiveDimensions[objIndex]) { | ||||
|  |                                         if (epochManager.getDimensionOfEpoch(originalModelSteps[choice], dim) > 0) { | ||||
|  |                                             objectiveHasStep = true; | ||||
|  |                                             break; | ||||
|  |                                         } | ||||
|  |                                     } | ||||
|  |                                     if (!objectiveHasStep) { | ||||
|  |                                         consideredChoice = false; | ||||
|  |                                         break; | ||||
|  |                                     } | ||||
|  |                                 } | ||||
|  |                                 if (consideredChoice) { | ||||
|  |                                     for (auto const& successor : productBuilder.getOriginalModel().getTransitionMatrix().getRow(choice)) { | ||||
|  |                                         if (productBuilder.isStateReachable(successor.getColumn(), memState)) { | ||||
|  |                                             additionalReachableStates[convertMemoryState(memStatePrimeBv)].set(successor.getColumn()); | ||||
|  |                                         } | ||||
|  |                                     } | ||||
|  |                                 } | ||||
|  |                             } | ||||
|  |                         } | ||||
|  |                         consideredObjectives.increment(); | ||||
|  |                     } while (!consideredObjectives.empty()); | ||||
|  |                 } | ||||
|  |                  | ||||
|  |                 for (uint64_t memState = 0; memState < memoryStateMap.size(); ++memState) { | ||||
|  |                     for (auto const& modelState : additionalReachableStates[memState]) { | ||||
|  |                         productBuilder.addReachableState(modelState, memState); | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |             } | ||||
|  | 
 | ||||
|  |             template<typename ValueType> | ||||
|  |             storm::models::sparse::Mdp<ValueType> const& ProductModel<ValueType>::getProduct() const { | ||||
|  |                 return *product; | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             std::vector<typename ProductModel<ValueType>::Epoch> const& ProductModel<ValueType>::getSteps() const { | ||||
|  |                 return steps; | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             bool ProductModel<ValueType>::productStateExists(uint64_t const& modelState, uint64_t const& memoryState) const { | ||||
|  |                 STORM_LOG_ASSERT(!memoryStateMap.empty(), "Tried to retrieve whether a product state exists but the memoryStateMap is not yet initialized."); | ||||
|  |                 return modelMemoryToProductStateMap[modelState * memoryStateMap.size() + memoryState] < getProduct().getNumberOfStates(); | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             uint64_t ProductModel<ValueType>::getProductState(uint64_t const& modelState, uint64_t const& memoryState) const { | ||||
|  |                 STORM_LOG_ASSERT(productStateExists(modelState, memoryState), "Tried to obtain a state in the model-memory-product that does not exist"); | ||||
|  |                 return modelMemoryToProductStateMap[modelState * memoryStateMap.size() + memoryState]; | ||||
|  |             } | ||||
|  | 
 | ||||
|  |             template<typename ValueType> | ||||
|  |             uint64_t ProductModel<ValueType>::getModelState(uint64_t const& productState) const { | ||||
|  |                 return productToModelStateMap[productState]; | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             uint64_t ProductModel<ValueType>::getMemoryState(uint64_t const& productState) const { | ||||
|  |                 return productToMemoryStateMap[productState]; | ||||
|  |             } | ||||
|  | 
 | ||||
|  |             template<typename ValueType> | ||||
|  |             storm::storage::BitVector const& ProductModel<ValueType>::convertMemoryState(uint64_t const& memoryState) const { | ||||
|  |                 STORM_LOG_ASSERT(!memoryStateMap.empty(), "Tried to convert a memory state, but the memoryStateMap is not yet initialized."); | ||||
|  |                 return memoryStateMap[memoryState]; | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             uint64_t ProductModel<ValueType>::convertMemoryState(storm::storage::BitVector const& memoryState) const { | ||||
|  |                 STORM_LOG_ASSERT(!memoryStateMap.empty(), "Tried to convert a memory state, but the memoryStateMap is not yet initialized."); | ||||
|  |                 auto memStateIt = std::find(memoryStateMap.begin(), memoryStateMap.end(), memoryState); | ||||
|  |                 return memStateIt - memoryStateMap.begin(); | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             uint64_t ProductModel<ValueType>::getNumberOfMemoryState() const { | ||||
|  |                 STORM_LOG_ASSERT(!memoryStateMap.empty(), "Tried to retrieve the number of memory states but the memoryStateMap is not yet initialized."); | ||||
|  |                 return memoryStateMap.size(); | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             uint64_t ProductModel<ValueType>::getProductStateFromChoice(uint64_t const& productChoice) const { | ||||
|  |                 return choiceToStateMap[productChoice]; | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             std::vector<std::vector<ValueType>> ProductModel<ValueType>::computeObjectiveRewards(Epoch const& epoch, std::vector<storm::modelchecker::multiobjective::Objective<ValueType>> const& objectives, std::vector<std::pair<std::shared_ptr<storm::logic::Formula const>, uint64_t>> subObjectives, std::vector<boost::optional<std::string>> const& memoryLabels) const { | ||||
|  |                 std::vector<std::vector<ValueType>> objectiveRewards; | ||||
|  |                 objectiveRewards.reserve(objectives.size()); | ||||
|  |                  | ||||
|  |                 for (uint64_t objIndex = 0; objIndex < objectives.size(); ++objIndex) { | ||||
|  |                     auto const& formula = *objectives[objIndex].formula; | ||||
|  |                     if (formula.isProbabilityOperatorFormula()) { | ||||
|  |                         storm::modelchecker::SparsePropositionalModelChecker<storm::models::sparse::Mdp<ValueType>> mc(getProduct()); | ||||
|  |                         std::vector<uint64_t> dimensionIndexMap; | ||||
|  |                         for (auto const& globalDimensionIndex : objectiveDimensions[objIndex]) { | ||||
|  |                             dimensionIndexMap.push_back(globalDimensionIndex); | ||||
|  |                         } | ||||
|  |                          | ||||
|  |                         std::shared_ptr<storm::logic::Formula const> sinkStatesFormula; | ||||
|  |                         for (auto const& dim : objectiveDimensions[objIndex]) { | ||||
|  |                             auto memLabelFormula = std::make_shared<storm::logic::AtomicLabelFormula>(memoryLabels[dim].get()); | ||||
|  |                             if (sinkStatesFormula) { | ||||
|  |                                 sinkStatesFormula = std::make_shared<storm::logic::BinaryBooleanStateFormula>(storm::logic::BinaryBooleanStateFormula::OperatorType::Or, sinkStatesFormula, memLabelFormula); | ||||
|  |                             } else { | ||||
|  |                                 sinkStatesFormula = memLabelFormula; | ||||
|  |                             } | ||||
|  |                         } | ||||
|  |                         sinkStatesFormula = std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, sinkStatesFormula); | ||||
|  |                          | ||||
|  |                         std::vector<ValueType> objRew(getProduct().getTransitionMatrix().getRowCount(), storm::utility::zero<ValueType>()); | ||||
|  |                         storm::storage::BitVector relevantObjectives(objectiveDimensions[objIndex].getNumberOfSetBits()); | ||||
|  |                          | ||||
|  |                         while (!relevantObjectives.full()) { | ||||
|  |                             relevantObjectives.increment(); | ||||
|  |                              | ||||
|  |                             // find out whether objective reward should be earned within this epoch
 | ||||
|  |                             bool collectRewardInEpoch = true; | ||||
|  |                             for (auto const& subObjIndex : relevantObjectives) { | ||||
|  |                                 if (epochManager.isBottomDimension(epoch, dimensionIndexMap[subObjIndex])) { | ||||
|  |                                     collectRewardInEpoch = false; | ||||
|  |                                     break; | ||||
|  |                                 } | ||||
|  |                             } | ||||
|  |                              | ||||
|  |                             if (collectRewardInEpoch) { | ||||
|  |                                 std::shared_ptr<storm::logic::Formula const> relevantStatesFormula; | ||||
|  |                                 std::shared_ptr<storm::logic::Formula const> goalStatesFormula =  storm::logic::CloneVisitor().clone(*sinkStatesFormula); | ||||
|  |                                 for (uint64_t subObjIndex = 0; subObjIndex < dimensionIndexMap.size(); ++subObjIndex) { | ||||
|  |                                     std::shared_ptr<storm::logic::Formula> memLabelFormula = std::make_shared<storm::logic::AtomicLabelFormula>(memoryLabels[dimensionIndexMap[subObjIndex]].get()); | ||||
|  |                                     if (relevantObjectives.get(subObjIndex)) { | ||||
|  |                                         auto rightSubFormula = subObjectives[dimensionIndexMap[subObjIndex]].first->asBoundedUntilFormula().getRightSubformula().asSharedPointer(); | ||||
|  |                                         goalStatesFormula = std::make_shared<storm::logic::BinaryBooleanStateFormula>(storm::logic::BinaryBooleanStateFormula::OperatorType::And, goalStatesFormula, rightSubFormula); | ||||
|  |                                     } else { | ||||
|  |                                         memLabelFormula = std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, memLabelFormula); | ||||
|  |                                     } | ||||
|  |                                     if (relevantStatesFormula) { | ||||
|  |                                         relevantStatesFormula = std::make_shared<storm::logic::BinaryBooleanStateFormula>(storm::logic::BinaryBooleanStateFormula::OperatorType::And, relevantStatesFormula, memLabelFormula); | ||||
|  |                                     } else { | ||||
|  |                                         relevantStatesFormula = memLabelFormula; | ||||
|  |                                     } | ||||
|  |                                 } | ||||
|  |                                  | ||||
|  |                                 storm::storage::BitVector relevantStates = mc.check(*relevantStatesFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); | ||||
|  |                                 storm::storage::BitVector relevantChoices = getProduct().getTransitionMatrix().getRowFilter(relevantStates); | ||||
|  |                                 storm::storage::BitVector goalStates = mc.check(*goalStatesFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); | ||||
|  |                                 for (auto const& choice : relevantChoices) { | ||||
|  |                                     objRew[choice] += getProduct().getTransitionMatrix().getConstrainedRowSum(choice, goalStates); | ||||
|  |                                 } | ||||
|  |                             } | ||||
|  |                         } | ||||
|  |                          | ||||
|  |                         objectiveRewards.push_back(std::move(objRew)); | ||||
|  |                          | ||||
|  |                     } else if (formula.isRewardOperatorFormula()) { | ||||
|  |                         auto const& rewModel = getProduct().getRewardModel(formula.asRewardOperatorFormula().getRewardModelName()); | ||||
|  |                         STORM_LOG_THROW(!rewModel.hasTransitionRewards(), storm::exceptions::NotSupportedException, "Reward model has transition rewards which is not expected."); | ||||
|  |                         bool rewardCollectedInEpoch = true; | ||||
|  |                         if (formula.getSubformula().isCumulativeRewardFormula()) { | ||||
|  |                             assert(objectiveDimensions[objIndex].getNumberOfSetBits() == 1); | ||||
|  |                             rewardCollectedInEpoch = !epochManager.isBottomDimension(epoch, *objectiveDimensions[objIndex].begin()); | ||||
|  |                         } else { | ||||
|  |                             STORM_LOG_THROW(formula.getSubformula().isTotalRewardFormula(), storm::exceptions::UnexpectedException, "Unexpected type of formula " << formula); | ||||
|  |                         } | ||||
|  |                         if (rewardCollectedInEpoch) { | ||||
|  |                             objectiveRewards.push_back(rewModel.getTotalRewardVector(getProduct().getTransitionMatrix())); | ||||
|  |                         } else { | ||||
|  |                             objectiveRewards.emplace_back(getProduct().getTransitionMatrix().getRowCount(), storm::utility::zero<ValueType>()); | ||||
|  |                         } | ||||
|  |                     } else { | ||||
|  |                         STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unexpected type of formula " << formula); | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |                  | ||||
|  |                 return objectiveRewards; | ||||
|  |             } | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             storm::storage::BitVector ProductModel<ValueType>::computeInStates(Epoch const& epoch) const { | ||||
|  |                 storm::storage::SparseMatrix<ValueType> const& productMatrix = getProduct().getTransitionMatrix(); | ||||
|  |                  | ||||
|  |                 // Initialize the result. Initial states are only considered if the epoch contains no bottom dimension.
 | ||||
|  |                 storm::storage::BitVector result; | ||||
|  |                 if (epochManager.hasBottomDimension(epoch)) { | ||||
|  |                     result = storm::storage::BitVector(getProduct().getNumberOfStates()); | ||||
|  |                 } else { | ||||
|  |                     result = getProduct().getInitialStates(); | ||||
|  |                 } | ||||
|  |                  | ||||
|  |                 // Compute the set of objectives that can not be satisfied anymore in the current epoch
 | ||||
|  |                 storm::storage::BitVector irrelevantObjectives(objectiveDimensions.size(), false); | ||||
|  |                 for (uint64_t objIndex = 0; objIndex < objectiveDimensions.size(); ++objIndex) { | ||||
|  |                     bool objIrrelevant = true; | ||||
|  |                     for (auto const& dim : objectiveDimensions[objIndex]) { | ||||
|  |                         if (!epochManager.isBottomDimension(epoch, dim)) { | ||||
|  |                             objIrrelevant = false; | ||||
|  |                         } | ||||
|  |                     } | ||||
|  |                     if (objIrrelevant) { | ||||
|  |                         irrelevantObjectives.set(objIndex, true); | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |      | ||||
|  |                 // Perform DFS
 | ||||
|  |                 storm::storage::BitVector reachableStates = getProduct().getInitialStates(); | ||||
|  |                 std::vector<uint_fast64_t> stack(reachableStates.begin(), reachableStates.end()); | ||||
|  |                  | ||||
|  |                 while (!stack.empty()) { | ||||
|  |                     uint64_t state = stack.back(); | ||||
|  |                     stack.pop_back(); | ||||
|  |                     for (uint64_t choice = productMatrix.getRowGroupIndices()[state]; choice < productMatrix.getRowGroupIndices()[state + 1]; ++choice) { | ||||
|  |                         auto const& choiceStep = getSteps()[choice]; | ||||
|  |                         if (!epochManager.isZeroEpoch(choiceStep)) { | ||||
|  |   | ||||
|  |                             // Compute the set of objectives that might or might not become irrelevant when the epoch is reached via the current choice
 | ||||
|  |                             storm::storage::BitVector maybeIrrelevantObjectives(objectiveDimensions.size(), false); | ||||
|  |                             for (uint64_t objIndex = 0; objIndex < objectiveDimensions.size(); ++objIndex) { | ||||
|  |                                 for (auto const& dim : objectiveDimensions[objIndex]) { | ||||
|  |                                     if (epochManager.isBottomDimension(epoch, dim) && epochManager.getDimensionOfEpoch(choiceStep, dim) > 0) { | ||||
|  |                                         maybeIrrelevantObjectives.set(objIndex); | ||||
|  |                                         break; | ||||
|  |                                     } | ||||
|  |                                 } | ||||
|  |                             } | ||||
|  |                             maybeIrrelevantObjectives &= ~irrelevantObjectives; | ||||
|  |                              | ||||
|  |                             // For optimization purposes, we treat the case that all objectives will be relevant seperately
 | ||||
|  |                             if (maybeIrrelevantObjectives.empty() && irrelevantObjectives.empty()) { | ||||
|  |                                 for (auto const& choiceSuccessor : productMatrix.getRow(choice)) { | ||||
|  |                                     result.set(choiceSuccessor.getColumn(), true); | ||||
|  |                                     if (!reachableStates.get(choiceSuccessor.getColumn())) { | ||||
|  |                                         reachableStates.set(choiceSuccessor.getColumn()); | ||||
|  |                                         stack.push_back(choiceSuccessor.getColumn()); | ||||
|  |                                     } | ||||
|  |                                 } | ||||
|  |                             } else { | ||||
|  |                                 // Enumerate all possible combinations of maybe relevant objectives
 | ||||
|  |                                 storm::storage::BitVector maybeObjSubset(maybeIrrelevantObjectives.getNumberOfSetBits(), false); | ||||
|  |                                 do { | ||||
|  |                                     for (auto const& choiceSuccessor : productMatrix.getRow(choice)) { | ||||
|  |                                         // Compute the successor memory state for the current objective-subset and transition
 | ||||
|  |                                         storm::storage::BitVector successorMemoryState = convertMemoryState(getMemoryState(choiceSuccessor.getColumn())); | ||||
|  |                                         // Unselect dimensions belonging to irrelevant objectives
 | ||||
|  |                                         for (auto const& irrelevantObjIndex : irrelevantObjectives) { | ||||
|  |                                             successorMemoryState &= ~objectiveDimensions[irrelevantObjIndex]; | ||||
|  |                                         } | ||||
|  |                                         // Unselect objectives that are not in the current subset of maybe relevant objectives
 | ||||
|  |                                         // We can skip a subset if it selects an objective that is irrelevant anyway (according to the original successor memorystate).
 | ||||
|  |                                         bool skipThisSubSet = false; | ||||
|  |                                         uint64_t i = 0; | ||||
|  |                                         for (auto const& objIndex : maybeIrrelevantObjectives) { | ||||
|  |                                             if (maybeObjSubset.get(i)) { | ||||
|  |                                                 if (successorMemoryState.isDisjointFrom(objectiveDimensions[objIndex])) { | ||||
|  |                                                     skipThisSubSet = true; | ||||
|  |                                                     break; | ||||
|  |                                                 } else { | ||||
|  |                                                     successorMemoryState &= ~objectiveDimensions[objIndex]; | ||||
|  |                                                 } | ||||
|  |                                             } | ||||
|  |                                             ++i; | ||||
|  |                                         } | ||||
|  |                                         if (!skipThisSubSet) { | ||||
|  |                                             uint64_t successorState = getProductState(getModelState(choiceSuccessor.getColumn()), convertMemoryState(successorMemoryState)); | ||||
|  |                                             result.set(successorState, true); | ||||
|  |                                             if (!reachableStates.get(successorState)) { | ||||
|  |                                                 reachableStates.set(successorState); | ||||
|  |                                                 stack.push_back(successorState); | ||||
|  |                                             } | ||||
|  |                                         } | ||||
|  |                                     } | ||||
|  |                                      | ||||
|  |                                     maybeObjSubset.increment(); | ||||
|  |                                 } while (!maybeObjSubset.empty()); | ||||
|  |                             } | ||||
|  |                         } else { | ||||
|  |                             for (auto const& choiceSuccessor : productMatrix.getRow(choice)) { | ||||
|  |                                 if (!reachableStates.get(choiceSuccessor.getColumn())) { | ||||
|  |                                     reachableStates.set(choiceSuccessor.getColumn()); | ||||
|  |                                     stack.push_back(choiceSuccessor.getColumn()); | ||||
|  |                                 } | ||||
|  |                             } | ||||
|  |                         } | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |                  | ||||
|  |                 return result; | ||||
|  |             } | ||||
|  |              | ||||
|  |             template class ProductModel<double>; | ||||
|  |             template class ProductModel<storm::RationalNumber>; | ||||
|  |              | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
| @ -0,0 +1,64 @@ | |||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <boost/optional.hpp> | ||||
|  | 
 | ||||
|  | #include "storm/storage/BitVector.h" | ||||
|  | #include "storm/modelchecker/multiobjective/Objective.h" | ||||
|  | #include "storm/modelchecker/multiobjective/rewardbounded/EpochManager.h" | ||||
|  | #include "storm/models/sparse/Mdp.h" | ||||
|  | #include "storm/utility/vector.h" | ||||
|  | #include "storm/storage/memorystructure/MemoryStructure.h" | ||||
|  | #include "storm/storage/memorystructure/SparseModelMemoryProduct.h" | ||||
|  | 
 | ||||
|  | namespace storm { | ||||
|  |     namespace modelchecker { | ||||
|  |         namespace multiobjective { | ||||
|  |              | ||||
|  |              | ||||
|  |             template<typename ValueType> | ||||
|  |             class ProductModel { | ||||
|  |             public: | ||||
|  |                  | ||||
|  |                 typedef typename EpochManager::Epoch Epoch; | ||||
|  |                  | ||||
|  |                 ProductModel(storm::models::sparse::Mdp<ValueType> const& model, storm::storage::MemoryStructure const& memory, std::vector<storm::storage::BitVector> const& objectiveDimensions, EpochManager const& epochManager, std::vector<storm::storage::BitVector>&& memoryStateMap, std::vector<Epoch> const& originalModelSteps); | ||||
|  |                  | ||||
|  |                 storm::models::sparse::Mdp<ValueType> const& getProduct() const; | ||||
|  |                 std::vector<Epoch> const& getSteps() const; | ||||
|  |                  | ||||
|  |                 bool productStateExists(uint64_t const& modelState, uint64_t const& memoryState) const; | ||||
|  |                 uint64_t getProductState(uint64_t const& modelState, uint64_t const& memoryState) const; | ||||
|  |                 uint64_t getModelState(uint64_t const& productState) const; | ||||
|  |                 uint64_t getMemoryState(uint64_t const& productState) const; | ||||
|  |                  | ||||
|  |                 uint64_t convertMemoryState(storm::storage::BitVector const& memoryState) const; | ||||
|  |                 storm::storage::BitVector const& convertMemoryState(uint64_t const& memoryState) const; | ||||
|  |                  | ||||
|  |                 uint64_t getNumberOfMemoryState() const; | ||||
|  |                  | ||||
|  |                 uint64_t getProductStateFromChoice(uint64_t const& productChoice) const; | ||||
|  |                  | ||||
|  |                 std::vector<std::vector<ValueType>> computeObjectiveRewards(Epoch const& epoch, std::vector<storm::modelchecker::multiobjective::Objective<ValueType>> const& objectives, std::vector<std::pair<std::shared_ptr<storm::logic::Formula const>, uint64_t>> subObjectives, std::vector<boost::optional<std::string>> const& memoryLabels) const; | ||||
|  |                 storm::storage::BitVector computeInStates(Epoch const& epoch) const; | ||||
|  | 
 | ||||
|  |                  | ||||
|  |             private: | ||||
|  |                  | ||||
|  |                 void setReachableStates(storm::storage::SparseModelMemoryProduct<ValueType>& productBuilder, std::vector<Epoch> const& originalModelSteps) const; | ||||
|  | 
 | ||||
|  |                 std::vector<storm::storage::BitVector> const& objectiveDimensions; | ||||
|  |                 EpochManager const& epochManager; | ||||
|  | 
 | ||||
|  |                 std::shared_ptr<storm::models::sparse::Mdp<ValueType>> product; | ||||
|  |                 std::vector<Epoch> steps; | ||||
|  |                  | ||||
|  |                 std::vector<uint64_t> modelMemoryToProductStateMap; | ||||
|  |                 std::vector<uint64_t> productToModelStateMap; | ||||
|  |                 std::vector<uint64_t> productToMemoryStateMap; | ||||
|  |                 std::vector<uint64_t> choiceToStateMap; | ||||
|  |                 std::vector<storm::storage::BitVector> memoryStateMap; | ||||
|  |                  | ||||
|  |             }; | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue