Skip to content

Commit aca5aa8

Browse files
SmokeTest.kt etc
Co-authored-by: Ioannis Panagiotas <ioannis.panagiotas@neo4j.com>
1 parent abfd825 commit aca5aa8

File tree

8 files changed

+283
-3
lines changed

8 files changed

+283
-3
lines changed

doc/modules/ROOT/pages/operations-reference/algorithm-references.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,11 @@
227227
| `gds.louvain.stream.estimate` label:procedure[Procedure]
228228
| `gds.louvain.stats` label:procedure[Procedure]
229229
| `gds.louvain.stats.estimate` label:procedure[Procedure]
230-
.3+<.^|Max flow
230+
.4+<.^|Max flow
231231
| `gds.maxFlow.mutate` label:procedure[Procedure]
232232
| `gds.maxFlow.stats` label:procedure[Procedure]
233233
| `gds.maxFlow.stream` label:procedure[Procedure]
234+
| `gds.maxFlow.write` label:procedure[Procedure]
234235
.4+<.^|xref:algorithms/approx-max-k-cut.adoc[Approximate Maximum k-cut]
235236
| `gds.maxkcut.mutate` label:procedure[Procedure]
236237
| `gds.maxkcut.mutate.estimate` label:procedure[Procedure]

open-packaging/src/test/java/org/neo4j/gds/OpenGdsProcedureSmokeTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ class OpenGdsProcedureSmokeTest extends BaseProcTest {
472472
"gds.maxFlow.mutate",
473473
"gds.maxFlow.stats",
474474
"gds.maxFlow.stream",
475+
"gds.maxFlow.write",
475476

476477
"gds.nodeSimilarity.mutate",
477478
"gds.nodeSimilarity.mutate.estimate",
@@ -633,7 +634,7 @@ void countShouldMatch() {
633634
);
634635

635636
// If you find yourself updating this count, please also update the count in SmokeTest.kt
636-
int expectedCount = 471;
637+
int expectedCount = 472;
637638
assertEquals(
638639
expectedCount,
639640
returnedRows,

procedures/pushback-procedures-facade/src/main/java/org/neo4j/gds/procedures/algorithms/pathfinding/PushbackPathFindingProcedureFacade.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ public Stream<MaxFlowStatsResult> maxFlowStats(String graphName, Map<String, Obj
281281

282282
@Override
283283
public Stream<MaxFlowWriteResult> maxFlowWrite(String graphName, Map<String, Object> configuration) {
284-
return Stream.empty();
284+
return writeProcedureFacade.maxFlow(graphName, configuration);
285285
}
286286

287287
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.procedures.algorithms.pathfinding.write;
21+
22+
import org.neo4j.gds.api.Graph;
23+
import org.neo4j.gds.api.GraphStore;
24+
import org.neo4j.gds.api.ResultStore;
25+
import org.neo4j.gds.core.utils.progress.JobId;
26+
import org.neo4j.gds.maxflow.FlowResult;
27+
import org.neo4j.gds.pathfinding.MaxFlowWriteStep;
28+
import org.neo4j.gds.procedures.algorithms.pathfinding.MaxFlowWriteResult;
29+
import org.neo4j.gds.result.TimedAlgorithmResult;
30+
import org.neo4j.gds.results.ResultTransformer;
31+
32+
import java.util.Map;
33+
import java.util.stream.Stream;
34+
35+
public class MaxFlowWriteResultTransformer implements ResultTransformer<TimedAlgorithmResult<FlowResult>, Stream<MaxFlowWriteResult>> {
36+
37+
private final MaxFlowWriteStep writeStep;
38+
private final Graph graph;
39+
private final GraphStore graphStore;
40+
@Deprecated(forRemoval = true)
41+
private final ResultStore resultStore;
42+
private final JobId jobId;
43+
private final Map<String, Object> configuration;
44+
45+
public MaxFlowWriteResultTransformer(
46+
MaxFlowWriteStep writeStep,
47+
Graph graph,
48+
GraphStore graphStore,
49+
ResultStore resultStore,
50+
JobId jobId,
51+
Map<String, Object> configuration
52+
) {
53+
this.writeStep = writeStep;
54+
this.graph = graph;
55+
this.graphStore = graphStore;
56+
this.resultStore = resultStore;
57+
this.jobId = jobId;
58+
this.configuration = configuration;
59+
}
60+
61+
@Override
62+
public Stream<MaxFlowWriteResult> apply(TimedAlgorithmResult<FlowResult> algorithmResult) {
63+
64+
var result = algorithmResult.result();
65+
var writeRelationshipsMetadata = WriteStepExecute.executeWriteRelationshipStep(
66+
writeStep,
67+
graph,
68+
graphStore,
69+
jobId,
70+
result,
71+
resultStore
72+
);
73+
return Stream.of(
74+
new MaxFlowWriteResult(
75+
0,
76+
algorithmResult.computeMillis(),
77+
writeRelationshipsMetadata.writeMillis(),
78+
writeRelationshipsMetadata.relationshipsWritten(),
79+
result.totalFlow(),
80+
configuration
81+
)
82+
);
83+
}
84+
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.procedures.algorithms.pathfinding.write;
21+
22+
import org.neo4j.gds.core.loading.GraphResources;
23+
import org.neo4j.gds.maxflow.FlowResult;
24+
import org.neo4j.gds.maxflow.MaxFlowWriteConfig;
25+
import org.neo4j.gds.pathfinding.MaxFlowWriteStep;
26+
import org.neo4j.gds.procedures.algorithms.pathfinding.MaxFlowWriteResult;
27+
import org.neo4j.gds.result.TimedAlgorithmResult;
28+
import org.neo4j.gds.results.ResultTransformer;
29+
import org.neo4j.gds.results.ResultTransformerBuilder;
30+
31+
import java.util.stream.Stream;
32+
33+
class MaxFlowWriteResultTransformerBuilder implements ResultTransformerBuilder<TimedAlgorithmResult<FlowResult>, Stream<MaxFlowWriteResult>> {
34+
private final MaxFlowWriteStep writeStep;
35+
private final MaxFlowWriteConfig config;
36+
37+
MaxFlowWriteResultTransformerBuilder(MaxFlowWriteStep writeStep, MaxFlowWriteConfig config) {
38+
this.writeStep = writeStep;
39+
this.config = config;
40+
}
41+
42+
43+
@Override
44+
public ResultTransformer<TimedAlgorithmResult<FlowResult>, Stream<MaxFlowWriteResult>> build(GraphResources graphResources) {
45+
return new MaxFlowWriteResultTransformer(
46+
writeStep,
47+
graphResources.graph(),
48+
graphResources.graphStore(),
49+
graphResources.resultStore(),
50+
config.jobId(),
51+
config.toMap()
52+
);
53+
}
54+
55+
}

procedures/pushback-procedures-facade/src/main/java/org/neo4j/gds/procedures/algorithms/pathfinding/write/PushbackPathFindingWriteProcedureFacade.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
import org.neo4j.gds.applications.algorithms.machinery.WriteRelationshipService;
2626
import org.neo4j.gds.kspanningtree.KSpanningTreeWriteConfig;
2727
import org.neo4j.gds.logging.Log;
28+
import org.neo4j.gds.maxflow.MaxFlowWriteConfig;
2829
import org.neo4j.gds.pathfinding.BellmanFordWriteStep;
2930
import org.neo4j.gds.pathfinding.KSpanningTreeWriteStep;
31+
import org.neo4j.gds.pathfinding.MaxFlowWriteStep;
3032
import org.neo4j.gds.pathfinding.PathFindingComputeBusinessFacade;
3133
import org.neo4j.gds.pathfinding.PrizeCollectingSteinerTreeWriteStep;
3234
import org.neo4j.gds.pathfinding.ShortestPathWriteStep;
@@ -42,6 +44,7 @@
4244
import org.neo4j.gds.procedures.algorithms.configuration.UserSpecificConfigurationParser;
4345
import org.neo4j.gds.procedures.algorithms.pathfinding.BellmanFordWriteResult;
4446
import org.neo4j.gds.procedures.algorithms.pathfinding.KSpanningTreeWriteResult;
47+
import org.neo4j.gds.procedures.algorithms.pathfinding.MaxFlowWriteResult;
4548
import org.neo4j.gds.procedures.algorithms.pathfinding.PrizeCollectingSteinerTreeWriteResult;
4649
import org.neo4j.gds.procedures.algorithms.pathfinding.SpanningTreeWriteResult;
4750
import org.neo4j.gds.procedures.algorithms.pathfinding.SteinerWriteResult;
@@ -166,6 +169,30 @@ public Stream<KSpanningTreeWriteResult> kSpanningTree(
166169
).join();
167170
}
168171

172+
public Stream<MaxFlowWriteResult> maxFlow(String graphName, Map<String, Object> configuration) {
173+
var config = configurationParser.parseConfiguration(
174+
configuration,
175+
MaxFlowWriteConfig::of
176+
);
177+
178+
var writeStep = new MaxFlowWriteStep(
179+
writeRelationshipService,
180+
config.writeRelationshipType(),
181+
config.writeProperty(),
182+
config::resolveResultStore,
183+
config.jobId()
184+
);
185+
186+
return businessFacade.maxFlow(
187+
GraphName.parse(graphName),
188+
config.toGraphParameters(),
189+
config.relationshipWeightProperty(),
190+
config.toParameters(),
191+
config.jobId(),
192+
config.logProgress(),
193+
new MaxFlowWriteResultTransformerBuilder(writeStep, config)
194+
).join();
195+
}
169196

170197
public Stream<PrizeCollectingSteinerTreeWriteResult> pcst(
171198
String graphName,

procedures/pushback-procedures-facade/src/test/java/org/neo4j/gds/procedures/algorithms/pathfinding/PushbackPathFindingProcedureFacadeTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,13 @@ void kSpanningTreeWrite() {
353353
verifyNoInteractions(mutateFacadeMock, statsFacadeMock, streamFacadeMock);
354354
}
355355

356+
@Test
357+
void maxFlowWrite() {
358+
facade.maxFlowWrite(graphName, config);
359+
verify(writeFacadeMock).maxFlow(graphName, config);
360+
verifyNoInteractions(mutateFacadeMock, statsFacadeMock, streamFacadeMock);
361+
}
362+
356363
@Test
357364
void prizeCollectingSteinerTreeWrite() {
358365
facade.prizeCollectingSteinerTreeWrite(graphName, config);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.procedures.algorithms.pathfinding.write;
21+
22+
import org.junit.jupiter.api.Test;
23+
import org.neo4j.gds.api.Graph;
24+
import org.neo4j.gds.api.GraphStore;
25+
import org.neo4j.gds.api.ResultStore;
26+
import org.neo4j.gds.applications.algorithms.metadata.RelationshipsWritten;
27+
import org.neo4j.gds.core.utils.progress.JobId;
28+
import org.neo4j.gds.maxflow.FlowResult;
29+
import org.neo4j.gds.pathfinding.MaxFlowWriteStep;
30+
import org.neo4j.gds.result.TimedAlgorithmResult;
31+
32+
import java.util.Map;
33+
34+
import static org.assertj.core.api.Assertions.assertThat;
35+
import static org.mockito.ArgumentMatchers.any;
36+
import static org.mockito.Mockito.mock;
37+
import static org.mockito.Mockito.times;
38+
import static org.mockito.Mockito.verify;
39+
import static org.mockito.Mockito.verifyNoMoreInteractions;
40+
import static org.mockito.Mockito.when;
41+
42+
class MaxFlowWriteResultTransformerTest {
43+
44+
@Test
45+
void shouldTransformToWriteResult() {
46+
var config = Map.<String, Object>of("foo", "bar");
47+
var graph = mock(Graph.class);
48+
var graphStore = mock(GraphStore.class);
49+
var resultStore = mock(ResultStore.class);
50+
var jobId = new JobId();
51+
var writeStep = mock(MaxFlowWriteStep.class);
52+
53+
var algoResult = mock(FlowResult.class);
54+
when(algoResult.totalFlow()).thenReturn(3D);
55+
56+
var relationshipsWritten = new RelationshipsWritten(5L);
57+
when(writeStep.execute(any(), any(), any(), any(), any())).thenReturn(relationshipsWritten);
58+
59+
var timedResult = new TimedAlgorithmResult<>(algoResult, 123L);
60+
61+
var transformer = new MaxFlowWriteResultTransformer(writeStep, graph, graphStore, resultStore, jobId, config);
62+
63+
var resultStream = transformer.apply(timedResult);
64+
var result = resultStream.findFirst().orElseThrow();
65+
66+
assertThat(result.preProcessingMillis()).isZero();
67+
assertThat(result.computeMillis()).isEqualTo(123L);
68+
assertThat(result.writeMillis()).isNotNegative();
69+
assertThat(result.configuration()).isEqualTo(config);
70+
assertThat(result.totalFlow()).isEqualTo(3D);
71+
72+
assertThat(result.relationshipsWritten()).isEqualTo(5L);
73+
74+
verify(writeStep, times(1)).execute(graph, graphStore, resultStore, algoResult, jobId);
75+
verifyNoMoreInteractions(writeStep);
76+
}
77+
78+
@Test
79+
void shouldTransformEmptyResultToWriteResult() {
80+
var config = Map.<String, Object>of("boo", "foo");
81+
var graph = mock(Graph.class);
82+
var graphStore = mock(GraphStore.class);
83+
var resultStore = mock(ResultStore.class);
84+
var jobId = new JobId();
85+
var writeStep = mock(MaxFlowWriteStep.class);
86+
when(writeStep.execute(any(), any(), any(), any(), any())).thenReturn(new RelationshipsWritten(0L));
87+
88+
var algoResult = FlowResult.EMPTY;
89+
90+
var timedResult = new TimedAlgorithmResult<>(algoResult, 123L);
91+
92+
var transformer = new MaxFlowWriteResultTransformer(writeStep, graph, graphStore, resultStore, jobId, config);
93+
94+
var resultStream = transformer.apply(timedResult);
95+
var result = resultStream.findFirst().orElseThrow();
96+
97+
assertThat(result.preProcessingMillis()).isZero();
98+
assertThat(result.computeMillis()).isEqualTo(123L);
99+
assertThat(result.writeMillis()).isNotNegative();
100+
assertThat(result.configuration()).isEqualTo(config);
101+
assertThat(result.totalFlow()).isEqualTo(0d);
102+
assertThat(result.relationshipsWritten()).isEqualTo(0);
103+
}
104+
}

0 commit comments

Comments
 (0)