private void testCIsReturnedOnDepthTwo( TraversalDescription description ) { try ( Transaction transaction = beginTx() ) { description = description.expand( PathExpanders.forTypeAndDirection( ONE, OUTGOING ) ); int i = 0; for ( Path position : description.traverse( node( "A" ) ) ) { assertEquals( i++, position.length() ); } } } }
private MonoDirectionalTraversalDescription( PathExpander expander, UniquenessFactory uniqueness, Object uniquenessParameter, PathEvaluator evaluator, InitialBranchState initialState, BranchOrderingPolicy branchOrdering, Comparator<? super Path> sorting, Collection<Node> endNodes, Supplier<? extends Resource> statementSupplier ) { this.expander = expander; this.uniqueness = uniqueness; this.uniquenessParameter = uniquenessParameter; this.evaluator = evaluator; this.branchOrdering = branchOrdering; this.sorting = sorting; this.endNodes = endNodes; this.initialState = initialState; this.statementSupplier = statementSupplier; }
PathExpanders.allTypesAndDirections(), PathInterestFactory.all(), Uniqueness.NODE_PATH, }, PathExpanders.allTypesAndDirections(), PathInterestFactory.allShortest(), Uniqueness.NODE_PATH, PathExpanders.forDirection( Direction.OUTGOING ), PathInterestFactory.all( ), Uniqueness.NODE_PATH, PathExpanders.allTypesAndDirections(), PathInterestFactory.all(), Uniqueness.NODE_GLOBAL, }, PathExpanders.allTypesAndDirections(), PathInterestFactory.all(), Uniqueness.RELATIONSHIP_GLOBAL,
/** * Get a path expander representing this input. * * @return path expander. */ public PathExpander getExpander() { if (typesAndDirections.isEmpty()) { return PathExpanders.forDirection(direction == null ? Direction.BOTH : direction); } //Maybe there's a less ugly way of doing this using Neo4j APIs, who knows: if (typesAndDirections.size() == 2) { return PathExpanders.forTypeAndDirection( (RelationshipType) typesAndDirections.get(0), (Direction) typesAndDirections.get(1) ); } return PathExpanders.forTypesAndDirections( (RelationshipType) typesAndDirections.get(0), (Direction) typesAndDirections.get(1), (RelationshipType) typesAndDirections.get(2), (Direction) typesAndDirections.get(3), typesAndDirections.size() > 3 ? typesAndDirections.subList(4, typesAndDirections.size()).toArray() : new Object[0] ); }
@SuppressWarnings( "unchecked" ) public ListRepresentation getNodeRelationships( long nodeId, RelationshipDirection direction, Collection<String> types ) throws NodeNotFoundException { Node node = node( nodeId ); PathExpander expander; if ( types.isEmpty() ) { expander = PathExpanders.forDirection( direction.internal ); } else { PathExpanderBuilder builder = PathExpanderBuilder.empty(); for ( String type : types ) { builder = builder.add( RelationshipType.withName( type ), direction.internal ); } expander = builder.build(); } return RelationshipRepresentation.list( expander.expand( Paths.singleNodePath( node ), BranchState.NO_STATE ) ); }
@Test public void testExactDepthPathsReturnsNoLoops() { // Layout: // // (a)-->(b)==>(c)-->(e) // ^ / // \ v // (d) // graph.makeEdgeChain( "a,b,c,d,b,c,e" ); Node a = graph.getNode( "a" ); Node e = graph.getNode( "e" ); assertPaths( GraphAlgoFactory.pathsWithLength( PathExpanders.forType( MyRelTypes.R1 ), 3 ).findAllPaths( a, e ), "a,b,c,e", "a,b,c,e" ); assertPaths( GraphAlgoFactory.pathsWithLength( PathExpanders.forType( MyRelTypes.R1 ), 4 ).findAllPaths( a, e ), "a,b,d,c,e" ); assertPaths( GraphAlgoFactory.pathsWithLength( PathExpanders.forType( MyRelTypes.R1 ), 6 ).findAllPaths( a, e ) ); }
@Test public void canCreateExpanderWithMultipleTypesAndDirections() { assertNotNull( PathExpanders.forTypesAndDirections( T1, INCOMING, T2, OUTGOING, T3, BOTH ) ); } }
final Node c = graph.getNode( "c" ); final Set<Node> allowedNodes = new HashSet<>( Arrays.asList( a, b, c ) ); final PathFinder<Path> finder = new ShortestPath( 100, PathExpanders.forDirection( OUTGOING ) )
@Test public void mirroredTraversalReversesInitialState() { /* * (a)-->(b)-->(c)-->(d) */ createGraph( "a TO b", "b TO c", "c TO d" ); BranchCollisionPolicy collisionPolicy = ( evaluator, pathPredicate ) -> new StandardBranchCollisionDetector( null, null ) { @Override protected boolean includePath( Path path, TraversalBranch startPath, TraversalBranch endPath ) { assertEquals( 0, startPath.state() ); assertEquals( 10, endPath.state() ); return true; } }; Iterables.count( getGraphDb().bidirectionalTraversalDescription() // Just make up a number bigger than the path length (in this case 10) so that we can assert it in // the collision policy later .mirroredSides( getGraphDb().traversalDescription().uniqueness( NODE_PATH ).expand( PathExpanders.forType( to ), new InitialBranchState.State<>( 0, 10 ) ) ) .collisionPolicy( collisionPolicy ) .traverse( getNodeWithName( "a" ), getNodeWithName( "d" ) ) ); } }
@Test public void unfortunateRelationshipOrderingInTriangle() { /* * (b) * ^ \ * / v * (a)---->(c) * * Relationships are created in such a way that they are iterated in the worst order, * i.e. (S) a-->b, (E) c<--b, (S) a-->c */ graph.makeEdgeChain( "a,b,c" ); graph.makeEdgeChain( "a,c" ); final Node a = graph.getNode( "a" ); final Node c = graph.getNode( "c" ); testShortestPathFinder( finder -> assertPathDef( finder.findSinglePath( a, c ), "a", "c" ), PathExpanders.forTypeAndDirection( R1, OUTGOING ), 2 ); testShortestPathFinder( finder -> assertPathDef( finder.findSinglePath( c, a ), "c", "a" ), PathExpanders.forTypeAndDirection( R1, INCOMING ), 2 ); }
private PathFinder<Path> newFinder() { return new ExactDepthPathFinder( PathExpanders.allTypesAndDirections(), 4, 4, true ); }
@Test public void shouldHandleDirectionalGraph() { // ALL DIRECTED from (a) towards (g) // (b) ----------------- (c) length 3 // / \ // (a) - (h) - (i) - (j) - (k) - (g) length 5 // \ / // (d) - (e) ------------ (f) length 4 graph.makeEdgeChain( "a,b,c,g" ); graph.makeEdgeChain( "a,d,e,f,g" ); graph.makeEdgeChain( "a,h,i,j,k,g" ); Node a = graph.getNode( "a" ); Node g = graph.getNode( "g" ); assertPaths( new ExactDepthPathFinder( PathExpanders.forDirection( Direction.OUTGOING ), 3, Integer.MAX_VALUE, false ).findAllPaths( a, g ), "a,b,c,g" ); assertPaths( new ExactDepthPathFinder( PathExpanders.forDirection( Direction.OUTGOING ), 4, Integer.MAX_VALUE, false ).findAllPaths( a, g ), "a,d,e,f,g" ); assertPaths( new ExactDepthPathFinder( PathExpanders.forDirection( Direction.OUTGOING ), 5, Integer.MAX_VALUE, false ).findAllPaths( a, g ), "a,h,i,j,k,g" ); }
@Test public void makeSureShortestPathsReturnsNoLoops() { // Layout: // // (a)-->(b)==>(c)-->(e) // ^ / // \ v // (d) // graph.makeEdgeChain( "a,b,c,d,b,c,e" ); testShortestPathFinder( finder -> { final Node a = graph.getNode( "a" ); final Node e = graph.getNode( "e" ); assertPaths( finder.findAllPaths( a, e ), "a,b,c,e", "a,b,c,e" ); }, PathExpanders.forTypeAndDirection( R1, BOTH ), 6 ); }
protected PathFinder<Path> instantiatePathFinder( int maxDepth ) { return allPaths( PathExpanders.allTypesAndDirections(), maxDepth ); }
@Test public void testExactDepthPathsLoopsAllowed() { // Layout: // // (a)-->(b)==>(c)-->(e) // ^ / // \ v // (d) // graph.makeEdgeChain( "a,b,c,d,b,c,e" ); Node a = graph.getNode( "a" ); Node e = graph.getNode( "e" ); assertPaths( new ExactDepthPathFinder( PathExpanders.forDirection( Direction.OUTGOING ), 6, Integer.MAX_VALUE, true ).findAllPaths( a, e ), "a,b,c,d,b,c,e" ); } }
@Test public void testDirectedFinder() { // Layout: // // (a)->(b)->(c)->(d)->(e)->(f)-------\ // \ v // >(g)->(h)->(i)->(j)->(k)->(l)->(m) // graph.makeEdgeChain( "a,b,c,d,e,f,m" ); graph.makeEdgeChain( "a,g,h,i,j,k,l,m" ); testShortestPathFinder( finder -> assertPaths( finder.findAllPaths( graph.getNode( "a" ), graph.getNode( "j" ) ), "a,g,h,i,j" ), PathExpanders.forTypeAndDirection( R1, OUTGOING ), 4 ); }
protected PathFinder<Path> instantiatePathFinder( int maxDepth ) { return GraphAlgoFactory.allSimplePaths( PathExpanders.allTypesAndDirections(), maxDepth ); }
@SuppressWarnings( "unchecked" ) public ListRepresentation getNodeRelationships( long nodeId, RelationshipDirection direction, Collection<String> types ) throws NodeNotFoundException { Node node = node( nodeId ); PathExpander expander; if ( types.isEmpty() ) { expander = PathExpanders.forDirection( direction.internal ); } else { PathExpanderBuilder builder = PathExpanderBuilder.empty(); for ( String type : types ) { builder = builder.add( RelationshipType.withName( type ), direction.internal ); } expander = builder.build(); } return RelationshipRepresentation.list( expander.expand( Paths.singleNodePath( node ), BranchState.NO_STATE ) ); }
@Test public void testSimplestGraph() { // Layout: // __ // / \ // (s) (t) // \__/ graph.makeEdge( "s", "t" ); graph.makeEdge( "s", "t" ); testShortestPathFinder( finder -> { final Iterable<Path> paths = finder.findAllPaths( graph.getNode( "s" ), graph.getNode( "t" ) ); assertPaths( paths, "s,t", "s,t" ); assertPaths( asList( finder.findSinglePath( graph.getNode( "s" ), graph.getNode( "t" ) ) ), "s,t" ); }, PathExpanders.forTypeAndDirection( R1, BOTH ), 1 ); }
@Parameters public static Collection<Object[]> data() { return Arrays.asList( new Object[][] { { GraphAlgoFactory.aStar( PathExpanders.allTypesAndDirections(), doubleCostEvaluator( "length" ), ESTIMATE_EVALUATOR ) }, { new TraversalAStar( PathExpanders.allTypesAndDirections(), doubleCostEvaluator( "length" ), ESTIMATE_EVALUATOR ) } } ); }