Path Generators
A generator is the algorithm that decides which edge to take at each step of the graph traversal. Each generator (except new_york_street_sweeper) is paired with a stop condition that determines when to stop.
DSL syntax
Generators are specified as strings in the format:
generator_name(stop_condition)
Generator names are case-insensitive. Both snake_case and camelCase forms are accepted. Multiple generators can be chained by separating them with whitespace.
random
Randomly walks the graph by selecting uniformly from available outgoing edges at each vertex.
Syntax: random(condition) or random_path(condition) or randompath(condition)
Algorithm:
- At a vertex: collect all outgoing edges that pass their guards. Pick one uniformly at random.
- At an edge: move to the target vertex.
Characteristics:
- Simple and fast
- No bias toward unvisited elements
- May revisit the same areas many times before reaching full coverage
- Good for smoke testing and exploring common paths
Example:
random(edge_coverage(100))
random(length(200))
random(vertex_coverage(80) or time_duration(60))
quick_random
A smarter random walk that steers toward unvisited areas using shortest-path computation.
Syntax: quick_random(condition) or quick_random_path(condition) or quickrandompath(condition)
Algorithm:
- On first step: collect all elements in the model, shuffle them.
- Maintain a target element. If the target is reached or not yet set, pick the least-visited element from the shuffled list.
- Use Floyd-Warshall shortest-path distances and A* navigation to move toward the target.
- Remove visited elements from the target list.
Characteristics:
- Significantly faster at achieving full coverage than pure random
- Biased toward unvisited elements
- Uses pre-computed shortest paths (Floyd-Warshall) for efficient navigation
- Good default choice for coverage-based testing
Example:
quick_random(edge_coverage(100))
quick_random(vertex_coverage(100))
weighted_random
Random walk where edges have weights that control selection probability.
Syntax: weighted_random(condition) or weighted_random_path(condition) or weightedrandompath(condition)
Algorithm:
- At a vertex: collect available outgoing edges with their weights.
- Edges with weight > 0 are selected with probability proportional to their weight.
- Edges with weight 0 share the remaining probability equally.
- At an edge: select uniformly from available next elements.
Weight rules:
- Weights are defined on edges in the model (the
weightfield, values 0.0 to 1.0) - The sum of all outgoing edge weights from a vertex must not exceed 1.0
- Edges with weight 0 get equal shares of
(1.0 - sum_of_weights) - If all weights are 0, all edges are equally likely
Example: If a vertex has three outgoing edges with weights 0.7, 0.2, and 0:
- Edge 1 is selected 70% of the time
- Edge 2 is selected 20% of the time
- Edge 3 is selected 10% of the time (the remaining probability)
weighted_random(edge_coverage(100))
weighted_random(length(500))
a_star
Directed pathfinding that navigates toward a specific target element using the A* algorithm.
Syntax: a_star(condition) or astar(condition) or astarpath(condition)
Algorithm:
- Extract target elements from the stop condition (works with
reached_vertex,reached_edge,reached_shared_state). - Use Floyd-Warshall pre-computed distances to find the nearest target.
- At each step, take the next step on the shortest path toward that target.
Characteristics:
- Deterministic shortest path to the target
- Requires a stop condition that defines target elements
- Ideal for “navigate to a specific state” scenarios
- Often used in combined generators: random exploration followed by directed navigation
Example:
a_star(reached_vertex(v_Checkout))
a_star(reached_edge(e_SubmitOrder))
a_star(reached_shared_state(LOGGED_IN))
shortest_all_paths
Computes an Eulerian path that traverses every edge exactly once (if the graph permits), then follows it deterministically.
Syntax: shortest_all_paths(condition) or shortestallpaths(condition)
Algorithm:
- On first step: compute an Eulerian trail from the current position.
- Follow the pre-computed trail step by step.
Characteristics:
- Deterministic: same graph always produces the same path
- Visits every edge exactly once (if the graph is Eulerian or semi-Eulerian)
- Fails if the graph does not have an Eulerian path
- Efficient: computes the path once, then just follows it
Requirements:
- The graph must be connected
- The graph must be Eulerian (all vertices have equal in-degree and out-degree) or semi-Eulerian (exactly two vertices have unequal degrees)
Example:
shortest_all_paths(edge_coverage(100))
predefined_path
Follows a predetermined sequence of edges defined in the model.
Syntax: predefined_path(condition) or predefinedpath(condition)
Algorithm:
- Read the
predefinedPathEdgeIdsarray from the model. - At each vertex: take the next edge from the predefined sequence.
- At each edge: move to the target vertex.
- Stop when the sequence is exhausted.
Characteristics:
- Fully deterministic: the path is defined in the model
- No randomness at all
- Useful for regression testing specific known paths
- Fails if the next predefined edge is not available from the current vertex
Example:
predefined_path(predefined_path)
predefined_path(length(20))
new_york_street_sweeper
Computes the optimal route that visits every edge at least once (the Directed Chinese Postman Problem) and follows it.
Syntax: new_york_street_sweeper() or newyorkstreetsweeper()
This generator takes no stop condition and no parameters. It terminates when the computed path is exhausted.
Algorithm:
- Check that the graph is strongly connected.
- Compute vertex polarities (out-degree minus in-degree).
- If all polarities are zero, the graph is Eulerian — compute the Euler circuit directly.
- Otherwise, find the minimum-cost set of edges to duplicate using BFS shortest paths and the Hungarian algorithm (min-cost bipartite matching).
- Augment the graph with the duplicate edges.
- Compute an Euler circuit on the augmented graph using Hierholzer’s algorithm.
Characteristics:
- Optimal: minimizes the number of duplicate edge traversals
- Deterministic: same graph always produces the same path
- Covers every edge at least once (some may be traversed more than once if the graph is not Eulerian)
- Ignores guards and actions: this generator skips action execution and ignores edge guards, treating the graph as a pure structure
- Requires the graph to be strongly connected
- Emits warnings to stderr for edges with guards, actions, non-unit weights, or missing source vertices
Example:
new_york_street_sweeper()
Combined generators
Multiple generators can be chained in a single string, separated by whitespace. They run sequentially: the first generator runs until its stop condition is fulfilled, then the second takes over from wherever the first stopped, and so on.
Syntax:
generator1(condition1) generator2(condition2) [generator3(condition3) ...]
Example:
random(length(20)) quick_random(edge_coverage(100)) a_star(reached_vertex(v_End))
This runs three phases:
- Random walk for 20 steps (warm-up)
- Quick random until all edges are covered
- A* navigation to
v_End
Summary table
| Generator | Deterministic | Needs stop condition | Respects guards | Special behavior |
|---|---|---|---|---|
random | No | Yes | Yes | |
quick_random | No | Yes | Yes | Steers toward unvisited elements |
weighted_random | No | Yes | Yes | Uses edge weights for selection |
a_star | Yes | Yes (with target) | Yes | Shortest path to target |
shortest_all_paths | Yes | Yes | Yes | Requires Eulerian graph |
predefined_path | Yes | Yes | Yes | Path defined in model |
new_york_street_sweeper | Yes | No | No | Skips actions, optimal edge coverage |