From 7f6c2ea353c87ae6addd3ba91064540f2a509d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20D=C3=BCrr?= Date: Wed, 28 Jun 2023 13:59:07 +0200 Subject: [PATCH] correct DFS, proposal type annotations --- .coverage | Bin 69632 -> 69632 bytes Makefile | 10 +++++----- tests/test_tryalgo.py | 4 ++-- tryalgo/dfs.py | 34 ++++++++++++++++++++++++++++------ tryalgo/graph.py | 6 +++++- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/.coverage b/.coverage index 63383b889592012f5e89ea4f4d42deddbb5d93ba..ad8226ea01bd70b23585d36de7e72193e6770e79 100644 GIT binary patch delta 4873 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 Vrl^1%!C#R@{}P%L?n2=I{{ur9RJQ;C diff --git a/Makefile b/Makefile index 2e35046..8409234 100755 --- a/Makefile +++ b/Makefile @@ -1,19 +1,19 @@ -help: +help:: @echo "make pycodestyle run pycodestyle on Python source" @echo "make pylint run pylint on Python source" -tests: +tests:: python -m unittest -pycodestyle: +pycodestyle:: -@find setup.py tryalgo -type f -name '*.py' | xargs pycodestyle -pylint: +pylint:: -@find setup.py tryalgo -type f -name '*.py' | xargs pylint --disable=C0103 -j 4 .PHONY: help pycodestyle pylint bin docs -docs: +docs:: cd docs/_static && convert logo_W.png logo_B.png +append logo_white.png sphinx-apidoc -f -o docs/tryalgo tryalgo sphinx-build docs docs/_build diff --git a/tests/test_tryalgo.py b/tests/test_tryalgo.py index cf6370c..0754230 100755 --- a/tests/test_tryalgo.py +++ b/tests/test_tryalgo.py @@ -48,7 +48,7 @@ def isclose(a, b, rel_tol, abs_tol): from tryalgo.ford_fulkerson import ford_fulkerson from tryalgo.gale_shapley import gale_shapley from tryalgo.gauss_jordan import gauss_jordan, GJ_ZERO_SOLUTIONS, GJ_SINGLE_SOLUTION, GJ_SEVERAL_SOLUTIONS -from tryalgo.graph import Graph +from tryalgo.graph import Graph_named_vertices from tryalgo.graph01 import dist01 from tryalgo.horn_sat import horn_sat from tryalgo.huffman import huffman @@ -774,7 +774,7 @@ def test_gauss_jordan(self): x, [1, 1, 3]), GJ_ZERO_SOLUTIONS) def test_graph(self): - G = Graph() + G = Graph_named_vertices() G.add_node("A") G.add_node("B") G.add_node("C") diff --git a/tryalgo/dfs.py b/tryalgo/dfs.py index 33bec78..9b85103 100644 --- a/tryalgo/dfs.py +++ b/tryalgo/dfs.py @@ -6,9 +6,11 @@ jill-jênn vie et christoph durr - 2015-2019 """ +from typing import List, Optional +from . graph import Graph # snip{ dfs-recursive -def dfs_recursive(graph, node, seen): +def dfs_recursive(graph: Graph, node: int, seen: List[bool]) -> None: """DFS, detect connected component, recursive implementation :param graph: directed graph in listlist or listdict format @@ -25,7 +27,7 @@ def dfs_recursive(graph, node, seen): # snip{ dfs-iterative -def dfs_iterative(graph, start, seen): +def dfs_iterative_old(graph, start, seen): """DFS, detect connected component, iterative implementation :param graph: directed graph in listlist or listdict format @@ -44,9 +46,29 @@ def dfs_iterative(graph, start, seen): to_visit.append(neighbor) # snip} +# snip{ dfs-iterative +def dfs_iterative(graph: Graph, start: int, seen: List[int]) -> None: + """DFS, detect connected component, iterative implementation + + :param graph: directed graph in listlist or listdict format + :param int node: to start graph exploration + :param boolean-table seen: will be set true for the connected component + containing node. + :complexity: `O(|V|+|E|)` + """ + to_visit = [start] + while to_visit: + node = to_visit.pop() + if not seen[node]: + for neighbor in reversed(graph[node]): + if not seen[neighbor]: + to_visit.append(neighbor) + seen[node] = True +# snip} + # snip{ dfs-tree -def dfs_tree(graph, start=0): +def dfs_tree(graph: Graph, start: int=0) -> List[int]: """DFS, build DFS tree in unweighted graph :param graph: directed graph in listlist or listdict format @@ -66,7 +88,7 @@ def dfs_tree(graph, start=0): # snip} -def dfs_grid_recursive(grid, i, j, mark='X', free='.'): +def dfs_grid_recursive(grid: List[List[str]], i: int, j: int, mark: str='X', free: str='.') -> None: """DFS on a grid, mark connected component, recursive version :param grid: matrix, 4-neighborhood @@ -86,7 +108,7 @@ def dfs_grid_recursive(grid, i, j, mark='X', free='.'): # snip{ dfs-grid -def dfs_grid(grid, i, j, mark='X', free='.'): +def dfs_grid(grid, i, j, mark='X', free: str='.') -> None: """DFS on a grid, mark connected component, iterative version :param grid: matrix, 4-neighborhood @@ -111,7 +133,7 @@ def dfs_grid(grid, i, j, mark='X', free='.'): # pylint: disable=too-many-nested-blocks, no-else-return -def find_cycle(graph): +def find_cycle(graph: Graph) -> Optional[List[int]]: """find a cycle in an undirected graph :param graph: undirected graph in listlist or listdict format diff --git a/tryalgo/graph.py b/tryalgo/graph.py index 80f97c8..ab8e3d9 100644 --- a/tryalgo/graph.py +++ b/tryalgo/graph.py @@ -8,6 +8,8 @@ # pylint: disable=bad-whitespace, line-too-long, missing-docstring # pylint: disable=dangerous-default-value, too-many-locals, too-many-branches +# from __future__ import annotations +from typing import List, Dict, Type, Union def readval(file, ty): """Reads a line from file with an item of type ty @@ -353,7 +355,7 @@ def make_flow_labels(graph, flow, capac): # pylint: disable=arguments-out-of-order # snip{ class_graph -class Graph: +class Graph_named_vertices: def __init__(self): self.neighbors = [] self.name2node = {} @@ -384,3 +386,5 @@ def add_arc(self, name_u, name_v, weight_uv=None): self.neighbors[u].append(v) self.weight[u][v] = weight_uv # snip} + +Graph = Union[List[List[int]], List[Dict[int, int]], Graph_named_vertices]