Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Traversal from terminal by depth or breadth first #335

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

FranckLecuyer
Copy link
Contributor

@FranckLecuyer FranckLecuyer commented Jun 26, 2023

Please check if the PR fulfills these requirements

  • The commit message follows our guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

Does this PR already have an issue describing the problem?

What kind of change does this PR introduce?

Feature

What is the current behavior?

The traversal from a terminal is only done by depth first

What is the new behavior (if this is a feature change)?
The traversal from a terminal can now be done by depth or breadth first

Does this PR introduce a breaking change or deprecate an API?

  • The Breaking Change or Deprecated label has been added
  • The migration guide has been updated in the github wiki (What changes might users need to make in their application due to this PR?)

Other information:

Waiting for PR : powsybl/powsybl-core#2626
Waiting for next powsybl-core release

BOUTIER Charly and others added 9 commits August 1, 2023 10:21
Signed-off-by: BOUTIER Charly <[email protected]>
Signed-off-by: BOUTIER Charly <[email protected]>
Signed-off-by: BOUTIER Charly <[email protected]>
Signed-off-by: BOUTIER Charly <[email protected]>
Signed-off-by: BOUTIER Charly <[email protected]>
Adds equipment information on problematic VSC and Busbar index
@jonenst jonenst force-pushed the main branch 2 times, most recently from 4fcdf56 to 32e5119 Compare September 22, 2023 08:51
result = traverser.traverse(node, null, nextNode);
} else {
throw new AssertionError();
if (traversalType == TraversalType.DEPTH_FIRST) { // traversal by depth first
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate DFS and BFS in two differents methods, otherwise it's a bit difficult to differentiate the recursive DFS with the BFS

}
} else { // traversal by breadth first
boolean keepGoing = true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should be able to get rid of the boolean keepGoing, see proposed changes. Instead of encounteredEdges, we could keep track of visitedNodes similarly to the "done" set in the DFS implementation. See suggestion

LinkedList<Integer> vertexToTraverse = new LinkedList<>();
vertexToTraverse.offer(node);
while (!vertexToTraverse.isEmpty()) {
int firstV = vertexToTraverse.getFirst();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to currentNode?

vertexToTraverse.offer(node);
while (!vertexToTraverse.isEmpty()) {
int firstV = vertexToTraverse.getFirst();
vertexToTraverse.poll();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be one line int firstV = vertexToTraverse.poll(); ?

if (done.contains(firstV)) {
continue;
}
done.add(firstV);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need done here as we have the encounteredEdges Set. we need to choose one or the other

NodeBreakerBiConnectable biConnectable = edge.getBiConnectable();
int node1 = biConnectable.getNode1();
int node2 = biConnectable.getNode2();

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can also use int nextNode similarly to the DFS to avoid the following if clause duplicated

break;
}
}
return keepGoing;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this seems to work for me on tests but I haven't tested on a real network only on the tests implemented.

    boolean traverseFromNode(int node, TraversalType traversalType, VoltageLevel.NodeBreakerView.TopologyTraverser traverser) {
        Graph<Integer, Edge> graph = NodeBreakerTopology.INSTANCE.buildGraph(index, getVoltageLevelResource(), true, true);
        if (traversalType == TraversalType.DEPTH_FIRST) {
            Set<Integer> visitedNodes = new HashSet<>();
            return traverseFromNodeDFS(graph, node, traverser, visitedNodes);
        } else {
            return traverseFromNodeBFS(graph, node, traverser);
        }
    }

    private boolean traverseFromNodeBFS(Graph<Integer, Edge> graph, int node, TopologyTraverser traverser) {
        Set<Integer> visitedNodes = new HashSet<>();
        LinkedList<Integer> nodeQueue = new LinkedList<>();
        nodeQueue.offer(node);

        while (!nodeQueue.isEmpty()) {
            int currentNode = nodeQueue.poll();

            for (Edge edge : graph.edgesOf(currentNode)) {
                NodeBreakerBiConnectable biConnectable = edge.getBiConnectable();
                int nextNode = biConnectable.getNode1() == currentNode ? biConnectable.getNode2() : biConnectable.getNode1();
                if (visitedNodes.contains(nextNode)) {
                    continue;
                }
                visitedNodes.add(nextNode);

                TraverseResult traverserResult;
                if (biConnectable instanceof SwitchAttributes) {
                    traverserResult = traverseSwitch(traverser, biConnectable, currentNode, nextNode);
                } else if (biConnectable instanceof InternalConnectionAttributes) {
                    traverserResult = traverser.traverse(currentNode, null, nextNode);
                } else {
                    throw new AssertionError();
                }

                if (traverserResult == TraverseResult.CONTINUE) {
                    nodeQueue.offer(nextNode);
                } else if (traverserResult == TraverseResult.TERMINATE_TRAVERSER) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean traverseFromNodeDFS(Graph<Integer, Edge> graph, int node,
                                        TopologyTraverser traverser, Set<Integer> visitedNodes) {
        if (visitedNodes.contains(node)) {
            return true;
        }
        visitedNodes.add(node);

        for (Edge edge : graph.edgesOf(node)) {
            NodeBreakerBiConnectable biConnectable = edge.getBiConnectable();
            int nextNode = biConnectable.getNode1() == node ? biConnectable.getNode2() : biConnectable.getNode1();
            TraverseResult result;
            if (visitedNodes.contains(nextNode)) {
                continue;
            }
            if (biConnectable instanceof SwitchAttributes) {
                result = traverseSwitch(traverser, biConnectable, node, nextNode);
            } else if (biConnectable instanceof InternalConnectionAttributes) {
                result = traverser.traverse(node, null, nextNode);
            } else {
                throw new AssertionError();
            }
            if (result == TraverseResult.CONTINUE) {
                if (!traverseFromNodeDFS(graph, nextNode, traverser, visitedNodes)) {
                    return false;
                }
            } else if (result == TraverseResult.TERMINATE_TRAVERSER) {
                return false;
            }
        }
        return true;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants