Browse Source
			
			
			handling of end components in which no reward is earned
			
				
		handling of end components in which no reward is earned
	
		
	
			
				Former-commit-id: 84f6149011
			
			
				main
			
			
		
				 3 changed files with 261 additions and 45 deletions
			
			
		- 
					4src/modelchecker/multiobjective/helper/SparseMultiObjectiveModelCheckerHelper.cpp
 - 
					91src/modelchecker/multiobjective/helper/SparseWeightedObjectivesModelCheckerHelper.cpp
 - 
					211src/transformer/EffectlessMECRemover.h
 
@ -0,0 +1,211 @@ | 
			
		|||||
 | 
				#ifndef STORM_TRANSFORMER_EFFECTLESSMECREMOVER_H | 
			
		||||
 | 
				#define STORM_TRANSFORMER_EFFECTLESSMECREMOVER_H | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				#include "src/utility/constants.h" | 
			
		||||
 | 
				#include "src/utility/macros.h" | 
			
		||||
 | 
				#include "src/utility/graph.h" | 
			
		||||
 | 
				#include "src/utility/vector.h" | 
			
		||||
 | 
				#include "src/storage/MaximalEndComponentDecomposition.h" | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				namespace storm { | 
			
		||||
 | 
				    namespace transformer { | 
			
		||||
 | 
				         | 
			
		||||
 | 
				        template <typename ValueType> | 
			
		||||
 | 
				        class EffectlessMECRemover { | 
			
		||||
 | 
				        public: | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				            struct EffectlessMECRemoverReturnType { | 
			
		||||
 | 
				                // The resulting matrix | 
			
		||||
 | 
				                storm::storage::SparseMatrix<ValueType> matrix; | 
			
		||||
 | 
				                // The resulting vector | 
			
		||||
 | 
				                std::vector<ValueType> vector; | 
			
		||||
 | 
				                // Index mapping that gives for each row of the resulting matrix and vector the corresponding row in the original matrix and vector. | 
			
		||||
 | 
				                // For the rows that lead to the newly introduced sink state, some row of the original matrix that stays inside the EC is given. | 
			
		||||
 | 
				                // The selfloop of the newly introduced sink state has no entry, i.e., matrix.rowCount() == newToOldRowMapping.size() + 1. | 
			
		||||
 | 
				                std::vector<uint_fast64_t> newToOldRowMapping; | 
			
		||||
 | 
				                // Gives for each state (=rowGroup) of the original matrix and vector the corresponding state in the resulting matrix and vector. | 
			
		||||
 | 
				                // if the given state does not exist in the result, the returned value will be numeric_limits<uint_fast64_t>::max() | 
			
		||||
 | 
				                std::vector<uint_fast64_t> oldToNewStateMapping; | 
			
		||||
 | 
				            }; | 
			
		||||
 | 
				             | 
			
		||||
 | 
				            /* | 
			
		||||
 | 
				             * Identifies maximal effectless end components and replaces them by a single state. | 
			
		||||
 | 
				             * | 
			
		||||
 | 
				             * A choice is effectless, iff the given vector is zero at the corresponding row. | 
			
		||||
 | 
				             * An EC is effectless iff it only consideres effectless choices. | 
			
		||||
 | 
				             * For each such EC that is not contained by another effectles EC, we add a new state and redirect all incoming and outgoing | 
			
		||||
 | 
				             * transitions of the EC to (and from) this state. | 
			
		||||
 | 
				             * If allowChoiceToSink is true for at least one state in an effectless EC, a choice that leads to a sink state is added to the new state. | 
			
		||||
 | 
				             * States from which all reachable choices are effectless will be removed. | 
			
		||||
 | 
				             * | 
			
		||||
 | 
				             */ | 
			
		||||
 | 
				            static EffectlessMECRemoverReturnType transform(storm::storage::SparseMatrix<ValueType> const& originalMatrix, std::vector<ValueType> const& originalVector, storm::storage::BitVector const& allowChoiceToSink) { | 
			
		||||
 | 
				                STORM_LOG_DEBUG("Invoked EffectlessMECRemover on matrix with " << originalMatrix.getRowGroupCount() << " row groups."); | 
			
		||||
 | 
				                 | 
			
		||||
 | 
				                storm::storage::BitVector keptStates = computeStatesFromWhichNonEffectlessChoiceIsReachable(originalMatrix, originalVector); | 
			
		||||
 | 
				                storm::storage::MaximalEndComponentDecomposition<ValueType> effectlessECs = computeEffectlessECs(originalMatrix, originalVector, keptStates); | 
			
		||||
 | 
				                 | 
			
		||||
 | 
				                //further shrink the set of kept states by removing all states that are part of an effectless EC | 
			
		||||
 | 
				                for (auto const& ec : effectlessECs) { | 
			
		||||
 | 
				                     for (auto const& stateActionsPair : ec) { | 
			
		||||
 | 
				                         keptStates.set(stateActionsPair.first, false); | 
			
		||||
 | 
				                     } | 
			
		||||
 | 
				                } | 
			
		||||
 | 
				                STORM_LOG_DEBUG("Found " << effectlessECs.size() << " effectless End Components. Keeping " << keptStates.getNumberOfSetBits() << " of " << keptStates.size() << " original states."); | 
			
		||||
 | 
				                 | 
			
		||||
 | 
				                EffectlessMECRemoverReturnType result; | 
			
		||||
 | 
				                std::vector<uint_fast64_t> newRowGroupIndices; | 
			
		||||
 | 
				                result.oldToNewStateMapping = std::vector<uint_fast64_t>(originalMatrix.getRowGroupCount(), std::numeric_limits<uint_fast64_t>::max()); | 
			
		||||
 | 
				                storm::storage::BitVector rowsToSinkState(originalMatrix.getRowCount(), false); // will be resized as soon as rowCount of resulting matrix is known | 
			
		||||
 | 
				                 | 
			
		||||
 | 
				                for(auto keptState : keptStates) { | 
			
		||||
 | 
				                    result.oldToNewStateMapping[keptState] = newRowGroupIndices.size(); // i.e., the current number of processed states | 
			
		||||
 | 
				                    newRowGroupIndices.push_back(result.newToOldRowMapping.size());     // i.e., the current number of processed rows | 
			
		||||
 | 
				                    for(uint_fast64_t oldRow = originalMatrix.getRowGroupIndices()[keptState]; oldRow < originalMatrix.getRowGroupIndices()[keptState + 1]; ++oldRow) { | 
			
		||||
 | 
				                        result.newToOldRowMapping.push_back(oldRow); | 
			
		||||
 | 
				                    } | 
			
		||||
 | 
				                } | 
			
		||||
 | 
				                for (auto const& ec : effectlessECs) { | 
			
		||||
 | 
				                    newRowGroupIndices.push_back(result.newToOldRowMapping.size()); | 
			
		||||
 | 
				                    bool ecHasChoiceToSink = false; | 
			
		||||
 | 
				                    for (auto const& stateActionsPair : ec) { | 
			
		||||
 | 
				                        result.oldToNewStateMapping[stateActionsPair.first] = newRowGroupIndices.size()-1; | 
			
		||||
 | 
				                        for(uint_fast64_t choice = 0; choice < originalMatrix.getRowGroupSize(stateActionsPair.first); ++choice) { | 
			
		||||
 | 
				                            if(stateActionsPair.second.find(choice) == stateActionsPair.second.end()) { | 
			
		||||
 | 
				                                result.newToOldRowMapping.push_back(originalMatrix.getRowGroupIndices()[stateActionsPair.first] + choice); | 
			
		||||
 | 
				                            } | 
			
		||||
 | 
				                        } | 
			
		||||
 | 
				                        ecHasChoiceToSink |= allowChoiceToSink.get(stateActionsPair.first); | 
			
		||||
 | 
				                    } | 
			
		||||
 | 
				                    if(ecHasChoiceToSink) { | 
			
		||||
 | 
				                        STORM_LOG_ASSERT(result.newToOldRowMapping.size() < originalMatrix.getRowCount(), "Didn't expect to see more rows in the reduced matrix than in the original one."); | 
			
		||||
 | 
				                        rowsToSinkState.set(result.newToOldRowMapping.size(), true); | 
			
		||||
 | 
				                        result.newToOldRowMapping.push_back(originalMatrix.getRowGroupIndices()[ec.begin()->first] + (*ec.begin()->second.begin())); | 
			
		||||
 | 
				                    } | 
			
		||||
 | 
				                } | 
			
		||||
 | 
				                 | 
			
		||||
 | 
				                newRowGroupIndices.push_back(result.newToOldRowMapping.size()); | 
			
		||||
 | 
				                newRowGroupIndices.push_back(result.newToOldRowMapping.size()+1); | 
			
		||||
 | 
				                rowsToSinkState.resize(result.newToOldRowMapping.size()); | 
			
		||||
 | 
				                 | 
			
		||||
 | 
				                result.matrix = buildTransformedMatrix(originalMatrix, newRowGroupIndices, result.newToOldRowMapping, result.oldToNewStateMapping, rowsToSinkState); | 
			
		||||
 | 
				                result.vector = buildTransformedVector(originalVector, result.newToOldRowMapping); | 
			
		||||
 | 
				               | 
			
		||||
 | 
				                STORM_LOG_DEBUG("EffectlessMECRemover is done. Resulting matrix has " << result.matrix.getRowGroupCount() << " row groups."); | 
			
		||||
 | 
				                return result; | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				             | 
			
		||||
 | 
				        private: | 
			
		||||
 | 
				             | 
			
		||||
 | 
				            static storm::storage::BitVector computeStatesFromWhichNonEffectlessChoiceIsReachable(storm::storage::SparseMatrix<ValueType> const& originalMatrix, std::vector<ValueType> const& originalVector) { | 
			
		||||
 | 
				                storm::storage::BitVector statesWithNonEffectlessChoice(originalMatrix.getRowGroupCount(), false); | 
			
		||||
 | 
				                for(uint_fast64_t rowGroup = 0; rowGroup < originalMatrix.getRowGroupCount(); ++rowGroup){ | 
			
		||||
 | 
				                    for(uint_fast64_t row = originalMatrix.getRowGroupIndices()[rowGroup]; row < originalMatrix.getRowGroupIndices()[rowGroup+1]; ++row) { | 
			
		||||
 | 
				                        if(!storm::utility::isZero(originalVector[row])) { | 
			
		||||
 | 
				                            statesWithNonEffectlessChoice.set(rowGroup); | 
			
		||||
 | 
				                            break; | 
			
		||||
 | 
				                        } | 
			
		||||
 | 
				                    } | 
			
		||||
 | 
				                } | 
			
		||||
 | 
				                storm::storage::BitVector trueVector(originalMatrix.getRowGroupCount(), true); | 
			
		||||
 | 
				                return storm::utility::graph::performProbGreater0E(originalMatrix, originalMatrix.getRowGroupIndices(), originalMatrix.transpose(true), trueVector, statesWithNonEffectlessChoice); | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				             | 
			
		||||
 | 
				            static storm::storage::MaximalEndComponentDecomposition<ValueType> computeEffectlessECs(storm::storage::SparseMatrix<ValueType> const& originalMatrix, std::vector<ValueType> const& originalVector, storm::storage::BitVector const& keptStates) { | 
			
		||||
 | 
				                // Get an auxiliary matrix to identify the effectless end components. | 
			
		||||
 | 
				                // This is done by redirecting choices that can never be part of an effectless EC to a sink state. | 
			
		||||
 | 
				                // Such choices are either non-effectless choices or choices that lead to a state that is not in keptStates. | 
			
		||||
 | 
				                storm::storage::BitVector effectlessChoices = storm::utility::vector::filter<ValueType>(originalVector, [&] (ValueType const& value) -> bool {return storm::utility::isZero(value); } ); | 
			
		||||
 | 
				                uint_fast64_t sinkState = originalMatrix.getRowGroupCount(); | 
			
		||||
 | 
				                storm::storage::SparseMatrixBuilder<ValueType> builder(originalMatrix.getRowCount() + 1, originalMatrix.getColumnCount() + 1, originalMatrix.getEntryCount() + 1, false, true,  originalMatrix.getRowGroupCount()+1); | 
			
		||||
 | 
				                uint_fast64_t row = 0; | 
			
		||||
 | 
				                for(uint_fast64_t rowGroup = 0; rowGroup < originalMatrix.getRowGroupCount(); ++rowGroup) { | 
			
		||||
 | 
				                    builder.newRowGroup(row); | 
			
		||||
 | 
				                    for (; row < originalMatrix.getRowGroupIndices()[rowGroup+1]; ++row ){ | 
			
		||||
 | 
				                        bool keepRow = effectlessChoices.get(row); | 
			
		||||
 | 
				                        if(keepRow) { //Also check whether all successors are kept | 
			
		||||
 | 
				                            for(auto const& entry : originalMatrix.getRow(row)){ | 
			
		||||
 | 
				                                keepRow &= keptStates.get(entry.getColumn()); | 
			
		||||
 | 
				                            } | 
			
		||||
 | 
				                        } | 
			
		||||
 | 
				                        if(keepRow) { | 
			
		||||
 | 
				                            for(auto const& entry : originalMatrix.getRow(row)){ | 
			
		||||
 | 
				                                builder.addNextValue(row, entry.getColumn(), entry.getValue()); | 
			
		||||
 | 
				                            } | 
			
		||||
 | 
				                        } else { | 
			
		||||
 | 
				                            builder.addNextValue(row, sinkState, storm::utility::one<ValueType>()); | 
			
		||||
 | 
				                        } | 
			
		||||
 | 
				                    } | 
			
		||||
 | 
				                } | 
			
		||||
 | 
				                builder.newRowGroup(row); | 
			
		||||
 | 
				                builder.addNextValue(row, sinkState, storm::utility::one<ValueType>()); | 
			
		||||
 | 
				                storm::storage::SparseMatrix<ValueType> auxiliaryMatrix = builder.build(); | 
			
		||||
 | 
				                storm::storage::SparseMatrix<ValueType> backwardsTransitions = auxiliaryMatrix.transpose(true); | 
			
		||||
 | 
				                storm::storage::BitVector sinkStateAsBitVector(auxiliaryMatrix.getRowGroupCount(), false); | 
			
		||||
 | 
				                sinkStateAsBitVector.set(sinkState); | 
			
		||||
 | 
				                storm::storage::BitVector subsystem = keptStates; | 
			
		||||
 | 
				                subsystem.resize(keptStates.size() + 1, true); | 
			
		||||
 | 
				                // The states for which sinkState is reachable under any scheduler can not be part of an EC | 
			
		||||
 | 
				                subsystem &= ~(storm::utility::graph::performProbGreater0A(auxiliaryMatrix, auxiliaryMatrix.getRowGroupIndices(), backwardsTransitions, subsystem, sinkStateAsBitVector)); | 
			
		||||
 | 
				                return storm::storage::MaximalEndComponentDecomposition<ValueType>(auxiliaryMatrix, backwardsTransitions, subsystem); | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				             | 
			
		||||
 | 
				            static storm::storage::SparseMatrix<ValueType> buildTransformedMatrix(storm::storage::SparseMatrix<ValueType> const& originalMatrix, | 
			
		||||
 | 
				                                                                                  std::vector<uint_fast64_t> const& newRowGroupIndices, | 
			
		||||
 | 
				                                                                                  std::vector<uint_fast64_t> const& newToOldRowMapping, | 
			
		||||
 | 
				                                                                                  std::vector<uint_fast64_t> const& oldToNewStateMapping, | 
			
		||||
 | 
				                                                                                  storm::storage::BitVector const& rowsToSinkState) { | 
			
		||||
 | 
				                 | 
			
		||||
 | 
				                uint_fast64_t numRowGroups = newRowGroupIndices.size()-1; | 
			
		||||
 | 
				                uint_fast64_t sinkState = numRowGroups-1; | 
			
		||||
 | 
				                storm::storage::SparseMatrixBuilder<ValueType> builder(newToOldRowMapping.size()+1, numRowGroups, 0, false, true, numRowGroups); | 
			
		||||
 | 
				                // Insert all matrix entries except the selfloop of the sink state | 
			
		||||
 | 
				                for(uint_fast64_t newRowGroup = 0; newRowGroup < numRowGroups-1; ++newRowGroup) { | 
			
		||||
 | 
				                    uint_fast64_t newRow = newRowGroupIndices[newRowGroup]; | 
			
		||||
 | 
				                    builder.newRowGroup(newRow); | 
			
		||||
 | 
				                    for(; newRow < newRowGroupIndices[newRowGroup+1]; ++newRow) { | 
			
		||||
 | 
				                        if(rowsToSinkState.get(newRow)) { | 
			
		||||
 | 
				                            builder.addNextValue(newRow, sinkState, storm::utility::one<ValueType>()); | 
			
		||||
 | 
				                        } else { | 
			
		||||
 | 
				                            // Make sure that the entries for this row are inserted in the right order. | 
			
		||||
 | 
				                            // Also, transitions to the same EC need to be merged. and transitions to states that are erased need to be ignored | 
			
		||||
 | 
				                            std::map<uint_fast64_t, ValueType> sortedEntries; | 
			
		||||
 | 
				                            for(auto const& entry : originalMatrix.getRow(newToOldRowMapping[newRow])){ | 
			
		||||
 | 
				                                uint_fast64_t newColumn = oldToNewStateMapping[entry.getColumn()]; | 
			
		||||
 | 
				                                if(newColumn < numRowGroups) { | 
			
		||||
 | 
				                                    auto insertRes = sortedEntries.insert(std::make_pair(newColumn, entry.getValue())); | 
			
		||||
 | 
				                                    if(!insertRes.second) { | 
			
		||||
 | 
				                                        // We have already seen an entry with this column. ==> merge transitions | 
			
		||||
 | 
				                                        insertRes.first->second += entry.getValue(); | 
			
		||||
 | 
				                                    } | 
			
		||||
 | 
				                                } | 
			
		||||
 | 
				                            } | 
			
		||||
 | 
				                            for(auto const& sortedEntry : sortedEntries) { | 
			
		||||
 | 
				                                builder.addNextValue(newRow, sortedEntry.first, sortedEntry.second); | 
			
		||||
 | 
				                            } | 
			
		||||
 | 
				                        } | 
			
		||||
 | 
				                    } | 
			
		||||
 | 
				                } | 
			
		||||
 | 
				                //Now add the selfloop at the sink state | 
			
		||||
 | 
				                builder.newRowGroup(newRowGroupIndices[sinkState]); | 
			
		||||
 | 
				                builder.addNextValue(newRowGroupIndices[sinkState], sinkState, storm::utility::one<ValueType>()); | 
			
		||||
 | 
				                 | 
			
		||||
 | 
				                return builder.build(); | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				             | 
			
		||||
 | 
				            static std::vector<ValueType> buildTransformedVector(std::vector<ValueType> const& originalVector, std::vector<uint_fast64_t> const& newToOldRowMapping) { | 
			
		||||
 | 
				                std::vector<ValueType> v; | 
			
		||||
 | 
				                v.reserve(newToOldRowMapping.size()+1); | 
			
		||||
 | 
				                for(auto const& oldRow : newToOldRowMapping) { | 
			
		||||
 | 
				                    v.push_back(originalVector[oldRow]); | 
			
		||||
 | 
				                } | 
			
		||||
 | 
				                // add entry for the sink state | 
			
		||||
 | 
				                v.push_back(storm::utility::zero<ValueType>()); | 
			
		||||
 | 
				                return v; | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				             | 
			
		||||
 | 
				        }; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				} | 
			
		||||
 | 
				#endif // STORM_TRANSFORMER_EFFECTLESSMECREMOVER_H | 
			
		||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue