Skip to content

Commit

Permalink
Switch from recursive node collection to iterative.
Browse files Browse the repository at this point in the history
Fixes #79. Also some cleanup and improvements in memory consumption
  • Loading branch information
asl committed Jul 17, 2022
1 parent a24dc07 commit 958f49d
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 122 deletions.
2 changes: 1 addition & 1 deletion graph/assemblygraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ void AssemblyGraph::markNodesToDraw(const std::vector<DeBruijnNode *>& startingN

node->setAsDrawn();
node->setAsSpecial();
node->labelNeighbouringNodesAsDrawn(nodeDistance, nullptr);
node->labelNeighbouringNodesAsDrawn(nodeDistance);
}
}

Expand Down
79 changes: 31 additions & 48 deletions graph/debruijnnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
#include <cmath>

#include <set>
#include <unordered_set>
#include <QApplication>
#include <QSet>


//The length parameter is optional. If it is set, then the node will use that
//for its length. If not set, it will just use the sequence length.
DeBruijnNode::DeBruijnNode(QString name, double depth, const Sequence& sequence, int length) :
Expand All @@ -42,9 +42,7 @@ DeBruijnNode::DeBruijnNode(QString name, double depth, const Sequence& sequence,
m_reverseComplement(nullptr),
m_graphicsItemNode(nullptr),
m_specialNode(false),
m_drawn(false),
m_highestDistanceInNeighbourSearch(0)
{
m_drawn(false) {
if (length > 0)
m_length = length;
}
Expand Down Expand Up @@ -74,7 +72,6 @@ void DeBruijnNode::resetNode()
resetContiguityStatus();
setAsNotDrawn();
setAsNotSpecial();
m_highestDistanceInNeighbourSearch = 0;
}

//This function determines the contiguity of nodes relative to this one.
Expand Down Expand Up @@ -328,40 +325,33 @@ QByteArray DeBruijnNode::getNodeNameForFasta(bool sign) const
}


