/*
* Created on Apr 2, 2006
*
* Copyright (c) 2006, the JUNG Project and the Regents of the University
* of California
* All rights reserved.
*
* This software is open-source under the BSD license; see either
* "license.txt" or
* http://jung.sourceforge.net/license.txt for a description.
*/
package edu.uci.ics.jung.graph;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.graph.util.Pair;
/**
* Abstract implementation of the <code>Graph</code> interface. Designed to
* simplify implementation of new graph classes.
*
* @author Joshua O'Madadhain
*/
@SuppressWarnings("serial")
public abstract class AbstractGraph<V, E> implements Graph<V, E>, Serializable {
@Override
public boolean addEdge(E edge, Collection<? extends V> vertices) {
return addEdge(edge, vertices, this.getDefaultEdgeType());
}
@Override
@SuppressWarnings("unchecked")
public boolean addEdge(E edge, Collection<? extends V> vertices,
EdgeType edgeType) {
if (vertices == null) {
throw new IllegalArgumentException(
"'vertices' parameter must not be null");
}
if (vertices.size() == 2) {
return addEdge(edge, vertices instanceof Pair ? (Pair<V>) vertices
: new Pair<V>(vertices), edgeType);
} else if (vertices.size() == 1) {
V vertex = vertices.iterator().next();
return addEdge(edge, new Pair<V>(vertex, vertex), edgeType);
} else {
throw new IllegalArgumentException(
"Graph objects connect 1 or 2 vertices; vertices arg has "
+ vertices.size());
}
}
@Override
public boolean addEdge(E e, V v1, V v2) {
return addEdge(e, v1, v2, this.getDefaultEdgeType());
}
@Override
public boolean addEdge(E e, V v1, V v2, EdgeType edge_type) {
return addEdge(e, new Pair<V>(v1, v2), edge_type);
}
/**
* Adds {@code edge} to this graph with the specified {@code endpoints},
* with the default edge type.
*
* @return {@code} true iff the graph was modified as a result of this call
*/
public boolean addEdge(E edge, Pair<? extends V> endpoints) {
return addEdge(edge, endpoints, this.getDefaultEdgeType());
}
/**
* Adds {@code edge} to this graph with the specified {@code endpoints} and
* {@code EdgeType}.
*
* @return {@code} true iff the graph was modified as a result of this call
*/
public abstract boolean addEdge(E edge, Pair<? extends V> endpoints,
EdgeType edgeType);
protected Pair<V> getValidatedEndpoints(E edge,
Pair<? extends V> endpoints) {
if (edge == null) {
throw new IllegalArgumentException("input edge may not be null");
}
if (endpoints == null) {
throw new IllegalArgumentException("endpoints may not be null");
}
Pair<V> new_endpoints = new Pair<V>(endpoints.getFirst(),
endpoints.getSecond());
if (containsEdge(edge)) {
Pair<V> existing_endpoints = getEndpoints(edge);
if (!existing_endpoints.equals(new_endpoints)) {
throw new IllegalArgumentException("edge " + edge
+ " already exists in this graph with endpoints "
+ existing_endpoints
+ " and cannot be added with endpoints " + endpoints);
}
return null;
}
return new_endpoints;
}
@Override
public int inDegree(V vertex) {
return this.getInEdges(vertex).size();
}
@Override
public int outDegree(V vertex) {
return this.getOutEdges(vertex).size();
}
@Override
public boolean isPredecessor(V v1, V v2) {
return this.getPredecessors(v1).contains(v2);
}
@Override
public boolean isSuccessor(V v1, V v2) {
return this.getSuccessors(v1).contains(v2);
}
@Override
public int getPredecessorCount(V vertex) {
return this.getPredecessors(vertex).size();
}
@Override
public int getSuccessorCount(V vertex) {
return this.getSuccessors(vertex).size();
}
@Override
public boolean isNeighbor(V v1, V v2) {
if (!containsVertex(v1) || !containsVertex(v2)) {
throw new IllegalArgumentException(
"At least one of these not in this graph: " + v1 + ", "
+ v2);
}
return this.getNeighbors(v1).contains(v2);
}
@Override
public boolean isIncident(V vertex, E edge) {
if (!containsVertex(vertex) || !containsEdge(edge)) {
throw new IllegalArgumentException(
"At least one of these not in this graph: " + vertex + ", "
+ edge);
}
return this.getIncidentEdges(vertex).contains(edge);
}
@Override
public int getNeighborCount(V vertex) {
if (!containsVertex(vertex)) {
throw new IllegalArgumentException(
vertex + " is not a vertex in this graph");
}
return this.getNeighbors(vertex).size();
}
@Override
public int degree(V vertex) {
if (!containsVertex(vertex)) {
throw new IllegalArgumentException(
vertex + " is not a vertex in this graph");
}
return this.getIncidentEdges(vertex).size();
}
@Override
public int getIncidentCount(E edge) {
Pair<V> incident = this.getEndpoints(edge);
if (incident == null) {
return 0;
}
if (incident.getFirst() == incident.getSecond()) {
return 1;
}
return 2;
}
@Override
public V getOpposite(V vertex, E edge) {
Pair<V> incident = this.getEndpoints(edge);
V first = incident.getFirst();
V second = incident.getSecond();
if (vertex.equals(first)) {
return second;
} else if (vertex.equals(second)) {
return first;
} else {
throw new IllegalArgumentException(
vertex + " is not incident to " + edge + " in this graph");
}
}
@Override
public E findEdge(V v1, V v2) {
for (E e : getOutEdges(v1)) {
if (getOpposite(v1, e).equals(v2)) {
return e;
}
}
return null;
}
@Override
public Collection<E> findEdgeSet(V v1, V v2) {
if (!getVertices().contains(v1)) {
throw new IllegalArgumentException(
v1 + " is not an element of this graph");
}
if (!getVertices().contains(v2)) {
throw new IllegalArgumentException(
v2 + " is not an element of this graph");
}
Collection<E> edges = new ArrayList<E>();
for (E e : getOutEdges(v1)) {
if (getOpposite(v1, e).equals(v2)) {
edges.add(e);
}
}
return Collections.unmodifiableCollection(edges);
}
@Override
public Collection<V> getIncidentVertices(E edge) {
Pair<V> endpoints = this.getEndpoints(edge);
Collection<V> incident = new ArrayList<V>();
incident.add(endpoints.getFirst());
incident.add(endpoints.getSecond());
return Collections.unmodifiableCollection(incident);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Vertices:");
for (V v : getVertices()) {
sb.append(v);
sb.append(",");
}
sb.setLength(sb.length() - 1);
sb.append("\nEdges:");
for (E e : getEdges()) {
Pair<V> ep = getEndpoints(e);
sb.append(e);
sb.append("[");
sb.append(ep.getFirst());
sb.append(",");
sb.append(ep.getSecond());
sb.append("] ");
}
return sb.toString();
}
}