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

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