Traversal

com.phasmidsoftware.visitor.core.Traversal
object Traversal

The traversal engine. Knows only about Frontier, Neighbours, Evaluable, VisitedSet, Visitor, and CostUpdate. Zero domain knowledge.

The choice of frontier F determines the traversal order: F = Queue → BFS F = Stack → DFS F = PrioQueue → best-first (requires Ordering[V] in scope)

Two visitor events are fired during traversal:

  • visit(v) — when a vertex is settled (dequeued/popped)
  • discover(v, cameFrom) — when a vertex is first seen as a neighbour

NOTE that there are three independent traversal engines which should be maintained in parallel as much as possible: traverse, traverseTree, and dfs.

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any
Self type
Traversal.type

Members list

Value members

Concrete methods

def bestFirst[V, R, J <: Appendable[(V, Option[R])]](start: V, visitor: Visitor[V, R, J], goal: V => Boolean = ...)(using evidence$1: Ordering[V], nbrs: GraphNeighbours[V], ev: Evaluable[V, R], vs: VisitedSet[V], tracer: Tracer[V] = ...): Visitor[V, R, J]

Best-first / min-priority-queue traversal. Smallest element dequeued first. Requires Ordering[V] in scope.

Best-first / min-priority-queue traversal. Smallest element dequeued first. Requires Ordering[V] in scope.

Value parameters

goal

optional early-termination predicate. Defaults to never stopping early.

Attributes

def bestFirstMax[V, R, J <: Appendable[(V, Option[R])]](start: V, visitor: Visitor[V, R, J], goal: V => Boolean = ...)(using evidence$1: Ordering[V], nbrs: GraphNeighbours[V], ev: Evaluable[V, R], vs: VisitedSet[V], tracer: Tracer[V] = ...): Visitor[V, R, J]

Best-first / max-priority-queue traversal. Largest element dequeued first. Requires Ordering[V] in scope.

Best-first / max-priority-queue traversal. Largest element dequeued first. Requires Ordering[V] in scope.

Value parameters

goal

optional early-termination predicate. Defaults to never stopping early.

Attributes

def bestFirstWeighted[W, R, J <: Appendable[(W, Option[R])]](start: W, visitor: Visitor[W, R, J], goal: W => Boolean = ...)(using evidence$1: Ordering[W], nbrs: GraphNeighbours[W], ev: Evaluable[W, R], vs: VisitedSet[W], cu: CostUpdate[W, IndexedPrioQueue], initial: IndexedPrioQueue[W], tracer: Tracer[W] = ...): Visitor[W, R, J]

Best-first traversal with an explicit CostUpdate — for Dijkstra and Prim.

Best-first traversal with an explicit CostUpdate — for Dijkstra and Prim.

