Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Pint Changelog
- Add conductivity dimension. (#2112)
- Add absorbance unit and dimension. (#2114)
- Add membrane filtration flux and permeability dimensionality, and shorthand "LMH". (#2116)
- Fix find_shortest_path to use breadth first search (#2146)


0.24.4 (2024-11-07)
Expand Down
15 changes: 15 additions & 0 deletions pint/testsuite/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,21 @@ def test_shortest_path(self):
p = find_shortest_path(g, 2, 1)
assert p == [2, 1]

def test_shortest_path_densely_connected_2146(self):
import itertools
g = collections.defaultdict(set)
for i, j in itertools.combinations(range(42), 2):
g[i].add(j)
g[j].add(i)
p = find_shortest_path(g, 0, 39)
assert p == [0, 39]
p = find_shortest_path(g, 0, 41)
assert p == [0, 41]
p = find_shortest_path(g, 17, 2)
assert p == [17, 2]
p = find_shortest_path(g, 12, 12)
assert p == [12]


class TestMatrix:
def test_matrix_to_string(self):
Expand Down
32 changes: 15 additions & 17 deletions pint/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import re
import tokenize
import types
from collections import deque
from collections.abc import Callable, Generator, Hashable, Iterable, Iterator, Mapping
from fractions import Fraction
from functools import lru_cache, partial
Expand Down Expand Up @@ -340,7 +341,7 @@ def solve_dependencies(


def find_shortest_path(
graph: dict[TH, set[TH]], start: TH, end: TH, path: list[TH] | None = None
graph: dict[TH, set[TH]], start: TH, end: TH
):
"""Find shortest path between two nodes within a graph.

Expand All @@ -353,32 +354,29 @@ def find_shortest_path(
Starting node.
end
End node.
path
Path to prepend to the one found.
(default = None, empty path.)

Returns
-------
list[TH]
The shortest path between two nodes.
"""
path = (path or []) + [start]
path = [start]
if start == end:
return path

# TODO: raise ValueError when start not in graph
if start not in graph:
return None

shortest = None
for node in graph[start]:
if node not in path:
newpath = find_shortest_path(graph, node, end, path)
if newpath:
if not shortest or len(newpath) < len(shortest):
shortest = newpath
fifo = deque()
fifo.append((start, path))
visited = set()
while fifo:
node, path = fifo.popleft()
visited.add(node)
for adjascent_node in graph[node] - visited:
if adjascent_node == end:
return path + [adjascent_node]
else:
fifo.append((adjascent_node, path + [adjascent_node]))

return shortest
return None


def find_connected_nodes(
Expand Down
Loading