11from __future__ import annotations
22
33import argparse
4+ import json
45import sys
56from dataclasses import dataclass
67from statistics import mean
@@ -142,39 +143,54 @@ def evaluate(problem_name: str, solver_name: str, config: SolverConfig, args):
142143 nifty_runtimes = []
143144
144145 for _ in range (args .n_repeats ):
145- bic_objective = bic .graph .MulticutObjective (bic_graph , costs )
146- start = perf_counter ()
147- bic_labels = config .make_bic_solver (args .threads ).optimize (bic_objective )
148- bic_runtimes .append (perf_counter () - start )
149- bic_energies .append (bic_energy (bic_graph , costs , bic_labels ))
150-
151- nifty_objective = nmc .multicutObjective (nifty_graph , costs )
152- start = perf_counter ()
153- nifty_labels = (
154- config .make_nifty_factory (nifty_objective , args .threads )
155- .create (nifty_objective )
156- .optimize ()
157- )
158- nifty_runtimes .append (perf_counter () - start )
159- nifty_energies .append (nifty_energy (nifty_graph , costs , nifty_labels ))
160-
161- bic_runtime = mean (bic_runtimes )
162- nifty_runtime = mean (nifty_runtimes )
146+ if args .backend in ("both" , "bic" ):
147+ bic_objective = bic .graph .MulticutObjective (bic_graph , costs )
148+ start = perf_counter ()
149+ bic_labels = config .make_bic_solver (args .threads ).optimize (bic_objective )
150+ bic_runtimes .append (perf_counter () - start )
151+ bic_energies .append (bic_energy (bic_graph , costs , bic_labels ))
152+
153+ if args .backend in ("both" , "nifty" ):
154+ nifty_objective = nmc .multicutObjective (nifty_graph , costs )
155+ start = perf_counter ()
156+ nifty_labels = (
157+ config .make_nifty_factory (nifty_objective , args .threads )
158+ .create (nifty_objective )
159+ .optimize ()
160+ )
161+ nifty_runtimes .append (perf_counter () - start )
162+ nifty_energies .append (nifty_energy (nifty_graph , costs , nifty_labels ))
163+
164+ bic_runtime = mean (bic_runtimes ) if bic_runtimes else None
165+ nifty_runtime = mean (nifty_runtimes ) if nifty_runtimes else None
166+ bic_energy_value = mean (bic_energies ) if bic_energies else None
167+ nifty_energy_value = mean (nifty_energies ) if nifty_energies else None
168+ energy_diff = (
169+ bic_energy_value - nifty_energy_value
170+ if bic_energy_value is not None and nifty_energy_value is not None
171+ else None
172+ )
163173 return {
164174 "problem" : problem_name ,
165175 "solver" : solver_name ,
166176 "nodes" : int (bic_graph .number_of_nodes ),
167177 "edges" : int (bic_graph .number_of_edges ),
168- "bic_energy" : mean ( bic_energies ) ,
169- "nifty_energy" : mean ( nifty_energies ) ,
170- "energy_diff" : mean ( bic_energies ) - mean ( nifty_energies ) ,
178+ "bic_energy" : bic_energy_value ,
179+ "nifty_energy" : nifty_energy_value ,
180+ "energy_diff" : energy_diff ,
171181 "bic_runtime_s" : bic_runtime ,
172182 "nifty_runtime_s" : nifty_runtime ,
173- "runtime_ratio" : nifty_runtime / bic_runtime if bic_runtime > 0 else float ("inf" ),
183+ "runtime_ratio" : (
184+ nifty_runtime / bic_runtime
185+ if bic_runtime is not None and nifty_runtime is not None and bic_runtime > 0
186+ else None
187+ ),
174188 }
175189
176190
177191def format_float (value : float ) -> str :
192+ if value is None :
193+ return ""
178194 return f"{ value :.6g} "
179195
180196
@@ -194,6 +210,13 @@ def print_progress(row: dict) -> None:
194210 )
195211
196212
213+ def append_jsonl (path : str , row : dict ) -> None :
214+ with open (path , "a" , encoding = "utf-8" ) as f :
215+ json .dump (row , f , sort_keys = True )
216+ f .write ("\n " )
217+ f .flush ()
218+
219+
197220def print_markdown_table (rows : list [dict ]) -> None :
198221 headers = [
199222 "problem" ,
@@ -250,6 +273,16 @@ def main() -> None:
250273 parser .add_argument ("--n-repeats" , type = int , default = 1 )
251274 parser .add_argument ("--threads" , type = int , default = 1 )
252275 parser .add_argument ("--timeout" , type = float , default = 30.0 )
276+ parser .add_argument (
277+ "--backend" ,
278+ choices = ("both" , "bic" , "nifty" ),
279+ default = "both" ,
280+ help = "Which implementation to run. Defaults to both." ,
281+ )
282+ parser .add_argument (
283+ "--results-jsonl" ,
284+ help = "Append each completed row to this JSONL file." ,
285+ )
253286 args = parser .parse_args ()
254287
255288 if args .n_repeats < 1 :
@@ -263,6 +296,8 @@ def main() -> None:
263296 row = evaluate (problem_name , solver_name , configs [solver_name ], args )
264297 rows .append (row )
265298 print_progress (row )
299+ if args .results_jsonl is not None :
300+ append_jsonl (args .results_jsonl , row )
266301 print_markdown_table (rows )
267302
268303
0 commit comments