com.googlecode.blaisemath.graph.SparseGraph Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of blaise-graphtheory Show documentation
Show all versions of blaise-graphtheory Show documentation
Link graph definitions, algorithms, and visualization.
The newest version!
/*
* SparseGraph.java
* Created May 21, 2010
*/
package com.googlecode.blaisemath.graph;
/*
* #%L
* BlaiseGraphTheory
* --
* Copyright (C) 2009 - 2016 Elisha Peterson
* --
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Table;
import com.googlecode.blaisemath.util.Edge;
import com.googlecode.blaisemath.util.Edge.UndirectedEdge;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.concurrent.Immutable;
/**
*
* General graph structure that maintains cached information to speed graph computations.
* Maintains a set of all edges in the graph, a map associating each vertex with its adjacent edges,
* and information about connected components. The graph cannot be changed once it is created.
*
*
* @param the type of the nodes
*
* @author Elisha Peterson
*/
@Immutable
public final class SparseGraph extends GraphSupport {
/** Edges in graph (replicated for speed) */
private final Set> edges = new LinkedHashSet>();
/**
* Edges in graph, by vertex. Each vertex contains all edges adjacent to the
* vertex, regardless of direction.
*/
private final SetMultimap> edgeIndex = HashMultimap.create();
/**
* The adjacencies in components of the graph. If directed, rows are sources
* and columns are destinations. Each pair of vertices may have multiple edges.
* If undirected, the set of edges is the same for both directions.
*/
private final Table>> edgeTable = HashBasedTable.create();
/** Information about the graph's components (replicated for speed) */
private GraphComponents components;
/**
* Helper constructor for factory methods
* @param directed whether graph is directed
* @param nodes nodes in the graph
*/
private SparseGraph(boolean directed, Iterable nodes) {
super(directed, nodes);
}
/**
* Construct graph with specific nodes and edges.
* @param graph node type
* @param directed whether graph is directed
* @param nodes nodes in the graph
* @param edges edges in the graph, as ordered node pairs; each must have a 0 element and a 1 element
* @return created graph
*/
public static SparseGraph createFromEdges(boolean directed, Iterable nodes, Iterable> edges) {
SparseGraph res = new SparseGraph(directed, Lists.newArrayList(nodes));
for (Edge e : edges) {
res.addEdge(e.getNode1(), e.getNode2());
}
res.components = new GraphComponents(res, GraphUtils.components(res.edgeTable));
return res;
}
//
// FACTORY METHODS
//
/**
* Construct graph with specific nodes and edges
* @param graph node type
* @param directed whether graph is directed
* @param nodes nodes in the graph
* @param edges edges in the graph, as ordered node pairs; each must have a 0 element and a 1 element
* @return graph
*/
public static SparseGraph createFromArrayEdges(boolean directed, V[] nodes, Iterable edges) {
SparseGraph res = new SparseGraph(directed, Arrays.asList(nodes));
for (V[] e : edges) {
res.addEdge(e[0], e[1]);
}
res.components = new GraphComponents(res, GraphUtils.components(res.edgeTable));
return res;
}
/**
* Construct graph with specific nodes and edges
* @param graph node type
* @param directed whether graph is directed
* @param nodes nodes in the graph
* @param edges edges in the graph, as ordered node pairs; each must have a 0 element and a 1 element
* @return graph
*/
public static SparseGraph createFromArrayEdges(boolean directed, Iterable nodes, Iterable edges) {
SparseGraph res = new SparseGraph(directed, nodes);
for (V[] e : edges) {
res.addEdge(e[0], e[1]);
}
res.components = new GraphComponents(res, GraphUtils.components(res.edgeTable));
return res;
}
/**
* Construct graph with a sparse adjacency representation.
* @param graph node type
* @param directed if graph is directed
* @param adjacencies map with adjacency info
* @return graph
*/
public static SparseGraph createFromAdjacencies(boolean directed, Multimap adjacencies) {
SparseGraph res = new SparseGraph(directed, GraphUtils.nodes(adjacencies));
for (Entry en : adjacencies.entries()) {
res.addEdge(en.getKey(), en.getValue());
}
res.components = new GraphComponents(res, GraphUtils.components(res.edgeTable));
return res;
}
//
/** Invoke from initializer only */
private void addEdge(V x, V y) {
Edge edge = directed ? addDirectedEdge(x, y) : addUndirectedEdge(x, y);
edges.add(edge);
edgeIndex.put(x, edge);
edgeIndex.put(y, edge);
}
/** Invoke from initializer only */
private Edge addDirectedEdge(V x, V y) {
if (!edgeTable.contains(x, y)) {
edgeTable.put(x, y, new HashSet>());
}
Edge edge = new Edge(x, y);
edgeTable.get(x, y).add(edge);
return edge;
}
/** Invoke from initializer only */
private Edge addUndirectedEdge(V x, V y) {
if (!edgeTable.contains(x, y)) {
edgeTable.put(x, y, new HashSet>());
}
if (!edgeTable.contains(y, x)) {
edgeTable.put(y, x, new HashSet>());
}
UndirectedEdge edge = new UndirectedEdge(x, y);
edgeTable.get(x, y).add(edge);
edgeTable.get(y, x).add(edge);
return edge;
}
//
@Override
public String toString() {
return String.format("SparseGraph[%s,%d nodes,%d edges]",
directed?"directed":"undirected", nodeCount(), edgeCount());
}
@Override
public boolean adjacent(V x, V y) {
if (edgeTable.contains(x, y) && !edgeTable.get(x, y).isEmpty()) {
return true;
}
if (directed && edgeTable.contains(y, x) && !edgeTable.get(y, x).isEmpty()) {
return true;
}
return false;
}
public GraphComponents getComponentInfo() {
return components;
}
@Override
public Set> edges() {
return Collections.unmodifiableSet(edges);
}
@Override
public Collection> edgesAdjacentTo(V x) {
return Collections.unmodifiableSet(edgeIndex.get(x));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy