Skip to content

Commit

Permalink
Refactor graph module.
Browse files Browse the repository at this point in the history
  • Loading branch information
wrandelshofer committed Oct 13, 2024
1 parent e45e526 commit 02bc66b
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ public void addArrowAsInt(final int v, final int u, final int data) {
}

/**
* Adds the arrow if its absent, updates the arrow data if the arrow is
* present. Does nothing if there is already an arrow.
* Adds the arrow if it is absent, updates the arrow data if the arrow is
* present.
*
* @param v index of vertex 'v'
* @param u index of vertex 'u'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public interface MutableDirectedGraph<V, A> extends DirectedGraph<V, A> {
void removeVertex(V v);

/**
* Adds an arrow from vertex v to vertex u.
* Adds a directed arrow from vertex v to vertex u.
* <p>
* This method adds additional an arrow if the arrow is already in the graph.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.jhotdraw8.graph;

import java.util.NoSuchElementException;

/**
* FIXME ensure that the methods do not clash with {@link MutableIndexedBidiGraph}
*/
public interface MutableIndexedDirectedGraph extends IndexedDirectedGraph {
/**
* Adds an arrow from vertex 'v' to vertex 'u'.
*
* @param v index of vertex 'v'
* @param u index of vertex 'u'
*/
int addArrowAsInt(int v, int u);


/**
* Adds a vertex to the graph.
*/
void addVertexAsInt();


/**
* Removes an arrow from vertex 'v' to vertex 'u'
*
* @param v index of vertex 'v'
* @param u index of vertex 'u'
* @throws NoSuchElementException if there is no such arrow
*/
default void removeArrowAsInt(int v, int u) {
removeNextAsInt(v, findIndexOfNextAsInt(v, u));
}

/**
* Removes the i-th arrow starting at vertex 'v'
*
* @param v index of vertex 'v'
* @param index the index of the arrow starting at 'v'
* @throws NoSuchElementException if there is no such arrow
*/
int removeNextAsInt(int v, int index);


/**
* Removes vertex 'v'
*
* @param v index of vertex 'v'
*/
void removeVertexAsInt(int v);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@


/**
* SimpleMutableDirectedGraph.
* Simple implementation of the {@link MutableDirectedGraph} interface.
*
* @param <V> the vertex data type
* @param <A> the arrow data type
* @author Werner Randelshofer
*/
public class SimpleMutableDirectedGraph<V, A> extends AbstractDirectedGraphBuilder
public class SimpleMutableDirectedGraph<V, A>
implements MutableDirectedGraph<V, A>, AttributedIndexedDirectedGraph<V, A> {

private static final Object TOMBSTONE_OBJECT = new Object();


private final SimpleMutableIndexedDirectedGraph g;
/**
* Maps a vertex to a vertex index.
*/
Expand Down Expand Up @@ -74,13 +74,13 @@ public SimpleMutableDirectedGraph(int vertexCapacity, int arrowCapacity) {
* @param identityMap whether to use an identity hash map for storing the vertices
*/
public SimpleMutableDirectedGraph(int vertexCapacity, int arrowCapacity, boolean identityMap) {
super(vertexCapacity, arrowCapacity);
this.g = new SimpleMutableIndexedDirectedGraph(vertexCapacity, arrowCapacity);
this.vertexMap = identityMap ? new IdentityHashMap<>(vertexCapacity) : new HashMap<>(vertexCapacity);
this.vertices = new ArrayList<>(vertexCapacity);
this.arrows = new ArrayList<>(arrowCapacity);
this.addVertexIfAbsent = k -> {
vertices.add(k);
buildAddVertex();
g.addVertexAsInt();
return vertices.size() - 1;
};
}
Expand Down Expand Up @@ -108,14 +108,14 @@ public SimpleMutableDirectedGraph(DirectedGraph<V, A> graph) {
public <VV, AA> SimpleMutableDirectedGraph(DirectedGraph<VV, AA> graph,
Function<VV, V> vertexMapper,
Function3<VV, VV, AA, A> arrowMapper) {
super(graph.getVertexCount(), graph.getArrowCount());
this.g = new SimpleMutableIndexedDirectedGraph(graph.getVertexCount(), graph.getArrowCount());
final int vcount = graph.getVertexCount();
this.vertexMap = new HashMap<>(vcount);
this.vertices = new ArrayList<>(vcount);
this.arrows = new ArrayList<>(graph.getArrowCount());
this.addVertexIfAbsent = k -> {
vertices.add(k);
buildAddVertex();
g.addVertexAsInt();
return vertices.size() - 1;
};

Expand All @@ -132,20 +132,14 @@ public <VV, AA> SimpleMutableDirectedGraph(DirectedGraph<VV, AA> graph,
}
}

/**
* Adds a directed arrow from va to vb.
*
* @param va vertex a
* @param vb vertex b
* @param arrow the arrow
*/

@Override
public void addArrow(V va, V vb, @Nullable A arrow) {
Objects.requireNonNull(va, "va");
Objects.requireNonNull(vb, "vb");
int a = vertexMap.get(va);
int b = vertexMap.get(vb);
int arrowIndex = super.buildAddArrow(a, b);
int arrowIndex = g.addArrowAsInt(a, b);
if (arrowIndex == arrows.size()) {
arrows.add(arrow);
} else {
Expand All @@ -162,7 +156,7 @@ public void removeArrow(V v, V u, @Nullable A a) {
for (Enumerator.OfInt it = nextVerticesEnumerator(vidx); it.moveNext(); ) {
int widx = it.currentAsInt();
if (uidx == widx && Objects.equals(a, this.getNextArrow(vidx, index))) {
int indexOfRemovedArrow = buildRemoveArrowAt(vertexMap.get(v), index);
int indexOfRemovedArrow = g.removeNextAsInt(vertexMap.get(v), index);
arrows.set(indexOfRemovedArrow, TOMBSTONE_OBJECT);
return;
}
Expand All @@ -177,7 +171,7 @@ public void removeArrow(V v, V u) {
for (Enumerator.OfInt it = nextVerticesEnumerator(vidx); it.moveNext(); ) {
int uidx = it.currentAsInt();
if (u.equals(vertices.get(uidx))) {
int indexOfRemovedArrow = buildRemoveArrowAt(vertexMap.get(v), index);
int indexOfRemovedArrow = g.removeNextAsInt(vertexMap.get(v), index);
arrows.set(indexOfRemovedArrow, TOMBSTONE_OBJECT);
return;
}
Expand All @@ -187,7 +181,7 @@ public void removeArrow(V v, V u) {

@Override
public void removeNext(V v, int k) {
int indexOfRemovedArrow = buildRemoveArrowAt(vertexMap.get(v), k);
int indexOfRemovedArrow = g.removeNextAsInt(vertexMap.get(v), k);
arrows.set(indexOfRemovedArrow, TOMBSTONE_OBJECT);
}

Expand Down Expand Up @@ -222,7 +216,7 @@ public void addVertex(V v) {
*/
public void addVertex(V v, int vidx) {
Objects.requireNonNull(v, "v");
buildInsertVertexAt(vidx);
g.insertVertexAt(vidx);
vertices.add(vidx, v);
for (Map.Entry<V, Integer> entry : vertexMap.entrySet()) {
Integer uidx = entry.getValue();
Expand All @@ -242,20 +236,20 @@ public void removeVertex(V v) {
int vidx = vidxBox;
// Remove all outgoing vertices
for (int i = getNextCount(vidx) - 1; i >= 0; i--) {
int indexOfRemovedArrow = buildRemoveArrowAt(vidx, i);
int indexOfRemovedArrow = g.removeNextAsInt(vidx, i);
arrows.set(indexOfRemovedArrow, TOMBSTONE_OBJECT);
}
// Remove all incoming vertices
for (int uidx = 0, n = getVertexCount(); uidx < n; uidx++) {
for (int i = getNextCount(uidx) - 1; i >= 0; i--) {
int next = getNextAsInt(uidx, i);
if (next == vidx) {
int indexOfRemovedArrow = buildRemoveArrowAt(uidx, i);
int indexOfRemovedArrow = g.removeNextAsInt(uidx, i);
arrows.set(indexOfRemovedArrow, TOMBSTONE_OBJECT);
}
}
}
buildRemoveVertexAfterArrowsHaveBeenRemoved(vidx);
g.removeVertexAfterArrowsHaveBeenRemoved(vidx);
vertices.remove(vidx);
for (Map.Entry<V, Integer> entry : vertexMap.entrySet()) {
Integer uidx = entry.getValue();
Expand All @@ -272,17 +266,16 @@ public void removeVertex(V v) {
private final Function<V, Integer> addVertexIfAbsent;


@Override
public void clear() {
super.clear();
g.clear();
vertexMap.clear();
vertices.clear();
arrows.clear();
}

@Override
public A getNextArrow(V v, int index) {
int arrowId = getNextArrowIndex(getVertexIndex(v), index);
int arrowId = g.getNextArrowIndex(getVertexIndex(v), index);
@SuppressWarnings("unchecked")
A a = (A) arrows.get(arrowId);
return a;
Expand All @@ -298,6 +291,21 @@ public int getNextCount(V v) {
return getNextCount(getVertexIndex(v));
}

@Override
public int getVertexCount() {
return g.getVertexCount();
}

@Override
public int getArrowCount() {
return g.getArrowCount();
}

@Override
public int getNextAsInt(int v, int i) {
return g.getNextAsInt(v, i);
}

@Override
public V getVertex(int vi) {
if (vertices.get(vi) == null) {
Expand Down Expand Up @@ -329,17 +337,28 @@ public A getArrow(int index) {
@Override
@SuppressWarnings("unchecked")
public A getNextArrow(int v, int index) {
int arrowId = getNextArrowIndex(v, index);
int arrowId = g.getNextArrowIndex(v, index);
return (A) arrows.get(arrowId);
}


@Override
public int getNextArrowAsInt(int v, int i) {
return getNextAsInt(v, i);
}

@Override
public int getNextCount(int v) {
return g.getNextCount(v);
}

@Override
public Set<V> getVertices() {
return new SetFacade<>(vertices::iterator, vertices::spliterator, vertices::size, vertices::contains, null, null, null);
}


public void setOrdered(boolean b) {
g.setOrdered(b);
}
}
Loading

0 comments on commit 02bc66b

Please sign in to comment.