Skip to content

Commit 776082a

Browse files
committed
Add benchmarks for batched versions
1 parent 84907d7 commit 776082a

File tree

4 files changed

+82
-64
lines changed

4 files changed

+82
-64
lines changed

benchmark/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
33
ComplementaritySolve = "b40a91a3-bdaf-4e1c-b965-8c278a33a8d3"
44
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
5+
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
56
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
67
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
78
PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee"

benchmark/benchmarks.jl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
using Weave
22

3-
dirs = filter(isdir, joinpath.(@__DIR__, readdir(@__DIR__)))
4-
5-
for dir in dirs
6-
files = filter(x -> endswith(x, ".jmd"), readdir(dir))
7-
for file in files
8-
weave(joinpath(dir, file))
3+
function findall_jmd_files(dir=@__DIR__)
4+
paths = String[]
5+
for p in readdir(dir)
6+
if isdir(joinpath(dir, p))
7+
append!(paths, findall_jmd_files(joinpath(dir, p)))
8+
elseif endswith(p, ".jmd")
9+
push!(paths, joinpath(dir, p))
10+
end
911
end
12+
return paths
1013
end
14+
15+
files = findall_jmd_files()
16+
17+
foreach(f -> weave(f; doctype="md2pdf"), files)

benchmark/lcp/solvers.jmd

Lines changed: 68 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Pkg.activate(joinpath(@__DIR__, ".."))
88
## Load Dependencies
99

1010
```julia
11-
using BenchmarkTools, ComplementaritySolve, DataFrames, PyPlot, StableRNGs
11+
using BenchmarkTools, ComplementaritySolve, DataFrames, NonlinearSolve, PyPlot, StableRNGs
1212
```
1313

1414
## Basic LCP
@@ -27,9 +27,10 @@ SOLVERS = [BokhovenIterativeAlgorithm(),
2727
RPGS(),
2828
InteriorPointMethod(),
2929
NonlinearReformulation(),
30+
NonlinearReformulation(:smooth, Broyden(; batched=true)),
3031
]
3132
times = zeros(length(SOLVERS), 2)
32-
solvers = ["Bok.", "RPSOR", "PGS", "RPGS", "IPM", "NLR"]
33+
solvers = ["Bok.", "RPSOR", "PGS", "RPGS", "IPM", "NLR (Newton)", "NLR (Broyden)"]
3334

3435
for (i, solver) in enumerate(SOLVERS)
3536
prob_iip = LCP{true}(A₁, q₁, rand(StableRNG(0), 2))
@@ -40,33 +41,34 @@ end
4041
```
4142

4243
```julia
43-
xloc = 1:length(solvers)
44-
width = 0.4 # the width of the bars
45-
multiplier = 0
46-
fig, ax = subplots(layout="constrained")
47-
ax.set_yscale("log")
48-
49-
for (i, group) in enumerate(["Inplace", "Out of Place"])
50-
global multiplier
51-
offset = width * multiplier
52-
rects = ax.bar(xloc .+ offset, times[:, i], width, label=group)
53-
for (j, rect) in enumerate(rects)
54-
height = rect.get_height()
55-
ax.annotate("$(round(times[j, i] * 10^6; digits=2))μs",
56-
xy=(rect.get_x() + rect.get_width() / 2, height),
57-
xytext=(0, 3), # 3 points vertical offset
58-
textcoords="offset points",
59-
ha="center", va="bottom")
44+
let _=plt.xkcd()
45+
xloc = 1:length(solvers)
46+
width = 0.4 # the width of the bars
47+
multiplier = 0
48+
fig, ax = subplots(layout="constrained", figsize=(14, 6))
49+
ax.set_yscale("log")
50+
51+
for (i, group) in enumerate(["Inplace", "Out of Place"])
52+
offset = width * multiplier
53+
rects = ax.bar(xloc .+ offset, times[:, i], width, label=group)
54+
for (j, rect) in enumerate(rects)
55+
height = rect.get_height()
56+
ax.annotate("$(round(times[j, i] * 10^6; digits=2))μs",
57+
xy=(rect.get_x() + rect.get_width() / 2, height),
58+
xytext=(0, 3), # 3 points vertical offset
59+
textcoords="offset points",
60+
ha="center", va="bottom")
61+
end
62+
multiplier += 1
6063
end
61-
multiplier += 1
62-
end
6364