//This function recursively labels all nodes as drawn that are within a
//certain distance of this node. Whichever node called this will
//definitely be drawn, so that one is excluded from the recursive call.
void DeBruijnNode::labelNeighbouringNodesAsDrawn(int nodeDistance, DeBruijnNode * callingNode)
{
if (m_highestDistanceInNeighbourSearch > nodeDistance)
return;
m_highestDistanceInNeighbourSearch = nodeDistance;

if (nodeDistance == 0)
return;

DeBruijnNode * otherNode;
for (auto &m_edge : m_edges)
{
otherNode = m_edge->getOtherNode(this);

if (otherNode == callingNode)
continue;

if (g_settings->doubleMode)
otherNode->m_drawn = true;
else //single mode
{
if (otherNode->isPositiveNode())
otherNode->m_drawn = true;
else
otherNode->getReverseComplement()->m_drawn = true;
// This function recursively labels all nodes as drawn that are within a
// certain distance of this node. Whichever node called this will
// definitely be drawn, so that one is excluded from the recursive call.
// FIXME: this function does not belong here
void DeBruijnNode::labelNeighbouringNodesAsDrawn(int nodeDistance) {
std::unordered_set<DeBruijnNode*> worklist, seen;
worklist.insert(this);
for (int depth = 0; depth <= nodeDistance; depth++) {
for (auto *node : worklist) {
auto *nodeToMark =
g_settings->doubleMode ? node : node->getCanonical();
nodeToMark->m_drawn = true;

for (auto *m_edge : node->m_edges) {
DeBruijnNode * otherNode = m_edge->getOtherNode(node);
if (!otherNode->thisNodeOrReverseComplementIsDrawn())
seen.insert(otherNode);
}
}
otherNode->labelNeighbouringNodesAsDrawn(nodeDistance-1, this);

if (seen.empty())
break;
worklist.clear();
worklist.swap(seen);
}
}


bool DeBruijnNode::isPositiveNode() const
{
QChar lastChar = m_name.at(m_name.length() - 1);
Expand Down Expand Up @@ -401,8 +391,7 @@ DeBruijnEdge * DeBruijnNode::doesNodeLeadAway(DeBruijnNode * node) const
}


bool DeBruijnNode::isNodeConnected(DeBruijnNode * node) const
{
bool DeBruijnNode::isNodeConnected(DeBruijnNode * node) const {
for (auto *edge : m_edges) {
if (edge->getStartingNode() == node || edge->getEndingNode() == node)
return true;
Expand Down Expand Up @@ -439,7 +428,7 @@ std::vector<DeBruijnNode *> DeBruijnNode::getDownstreamNodes() const

std::vector<DeBruijnNode *> returnVector;
returnVector.reserve(leavingEdges.size());
for (auto &leavingEdge : leavingEdges)
for (auto *leavingEdge : leavingEdges)
returnVector.push_back(leavingEdge->getEndingNode());

return returnVector;
Expand All @@ -452,7 +441,7 @@ std::vector<DeBruijnNode *> DeBruijnNode::getUpstreamNodes() const

std::vector<DeBruijnNode *> returnVector;
returnVector.reserve(enteringEdges.size());
for (auto &enteringEdge : enteringEdges)
for (auto *enteringEdge : enteringEdges)
returnVector.push_back(enteringEdge->getStartingNode());

return returnVector;
Expand Down Expand Up @@ -518,23 +507,17 @@ int DeBruijnNode::getDeadEndCount() const
//reverse complement) are connected to.
std::vector<DeBruijnNode *> DeBruijnNode::getAllConnectedPositiveNodes() const
{
QSet<DeBruijnNode *> connectedPositiveNodesSet;
std::unordered_set<DeBruijnNode *> connectedPositiveNodesSet;

for (auto edge : m_edges)
{
for (auto *edge : m_edges) {
DeBruijnNode * connectedNode = edge->getOtherNode(this);
if (connectedNode->isNegativeNode())
connectedNode = connectedNode->getReverseComplement();

connectedPositiveNodesSet.insert(connectedNode);
}

std::vector<DeBruijnNode *> connectedPositiveNodesVector;
QSetIterator<DeBruijnNode *> i(connectedPositiveNodesSet);
while (i.hasNext())
connectedPositiveNodesVector.push_back(i.next());

return connectedPositiveNodesVector;
return { connectedPositiveNodesSet.begin(), connectedPositiveNodesSet.end() };
}

float DeBruijnNode::getGC() const {
Expand Down
6 changes: 3 additions & 3 deletions graph/debruijnnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class DeBruijnNode
char getBaseAt(int i) const {if (i >= 0 && i < m_sequence.size()) return m_sequence[i]; else return '\0';} // NOTE
ContiguityStatus getContiguityStatus() const {return m_contiguityStatus;}
DeBruijnNode * getReverseComplement() const {return m_reverseComplement;}
DeBruijnNode *getCanonical() { return isPositiveNode() ? this : m_reverseComplement; }

GraphicsItemNode * getGraphicsItemNode() const {return m_graphicsItemNode;}
bool hasGraphicsItem() const {return m_graphicsItemNode != nullptr;}
Expand Down Expand Up @@ -108,7 +109,7 @@ class DeBruijnNode
void addEdge(DeBruijnEdge * edge);
void removeEdge(DeBruijnEdge * edge);
void determineContiguity();
void labelNeighbouringNodesAsDrawn(int nodeDistance, DeBruijnNode * callingNode);
void labelNeighbouringNodesAsDrawn(int nodeDistance);
void setDepth(double newDepth) {m_depth = newDepth;}
void setName(QString newName) {m_name = std::move(newName);}

Expand All @@ -122,8 +123,7 @@ class DeBruijnNode

GraphicsItemNode * m_graphicsItemNode;

int m_length;
int m_highestDistanceInNeighbourSearch : 27;
int m_length : 27;
ContiguityStatus m_contiguityStatus : 3;
bool m_specialNode : 1;
bool m_drawn : 1;
Expand Down
70 changes: 0 additions & 70 deletions tests/bandagetests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,11 +618,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 44);

Expand All @@ -632,11 +627,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 88);

Expand All @@ -647,11 +637,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 1);

Expand All @@ -662,11 +647,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 2);

Expand All @@ -677,11 +657,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 1);

Expand All @@ -692,11 +667,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 3);

Expand All @@ -707,11 +677,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 10);

Expand All @@ -723,11 +688,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 43);

Expand All @@ -739,11 +699,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 43);

Expand All @@ -755,11 +710,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 1);

Expand All @@ -771,11 +721,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 42);

Expand All @@ -790,11 +735,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "all", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 1);

Expand All @@ -804,11 +744,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "all", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 3);

Expand All @@ -818,11 +753,6 @@ void BandageTests::graphScope()
startingNodes = g_assemblyGraph->getStartingNodes(&errorTitle, &errorMessage, g_settings->doubleMode, g_settings->startingNodes, "all", "");
g_assemblyGraph->resetNodes();
g_assemblyGraph->markNodesToDraw(startingNodes, g_settings->nodeDistance);
{
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(*g_assemblyGraph);
}
drawnNodes = g_assemblyGraph->getDrawnNodeCount();
QCOMPARE(drawnNodes, 9);

Expand Down

0 comments on commit 958f49d

Please sign in to comment.