com.powsybl.openloadflow.graph.ModificationsContext Maven / Gradle / Ivy
/**
* Copyright (c) 2022, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.openloadflow.graph;
import org.jgrapht.Graph;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author Florian Dupuy {@literal }
*/
public class ModificationsContext {
private final Deque> modifications = new ArrayDeque<>();
private final Function> verticesNotInMainComponentGetter;
private Set verticesNotInMainComponentBefore;
private Set verticesAddedToMainComponent;
private Set verticesRemovedFromMainComponent;
private Set edgesAddedToMainComponent;
private Set edgesRemovedFromMainComponent;
private Map> edgeFirstModificationMap;
private V mainComponentVertex;
public ModificationsContext(Function> verticesNotInMainComponentGetter, V mainComponentVertex) {
this.mainComponentVertex = mainComponentVertex;
this.verticesNotInMainComponentGetter = verticesNotInMainComponentGetter;
}
public void computeVerticesNotInMainComponentBefore() {
this.verticesNotInMainComponentBefore = verticesNotInMainComponentGetter.apply(mainComponentVertex);
}
public void add(GraphModification graphModification) {
invalidateComparisons();
modifications.add(graphModification);
}
private void invalidateComparisons() {
verticesAddedToMainComponent = null;
edgesAddedToMainComponent = null;
verticesRemovedFromMainComponent = null;
edgesRemovedFromMainComponent = null;
edgeFirstModificationMap = null;
}
public Deque> getModifications() {
return modifications;
}
public Set getEdgesRemovedFromMainComponent(Graph graph) {
if (edgesRemovedFromMainComponent == null) {
edgesRemovedFromMainComponent = computeEdgesRemovedFromMainComponent(graph);
}
return edgesRemovedFromMainComponent;
}
public Set getVerticesRemovedFromMainComponent() {
if (verticesRemovedFromMainComponent == null) {
Set result = new HashSet<>(getVerticesNotInMainComponentAfter());
result.removeAll(verticesNotInMainComponentBefore);
if (!result.isEmpty()) {
// remove vertices added in between
// note that there is no VertexRemove modification, thus we do not need to check if vertex is in the graph in the end
getAddedVertexStream().forEach(result::remove);
}
verticesRemovedFromMainComponent = result;
}
return verticesRemovedFromMainComponent;
}
public Set getEdgesAddedToMainComponent(Graph graph) {
if (edgesAddedToMainComponent == null) {
edgesAddedToMainComponent = computeEdgesAddedToMainComponent(graph);
}
return edgesAddedToMainComponent;
}
public Set getVerticesAddedToMainComponent() {
if (verticesAddedToMainComponent == null) {
Set result = new HashSet<>(verticesNotInMainComponentBefore);
Set verticesNotInMainComponentAfter = getVerticesNotInMainComponentAfter();
result.removeAll(verticesNotInMainComponentAfter);
// add vertices added to main component in between
// note that there is no VertexRemove modification, thus we do not need to check if vertex is in the graph before / in the end
getAddedVertexStream().filter(addedVertex -> !verticesNotInMainComponentAfter.contains(addedVertex)).forEach(result::add);
verticesAddedToMainComponent = result;
}
return verticesAddedToMainComponent;
}
private Set getVerticesNotInMainComponentAfter() {
return verticesNotInMainComponentGetter.apply(mainComponentVertex);
}
private Set computeEdgesRemovedFromMainComponent(Graph graph) {
Set verticesRemoved = getVerticesRemovedFromMainComponent();
Set result = verticesRemoved.stream().map(graph::edgesOf).flatMap(Set::stream).collect(Collectors.toSet());
// We need to look in modifications to adjust the computation of the edges above, indeed:
// - result contains the edges which were added in the small components
// - result is missing the edges removed in main component with an EdgeRemove modification
computeEdgeFirstModificationMap();
// Remove the new edges
modifications.stream().filter(EdgeAdd.class::isInstance).map(m -> ((EdgeAdd) m).e)
.filter(graph::containsEdge) // the edge is in the graph: it was not removed afterwards
.filter(edgeAdded -> !graphContainedEdgeBefore(edgeAdded)) // the edge did not exist in the graph before the modifications
.forEach(result::remove);
// Add edges explicitly removed (with an EdgeRemove modification)
modifications.stream().filter(EdgeRemove.class::isInstance).map(m -> ((EdgeRemove) m).e)
.filter(edgeRemoved -> !graph.containsEdge(edgeRemoved)) // the edge was not added afterwards
.filter(this::graphContainedEdgeBefore) // the edge was in the graph before the modifications
.filter(edgeRemoved -> !verticesNotInMainComponentBefore.contains((edgeFirstModificationMap.get(edgeRemoved)).v1)) // one of the original vertices of the edge was in the main component
.forEach(result::add);
return result;
}
private Set computeEdgesAddedToMainComponent(Graph graph) {
Set result = getVerticesAddedToMainComponent().stream().map(graph::edgesOf).flatMap(Set::stream).collect(Collectors.toSet());
// We need to look in modifications to adjust the computation of the edges above
// Indeed result is missing the edges added in main component with an EdgeAdd modification
computeEdgeFirstModificationMap();
// Add edges added to main component in between
Set verticesNotInMainComponentAfter = getVerticesNotInMainComponentAfter();
modifications.stream().filter(EdgeAdd.class::isInstance).map(m -> ((EdgeAdd) m).e)
.filter(graph::containsEdge) // the edge is in the graph: it was not removed afterwards
.filter(edgeAdded -> !graphContainedEdgeBefore(edgeAdded)) // the edge did not exist in the graph before the modifications
.filter(edgeAdded -> !verticesNotInMainComponentAfter.contains(graph.getEdgeSource(edgeAdded))) // one of the final vertices of the edge is in the main component
.forEach(result::add);
return result;
}
private void computeEdgeFirstModificationMap() {
if (edgeFirstModificationMap == null) {
edgeFirstModificationMap = modifications.stream()
.filter(AbstractEdgeModification.class::isInstance)
.map(m -> (AbstractEdgeModification) m)
.collect(Collectors.toMap(m -> m.e, m -> m, (m1, m2) -> m1));
}
}
private boolean graphContainedEdgeBefore(E edge) {
// If first modification is a EdgeRemove, knowing that the non-effective modifications are not added in the queue,
// we can conclude that the graph contained the edge before the modifications were applied
return edgeFirstModificationMap.get(edge) instanceof EdgeRemove;
}
private Stream getAddedVertexStream() {
return modifications.stream().filter(VertexAdd.class::isInstance).map(m -> ((VertexAdd) m).v);
}
public void setMainComponentVertex(V mainComponentVertex) {
invalidateComparisons();
this.mainComponentVertex = mainComponentVertex;
}
public boolean isInMainComponentBefore(V vertex) {
return !verticesNotInMainComponentBefore.contains(vertex);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy