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

org.jgrapht.Graphs Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2003-2023, by Barak Naveh and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package org.jgrapht;

import org.jgrapht.graph.*;
import org.jgrapht.util.*;

import java.util.*;
import java.util.function.*;

/**
 * A collection of utilities to assist with graph manipulation.
 *
 * @author Barak Naveh
 */
public abstract class Graphs
{

    /**
     * Creates a new edge and adds it to the specified graph similarly to the
     * {@link Graph#addEdge(Object, Object)} method.
     *
     * @param g the graph for which the edge to be added
     * @param sourceVertex source vertex of the edge
     * @param targetVertex target vertex of the edge
     * @param weight weight of the edge
     * @param  the graph vertex type
     * @param  the graph edge type
     *
     * @return The newly created edge if added to the graph, otherwise 
     * null.
     * 
     * @throws UnsupportedOperationException if the graph has no edge supplier
     *
     * @see Graph#addEdge(Object, Object)
     */
    public static  E addEdge(Graph g, V sourceVertex, V targetVertex, double weight)
    {
        Supplier edgeSupplier = g.getEdgeSupplier();
        if (edgeSupplier == null) {
            throw new UnsupportedOperationException("Graph contains no edge supplier");
        }
        E e = edgeSupplier.get();

        if (g.addEdge(sourceVertex, targetVertex, e)) {
            g.setEdgeWeight(e, weight);
            return e;
        } else {
            return null;
        }
    }

    /**
     * Adds the specified source and target vertices to the graph, if not already included, and
     * creates a new edge and adds it to the specified graph similarly to the
     * {@link Graph#addEdge(Object, Object)} method.
     *
     * @param g the graph for which the specified edge to be added
     * @param sourceVertex source vertex of the edge
     * @param targetVertex target vertex of the edge
     * @param  the graph vertex type
     * @param  the graph edge type
     *
     * @return The newly created edge if added to the graph, otherwise 
     * null.
     */
    public static  E addEdgeWithVertices(Graph g, V sourceVertex, V targetVertex)
    {
        g.addVertex(sourceVertex);
        g.addVertex(targetVertex);

        return g.addEdge(sourceVertex, targetVertex);
    }

    /**
     * Adds the specified edge to the graph, including its vertices if not already included.
     *
     * @param targetGraph the graph for which the specified edge to be added
     * @param sourceGraph the graph in which the specified edge is already present
     * @param edge edge to add
     * @param  the graph vertex type
     * @param  the graph edge type
     *
     * @return true if the target graph did not already contain the specified edge.
     */
    public static  boolean addEdgeWithVertices(Graph targetGraph, Graph sourceGraph, E edge)
    {
        V sourceVertex = sourceGraph.getEdgeSource(edge);
        V targetVertex = sourceGraph.getEdgeTarget(edge);

        targetGraph.addVertex(sourceVertex);
        targetGraph.addVertex(targetVertex);

        return targetGraph.addEdge(sourceVertex, targetVertex, edge);
    }

    /**
     * Adds the specified source and target vertices to the graph, if not already included, and
     * creates a new weighted edge and adds it to the specified graph similarly to the
     * {@link Graph#addEdge(Object, Object)} method.
     *
     * @param g the graph for which the specified edge to be added
     * @param sourceVertex source vertex of the edge
     * @param targetVertex target vertex of the edge
     * @param weight weight of the edge
     * @param  the graph vertex type
     * @param  the graph edge type
     *
     * @return The newly created edge if added to the graph, otherwise 
     * null.
     */
    public static  E addEdgeWithVertices(Graph g, V sourceVertex, V targetVertex, double weight)
    {
        g.addVertex(sourceVertex);
        g.addVertex(targetVertex);

        return addEdge(g, sourceVertex, targetVertex, weight);
    }