The frontier element type W is typically (E, V) where E is the cost type and V is the vertex type. The caller supplies:

  • start: the seed element, e.g. (zero, startVertex)
  • a given IndexedPrioQueue[W] = IndexedPrioQueue.empty[W] (always empty; traverse seeds the frontier from start's neighbours)
  • a given CostUpdate[W, IndexedPrioQueue] that calls decreaseKey after each settle
  • Neighbours[W, W] expanding (cost, vertex) to (newCost, neighbour) pairs

NOTE: discover is not called in bestFirstWeighted — the came-from relationship for weighted traversals is already tracked via the pred map inside WeightedTraversal.CostUpdate.

Value parameters

goal

optional early-termination predicate.

Attributes

def bfs[V, R, J <: Appendable[(V, Option[R])]](start: V, visitor: Visitor[V, R, J], goal: V => Boolean = ...)(using nbrs: GraphNeighbours[V], ev: Evaluable[V, R], vs: VisitedSet[V], tracer: Tracer[V] = ...): Visitor[V, R, J]

Breadth-first search traversal.

Breadth-first search traversal.

discover(neighbour, node) is called for each unvisited neighbour before it is offered to the frontier, recording the came-from relationship at discovery time.

Value parameters

goal

optional early-termination predicate. Defaults to never stopping early.

Attributes

def dfs[V, R, J <: Appendable[(V, Option[R])]](start: V, visitor: Visitor[V, R, J], order: DfsOrder = ..., goal: V => Boolean = ...)(using nbrs: GraphNeighbours[V], ev: Evaluable[V, R], vs: VisitedSet[V], tracer: Tracer[V] = ...): Visitor[V, R, J]

Depth-first search with configurable pre- or post-order recording.

Depth-first search with configurable pre- or post-order recording.

The internal stack holds Either[V, V] frames:

  • Left(v) means "expand v — push its children and a record frame"
  • Right(v) means "record v in the visitor now"

Pre-order: record before expanding → Right(v) on top, visited first. Post-order: record after expanding → children expanded before v is recorded.

discover(child, node) is called for each unvisited child at expand time (the Left(node) branch), before the child frames are pushed to the stack. This records the came-from relationship at the point of discovery.

The goal predicate is checked on Right (record) frames — i.e. after a node is visited. Traversal halts after recording the first node satisfying goal; its remaining siblings and their subtrees are not visited.

Value parameters

goal

optional early-termination predicate. Defaults to never stopping early.

order

DfsOrder.Pre (default) or DfsOrder.Post

Attributes

def traverse[V, R, J <: Appendable[(V, Option[R])], F[_]](start: V, visitor: Visitor[V, R, J], goal: V => Boolean = ...)(using nbrs: Neighbours[V, V], ev: Evaluable[V, R], vs: VisitedSet[V], fr: Frontier[F], cu: CostUpdate[V, F], initial: F[V], tracer: Tracer[V] = ...): Visitor[V, R, J]

Traverses a (homogeneous) graph structure starting from a given node, visiting nodes iteratively and accumulating results into a visitor.

Traverses a (homogeneous) graph structure starting from a given node, visiting nodes iteratively and accumulating results into a visitor.

After each node's neighbours are offered to the frontier, cu.update is called to apply any priority improvements (e.g. decreaseKey in Dijkstra/Prim). For DFS and BFS the default no-op CostUpdate is resolved automatically.

The start node is always visited and recorded first, before any goal check or frontier expansion. If goal(start) is true, traversal stops immediately after recording the start node — no neighbours are expanded.

For all subsequent nodes, traversal stops after recording the first node for which goal(node) returns true — that node is recorded in the journal but its neighbours are not expanded.

discover(neighbour, node) is called for each unvisited neighbour before it is offered to the frontier, recording the came-from relationship at discovery time.

Value parameters

cu

Typeclass for post-settle priority updates (no-op for DFS/BFS).

ev

Typeclass defining how to extract results from each node.

fr

Typeclass representing the frontier structure used for traversal.

goal

A predicate that, when true for a visited node, halts the traversal after recording that node. Defaults to never stopping early.

initial

The initial empty frontier structure for the traversal.

nbrs

Typeclass providing the neighbours for each node.

start

The starting node where the traversal begins.

tracer

Typeclass for tracing the primary parametric type (V).

visitor

An instance of Visitor that collects results during traversal.

vs

Typeclass representing the set of visited nodes to prevent revisiting.

Attributes

Returns

A Visitor instance containing the accumulated results after traversal completes.

def traverseTree[H, V, R, J <: Appendable[(V, Option[R])]](start: H, visitor: Visitor[V, R, J], order: DfsOrder = ..., goal: V => Boolean = ...)(using rootNbrs: Neighbours[H, V], graphNbrs: Neighbours[V, V], ev: Evaluable[V, R], vs: VisitedSet[V], tracer: Tracer[V] = ...): Visitor[V, R, J]

Traverses a tree-like structure starting from a given root node, visiting nodes as specified by the provided Visitor.

Traverses a tree-like structure starting from a given root node, visiting nodes as specified by the provided Visitor.

NOTE: traverseTree does not visit the root start itself (there is no Evaluable[H, R] in scope for H), so the visitor is unseeded before the loop begins — unlike traverse where visitor.visit(start) is called first.

The order parameter controls pre- or post-order recording, using the same Either-tagged stack mechanism as dfs:

  • Left(v) — expand node: mark visited, push children and a record frame
  • Right(v) — record node: call visitor.visit(v)

The seed step uses rootNbrs (H → V) to get the initial children from the root. All subsequent steps use graphNbrs (V → V).

Traversal stops after recording the first V node for which goal(node) returns true. The goal node is recorded in the journal but its neighbours are not expanded.

NOTE: discover is not called in traverseTree — the tree structure implies the came-from relationship is already known from the tree shape.

Value parameters

ev

A typeclass representing how to evaluate a node and extract its result.

goal

A predicate that, when true for a visited node, halts the traversal after recording that node. Defaults to never stopping early.

graphNbrs

A typeclass instance providing neighbour nodes for the graph structure.

order

DfsOrder.Pre (default) or DfsOrder.Post.

rootNbrs

A typeclass instance providing neighbour nodes for the root structure.

start

The root node where the traversal begins.

visitor

An instance of Visitor that accumulates results during the traversal.

vs

A typeclass representing a set of visited nodes to prevent revisits.

Attributes

Returns

A Visitor instance containing the accumulated results of the traversal.