* Assigns distances to and enqueues downstream or upstream according to direction.
*/
private void bfsStep(LinkedList<Node> queue, Node root, boolean direction)
{
// Next node in queue
Node node = queue.poll();
// Get previously assigned distance. This will not change, but will be used for labeling
// neighbors.
assert !isVisited(node) || node.hasLabel(VISITED_WO_CH) || node.hasLabel(VISITED_WO_PR);
int d = !isVisited(node) ? getDistance(node, root, direction) :
(Integer) node.getLabel(TEMP_DIST);
// Put parents in front of the queue if not already coming from a parent.
if (!node.hasLabel(PARENT_LOCK) && (!isVisited(node) || node.hasLabel(VISITED_WO_PR)))
{
for (Node parent : node.getParents())
{
if (!isVisited(parent) || parent.hasLabel(VISITED_WO_PR))
{
if (queue.contains(parent))
{
queue.remove(parent);
}
queue.addFirst(parent);
if (!isVisited(parent))
{
parent.putLabel(CHILD_LOCK);
putDistance(parent, root, direction, d);
}
else
{
parent.putLabel(TEMP_DIST, d);
}
}
}
}
// Put children in front of the queue if not already coming from a child.
if (!node.hasLabel(CHILD_LOCK) && (!isVisited(node) || node.hasLabel(VISITED_WO_CH)))
{
for (Node child : node.getChildren())
{
if (!isVisited(child) || child.hasLabel(VISITED_WO_CH))
{
if (queue.contains(child))
{
queue.remove(child);
}
queue.addFirst(child);
if (!isVisited(child))
{
putDistance(child, root, direction, d);
child.putLabel(PARENT_LOCK);
}
else
{
child.putLabel(TEMP_DIST, d);
}
}
}
}
// Proceed to up/downstream only if not reached the distance limit
if (d < limit && !isVisited(node))
{
// Iterate neighbors
for (Edge edge : getEdges(node, direction))
{
// Do not consider non-causative edges
if (!edge.isCausative()) continue;
Node neigh = getEdgeEnd(edge, direction);
boolean step = neigh.isBreadthNode() && edge.isBreadthEdge();
// Process only if neighbor is not already in the queue.
if (!queue.contains(neigh))
{
if (!isVisited(neigh))
{
putDistance(neigh, root, direction, step ? d+1 : d);
// Enqueue neighbor
if (step)
{
queue.addLast(neigh);
}
else
{
if (queue.contains(neigh))
{
queue.remove(neigh);
}
queue.addFirst(neigh);
}
}
else if (neigh.hasLabel(VISITED_WO_CH) || neigh.hasLabel(VISITED_WO_PR))
{
neigh.putLabel(TEMP_DIST, step ? d+1 : d);
if (step)
{
queue.addLast(neigh);
}