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]]:
|
||||
"""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.
|
||||
|
||||
Number of edges = M = (N**2/16 + N/2).
|
||||
Number of delta steps required to solve the matching = (M - 1).
|
||||
Number of edges = M = N**2/16 + N/2
|
||||
Number of delta steps required to solve the matching = M - 1
|
||||
"""
|
||||
|
||||
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]]:
|
||||
"""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.
|
||||
|
||||
Number of edges = M = (5/4 * N - 3).
|
||||
Number of delta steps required to solve the matching ~ (N**2 / 16).
|
||||
Number of edges = M = 5/4 * N - 3
|
||||
Number of delta steps required to solve the matching = N**2/16 + 3/4*N - 3
|
||||
"""
|
||||
|
||||
assert n >= 12
|
||||
|
@ -233,20 +237,40 @@ def make_sparse_slow_graph(n: int) -> list[tuple[int, int, int]]:
|
|||
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:
|
||||
"""Main program."""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
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",
|
||||
action="store_true",
|
||||
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",
|
||||
action="store",
|
||||
type=int,
|
||||
|
@ -283,6 +307,18 @@ def main() -> int:
|
|||
|
||||
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:
|
||||
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