-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmake_table2.py
More file actions
208 lines (175 loc) · 7.39 KB
/
Copy pathmake_table2.py
File metadata and controls
208 lines (175 loc) · 7.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/usr/bin/env python3
"""Regenerate Table2.tex — the per-instance numerical tables for Experiment A.
Input : resultsA_raw.csv written by run_experimentA.m
Output: Table2.tex, a standalone LaTeX document with one landscape table per
benchmark problem, in the column layout of the previous archive
(\\#Dim, Ip, then \\#Itr / \\#Fev / \\#Tm / \\#Nrm for each of the four
solvers).
Differences from the previous archive, all deliberate:
* seven tables rather than six; Problem 7 was never in the old archive
* six dimensions rather than five; n = 150000 was never run before
* the \\multicolumn spans in the header are 4, matching the four data
columns per solver (the old file said 3)
* a Status column is not added, but any run that did not meet the common
stopping criterion is flagged with a dagger and named in the caption
"""
import sys
import os
from collections import OrderedDict
SOLVERS = ["BBSANME", "Modified Algorithm 2.1", "Algorithm 2.1", "DLLA"]
SOLVER_TEX = ["\\texttt{BBSANME}", "Modified Algorithm 2.1",
"\\texttt{Algorithm 2.1}", "DLLA"]
PROBLEM_NOTE = {
"P1": "not globally Lipschitz",
"P4": "not globally Lipschitz",
"P7": "pseudomonotone, $n=2$",
}
def read_raw(path):
rows = []
with open(path) as fh:
for line in fh:
if line.startswith("#") or line.startswith("Solver,"):
continue
q = line.rstrip("\n").split(",")
if len(q) < 10:
continue
fam, dim, guess = q[1].split("_")
rows.append(dict(solver=q[0], family=fam,
dim=int(dim[3:]), guess=int(guess[5:]),
it=int(float(q[3])), fe=int(float(q[4])),
tm=float(q[6]), nrm=float(q[7]),
status=q[8], ok=bool(int(q[9]))))
return rows
def sci(x):
"""1.23E-07, matching the previous archive's format."""
s = "%.2E" % x
m, e = s.split("E")
return "%sE%s%02d" % (m, e[0], abs(int(e)))
def table_for(rows, fam):
sub = [r for r in rows if r["family"] == fam]
dims = sorted({r["dim"] for r in sub})
guesses = sorted({r["guess"] for r in sub})
index = {(r["solver"], r["dim"], r["guess"]): r for r in sub}
failures = [r for r in sub if not r["ok"]]
out = []
out.append("\\begin{sidewaystable}[htbp]")
cap = ("Numerical results for \\texttt{BBSANME}, Modified Algorithm~2.1, "
"\\texttt{Algorithm~2.1} and DLLA on Problem~%s" % fam[1:])
if fam in PROBLEM_NOTE:
cap += " (%s)" % PROBLEM_NOTE[fam]
cap += "."
if failures:
cap += (" Runs marked $\\dagger$ did not reach $\\|\\mathcal{H}(x_k)\\|"
"\\le 10^{-6}$.")
else:
cap += " Every run reached $\\|\\mathcal{H}(x_k)\\|\\le 10^{-6}$."
out.append("\t\\caption{%s}" % cap)
out.append("\t\\label{tab:A-%s}" % fam)
# Scale to fit, never stretch. The previous archive forced
# height=7.5cm, width=24cm on every table, which inflated the
# six-row Problem 7 table until its text was unreadable.
out.append("\t\\adjustbox{max width=24cm, max totalheight=17cm, "
"keepaspectratio}")
out.append("\t{")
out.append("\t\t\\footnotesize")
out.append("\t\t\\setlength{\\tabcolsep}{4pt}")
out.append("\t\t\\begin{tabular}{cc" + "cccc" * 4 + "}")
out.append("\t\t\t\\hline")
header = " & " * 2 + " & ".join(
"\\multicolumn{4}{c}{%s}" % s for s in SOLVER_TEX) + " \\\\"
out.append("\t\t\t" + header)
out.append("\t\t\t\\cline{3-6}\\cline{7-10}\\cline{11-14}\\cline{15-18}")
sub_header = ("\\#Dim & Ip & " +
" & ".join(["\\#Itr & \\#Fev & \\#Tm & \\#Nrm"] * 4) +
" \\\\")
out.append("\t\t\t" + sub_header)
out.append("\t\t\t\\hline")
for dim in dims:
mid = len(guesses) // 2
for i, g in enumerate(guesses):
first = ("%d" % dim) if i == mid else ""
cells = [first, "$x_{%d}$" % g]
for s in SOLVERS:
r = index.get((s, dim, g))
if r is None:
cells += ["--", "--", "--", "--"]
continue
mark = "$^{\\dagger}$" if not r["ok"] else ""
cells += ["%d" % r["it"], "%d" % r["fe"],
"%.6f" % r["tm"], sci(r["nrm"]) + mark]
out.append("\t\t\t" + " & ".join(cells) + " \\\\")
out.append("\t\t\t\\hline")
out.append("\t\t\\end{tabular}%")
out.append("\t}")
out.append("\\end{sidewaystable}")
out.append("")
return "\n".join(out)
PREAMBLE = r"""\documentclass[11pt]{article}
\usepackage{amsmath,amsfonts,amssymb}
\usepackage[a4paper, left=0.5in, right=0.5in, top=0.9in, bottom=0.9in]{geometry}
\usepackage{rotating}
\usepackage{adjustbox}
\usepackage{booktabs, multirow}
\usepackage{longtable}
\usepackage{caption}
\usepackage{hyperref}
\usepackage[T1]{fontenc}
\title{Numerical tables for \\
\emph{Barzilai--Borwein-like spectral algorithm with norm descent line search
for monotone operator equations}}
\author{H. Mohammad \and H. Choi \and A. B. Abubakar \and M. Abdullahi
\and M. S. Sarkinbai}
\date{%(date)s}
\begin{document}
\maketitle
\noindent
This archive holds the per-instance numerical results behind Section~4.1 of
the manuscript. Four solvers are compared on seven benchmark problems:
\texttt{BBSANME}, Modified Algorithm~2.1 (Muangchoo and Abubakar, 2024),
\texttt{Algorithm~2.1} (Feng, Sun and Wang, 2017) and DLLA (Awwal et al.,
2023).
\medskip
\noindent
\textbf{Design.} Problems~1--6 are run at $n \in \{1000, 5000, 10\,000,
50\,000, 100\,000, 150\,000\}$ from the six initial points $x_1,\dots,x_6$ of
Section~4.1; Problem~7 is two-dimensional and uses its own six initial
points. That is $222$ instances and $888$ runs.
\medskip
\noindent
\textbf{Settings.} \texttt{BBSANME} uses $\rho = 0.80$, $a = 10^{-4}$,
$r = 10^{-3}$ and $\eta_k = 1/\exp(k^2)$. The parameters of the three
competing methods are those recommended in their own papers. Every run stops
when $\|\mathcal{H}(x_k)\| \le 10^{-6}$ or after $1000$ iterations.
\medskip
\noindent
\textbf{Reported quantities.} \#Itr is the number of iterations, \#Fev the
number of evaluations of $\mathcal{H}$, \#Tm the CPU time in seconds and
\#Nrm the residual norm at the returned point. \#Fev counts every evaluation:
the initial $\mathcal{H}(x_0)$, every backtracking trial including rejected
ones, and, for the three projection methods, the evaluation at the projection
point. The same convention applies to all four solvers.
\medskip
\noindent
\textbf{Environment.} %(env)s
\clearpage
"""
POSTAMBLE = r"""
\end{document}
"""
def main():
raw = sys.argv[1] if len(sys.argv) > 1 else "resultsA_raw.csv"
out = sys.argv[2] if len(sys.argv) > 2 else "Table2.tex"
env = sys.argv[3] if len(sys.argv) > 3 else "MATLAB, Microsoft Windows."
date = sys.argv[4] if len(sys.argv) > 4 else "\\today"
rows = read_raw(raw)
fams = sorted({r["family"] for r in rows}, key=lambda f: int(f[1:]))
body = "\n\\clearpage\n\n".join(table_for(rows, f) for f in fams)
with open(out, "w") as fh:
fh.write(PREAMBLE % dict(env=env, date=date))
fh.write(body)
fh.write(POSTAMBLE)
nfail = sum(1 for r in rows if not r["ok"])
print("%s written: %d runs, %d problems, %d not meeting the criterion"
% (out, len(rows), len(fams), nfail))
if __name__ == "__main__":
main()