2424import org .junit .jupiter .params .provider .Arguments ;
2525import org .junit .jupiter .params .provider .MethodSource ;
2626import org .junit .jupiter .params .provider .ValueSource ;
27- import org .neo4j .gds .triangle .IntersectingTriangleCount .TriangleCountResult ;
27+ import org .neo4j .gds .Orientation ;
28+ import org .neo4j .gds .TestSupport ;
2829import org .neo4j .gds .api .Graph ;
2930import org .neo4j .gds .core .concurrency .Pools ;
31+ import org .neo4j .gds .triangle .IntersectingTriangleCount .TriangleCountResult ;
3032
3133import java .util .stream .Stream ;
3234
35+ import static org .assertj .core .api .Assertions .assertThat ;
3336import static org .junit .jupiter .api .Assertions .assertEquals ;
37+ import static org .neo4j .gds .Orientation .UNDIRECTED ;
3438import static org .neo4j .gds .triangle .IntersectingTriangleCount .EXCLUDED_NODE_TRIANGLE_COUNT ;
3539import static org .neo4j .gds .utils .StringFormatting .formatWithLocale ;
36- import static org .neo4j .gds .Orientation .UNDIRECTED ;
37- import static org .neo4j .gds .TestSupport .fromGdl ;
3840
3941class IntersectingTriangleCountTest {
4042
4143 private static Stream <Arguments > noTriangleQueries () {
4244 return Stream .of (
43- Arguments .of (fromGdl ("CREATE ()-[:T]->()-[:T]->()" , UNDIRECTED ), "line" ),
44- Arguments .of (fromGdl ("CREATE (), (), ()" , UNDIRECTED ), "no rels" ),
45- Arguments .of (fromGdl ("CREATE ()-[:T]->(), ()" , UNDIRECTED ), "one rel" ),
46- Arguments .of (fromGdl ("CREATE (a1)-[:T]->()-[:T]->(a1), ()" , UNDIRECTED ), "back and forth" )
45+ Arguments .of (fromGdl ("CREATE ()-[:T]->()-[:T]->()" ), "line" ),
46+ Arguments .of (fromGdl ("CREATE (), (), ()" ), "no rels" ),
47+ Arguments .of (fromGdl ("CREATE ()-[:T]->(), ()" ), "one rel" ),
48+ Arguments .of (fromGdl ("CREATE (a1)-[:T]->()-[:T]->(a1), ()" ), "back and forth" )
4749 );
4850 }
4951
@@ -67,10 +69,10 @@ void independentTriangles(int nbrOfTriangles) {
6769 gdl .append (formatWithLocale ("(a%d)-[:T]->()-[:T]->()-[:T]->(a%d) " , i , i ));
6870 }
6971
70- TriangleCountResult result = compute (fromGdl (gdl .toString (), UNDIRECTED ));
72+ TriangleCountResult result = compute (fromGdl (gdl .toString ()));
7173
7274 assertEquals (nbrOfTriangles , result .globalTriangles ());
73- assertEquals (3 * nbrOfTriangles , result .localTriangles ().size ());
75+ assertEquals (3L * nbrOfTriangles , result .localTriangles ().size ());
7476 for (int i = 0 ; i < result .localTriangles ().size (); ++i ) {
7577 assertEquals (1 , result .localTriangles ().get (i ));
7678 }
@@ -89,8 +91,7 @@ void clique5() {
8991 " (a2)-[:T]->(a5), " +
9092 " (a3)-[:T]->(a4), " +
9193 " (a3)-[:T]->(a5), " +
92- " (a4)-[:T]->(a5)" ,
93- UNDIRECTED
94+ " (a4)-[:T]->(a5)"
9495 );
9596
9697 TriangleCountResult result = compute (graph );
@@ -115,8 +116,7 @@ void clique5UnionGraph() {
115116 " (a2)-[:T2]->(a5), " +
116117 " (a3)-[:T3]->(a4), " +
117118 " (a3)-[:T1]->(a5), " +
118- " (a4)-[:T4]->(a5)" ,
119- UNDIRECTED
119+ " (a4)-[:T4]->(a5)"
120120 );
121121
122122 TriangleCountResult result = compute (graph );
@@ -133,8 +133,7 @@ void twoAdjacentTriangles() {
133133 var graph = fromGdl (
134134 "CREATE " +
135135 " (a)-[:T]->()-[:T]->()-[:T]->(a) " +
136- ", (a)-[:T]->()-[:T]->()-[:T]->(a)" ,
137- UNDIRECTED
136+ ", (a)-[:T]->()-[:T]->()-[:T]->(a)"
138137 );
139138
140139 TriangleCountResult result = compute (graph );
@@ -149,8 +148,7 @@ void twoTrianglesWithLine() {
149148 "CREATE " +
150149 " (a)-[:T]->(b)-[:T]->(c)-[:T]->(a) " +
151150 ", (q)-[:T]->(r)-[:T]->(t)-[:T]->(q) " +
152- ", (a)-[:T]->(q)" ,
153- UNDIRECTED
151+ ", (a)-[:T]->(q)"
154152 );
155153
156154 TriangleCountResult result = compute (graph );
@@ -165,7 +163,7 @@ void twoTrianglesWithLine() {
165163
166164 @ Test
167165 void selfLoop () {
168- var graph = fromGdl ("CREATE (a)-[:T]->(a)-[:T]->(a)-[:T]->(a)" , UNDIRECTED );
166+ var graph = fromGdl ("CREATE (a)-[:T]->(a)-[:T]->(a)-[:T]->(a)" );
169167
170168 TriangleCountResult result = compute (graph );
171169
@@ -176,7 +174,7 @@ void selfLoop() {
176174
177175 @ Test
178176 void selfLoop2 () {
179- var graph = fromGdl ("CREATE (a)-[:T]->(b)-[:T]->(c)-[:T]->(a)-[:T]->(a)" , UNDIRECTED );
177+ var graph = fromGdl ("CREATE (a)-[:T]->(b)-[:T]->(c)-[:T]->(a)-[:T]->(a)" );
180178
181179 TriangleCountResult result = compute (graph );
182180
@@ -192,8 +190,7 @@ void parallelRelationships() {
192190 var graph = fromGdl (
193191 "CREATE" +
194192 " (a)-[:T]->(b)-[:T]->(c)-[:T]->(a)" +
195- ", (a)-[:T]->(b)" ,
196- UNDIRECTED
193+ ", (a)-[:T]->(b)"
197194 );
198195
199196 TriangleCountResult result = compute (graph );
@@ -210,8 +207,7 @@ void parallelTriangles() {
210207 var graph = fromGdl (
211208 "CREATE" +
212209 " (a)-[:T]->(b)-[:T]->(c)-[:T]->(a)" +
213- ",(a)-[:T]->(b)-[:T]->(c)-[:T]->(a)" ,
214- UNDIRECTED
210+ ",(a)-[:T]->(b)-[:T]->(c)-[:T]->(a)"
215211 );
216212
217213 TriangleCountResult result = compute (graph );
@@ -230,8 +226,7 @@ void triangleNotOnFirstPathAndFirstNodeHasNoMoreNeighbours() {
230226 " (n0)-[:REL]->(n1)" +
231227 ", (n1)-[:REL]->(n2)" +
232228 ", (n0)-[:REL]->(n3)" +
233- ", (n1)-[:REL]->(n3)" ,
234- UNDIRECTED
229+ ", (n1)-[:REL]->(n3)"
235230 );
236231
237232 TriangleCountResult result = compute (graph );
@@ -252,8 +247,7 @@ void triangleNotOnFirstPathAndFirstNodeHasAnotherNeighbours() {
252247 ", (n1)-[:REL]->(n2)" +
253248 ", (n0)-[:REL]->(n3)" +
254249 ", (n0)-[:REL]->(n4)" +
255- ", (n1)-[:REL]->(n3)" ,
256- UNDIRECTED
250+ ", (n1)-[:REL]->(n3)"
257251 );
258252
259253 TriangleCountResult result = compute (graph );
@@ -276,8 +270,7 @@ void triangleNotOnFirstPathAndFirstNodeHasTheMostNeighbours() {
276270 ", (n0)-[:REL]->(n3)" +
277271 ", (n0)-[:REL]->(n4)" +
278272 ", (n0)-[:REL]->(n5)" +
279- ", (n1)-[:REL]->(n3)" ,
280- UNDIRECTED
273+ ", (n1)-[:REL]->(n3)"
281274 );
282275
283276 TriangleCountResult result = compute (graph );
@@ -300,8 +293,7 @@ void triangleWhenSecondMemberAtEndOfRelChain() {
300293 ", (n1)-[:REL]->(n2)" +
301294 ", (n0)-[:REL]->(n3)" +
302295 ", (n0)-[:REL]->(n4)" +
303- ", (n1)-[:REL]->(n4)" ,
304- UNDIRECTED
296+ ", (n1)-[:REL]->(n4)"
305297 );
306298
307299 TriangleCountResult result = compute (graph );
@@ -325,8 +317,7 @@ void triangleWhenFirstMemberHasMoreNeighbours() {
325317 ", (n0)-[:REL]->(n4)" +
326318 ", (n0)-[:REL]->(n5)" +
327319 ", (n1)-[:REL]->(n4)" +
328- ", (n1)-[:REL]->(n6)" ,
329- UNDIRECTED
320+ ", (n1)-[:REL]->(n6)"
330321 );
331322
332323 TriangleCountResult result = compute (graph );
@@ -354,8 +345,7 @@ void filterMaxDegreeFirstCNode() {
354345 ", (n3)-[:REL]->(n4)" +
355346 ", (n1)-[:REL]->(n6)" +
356347 ", (n0)-[:REL]->(n2)" +
357- ", (n0)-[:REL]->(n6)" ,
358- UNDIRECTED
348+ ", (n0)-[:REL]->(n6)"
359349 );
360350
361351 TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
@@ -387,8 +377,7 @@ void filterMaxDegreeSecondCNode() {
387377 ", (n3)-[:REL]->(n0)" +
388378 ", (n3)-[:REL]->(n4)" +
389379 ", (n3)-[:REL]->(n5)" +
390- ", (n3)-[:REL]->(n6)" ,
391- UNDIRECTED
380+ ", (n3)-[:REL]->(n6)"
392381 );
393382
394383 TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
@@ -420,8 +409,7 @@ void manyTrianglesAndOtherThings() {
420409 ", (h)-[:T]->(i)-[:T]->(j)-[:T]->(k)-[:T]->(e)" +
421410 ", (k)-[:T]->(l)" +
422411 ", (k)-[:T]->(m)-[:T]->(n)-[:T]->(j)" +
423- ", (o)" ,
424- UNDIRECTED
412+ ", (o)"
425413 );
426414
427415 TriangleCountResult result = compute (graph );
@@ -449,16 +437,15 @@ void manyTrianglesAndOtherThings() {
449437 void testTriangleCountingWithMaxDegree () {
450438 var graph = fromGdl (
451439 "CREATE" +
452- " (a)-[:T]->(b)" +
453- " ,(a)-[:T]->(c)" +
454- " ,(a)-[:T]->(d)" +
455- " ,(b)-[:T]->(c)" +
456- " ,(b)-[:T]->(d)" +
457-
458- " ,(e)-[:T]->(f)" +
459- " ,(f)-[:T]->(g)" +
460- " ,(g)-[:T]->(e)" ,
461- UNDIRECTED
440+ " (a)-[:T]->(b)" +
441+ " ,(a)-[:T]->(c)" +
442+ " ,(a)-[:T]->(d)" +
443+ " ,(b)-[:T]->(c)" +
444+ " ,(b)-[:T]->(d)" +
445+
446+ " ,(e)-[:T]->(f)" +
447+ " ,(f)-[:T]->(g)" +
448+ " ,(g)-[:T]->(e)"
462449 );
463450
464451 TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
@@ -483,16 +470,15 @@ void testTriangleCountingWithMaxDegree() {
483470 void testTriangleCountingWithMaxDegreeOnUnionGraph () {
484471 var graph = fromGdl (
485472 "CREATE" +
486- " (a)-[:T1]->(b)" +
487- " ,(a)-[:T2]->(c)" +
488- " ,(a)-[:T2]->(d)" +
489- " ,(b)-[:T1]->(c)" +
490- " ,(b)-[:T2]->(d)" +
491-
492- " ,(e)-[:T1]->(f)" +
493- " ,(f)-[:T1]->(g)" +
494- " ,(g)-[:T1]->(e)" ,
495- UNDIRECTED
473+ " (a)-[:T1]->(b)" +
474+ " ,(a)-[:T2]->(c)" +
475+ " ,(a)-[:T2]->(d)" +
476+ " ,(b)-[:T1]->(c)" +
477+ " ,(b)-[:T2]->(d)" +
478+
479+ " ,(e)-[:T1]->(f)" +
480+ " ,(f)-[:T1]->(g)" +
481+ " ,(g)-[:T1]->(e)"
496482 );
497483
498484 TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
@@ -513,6 +499,33 @@ void testTriangleCountingWithMaxDegreeOnUnionGraph() {
513499 assertEquals (1 , result .globalTriangles ());
514500 }
515501
502+ @ Test
503+ void testTriangleCountingOnUnionGraphWithIncompleteTriangles () {
504+ // triangle would be (a)-(b)-(c), but it is not complete, there is no (b)-(c)
505+ // (b) is connected to (x) and (y), both have smaller ids than (c)
506+ // TC tries to find (b)-(c) und the union graph has to exhaust all cursors during advance
507+ // to learn that there are only nodes that are smaller than (c)
508+ var testGraph = TestSupport .fromGdl (
509+ "CREATE" +
510+ " (a)-[:T]->(b)" +
511+ " ,(b)-[:X]->(x)" +
512+ " ,(b)-[:Y]->(y)" +
513+ " ,(a)-[:T]->(c)" ,
514+ UNDIRECTED
515+ );
516+
517+ var config = ImmutableTriangleCountBaseConfig .builder ().build ();
518+ var result = compute (testGraph .graph (), config );
519+
520+ assertThat (result .globalTriangles ()).isEqualTo (0L );
521+ assertThat (result .localTriangles ())
522+ .returns (0L , t -> t .get (testGraph .toMappedNodeId ("a" )))
523+ .returns (0L , t -> t .get (testGraph .toMappedNodeId ("b" )))
524+ .returns (0L , t -> t .get (testGraph .toMappedNodeId ("c" )))
525+ .returns (0L , t -> t .get (testGraph .toMappedNodeId ("x" )))
526+ .returns (0L , t -> t .get (testGraph .toMappedNodeId ("y" )));
527+ }
528+
516529 private TriangleCountResult compute (Graph graph ) {
517530 TriangleCountStatsConfig config = ImmutableTriangleCountStatsConfig .builder ().build ();
518531 return compute (graph , config );
@@ -521,4 +534,8 @@ private TriangleCountResult compute(Graph graph) {
521534 private TriangleCountResult compute (Graph graph , TriangleCountBaseConfig config ) {
522535 return IntersectingTriangleCount .create (graph , config , Pools .DEFAULT ).compute ();
523536 }
537+
538+ private static Graph fromGdl (String gdl ) {
539+ return TestSupport .fromGdl (gdl , Orientation .UNDIRECTED ).graph ();
540+ }
524541}
0 commit comments