All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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