|  |  | @ -54,18 +54,39 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                 // Subtract from the maybe states the set of states that is not reachable (on a path from the initial to a target state).
 | 
			
		
	
		
			
				
					|  |  |  |                 maybeStates &= reachableStates; | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Otherwise, we build the submatrix that only has the transitions of the maybe states.
 | 
			
		
	
		
			
				
					|  |  |  |                 // Create a vector for the probabilities to go to a state with probability 1 in one step.
 | 
			
		
	
		
			
				
					|  |  |  |                 std::vector<ValueType> oneStepProbabilities = dtmc.getTransitionMatrix().getConstrainedRowSumVector(maybeStates, statesWithProbability1); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Determine the set of initial states of the sub-DTMC.
 | 
			
		
	
		
			
				
					|  |  |  |                 storm::storage::BitVector newInitialStates = dtmc.getInitialStates() % maybeStates; | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // We then build the submatrix that only has the transitions of the maybe states.
 | 
			
		
	
		
			
				
					|  |  |  |                 storm::storage::SparseMatrix<ValueType> submatrix = dtmc.getTransitionMatrix().getSubmatrix(false, maybeStates, maybeStates); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Create a bit vector that represents the subsystem of states we still have to eliminate.
 | 
			
		
	
		
			
				
					|  |  |  |                 storm::storage::BitVector subsystem = storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Now eliminate chains.
 | 
			
		
	
		
			
				
					|  |  |  | //                {
 | 
			
		
	
		
			
				
					|  |  |  | //                    storm::storage::SparseMatrix<ValueType> backwardTransitions = submatrix.transpose();
 | 
			
		
	
		
			
				
					|  |  |  | //                    
 | 
			
		
	
		
			
				
					|  |  |  | //                    // As a preprocessing step, we eliminate all states in place that have exactly one outgoing transition,
 | 
			
		
	
		
			
				
					|  |  |  | //                    // because we can eliminate them in-place.
 | 
			
		
	
		
			
				
					|  |  |  | //                    for (auto state : maybeStates & ~newInitialStates) {
 | 
			
		
	
		
			
				
					|  |  |  | //                        if (submatrix.getRow(state).getNumberOfEntries() == 1 && backwardTransitions.getRow(state).getNumberOfEntries() == 1) {
 | 
			
		
	
		
			
				
					|  |  |  | //                            if (eliminateStateInPlace(submatrix, oneStepProbabilities, state, backwardTransitions)) {
 | 
			
		
	
		
			
				
					|  |  |  | //                                subsystem.set(state, false);
 | 
			
		
	
		
			
				
					|  |  |  | //                            }
 | 
			
		
	
		
			
				
					|  |  |  | //                        }
 | 
			
		
	
		
			
				
					|  |  |  | //                    }
 | 
			
		
	
		
			
				
					|  |  |  | //                }
 | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily.
 | 
			
		
	
		
			
				
					|  |  |  |                 FlexibleSparseMatrix<ValueType> flexibleMatrix = getFlexibleSparseMatrix(submatrix); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Create a vector for the probabilities to go to a state with probability 1 in one step.
 | 
			
		
	
		
			
				
					|  |  |  |                 std::vector<ValueType> oneStepProbabilities = dtmc.getTransitionMatrix().getConstrainedRowSumVector(maybeStates, statesWithProbability1); | 
			
		
	
		
			
				
					|  |  |  |                 FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions = getFlexibleSparseMatrix(submatrix.transpose(), true); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Then, we recursively treat all SCCs.
 | 
			
		
	
		
			
				
					|  |  |  |                 FlexibleSparseMatrix<ValueType> backwardTransitions = getFlexibleSparseMatrix(submatrix.transpose(), true); | 
			
		
	
		
			
				
					|  |  |  |                 treatScc(dtmc, flexibleMatrix, oneStepProbabilities, dtmc.getInitialStates() % maybeStates, storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true), submatrix, backwardTransitions, false, 0); | 
			
		
	
		
			
				
					|  |  |  |                 treatScc(dtmc, flexibleMatrix, oneStepProbabilities, newInitialStates, subsystem, submatrix, flexibleBackwardTransitions, false, 0); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Now, we return the value for the only initial state.
 | 
			
		
	
		
			
				
					|  |  |  |                 return oneStepProbabilities[initialStateIndex]; | 
			
		
	
	
		
			
				
					|  |  | @ -76,10 +97,10 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                 // If the SCCs are large enough, we try to split them further.
 | 
			
		
	
		
			
				
					|  |  |  |                 if (scc.getNumberOfSetBits() > SparseSccModelChecker<ValueType>::maximalSccSize) { | 
			
		
	
		
			
				
					|  |  |  |                     // Here, we further decompose the SCC into sub-SCCs.
 | 
			
		
	
		
			
				
					|  |  |  |                     storm::storage::StronglyConnectedComponentDecomposition<ValueType> decomposition(forwardTransitions, scc & ~entryStates, true, false); | 
			
		
	
		
			
				
					|  |  |  |                     storm::storage::StronglyConnectedComponentDecomposition<ValueType> decomposition(forwardTransitions, scc & ~entryStates, false, false); | 
			
		
	
		
			
				
					|  |  |  |                      | 
			
		
	
		
			
				
					|  |  |  |                     // To eliminate the remaining one-state SCCs, we need to keep track of them.
 | 
			
		
	
		
			
				
					|  |  |  |                     storm::storage::BitVector remainingStates(scc); | 
			
		
	
		
			
				
					|  |  |  |                     // storm::storage::BitVector remainingStates(scc);
 | 
			
		
	
		
			
				
					|  |  |  |                      | 
			
		
	
		
			
				
					|  |  |  |                     // Store a bit vector of remaining SCCs so we can be flexible when it comes to the order in which
 | 
			
		
	
		
			
				
					|  |  |  |                     // we eliminate the SCCs.
 | 
			
		
	
	
		
			
				
					|  |  | @ -106,7 +127,7 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                          | 
			
		
	
		
			
				
					|  |  |  |                         // Rewrite SCC into bit vector and subtract it from the remaining states.
 | 
			
		
	
		
			
				
					|  |  |  |                         storm::storage::BitVector newSccAsBitVector(forwardTransitions.getRowCount(), newScc.begin(), newScc.end()); | 
			
		
	
		
			
				
					|  |  |  |                         remainingStates &= ~newSccAsBitVector; | 
			
		
	
		
			
				
					|  |  |  |                         // remainingStates &= ~newSccAsBitVector;
 | 
			
		
	
		
			
				
					|  |  |  |                          | 
			
		
	
		
			
				
					|  |  |  |                         // Determine the set of entry states of the SCC.
 | 
			
		
	
		
			
				
					|  |  |  |                         storm::storage::BitVector entryStates(dtmc.getNumberOfStates()); | 
			
		
	
	
		
			
				
					|  |  | @ -124,15 +145,15 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                      | 
			
		
	
		
			
				
					|  |  |  |                     // If we are not supposed to eliminate the entry states, we need to take them out of the set of
 | 
			
		
	
		
			
				
					|  |  |  |                     // remaining states.
 | 
			
		
	
		
			
				
					|  |  |  |                     if (!eliminateEntryStates) { | 
			
		
	
		
			
				
					|  |  |  |                         remainingStates &= ~entryStates; | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                      | 
			
		
	
		
			
				
					|  |  |  |                     // if (!eliminateEntryStates) {
 | 
			
		
	
		
			
				
					|  |  |  |                     //     remainingStates &= ~entryStates;
 | 
			
		
	
		
			
				
					|  |  |  |                     // }
 | 
			
		
	
		
			
				
					|  |  |  |                     //
 | 
			
		
	
		
			
				
					|  |  |  |                     // Now that we eliminated all non-trivial sub-SCCs, we need to take care of trivial sub-SCCs.
 | 
			
		
	
		
			
				
					|  |  |  |                     // Therefore, we need to eliminate all states.
 | 
			
		
	
		
			
				
					|  |  |  |                     for (auto const& state : remainingStates) { | 
			
		
	
		
			
				
					|  |  |  |                         eliminateState(matrix, oneStepProbabilities, state, backwardTransitions); | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                     // for (auto const& state : remainingStates) {
 | 
			
		
	
		
			
				
					|  |  |  |                     //     eliminateState(matrix, oneStepProbabilities, state, backwardTransitions);
 | 
			
		
	
		
			
				
					|  |  |  |                     // }
 | 
			
		
	
		
			
				
					|  |  |  |                 } else { | 
			
		
	
		
			
				
					|  |  |  |                     // In this case, we perform simple state elimination in the current SCC.
 | 
			
		
	
		
			
				
					|  |  |  |                     storm::storage::BitVector remainingStates(scc); | 
			
		
	
	
		
			
				
					|  |  | @ -301,6 +322,86 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                 currentStateSuccessors.shrink_to_fit(); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             template <typename ValueType> | 
			
		
	
		
			
				
					|  |  |  |             bool SparseSccModelChecker<ValueType>::eliminateStateInPlace(storm::storage::SparseMatrix<ValueType>& matrix, std::vector<ValueType>& oneStepProbabilities, uint_fast64_t state, storm::storage::SparseMatrix<ValueType>& backwardTransitions) { | 
			
		
	
		
			
				
					|  |  |  |                 typename storm::storage::SparseMatrix<ValueType>::iterator forwardElement = matrix.getRow(state).begin(); | 
			
		
	
		
			
				
					|  |  |  |                 typename storm::storage::SparseMatrix<ValueType>::iterator backwardElement = backwardTransitions.getRow(state).begin(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                 if (forwardElement->getValue() != storm::utility::constantOne<ValueType>() || backwardElement->getValue() != storm::utility::constantOne<ValueType>()) { | 
			
		
	
		
			
				
					|  |  |  |                     return false; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 std::cout << "eliminating " << state << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 std::cout << "fwd element: " << *forwardElement << " and bwd element: " << *backwardElement << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Find the element of the predecessor that moves to the state that we want to eliminate.
 | 
			
		
	
		
			
				
					|  |  |  |                 typename storm::storage::SparseMatrix<ValueType>::rows forwardRow = matrix.getRow(backwardElement->getColumn()); | 
			
		
	
		
			
				
					|  |  |  |                 typename storm::storage::SparseMatrix<ValueType>::iterator multiplyElement = std::find_if(forwardRow.begin(), forwardRow.end(), [&](storm::storage::MatrixEntry<typename storm::storage::SparseMatrix<ValueType>::index_type, typename storm::storage::SparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() == state; }); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 std::cout << "before fwd: " << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 for (auto element : matrix.getRow(backwardElement->getColumn())) { | 
			
		
	
		
			
				
					|  |  |  |                     std::cout << element << ", " << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Modify the forward probability entry of the predecessor.
 | 
			
		
	
		
			
				
					|  |  |  |                 multiplyElement->setValue(multiplyElement->getValue() * forwardElement->getValue()); | 
			
		
	
		
			
				
					|  |  |  |                 multiplyElement->setColumn(forwardElement->getColumn()); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Modify the one-step probability for the predecessor if necessary.
 | 
			
		
	
		
			
				
					|  |  |  |                 if (oneStepProbabilities[state] != storm::utility::constantZero<ValueType>()) { | 
			
		
	
		
			
				
					|  |  |  |                     oneStepProbabilities[backwardElement->getColumn()] += multiplyElement->getValue() * oneStepProbabilities[state]; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // If the forward entry is not at the right position, we need to move it there.
 | 
			
		
	
		
			
				
					|  |  |  |                 if (multiplyElement != forwardRow.begin() && multiplyElement->getColumn() < (multiplyElement - 1)->getColumn()) { | 
			
		
	
		
			
				
					|  |  |  |                     while (multiplyElement != forwardRow.begin() && multiplyElement->getColumn() < (multiplyElement - 1)->getColumn()) { | 
			
		
	
		
			
				
					|  |  |  |                         std::swap(*multiplyElement, *(multiplyElement - 1)); | 
			
		
	
		
			
				
					|  |  |  |                         --multiplyElement; | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                 } else if ((multiplyElement + 1) != forwardRow.end() && multiplyElement->getColumn() > (multiplyElement + 1)->getColumn()) { | 
			
		
	
		
			
				
					|  |  |  |                     while ((multiplyElement + 1) != forwardRow.end() && multiplyElement->getColumn() > (multiplyElement + 1)->getColumn()) { | 
			
		
	
		
			
				
					|  |  |  |                         std::swap(*multiplyElement, *(multiplyElement + 1)); | 
			
		
	
		
			
				
					|  |  |  |                         ++multiplyElement; | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 std::cout << "after fwd: " << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 for (auto element : matrix.getRow(backwardElement->getColumn())) { | 
			
		
	
		
			
				
					|  |  |  |                     std::cout << element << ", " << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Find the backward element of the successor that moves to the state that we want to eliminate.
 | 
			
		
	
		
			
				
					|  |  |  |                 typename storm::storage::SparseMatrix<ValueType>::rows backwardRow = backwardTransitions.getRow(forwardElement->getColumn()); | 
			
		
	
		
			
				
					|  |  |  |                 typename storm::storage::SparseMatrix<ValueType>::iterator backwardEntry = std::find_if(backwardRow.begin(), backwardRow.end(), [&](storm::storage::MatrixEntry<typename storm::storage::SparseMatrix<ValueType>::index_type, typename storm::storage::SparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() == state; }); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 std::cout << "before bwd" << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 for (auto element : backwardTransitions.getRow(forwardElement->getColumn())) { | 
			
		
	
		
			
				
					|  |  |  |                     std::cout << element << ", " << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Modify the predecessor list of the successor and add the predecessor of the state we eliminate.
 | 
			
		
	
		
			
				
					|  |  |  |                 backwardEntry->setColumn(backwardElement->getColumn()); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // If the backward entry is not at the right position, we need to move it there.
 | 
			
		
	
		
			
				
					|  |  |  |                 if (backwardEntry != backwardRow.begin() && backwardEntry->getColumn() < (backwardEntry - 1)->getColumn()) { | 
			
		
	
		
			
				
					|  |  |  |                     while (backwardEntry != backwardRow.begin() && backwardEntry->getColumn() < (backwardEntry - 1)->getColumn()) { | 
			
		
	
		
			
				
					|  |  |  |                         std::swap(*backwardEntry, *(backwardEntry - 1)); | 
			
		
	
		
			
				
					|  |  |  |                         --backwardEntry; | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                 } else if ((backwardEntry + 1) != backwardRow.end() && backwardEntry->getColumn() > (backwardEntry + 1)->getColumn()) { | 
			
		
	
		
			
				
					|  |  |  |                     while ((backwardEntry + 1) != backwardRow.end() && backwardEntry->getColumn() > (backwardEntry + 1)->getColumn()) { | 
			
		
	
		
			
				
					|  |  |  |                         std::swap(*backwardEntry, *(backwardEntry + 1)); | 
			
		
	
		
			
				
					|  |  |  |                         ++backwardEntry; | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 std::cout << "after bwd" << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 for (auto element : backwardTransitions.getRow(forwardElement->getColumn())) { | 
			
		
	
		
			
				
					|  |  |  |                     std::cout << element << ", " << std::endl; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                 return true; | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             template<typename ValueType> | 
			
		
	
		
			
				
					|  |  |  |             FlexibleSparseMatrix<ValueType>::FlexibleSparseMatrix(index_type rows) : data(rows) { | 
			
		
	
		
			
				
					|  |  |  |                 // Intentionally left empty.
 | 
			
		
	
	
		
			
				
					|  |  | 
 |