Skip to content

Commit

Permalink
Removed option to find path with exact depth from ShortestPath
Browse files Browse the repository at this point in the history
It does not make sense to find a shortest path with specified length and ExactDepthPathFinder already provides that functionality.
 - Added further testing for ExactDepthPathFinder.
 - GraphAlgoFactory now uses ExactDepthPathFinder instead of ShortsetPath.
 - Fixed ExactDepthPathFinder not handeling neighbouring node (depth 1).

Fixing imports
  • Loading branch information
burqen committed May 19, 2015
1 parent 3132c99 commit 6884c91
Show file tree
Hide file tree
Showing 8 changed files with 350 additions and 224 deletions.
Expand Up @@ -23,6 +23,7 @@
import org.neo4j.graphalgo.impl.path.AllPaths; import org.neo4j.graphalgo.impl.path.AllPaths;
import org.neo4j.graphalgo.impl.path.AllSimplePaths; import org.neo4j.graphalgo.impl.path.AllSimplePaths;
import org.neo4j.graphalgo.impl.path.Dijkstra; import org.neo4j.graphalgo.impl.path.Dijkstra;
import org.neo4j.graphalgo.impl.path.ExactDepthPathFinder;
import org.neo4j.graphalgo.impl.path.ShortestPath; import org.neo4j.graphalgo.impl.path.ShortestPath;
import org.neo4j.graphalgo.impl.util.DoubleEvaluator; import org.neo4j.graphalgo.impl.util.DoubleEvaluator;
import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Node;
Expand All @@ -37,7 +38,7 @@
* Static factory methods for the recommended implementations of common * Static factory methods for the recommended implementations of common
* graph algorithms for Neo4j. The algorithms exposed here are implementations * graph algorithms for Neo4j. The algorithms exposed here are implementations
* which are tested extensively and also scale on bigger graphs. * which are tested extensively and also scale on bigger graphs.
* *
* @author Mattias Persson * @author Mattias Persson
*/ */
public abstract class GraphAlgoFactory public abstract class GraphAlgoFactory
Expand Down Expand Up @@ -73,7 +74,7 @@ public static PathFinder<Path> allPaths( PathExpander expander, int maxDepth )
{ {
return new AllPaths( maxDepth, expander ); return new AllPaths( maxDepth, expander );
} }

