Skip to content

Commit 297d2dd

Browse files
Add approx max k cut in business facade
1 parent 58038f7 commit 297d2dd

File tree

4 files changed

+205
-0
lines changed

4 files changed

+205
-0
lines changed

algorithms-compute-business-facade/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dependencies {
1010
implementation project(':algo-common') // TODO: extract the results to a separate module and depend on it
1111
implementation project(':algorithms-compute-facade')
1212
implementation project(':collections')
13+
implementation project(':community-params')
1314
implementation project(':core') // TODO: this is here because of the `GraphStoreCatalogService` --> refactor it so we can use the service without bringing the entire sub-project
1415
implementation project(':graph-schema-api')
1516
implementation project(':logging')
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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.community;
21+
22+
import org.neo4j.gds.GraphParameters;
23+
import org.neo4j.gds.api.DatabaseId;
24+
import org.neo4j.gds.api.GraphName;
25+
import org.neo4j.gds.api.User;
26+
import org.neo4j.gds.approxmaxkcut.ApproxMaxKCutParameters;
27+
import org.neo4j.gds.approxmaxkcut.ApproxMaxKCutResult;
28+
import org.neo4j.gds.community.validation.ApproxMaxKCutValidation;
29+
import org.neo4j.gds.core.JobId;
30+
import org.neo4j.gds.core.loading.GraphStoreCatalogService;
31+
import org.neo4j.gds.result.TimedAlgorithmResult;
32+
import org.neo4j.gds.results.ResultTransformerBuilder;
33+
34+
import java.util.Optional;
35+
import java.util.concurrent.CompletableFuture;
36+
37+
public class CommunityComputeBusinessFacade {
38+
39+
// Global dependencies
40+
private final GraphStoreCatalogService graphStoreCatalogService;
41+
private final CommunityComputeFacade computeFacade;
42+
43+
// Request scope dependencies -- can we move these as method parameters?! 🤔
44+
private final User user;
45+
private final DatabaseId databaseId;
46+
47+
public CommunityComputeBusinessFacade(
48+
GraphStoreCatalogService graphStoreCatalogService,
49+
CommunityComputeFacade computeFacade,
50+
User user,
51+
DatabaseId databaseId
52+
) {
53+
this.graphStoreCatalogService = graphStoreCatalogService;
54+
this.computeFacade = computeFacade;
55+
this.user = user;
56+
this.databaseId = databaseId;
57+
}
58+
59+
public <TR> CompletableFuture<TR> approxMaxKCut(
60+
GraphName graphName,
61+
GraphParameters graphParameters,
62+
Optional<String> relationshipProperty,
63+
ApproxMaxKCutParameters parameters,
64+
JobId jobId,
65+
boolean logProgress,
66+
ResultTransformerBuilder<TimedAlgorithmResult<ApproxMaxKCutResult>, TR> resultTransformerBuilder
67+
) {
68+
// Fetch the Graph the algorithm will operate on
69+
var graphResources = graphStoreCatalogService.fetchGraphResources(
70+
graphName,
71+
graphParameters,
72+
relationshipProperty,
73+
new ApproxMaxKCutValidation(parameters.minCommunitySizes()),
74+
Optional.empty(),
75+
user,
76+
databaseId
77+
);
78+
var graph = graphResources.graph();
79+
80+
return computeFacade.approxMaxKCut(
81+
graph,
82+
parameters,
83+
jobId,
84+
logProgress
85+
86+
).thenApply(resultTransformerBuilder.build(graphResources));
87+
}
88+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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.community.validation;
21+
22+
import org.neo4j.gds.NodeLabel;
23+
import org.neo4j.gds.RelationshipType;
24+
import org.neo4j.gds.api.GraphStore;
25+
import org.neo4j.gds.core.loading.validation.GraphStoreValidation;
26+
27+
import java.util.Collection;
28+
import java.util.List;
29+
30+
import static org.neo4j.gds.utils.StringFormatting.formatWithLocale;
31+
32+
public class ApproxMaxKCutValidation extends GraphStoreValidation {
33+
34+
private final List<Long> minCommunitySizes;
35+
36+
public ApproxMaxKCutValidation(List<Long> minCommunitySizes) {
37+
this.minCommunitySizes = minCommunitySizes;
38+
}
39+
40+
41+
@Override
42+
protected void validateAlgorithmRequirements(
43+
GraphStore graphStore,
44+
Collection<NodeLabel> selectedLabels,
45+
Collection<RelationshipType> selectedRelationshipTypes
46+
) {
47+
validateMinCommunitySizesSum(graphStore);
48+
}
49+
50+
void validateMinCommunitySizesSum(GraphStore graphStore){
51+
long minCommunitySizesSum = minCommunitySizes.stream().mapToLong(Long::valueOf).sum();
52+
long halfNodeCount = graphStore.nodeCount() / 2;
53+
if (minCommunitySizesSum > halfNodeCount) {
54+
throw new IllegalArgumentException(formatWithLocale(
55+
"The sum of min community sizes is larger than half of the number of nodes in the graph: %d > %d",
56+
minCommunitySizesSum,
57+
halfNodeCount
58+
));
59+
}
60+
}
61+
62+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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.community.validation;
21+
22+
import org.junit.jupiter.api.Test;
23+
import org.neo4j.gds.api.GraphStore;
24+
25+
import java.util.List;
26+
27+
import static org.assertj.core.api.Assertions.assertThatNoException;
28+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
29+
import static org.mockito.Mockito.mock;
30+
import static org.mockito.Mockito.when;
31+
32+
class ApproxMaxKCutValidationTest {
33+
34+
@Test
35+
void shouldNotThrowIfMinCommunitySizesIsValid(){
36+
37+
var graphStore = mock(GraphStore.class);
38+
when(graphStore.nodeCount()).thenReturn(202L);
39+
var validation = new ApproxMaxKCutValidation(List.of(100L));
40+
41+
assertThatNoException().isThrownBy(() -> validation.validateMinCommunitySizesSum(graphStore));
42+
}
43+
44+
@Test
45+
void shouldThrowIfMinCommunitySizesIsLarge(){
46+
47+
var graphStore = mock(GraphStore.class);
48+
when(graphStore.nodeCount()).thenReturn(2L);
49+
var validation = new ApproxMaxKCutValidation(List.of(100L));
50+
51+
assertThatThrownBy(()-> validation.validateMinCommunitySizesSum(graphStore))
52+
.hasMessageContaining("The sum of min community sizes is larger than half of the number of nodes in the graph: 100 > 1");
53+
}
54+
}

0 commit comments

Comments
 (0)