    /**
     * Adds all the vertices and all the edges of the specified source graph to the specified
     * destination graph. First all vertices of the source graph are added to the destination graph.
     * Then every edge of the source graph is added to the destination graph. This method returns
     * true if the destination graph has been modified as a result of this operation,
     * otherwise it returns false.
     *
     * 

* The behavior of this operation is undefined if any of the specified graphs is modified while * operation is in progress. *

* * @param destination the graph to which vertices and edges are added * @param source the graph used as source for vertices and edges to add * @param the graph vertex type * @param the graph edge type * * @return true if and only if the destination graph has been changed as a result * of this operation. */ public static boolean addGraph(Graph destination, Graph source) { boolean modified = addAllVertices(destination, source.vertexSet()); modified |= addAllEdges(destination, source, source.edgeSet()); return modified; } /** * Adds all the vertices and all the edges of the specified source digraph to the specified * destination digraph, reversing all of the edges. If you want to do this as a linked view of * the source graph (rather than by copying to a destination graph), use * {@link EdgeReversedGraph} instead. * *

* The behavior of this operation is undefined if any of the specified graphs is modified while * operation is in progress. * * @param destination the graph to which vertices and edges are added * @param source the graph used as source for vertices and edges to add * @param the graph vertex type * @param the graph edge type * * @see EdgeReversedGraph */ public static void addGraphReversed(Graph destination, Graph source) { if (!source.getType().isDirected() || !destination.getType().isDirected()) { throw new IllegalArgumentException("graph must be directed"); } addAllVertices(destination, source.vertexSet()); for (E edge : source.edgeSet()) { destination.addEdge(source.getEdgeTarget(edge), source.getEdgeSource(edge)); } } /** * Adds a subset of the edges of the specified source graph to the specified destination graph. * The behavior of this operation is undefined if either of the graphs is modified while the * operation is in progress. {@link #addEdgeWithVertices} is used for the transfer, so source * vertexes will be added automatically to the target graph. * * @param destination the graph to which edges are to be added * @param source the graph used as a source for edges to add * @param edges the edges to be added * @param the graph vertex type * @param the graph edge type * * @return true if this graph changed as a result of the call */ public static boolean addAllEdges( Graph destination, Graph source, Collection edges) { boolean modified = false; for (E e : edges) { V s = source.getEdgeSource(e); V t = source.getEdgeTarget(e); destination.addVertex(s); destination.addVertex(t); modified |= destination.addEdge(s, t, e); } return modified; } /** * Adds all of the specified vertices to the destination graph. The behavior of this operation * is undefined if the specified vertex collection is modified while the operation is in * progress. This method will invoke the {@link Graph#addVertex(Object)} method. * * @param destination the graph to which edges are to be added * @param vertices the vertices to be added to the graph * @param the graph vertex type * @param the graph edge type * * @return true if graph changed as a result of the call * * @throws NullPointerException if the specified vertices contains one or more null vertices, or * if the specified vertex collection is * null. * * @see Graph#addVertex(Object) */ public static boolean addAllVertices( Graph destination, Collection vertices) { boolean modified = false; for (V v : vertices) { modified |= destination.addVertex(v); } return modified; } /** * Returns a list of vertices that are the neighbors of a specified vertex. If the graph is a * multigraph vertices may appear more than once in the returned list. * *

* The method uses {@link Graph#edgesOf(Object)} to traverse the graph. * * @param g the graph to look for neighbors in * @param vertex the vertex to get the neighbors of * @param the graph vertex type * @param the graph edge type * * @return a list of the vertices that are the neighbors of the specified vertex. */ public static List neighborListOf(Graph g, V vertex) { List neighbors = new ArrayList<>(); for (E e : g.iterables().edgesOf(vertex)) { neighbors.add(getOppositeVertex(g, e, vertex)); } return neighbors; } /** * Returns a set of vertices that are neighbors of a specified vertex. * * @param g the graph to look for neighbors in * @param vertex the vertex to get the neighbors of * @param the graph vertex type * @param the graph edge type * @return a set of the vertices that are neighbors of the specified vertex */ public static Set neighborSetOf(Graph g, V vertex) { Set neighbors = new LinkedHashSet<>(); for (E e : g.iterables().edgesOf(vertex)) { neighbors.add(Graphs.getOppositeVertex(g, e, vertex)); } return neighbors; } /** * Returns a list of vertices that are the direct predecessors of a specified vertex. If the * graph is a multigraph, vertices may appear more than once in the returned list. * *

* The method uses {@link Graph#incomingEdgesOf(Object)} to traverse the graph. * * @param g the graph to look for predecessors in * @param vertex the vertex to get the predecessors of * @param the graph vertex type * @param the graph edge type * * @return a list of the vertices that are the direct predecessors of the specified vertex. */ public static List predecessorListOf(Graph g, V vertex) { List predecessors = new ArrayList<>(); for (E e : g.iterables().incomingEdgesOf(vertex)) { predecessors.add(getOppositeVertex(g, e, vertex)); } return predecessors; } /** * Returns a list of vertices that are the direct successors of a specified vertex. If the graph * is a multigraph vertices may appear more than once in the returned list. * *

* The method uses {@link Graph#outgoingEdgesOf(Object)} to traverse the graph. * * @param g the graph to look for successors in * @param vertex the vertex to get the successors of * @param the graph vertex type * @param the graph edge type * * @return a list of the vertices that are the direct successors of the specified vertex. */ public static List successorListOf(Graph g, V vertex) { List successors = new ArrayList<>(); for (E e : g.iterables().outgoingEdgesOf(vertex)) { successors.add(getOppositeVertex(g, e, vertex)); } return successors; } /** * Returns an undirected view of the specified graph. If the specified graph is directed, * returns an undirected view of it. If the specified graph is already undirected, just returns * it. * * @param g the graph for which an undirected view is to be returned * @param the graph vertex type * @param the graph edge type * * @return an undirected view of the specified graph, if it is directed, or or the specified * graph itself if it is already undirected. * * @throws IllegalArgumentException if the graph is neither directed nor undirected * @see AsUndirectedGraph */ public static Graph undirectedGraph(Graph g) { if (g.getType().isDirected()) { return new AsUndirectedGraph<>(g); } else if (g.getType().isUndirected()) { return g; } else { throw new IllegalArgumentException("graph must be either directed or undirected"); } } /** * Tests whether an edge is incident to a vertex. * * @param g graph containing e and v * @param e edge in g * @param v vertex in g * @param the graph vertex type * @param the graph edge type * * @return true iff e is incident on v */ public static boolean testIncidence(Graph g, E e, V v) { return (g.getEdgeSource(e).equals(v)) || (g.getEdgeTarget(e).equals(v)); } /** * Gets the vertex opposite another vertex across an edge. * * @param g graph containing e and v * @param e edge in g * @param v vertex in g * @param the graph vertex type * @param the graph edge type * * @return vertex opposite to v across e */ public static V getOppositeVertex(Graph g, E e, V v) { V source = g.getEdgeSource(e); V target = g.getEdgeTarget(e); if (v.equals(source)) { return target; } else if (v.equals(target)) { return source; } else { throw new IllegalArgumentException("no such vertex: " + v.toString()); } } /** * Removes the given vertex from the given graph. If the vertex to be removed has one or more * predecessors, the predecessors will be connected directly to the successors of the vertex to * be removed. * * @param graph graph to be mutated * @param vertex vertex to be removed from this graph, if present * @param the graph vertex type * @param the graph edge type * * @return true if the graph contained the specified vertex; false otherwise. */ public static boolean removeVertexAndPreserveConnectivity(Graph graph, V vertex) { if (!graph.containsVertex(vertex)) { return false; } if (vertexHasPredecessors(graph, vertex)) { List predecessors = Graphs.predecessorListOf(graph, vertex); List successors = Graphs.successorListOf(graph, vertex); for (V predecessor : predecessors) { addOutgoingEdges(graph, predecessor, successors); } } graph.removeVertex(vertex); return true; } /** * Filters vertices from the given graph and subsequently removes them. If the vertex to be * removed has one or more predecessors, the predecessors will be connected directly to the * successors of the vertex to be removed. * * @param graph graph to be mutated * @param predicate a non-interfering stateless predicate to apply to each vertex to determine * if it should be removed from the graph * @param the graph vertex type * @param the graph edge type * * @return true if at least one vertex has been removed; false otherwise. */ public static boolean removeVerticesAndPreserveConnectivity(Graph graph, Predicate predicate) { List verticesToRemove = new ArrayList<>(); for (V node : graph.vertexSet()) { if (predicate.test(node)) { verticesToRemove.add(node); } } return removeVertexAndPreserveConnectivity(graph, verticesToRemove); } /** * Removes all the given vertices from the given graph. If the vertex to be removed has one or * more predecessors, the predecessors will be connected directly to the successors of the * vertex to be removed. * * @param graph to be mutated * @param vertices vertices to be removed from this graph, if present * @param the graph vertex type * @param the graph edge type * * @return true if at least one vertex has been removed; false otherwise. */ public static boolean removeVertexAndPreserveConnectivity(Graph graph, Iterable vertices) { boolean atLeastOneVertexHasBeenRemoved = false; for (V vertex : vertices) { if (removeVertexAndPreserveConnectivity(graph, vertex)) { atLeastOneVertexHasBeenRemoved = true; } } return atLeastOneVertexHasBeenRemoved; } /** * Add edges from one source vertex to multiple target vertices. Whether duplicates are created * depends on the underlying {@link Graph} implementation. * * @param graph graph to be mutated * @param source source vertex of the new edges * @param targets target vertices for the new edges * @param the graph vertex type * @param the graph edge type */ public static void addOutgoingEdges(Graph graph, V source, Iterable targets) { if (!graph.containsVertex(source)) { graph.addVertex(source); } for (V target : targets) { if (!graph.containsVertex(target)) { graph.addVertex(target); } graph.addEdge(source, target); } } /** * Add edges from multiple source vertices to one target vertex. Whether duplicates are created * depends on the underlying {@link Graph} implementation. * * @param graph graph to be mutated * @param target target vertex for the new edges * @param sources source vertices for the new edges * @param the graph vertex type * @param the graph edge type */ public static void addIncomingEdges(Graph graph, V target, Iterable sources) { if (!graph.containsVertex(target)) { graph.addVertex(target); } for (V source : sources) { if (!graph.containsVertex(source)) { graph.addVertex(source); } graph.addEdge(source, target); } } /** * Check if a vertex has any direct successors. * * @param graph the graph to look for successors * @param vertex the vertex to look for successors * @param the graph vertex type * @param the graph edge type * * @return true if the vertex has any successors, false otherwise */ public static boolean vertexHasSuccessors(Graph graph, V vertex) { return !graph.outgoingEdgesOf(vertex).isEmpty(); } /** * Check if a vertex has any direct predecessors. * * @param graph the graph to look for predecessors * @param vertex the vertex to look for predecessors * @param the graph vertex type * @param the graph edge type * * @return true if the vertex has any predecessors, false otherwise */ public static boolean vertexHasPredecessors(Graph graph, V vertex) { return !graph.incomingEdgesOf(vertex).isEmpty(); } /** * Compute a new mapping from the vertices of a graph to the integer range $[0, n)$ where $n$ is * the number of vertices in the graph. * * @param graph the input graph * @param the graph vertex type * @param the graph edge type * @throws NullPointerException if {@code graph} is {@code null} * * @return the mapping as an object containing the {@code vertexMap} and the {@code indexList} * * @see VertexToIntegerMapping */ public static VertexToIntegerMapping getVertexToIntegerMapping(Graph graph) { return new VertexToIntegerMapping<>(Objects.requireNonNull(graph).vertexSet()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy