abstract loop body into Runner class

This commit is contained in:
Connor Olding 2023-05-14 02:15:32 -07:00
parent 3c7b41b562
commit 953f522360
2 changed files with 86 additions and 50 deletions

View file

@ -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()

View file

@ -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 (
"<COWrap on "