/** /**
* Returns an algorithm which can find all simple paths between two * Returns an algorithm which can find all simple paths between two
* nodes. These returned paths cannot contain loops (i.e. a node cannot * nodes. These returned paths cannot contain loops (i.e. a node cannot
Expand Down Expand Up @@ -107,7 +108,7 @@ public static PathFinder<Path> allSimplePaths( PathExpander expander,
{ {
return new AllSimplePaths( maxDepth, expander ); return new AllSimplePaths( maxDepth, expander );
} }

/** /**
* Returns an algorithm which can find all shortest paths (that is paths * Returns an algorithm which can find all shortest paths (that is paths
* with as short {@link Path#length()} as possible) between two nodes. These * with as short {@link Path#length()} as possible) between two nodes. These
Expand All @@ -130,7 +131,7 @@ public static PathFinder<Path> shortestPath( RelationshipExpander expander, int
* with as short {@link Path#length()} as possible) between two nodes. These * with as short {@link Path#length()} as possible) between two nodes. These
* returned paths cannot contain loops (i.e. a node cannot occur more than * returned paths cannot contain loops (i.e. a node cannot occur more than
* once in any returned path). * once in any returned path).
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param maxDepth the max {@link Path#length()} returned paths are allowed * @param maxDepth the max {@link Path#length()} returned paths are allowed
Expand All @@ -141,13 +142,13 @@ public static PathFinder<Path> shortestPath( PathExpander expander, int maxDepth
{ {
return new ShortestPath( maxDepth, expander ); return new ShortestPath( maxDepth, expander );
} }

/** /**
* Returns an algorithm which can find all shortest paths (that is paths * Returns an algorithm which can find all shortest paths (that is paths
* with as short {@link Path#length()} as possible) between two nodes. These * with as short {@link Path#length()} as possible) between two nodes. These
* returned paths cannot contain loops (i.e. a node cannot occur more than * returned paths cannot contain loops (i.e. a node cannot occur more than
* once in any returned path). * once in any returned path).
* *
* @param expander the {@link RelationshipExpander} to use for expanding * @param expander the {@link RelationshipExpander} to use for expanding
* {@link Relationship}s for each {@link Node}. * {@link Relationship}s for each {@link Node}.
* @param maxDepth the max {@link Path#length()} returned paths are allowed * @param maxDepth the max {@link Path#length()} returned paths are allowed
Expand All @@ -160,13 +161,13 @@ public static PathFinder<Path> shortestPath( RelationshipExpander expander, int
{ {
return new ShortestPath( maxDepth, expander, maxHitCount ); return new ShortestPath( maxDepth, expander, maxHitCount );
} }

/** /**
* Returns an algorithm which can find all shortest paths (that is paths * Returns an algorithm which can find all shortest paths (that is paths
* with as short {@link Path#length()} as possible) between two nodes. These * with as short {@link Path#length()} as possible) between two nodes. These
* returned paths cannot contain loops (i.e. a node cannot occur more than * returned paths cannot contain loops (i.e. a node cannot occur more than
* once in any returned path). * once in any returned path).
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param maxDepth the max {@link Path#length()} returned paths are allowed * @param maxDepth the max {@link Path#length()} returned paths are allowed
Expand All @@ -179,12 +180,12 @@ public static PathFinder<Path> shortestPath( PathExpander expander, int maxDepth
{ {
return new ShortestPath( maxDepth, expander, maxHitCount ); return new ShortestPath( maxDepth, expander, maxHitCount );
} }

/** /**
* Returns an algorithm which can find simple all paths of a certain length * Returns an algorithm which can find simple all paths of a certain length
* between two nodes. These returned paths cannot contain loops (i.e. a node * between two nodes. These returned paths cannot contain loops (i.e. a node
* could not occur more than once in any returned path). * could not occur more than once in any returned path).
* *
* @param expander the {@link RelationshipExpander} to use for expanding * @param expander the {@link RelationshipExpander} to use for expanding
* {@link Relationship}s for each {@link Node}. * {@link Relationship}s for each {@link Node}.
* @param length the {@link Path#length()} returned paths will have, if any * @param length the {@link Path#length()} returned paths will have, if any
Expand All @@ -193,14 +194,14 @@ public static PathFinder<Path> shortestPath( PathExpander expander, int maxDepth
*/ */
public static PathFinder<Path> pathsWithLength( RelationshipExpander expander, int length ) public static PathFinder<Path> pathsWithLength( RelationshipExpander expander, int length )
{ {
return new ShortestPath( length, expander, Integer.MAX_VALUE, true ); return new ExactDepthPathFinder( expander, length, Integer.MAX_VALUE, false );
} }

/** /**
* Returns an algorithm which can find simple all paths of a certain length * Returns an algorithm which can find simple all paths of a certain length
* between two nodes. These returned paths cannot contain loops (i.e. a node * between two nodes. These returned paths cannot contain loops (i.e. a node
* could not occur more than once in any returned path). * could not occur more than once in any returned path).
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Node}. * {@link Relationship}s for each {@link Node}.
* @param length the {@link Path#length()} returned paths will have, if any * @param length the {@link Path#length()} returned paths will have, if any
Expand All @@ -209,20 +210,20 @@ public static PathFinder<Path> pathsWithLength( RelationshipExpander expander, i
*/ */
public static PathFinder<Path> pathsWithLength( PathExpander expander, int length ) public static PathFinder<Path> pathsWithLength( PathExpander expander, int length )
{ {
return new ShortestPath( length, expander, Integer.MAX_VALUE, true ); return new ExactDepthPathFinder( expander, length, Integer.MAX_VALUE, false );
} }

