com.powsybl.openloadflow.graph.AbstractGraphConnectivity 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 com.powsybl.commons.PowsyblException;
import org.jgrapht.Graph;
import org.jgrapht.graph.Pseudograph;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Florian Dupuy {@literal }
*/
public abstract class AbstractGraphConnectivity implements GraphConnectivity {
private final Graph graph = new Pseudograph<>(null, null, false);
private final Deque> modificationsContexts = new ArrayDeque<>();
protected List> componentSets;
private V defaultMainComponentVertex;
protected abstract void updateConnectivity(EdgeRemove edgeRemove);
protected abstract void updateConnectivity(EdgeAdd edgeAdd);
protected abstract void updateConnectivity(VertexAdd vertexAdd);
protected abstract void resetConnectivity(Deque> m);
protected abstract void updateComponents();
@Override
public void addVertex(V vertex) {
Objects.requireNonNull(vertex);
if (graph.containsVertex(vertex)) {
return;
}
VertexAdd vertexAdd = new VertexAdd<>(vertex);
vertexAdd.apply(graph);
if (!modificationsContexts.isEmpty()) {
ModificationsContext modificationsContext = modificationsContexts.peekLast();
modificationsContext.add(vertexAdd);
updateConnectivity(vertexAdd);
}
}
@Override
public void addEdge(V vertex1, V vertex2, E edge) {
Objects.requireNonNull(vertex1);
Objects.requireNonNull(vertex2);
Objects.requireNonNull(edge);
if (graph.containsEdge(edge)) {
return;
}
EdgeAdd edgeAdd = new EdgeAdd<>(vertex1, vertex2, edge);
edgeAdd.apply(graph);
if (!modificationsContexts.isEmpty()) {
ModificationsContext modificationsContext = modificationsContexts.peekLast();
modificationsContext.add(edgeAdd);
updateConnectivity(edgeAdd);
}
}
@Override
public void removeEdge(E edge) {
Objects.requireNonNull(edge);
if (!graph.containsEdge(edge)) {
return;
}
V vertex1 = graph.getEdgeSource(edge);
V vertex2 = graph.getEdgeTarget(edge);
EdgeRemove edgeRemove = new EdgeRemove<>(vertex1, vertex2, edge);
edgeRemove.apply(graph);
if (!modificationsContexts.isEmpty()) {
ModificationsContext modificationsContext = modificationsContexts.peekLast();
modificationsContext.add(edgeRemove);
updateConnectivity(edgeRemove);
}
}
@Override
public void startTemporaryChanges() {
ModificationsContext modificationsContext = new ModificationsContext<>(this::getVerticesNotInMainComponent, defaultMainComponentVertex);
modificationsContexts.add(modificationsContext);
modificationsContext.computeVerticesNotInMainComponentBefore();
}
@Override
public void undoTemporaryChanges() {
if (modificationsContexts.isEmpty()) {
throw new PowsyblException("Cannot reset, no remaining saved connectivity");
}
ModificationsContext m = modificationsContexts.pollLast();
Deque> modifications = m.getModifications();
resetConnectivity(modifications);
modifications.descendingIterator().forEachRemaining(gm -> gm.undo(graph));
}
@Override
public int getComponentNumber(V vertex) {
checkSavedContext();
checkVertex(vertex);
updateComponents();
return getQuickComponentNumber(vertex);
}
protected abstract int getQuickComponentNumber(V vertex);
@Override
public int getNbConnectedComponents() {
checkSavedContext();
updateComponents();
return componentSets.size();
}
protected Collection> getSmallComponents() {
checkSavedContext();
updateComponents();
return componentSets.subList(1, componentSets.size());
}
@Override
public Set getConnectedComponent(V vertex) {
int componentNumber = getComponentNumber(vertex);
return componentSets.get(componentNumber);
}
@Override
public Set getLargestConnectedComponent() {
checkSavedContext();
updateComponents();
return componentSets.get(0);
}
protected Set getNonConnectedVertices(V vertex) {
Set connectedComponent = getConnectedComponent(vertex);
return componentSets.stream()
.filter(component -> component != connectedComponent)
.flatMap(Collection::stream).collect(Collectors.toSet());
}
public Graph getGraph() {
return graph;
}
protected Deque> getModificationsContexts() {
return modificationsContexts;
}
protected ModificationsContext checkSavedContext() {
if (modificationsContexts.isEmpty()) {
throw new PowsyblException("Cannot compute connectivity without a saved state, please call GraphConnectivity::startTemporaryChanges at least once beforehand");
}
return modificationsContexts.peekLast();
}
protected void checkVertex(V vertex) {
if (!graph.containsVertex(vertex)) {
throw new IllegalArgumentException("given vertex " + vertex + " is not in the graph");
}
}
@Override
public Set getVerticesAddedToMainComponent() {
return checkSavedContext().getVerticesAddedToMainComponent();
}
@Override
public Set getEdgesAddedToMainComponent() {
return checkSavedContext().getEdgesAddedToMainComponent(graph);
}
@Override
public Set getVerticesRemovedFromMainComponent() {
return checkSavedContext().getVerticesRemovedFromMainComponent();
}
@Override
public Set getEdgesRemovedFromMainComponent() {
return checkSavedContext().getEdgesRemovedFromMainComponent(graph);
}
private Set getVerticesNotInMainComponent(V mainComponentVertex) {
if (mainComponentVertex != null) {
return getNonConnectedVertices(mainComponentVertex);
} else {
return getSmallComponents().stream().flatMap(Set::stream).collect(Collectors.toSet());
}
}
public void setMainComponentVertex(V mainComponentVertex) {
if (!modificationsContexts.isEmpty()) {
var modificationsContext = modificationsContexts.peekLast();
modificationsContext.setMainComponentVertex(mainComponentVertex);
if (!modificationsContext.isInMainComponentBefore(mainComponentVertex)) {
throw new PowsyblException("Cannot take the given vertex as main component vertex! This vertex was outside the main component before starting temporary changes");
}
}
defaultMainComponentVertex = mainComponentVertex;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy