com.salesforce.jgrapht.GraphTests Maven / Gradle / Ivy
Show all versions of AptSpringProcessor Show documentation
/*
* (C) Copyright 2003-2017, by Barak Naveh, Dimitrios Michail and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
package com.salesforce.jgrapht;
import java.util.*;
import com.salesforce.jgrapht.alg.*;
import com.salesforce.jgrapht.alg.cycle.*;
import com.salesforce.jgrapht.graph.*;
/**
* A collection of utilities to test for various graph properties.
*
* @author Barak Naveh
* @author Dimitrios Michail
*/
public abstract class GraphTests
{
/**
* Test whether a graph is empty. An empty graph on n nodes consists of n isolated vertices with
* no edges.
*
* @param graph the input graph
* @param the graph vertex type
* @param the graph edge type
* @return true if the graph is empty, false otherwise
*/
public static boolean isEmpty(Graph graph)
{
Objects.requireNonNull(graph, "Graph cannot be null");
return graph.edgeSet().isEmpty();
}
/**
* Check if a graph is simple. A graph is simple if it has no self-loops and multiple edges.
*
* @param graph a graph
* @param the graph vertex type
* @param the graph edge type
* @return true if a graph is simple, false otherwise
*/
public static boolean isSimple(Graph graph)
{
Objects.requireNonNull(graph, "Graph cannot be null");
if (graph instanceof AbstractBaseGraph, ?>) {
AbstractBaseGraph abg = (AbstractBaseGraph) graph;
if (!abg.isAllowingLoops() && !abg.isAllowingMultipleEdges()) {
return true;
}
}
// no luck, we have to check
boolean isDirected = graph instanceof DirectedGraph, ?>;
for (V v : graph.vertexSet()) {
Iterable edgesOf;
if (isDirected) {
edgesOf = ((DirectedGraph) graph).outgoingEdgesOf(v);
} else {
edgesOf = graph.edgesOf(v);
}
Set neighbors = new HashSet<>();
for (E e : edgesOf) {
V u = Graphs.getOppositeVertex(graph, e, v);
if (u.equals(v) || !neighbors.add(u)) {
return false;
}
}
}
return true;
}
/**
* Test whether a graph is complete. A complete undirected graph is a simple graph in which
* every pair of distinct vertices is connected by a unique edge. A complete directed graph is a
* directed graph in which every pair of distinct vertices is connected by a pair of unique
* edges (one in each direction).
*
* @param graph the input graph
* @param the graph vertex type
* @param the graph edge type
* @return true if the graph is complete, false otherwise
*/
public static boolean isComplete(Graph graph)
{
Objects.requireNonNull(graph, "Graph cannot be null");
int n = graph.vertexSet().size();
int allEdges;
if (graph instanceof DirectedGraph, ?>) {
allEdges = Math.multiplyExact(n, n - 1);
} else if (graph instanceof UndirectedGraph, ?>) {
if (n % 2 == 0) {
allEdges = Math.multiplyExact(n / 2, n - 1);
} else {
allEdges = Math.multiplyExact(n, (n - 1) / 2);
}
} else {
throw new IllegalArgumentException("Graph must be directed or undirected");
}
return graph.edgeSet().size() == allEdges && isSimple(graph);
}
/**
* Test whether an undirected graph is connected.
*
*
* This method does not performing any caching, instead recomputes everything from scratch. In
* case more control is required use {@link ConnectivityInspector} directly.
*
* @param graph the input graph
* @param the graph vertex type
* @param the graph edge type
* @return true if the graph is connected, false otherwise
* @see ConnectivityInspector
*/
public static boolean isConnected(UndirectedGraph graph)
{
Objects.requireNonNull(graph, "Graph cannot be null");
return new ConnectivityInspector<>(graph).isGraphConnected();
}
/**
* Test whether a directed graph is weakly connected.
*
*
* This method does not performing any caching, instead recomputes everything from scratch. In
* case more control is required use {@link ConnectivityInspector} directly.
*
* @param graph the input graph
* @param the graph vertex type
* @param the graph edge type
* @return true if the graph is weakly connected, false otherwise
* @see ConnectivityInspector
*/
public static boolean isWeaklyConnected(DirectedGraph graph)
{
Objects.requireNonNull(graph, "Graph cannot be null");
return new ConnectivityInspector<>(graph).isGraphConnected();
}
/**
* Test whether a directed graph is strongly connected.
*
*
* This method does not performing any caching, instead recomputes everything from scratch. In
* case more control is required use {@link KosarajuStrongConnectivityInspector} directly.
*
* @param graph the input graph
* @param the graph vertex type
* @param the graph edge type
* @return true if the graph is strongly connected, false otherwise
* @see KosarajuStrongConnectivityInspector
*/
public static boolean isStronglyConnected(DirectedGraph graph)
{
Objects.requireNonNull(graph, "Graph cannot be null");
return new KosarajuStrongConnectivityInspector<>(graph).isStronglyConnected();
}
/**
* Test whether an undirected graph is a tree.
*
* @param graph the input graph
* @param the graph vertex type
* @param the graph edge type
* @return true if the graph is tree, false otherwise
*/
public static boolean isTree(UndirectedGraph graph)
{
return (graph.edgeSet().size() == (graph.vertexSet().size() - 1)) && isConnected(graph);
}
/**
* Test whether a graph is bipartite.
*
* @param graph the input graph
* @param the graph vertex type
* @param the graph edge type
* @return true if the graph is bipartite, false otherwise
*/
public static boolean isBipartite(Graph graph)
{
if (isEmpty(graph)) {
return true;
}
try {
// at most n^2/4 edges
if (Math.multiplyExact(4, graph.edgeSet().size()) > Math
.multiplyExact(graph.vertexSet().size(), graph.vertexSet().size()))
{
return false;
}
} catch (ArithmeticException e) {
// ignore
}
Set unknown = new HashSet<>(graph.vertexSet());
Set odd = new HashSet<>();
Deque queue = new LinkedList<>();
while (!unknown.isEmpty()) {
if (queue.isEmpty()) {
queue.add(unknown.iterator().next());
}
V v = queue.removeFirst();
unknown.remove(v);
for (E e : graph.edgesOf(v)) {
V n = Graphs.getOppositeVertex(graph, e, v);
if (unknown.contains(n)) {
queue.add(n);
if (!odd.contains(v)) {
odd.add(n);
}
} else if (!(odd.contains(v) ^ odd.contains(n))) {
return false;
}
}
}
return true;
}
/**
* Test whether a partition of the vertices into two sets is a bipartite partition.
*
* @param graph the input graph
* @param firstPartition the first vertices partition
* @param secondPartition the second vertices partition
* @return true if the partition is a bipartite partition, false otherwise
* @param the graph vertex type
* @param the graph edge type
*/
public static boolean isBipartitePartition(
Graph graph, Set extends V> firstPartition, Set extends V> secondPartition)
{
Objects.requireNonNull(graph, "Graph cannot be null");
Objects.requireNonNull(firstPartition, "First partition cannot be null");
Objects.requireNonNull(secondPartition, "Second partition cannot be null");
if (graph.vertexSet().size() != firstPartition.size() + secondPartition.size()) {
return false;
}
for (V v : graph.vertexSet()) {
Set extends V> otherPartition;
if (firstPartition.contains(v)) {
otherPartition = secondPartition;
} else if (secondPartition.contains(v)) {
otherPartition = firstPartition;
} else {
// v does not belong to any of the two partitions
return false;
}
for (E e : graph.edgesOf(v)) {
V other = Graphs.getOppositeVertex(graph, e, v);
if (!otherPartition.contains(other)) {
return false;
}
}
}
return true;
}
/**
* Test whether a graph is Eulerian. An undirected graph is Eulerian if it is connected and each
* vertex has an even degree. A directed graph is Eulerian if it is strongly connected and each
* vertex has the same incoming and outgoing degree. Test whether a graph is Eulerian. An
* Eulerian graph is a graph
* containing an Eulerian cycle.
*
* @param graph the input graph
* @param the graph vertex type
* @param the graph edge type
*
* @return true if the graph is Eulerian, false otherwise
* @see HierholzerEulerianCycle#isEulerian(Graph)
*/
public static boolean isEulerian(Graph graph)
{
Objects.requireNonNull(graph, "Graph cannot be null");
return new HierholzerEulerianCycle().isEulerian(graph);
}
}
// End GraphTests.java