Initial commit
This adds the initial contents of the repository.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package com.github.btrekkie.connectivity;
|
||||
|
||||
/**
|
||||
* A combining function for taking the augmentations associated with a set of ConnVertices and reducing them to a single
|
||||
* result. The function is a binary operation for combining two values into one. For example, given vertices with
|
||||
* augmentations A1, A2, A3, and A4, the combined result may be obtained by computing
|
||||
* combine(combine(combine(A1, A2), A3), A4). In order for an augmentation result to be meaningful, the combining
|
||||
* function must be commutative, meaning combine(x, y) is equivalent to combine(y, x), and associative, meaning
|
||||
* combine(x, combine(y, z)) is equivalent to combine(combine(x, y), z).
|
||||
*
|
||||
* If a ConnGraph represents a game map, then one example of an augmentation would be the amount of gold accessible from
|
||||
* a certain location. Each vertex would be augmented with the amount of gold in that location, and the combining
|
||||
* function would add the two amounts of gold passed in as arguments. Another example would be the strongest monster
|
||||
* that can reach a particular location. Each vertex with at least one monster would be augmented with a pointer to the
|
||||
* strongest monster at that location, and the combining function would return the stronger of the two monsters passed
|
||||
* in as arguments. A third example would be the number of locations accessible from a given vertex. Each vertex would
|
||||
* be augmented with the number 1, and the combining function would add the two numbers of vertices passed in as
|
||||
* arguments.
|
||||
*
|
||||
* ConnGraph treats two augmentation values X and Y as interchangeable if they are equal, as in
|
||||
* X != null ? X.equals(Y) : Y == null. The same holds for two combined augmentation values, and for one combined
|
||||
* augmentation value and one augmentation value.
|
||||
*
|
||||
* See the comments for ConnGraph.
|
||||
*/
|
||||
public interface Augmentation {
|
||||
/**
|
||||
* Returns the result of combining the specified values into one. Each argument is either the augmentation
|
||||
* information associated with a vertex, or the result of a previous call to "combine".
|
||||
*
|
||||
* Note that a value of null is never passed in to indicate the absence of augmentation information. The fact that
|
||||
* ConnGraph.getVertexAugmentation, for example, may return null when there is no associated augmentation might lead
|
||||
* you to believe that a null argument indicates the absence of augmentation information, but again, it does not. A
|
||||
* null argument can only mean that a vertex is explicitly associated with null augmentation information, due to a
|
||||
* prior call to ConnGraph.setVertexAugmentation(vertex, null), or that the "combine" method previously returned
|
||||
* null.
|
||||
*/
|
||||
public Object combine(Object value1, Object value2);
|
||||
}
|
||||
61
src/main/java/com/github/btrekkie/connectivity/ConnEdge.java
Normal file
61
src/main/java/com/github/btrekkie/connectivity/ConnEdge.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package com.github.btrekkie.connectivity;
|
||||
|
||||
/**
|
||||
* Represents an edge in a ConnGraph, at the level of the edge (i.e. at the lowest level i for which G_i contains the
|
||||
* edge). Every graph edge has exactly one corresponding ConnEdge object, regardless of the number of levels it appears
|
||||
* in. See the comments for the implementation of ConnGraph.
|
||||
*
|
||||
* ConnEdges are stored in the linked lists suggested by EulerTourVertex.graphListHead and
|
||||
* EulerTourVertex.forestListHead. Each ConnEdge is in two linked lists, so care must be taken when traversing the
|
||||
* linked lists. prev1 and next1 are the links for the list starting at vertex1.graphListHead or vertex1.forestListHead,
|
||||
* while prev2 and next2 are the links for vertex2. But the vertex1 and vertex2 fields of a given edge are different
|
||||
* from the vertex1 and vertex2 fields of the linked edges. For example, the edge after next1 is not necessarily
|
||||
* next1.next1. It depends on whether next1.vertex1 is the same as vertex1. If next1.vertex1 == vertex1, then the edge
|
||||
* after next1 is next1.next1, but otherwise, it is next1.next2.
|
||||
*/
|
||||
class ConnEdge {
|
||||
/** The edge's first endpoint (at the same level as the edge). */
|
||||
public EulerTourVertex vertex1;
|
||||
|
||||
/** The edge's second endpoint (at the same level as the edge). */
|
||||
public EulerTourVertex vertex2;
|
||||
|
||||
/**
|
||||
* The EulerTourEdge object describing the edge's presence in an Euler tour tree, at the same level as the edge, or
|
||||
* null if the edge is not in the Euler tour forest F_i.
|
||||
*/
|
||||
public EulerTourEdge eulerTourEdge;
|
||||
|
||||
/**
|
||||
* The edge preceding this in a linked list of same-level edges adjacent to vertex1, if any. The edge is either part
|
||||
* of a list of non-forest edges starting with vertex1.graphListHead, or part of a list of forest edges starting
|
||||
* with vertex1.forestListHead. Note that this list excludes any edges that also appear in lower levels.
|
||||
*/
|
||||
public ConnEdge prev1;
|
||||
|
||||
/**
|
||||
* The edge succeeding this in a linked list of same-level edges adjacent to vertex1, if any. The edge is either
|
||||
* part of a list of non-forest edges starting with vertex1.graphListHead, or part of a list of forest edges
|
||||
* starting with vertex1.forestListHead. Note that this list excludes any edges that also appear in lower levels.
|
||||
*/
|
||||
public ConnEdge next1;
|
||||
|
||||
/**
|
||||
* The edge preceding this in a linked list of same-level edges adjacent to vertex2, if any. The edge is either part
|
||||
* of a list of non-forest edges starting with vertex2.graphListHead, or part of a list of forest edges starting
|
||||
* with vertex2.forestListHead. Note that this list excludes any edges that also appear in lower levels.
|
||||
*/
|
||||
public ConnEdge prev2;
|
||||
|
||||
/**
|
||||
* The edge succeeding this in a linked list of same-level edges adjacent to vertex2, if any. The edge is either
|
||||
* part of a list of non-forest edges starting with vertex2.graphListHead, or part of a list of forest edges
|
||||
* starting with vertex2.forestListHead. Note that this list excludes any edges that also appear in lower levels.
|
||||
*/
|
||||
public ConnEdge next2;
|
||||
|
||||
public ConnEdge(EulerTourVertex vertex1, EulerTourVertex vertex2) {
|
||||
this.vertex1 = vertex1;
|
||||
this.vertex2 = vertex2;
|
||||
}
|
||||
}
|
||||
1183
src/main/java/com/github/btrekkie/connectivity/ConnGraph.java
Normal file
1183
src/main/java/com/github/btrekkie/connectivity/ConnGraph.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
package com.github.btrekkie.connectivity;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/** A vertex in a ConnGraph. See the comments for ConnGraph. */
|
||||
public class ConnVertex {
|
||||
/**
|
||||
* The thread-local random number generator we use by default to set the "hash" field. We could use
|
||||
* ThreadLocalRandom instead, but ThreadLocalRandom isn't available in Java 6.0 and below.
|
||||
*/
|
||||
private static final ThreadLocal<Random> random = new ThreadLocal<Random>() {
|
||||
@Override
|
||||
protected Random initialValue() {
|
||||
return new Random();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A randomly generated integer to use as the return value of hashCode(). ConnGraph relies on random hash codes for
|
||||
* its performance guarantees.
|
||||
*/
|
||||
private final int hash;
|
||||
|
||||
public ConnVertex() {
|
||||
hash = random.get().nextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ConnVertex.
|
||||
* @param random The random number generator to use to produce a random hash code. ConnGraph relies on random hash
|
||||
* codes for its performance guarantees.
|
||||
*/
|
||||
public ConnVertex(Random random) {
|
||||
hash = random.nextInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.github.btrekkie.connectivity;
|
||||
|
||||
/**
|
||||
* The representation of a forest edge in some Euler tour forest F_i at some particular level i. Each forest edge has
|
||||
* one EulerTourEdge object for each level it appears in. See the comments for the implementation of ConnGraph.
|
||||
*/
|
||||
class EulerTourEdge {
|
||||
/**
|
||||
* One of the two visits preceding the edge in the Euler tour, in addition to visit2. (The node is at the same level
|
||||
* as the EulerTourEdge.)
|
||||
*/
|
||||
public final EulerTourNode visit1;
|
||||
|
||||
/**
|
||||
* One of the two visits preceding the edge in the Euler tour, in addition to visit1. (The node is at the same level
|
||||
* as the EulerTourEdge.)
|
||||
*/
|
||||
public final EulerTourNode visit2;
|
||||
|
||||
/**
|
||||
* The representation of this edge in the next-higher level. higherEdge is null if this edge is in the highest
|
||||
* level.
|
||||
*/
|
||||
public EulerTourEdge higherEdge;
|
||||
|
||||
public EulerTourEdge(EulerTourNode visit1, EulerTourNode visit2) {
|
||||
this.visit1 = visit1;
|
||||
this.visit2 = visit2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.github.btrekkie.connectivity;
|
||||
|
||||
import com.github.btrekkie.red_black_node.RedBlackNode;
|
||||
|
||||
/**
|
||||
* A node in an Euler tour tree for ConnGraph (at some particular level i). See the comments for the implementation of
|
||||
* ConnGraph.
|
||||
*/
|
||||
class EulerTourNode extends RedBlackNode<EulerTourNode> {
|
||||
/** The dummy leaf node. */
|
||||
public static final EulerTourNode LEAF = new EulerTourNode(null, null);
|
||||
|
||||
/** The vertex this node visits. */
|
||||
public final EulerTourVertex vertex;
|
||||
|
||||
/** The number of nodes in the subtree rooted at this node. */
|
||||
public int size;
|
||||
|
||||
/**
|
||||
* Whether the subtree rooted at this node contains a node "node" for which
|
||||
* node.vertex.arbitraryNode == node && node.vertex.graphListHead != null.
|
||||
*/
|
||||
public boolean hasGraphEdge;
|
||||
|
||||
/**
|
||||
* Whether the subtree rooted at this node contains a node "node" for which
|
||||
* node.vertex.arbitraryNode == node && node.vertex.forestListHead != null.
|
||||
*/
|
||||
public boolean hasForestEdge;
|
||||
|
||||
/**
|
||||
* The combining function for combining user-provided augmentations. augmentationFunc is null if this node is not in
|
||||
* the highest level.
|
||||
*/
|
||||
public final Augmentation augmentationFunc;
|
||||
|
||||
/**
|
||||
* The combined augmentation for the subtree rooted at this node. This is the result of combining the augmentation
|
||||
* values node.vertex.augmentation for all nodes "node" in the subtree rooted at this node for which
|
||||
* node.vertex.arbitraryVisit == node, using augmentationFunc. This is null if hasAugmentation is false.
|
||||
*/
|
||||
public Object augmentation;
|
||||
|
||||
/**
|
||||
* Whether the subtree rooted at this node contains at least one augmentation value. This indicates whether there is
|
||||
* some node "node" in the subtree rooted at this node for which node.vertex.hasAugmentation is true and
|
||||
* node.vertex.arbitraryVisit == node.
|
||||
*/
|
||||
public boolean hasAugmentation;
|
||||
|
||||
public EulerTourNode(EulerTourVertex vertex, Augmentation augmentationFunc) {
|
||||
this.vertex = vertex;
|
||||
this.augmentationFunc = augmentationFunc;
|
||||
}
|
||||
|
||||
/** Like augment(), but only updates the augmentation fields hasGraphEdge and hasForestEdge. */
|
||||
public boolean augmentFlags() {
|
||||
boolean newHasGraphEdge =
|
||||
left.hasGraphEdge || right.hasGraphEdge || (vertex.arbitraryVisit == this && vertex.graphListHead != null);
|
||||
boolean newHasForestEdge =
|
||||
left.hasForestEdge || right.hasForestEdge ||
|
||||
(vertex.arbitraryVisit == this && vertex.forestListHead != null);
|
||||
if (newHasGraphEdge == hasGraphEdge && newHasForestEdge == hasForestEdge) {
|
||||
return false;
|
||||
} else {
|
||||
hasGraphEdge = newHasGraphEdge;
|
||||
hasForestEdge = newHasForestEdge;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean augment() {
|
||||
int newSize = left.size + right.size + 1;
|
||||
boolean augmentedFlags = augmentFlags();
|
||||
|
||||
Object newAugmentation = null;
|
||||
boolean newHasAugmentation = false;
|
||||
if (augmentationFunc != null) {
|
||||
if (left.hasAugmentation) {
|
||||
newAugmentation = left.augmentation;
|
||||
newHasAugmentation = true;
|
||||
}
|
||||
if (vertex.hasAugmentation && vertex.arbitraryVisit == this) {
|
||||
if (newHasAugmentation) {
|
||||
newAugmentation = augmentationFunc.combine(newAugmentation, vertex.augmentation);
|
||||
} else {
|
||||
newAugmentation = vertex.augmentation;
|
||||
newHasAugmentation = true;
|
||||
}
|
||||
}
|
||||
if (right.hasAugmentation) {
|
||||
if (newHasAugmentation) {
|
||||
newAugmentation = augmentationFunc.combine(newAugmentation, right.augmentation);
|
||||
} else {
|
||||
newAugmentation = right.augmentation;
|
||||
newHasAugmentation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newSize == size && !augmentedFlags && hasAugmentation == newHasAugmentation &&
|
||||
(newAugmentation != null ? newAugmentation.equals(augmentation) : augmentation == null)) {
|
||||
return false;
|
||||
} else {
|
||||
size = newSize;
|
||||
augmentation = newAugmentation;
|
||||
hasAugmentation = newHasAugmentation;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.github.btrekkie.connectivity;
|
||||
|
||||
/**
|
||||
* The representation of a ConnVertex at some particular level i. Each vertex has one EulerTourVertex object for each
|
||||
* level it appears in. Note that different vertices may appear in different numbers of levels, as EulerTourVertex
|
||||
* objects are only created for lower levels as needed. See the comments for the implementation of ConnGraph.
|
||||
*/
|
||||
class EulerTourVertex {
|
||||
/**
|
||||
* The representation of this edge in the next-lower level. lowerVertex is null if this is the lowest-level
|
||||
* representation of this vertex.
|
||||
*/
|
||||
public EulerTourVertex lowerVertex;
|
||||
|
||||
/**
|
||||
* The representation of this edge in the next-higher level. This is null if this vertex is in the highest level.
|
||||
*/
|
||||
public EulerTourVertex higherVertex;
|
||||
|
||||
/**
|
||||
* An arbitrarily selected visit to the vertex in the Euler tour tree that contains it (at the same level as this).
|
||||
*/
|
||||
public EulerTourNode arbitraryVisit;
|
||||
|
||||
/**
|
||||
* The first edge in the linked list of level-i edges that are adjacent to the vertex in G_i, but are not in the
|
||||
* Euler tour forest F_i, where i is the level of the vertex. Note that this list excludes any edges that also
|
||||
* appear in lower levels.
|
||||
*/
|
||||
public ConnEdge graphListHead;
|
||||
|
||||
/**
|
||||
* The first edge in the linked list of level-i edges adjacent to the vertex that are in F_i, where i is the level
|
||||
* of the vertex. Note that this list excludes any edges that also appear in lower levels.
|
||||
*/
|
||||
public ConnEdge forestListHead;
|
||||
|
||||
/** The augmentation associated with this vertex, if any. This is null instead if higherVertex != null. */
|
||||
public Object augmentation;
|
||||
|
||||
/** Whether there is any augmentation associated with this vertex. This is false instead if higherVertex != null. */
|
||||
public boolean hasAugmentation;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.github.btrekkie.connectivity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Describes a ConnVertex, with respect to a particular ConnGraph. There is exactly one VertexInfo object per vertex in
|
||||
* a given graph, regardless of how many levels the vertex is in. See the comments for the implementation of ConnGraph.
|
||||
*/
|
||||
class VertexInfo {
|
||||
/** The representation of the vertex in the highest level. */
|
||||
public EulerTourVertex vertex;
|
||||
|
||||
/**
|
||||
* A map from each ConnVertex adjacent to this vertex to the ConnEdge object for the edge connecting it to this
|
||||
* vertex. Lookups take O(1) expected time and O(log N / log log N) time with high probability, because "edges" is a
|
||||
* HashMap, and ConnVertex.hashCode() returns a random integer.
|
||||
*/
|
||||
public Map<ConnVertex, ConnEdge> edges = new HashMap<ConnVertex, ConnEdge>();
|
||||
|
||||
/**
|
||||
* The maximum number of entries in "edges" since the last time we "rebuilt" that field. When the number of edges
|
||||
* drops sufficiently, we rebuild "edges" by copying its contents to a new HashMap. We do this to ensure that
|
||||
* "edges" uses O(K) space, where K is the number of vertices adjacent to this. (The capacity of a HashMap is not
|
||||
* automatically reduced as the number of entries decreases, so we have to limit space usage manually.)
|
||||
*/
|
||||
public int maxEdgeCountSinceRebuild;
|
||||
|
||||
public VertexInfo(EulerTourVertex vertex) {
|
||||
this.vertex = vertex;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user