Skip to content

Commit

Permalink
GraphFactory: newImmutableCopyOf, uses the graphs hints
Browse files Browse the repository at this point in the history
  • Loading branch information
barakugav committed Dec 23, 2023
1 parent d3d7d62 commit 91ae8c3
Show file tree
Hide file tree
Showing 26 changed files with 432 additions and 167 deletions.
23 changes: 3 additions & 20 deletions jgalgo-core/src/main/java/com/jgalgo/graph/Graph.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package com.jgalgo.graph;

import java.util.Collection;
import java.util.Optional;
import java.util.Set;

/**
Expand Down Expand Up @@ -957,7 +956,7 @@ default <T, WeightsT extends Weights<E, T>> WeightsT addEdgesWeights(String key,
* <p>
* An identical copy of this graph will be created, with the same vertices, edges, capabilities (inclusive) such as
* self edges and parallel edges support, without copying the vertices/edges weights. The returned graph will always
* be modifiable, with no side affects on the original graph.
* be mutable, with no side affects on the original graph.
*
* @return an identical copy of this graph, with the same vertices and edges, without this graph weights
*/
Expand All @@ -971,7 +970,7 @@ default Graph<V, E> copy() {
* <p>
* An identical copy of this graph will be created, with the same vertices, edges, capabilities (inclusive) such as
* self edges and parallel edges support, with/without copying the vertices/edges weights. The returned graph will
* always be modifiable, with no side affects on the original graph.
* always be mutable, with no side affects on the original graph.
*
* <p>
* Note that although {@code g.equals(g.copy())} is always {@code true} if both {@code copyVerticesWeights}
Expand Down Expand Up @@ -1037,23 +1036,7 @@ default Graph<V, E> immutableCopy() {
* graph weights
*/
default Graph<V, E> immutableCopy(boolean copyVerticesWeights, boolean copyEdgesWeights) {
IndexIdMap<V> viMap = indexGraphVerticesMap();
IndexIdMap<E> eiMap = indexGraphEdgesMap();
/* create a new factory with no vertex and edge builders */
GraphFactoryImpl<V, E> factory = new GraphFactoryImpl<>(isDirected());
factory.setVertexBuilder(null);
factory.setEdgeBuilder(null);
if (isDirected()) {
IndexGraphBuilder.ReIndexedGraph reIndexedGraph =
GraphCsrDirectedReindexed.newInstance(indexGraph(), copyVerticesWeights, copyEdgesWeights);
IndexGraph iGraph = reIndexedGraph.graph();
Optional<IndexGraphBuilder.ReIndexingMap> vReIndexing = reIndexedGraph.verticesReIndexing();
Optional<IndexGraphBuilder.ReIndexingMap> eReIndexing = reIndexedGraph.edgesReIndexing();
return new GraphImpl<>(factory, iGraph, viMap, eiMap, vReIndexing.orElse(null), eReIndexing.orElse(null));
} else {
IndexGraph iGraph = new GraphCsrUndirected(indexGraph(), copyVerticesWeights, copyEdgesWeights);
return new GraphImpl<>(factory, iGraph, viMap, eiMap, null, null);
}
return Graphs.immutableCopy(this, copyVerticesWeights, copyEdgesWeights);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ class GraphBuilderImpl<V, E> implements GraphBuilder<V, E> {
boolean copyEdgesWeights) {
this.factory = factory;
this.ibuilder = factory.indexFactory.newBuilderCopyOf(g.indexGraph(), copyVerticesWeights, copyEdgesWeights);
viMap = IndexIdMapImpl.newCopyOf(g.indexGraphVerticesMap(), null, ibuilder.vertices(), false, false);
eiMap = IndexIdMapImpl.newCopyOf(g.indexGraphEdgesMap(), null, ibuilder.edges(), true, false);
viMap = IndexIdMapImpl.newCopyOf(g.indexGraphVerticesMap(), Optional.empty(), ibuilder.vertices(), false,
false);
eiMap = IndexIdMapImpl.newCopyOf(g.indexGraphEdgesMap(), Optional.empty(), ibuilder.edges(), true, false);
resetVertexAndEdgeBuilders();
}

Expand Down Expand Up @@ -227,7 +228,7 @@ private Graph<V, E> buildFromReIndexed(IndexGraphBuilder.ReIndexedGraph reIndexe
IndexGraph iGraph = reIndexedGraph.graph();
Optional<IndexGraphBuilder.ReIndexingMap> vReIndexing = reIndexedGraph.verticesReIndexing();
Optional<IndexGraphBuilder.ReIndexingMap> eReIndexing = reIndexedGraph.edgesReIndexing();
return new GraphImpl<>(factory, iGraph, viMap, eiMap, vReIndexing.orElse(null), eReIndexing.orElse(null));
return new GraphImpl<>(factory, iGraph, viMap, eiMap, vReIndexing, eReIndexing);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
*/
package com.jgalgo.graph;

import java.util.Optional;

import com.jgalgo.internal.util.JGAlgoUtils.Variant2;

abstract class GraphCsrAbstractUnindexed extends GraphCsrBase {

final int[] edgesOut;

GraphCsrAbstractUnindexed(boolean directed, IndexGraphBuilderImpl builder, BuilderProcessEdges processEdges) {
super(directed, Variant2.ofB(builder), processEdges, null, true, true);
super(directed, Variant2.ofB(builder), processEdges, Optional.empty(), true, true);
edgesOut = processEdges.edgesOut;

for (int m = builder.edges.size(), e = 0; e < m; e++)
Expand Down
9 changes: 5 additions & 4 deletions jgalgo-core/src/main/java/com/jgalgo/graph/GraphCsrBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ abstract class GraphCsrBase extends IndexGraphBase implements ImmutableGraph {
private boolean containsParallelEdgesValid;

GraphCsrBase(boolean directed, Variant2<IndexGraph, IndexGraphBuilderImpl> graphOrBuilder,
BuilderProcessEdges processEdges, IndexGraphBuilder.ReIndexingMap edgesReIndexing,
BuilderProcessEdges processEdges, Optional<IndexGraphBuilder.ReIndexingMap> edgesReIndexing,
boolean copyVerticesWeights, boolean copyEdgesWeights) {
super(graphOrBuilder, false);
final int n = verticesNum(graphOrBuilder);
Expand Down Expand Up @@ -83,7 +83,7 @@ abstract class GraphCsrBase extends IndexGraphBase implements ImmutableGraph {
}

if (copyEdgesWeights && inputCsrGraph.isPresent()) {
assert edgesReIndexing == null;
assert edgesReIndexing.isEmpty();
edgesUserWeights = inputCsrGraph.get().edgesUserWeights;

} else if (copyEdgesWeights) {
Expand All @@ -94,12 +94,13 @@ abstract class GraphCsrBase extends IndexGraphBase implements ImmutableGraph {

WeightsImpl.IndexImmutable.Builder edgesUserWeightsBuilder =
new WeightsImpl.IndexImmutable.Builder(edges, true);
if (edgesReIndexing == null) {
if (edgesReIndexing.isEmpty()) {
for (String key : edgesWeightsKeys)
edgesUserWeightsBuilder.copyAndAddWeights(key, getWeights.apply(key));
} else {
for (String key : edgesWeightsKeys)
edgesUserWeightsBuilder.copyAndAddWeightsReindexed(key, getWeights.apply(key), edgesReIndexing);
edgesUserWeightsBuilder.copyAndAddWeightsReindexed(key, getWeights.apply(key),
edgesReIndexing.get());
}
edgesUserWeights = edgesUserWeightsBuilder.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ class GraphCsrDirectedReindexed extends GraphCsrBase {
private final int[] edgesInBegin;

private GraphCsrDirectedReindexed(Variant2<IndexGraph, IndexGraphBuilderImpl> graphOrBuilder,
BuilderProcessEdgesDirected processEdges, IndexGraphBuilder.ReIndexingMap edgesReIndexing,
BuilderProcessEdgesDirected processEdges, Optional<IndexGraphBuilder.ReIndexingMap> edgesReIndexing,
boolean copyVerticesWeights, boolean copyEdgesWeights) {
super(true, graphOrBuilder, processEdges, edgesReIndexing, copyVerticesWeights, copyEdgesWeights);
final int n = verticesNum(graphOrBuilder);
final int m = edgesNum(graphOrBuilder);

if (graphOrBuilder.contains(IndexGraph.class)
&& graphOrBuilder.get(IndexGraph.class) instanceof GraphCsrDirectedReindexed) {
assert edgesReIndexing == null;
assert edgesReIndexing.isEmpty();
GraphCsrDirectedReindexed g = (GraphCsrDirectedReindexed) graphOrBuilder.get(IndexGraph.class);
edgesIn = g.edgesIn;
edgesInBegin = g.edgesInBegin;
Expand All @@ -46,10 +46,10 @@ private GraphCsrDirectedReindexed(Variant2<IndexGraph, IndexGraphBuilderImpl> gr
assert edgesIn.length == m;
assert edgesInBegin.length == n + 1;

assert edgesReIndexing != null;
IndexGraphBuilder.ReIndexingMap edgesReIndexing0 = edgesReIndexing.get();
for (int eIdx = 0; eIdx < m; eIdx++) {
int eOrig = edgesIn[eIdx];
int eCsr = edgesReIndexing.origToReIndexed(eOrig);
int eCsr = edgesReIndexing0.origToReIndexed(eOrig);
edgesIn[eIdx] = eCsr;
}

Expand All @@ -58,15 +58,15 @@ private GraphCsrDirectedReindexed(Variant2<IndexGraph, IndexGraphBuilderImpl> gr
assert g.isDirected();

for (int eCsr = 0; eCsr < m; eCsr++) {
int eOrig = edgesReIndexing.reIndexedToOrig(eCsr);
int eOrig = edgesReIndexing0.reIndexedToOrig(eCsr);
setEndpoints(eCsr, g.edgeSource(eOrig), g.edgeTarget(eOrig));
}
} else {
IndexGraphBuilderImpl builder = graphOrBuilder.get(IndexGraphBuilderImpl.class);
assert builder.isDirected();

for (int eCsr = 0; eCsr < m; eCsr++) {
int eOrig = edgesReIndexing.reIndexedToOrig(eCsr);
int eOrig = edgesReIndexing0.reIndexedToOrig(eCsr);
setEndpoints(eCsr, builder.edgeSource(eOrig), builder.edgeTarget(eOrig));
}
}
Expand Down Expand Up @@ -94,20 +94,20 @@ private static IndexGraphBuilder.ReIndexedGraph newInstance(
GraphCsrBase.BuilderProcessEdgesDirected processEdges =
GraphCsrBase.BuilderProcessEdgesDirected.valueOf(graphOrBuilder);

IndexGraphBuilder.ReIndexingMap edgesReIndexing = null;
Optional<IndexGraphBuilder.ReIndexingMap> edgesReIndexing = Optional.empty();
if (!graphOrBuilder.contains(IndexGraph.class)
|| !(graphOrBuilder.get(IndexGraph.class) instanceof GraphCsrDirectedReindexed)) {
final int m = edgesNum(graphOrBuilder);
int[] edgesCsrToOrig = processEdges.edgesOut;
int[] edgesOrigToCsr = new int[m];
for (int eCsr = 0; eCsr < m; eCsr++)
edgesOrigToCsr[edgesCsrToOrig[eCsr]] = eCsr;
edgesReIndexing = new IndexGraphBuilderImpl.ReIndexingMapImpl(edgesOrigToCsr, edgesCsrToOrig);
edgesReIndexing = Optional.of(new IndexGraphBuilderImpl.ReIndexingMapImpl(edgesOrigToCsr, edgesCsrToOrig));
}

GraphCsrDirectedReindexed g = new GraphCsrDirectedReindexed(graphOrBuilder, processEdges, edgesReIndexing,
copyVerticesWeights, copyEdgesWeights);
return new IndexGraphBuilderImpl.ReIndexedGraphImpl(g, Optional.empty(), Optional.ofNullable(edgesReIndexing));
return new IndexGraphBuilderImpl.ReIndexedGraphImpl(g, Optional.empty(), edgesReIndexing);
}

@Override
Expand Down
69 changes: 61 additions & 8 deletions jgalgo-core/src/main/java/com/jgalgo/graph/GraphFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@ public interface GraphFactory<V, E> {
*
* <p>
* An identical copy of the given graph will be created, with the same vertices and edges, without copying the
* vertices/edges weights. The returned Graph will always be modifiable, with no side affects on the original graph.
* vertices/edges weights. The returned Graph will always be mutable, with no side affects on the original graph.
*
* <p>
* Differing from {@link Graph#copy()}, the capabilities of the new graph are determined by the factory
* configuration, rather than copied from the given graph. Note for example that if the factory chooses to use an
* implementation that does not (have to) support self edges (if {@link #allowSelfEdges(boolean)} was not called
* with {@code true}), attempting to create a copy of a graph that does contains self edges will result in an
* exception.
* implementation that does not support self edges (if {@link #allowSelfEdges(boolean)} was not called with
* {@code true}), attempting to create a copy of a graph that does contains self edges will result in an exception.
*
* <p>
* For an immutable copy of a graph, see {@link #newImmutableCopyOf(Graph, boolean, boolean)}.
*
* @param g the original graph to copy
* @return an identical copy of the given graph, with the same vertices and edges, without the original graph
Expand All @@ -74,14 +76,16 @@ default Graph<V, E> newCopyOf(Graph<V, E> g) {
*
* <p>
* An identical copy of the given graph will be created, with the same vertices and edges, with/without copying the
* vertices/edges weights. The returned Graph will always be modifiable, with no side affects on the original graph.
* vertices/edges weights. The returned Graph will always be mutable, with no side affects on the original graph.
*
* <p>
* Differing from {@link Graph#copy(boolean, boolean)}, the capabilities of the new graph are determined by the
* factory configuration, rather than copied from the given graph. Note for example that if the factory chooses to
* use an implementation that does not (have to) support self edges (if {@link #allowSelfEdges(boolean)} was not
* called with {@code true}), attempting to create a copy of a graph that does contains self edges will result in an
* exception.
* use an implementation that does not support self edges (if {@link #allowSelfEdges(boolean)} was not called with
* {@code true}), attempting to create a copy of a graph that does contains self edges will result in an exception.
*
* <p>
* For an immutable copy of a graph, see {@link #newImmutableCopyOf(Graph, boolean, boolean)}.
*
* @param g the original graph to copy
* @param copyVerticesWeights if {@code true}, the weights of the vertices will be copied to the new graph
Expand All @@ -91,6 +95,55 @@ default Graph<V, E> newCopyOf(Graph<V, E> g) {
*/
Graph<V, E> newCopyOf(Graph<V, E> g, boolean copyVerticesWeights, boolean copyEdgesWeights);

/**
* Create a new immutable copy of a given graph, with the same vertices and edges, without copying weights.
*
* <p>
* An identical copy of the given graph will be created, with the same vertices and edges, without copying the
* vertices/edges weights. The returned Graph will be immutable, with no side affects on the original graph.
*
* <p>
* Differing from {@link Graph#immutableCopy()}, the capabilities of the new graph are determined by the factory
* configuration, rather than copied from the given graph. Note for example that if the factory chooses to use an
* implementation that does not support self edges (if {@link #allowSelfEdges(boolean)} was not called with
* {@code true}), attempting to create a copy of a graph that does contains self edges will result in an exception.
*
* <p>
* For a mutable copy of a graph, see {@link #newCopyOf(Graph, boolean, boolean)}.
*
* @param g the original graph to copy
* @return an identical immutable copy of the given graph, with the same vertices and edges, without the original
* graph weights
*/
default Graph<V, E> newImmutableCopyOf(Graph<V, E> g) {
return newImmutableCopyOf(g, false, false);
}

/**
* Create a new immutable copy of a given graph, with the same vertices and edges, with/without copying weights.
*
* <p>
* An identical copy of the given graph will be created, with the same vertices and edges, with/without copying the
* vertices/edges weights. The returned Graph will be immutable, with no side affects on the original graph.
*
* <p>
* Differing from {@link Graph#immutableCopy(boolean, boolean)}, the capabilities of the new graph are determined by
* the factory configuration, rather than copied from the given graph. Note for example that if the factory chooses
* to use an implementation that does not support self edges (if {@link #allowSelfEdges(boolean)} was not called
* with {@code true}), attempting to create a copy of a graph that does contains self edges will result in an
* exception.
*
* <p>
* For a mutable copy of a graph, see {@link #newCopyOf(Graph, boolean, boolean)}.
*
* @param g the original graph to copy
* @param copyVerticesWeights if {@code true}, the weights of the vertices will be copied to the new graph
* @param copyEdgesWeights if {@code true}, the weights of the edges will be copied to the new graph
* @return an identical immutable copy of the given graph, with the same vertices and edges,
* without the original graph weights
*/
Graph<V, E> newImmutableCopyOf(Graph<V, E> g, boolean copyVerticesWeights, boolean copyEdgesWeights);

/**
* Create a new graph builder with the factory parameters.
*
Expand Down
18 changes: 17 additions & 1 deletion jgalgo-core/src/main/java/com/jgalgo/graph/GraphFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.jgalgo.graph;

import java.util.Optional;
import java.util.function.Supplier;

class GraphFactoryImpl<V, E> implements GraphFactory<V, E> {
Expand All @@ -34,7 +35,22 @@ public Graph<V, E> newGraph() {

@Override
public Graph<V, E> newCopyOf(Graph<V, E> g, boolean copyVerticesWeights, boolean copyEdgesWeights) {
return new GraphImpl<>(this, g, copyVerticesWeights, copyEdgesWeights);
IndexGraph ig = indexFactory.newCopyOf(g.indexGraph(), copyVerticesWeights, copyEdgesWeights);
IndexIdMap<V> viMap = g.indexGraphVerticesMap();
IndexIdMap<E> eiMap = g.indexGraphEdgesMap();
return new GraphImpl<>(this, ig, viMap, eiMap, Optional.empty(), Optional.empty());
}

@Override
public Graph<V, E> newImmutableCopyOf(Graph<V, E> g, boolean copyVerticesWeights, boolean copyEdgesWeights) {
IndexGraphBuilder.ReIndexedGraph reIndexedGraph = indexFactory.immutableImpl()
.newCopyOfWithReIndex(g.indexGraph(), true, true, copyVerticesWeights, copyEdgesWeights);
IndexIdMap<V> viMap = g.indexGraphVerticesMap();
IndexIdMap<E> eiMap = g.indexGraphEdgesMap();
IndexGraph iGraph = reIndexedGraph.graph();
Optional<IndexGraphBuilder.ReIndexingMap> vReIndexing = reIndexedGraph.verticesReIndexing();
Optional<IndexGraphBuilder.ReIndexingMap> eReIndexing = reIndexedGraph.edgesReIndexing();
return new GraphImpl<>(this, iGraph, viMap, eiMap, vReIndexing, eReIndexing);
}

@Override
Expand Down
10 changes: 3 additions & 7 deletions jgalgo-core/src/main/java/com/jgalgo/graph/GraphImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import com.jgalgo.graph.Graphs.ImmutableGraph;
import it.unimi.dsi.fastutil.ints.AbstractIntSet;
Expand All @@ -46,7 +47,8 @@ class GraphImpl<V, E> extends AbstractGraph<V, E> {
}

GraphImpl(GraphFactoryImpl<V, E> factory, IndexGraph indexGraph, IndexIdMap<V> viMap, IndexIdMap<E> eiMap,
IndexGraphBuilder.ReIndexingMap vReIndexing, IndexGraphBuilder.ReIndexingMap eReIndexing) {
Optional<IndexGraphBuilder.ReIndexingMap> vReIndexing,
Optional<IndexGraphBuilder.ReIndexingMap> eReIndexing) {
this.indexGraph = Objects.requireNonNull(indexGraph);
boolean immutable = this.indexGraph instanceof ImmutableGraph;
this.viMap = IndexIdMapImpl.newCopyOf(viMap, vReIndexing, this.indexGraph.vertices(), false, immutable);
Expand All @@ -59,12 +61,6 @@ class GraphImpl<V, E> extends AbstractGraph<V, E> {
edgeBuilder = factory.edgeFactory != null ? factory.edgeFactory.get() : null;
}

/* copy constructor */
GraphImpl(GraphFactoryImpl<V, E> factory, Graph<V, E> orig, boolean copyVerticesWeights, boolean copyEdgesWeights) {
this(factory, factory.indexFactory.newCopyOf(orig.indexGraph(), copyVerticesWeights, copyEdgesWeights),
orig.indexGraphVerticesMap(), orig.indexGraphEdgesMap(), null, null);
}

@Override
public IndexGraph indexGraph() {
return indexGraph;
Expand Down
12 changes: 10 additions & 2 deletions jgalgo-core/src/main/java/com/jgalgo/graph/Graphs.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,16 @@
public class Graphs {
private Graphs() {}

@SuppressWarnings("unchecked")
static <V, E> Graph<V, E> copy(Graph<V, E> g, boolean copyVerticesWeights, boolean copyEdgesWeights) {
return factoryForCopy(g).newCopyOf(g, copyVerticesWeights, copyEdgesWeights);
}

static <V, E> Graph<V, E> immutableCopy(Graph<V, E> g, boolean copyVerticesWeights, boolean copyEdgesWeights) {
return factoryForCopy(g).newImmutableCopyOf(g, copyVerticesWeights, copyEdgesWeights);
}

@SuppressWarnings("unchecked")
private static <V, E> GraphFactory<V, E> factoryForCopy(Graph<V, E> g) {
GraphFactory<V, E> factory;
if (g instanceof IndexGraph) {
factory = (GraphFactory<V, E>) IndexGraphFactory.newInstance(g.isDirected());
Expand All @@ -60,7 +68,7 @@ static <V, E> Graph<V, E> copy(Graph<V, E> g, boolean copyVerticesWeights, boole
factory.allowSelfEdges();
if (g.isAllowParallelEdges())
factory.allowParallelEdges();
return factory.newCopyOf(g, copyVerticesWeights, copyEdgesWeights);
return factory;
}

/**
Expand Down
6 changes: 1 addition & 5 deletions jgalgo-core/src/main/java/com/jgalgo/graph/IndexGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -539,11 +539,7 @@ default IndexGraph immutableCopy() {

@Override
default IndexGraph immutableCopy(boolean copyVerticesWeights, boolean copyEdgesWeights) {
if (isDirected()) {
return new GraphCsrDirected(this, copyVerticesWeights, copyEdgesWeights);
} else {
return new GraphCsrUndirected(this, copyVerticesWeights, copyEdgesWeights);
}
return (IndexGraph) IntGraph.super.immutableCopy(copyVerticesWeights, copyEdgesWeights);
}

@Override
Expand Down
Loading

0 comments on commit 91ae8c3

Please sign in to comment.