/* * Created on May 8, 2008 * * Copyright (c) 2008, 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.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections15.CollectionUtils; import org.apache.commons.collections15.Factory; import org.geogebra.common.util.debug.Log; import edu.uci.ics.jung.graph.util.EdgeType; import edu.uci.ics.jung.graph.util.Pair; /** * An implementation of <code>Tree</code> in which each vertex has <= k * children. The value of 'k' is specified by the constructor parameter. A * specific child (edge) can be retrieved directly by specifying the index at * which the child is located. By default, new (child) vertices are added at the * lowest index available, if no index is specified. * */ @SuppressWarnings("serial") public class OrderedKAryTree<V, E> extends AbstractTypedGraph<V, E> implements Tree<V, E> { protected Map<E, Pair<V>> edge_vpairs; protected Map<V, VertexData> vertex_data; protected int height; protected V root; protected int order; /** * Returns a {@code Factory} that creates an instance of this graph type. * * @param <V> * the vertex type for the graph factory * @param <E> * the edge type for the graph factory */ public static <V, E> Factory<DirectedGraph<V, E>> getFactory( final int order) { return new Factory<DirectedGraph<V, E>>() { @Override public DirectedGraph<V, E> create() { return new OrderedKAryTree<V, E>(order); } }; } /** * Creates a new instance with the specified order (maximum number of * children). */ public OrderedKAryTree(int order) { super(EdgeType.DIRECTED); this.order = order; this.height = -1; this.edge_vpairs = new HashMap<E, Pair<V>>(); this.vertex_data = new HashMap<V, VertexData>(); } /** * Returns the number of children that {@code vertex} has. * * @see edu.uci.ics.jung.graph.Tree#getChildCount(java.lang.Object) */ @Override public int getChildCount(V vertex) { if (!containsVertex(vertex)) { return 0; } List<E> edges = vertex_data.get(vertex).child_edges; if (edges == null) { return 0; } int count = 0; for (E edge : edges) { count += edge == null ? 0 : 1; } return count; } /** * Returns the child edge of the vertex at index <code>index</code>. * * @param vertex * @param index * @return the child edge of the vertex at index <code>index</code> */ public E getChildEdge(V vertex, int index) { if (!containsVertex(vertex)) { return null; } List<E> edges = vertex_data.get(vertex).child_edges; if (edges == null) { return null; } return edges.get(index); } /** * @see edu.uci.ics.jung.graph.Tree#getChildEdges(java.lang.Object) */ @Override public Collection<E> getChildEdges(V vertex) { if (!containsVertex(vertex)) { return null; } List<E> edges = vertex_data.get(vertex).child_edges; return edges == null ? Collections.<E> emptySet() : CollectionUtils.unmodifiableCollection(edges); } /** * Returns an ordered list of {@code vertex}'s child vertices. If there is * no child in position i, then the list will contain {@code null} in * position i. If {@code vertex} has no children then the empty set will be * returned. * * @see edu.uci.ics.jung.graph.Tree#getChildren(java.lang.Object) */ @Override public Collection<V> getChildren(V vertex) { if (!containsVertex(vertex)) { return null; } List<E> edges = vertex_data.get(vertex).child_edges; if (edges == null) { return Collections.emptySet(); } Collection<V> children = new ArrayList<V>(order); for (E edge : edges) { children.add(this.getOpposite(vertex, edge)); } return CollectionUtils.unmodifiableCollection(children); } /** * @see edu.uci.ics.jung.graph.Tree#getDepth(java.lang.Object) * @return the depth of the vertex in this tree, or -1 if the vertex is not * present in this tree */ @Override public int getDepth(V vertex) { if (!containsVertex(vertex)) { return -1; } return vertex_data.get(vertex).depth; } /** * Returns the height of the tree, or -1 if the tree is empty. * * @see edu.uci.ics.jung.graph.Tree#getHeight() */ @Override public int getHeight() { return height; } /** * @see edu.uci.ics.jung.graph.Tree#getParent(java.lang.Object) */ @Override public V getParent(V vertex) { if (!containsVertex(vertex)) { return null; } else if (vertex.equals(root)) { return null; } return edge_vpairs.get(vertex_data.get(vertex).parent_edge).getFirst(); } /** * @see edu.uci.ics.jung.graph.Tree#getParentEdge(java.lang.Object) */ @Override public E getParentEdge(V vertex) { if (!containsVertex(vertex)) { return null; } return vertex_data.get(vertex).parent_edge; } /** * @see edu.uci.ics.jung.graph.Tree#getRoot() */ @Override public V getRoot() { return root; } /** * @see edu.uci.ics.jung.graph.Forest#getTrees() */ @Override public Collection<Tree<V, E>> getTrees() { Collection<Tree<V, E>> forest = new ArrayList<Tree<V, E>>(1); forest.add(this); return forest; } /** * Adds the specified {@code child} vertex and edge {@code e} to the graph * with the specified parent vertex {@code parent}. If {@code index} is * greater than or equal to 0, then the child is placed at position * {@code index}; if it is less than 0, the child is placed at the lowest * available position; if it is greater than or equal to the order of this * tree, an exception is thrown. * * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, * java.lang.Object, java.lang.Object) */ public boolean addEdge(E e, V parent, V child, int index) { if (e == null || child == null || parent == null) { throw new IllegalArgumentException("Inputs may not be null"); } if (!containsVertex(parent)) { throw new IllegalArgumentException( "Tree must already " + "include parent: " + parent); } if (containsVertex(child)) { throw new IllegalArgumentException( "Tree must not already " + "include child: " + child); } if (parent.equals(child)) { throw new IllegalArgumentException( "Input vertices must be distinct"); } if (index < 0 || index >= order) { throw new IllegalArgumentException( "'index' must be in [0, [order-1]]"); } Pair<V> endpoints = new Pair<V>(parent, child); if (containsEdge(e)) { if (!endpoints.equals(edge_vpairs.get(e))) { throw new IllegalArgumentException("Tree already includes edge" + e + " with different endpoints " + edge_vpairs.get(e)); } return false; } VertexData parent_data = vertex_data.get(parent); List<E> outedges = parent_data.child_edges; if (outedges == null) { outedges = new ArrayList<E>(this.order); } boolean edge_placed = false; if (outedges.get(index) != null) { throw new IllegalArgumentException( "Parent " + parent + " already has a child at index " + index + " in this tree"); } outedges.set(index, e); for (int i = 0; i < order; i++) { if (outedges.get(i) == null) { outedges.set(i, e); edge_placed = true; break; } } if (!edge_placed) { throw new IllegalArgumentException("Parent " + parent + " already" + " has " + order + " children in this tree"); } // initialize VertexData for child; leave child's child_edges null for // now VertexData child_data = new VertexData(e, parent_data.depth + 1); vertex_data.put(child, child_data); height = child_data.depth > height ? child_data.depth : height; edge_vpairs.put(e, endpoints); return true; } /** * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, * java.lang.Object, java.lang.Object) */ @Override public boolean addEdge(E e, V parent, V child) { return addEdge(e, parent, child, -1); } /** * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, * java.lang.Object, java.lang.Object, * edu.uci.ics.jung.graph.util.EdgeType) */ @Override public boolean addEdge(E e, V v1, V v2, EdgeType edge_type) { this.validateEdgeType(edge_type); return addEdge(e, v1, v2); } /** * @see edu.uci.ics.jung.graph.Graph#getDest(java.lang.Object) */ @Override public V getDest(E directed_edge) { if (!containsEdge(directed_edge)) { return null; } return edge_vpairs.get(directed_edge).getSecond(); } /** * @see edu.uci.ics.jung.graph.Graph#getEndpoints(java.lang.Object) */ @Override public Pair<V> getEndpoints(E edge) { if (!containsEdge(edge)) { return null; } return edge_vpairs.get(edge); } /** * @see edu.uci.ics.jung.graph.Graph#getInEdges(java.lang.Object) */ @Override public Collection<E> getInEdges(V vertex) { if (!containsVertex(vertex)) { return null; } else if (vertex.equals(root)) { return Collections.emptySet(); } else { return Collections.singleton(getParentEdge(vertex)); } } /** * @see edu.uci.ics.jung.graph.Graph#getOpposite(java.lang.Object, * java.lang.Object) */ @Override public V getOpposite(V vertex, E edge) { if (!containsVertex(vertex) || !containsEdge(edge)) { return null; } Pair<V> endpoints = edge_vpairs.get(edge); V v1 = endpoints.getFirst(); V v2 = endpoints.getSecond(); return v1.equals(vertex) ? v2 : v1; } /** * @see edu.uci.ics.jung.graph.Graph#getOutEdges(java.lang.Object) */ @Override public Collection<E> getOutEdges(V vertex) { return getChildEdges(vertex); } /** * @see edu.uci.ics.jung.graph.Graph#getPredecessorCount(java.lang.Object) * @return 0 if <code>vertex</code> is the root, -1 if the vertex is not an * element of this tree, and 1 otherwise */ @Override public int getPredecessorCount(V vertex) { if (!containsVertex(vertex)) { return -1; } return vertex.equals(root) ? 0 : 1; } /** * @see edu.uci.ics.jung.graph.Graph#getPredecessors(java.lang.Object) */ @Override public Collection<V> getPredecessors(V vertex) { if (!containsVertex(vertex)) { return null; } if (vertex.equals(root)) { return Collections.emptySet(); } return Collections.singleton(getParent(vertex)); } /** * @see edu.uci.ics.jung.graph.Graph#getSource(java.lang.Object) */ @Override public V getSource(E directed_edge) { if (!containsEdge(directed_edge)) { return null; } return edge_vpairs.get(directed_edge).getSecond(); } /** * @see edu.uci.ics.jung.graph.Graph#getSuccessorCount(java.lang.Object) */ @Override public int getSuccessorCount(V vertex) { return getChildCount(vertex); } /** * @see edu.uci.ics.jung.graph.Graph#getSuccessors(java.lang.Object) */ @Override public Collection<V> getSuccessors(V vertex) { return getChildren(vertex); } /** * @see edu.uci.ics.jung.graph.Graph#inDegree(java.lang.Object) */ @Override public int inDegree(V vertex) { if (!containsVertex(vertex)) { return 0; } if (vertex.equals(root)) { return 0; } return 1; } /** * @see edu.uci.ics.jung.graph.Graph#isDest(java.lang.Object, * java.lang.Object) */ @Override public boolean isDest(V vertex, E edge) { if (!containsEdge(edge) || !containsVertex(vertex)) { return false; } return edge_vpairs.get(edge).getSecond().equals(vertex); } /** * Returns <code>true</code> if <code>vertex</code> is a leaf of this tree, * i.e., if it has no children. * * @param vertex * the vertex to be queried * @return <code>true</code> if <code>outDegree(vertex)==0</code> */ public boolean isLeaf(V vertex) { if (!containsVertex(vertex)) { return false; } return outDegree(vertex) == 0; } /** * Returns true iff <code>v1</code> is the parent of <code>v2</code>. Note * that if <code>v2</code> is the root and <code>v1</code> is * <code>null</code>, this method returns <code>true</code>. * * @see edu.uci.ics.jung.graph.Graph#isPredecessor(java.lang.Object, * java.lang.Object) */ @Override public boolean isPredecessor(V v1, V v2) { if (!containsVertex(v2)) { return false; } return getParent(v2).equals(v1); } /** * Returns <code>true</code> if <code>vertex</code> is a leaf of this tree, * i.e., if it has no children. * * @param vertex * the vertex to be queried * @return <code>true</code> if <code>outDegree(vertex)==0</code> */ public boolean isRoot(V vertex) { if (root == null) { return false; } return root.equals(vertex); } /** * @see edu.uci.ics.jung.graph.Graph#isSource(java.lang.Object, * java.lang.Object) */ @Override public boolean isSource(V vertex, E edge) { if (!containsEdge(edge) || !containsVertex(vertex)) { return false; } return edge_vpairs.get(edge).getFirst().equals(vertex); } /** * @see edu.uci.ics.jung.graph.Graph#isSuccessor(java.lang.Object, * java.lang.Object) */ @Override public boolean isSuccessor(V v1, V v2) { if (!containsVertex(v2)) { return false; } if (containsVertex(v1)) { return getParent(v1).equals(v2); } return isLeaf(v2) && v1 == null; } /** * @see edu.uci.ics.jung.graph.Graph#outDegree(java.lang.Object) */ @Override public int outDegree(V vertex) { if (!containsVertex(vertex)) { return 0; } List<E> out_edges = vertex_data.get(vertex).child_edges; if (out_edges == null) { return 0; } int degree = 0; for (E e : out_edges) { degree += (e == null) ? 0 : 1; } return degree; } /** * @see edu.uci.ics.jung.graph.Hypergraph#addEdge(java.lang.Object, * java.util.Collection) */ @Override @SuppressWarnings("unchecked") public boolean addEdge(E edge, Collection<? extends V> vertices, EdgeType edge_type) { if (edge == null || vertices == null) { throw new IllegalArgumentException("inputs may not be null"); } if (vertices.size() != 2) { throw new IllegalArgumentException( "'vertices' must contain " + "exactly 2 distinct vertices"); } this.validateEdgeType(edge_type); Pair<V> endpoints; if (vertices instanceof Pair) { endpoints = (Pair<V>) vertices; } else { endpoints = new Pair<V>(vertices); } V v1 = endpoints.getFirst(); V v2 = endpoints.getSecond(); if (v1.equals(v2)) { throw new IllegalArgumentException( "Input vertices must be distinct"); } return addEdge(edge, v1, v2); } /** * @see edu.uci.ics.jung.graph.Hypergraph#addVertex(java.lang.Object) */ @Override public boolean addVertex(V vertex) { if (root == null) { this.root = vertex; vertex_data.put(vertex, new VertexData(null, 0)); this.height = 0; return true; } throw new UnsupportedOperationException("Unless you are setting " + "the root, use addEdge() or addChild()"); } /** * @see edu.uci.ics.jung.graph.Hypergraph#isIncident(java.lang.Object, * java.lang.Object) */ @Override public boolean isIncident(V vertex, E edge) { if (!containsVertex(vertex) || !containsEdge(edge)) { return false; } return edge_vpairs.get(edge).contains(vertex); } /** * @see edu.uci.ics.jung.graph.Hypergraph#isNeighbor(java.lang.Object, * java.lang.Object) */ @Override public boolean isNeighbor(V v1, V v2) { if (!containsVertex(v1) || !containsVertex(v2)) { return false; } return getNeighbors(v1).contains(v2); } /** * @see edu.uci.ics.jung.graph.Hypergraph#containsEdge(java.lang.Object) */ @Override public boolean containsEdge(E edge) { return edge_vpairs.containsKey(edge); } /** * @see edu.uci.ics.jung.graph.Hypergraph#containsVertex(java.lang.Object) */ @Override public boolean containsVertex(V vertex) { return vertex_data.containsKey(vertex); } /** * @see edu.uci.ics.jung.graph.Hypergraph#findEdge(java.lang.Object, * java.lang.Object) */ @Override public E findEdge(V v1, V v2) { if (!containsVertex(v1) || !containsVertex(v2)) { return null; } VertexData v1_data = vertex_data.get(v1); if (edge_vpairs.get(v1_data.parent_edge).getFirst().equals(v2)) { return v1_data.parent_edge; } List<E> edges = v1_data.child_edges; if (edges == null) { return null; } for (E edge : edges) { if (edge != null && edge_vpairs.get(edge).getSecond().equals(v2)) { return edge; } } return null; } /** * @see edu.uci.ics.jung.graph.Hypergraph#findEdgeSet(java.lang.Object, * java.lang.Object) */ @Override public Collection<E> findEdgeSet(V v1, V v2) { E edge = findEdge(v1, v2); if (edge == null) { return Collections.emptySet(); } return Collections.singleton(edge); } /** * Returns the child of <code>vertex</code> at position <code>index</code> * in this tree, or <code>null</code> if it has no child at that position. * * @param vertex * the vertex to query * @return the child of <code>vertex</code> at position <code>index</code> * in this tree, or <code>null</code> if it has no child at that * position * @throws ArrayIndexOutOfBoundsException * if <code>index</code> is not in the range * {@code [0, order-1]} */ public V getChild(V vertex, int index) { if (index < 0 || index >= order) { throw new ArrayIndexOutOfBoundsException( index + " is not in [0, order-1]"); } if (!containsVertex(vertex)) { return null; } List<E> edges = vertex_data.get(vertex).child_edges; if (edges == null) { return null; } E edge = edges.get(index); return edge == null ? null : edge_vpairs.get(edge).getSecond(); } /** * @see edu.uci.ics.jung.graph.Hypergraph#getEdgeCount() */ @Override public int getEdgeCount() { return edge_vpairs.size(); } /** * @see edu.uci.ics.jung.graph.Hypergraph#getEdges() */ @Override public Collection<E> getEdges() { return CollectionUtils.unmodifiableCollection(edge_vpairs.keySet()); } /** * @see edu.uci.ics.jung.graph.Hypergraph#getIncidentCount(java.lang.Object) */ @Override public int getIncidentCount(E edge) { return 2; // all tree edges have 2 incident vertices } /** * @see edu.uci.ics.jung.graph.Hypergraph#getIncidentEdges(java.lang.Object) */ @Override public Collection<E> getIncidentEdges(V vertex) { if (!containsVertex(vertex)) { return null; } ArrayList<E> edges = new ArrayList<E>(order + 1); VertexData v_data = vertex_data.get(vertex); if (v_data.parent_edge != null) { edges.add(v_data.parent_edge); } if (v_data.child_edges != null) { for (E edge : v_data.child_edges) { if (edge != null) { edges.add(edge); } } } if (edges.isEmpty()) { return Collections.emptySet(); } return Collections.unmodifiableCollection(edges); } /** * @see edu.uci.ics.jung.graph.Hypergraph#getIncidentVertices(java.lang.Object) */ @Override public Collection<V> getIncidentVertices(E edge) { return edge_vpairs.get(edge); } /** * @see edu.uci.ics.jung.graph.Hypergraph#getNeighborCount(java.lang.Object) */ @Override public int getNeighborCount(V vertex) { if (!containsVertex(vertex)) { return 0; } return (vertex.equals(root) ? 0 : 1) + this.getChildCount(vertex); } /** * @see edu.uci.ics.jung.graph.Hypergraph#getNeighbors(java.lang.Object) */ @Override public Collection<V> getNeighbors(V vertex) { if (!containsVertex(vertex)) { return null; } ArrayList<V> vertices = new ArrayList<V>(order + 1); VertexData v_data = vertex_data.get(vertex); if (v_data.parent_edge != null) { vertices.add(edge_vpairs.get(v_data.parent_edge).getFirst()); } if (v_data.child_edges != null) { for (E edge : v_data.child_edges) { if (edge != null) { vertices.add(edge_vpairs.get(edge).getSecond()); } } } if (vertices.isEmpty()) { return Collections.emptySet(); } return Collections.unmodifiableCollection(vertices); } /** * @see edu.uci.ics.jung.graph.Hypergraph#getVertexCount() */ @Override public int getVertexCount() { return vertex_data.size(); } /** * @see edu.uci.ics.jung.graph.Hypergraph#getVertices() */ @Override public Collection<V> getVertices() { return CollectionUtils.unmodifiableCollection(vertex_data.keySet()); } /** * @see edu.uci.ics.jung.graph.Hypergraph#removeEdge(java.lang.Object) */ @Override public boolean removeEdge(E edge) { if (!containsEdge(edge)) { return false; } removeVertex(edge_vpairs.get(edge).getSecond()); edge_vpairs.remove(edge); return true; } /** * @see edu.uci.ics.jung.graph.Hypergraph#removeVertex(java.lang.Object) */ @Override public boolean removeVertex(V vertex) { if (!containsVertex(vertex)) { return false; } // recursively remove all of vertex's children for (V v : getChildren(vertex)) { removeVertex(v); } E parent_edge = getParentEdge(vertex); edge_vpairs.remove(parent_edge); List<E> edges = vertex_data.get(vertex).child_edges; if (edges != null) { for (E edge : edges) { edge_vpairs.remove(edge); } } vertex_data.remove(vertex); return true; } protected class VertexData { List<E> child_edges; E parent_edge; int depth; protected VertexData(E parent_edge, int depth) { this.parent_edge = parent_edge; this.depth = depth; } } @Override public boolean addEdge(E edge, Pair<? extends V> endpoints, EdgeType edgeType) { if (edge == null || endpoints == null) { throw new IllegalArgumentException("inputs must not be null"); } return addEdge(edge, endpoints.getFirst(), endpoints.getSecond(), edgeType); } @Override public OrderedKAryTree<V, E> newInstance() { // TODO Auto-generated method stub Log.debug("implementation needed"); return null; } }