Add generators: chain, hardcard.f, t.f, tt.f
This commit is contained in:
parent
3f5d61d0e7
commit
71a7dfc9a3
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Generate a graph that belongs to a class of worst-case graphs
|
||||||
|
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.
|
||||||
|
|
||||||
|
For the original Fortran code, see
|
||||||
|
http://archive.dimacs.rutgers.edu/pub/netflow/generators/matching/hardcard.f
|
||||||
|
|
||||||
|
Output to stdout in DIMACS edge format.
|
||||||
|
All edges have weight 1.
|
||||||
|
|
||||||
|
Input parameter: K
|
||||||
|
Number of vertices: N = 6*K
|
||||||
|
Number of edges: M = 8*K*K
|
||||||
|
|
||||||
|
The graph is constructed so that vertices 1 - 4*K form a complete subgraph.
|
||||||
|
For 1 <= I <= 2*K, vertex (2*I-1) is joined to vertex (4*K+I).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.description = "Generate a difficult graph"
|
||||||
|
|
||||||
|
parser.add_argument("k",
|
||||||
|
action="store",
|
||||||
|
type=int,
|
||||||
|
help="size parameter; N = 6*K, M = 4*K*K")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.k < 1:
|
||||||
|
print("ERROR: K must be at least 1", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
k = args.k
|
||||||
|
n = 6 * k
|
||||||
|
m = 8 * k * k
|
||||||
|
|
||||||
|
print(f"p edge {n} {m}")
|
||||||
|
|
||||||
|
for i in range(1, 4*k):
|
||||||
|
for j in range(i + 1, 4*k + 1):
|
||||||
|
print(f"e {i} {j} 1")
|
||||||
|
if i % 2 == 1:
|
||||||
|
j = 4 * k + (i + 1) // 2
|
||||||
|
print(f"e {i} {j} 1")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -70,12 +70,14 @@ def write_dimacs_graph(
|
||||||
|
|
||||||
|
|
||||||
def make_dense_slow_graph(n: int) -> list[tuple[int, int, int]]:
|
def make_dense_slow_graph(n: int) -> list[tuple[int, int, int]]:
|
||||||
"""Generate a dense (not complete) graph with N vertices.
|
"""Generate a dense graph with N vertices.
|
||||||
|
|
||||||
|
The graph contains O(n**2) edges and triggers O(n**2) delta steps.
|
||||||
|
|
||||||
N must be divisible by 4.
|
N must be divisible by 4.
|
||||||
|
|
||||||
Number of edges = M = (N**2/16 + N/2).
|
Number of edges = M = N**2/16 + N/2
|
||||||
Number of delta steps required to solve the matching = (M - 1).
|
Number of delta steps required to solve the matching = M - 1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert n % 4 == 0
|
assert n % 4 == 0
|
||||||
|
@ -118,10 +120,12 @@ def make_dense_slow_graph(n: int) -> list[tuple[int, int, int]]:
|
||||||
def make_sparse_slow_graph(n: int) -> list[tuple[int, int, int]]:
|
def make_sparse_slow_graph(n: int) -> list[tuple[int, int, int]]:
|
||||||
"""Generate a sparse graph with N vertices.
|
"""Generate a sparse graph with N vertices.
|
||||||
|
|
||||||
|
The graph contains just O(n) edges but still triggers O(n**2) delta steps.
|
||||||
|
|
||||||
N must be 4 modulo 8.
|
N must be 4 modulo 8.
|
||||||
|
|
||||||
Number of edges = M = (5/4 * N - 3).
|
Number of edges = M = 5/4 * N - 3
|
||||||
Number of delta steps required to solve the matching ~ (N**2 / 16).
|
Number of delta steps required to solve the matching = N**2/16 + 3/4*N - 3
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert n >= 12
|
assert n >= 12
|
||||||
|
@ -233,20 +237,40 @@ def make_sparse_slow_graph(n: int) -> list[tuple[int, int, int]]:
|
||||||
return edges
|
return edges
|
||||||
|
|
||||||
|
|
||||||
|
def make_chain_graph(n: int) -> list[tuple[int, int, int]]:
|
||||||
|
"""Generate a graph with N vertices connected into a simple chain.
|
||||||
|
|
||||||
|
The graph contains O(n) edges and triggers O(n) delta steps.
|
||||||
|
To force a large number of delta steps, N must be even.
|
||||||
|
|
||||||
|
Number of edges = M = N - 1
|
||||||
|
Number of delta steps required to solve the matching = N - 2
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert n >= 2
|
||||||
|
|
||||||
|
edges: list[tuple[int, int, int]] = []
|
||||||
|
|
||||||
|
for i in range(n - 1):
|
||||||
|
w = n + i % 2
|
||||||
|
edges.append((i, i + 1, w))
|
||||||
|
|
||||||
|
return edges
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
"""Main program."""
|
"""Main program."""
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.description = "Generate a difficult graph."
|
parser.description = "Generate a difficult graph."
|
||||||
|
|
||||||
parser.add_argument("--structure",
|
|
||||||
action="store",
|
|
||||||
choices=("sparse", "dense"),
|
|
||||||
default="sparse",
|
|
||||||
help="choose graph structure")
|
|
||||||
parser.add_argument("--check",
|
parser.add_argument("--check",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="solve the matching and count delta steps")
|
help="solve the matching and count delta steps")
|
||||||
|
parser.add_argument("structure",
|
||||||
|
action="store",
|
||||||
|
choices=("sparse", "dense", "chain"),
|
||||||
|
help="graph structure")
|
||||||
parser.add_argument("n",
|
parser.add_argument("n",
|
||||||
action="store",
|
action="store",
|
||||||
type=int,
|
type=int,
|
||||||
|
@ -283,6 +307,18 @@ def main() -> int:
|
||||||
|
|
||||||
edges = make_dense_slow_graph(args.n)
|
edges = make_dense_slow_graph(args.n)
|
||||||
|
|
||||||
|
elif args.structure == "chain":
|
||||||
|
|
||||||
|
if args.n < 2:
|
||||||
|
print("ERROR: Number of vertices must be >= 2", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if args.n % 2 != 0:
|
||||||
|
print("ERROR: Number of vertices must be even", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
edges = make_chain_graph(args.n)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
r"""
|
||||||
|
Generate a graph that consists of interconnected triangles.
|
||||||
|
|
||||||
|
The graph is a chain of triangles, connected either at 1 vertex
|
||||||
|
or at 3 vertices.
|
||||||
|
|
||||||
|
Example of triangles connected at one vertex:
|
||||||
|
|
||||||
|
[1]-------[4] [7] [10]-------[13]
|
||||||
|
| \ | \ | \ / | | \
|
||||||
|
| [3] | [6] | [9]---[12] | | [15]
|
||||||
|
| / | / | / \ | | /
|
||||||
|
[2] [5]-------[8] [11] [14]-----
|
||||||
|
|
||||||
|
Example of triangles connected at 3 vertices:
|
||||||
|
|
||||||
|
[1]-------[4]-------[7]-------[10]-------[13]
|
||||||
|
| \ | \ | \ | \ | \
|
||||||
|
| [3]----|--[6]----|--[9]----|--[12]----|--[15]
|
||||||
|
| / | / | / | / | /
|
||||||
|
[2]-------[5]-------[8]-------[11]-------[14]
|
||||||
|
|
||||||
|
Based on Fortran programs "t.f" and "tt.f"
|
||||||
|
by N. Ritchey and B. Mattingly, Youngstown State University, 1991.
|
||||||
|
|
||||||
|
Rewritten in Python by Joris van Rantwijk, 2023.
|
||||||
|
|
||||||
|
For the original Fortran code, see
|
||||||
|
http://archive.dimacs.rutgers.edu/pub/netflow/generators/matching/t.f
|
||||||
|
http://archive.dimacs.rutgers.edu/pub/netflow/generators/matching/tt.f
|
||||||
|
|
||||||
|
Output to stdout in DIMACS edge format.
|
||||||
|
All edges have weight 1.
|
||||||
|
|
||||||
|
Input parameter: K = number of triangles
|
||||||
|
Input parameter: C = 1 to connect triangles by 1 corner
|
||||||
|
C = 3 to connect triangles by 3 corners
|
||||||
|
Number of vertices: N = 3*K
|
||||||
|
Number of edges: M = 3*K + C*(K-1)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.description = (
|
||||||
|
"Generate a graph that consists of interconnected triangles.")
|
||||||
|
|
||||||
|
parser.add_argument("k",
|
||||||
|
action="store",
|
||||||
|
type=int,
|
||||||
|
help="size parameter; N = 3*K, M = 3*K+C*(K-1)")
|
||||||
|
parser.add_argument("c",
|
||||||
|
action="store",
|
||||||
|
type=int,
|
||||||
|
choices=(1, 3),
|
||||||
|
help="number of corners to connect")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.k < 1:
|
||||||
|
print("ERROR: K must be at least 1", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
k = args.k
|
||||||
|
n = 3 * k
|
||||||
|
m = 3 * k + args.c * (k - 1)
|
||||||
|
|
||||||
|
print(f"p edge {n} {m}")
|
||||||
|
|
||||||
|
for i in range(k):
|
||||||
|
x = 3 * i + 1
|
||||||
|
print(f"e {x} {x+1} 1")
|
||||||
|
print(f"e {x} {x+2} 1")
|
||||||
|
print(f"e {x+1} {x+2} 1")
|
||||||
|
|
||||||
|
if args.c == 1:
|
||||||
|
for i in range(k - 1):
|
||||||
|
x = 3 * i + i % 3 + 1
|
||||||
|
print(f"e {x} {x+3} 1")
|
||||||
|
|
||||||
|
elif args.c == 3:
|
||||||
|
for x in range(1, 3 * k - 2):
|
||||||
|
print(f"e {x} {x+3} 1")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue