
com.simplaex.bedrock.DirectedGraph Maven / Gradle / Ivy
package com.simplaex.bedrock;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.TreeSet;
import java.util.function.Consumer;
import java.util.function.ToIntFunction;
import static com.simplaex.bedrock.Pair.pair;
public class DirectedGraph extends SimpleDirectedGraph {
private final Object[] vertices;
private final Map verticesToIndicesMap;
DirectedGraph(
final Object[] vertices,
final Map verticesToIndicesMap,
final int numberOfEdges,
final int[][] outgoingEdges) {
super(vertices.length, numberOfEdges, outgoingEdges, null);
this.vertices = vertices;
this.verticesToIndicesMap = verticesToIndicesMap;
}
@SuppressWarnings("unchecked")
@Nonnull
public V vertex(final int index) {
return (V) vertices[index];
}
public int index(@Nonnull final V vertex) {
return verticesToIndicesMap.getOrDefault(vertex, -1);
}
public Seq vertices() {
return Seq.ofArrayZeroCopyInternal(vertices);
}
@SuppressWarnings("unchecked")
public void forEachOutgoingEdge(@Nonnull final V vertex, @Nonnull final Consumer consumer) {
final int index = verticesToIndicesMap.get(vertex);
forEachOutgoing(index, to -> {
consumer.accept((V) vertices[to]);
});
}
@Nonnegative
public int countOutgoingEdges(@Nonnull final V vertex) {
return countOutgoing(verticesToIndicesMap.get(vertex));
}
public boolean hasOutgoingEdges(@Nonnull final V vertex) {
return countOutgoingEdges(vertex) > 0;
}
@SuppressWarnings("unchecked")
public void forEachIncomingEdge(@Nonnull final V vertex, @Nonnull final Consumer consumer) {
final int index = verticesToIndicesMap.get(vertex);
forEachIncoming(index, from -> consumer.accept((V) vertices[from]));
}
@Nonnegative
public int countIncomingEdges(@Nonnull final V vertex) {
return countIncoming(verticesToIndicesMap.get(vertex));
}
public boolean hasIncomingEdges(@Nonnull final V vertex) {
return countIncomingEdges(vertex) > 0;
}
public Seq> edges() {
final SeqBuilder> edgesBuilder = Seq.builder(numberOfEdges);
vertices().forEach(v -> forEachOutgoingEdge(v, v2 -> edgesBuilder.add(pair(v, v2))));
return edgesBuilder.result();
}
@Nonnull
public static DirectedGraph fromEdges(@Nonnull final Seq> edges) {
Objects.requireNonNull(edges, "'edges' must not be null.");
final Map verticesToIndicesMap = new HashMap<>();
final Map> outgoingEdgesMap = new HashMap<>();
final Box.IntBox index = Box.intBox(0);
final ToIntFunction add = vertex -> {
final int ix;
final Integer ixMaybe = verticesToIndicesMap.get(vertex);
if (ixMaybe == null) {
ix = index.getValue();
outgoingEdgesMap.put(ix, new TreeSet<>());
verticesToIndicesMap.put(vertex, ix);
index.inc();
} else {
ix = ixMaybe;
}
return ix;
};
edges.forEach(edge -> {
final int from = add.applyAsInt(edge.fst());
final int to = add.applyAsInt(edge.snd());
outgoingEdgesMap.get(from).add(to);
});
final int numberOfVertices = index.getValue();
final Object[] vertices = new Object[numberOfVertices];
verticesToIndicesMap.forEach((vertex, ix) -> vertices[ix] = vertex);
final int[][] outgoingEdges = new int[numberOfVertices][];
final Box.IntBox numberOfEdges = Box.intBox(0);
outgoingEdgesMap.forEach((from, tos) -> {
final int[] out = new int[tos.size()];
int i = 0;
for (final int to : outgoingEdgesMap.get(from)) {
out[i++] = to;
}
numberOfEdges.add(i);
outgoingEdges[from] = out;
});
return new DirectedGraph<>(
vertices,
verticesToIndicesMap,
numberOfEdges.getValue(),
outgoingEdges
);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy