1
0
Fork 0

Code style cleanups

This commit is contained in:
Joris van Rantwijk 2024-06-22 20:04:49 +02:00
parent de30ac3c5e
commit 0675230692
6 changed files with 46 additions and 31 deletions

View File

@ -162,7 +162,9 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
assert node is not None
return node.min_node.data
def merge(self, sub_queues: "list[UnionFindQueue[_NameT, _ElemT]]") -> None:
def merge(self,
sub_queues: "list[UnionFindQueue[_NameT, _ElemT]]"
) -> None:
"""Merge the specified queues.
This queue must inititially be empty.
@ -171,7 +173,8 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
This function removes all elements from the specified sub-queues
and adds them to this queue.
After merging, this queue retains a reference to the list of sub-queues.
After merging, this queue retains a reference to the list of
sub-queues.
This function takes time O(len(sub_queues) * log(n)).
"""
@ -268,7 +271,9 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
min_node = right_min_node
node.min_node = min_node
def _rotate_left(self, node: Node[_NameT, _ElemT]) -> Node[_NameT, _ElemT]:
def _rotate_left(self,
node: Node[_NameT, _ElemT]
) -> Node[_NameT, _ElemT]:
"""Rotate the specified subtree to the left.
Return the new root node of the subtree.
@ -303,7 +308,9 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
return new_top
def _rotate_right(self, node: Node[_NameT, _ElemT]) -> Node[_NameT, _ElemT]:
def _rotate_right(self,
node: Node[_NameT, _ElemT]
) -> Node[_NameT, _ElemT]:
"""Rotate the specified node to the right.
Return the new root node of the subtree.
@ -338,7 +345,9 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
return new_top
def _rebalance_up(self, node: Node[_NameT, _ElemT]) -> Node[_NameT, _ElemT]:
def _rebalance_up(self,
node: Node[_NameT, _ElemT]
) -> Node[_NameT, _ElemT]:
"""Repair and rebalance the specified node and its ancestors.
Return the root node of the rebalanced tree.

View File

@ -1,14 +1,18 @@
#!/bin/sh
#!/bin/bash
set -e
echo
echo "Running pycodestyle"
pycodestyle python/mwmatching.py python/datastruct.py tests
echo
echo "Running mypy"
mypy --disallow-incomplete-defs python tests
echo
echo "Running pylint"
pylint --ignore=test_mwmatching.py python tests
pylint --ignore=test_mwmatching.py python tests || [ $(($? & 3)) -eq 0 ]
echo
echo "Running test_mwmatching.py"

View File

@ -7,7 +7,7 @@ described by Gabow.
Reference: H. N. Gabow, "An efficient implementation of Edmonds'
algorithm for maximum matching on graphs", JACM 23
(1976), pp. 221-234.
Based on Fortran program "hardcard.f" by R. Bruce Mattingly, 1991.
Rewritten in Python by Joris van Rantwijk, 2023.

View File

@ -14,7 +14,7 @@ from typing import TextIO
def write_dimacs_graph(
f: TextIO,
edges: list[tuple[int, int, int|float]]
edges: list[tuple[int, int, float]]
) -> None:
"""Write a graph in DIMACS edge list format."""
@ -38,7 +38,7 @@ def make_random_graph(
max_weight: float,
float_weights: bool,
rng: random.Random
) -> list[tuple[int, int, int|float]]:
) -> list[tuple[int, int, float]]:
"""Generate a random graph with random edge weights."""
edge_set: set[tuple[int, int]] = set()
@ -59,9 +59,9 @@ def make_random_graph(
rng.shuffle(edge_candidates)
edge_set.update(edge_candidates[:m])
edges: list[tuple[int, int, int|float]] = []
edges: list[tuple[int, int, float]] = []
for (x, y) in sorted(edge_set):
w: int|float
w: float
if float_weights:
w = rng.uniform(1.0e-8, max_weight)
else:

View File

@ -36,7 +36,8 @@ def patch_matching_code() -> None:
ret = orig_substage_calc_dual_delta(*args, **kwargs)
return ret
mwmatching._MatchingContext.make_blossom = stub_make_blossom # type: ignore
mwmatching._MatchingContext.make_blossom = ( # type: ignore
stub_make_blossom)
mwmatching._MatchingContext.substage_calc_dual_delta = ( # type: ignore
stub_substage_calc_dual_delta)

View File

@ -29,7 +29,7 @@ class SolverError(Exception):
class Graph(NamedTuple):
"""Represents a graph. Vertex indices start from 0."""
edges: list[tuple[int, int, int|float]]
edges: list[tuple[int, int, float]]
def num_vertex(self) -> int:
"""Count number of vertices."""
@ -55,11 +55,11 @@ class RunStatus(enum.IntEnum):
class RunResult(NamedTuple):
"""Represent the result of running a solver on a graph."""
status: RunStatus = RunStatus.OK
weight: int|float = 0
weight: float = 0
run_time: Sequence[float] = ()
def parse_int_or_float(s: str) -> int|float:
def parse_int_or_float(s: str) -> float:
"""Convert a string to integer or float value."""
try:
return int(s)
@ -130,11 +130,11 @@ def write_dimacs_graph(f: TextIO, graph: Graph) -> None:
print(f"e {x+1} {y+1} {w:.12g}", file=f)
def read_dimacs_matching(f: TextIO) -> tuple[int|float, Matching]:
def read_dimacs_matching(f: TextIO) -> tuple[float, Matching]:
"""Read a matching solution in DIMACS format."""
have_weight = False
weight: int|float = 0
weight: float = 0
pairs: list[tuple[int, int]] = []
for line in f:
@ -208,9 +208,9 @@ def make_random_graph(
rng.shuffle(edge_candidates)
edge_set.update(edge_candidates[:m])
edges: list[tuple[int, int, int|float]] = []
edges: list[tuple[int, int, float]] = []
for (x, y) in sorted(edge_set):
w: int|float
w: float
if float_weights:
w = rng.uniform(1.0e-8, max_weight)
else:
@ -220,14 +220,14 @@ def make_random_graph(
return Graph(edges)
def check_matching(graph: Graph, matching: Matching) -> int|float:
def check_matching(graph: Graph, matching: Matching) -> float:
"""Verify that the matching is valid and calculate its weight."""
edge_map: dict[tuple[int, int], int|float] = {}
edge_map: dict[tuple[int, int], float] = {}
for (x, y, w) in graph.edges:
edge_map[(min(x, y), max(x, y))] = w
weight: int|float = 0
weight: float = 0
nodes_used: set[int] = set()
for pair in matching.pairs:
@ -247,7 +247,7 @@ def check_matching(graph: Graph, matching: Matching) -> int|float:
return weight
def compare_weight(weight1: int|float, weight2: int|float) -> int:
def compare_weight(weight1: float, weight2: float) -> int:
"""Compare weights of matchings.
Returns:
@ -406,7 +406,7 @@ class WmatchSolver(Solver):
num_edge = len(graph.edges)
all_integer = True
adjacent: list[list[tuple[int, int|float]]] = [
adjacent: list[list[tuple[int, float]]] = [
[] for i in range(num_vertex)]
for (x, y, w) in graph.edges:
@ -451,13 +451,13 @@ def test_solver_on_graph(
solver: Solver,
graph: Graph,
graph_desc: str,
gold_weight: Optional[int|float],
gold_weight: Optional[float],
num_run: int
) -> RunResult:
"""Test the specified solver with the specified graph."""
solver_run_time: list[float] = []
solver_weight: Optional[int|float] = None
solver_weight: Optional[float] = None
for i in range(num_run):
@ -507,7 +507,7 @@ def test_graph(
solvers: list[Solver],
graph: Graph,
graph_desc: str,
gold_weight: Optional[int|float],
gold_weight: Optional[float],
num_run: int
) -> list[RunResult]:
"""Test all solvers with the specified graph."""
@ -525,7 +525,7 @@ def test_graph(
if gold_weight is None:
best_weight: Optional[int|float] = None
best_weight: Optional[float] = None
for result in results:
if result.status == RunStatus.OK:
if (best_weight is None) or (result.weight > best_weight):
@ -668,7 +668,7 @@ def test_input(
file=sys.stderr)
return 1
gold_weight: Optional[int|float] = None
gold_weight: Optional[float] = None
if verify:
reffile = os.path.splitext(filename)[0] + ".out"
try:
@ -740,7 +740,8 @@ def main() -> int:
parser.add_argument("--timeout",
action="store",
type=float,
help="abort when solver runs longer than TIMEOUT seconds")
help="abort when solver runs longer than TIMEOUT"
" seconds")
parser.add_argument("--runs",
action="store",
type=int,