Code style cleanups
This commit is contained in:
parent
de30ac3c5e
commit
0675230692
|
@ -162,7 +162,9 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
|
||||||
assert node is not None
|
assert node is not None
|
||||||
return node.min_node.data
|
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.
|
"""Merge the specified queues.
|
||||||
|
|
||||||
This queue must inititially be empty.
|
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
|
This function removes all elements from the specified sub-queues
|
||||||
and adds them to this queue.
|
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)).
|
This function takes time O(len(sub_queues) * log(n)).
|
||||||
"""
|
"""
|
||||||
|
@ -268,7 +271,9 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
|
||||||
min_node = right_min_node
|
min_node = right_min_node
|
||||||
node.min_node = 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.
|
"""Rotate the specified subtree to the left.
|
||||||
|
|
||||||
Return the new root node of the subtree.
|
Return the new root node of the subtree.
|
||||||
|
@ -303,7 +308,9 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
|
||||||
|
|
||||||
return new_top
|
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.
|
"""Rotate the specified node to the right.
|
||||||
|
|
||||||
Return the new root node of the subtree.
|
Return the new root node of the subtree.
|
||||||
|
@ -338,7 +345,9 @@ class UnionFindQueue(Generic[_NameT, _ElemT]):
|
||||||
|
|
||||||
return new_top
|
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.
|
"""Repair and rebalance the specified node and its ancestors.
|
||||||
|
|
||||||
Return the root node of the rebalanced tree.
|
Return the root node of the rebalanced tree.
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Running pycodestyle"
|
||||||
|
pycodestyle python/mwmatching.py python/datastruct.py tests
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Running mypy"
|
echo "Running mypy"
|
||||||
mypy --disallow-incomplete-defs python tests
|
mypy --disallow-incomplete-defs python tests
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Running pylint"
|
echo "Running pylint"
|
||||||
pylint --ignore=test_mwmatching.py python tests
|
pylint --ignore=test_mwmatching.py python tests || [ $(($? & 3)) -eq 0 ]
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Running test_mwmatching.py"
|
echo "Running test_mwmatching.py"
|
||||||
|
|
|
@ -7,7 +7,7 @@ described by Gabow.
|
||||||
Reference: H. N. Gabow, "An efficient implementation of Edmonds'
|
Reference: H. N. Gabow, "An efficient implementation of Edmonds'
|
||||||
algorithm for maximum matching on graphs", JACM 23
|
algorithm for maximum matching on graphs", JACM 23
|
||||||
(1976), pp. 221-234.
|
(1976), pp. 221-234.
|
||||||
|
|
||||||
Based on Fortran program "hardcard.f" by R. Bruce Mattingly, 1991.
|
Based on Fortran program "hardcard.f" by R. Bruce Mattingly, 1991.
|
||||||
Rewritten in Python by Joris van Rantwijk, 2023.
|
Rewritten in Python by Joris van Rantwijk, 2023.
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ from typing import TextIO
|
||||||
|
|
||||||
def write_dimacs_graph(
|
def write_dimacs_graph(
|
||||||
f: TextIO,
|
f: TextIO,
|
||||||
edges: list[tuple[int, int, int|float]]
|
edges: list[tuple[int, int, float]]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Write a graph in DIMACS edge list format."""
|
"""Write a graph in DIMACS edge list format."""
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ def make_random_graph(
|
||||||
max_weight: float,
|
max_weight: float,
|
||||||
float_weights: bool,
|
float_weights: bool,
|
||||||
rng: random.Random
|
rng: random.Random
|
||||||
) -> list[tuple[int, int, int|float]]:
|
) -> list[tuple[int, int, float]]:
|
||||||
"""Generate a random graph with random edge weights."""
|
"""Generate a random graph with random edge weights."""
|
||||||
|
|
||||||
edge_set: set[tuple[int, int]] = set()
|
edge_set: set[tuple[int, int]] = set()
|
||||||
|
@ -59,9 +59,9 @@ def make_random_graph(
|
||||||
rng.shuffle(edge_candidates)
|
rng.shuffle(edge_candidates)
|
||||||
edge_set.update(edge_candidates[:m])
|
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):
|
for (x, y) in sorted(edge_set):
|
||||||
w: int|float
|
w: float
|
||||||
if float_weights:
|
if float_weights:
|
||||||
w = rng.uniform(1.0e-8, max_weight)
|
w = rng.uniform(1.0e-8, max_weight)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -36,7 +36,8 @@ def patch_matching_code() -> None:
|
||||||
ret = orig_substage_calc_dual_delta(*args, **kwargs)
|
ret = orig_substage_calc_dual_delta(*args, **kwargs)
|
||||||
return ret
|
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
|
mwmatching._MatchingContext.substage_calc_dual_delta = ( # type: ignore
|
||||||
stub_substage_calc_dual_delta)
|
stub_substage_calc_dual_delta)
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ class SolverError(Exception):
|
||||||
|
|
||||||
class Graph(NamedTuple):
|
class Graph(NamedTuple):
|
||||||
"""Represents a graph. Vertex indices start from 0."""
|
"""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:
|
def num_vertex(self) -> int:
|
||||||
"""Count number of vertices."""
|
"""Count number of vertices."""
|
||||||
|
@ -55,11 +55,11 @@ class RunStatus(enum.IntEnum):
|
||||||
class RunResult(NamedTuple):
|
class RunResult(NamedTuple):
|
||||||
"""Represent the result of running a solver on a graph."""
|
"""Represent the result of running a solver on a graph."""
|
||||||
status: RunStatus = RunStatus.OK
|
status: RunStatus = RunStatus.OK
|
||||||
weight: int|float = 0
|
weight: float = 0
|
||||||
run_time: Sequence[float] = ()
|
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."""
|
"""Convert a string to integer or float value."""
|
||||||
try:
|
try:
|
||||||
return int(s)
|
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)
|
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."""
|
"""Read a matching solution in DIMACS format."""
|
||||||
|
|
||||||
have_weight = False
|
have_weight = False
|
||||||
weight: int|float = 0
|
weight: float = 0
|
||||||
pairs: list[tuple[int, int]] = []
|
pairs: list[tuple[int, int]] = []
|
||||||
|
|
||||||
for line in f:
|
for line in f:
|
||||||
|
@ -208,9 +208,9 @@ def make_random_graph(
|
||||||
rng.shuffle(edge_candidates)
|
rng.shuffle(edge_candidates)
|
||||||
edge_set.update(edge_candidates[:m])
|
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):
|
for (x, y) in sorted(edge_set):
|
||||||
w: int|float
|
w: float
|
||||||
if float_weights:
|
if float_weights:
|
||||||
w = rng.uniform(1.0e-8, max_weight)
|
w = rng.uniform(1.0e-8, max_weight)
|
||||||
else:
|
else:
|
||||||
|
@ -220,14 +220,14 @@ def make_random_graph(
|
||||||
return Graph(edges)
|
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."""
|
"""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:
|
for (x, y, w) in graph.edges:
|
||||||
edge_map[(min(x, y), max(x, y))] = w
|
edge_map[(min(x, y), max(x, y))] = w
|
||||||
|
|
||||||
weight: int|float = 0
|
weight: float = 0
|
||||||
nodes_used: set[int] = set()
|
nodes_used: set[int] = set()
|
||||||
|
|
||||||
for pair in matching.pairs:
|
for pair in matching.pairs:
|
||||||
|
@ -247,7 +247,7 @@ def check_matching(graph: Graph, matching: Matching) -> int|float:
|
||||||
return weight
|
return weight
|
||||||
|
|
||||||
|
|
||||||
def compare_weight(weight1: int|float, weight2: int|float) -> int:
|
def compare_weight(weight1: float, weight2: float) -> int:
|
||||||
"""Compare weights of matchings.
|
"""Compare weights of matchings.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -406,7 +406,7 @@ class WmatchSolver(Solver):
|
||||||
num_edge = len(graph.edges)
|
num_edge = len(graph.edges)
|
||||||
|
|
||||||
all_integer = True
|
all_integer = True
|
||||||
adjacent: list[list[tuple[int, int|float]]] = [
|
adjacent: list[list[tuple[int, float]]] = [
|
||||||
[] for i in range(num_vertex)]
|
[] for i in range(num_vertex)]
|
||||||
|
|
||||||
for (x, y, w) in graph.edges:
|
for (x, y, w) in graph.edges:
|
||||||
|
@ -451,13 +451,13 @@ def test_solver_on_graph(
|
||||||
solver: Solver,
|
solver: Solver,
|
||||||
graph: Graph,
|
graph: Graph,
|
||||||
graph_desc: str,
|
graph_desc: str,
|
||||||
gold_weight: Optional[int|float],
|
gold_weight: Optional[float],
|
||||||
num_run: int
|
num_run: int
|
||||||
) -> RunResult:
|
) -> RunResult:
|
||||||
"""Test the specified solver with the specified graph."""
|
"""Test the specified solver with the specified graph."""
|
||||||
|
|
||||||
solver_run_time: list[float] = []
|
solver_run_time: list[float] = []
|
||||||
solver_weight: Optional[int|float] = None
|
solver_weight: Optional[float] = None
|
||||||
|
|
||||||
for i in range(num_run):
|
for i in range(num_run):
|
||||||
|
|
||||||
|
@ -507,7 +507,7 @@ def test_graph(
|
||||||
solvers: list[Solver],
|
solvers: list[Solver],
|
||||||
graph: Graph,
|
graph: Graph,
|
||||||
graph_desc: str,
|
graph_desc: str,
|
||||||
gold_weight: Optional[int|float],
|
gold_weight: Optional[float],
|
||||||
num_run: int
|
num_run: int
|
||||||
) -> list[RunResult]:
|
) -> list[RunResult]:
|
||||||
"""Test all solvers with the specified graph."""
|
"""Test all solvers with the specified graph."""
|
||||||
|
@ -525,7 +525,7 @@ def test_graph(
|
||||||
|
|
||||||
if gold_weight is None:
|
if gold_weight is None:
|
||||||
|
|
||||||
best_weight: Optional[int|float] = None
|
best_weight: Optional[float] = None
|
||||||
for result in results:
|
for result in results:
|
||||||
if result.status == RunStatus.OK:
|
if result.status == RunStatus.OK:
|
||||||
if (best_weight is None) or (result.weight > best_weight):
|
if (best_weight is None) or (result.weight > best_weight):
|
||||||
|
@ -668,7 +668,7 @@ def test_input(
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
gold_weight: Optional[int|float] = None
|
gold_weight: Optional[float] = None
|
||||||
if verify:
|
if verify:
|
||||||
reffile = os.path.splitext(filename)[0] + ".out"
|
reffile = os.path.splitext(filename)[0] + ".out"
|
||||||
try:
|
try:
|
||||||
|
@ -740,7 +740,8 @@ def main() -> int:
|
||||||
parser.add_argument("--timeout",
|
parser.add_argument("--timeout",
|
||||||
action="store",
|
action="store",
|
||||||
type=float,
|
type=float,
|
||||||
help="abort when solver runs longer than TIMEOUT seconds")
|
help="abort when solver runs longer than TIMEOUT"
|
||||||
|
" seconds")
|
||||||
parser.add_argument("--runs",
|
parser.add_argument("--runs",
|
||||||
action="store",
|
action="store",
|
||||||
type=int,
|
type=int,
|
||||||
|
|
Loading…
Reference in New Issue