Skip to content

AllShortestPaths

relationalai.semantics.std.path

Selects every shortest matching path per group. Built by PathPattern.all_shortest.

Methods

.per()

AllShortestPaths.per(*args: Value) -> AllShortestPaths

Group the matching paths.

AllShortestPaths.paths and AllShortestPaths.count return and count (respectively) paths that have the shortest length, where shortest is determined per group - this call defines the groups. Required before .count() or .paths().

Currently the only supported grouping is the pattern’s endpoint pair, .per(initial_node, final_node) with the pattern’s initial and final endpoint identifiers in that order; any other grouping raises.

Returns:

  • AllShortestPaths - This selector (self), to allow chaining .paths() or .count().

Raises:

  • relationalai.util.error.RAIException - PathPerAppliedTwiceError if .per(...) has already been applied to this selector.

.paths()

AllShortestPaths.paths() -> DerivedColumn

Return every shortest PathTraversal per group.

For each group (see AllShortestPaths.per) containing at least one matching path, yields every matching path of that group’s minimum length. A group whose minimum length is reached by several paths yields all of them, whereas AnyShortestPath.paths yields one per group.

Returns:

Raises:

  • relationalai.util.error.RAIException - PathSelectorPerError if .per(...) is missing or not yet supported. Currently, the only supported grouping is the pattern’s endpoint pair, .per(initial_node, final_node) with the pattern’s initial and final endpoint identifiers in that order; any other grouping raises.

Examples:

reached_person = Person.ref()
p = (
m.path(Person.follows.repeat(1, 5), reached_person)
.where(Person.name == "Alice")
.all_shortest()
.per(Person, reached_person)
.paths()
)
m.where(p).select(p, p.length, reached_person.name)

Notes:

Only the path’s endpoint identifiers unify with the enclosing scope. Filters on interior nodes must be attached with PathPattern.where on the pattern; a filter referencing interior nodes placed in an enclosing Model.where cannot be routed into the path and raises.

Performance: Unlike AnyShortestPath.paths, the number of results is not bounded by the number of groups. A group can have exponentially many shortest paths in the size of the graph, and every one of them is enumerated. Use AllShortestPaths.count first to check how many there are; it runs in time polynomial in the size of the graph, even if the counts grow exponentially.

.count()

AllShortestPaths.count() -> Aggregate

Return the number of paths that are shortest within their group.

The returned object acts like any other PyRel sum or count aggregate. When used bare, it has an implied empty .per(), so returns the single global count of selected paths, exactly like a bare count(x) aggregates globally. Group the count by applying .per(...) to the result with the endpoint identifiers: .per(initial_node, final_node) counts per connected pair, .per(final_node) counts per final node, and so on.

Returns:

  • Aggregate - The Integer count, usable inside Model.where / Model.select, grouped by an optional .per(...) at the use site.

Raises:

  • relationalai.util.error.RAIException - PathSelectorPerError if .per(...) is missing or not yet supported. Currently, the only supported grouping is the pattern’s endpoint pair, .per(initial_node, final_node) with the pattern’s initial and final endpoint identifiers in that order; any other grouping raises.

    PathNonDeterminismError if the pattern is ambiguous. Counting requires the pattern to be deterministic, i.e., there is only one way to match each path. An ambiguous pattern like path(x.follows.repeat(0, 1), y.follows.repeat(0, 1), z), where x and y are Refs of the same Concept, raises when used with this method.

Examples:

Define the count of shortest paths from each criminal to each suspect. Suppose the below pattern path(Criminal.works_with.repeat(1, 5), suspect) matches:

  • 3 paths of length 1 from Alice to Bob
  • 2 paths of length 2 from Alice to Bob
  • 1 path of length 3 from Alice to Charlie The length-2 paths will be excluded from shortest_counts, because there are shorter paths in the group (Alice, Bob).
suspect = Person.ref()
shortest_counts = (
m.path(Criminal.works_with.repeat(1, 5), suspect)
.all_shortest()
.per(Criminal, suspect)
.count()
)

Select the number of shortest paths, grouped by both path endpoints, assuming that Alice is the only Criminal in the model:

m.select(Criminal.name, suspect.name, shortest_counts.per(Criminal, suspect)).inspect()
# name name_2 sum
# 0 Alice Alice <NA>
# 1 Alice Bob 3
# 2 Alice Charlie 1

Select the total number of shortest paths:

m.select(shortest_counts).inspect()
# sum
# 0 4

Select the number of shortest paths, grouped by the initial node:

m.select(Criminal.name, shortest_counts.per(Criminal)).inspect()
# name sum
# 0 Alice 4

Select the number of shortest paths, grouped by the final node:

m.select(suspect.name, shortest_counts.per(suspect) | 0).inspect()
# name v0
# 0 Alice 0
# 1 Bob 3
# 2 Charlie 1

Select the suspects with 2 or more shortest paths from a Criminal:

m.where(shortest_counts.per(suspect) >= 2).select(suspect.name).inspect()
# name
# 0 Bob

Notes:

Only the path’s endpoint identifiers unify with the enclosing scope. Filters on interior nodes must be attached with PathPattern.where on the pattern; a filter referencing interior nodes placed in an enclosing Model.where cannot be routed into the path and raises.

The count’s per (.count().per()) is distinct from the selector’s .per (path(...).all_shortest().per().count()): the selector’s .per groups the selection (which paths count as shortest), while the count’s .per groups the count of those paths.

A group with no selected paths gets no count. If you select the group’s keys together with the count, its count shows as empty, not 0. Use | 0 to get a 0 instead.

Performance: The paths are counted without being enumerated: computing the counts is polynomial in the size of the graph, even when the number of shortest paths is exponential.

Inheritance Hierarchy

AllShortestPathsGroupedPathSelectorPathSelectorabc.ABC