From 09f192b40f89768f9264cc005197127109f3cae2 Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 17 Nov 2013 15:29:09 +0100 Subject: [PATCH] Refactored SCC-Decomposition design as a preparation step for computing maximal end components of Markov automata. Former-commit-id: 4596ba71ec3ca3eac44cf35f3ed4911903a01307 --- src/models/AbstractModel.h | 20 +-- src/storage/Decomposition.cpp | 57 +++++++ src/storage/Decomposition.h | 54 ++++++ ...tronglyConnectedComponentDecomposition.cpp | 156 ++++++++++++++++++ .../StronglyConnectedComponentDecomposition.h | 49 ++++++ src/storage/VectorSet.h | 2 + src/utility/graph.h | 137 --------------- test/performance/graph/GraphTest.cpp | 17 +- 8 files changed, 337 insertions(+), 155 deletions(-) create mode 100644 src/storage/Decomposition.cpp create mode 100644 src/storage/Decomposition.h create mode 100644 src/storage/StronglyConnectedComponentDecomposition.cpp create mode 100644 src/storage/StronglyConnectedComponentDecomposition.h diff --git a/src/models/AbstractModel.h b/src/models/AbstractModel.h index fd01131c3..8689802e3 100644 --- a/src/models/AbstractModel.h +++ b/src/models/AbstractModel.h @@ -10,6 +10,7 @@ #include "src/storage/BitVector.h" #include "src/storage/SparseMatrix.h" #include "src/storage/VectorSet.h" +#include "src/storage/StronglyConnectedComponentDecomposition.h" #include "src/utility/Hash.h" namespace storm { @@ -146,15 +147,14 @@ class AbstractModel: public std::enable_shared_from_this> { * @param partition A vector containing the blocks of the partition of the system. * @return A sparse matrix with bool entries that represents the dependency graph of the blocks of the partition. */ - storm::storage::SparseMatrix extractPartitionDependencyGraph(std::vector> const& partition) const { - uint_fast64_t numberOfStates = partition.size(); + storm::storage::SparseMatrix extractPartitionDependencyGraph(storm::storage::Decomposition const& decomposition) const { + uint_fast64_t numberOfStates = decomposition.size(); - // First, we need to create a mapping of states to their SCC index, to ease the computation - // of dependency transitions later. + // First, we need to create a mapping of states to their SCC index, to ease the computation of dependency transitions later. std::vector stateToBlockMap(this->getNumberOfStates()); - for (uint_fast64_t i = 0; i < numberOfStates; ++i) { - for (uint_fast64_t j = 0; j < partition[i].size(); ++j) { - stateToBlockMap[partition[i][j]] = i; + for (uint_fast64_t i = 0; i < decomposition.size(); ++i) { + for (auto state : decomposition[i]) { + stateToBlockMap[state] = i; } } @@ -162,12 +162,12 @@ class AbstractModel: public std::enable_shared_from_this> { storm::storage::SparseMatrix dependencyGraph(numberOfStates); dependencyGraph.initialize(); - for (uint_fast64_t currentBlockIndex = 0; currentBlockIndex < partition.size(); ++currentBlockIndex) { + for (uint_fast64_t currentBlockIndex = 0; currentBlockIndex < decomposition.size(); ++currentBlockIndex) { // Get the next block. - std::vector const& block = partition[currentBlockIndex]; + typename storm::storage::Decomposition::Block const& block = decomposition[currentBlockIndex]; // Now, we determine the blocks which are reachable (in one step) from the current block. - std::set allTargetBlocks; + storm::storage::VectorSet allTargetBlocks; for (auto state : block) { typename storm::storage::SparseMatrix::Rows rows = this->getRows(state); for (auto& transition : rows) { diff --git a/src/storage/Decomposition.cpp b/src/storage/Decomposition.cpp new file mode 100644 index 000000000..dace4879a --- /dev/null +++ b/src/storage/Decomposition.cpp @@ -0,0 +1,57 @@ +#include "src/storage/Decomposition.h" + +namespace storm { + namespace storage { + + Decomposition::Decomposition() : blocks() { + // Intentionally left empty. + } + + Decomposition::Decomposition(Decomposition const& other) : blocks(other.blocks) { + // Intentionally left empty. + } + + Decomposition& Decomposition::operator=(Decomposition const& other) { + this->blocks = other.blocks; + return *this; + } + + Decomposition::Decomposition(Decomposition&& other) : blocks(std::move(other.blocks)) { + // Intentionally left empty. + } + + Decomposition& Decomposition::operator=(Decomposition&& other) { + this->blocks = std::move(other.blocks); + return *this; + } + + size_t Decomposition::size() const { + return blocks.size(); + } + + Decomposition::iterator Decomposition::begin() { + return blocks.begin(); + } + + Decomposition::iterator Decomposition::end() { + return blocks.end(); + } + + Decomposition::const_iterator Decomposition::begin() const { + return blocks.begin(); + } + + Decomposition::const_iterator Decomposition::end() const { + return blocks.end(); + } + + Decomposition::Block const& Decomposition::getBlock(uint_fast64_t index) const { + return blocks.at(index); + } + + Decomposition::Block const& Decomposition::operator[](uint_fast64_t index) const { + return blocks[index]; + } + + } // namespace storage +} // namespace storm \ No newline at end of file diff --git a/src/storage/Decomposition.h b/src/storage/Decomposition.h new file mode 100644 index 000000000..4bf8cc9c8 --- /dev/null +++ b/src/storage/Decomposition.h @@ -0,0 +1,54 @@ +#ifndef STORM_STORAGE_DECOMPOSITION_H_ +#define STORM_STORAGE_DECOMPOSITION_H_ + +#include + +#include "src/storage/VectorSet.h" + +namespace storm { + namespace storage { + + /*! + * This class represents the decomposition of a model into state sets. + */ + class Decomposition { + public: + typedef storm::storage::VectorSet Block; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + /* + * Creates an empty SCC decomposition. + */ + Decomposition(); + + Decomposition(Decomposition const& other); + + Decomposition& operator=(Decomposition const& other); + + Decomposition(Decomposition&& other); + + Decomposition& operator=(Decomposition&& other); + + size_t size() const; + + iterator begin(); + + iterator end(); + + const_iterator begin() const; + + const_iterator end() const; + + Block const& getBlock(uint_fast64_t index) const; + + Block const& operator[](uint_fast64_t index) const; + + protected: + // The blocks of the decomposition. + std::vector blocks; + }; + } +} + +#endif /* STORM_STORAGE_DECOMPOSITION_H_ */ diff --git a/src/storage/StronglyConnectedComponentDecomposition.cpp b/src/storage/StronglyConnectedComponentDecomposition.cpp new file mode 100644 index 000000000..751337d01 --- /dev/null +++ b/src/storage/StronglyConnectedComponentDecomposition.cpp @@ -0,0 +1,156 @@ +#include "src/storage/StronglyConnectedComponentDecomposition.h" +#include "src/models/AbstractModel.h" + +namespace storm { + namespace storage { + template + StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition() : Decomposition() { + // Intentionally left empty. + } + + template + StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::models::AbstractModel const& model) : Decomposition() { + performSccDecomposition(model); + } + + template + StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(StronglyConnectedComponentDecomposition const& other) : Decomposition(other) { + // Intentionally left empty. + } + + template + StronglyConnectedComponentDecomposition& StronglyConnectedComponentDecomposition::operator=(StronglyConnectedComponentDecomposition const& other) { + this->blocks = other.blocks; + return *this; + } + + template + StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(StronglyConnectedComponentDecomposition&& other) : Decomposition(std::move(other)) { + // Intentionally left empty. + } + + template + StronglyConnectedComponentDecomposition& StronglyConnectedComponentDecomposition::operator=(StronglyConnectedComponentDecomposition&& other) { + this->blocks = std::move(other.blocks); + return *this; + } + + template + void StronglyConnectedComponentDecomposition::performSccDecomposition(storm::models::AbstractModel const& model) { + LOG4CPLUS_INFO(logger, "Computing SCC decomposition."); + + uint_fast64_t numberOfStates = model.getNumberOfStates(); + + // Set up the environment of Tarjan's algorithm. + std::vector tarjanStack; + tarjanStack.reserve(numberOfStates); + storm::storage::BitVector tarjanStackStates(numberOfStates); + std::vector stateIndices(numberOfStates); + std::vector lowlinks(numberOfStates); + storm::storage::BitVector visitedStates(numberOfStates); + + // Start the search for SCCs from every vertex in the graph structure, because there is. + uint_fast64_t currentIndex = 0; + for (uint_fast64_t state = 0; state < numberOfStates; ++state) { + if (!visitedStates.get(state)) { + performSccDecompositionHelper(model, state, currentIndex, stateIndices, lowlinks, tarjanStack, tarjanStackStates, visitedStates); + } + } + + LOG4CPLUS_INFO(logger, "Done computing SCC decomposition."); + } + + template + void StronglyConnectedComponentDecomposition::performSccDecompositionHelper(storm::models::AbstractModel const& model, uint_fast64_t startState, uint_fast64_t& currentIndex, std::vector& stateIndices, std::vector& lowlinks, std::vector& tarjanStack, storm::storage::BitVector& tarjanStackStates, storm::storage::BitVector& visitedStates) { + // Create the stacks needed for turning the recursive formulation of Tarjan's algorithm + // into an iterative version. In particular, we keep one stack for states and one stack + // for the iterators. The last one is not strictly needed, but reduces iteration work when + // all successors of a particular state are considered. + std::vector recursionStateStack; + recursionStateStack.reserve(lowlinks.size()); + std::vector::ConstIterator> recursionIteratorStack; + recursionIteratorStack.reserve(lowlinks.size()); + std::vector statesInStack(lowlinks.size()); + + // Initialize the recursion stacks with the given initial state (and its successor iterator). + recursionStateStack.push_back(startState); + recursionIteratorStack.push_back(model.getRows(startState).begin()); + + recursionStepForward: + while (!recursionStateStack.empty()) { + uint_fast64_t currentState = recursionStateStack.back(); + typename storm::storage::SparseMatrix::ConstIterator successorIt = recursionIteratorStack.back(); + + // Perform the treatment of newly discovered state as defined by Tarjan's algorithm + visitedStates.set(currentState, true); + stateIndices[currentState] = currentIndex; + lowlinks[currentState] = currentIndex; + ++currentIndex; + tarjanStack.push_back(currentState); + tarjanStackStates.set(currentState, true); + + // Now, traverse all successors of the current state. + for(; successorIt != model.getRows(currentState).end(); ++successorIt) { + // If we have not visited the successor already, we need to perform the procedure + // recursively on the newly found state. + if (!visitedStates.get(successorIt.column())) { + // Save current iterator position so we can continue where we left off later. + recursionIteratorStack.pop_back(); + recursionIteratorStack.push_back(successorIt); + + // Put unvisited successor on top of our recursion stack and remember that. + recursionStateStack.push_back(successorIt.column()); + statesInStack[successorIt.column()] = true; + + // Also, put initial value for iterator on corresponding recursion stack. + recursionIteratorStack.push_back(model.getRows(successorIt.column()).begin()); + + // Perform the actual recursion step in an iterative way. + goto recursionStepForward; + + recursionStepBackward: + lowlinks[currentState] = std::min(lowlinks[currentState], lowlinks[successorIt.column()]); + } else if (tarjanStackStates.get(successorIt.column())) { + // Update the lowlink of the current state. + lowlinks[currentState] = std::min(lowlinks[currentState], stateIndices[successorIt.column()]); + } + } + + // If the current state is the root of a SCC, we need to pop all states of the SCC from + // the algorithm's stack. + if (lowlinks[currentState] == stateIndices[currentState]) { + Block scc; + + uint_fast64_t lastState = 0; + do { + // Pop topmost state from the algorithm's stack. + lastState = tarjanStack.back(); + tarjanStack.pop_back(); + tarjanStackStates.set(lastState, false); + + // Add the state to the current SCC. + scc.insert(lastState); + } while (lastState != currentState); + this->blocks.emplace_back(std::move(scc)); + } + + // If we reach this point, we have completed the recursive descent for the current state. + // That is, we need to pop it from the recursion stacks. + recursionStateStack.pop_back(); + recursionIteratorStack.pop_back(); + + // If there is at least one state under the current one in our recursion stack, we need + // to restore the topmost state as the current state and jump to the part after the + // original recursive call. + if (recursionStateStack.size() > 0) { + currentState = recursionStateStack.back(); + successorIt = recursionIteratorStack.back(); + + goto recursionStepBackward; + } + } + } + + template class StronglyConnectedComponentDecomposition; + } // namespace storage +} // namespace storm \ No newline at end of file diff --git a/src/storage/StronglyConnectedComponentDecomposition.h b/src/storage/StronglyConnectedComponentDecomposition.h new file mode 100644 index 000000000..a2f3e365b --- /dev/null +++ b/src/storage/StronglyConnectedComponentDecomposition.h @@ -0,0 +1,49 @@ +#ifndef STORM_STORAGE_STRONGLYCONNECTEDCOMPONENTDECOMPOSITION_H_ +#define STORM_STORAGE_STRONGLYCONNECTEDCOMPONENTDECOMPOSITION_H_ + +#include "src/storage/Decomposition.h" +#include "src/storage/VectorSet.h" +#include "src/storage/BitVector.h" +#include "src/storage/SparseMatrix.h" + +namespace storm { + namespace models { + // Forward declare the abstract model class. + template class AbstractModel; + } + + namespace storage { + + /*! + * This class represents the decomposition of a graph-like structure into its strongly connected components. + */ + template + class StronglyConnectedComponentDecomposition : public Decomposition { + public: + /* + * Creates an empty SCC decomposition. + */ + StronglyConnectedComponentDecomposition(); + + /* + * Creates an SCC decomposition of the given model. + */ + StronglyConnectedComponentDecomposition(storm::models::AbstractModel const& model); + + StronglyConnectedComponentDecomposition(StronglyConnectedComponentDecomposition const& other); + + StronglyConnectedComponentDecomposition& operator=(StronglyConnectedComponentDecomposition const& other); + + StronglyConnectedComponentDecomposition(StronglyConnectedComponentDecomposition&& other); + + StronglyConnectedComponentDecomposition& operator=(StronglyConnectedComponentDecomposition&& other); + + private: + void performSccDecomposition(storm::models::AbstractModel const& model); + + void performSccDecompositionHelper(storm::models::AbstractModel const& model, uint_fast64_t startState, uint_fast64_t& currentIndex, std::vector& stateIndices, std::vector& lowlinks, std::vector& tarjanStack, storm::storage::BitVector& tarjanStackStates, storm::storage::BitVector& visitedStates); + }; + } +} + +#endif /* STORM_STORAGE_STRONGLYCONNECTEDCOMPONENTDECOMPOSITION_H_ */ diff --git a/src/storage/VectorSet.h b/src/storage/VectorSet.h index 1bbf30652..1257bbec3 100644 --- a/src/storage/VectorSet.h +++ b/src/storage/VectorSet.h @@ -10,6 +10,8 @@ #include #include +#include +#include namespace storm { namespace storage { diff --git a/src/utility/graph.h b/src/utility/graph.h index b084ddfa3..e0e68402b 100644 --- a/src/utility/graph.h +++ b/src/utility/graph.h @@ -550,143 +550,6 @@ namespace storm { return result; } - /*! - * Performs an SCC decomposition using Tarjan's algorithm. - * - * @param startState The state at which the search is started. - * @param currentIndex The index that is to be used as the next free index. - * @param stateIndices The vector that stores the index for each state. - * @param lowlinks A vector that stores the lowlink of each state, i.e. the lowest index of a state reachable from - * a particular state. - * @param tarjanStack A stack used for Tarjan's algorithm. - * @param tarjanStackStates A bit vector that represents all states that are currently contained in tarjanStack. - * @param visitedStates A bit vector that stores all states that have already been visited. - * @param matrix The transition matrix representing the graph structure. - * @param stronglyConnectedComponents A vector of strongly connected components to which newly found SCCs are added. - */ - template - void performSccDecompositionHelper(uint_fast64_t startState, uint_fast64_t& currentIndex, std::vector& stateIndices, std::vector& lowlinks, std::vector& tarjanStack, storm::storage::BitVector& tarjanStackStates, storm::storage::BitVector& visitedStates, storm::storage::SparseMatrix const& matrix, std::vector>& stronglyConnectedComponents) { - // Create the stacks needed for turning the recursive formulation of Tarjan's algorithm - // into an iterative version. In particular, we keep one stack for states and one stack - // for the iterators. The last one is not strictly needed, but reduces iteration work when - // all successors of a particular state are considered. - std::vector recursionStateStack; - recursionStateStack.reserve(lowlinks.size()); - std::vector::ConstIndexIterator> recursionIteratorStack; - recursionIteratorStack.reserve(lowlinks.size()); - std::vector statesInStack(lowlinks.size()); - - // Initialize the recursion stacks with the given initial state (and its successor iterator). - recursionStateStack.push_back(startState); - recursionIteratorStack.push_back(matrix.constColumnIteratorBegin(startState)); - - recursionStepForward: - while (!recursionStateStack.empty()) { - uint_fast64_t currentState = recursionStateStack.back(); - typename storm::storage::SparseMatrix::ConstIndexIterator successorIt = recursionIteratorStack.back(); - - // Perform the treatment of newly discovered state as defined by Tarjan's algorithm - visitedStates.set(currentState, true); - stateIndices[currentState] = currentIndex; - lowlinks[currentState] = currentIndex; - ++currentIndex; - tarjanStack.push_back(currentState); - tarjanStackStates.set(currentState, true); - - // Now, traverse all successors of the current state. - for(; successorIt != matrix.constColumnIteratorEnd(currentState); ++successorIt) { - // If we have not visited the successor already, we need to perform the procedure - // recursively on the newly found state. - if (!visitedStates.get(*successorIt)) { - // Save current iterator position so we can continue where we left off later. - recursionIteratorStack.pop_back(); - recursionIteratorStack.push_back(successorIt); - - // Put unvisited successor on top of our recursion stack and remember that. - recursionStateStack.push_back(*successorIt); - statesInStack[*successorIt] = true; - - // Also, put initial value for iterator on corresponding recursion stack. - recursionIteratorStack.push_back(matrix.constColumnIteratorBegin(*successorIt)); - - // Perform the actual recursion step in an iterative way. - goto recursionStepForward; - - recursionStepBackward: - lowlinks[currentState] = std::min(lowlinks[currentState], lowlinks[*successorIt]); - } else if (tarjanStackStates.get(*successorIt)) { - // Update the lowlink of the current state. - lowlinks[currentState] = std::min(lowlinks[currentState], stateIndices[*successorIt]); - } - } - - // If the current state is the root of a SCC, we need to pop all states of the SCC from - // the algorithm's stack. - if (lowlinks[currentState] == stateIndices[currentState]) { - stronglyConnectedComponents.emplace_back(); - - uint_fast64_t lastState = 0; - do { - // Pop topmost state from the algorithm's stack. - lastState = tarjanStack.back(); - tarjanStack.pop_back(); - tarjanStackStates.set(lastState, false); - - // Add the state to the current SCC. - stronglyConnectedComponents.back().push_back(lastState); - } while (lastState != currentState); - } - - // If we reach this point, we have completed the recursive descent for the current state. - // That is, we need to pop it from the recursion stacks. - recursionStateStack.pop_back(); - recursionIteratorStack.pop_back(); - - // If there is at least one state under the current one in our recursion stack, we need - // to restore the topmost state as the current state and jump to the part after the - // original recursive call. - if (recursionStateStack.size() > 0) { - currentState = recursionStateStack.back(); - successorIt = recursionIteratorStack.back(); - - goto recursionStepBackward; - } - } - } - - /*! - * Performs a decomposition of the given model into its SCCs. - * - * @param model The nondeterminstic model to decompose. - * @return A vector of SCCs of the model. - */ - template - std::vector> performSccDecomposition(storm::models::AbstractModel const& model) { - LOG4CPLUS_INFO(logger, "Computing SCC decomposition."); - - std::vector> scc; - uint_fast64_t numberOfStates = model.getNumberOfStates(); - - // Set up the environment of Tarjan's algorithm. - std::vector tarjanStack; - tarjanStack.reserve(numberOfStates); - storm::storage::BitVector tarjanStackStates(numberOfStates); - std::vector stateIndices(numberOfStates); - std::vector lowlinks(numberOfStates); - storm::storage::BitVector visitedStates(numberOfStates); - - // Start the search for SCCs from every vertex in the graph structure, because there is. - uint_fast64_t currentIndex = 0; - for (uint_fast64_t state = 0; state < numberOfStates; ++state) { - if (!visitedStates.get(state)) { - performSccDecompositionHelper(state, currentIndex, stateIndices, lowlinks, tarjanStack, tarjanStackStates, visitedStates, model.getTransitionMatrix(), scc); - } - } - - LOG4CPLUS_INFO(logger, "Done computing SCC decomposition."); - return scc; - } - /*! * Performs a topological sort of the states of the system according to the given transitions. * diff --git a/test/performance/graph/GraphTest.cpp b/test/performance/graph/GraphTest.cpp index 47c589a86..a050be516 100644 --- a/test/performance/graph/GraphTest.cpp +++ b/test/performance/graph/GraphTest.cpp @@ -3,6 +3,7 @@ #include "src/settings/Settings.h" #include "src/parser/AutoParser.h" #include "src/utility/graph.h" +#include "src/storage/StronglyConnectedComponentDecomposition.h" TEST(GraphTest, PerformProb01) { storm::parser::AutoParser parser(STORM_CPP_BASE_PATH "/examples/dtmc/crowds/crowds20_5.tra", STORM_CPP_BASE_PATH "/examples/dtmc/crowds/crowds20_5.lab", "", ""); @@ -91,7 +92,7 @@ TEST(GraphTest, PerformSCCDecompositionAndGetDependencyGraph) { std::shared_ptr> dtmc = parser.getModel>(); LOG4CPLUS_WARN(logger, "Computing SCC decomposition of crowds/crowds20_5..."); - std::vector> sccDecomposition(std::move(storm::utility::graph::performSccDecomposition(*dtmc))); + storm::storage::StronglyConnectedComponentDecomposition sccDecomposition(*dtmc); LOG4CPLUS_WARN(logger, "Done."); ASSERT_EQ(sccDecomposition.size(), 1290297ull); @@ -108,7 +109,7 @@ TEST(GraphTest, PerformSCCDecompositionAndGetDependencyGraph) { std::shared_ptr> dtmc2 = parser2.getModel>(); LOG4CPLUS_WARN(logger, "Computing SCC decomposition of synchronous_leader/leader6_8..."); - sccDecomposition = std::move(storm::utility::graph::performSccDecomposition(*dtmc2)); + sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition(*dtmc2); LOG4CPLUS_WARN(logger, "Done."); ASSERT_EQ(sccDecomposition.size(), 1279673ull); @@ -125,16 +126,16 @@ TEST(GraphTest, PerformSCCDecompositionAndGetDependencyGraph) { std::shared_ptr> mdp = parser3.getModel>(); LOG4CPLUS_WARN(logger, "Computing SCC decomposition of asynchronous_leader/leader6..."); - sccDecomposition = std::move(storm::utility::graph::performSccDecomposition(*mdp)); + sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition(*mdp); LOG4CPLUS_WARN(logger, "Done."); - ASSERT_EQ(sccDecomposition.size(), 214675ull); + ASSERT_EQ(sccDecomposition.size(), 146844ull); LOG4CPLUS_WARN(logger, "Extracting SCC dependency graph of asynchronous_leader/leader6..."); sccDependencyGraph = std::move(mdp->extractPartitionDependencyGraph(sccDecomposition)); LOG4CPLUS_WARN(logger, "Done."); - ASSERT_EQ(sccDependencyGraph.getNonZeroEntryCount(), 684093ull); + ASSERT_EQ(sccDependencyGraph.getNonZeroEntryCount(), 489918ull); mdp = nullptr; @@ -142,16 +143,16 @@ TEST(GraphTest, PerformSCCDecompositionAndGetDependencyGraph) { std::shared_ptr> mdp2 = parser4.getModel>(); LOG4CPLUS_WARN(logger, "Computing SCC decomposition of consensus/coin4_6..."); - sccDecomposition = std::move(storm::utility::graph::performSccDecomposition(*mdp2)); + sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition(*mdp2); LOG4CPLUS_WARN(logger, "Done."); - ASSERT_EQ(sccDecomposition.size(), 63611ull); + ASSERT_EQ(sccDecomposition.size(), 2611ull); LOG4CPLUS_WARN(logger, "Extracting SCC dependency graph of consensus/coin4_6..."); sccDependencyGraph = std::move(mdp2->extractPartitionDependencyGraph(sccDecomposition)); LOG4CPLUS_WARN(logger, "Done."); - ASSERT_EQ(sccDependencyGraph.getNonZeroEntryCount(), 213400ull); + ASSERT_EQ(sccDependencyGraph.getNonZeroEntryCount(), 7888ull); mdp2 = nullptr; } \ No newline at end of file