24
24
import org .junit .jupiter .params .provider .Arguments ;
25
25
import org .junit .jupiter .params .provider .MethodSource ;
26
26
import 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 ;
28
29
import org .neo4j .gds .api .Graph ;
29
30
import org .neo4j .gds .core .concurrency .Pools ;
31
+ import org .neo4j .gds .triangle .IntersectingTriangleCount .TriangleCountResult ;
30
32
31
33
import java .util .stream .Stream ;
32
34
35
+ import static org .assertj .core .api .Assertions .assertThat ;
33
36
import static org .junit .jupiter .api .Assertions .assertEquals ;
37
+ import static org .neo4j .gds .Orientation .UNDIRECTED ;
34
38
import static org .neo4j .gds .triangle .IntersectingTriangleCount .EXCLUDED_NODE_TRIANGLE_COUNT ;
35
39
import static org .neo4j .gds .utils .StringFormatting .formatWithLocale ;
36
- import static org .neo4j .gds .Orientation .UNDIRECTED ;
37
- import static org .neo4j .gds .TestSupport .fromGdl ;
38
40
39
41
class IntersectingTriangleCountTest {
40
42
41
43
private static Stream <Arguments > noTriangleQueries () {
42
44
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" )
47
49
);
48
50
}
49
51
@@ -67,10 +69,10 @@ void independentTriangles(int nbrOfTriangles) {
67
69
gdl .append (formatWithLocale ("(a%d)-[:T]->()-[:T]->()-[:T]->(a%d) " , i , i ));
68
70
}
69
71
70
- TriangleCountResult result = compute (fromGdl (gdl .toString (), UNDIRECTED ));
72
+ TriangleCountResult result = compute (fromGdl (gdl .toString ()));
71
73
72
74
assertEquals (nbrOfTriangles , result .globalTriangles ());
73
- assertEquals (3 * nbrOfTriangles , result .localTriangles ().size ());
75
+ assertEquals (3L * nbrOfTriangles , result .localTriangles ().size ());
74
76
for (int i = 0 ; i < result .localTriangles ().size (); ++i ) {
75
77
assertEquals (1 , result .localTriangles ().get (i ));
76
78
}
@@ -89,8 +91,7 @@ void clique5() {
89
91
" (a2)-[:T]->(a5), " +
90
92
" (a3)-[:T]->(a4), " +
91
93
" (a3)-[:T]->(a5), " +
92
- " (a4)-[:T]->(a5)" ,
93
- UNDIRECTED
94
+ " (a4)-[:T]->(a5)"
94
95
);
95
96
96
97
TriangleCountResult result = compute (graph );
@@ -115,8 +116,7 @@ void clique5UnionGraph() {
115
116
" (a2)-[:T2]->(a5), " +
116
117
" (a3)-[:T3]->(a4), " +
117
118
" (a3)-[:T1]->(a5), " +
118
- " (a4)-[:T4]->(a5)" ,
119
- UNDIRECTED
119
+ " (a4)-[:T4]->(a5)"
120
120
);
121
121
122
122
TriangleCountResult result = compute (graph );
@@ -133,8 +133,7 @@ void twoAdjacentTriangles() {
133
133
var graph = fromGdl (
134
134
"CREATE " +
135
135
" (a)-[:T]->()-[:T]->()-[:T]->(a) " +
136
- ", (a)-[:T]->()-[:T]->()-[:T]->(a)" ,
137
- UNDIRECTED
136
+ ", (a)-[:T]->()-[:T]->()-[:T]->(a)"
138
137
);
139
138
140
139
TriangleCountResult result = compute (graph );
@@ -149,8 +148,7 @@ void twoTrianglesWithLine() {
149
148
"CREATE " +
150
149
" (a)-[:T]->(b)-[:T]->(c)-[:T]->(a) " +
151
150
", (q)-[:T]->(r)-[:T]->(t)-[:T]->(q) " +
152
- ", (a)-[:T]->(q)" ,
153
- UNDIRECTED
151
+ ", (a)-[:T]->(q)"
154
152
);
155
153
156
154
TriangleCountResult result = compute (graph );
@@ -165,7 +163,7 @@ void twoTrianglesWithLine() {
165
163
166
164
@ Test
167
165
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)" );
169
167
170
168
TriangleCountResult result = compute (graph );
171
169
@@ -176,7 +174,7 @@ void selfLoop() {
176
174
177
175
@ Test
178
176
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)" );
180
178
181
179
TriangleCountResult result = compute (graph );
182
180
@@ -192,8 +190,7 @@ void parallelRelationships() {
192
190
var graph = fromGdl (
193
191
"CREATE" +
194
192
" (a)-[:T]->(b)-[:T]->(c)-[:T]->(a)" +
195
- ", (a)-[:T]->(b)" ,
196
- UNDIRECTED
193
+ ", (a)-[:T]->(b)"
197
194
);
198
195
199
196
TriangleCountResult result = compute (graph );
@@ -210,8 +207,7 @@ void parallelTriangles() {
210
207
var graph = fromGdl (
211
208
"CREATE" +
212
209
" (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)"
215
211
);
216
212
217
213
TriangleCountResult result = compute (graph );
@@ -230,8 +226,7 @@ void triangleNotOnFirstPathAndFirstNodeHasNoMoreNeighbours() {
230
226
" (n0)-[:REL]->(n1)" +
231
227
", (n1)-[:REL]->(n2)" +
232
228
", (n0)-[:REL]->(n3)" +
233
- ", (n1)-[:REL]->(n3)" ,
234
- UNDIRECTED
229
+ ", (n1)-[:REL]->(n3)"
235
230
);
236
231
237
232
TriangleCountResult result = compute (graph );
@@ -252,8 +247,7 @@ void triangleNotOnFirstPathAndFirstNodeHasAnotherNeighbours() {
252
247
", (n1)-[:REL]->(n2)" +
253
248
", (n0)-[:REL]->(n3)" +
254
249
", (n0)-[:REL]->(n4)" +
255
- ", (n1)-[:REL]->(n3)" ,
256
- UNDIRECTED
250
+ ", (n1)-[:REL]->(n3)"
257
251
);
258
252
259
253
TriangleCountResult result = compute (graph );
@@ -276,8 +270,7 @@ void triangleNotOnFirstPathAndFirstNodeHasTheMostNeighbours() {
276
270
", (n0)-[:REL]->(n3)" +
277
271
", (n0)-[:REL]->(n4)" +
278
272
", (n0)-[:REL]->(n5)" +
279
- ", (n1)-[:REL]->(n3)" ,
280
- UNDIRECTED
273
+ ", (n1)-[:REL]->(n3)"
281
274
);
282
275
283
276
TriangleCountResult result = compute (graph );
@@ -300,8 +293,7 @@ void triangleWhenSecondMemberAtEndOfRelChain() {
300
293
", (n1)-[:REL]->(n2)" +
301
294
", (n0)-[:REL]->(n3)" +
302
295
", (n0)-[:REL]->(n4)" +
303
- ", (n1)-[:REL]->(n4)" ,
304
- UNDIRECTED
296
+ ", (n1)-[:REL]->(n4)"
305
297
);
306
298
307
299
TriangleCountResult result = compute (graph );
@@ -325,8 +317,7 @@ void triangleWhenFirstMemberHasMoreNeighbours() {
325
317
", (n0)-[:REL]->(n4)" +
326
318
", (n0)-[:REL]->(n5)" +
327
319
", (n1)-[:REL]->(n4)" +
328
- ", (n1)-[:REL]->(n6)" ,
329
- UNDIRECTED
320
+ ", (n1)-[:REL]->(n6)"
330
321
);
331
322
332
323
TriangleCountResult result = compute (graph );
@@ -354,8 +345,7 @@ void filterMaxDegreeFirstCNode() {
354
345
", (n3)-[:REL]->(n4)" +
355
346
", (n1)-[:REL]->(n6)" +
356
347
", (n0)-[:REL]->(n2)" +
357
- ", (n0)-[:REL]->(n6)" ,
358
- UNDIRECTED
348
+ ", (n0)-[:REL]->(n6)"
359
349
);
360
350
361
351
TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
@@ -387,8 +377,7 @@ void filterMaxDegreeSecondCNode() {
387
377
", (n3)-[:REL]->(n0)" +
388
378
", (n3)-[:REL]->(n4)" +
389
379
", (n3)-[:REL]->(n5)" +
390
- ", (n3)-[:REL]->(n6)" ,
391
- UNDIRECTED
380
+ ", (n3)-[:REL]->(n6)"
392
381
);
393
382
394
383
TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
@@ -420,8 +409,7 @@ void manyTrianglesAndOtherThings() {
420
409
", (h)-[:T]->(i)-[:T]->(j)-[:T]->(k)-[:T]->(e)" +
421
410
", (k)-[:T]->(l)" +
422
411
", (k)-[:T]->(m)-[:T]->(n)-[:T]->(j)" +
423
- ", (o)" ,
424
- UNDIRECTED
412
+ ", (o)"
425
413
);
426
414
427
415
TriangleCountResult result = compute (graph );
@@ -449,16 +437,15 @@ void manyTrianglesAndOtherThings() {
449
437
void testTriangleCountingWithMaxDegree () {
450
438
var graph = fromGdl (
451
439
"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)"
462
449
);
463
450
464
451
TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
@@ -483,16 +470,15 @@ void testTriangleCountingWithMaxDegree() {
483
470
void testTriangleCountingWithMaxDegreeOnUnionGraph () {
484
471
var graph = fromGdl (
485
472
"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)"
496
482
);
497
483
498
484
TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
@@ -513,6 +499,33 @@ void testTriangleCountingWithMaxDegreeOnUnionGraph() {
513
499
assertEquals (1 , result .globalTriangles ());
514
500
}
515
501
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
+
516
529
private TriangleCountResult compute (Graph graph ) {
517
530
TriangleCountStatsConfig config = ImmutableTriangleCountStatsConfig .builder ().build ();
518
531
return compute (graph , config );
@@ -521,4 +534,8 @@ private TriangleCountResult compute(Graph graph) {
521
534
private TriangleCountResult compute (Graph graph , TriangleCountBaseConfig config ) {
522
535
return IntersectingTriangleCount .create (graph , config , Pools .DEFAULT ).compute ();
523
536
}
537
+
538
+ private static Graph fromGdl (String gdl ) {
539
+ return TestSupport .fromGdl (gdl , Orientation .UNDIRECTED ).graph ();
540
+ }
524
541
}
0 commit comments