/** /**
* Returns a {@link PathFinder} which uses the A* algorithm to find the * Returns a {@link PathFinder} which uses the A* algorithm to find the
* cheapest path between two nodes. The definition of "cheap" is the lowest * cheapest path between two nodes. The definition of "cheap" is the lowest
* possible cost to get from the start node to the end node, where the cost * possible cost to get from the start node to the end node, where the cost
* is returned from {@code lengthEvaluator} and {@code estimateEvaluator}. * is returned from {@code lengthEvaluator} and {@code estimateEvaluator}.
* These returned paths cannot contain loops (i.e. a node cannot occur more * These returned paths cannot contain loops (i.e. a node cannot occur more
* than once in any returned path). * than once in any returned path).
* *
* See http://en.wikipedia.org/wiki/A*_search_algorithm for more * See http://en.wikipedia.org/wiki/A*_search_algorithm for more
* information. * information.
* *
* @param expander the {@link RelationshipExpander} to use for expanding * @param expander the {@link RelationshipExpander} to use for expanding
* {@link Relationship}s for each {@link Node}. * {@link Relationship}s for each {@link Node}.
* @param lengthEvaluator evaluator that can return the cost represented * @param lengthEvaluator evaluator that can return the cost represented
Expand All @@ -246,10 +247,10 @@ public static PathFinder<WeightedPath> aStar( RelationshipExpander expander,
* is returned from {@code lengthEvaluator} and {@code estimateEvaluator}. * is returned from {@code lengthEvaluator} and {@code estimateEvaluator}.
* These returned paths cannot contain loops (i.e. a node cannot occur more * These returned paths cannot contain loops (i.e. a node cannot occur more
* than once in any returned path). * than once in any returned path).
* *
* See http://en.wikipedia.org/wiki/A*_search_algorithm for more * See http://en.wikipedia.org/wiki/A*_search_algorithm for more
* information. * information.
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param lengthEvaluator evaluator that can return the cost represented * @param lengthEvaluator evaluator that can return the cost represented
Expand All @@ -265,18 +266,18 @@ public static PathFinder<WeightedPath> aStar( PathExpander expander,
{ {
return new AStar( expander, lengthEvaluator, estimateEvaluator ); return new AStar( expander, lengthEvaluator, estimateEvaluator );
} }

/** /**
* Returns a {@link PathFinder} which uses the Dijkstra algorithm to find * Returns a {@link PathFinder} which uses the Dijkstra algorithm to find
* the cheapest path between two nodes. The definition of "cheap" is the * the cheapest path between two nodes. The definition of "cheap" is the
* lowest possible cost to get from the start node to the end node, where * lowest possible cost to get from the start node to the end node, where
* the cost is returned from {@code costEvaluator}. These returned paths * the cost is returned from {@code costEvaluator}. These returned paths
* cannot contain loops (i.e. a node cannot occur more than once in any * cannot contain loops (i.e. a node cannot occur more than once in any
* returned path). * returned path).
* *
* See http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm for more * See http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm for more
* information. * information.
* *
* @param expander the {@link RelationshipExpander} to use for expanding * @param expander the {@link RelationshipExpander} to use for expanding
* {@link Relationship}s for each {@link Node}. * {@link Relationship}s for each {@link Node}.
* @param costEvaluator evaluator that can return the cost represented * @param costEvaluator evaluator that can return the cost represented
Expand All @@ -289,18 +290,18 @@ public static PathFinder<WeightedPath> dijkstra( RelationshipExpander expander,
{ {
return new Dijkstra( expander, costEvaluator ); return new Dijkstra( expander, costEvaluator );
} }

/** /**
* Returns a {@link PathFinder} which uses the Dijkstra algorithm to find * Returns a {@link PathFinder} which uses the Dijkstra algorithm to find
* the cheapest path between two nodes. The definition of "cheap" is the * the cheapest path between two nodes. The definition of "cheap" is the
* lowest possible cost to get from the start node to the end node, where * lowest possible cost to get from the start node to the end node, where
* the cost is returned from {@code costEvaluator}. These returned paths * the cost is returned from {@code costEvaluator}. These returned paths
* cannot contain loops (i.e. a node cannot occur more than once in any * cannot contain loops (i.e. a node cannot occur more than once in any
* returned path). * returned path).
* *
* See http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm for more * See http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm for more
* information. * information.
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param costEvaluator evaluator that can return the cost represented * @param costEvaluator evaluator that can return the cost represented
Expand All @@ -313,13 +314,13 @@ public static PathFinder<WeightedPath> dijkstra( PathExpander expander,
{ {
return new Dijkstra( expander, costEvaluator ); return new Dijkstra( expander, costEvaluator );
} }

/** /**
* See {@link #dijkstra(RelationshipExpander, CostEvaluator)}. * See {@link #dijkstra(RelationshipExpander, CostEvaluator)}.
* *
* Uses a cost evaluator which uses the supplied property key to * Uses a cost evaluator which uses the supplied property key to
* represent the cost (values of type <bold>double</bold>). * represent the cost (values of type <bold>double</bold>).
* *
* @param expander the {@link RelationshipExpander} to use for expanding * @param expander the {@link RelationshipExpander} to use for expanding
* {@link Relationship}s for each {@link Node}. * {@link Relationship}s for each {@link Node}.
* @param relationshipPropertyRepresentingCost the property to represent cost * @param relationshipPropertyRepresentingCost the property to represent cost
Expand All @@ -332,13 +333,13 @@ public static PathFinder<WeightedPath> dijkstra( RelationshipExpander expander,
{ {
return dijkstra( expander, new DoubleEvaluator( relationshipPropertyRepresentingCost ) ); return dijkstra( expander, new DoubleEvaluator( relationshipPropertyRepresentingCost ) );
} }

/** /**
* See {@link #dijkstra(RelationshipExpander, CostEvaluator)}. * See {@link #dijkstra(RelationshipExpander, CostEvaluator)}.
* *
* Uses a cost evaluator which uses the supplied property key to * Uses a cost evaluator which uses the supplied property key to
* represent the cost (values of type <bold>double</bold>). * represent the cost (values of type <bold>double</bold>).
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param relationshipPropertyRepresentingCost the property to represent cost * @param relationshipPropertyRepresentingCost the property to represent cost
Expand All @@ -351,13 +352,13 @@ public static PathFinder<WeightedPath> dijkstra( PathExpander expander,
{ {
return dijkstra( expander, new DoubleEvaluator( relationshipPropertyRepresentingCost ) ); return dijkstra( expander, new DoubleEvaluator( relationshipPropertyRepresentingCost ) );
} }

/** /**
* See {@link #dijkstra(RelationshipExpander, CostEvaluator)}. * See {@link #dijkstra(RelationshipExpander, CostEvaluator)}.
* *
* Uses a cost evaluator which uses the supplied property key to * Uses a cost evaluator which uses the supplied property key to
* represent the cost (values of type <bold>double</bold>). * represent the cost (values of type <bold>double</bold>).
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param stateFactory initial state for the traversal branches. * @param stateFactory initial state for the traversal branches.
Expand All @@ -373,10 +374,10 @@ public static PathFinder<WeightedPath> dijkstra( PathExpander expander,


/** /**
* See {@link #dijkstra(RelationshipExpander, CostEvaluator)}. * See {@link #dijkstra(RelationshipExpander, CostEvaluator)}.
* *
* Uses a cost evaluator which uses the supplied property key to * Uses a cost evaluator which uses the supplied property key to
* represent the cost (values of type <bold>double</bold>). * represent the cost (values of type <bold>double</bold>).
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param stateFactory initial state for the traversal branches. * @param stateFactory initial state for the traversal branches.
Expand All @@ -389,13 +390,13 @@ public static PathFinder<WeightedPath> dijkstra( PathExpander expander,
{ {
return new Dijkstra( expander, stateFactory, costEvaluator ); return new Dijkstra( expander, stateFactory, costEvaluator );
} }

/** /**
* See {@link #dijkstra(RelationshipExpander, CostEvaluator)}. * See {@link #dijkstra(RelationshipExpander, CostEvaluator)}.
* *
* Uses a cost evaluator which uses the supplied property key to * Uses a cost evaluator which uses the supplied property key to
* represent the cost (values of type <bold>double</bold>). * represent the cost (values of type <bold>double</bold>).
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param stateFactory initial state for the traversal branches. * @param stateFactory initial state for the traversal branches.
Expand All @@ -412,10 +413,10 @@ public static PathFinder<WeightedPath> dijkstra( PathExpander expander,


/** /**
* See {@link #dijkstra(RelationshipExpander, CostEvaluator)}. * See {@link #dijkstra(RelationshipExpander, CostEvaluator)}.
* *
* Uses a cost evaluator which uses the supplied property key to * Uses a cost evaluator which uses the supplied property key to
* represent the cost (values of type <bold>double</bold>). * represent the cost (values of type <bold>double</bold>).
* *
* @param expander the {@link PathExpander} to use for expanding * @param expander the {@link PathExpander} to use for expanding
* {@link Relationship}s for each {@link Path}. * {@link Relationship}s for each {@link Path}.
* @param stateFactory initial state for the traversal branches. * @param stateFactory initial state for the traversal branches.
Expand Down
Expand Up @@ -19,13 +19,6 @@
*/ */
package org.neo4j.graphalgo.impl.path; package org.neo4j.graphalgo.impl.path;