64-
ax.set_ylabel("Times (s)")
65-
ax.set_title("Basic LCP Unbatched")
66-
ax.set_xticks(xloc .+ width ./ 2, solvers)
67-
ax.legend(loc="upper right", ncols=3)
68-
fig.tight_layout()
69-
fig
65+
ax.set_ylabel("Times (s)")
66+
ax.set_title("Basic LCP Unbatched")
67+
ax.set_xticks(xloc .+ width ./ 2, solvers)
68+
ax.legend(ncols=3)
69+
fig.tight_layout()
70+
fig
71+
end
7072
```
7173

7274
### Batched Version
@@ -81,51 +83,59 @@ SOLVERS = [BokhovenIterativeAlgorithm(),
8183
PGS(),
8284
RPGS(),
8385
InteriorPointMethod(),
84-
NonlinearReformulation(),
86+
NonlinearReformulation(:smooth, SimpleNewtonRaphson(; batched=true)),
87+
NonlinearReformulation(:smooth, SimpleDFSane(; batched=true)),
88+
NonlinearReformulation(:smooth, Broyden(; batched=true)),
8589
]
86-
BATCH_SIZES = 2 .^ 1:2:11
90+
BATCH_SIZES = 2 .^ (1:2:11)
8791
times = zeros(length(SOLVERS), length(BATCH_SIZES), 2)
88-
solvers = ["Bok.", "RPSOR", "PGS", "RPGS", "IPM", "NLR"]
92+
solvers = ["Bok.", "RPSOR", "PGS", "RPGS", "IPM", "NLR (Newton)", "NLR (DFSane)", "NLR (Broyden)"]
8993

9094
for (i, solver) in enumerate(SOLVERS)
9195
for (j, N) in enumerate(BATCH_SIZES)
9296
prob_iip = LCP{true}(A₁, q₁, rand(StableRNG(0), 2, N))
9397
prob_oop = LCP{false}(A₁, q₁, rand(StableRNG(0), 2, N))
94-
times[i, j, 1] = @elapsed solve(prob_iip, solver)
95-
times[i, j, 2] = @elapsed solve(prob_oop, solver)
98+
times[i, j, 2] = @belapsed solve($prob_oop, $solver)
99+
if i == 6
100+
times[i, j, 1] = -1 # SimpleNewtonRaphson is not implemented for inplace
101+
continue
102+
end
103+
times[i, j, 1] = @belapsed solve($prob_iip, $solver)
96104
end
97105
end
98106
```
99107

100-
101108
```julia
102-
xloc = 1:length(solvers)
103-
width = 0.4 # the width of the bars
104-
multiplier = 0
105-
fig, ax = subplots(layout="constrained")
106-
ax.set_yscale("log")
107-
108-
for (i, group) in enumerate(["Inplace", "Out of Place"])
109-
global multiplier
110-
offset = width * multiplier
111-
rects = ax.bar(xloc .+ offset, times[:, i], width, label=group)
112-
for (j, rect) in enumerate(rects)
113-
height = rect.get_height()
114-
ax.annotate("$(round(times[j, i] * 10^6; digits=2))μs",
115-
xy=(rect.get_x() + rect.get_width() / 2, height),
116-
xytext=(0, 3), # 3 points vertical offset
117-
textcoords="offset points",
118-
ha="center", va="bottom")
109+
let _=plt.xkcd()
110+
prop_cycle = plt.rcParams["axes.prop_cycle"]
111+
colors = prop_cycle.by_key()["color"]
112+
fig, (ax1, ax2) = subplots(1, 2; layout="constrained", sharey=true, sharex=true, figsize=(16, 6))
113+
ax1.set_yscale("log")
114+
ax1.set_xscale("log")
115+
116+
fig.suptitle("Basic LCP Batched")
117+
ax1.set_title("In-Place Solvers")
118+
ax2.set_title("Out-Of-Place Solvers")
119+
120+
for (j, solver) in enumerate(solvers)
121+
if !any(times[j, :, 1] .< 0)
122+
ax1.plot(BATCH_SIZES, times[j, :, 1]; label=solver, color=colors[j])
123+
ax1.scatter(BATCH_SIZES, times[j, :, 1]; color=colors[j])
124+
end
125+
if !any(times[j, :, 2] .< 0)
126+
ax2.plot(BATCH_SIZES, times[j, :, 2]; label=solver, color=colors[j])
127+
ax2.scatter(BATCH_SIZES, times[j, :, 2]; color=colors[j])
128+
end
119129
end
120-
multiplier += 1
121-
end
122130

123-
ax.set_ylabel("Times (s)")
124-
ax.set_title("Basic LCP Unbatched")
125-
ax.set_xticks(xloc .+ width ./ 2, solvers)
126-
ax.legend(loc="upper right", ncols=3)
127-
fig.tight_layout()
128-
fig
131+
ax1.set_ylabel("Times (s)")
132+
ax1.set_xlabel("Batch Size")
133+
ax2.set_xlabel("Batch Size")
134+
ax1.legend(ncols=3)
135+
ax2.legend(ncols=3)
136+
fig.tight_layout()
137+
fig
138+
end
129139
```
130140

131141

benchmark/lcp/solvers.pdf

51.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)