From 953f522360885a35f716b5a3ca88183140980769 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sun, 14 May 2023 02:15:32 -0700 Subject: [PATCH] abstract loop body into Runner class --- thursday/go_benchmark_it.py | 127 ++++++++++++++++++++------------- thursday/utilities/utils_np.py | 9 +++ 2 files changed, 86 insertions(+), 50 deletions(-) diff --git a/thursday/go_benchmark_it.py b/thursday/go_benchmark_it.py index 6fcafbe..55fd629 100644 --- a/thursday/go_benchmark_it.py +++ b/thursday/go_benchmark_it.py @@ -153,6 +153,73 @@ for problem_list in GO_BENCHMARKS.values(): ), "please use Infinity instead; it's basically equivalent" +class Runner: + def __init__(self, multiple=2, run_anyway=3, always_run_anyway=True, quiet=False): + self.multiple = multiple + self.run_anyway = run_anyway + self.always_run_anyway = always_run_anyway + self.quiet = quiet + self._wrapped = None + + def run( + self, optimizer, objective, size, budget, frugal_percent=1.0, greedy_percent=2.0 + ): + note = (lambda s: None) if self.quiet else m36 + warn = m33 + + opt_name = optimizer.__name__ + obj_name = objective.__name__ + obj_realname = getattr(objective, "__realname__", obj_name) + + wrapped_kwargs = dict( + objective=objective, + optimizer=optimizer, + budget=budget, + size=size, + frugal_percent=frugal_percent, + greedy_percent=greedy_percent, + ) + if self._wrapped is None: + wrapped = COWrap(**wrapped_kwargs) + else: + # this can be 10+ times faster. + wrapped = self._wrapped.attempt_reuse(**wrapped_kwargs) + self._wrapped = wrapped + + results = [] + + run = 1 + while (cache := wrapped.cached(run)) is not None: + run += 1 + fopt, xopt, history = cache + results.append((fopt, opt_name, history)) + + once = False + while ( + run <= self.multiple + or (self.always_run_anyway or not once) + and self.run_anyway + and run <= self.run_anyway + ): + # assert run == wrapped._run, (run, wrapped._run) + if run != (_run := wrapped._run): + warn(f"Note: updating local run count from {run} to {_run}.") + run = _run + continue # check conditions again + + note( + f"Using {opt_name} to optimize {obj_realname} ({obj_name}) [{run}] ..." + ) + _ = optimizer(wrapped, size=size, budget=budget) + fopt, xopt = wrapped.finish() + result = (fopt, opt_name, wrapped.history) + results.append(result) + once = True + run += 1 + + return results + + def main(argv, display=True): from .utilities import fib from .utilities import prune_results, perform_another_experimental_scoring_method @@ -199,7 +266,7 @@ def main(argv, display=True): if type(score) is float: assert type(price) is float, "type mismatch" # unweight = 10 # len(optimizers) # sum(place_scores) - unweight = multiple * np.sqrt(len(optimizers)) + unweight = runner.multiple * np.sqrt(len(optimizers)) stats = f"(score:{score * unweight:4.0f}, price:{price * unweight:4.0f})" else: stats = f"(score:{score:4}, price:{price:4})" @@ -253,9 +320,7 @@ def main(argv, display=True): old_summary = True note = (lambda s: None) if quieter else m36 - multiple = 2 - run_anyway = 3 - always_run_anyway = True + runner = Runner() percents = dict(frugal_percent=1.0, greedy_percent=2.0) @@ -270,7 +335,11 @@ def main(argv, display=True): size = abs(size) objectives = GO_BENCHMARKS[size] # * multiple optimizers = list(which) # copy - ms = f" ({multiple}+{run_anyway-multiple} times)" if multiple != 1 else "" + ms = ( + f" ({runner.multiple}+{runner.run_anyway - runner.multiple} times)" + if runner.multiple != 1 + else "" + ) n_obj = len(objectives) n_opt = len(optimizers) print(f"Optimizing {n_obj} objectives{ms} with {n_opt} optimizers...") @@ -281,54 +350,12 @@ def main(argv, display=True): results = {} for optimizer in prog(pseudo_shuffled(optimizers), pref="m"): - opt_name = optimizer.__name__ - wrapped = None for objective in prog(pseudo_shuffled(objectives), pref="s"): - obj_name = objective.__name__ - obj_realname = getattr(objective, "__realname__", obj_name) - - if wrapped is None: - wrapped = COWrap( - objective, - optimizer=optimizer, - budget=budget, - size=size, - **percents, - ) - else: - wrapped.objective = objective # 10+ times faster - - run = 1 - while (cache := wrapped.cached(run)) is not None: - run += 1 - fopt, xopt, history = cache - results.setdefault(obj_name, []).append((fopt, opt_name, history)) - - once = False - while ( - run <= multiple - or (always_run_anyway or not once) - and run_anyway - and run <= run_anyway - ): - # assert run == wrapped._run, (run, wrapped._run) - if run != (_run := wrapped._run): - m33(f"Note: updating local run count from {run} to {_run}.") - run = _run - continue # check conditions again - - note( - f"Using {opt_name} to optimize {obj_realname} ({obj_name}) [{run}] ..." - ) - _ = optimizer(wrapped, size=size, budget=budget) - fopt, xopt = wrapped.finish() - result = (fopt, opt_name, wrapped.history) - results.setdefault(obj_name, []).append(result) - once = True - run += 1 + new_results = runner.run(optimizer, objective, size, budget) + results.setdefault(objective.__name__, []).extend(new_results) all_results = results - results = prune_results(results, multiple, _check=old_summary) + results = prune_results(results, runner.multiple, _check=old_summary) scores, prices = {}, {} all_opt_names = set() diff --git a/thursday/utilities/utils_np.py b/thursday/utilities/utils_np.py index deb544f..4c92c20 100644 --- a/thursday/utilities/utils_np.py +++ b/thursday/utilities/utils_np.py @@ -162,6 +162,15 @@ class COWrap: self._cached_summaries = None self.reset_objective() + # this should always have the same arguments as __init__. + def attempt_reuse(self, objective, *, optimizer, size, budget, **kwargs): + if self.optimizer != optimizer or self.size != size or self.budget != budget: + return type(self)( + objective, optimizer=optimizer, size=size, budget=budget, **kwargs + ) + self.objective = objective + return self + def __str__(self): return ( "