import static org.neo4j.graphdb.traversal.Evaluators.atDepth;
import static org.neo4j.graphdb.traversal.Evaluators.toDepth;
import static org.neo4j.kernel.StandardExpander.toPathExpander;
import static org.neo4j.kernel.Traversal.bidirectionalTraversal;
import static org.neo4j.kernel.Traversal.traversal;
import static org.neo4j.kernel.Uniqueness.RELATIONSHIP_GLOBAL;

import org.neo4j.graphalgo.impl.util.LiteDepthFirstSelector; import org.neo4j.graphalgo.impl.util.LiteDepthFirstSelector;
import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.PathExpander; import org.neo4j.graphdb.PathExpander;
Expand All @@ -35,6 +28,13 @@
import org.neo4j.graphdb.traversal.TraversalBranch; import org.neo4j.graphdb.traversal.TraversalBranch;
import org.neo4j.graphdb.traversal.TraversalDescription; import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser; import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.graphdb.traversal.Uniqueness;

import static org.neo4j.graphdb.traversal.Evaluators.atDepth;
import static org.neo4j.graphdb.traversal.Evaluators.toDepth;
import static org.neo4j.kernel.StandardExpander.toPathExpander;
import static org.neo4j.kernel.Traversal.bidirectionalTraversal;
import static org.neo4j.kernel.Traversal.traversal;


