|  | @ -77,92 +77,64 @@ namespace storm { | 
		
	
		
			
				|  |  |             template<typename ValueType> |  |  |             template<typename ValueType> | 
		
	
		
			
				|  |  |             void ProductModel<ValueType>::setReachableProductStates(storm::storage::SparseModelMemoryProduct<ValueType>& productBuilder, std::vector<Epoch> const& originalModelSteps) const { |  |  |             void ProductModel<ValueType>::setReachableProductStates(storm::storage::SparseModelMemoryProduct<ValueType>& productBuilder, std::vector<Epoch> const& originalModelSteps) const { | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |                 storm::storage::BitVector lowerBoundedDimensions(dimensions.size(), false); |  |  |  | 
		
	
		
			
				|  |  |                 for (uint64_t dim = 0; dim < dimensions.size(); ++dim) { |  |  |  | 
		
	
		
			
				|  |  |                     if (!dimensions[dim].isUpperBounded) { |  |  |  | 
		
	
		
			
				|  |  |                         lowerBoundedDimensions.set(dim); |  |  |  | 
		
	
		
			
				|  |  |                     } |  |  |  | 
		
	
		
			
				|  |  |                 } |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                 auto const& memory = productBuilder.getMemory(); | 
		
	
		
			
				|  |  |  |  |  |                 auto const& model = productBuilder.getOriginalModel(); | 
		
	
		
			
				|  |  |  |  |  |                 auto const& modelTransitions = model.getTransitionMatrix(); | 
		
	
		
			
				|  |  |                  |  |  |                  | 
		
	
		
			
				|  |  |                 // We add additional reachable states until no more states are found
 |  |  |  | 
		
	
		
			
				|  |  |                 std::vector<storm::storage::BitVector> additionalReachableStates(memoryStateMap.size(), storm::storage::BitVector(productBuilder.getOriginalModel().getNumberOfStates(), false)); |  |  |  | 
		
	
		
			
				|  |  |                 bool converged = false; |  |  |  | 
		
	
		
			
				|  |  |                 while (!converged) { |  |  |  | 
		
	
		
			
				|  |  |                     for (uint64_t memState = 0; memState < memoryStateMap.size(); ++memState) { |  |  |  | 
		
	
		
			
				|  |  |                         auto const& memStateBv = memoryStateMap[memState]; |  |  |  | 
		
	
		
			
				|  |  |                         storm::storage::BitVector consideredObjectives(objectiveDimensions.size(), false); |  |  |  | 
		
	
		
			
				|  |  |                         do { |  |  |  | 
		
	
		
			
				|  |  |                             // The current set of considered objectives can be skipped if it contains an objective that only consists of dimensions with lower reward bounds
 |  |  |  | 
		
	
		
			
				|  |  |                             bool skipThisObjectiveSet = false; |  |  |  | 
		
	
		
			
				|  |  |                             for (auto const& objindex : consideredObjectives) { |  |  |  | 
		
	
		
			
				|  |  |                                 if (objectiveDimensions[objindex].isSubsetOf(lowerBoundedDimensions)) { |  |  |  | 
		
	
		
			
				|  |  |                                     skipThisObjectiveSet = true; |  |  |  | 
		
	
		
			
				|  |  |                                 } |  |  |  | 
		
	
		
			
				|  |  |                             } |  |  |  | 
		
	
		
			
				|  |  |                             if (!skipThisObjectiveSet) { |  |  |  | 
		
	
		
			
				|  |  |                                 storm::storage::BitVector memStatePrimeBv = memStateBv; |  |  |  | 
		
	
		
			
				|  |  |                                 for (auto const& objIndex : consideredObjectives) { |  |  |  | 
		
	
		
			
				|  |  |                                     memStatePrimeBv &= ~objectiveDimensions[objIndex]; |  |  |  | 
		
	
		
			
				|  |  |                                 } |  |  |  | 
		
	
		
			
				|  |  |                                 if (memStatePrimeBv != memStateBv) { |  |  |  | 
		
	
		
			
				|  |  |                                     uint64_t memStatePrime = convertMemoryState(memStatePrimeBv); |  |  |  | 
		
	
		
			
				|  |  |                                     for (uint64_t choice = 0; choice < productBuilder.getOriginalModel().getTransitionMatrix().getRowCount(); ++choice) { |  |  |  | 
		
	
		
			
				|  |  |                                         // Consider the choice only if for every considered objective there is one dimension for which the step of this choice is positive
 |  |  |  | 
		
	
		
			
				|  |  |                                         bool consideredChoice = true; |  |  |  | 
		
	
		
			
				|  |  |                                         for (auto const& objIndex : consideredObjectives) { |  |  |  | 
		
	
		
			
				|  |  |                                             bool objectiveHasStep = false; |  |  |  | 
		
	
		
			
				|  |  |                                             auto upperBoundedObjectiveDimensions = objectiveDimensions[objIndex] & (~lowerBoundedDimensions); |  |  |  | 
		
	
		
			
				|  |  |                                             for (auto const& dim : upperBoundedObjectiveDimensions) { |  |  |  | 
		
	
		
			
				|  |  |                                                 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) && !productBuilder.isStateReachable(successor.getColumn(), memStatePrime)) { |  |  |  | 
		
	
		
			
				|  |  |                                                     additionalReachableStates[memStatePrime].set(successor.getColumn()); |  |  |  | 
		
	
		
			
				|  |  |                                                 } |  |  |  | 
		
	
		
			
				|  |  |                                             } |  |  |  | 
		
	
		
			
				|  |  |                                         } |  |  |  | 
		
	
		
			
				|  |  |                                     } |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                 std::vector<storm::storage::BitVector> reachableStates(memory.getNumberOfStates(), storm::storage::BitVector(model.getNumberOfStates(), false)); | 
		
	
		
			
				|  |  |  |  |  |                  | 
		
	
		
			
				|  |  |  |  |  |                 // Initialize the reachable states with the initial states
 | 
		
	
		
			
				|  |  |  |  |  |                 EpochClass initEpochClass = epochManager.getEpochClass(epochManager.getZeroEpoch()); | 
		
	
		
			
				|  |  |  |  |  |                 storm::storage::BitVector initMemState(epochManager.getDimensionCount(), true); | 
		
	
		
			
				|  |  |  |  |  |                 auto memStateIt = memory.getInitialMemoryStates().begin(); | 
		
	
		
			
				|  |  |  |  |  |                 for (auto const& initState : model.getInitialStates()) { | 
		
	
		
			
				|  |  |  |  |  |                     uint64_t transformedMemoryState = transformMemoryState(*memStateIt, initEpochClass, convertMemoryState(initMemState)); | 
		
	
		
			
				|  |  |  |  |  |                     reachableStates[transformedMemoryState].set(initState, true); | 
		
	
		
			
				|  |  |  |  |  |                     ++memStateIt; | 
		
	
		
			
				|  |  |                 } |  |  |                 } | 
		
	
		
			
				|  |  |  |  |  |                 assert(memStateIt == memory.getInitialMemoryStates().end()); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |                 // Find the reachable epoch classes
 | 
		
	
		
			
				|  |  |  |  |  |                 std::set<Epoch> possibleSteps(originalModelSteps.begin(), originalModelSteps.end()); | 
		
	
		
			
				|  |  |  |  |  |                 std::set<EpochClass, std::function<bool(EpochClass const&, EpochClass const&)>> reachableEpochClasses(std::bind(&EpochManager::epochClassOrder, &epochManager, std::placeholders::_1, std::placeholders::_2)); | 
		
	
		
			
				|  |  |  |  |  |                 collectReachableEpochClasses(reachableEpochClasses, possibleSteps); | 
		
	
		
			
				|  |  |  |  |  |                  | 
		
	
		
			
				|  |  |  |  |  |   | 
		
	
		
			
				|  |  |  |  |  |                 // Iterate over all epoch classes starting from the initial one (i.e., no bottom dimension).
 | 
		
	
		
			
				|  |  |  |  |  |                 for (auto epochClassIt = reachableEpochClasses.rbegin(); epochClassIt != reachableEpochClasses.rend(); ++epochClassIt) { | 
		
	
		
			
				|  |  |  |  |  |                     auto const& epochClass = *epochClassIt; | 
		
	
		
			
				|  |  |  |  |  |                      | 
		
	
		
			
				|  |  |  |  |  |                     // Find the remaining set of reachable states via DFS.
 | 
		
	
		
			
				|  |  |  |  |  |                     std::vector<std::pair<uint64_t, uint64_t>> dfsStack; | 
		
	
		
			
				|  |  |  |  |  |                     for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) { | 
		
	
		
			
				|  |  |  |  |  |                         for (auto const& modelState : reachableStates[memState]) { | 
		
	
		
			
				|  |  |  |  |  |                             dfsStack.emplace_back(modelState, memState); | 
		
	
		
			
				|  |  |                         } |  |  |                         } | 
		
	
		
			
				|  |  |                             consideredObjectives.increment(); |  |  |  | 
		
	
		
			
				|  |  |                         } while (!consideredObjectives.empty()); |  |  |  | 
		
	
		
			
				|  |  |                     } |  |  |                     } | 
		
	
		
			
				|  |  |                  |  |  |                  | 
		
	
		
			
				|  |  |                     storm::storage::BitVector consideredDimensions(dimensions.size(), false); |  |  |  | 
		
	
		
			
				|  |  |                     do { |  |  |  | 
		
	
		
			
				|  |  |                         // todo: this selects more states then necessary
 |  |  |  | 
		
	
		
			
				|  |  |                         if (consideredDimensions.isSubsetOf(lowerBoundedDimensions)) { |  |  |  | 
		
	
		
			
				|  |  |                             for (uint64_t memoryState = 0; memoryState < productBuilder.getMemory().getNumberOfStates(); ++memoryState) { |  |  |  | 
		
	
		
			
				|  |  |                                 uint64_t memoryStatePrime = convertMemoryState(convertMemoryState(memoryState) | consideredDimensions); |  |  |  | 
		
	
		
			
				|  |  |                                 for (uint64_t modelState = 0; modelState < productBuilder.getOriginalModel().getNumberOfStates(); ++modelState) { |  |  |  | 
		
	
		
			
				|  |  |                                     if (productBuilder.isStateReachable(modelState, memoryState) && !productBuilder.isStateReachable(modelState, memoryStatePrime)) { |  |  |  | 
		
	
		
			
				|  |  |                                         additionalReachableStates[memoryStatePrime].set(modelState); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                     while (!dfsStack.empty()) { | 
		
	
		
			
				|  |  |  |  |  |                         uint64_t currentModelState = dfsStack.back().first; | 
		
	
		
			
				|  |  |  |  |  |                         uint64_t currentMemoryState = dfsStack.back().second; | 
		
	
		
			
				|  |  |  |  |  |                         dfsStack.pop_back(); | 
		
	
		
			
				|  |  |  |  |  |                          | 
		
	
		
			
				|  |  |  |  |  |                         for (uint64_t choice = modelTransitions.getRowGroupIndices()[currentModelState]; choice != modelTransitions.getRowGroupIndices()[currentModelState + 1]; ++choice) { | 
		
	
		
			
				|  |  |  |  |  |                              | 
		
	
		
			
				|  |  |  |  |  |                             for (auto transitionIt = modelTransitions.getRow(choice).begin(); transitionIt < modelTransitions.getRow(choice).end(); ++transitionIt) { | 
		
	
		
			
				|  |  |  |  |  |                                  | 
		
	
		
			
				|  |  |  |  |  |                                 uint64_t successorMemoryState = memory.getSuccessorMemoryState(currentMemoryState, transitionIt - modelTransitions.begin()); | 
		
	
		
			
				|  |  |  |  |  |                                 successorMemoryState = transformMemoryState(successorMemoryState, epochClass, currentMemoryState); | 
		
	
		
			
				|  |  |  |  |  |                                 if (!reachableStates[successorMemoryState].get(transitionIt->getColumn())) { | 
		
	
		
			
				|  |  |  |  |  |                                     reachableStates[successorMemoryState].set(transitionIt->getColumn(), true); | 
		
	
		
			
				|  |  |  |  |  |                                     dfsStack.emplace_back(transitionIt->getColumn(), successorMemoryState); | 
		
	
		
			
				|  |  |  |  |  |                                 } | 
		
	
		
			
				|  |  |                             } |  |  |                             } | 
		
	
		
			
				|  |  |                         } |  |  |                         } | 
		
	
		
			
				|  |  |                     } |  |  |                     } | 
		
	
		
			
				|  |  |                 } |  |  |                 } | 
		
	
		
			
				|  |  |                         consideredDimensions.increment(); |  |  |  | 
		
	
		
			
				|  |  |                     } while (!consideredDimensions.empty()); |  |  |  | 
		
	
		
			
				|  |  |                      |  |  |  | 
		
	
		
			
				|  |  |                     converged = true; |  |  |  | 
		
	
		
			
				|  |  |                 for (uint64_t memState = 0; memState < memoryStateMap.size(); ++memState) { |  |  |                 for (uint64_t memState = 0; memState < memoryStateMap.size(); ++memState) { | 
		
	
		
			
				|  |  |                         if (!additionalReachableStates[memState].empty()) { |  |  |  | 
		
	
		
			
				|  |  |                             converged = false; |  |  |  | 
		
	
		
			
				|  |  |                             for (auto const& modelState : additionalReachableStates[memState]) { |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                     for (auto const& modelState : reachableStates[memState]) { | 
		
	
		
			
				|  |  |                         productBuilder.addReachableState(modelState, memState); |  |  |                         productBuilder.addReachableState(modelState, memState); | 
		
	
		
			
				|  |  |                     } |  |  |                     } | 
		
	
		
			
				|  |  |                             additionalReachableStates[memState].clear(); |  |  |  | 
		
	
		
			
				|  |  |                         } |  |  |  | 
		
	
		
			
				|  |  |                     } |  |  |  | 
		
	
		
			
				|  |  |                 } |  |  |                 } | 
		
	
		
			
				|  |  |             } |  |  |             } | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
	
		
			
				|  | @ -371,9 +343,9 @@ namespace storm { | 
		
	
		
			
				|  |  |                 storm::storage::BitVector ecInStates(getProduct().getNumberOfStates(), false); |  |  |                 storm::storage::BitVector ecInStates(getProduct().getNumberOfStates(), false); | 
		
	
		
			
				|  |  |                  |  |  |                  | 
		
	
		
			
				|  |  |                 if (!epochManager.hasBottomDimensionEpochClass(epochClass)) { |  |  |                 if (!epochManager.hasBottomDimensionEpochClass(epochClass)) { | 
		
	
		
			
				|  |  |                     storm::storage::BitVector initMemState(epochManager.getDimensionCount(), true); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                     uint64_t initMemState = convertMemoryState(storm::storage::BitVector(epochManager.getDimensionCount(), true)); | 
		
	
		
			
				|  |  |                     for (auto const& initState : getProduct().getInitialStates()) { |  |  |                     for (auto const& initState : getProduct().getInitialStates()) { | 
		
	
		
			
				|  |  |                         uint64_t transformedInitState = transformProductState(initState, epochClass, convertMemoryState(initMemState)); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                         uint64_t transformedInitState = transformProductState(initState, epochClass, initMemState); | 
		
	
		
			
				|  |  |                         ecInStates.set(transformedInitState, true); |  |  |                         ecInStates.set(transformedInitState, true); | 
		
	
		
			
				|  |  |                     } |  |  |                     } | 
		
	
		
			
				|  |  |                 } |  |  |                 } | 
		
	
	
		
			
				|  | @ -388,6 +360,7 @@ namespace storm { | 
		
	
		
			
				|  |  |                     STORM_LOG_ASSERT(reachableStates.find(predecessor) != reachableStates.end(), "Could not find reachable states of predecessor epoch class."); |  |  |                     STORM_LOG_ASSERT(reachableStates.find(predecessor) != reachableStates.end(), "Could not find reachable states of predecessor epoch class."); | 
		
	
		
			
				|  |  |                     storm::storage::BitVector predecessorStates = reachableStates.find(predecessor)->second; |  |  |                     storm::storage::BitVector predecessorStates = reachableStates.find(predecessor)->second; | 
		
	
		
			
				|  |  |                     for (auto const& predecessorState : predecessorStates) { |  |  |                     for (auto const& predecessorState : predecessorStates) { | 
		
	
		
			
				|  |  |  |  |  |                         uint64_t predecessorMemoryState = getMemoryState(predecessorState); | 
		
	
		
			
				|  |  |                         for (uint64_t choice = getProduct().getTransitionMatrix().getRowGroupIndices()[predecessorState]; choice < getProduct().getTransitionMatrix().getRowGroupIndices()[predecessorState + 1]; ++choice) { |  |  |                         for (uint64_t choice = getProduct().getTransitionMatrix().getRowGroupIndices()[predecessorState]; choice < getProduct().getTransitionMatrix().getRowGroupIndices()[predecessorState + 1]; ++choice) { | 
		
	
		
			
				|  |  |                             bool choiceLeadsToThisClass = false; |  |  |                             bool choiceLeadsToThisClass = false; | 
		
	
		
			
				|  |  |                             Epoch const& choiceStep = getSteps()[choice]; |  |  |                             Epoch const& choiceStep = getSteps()[choice]; | 
		
	
	
		
			
				|  | @ -399,7 +372,7 @@ namespace storm { | 
		
	
		
			
				|  |  |                              |  |  |                              | 
		
	
		
			
				|  |  |                             if (choiceLeadsToThisClass) { |  |  |                             if (choiceLeadsToThisClass) { | 
		
	
		
			
				|  |  |                                 for (auto const& transition : getProduct().getTransitionMatrix().getRow(choice)) { |  |  |                                 for (auto const& transition : getProduct().getTransitionMatrix().getRow(choice)) { | 
		
	
		
			
				|  |  |                                     uint64_t successorState = transformProductState(transition.getColumn(), epochClass, getMemoryState(predecessorState)); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                                     uint64_t successorState = transformProductState(transition.getColumn(), epochClass, predecessorMemoryState); | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |                                     ecInStates.set(successorState, true); |  |  |                                     ecInStates.set(successorState, true); | 
		
	
		
			
				|  |  |                                 } |  |  |                                 } | 
		
	
	
		
			
				|  | @ -414,6 +387,7 @@ namespace storm { | 
		
	
		
			
				|  |  |                  |  |  |                  | 
		
	
		
			
				|  |  |                 while (!dfsStack.empty()) { |  |  |                 while (!dfsStack.empty()) { | 
		
	
		
			
				|  |  |                     uint64_t currentState = dfsStack.back(); |  |  |                     uint64_t currentState = dfsStack.back(); | 
		
	
		
			
				|  |  |  |  |  |                     uint64_t currentMemoryState = getMemoryState(currentState); | 
		
	
		
			
				|  |  |                     dfsStack.pop_back(); |  |  |                     dfsStack.pop_back(); | 
		
	
		
			
				|  |  |                      |  |  |                      | 
		
	
		
			
				|  |  |                     for (uint64_t choice = getProduct().getTransitionMatrix().getRowGroupIndices()[currentState]; choice != getProduct().getTransitionMatrix().getRowGroupIndices()[currentState + 1]; ++choice) { |  |  |                     for (uint64_t choice = getProduct().getTransitionMatrix().getRowGroupIndices()[currentState]; choice != getProduct().getTransitionMatrix().getRowGroupIndices()[currentState + 1]; ++choice) { | 
		
	
	
		
			
				|  | @ -423,11 +397,12 @@ namespace storm { | 
		
	
		
			
				|  |  |                         for (auto const& dim : nonBottomDimensions) { |  |  |                         for (auto const& dim : nonBottomDimensions) { | 
		
	
		
			
				|  |  |                             if (epochManager.getDimensionOfEpoch(choiceStep, dim) > 0) { |  |  |                             if (epochManager.getDimensionOfEpoch(choiceStep, dim) > 0) { | 
		
	
		
			
				|  |  |                                 choiceLeadsOutsideOfEpoch = true; |  |  |                                 choiceLeadsOutsideOfEpoch = true; | 
		
	
		
			
				|  |  |  |  |  |                                 break; | 
		
	
		
			
				|  |  |                             } |  |  |                             } | 
		
	
		
			
				|  |  |                         } |  |  |                         } | 
		
	
		
			
				|  |  |                          |  |  |                          | 
		
	
		
			
				|  |  |                         for (auto const& transition : getProduct().getTransitionMatrix().getRow(choice)) { |  |  |                         for (auto const& transition : getProduct().getTransitionMatrix().getRow(choice)) { | 
		
	
		
			
				|  |  |                             uint64_t successorState = transformProductState(transition.getColumn(), epochClass, getMemoryState(currentState)); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |                             uint64_t successorState = transformProductState(transition.getColumn(), epochClass, currentMemoryState); | 
		
	
		
			
				|  |  |                             if (choiceLeadsOutsideOfEpoch) { |  |  |                             if (choiceLeadsOutsideOfEpoch) { | 
		
	
		
			
				|  |  |                                 ecInStates.set(successorState, true); |  |  |                                 ecInStates.set(successorState, true); | 
		
	
		
			
				|  |  |                             } |  |  |                             } | 
		
	
	
		
			
				|  | 
 |