/** /**
* Tries to find paths in a graph from a start node to an end node where the * Tries to find paths in a graph from a start node to an end node where the
Expand All @@ -53,39 +53,38 @@ public class ExactDepthPathFinder extends TraversalPathFinder
private final PathExpander expander; private final PathExpander expander;
private final int onDepth; private final int onDepth;
private final int startThreshold; private final int startThreshold;
private final Uniqueness uniqueness;


public ExactDepthPathFinder( RelationshipExpander expander, int onDepth, public ExactDepthPathFinder( RelationshipExpander expander, int onDepth, int startThreshold, boolean allowLoops )
int startThreshold )
{ {
this( toPathExpander( expander ), onDepth, startThreshold ); this( toPathExpander( expander ), onDepth, startThreshold, allowLoops );
} }


public ExactDepthPathFinder( PathExpander expander, int onDepth, int startThreshold ) public ExactDepthPathFinder( PathExpander expander, int onDepth, int startThreshold, boolean allowLoops )
{ {
this.expander = expander; this.expander = expander;
this.onDepth = onDepth; this.onDepth = onDepth;
this.startThreshold = startThreshold; this.startThreshold = startThreshold;
this.uniqueness = allowLoops ? Uniqueness.RELATIONSHIP_GLOBAL : Uniqueness.NODE_PATH;
} }


@Override @Override
protected Traverser instantiateTraverser( Node start, Node end ) protected Traverser instantiateTraverser( Node start, Node end )
{ {
TraversalDescription side = traversal().breadthFirst().expand( expander ).uniqueness( RELATIONSHIP_GLOBAL ).order( TraversalDescription side =
new BranchOrderingPolicy() traversal().breadthFirst().uniqueness( uniqueness ).order( new BranchOrderingPolicy()
{ {
@Override
public BranchSelector create( TraversalBranch startSource, PathExpander expander ) public BranchSelector create( TraversalBranch startSource, PathExpander expander )
{ {
return new LiteDepthFirstSelector( startSource, return new LiteDepthFirstSelector( startSource, startThreshold, expander );
startThreshold, expander );
} }
} ); } );

return bidirectionalTraversal().startSide( side.expand( expander ).evaluator( toDepth( onDepth / 2 ) ) )
return bidirectionalTraversal() .endSide( side.expand( expander.reverse() ).evaluator( toDepth( onDepth - onDepth / 2 ) ) )
.startSide( side.evaluator( toDepth( onDepth/2 ) ) )
.endSide( side.evaluator( toDepth( onDepth-onDepth/2 ) ) )
.collisionEvaluator( atDepth( onDepth ) ) .collisionEvaluator( atDepth( onDepth ) )
// TODO Level side selector will make the traversal return wrong result, why? // TODO Level side selector will make the traversal return wrong result, why?
// .sideSelector( SideSelectorPolicies.LEVEL, onDepth ) // .sideSelector( SideSelectorPolicies.LEVEL, onDepth )
.traverse( start, end ); .traverse( start, end );
} }
} }

0 comments on commit 6884c91

Please sign in to comment.