add history of optimal values and incorporate into each ranking

This commit is contained in:
Connor Olding 2023-05-05 14:11:44 -07:00
parent 3353b27884
commit 05343dad24
3 changed files with 82 additions and 28 deletions

View File

@ -269,21 +269,28 @@ if __name__ == "__main__":
new_results = {} new_results = {}
for obj_name, obj_res in results.items(): for obj_name, obj_res in results.items():
new_res = {} new_res = {}
for fopt, opt_name in sorted(obj_res): for fopt, opt_name, extra in sorted(obj_res):
new_res.setdefault(opt_name, []).append(fopt) l = new_res.setdefault(opt_name, [[], []])
for opt_name, fopts in new_res.items(): l[0].append(fopt)
l[1].append(extra)
slices = {}
for opt_name, res in new_res.items():
# in the event that an odd number of results needs to be trimmed, # in the event that an odd number of results needs to be trimmed,
# prefer trimming from the bottom (i.e. worse solutions get removed first). # prefer trimming from the bottom (i.e. worse solutions get removed first).
fopts, extras = res
down = (len(fopts) - multiple) // 2 down = (len(fopts) - multiple) // 2
up = len(fopts) - (len(fopts) - multiple + 1) // 2 up = len(fopts) - (len(fopts) - multiple + 1) // 2
# print("asdf", len(fopts), down, up) slices[opt_name] = slice(down, up)
new_res[opt_name] = fopts[down:up] for opt_name, res in new_res.items():
for opt_name, fopts in new_res.items(): fopts, extras = res
s = slices[opt_name]
fopts, extras = fopts[s], extras[s]
if not no_summary: if not no_summary:
assert len(fopts) == multiple, (len(fopts), multiple) assert len(fopts) == multiple, (len(fopts), multiple)
if len(fopts) == multiple: if len(fopts) == multiple:
for fopt in fopts: for fopt, extra in zip(fopts, extras):
new_results.setdefault(obj_name, []).append((fopt, opt_name)) result = (fopt, opt_name, extra)
new_results.setdefault(obj_name, []).append(result)
return results return results
reset = "\033[m" reset = "\033[m"
@ -354,8 +361,8 @@ if __name__ == "__main__":
run = 1 run = 1
while (cache := wrapped.cached(run)) is not None: while (cache := wrapped.cached(run)) is not None:
run += 1 run += 1
fopt, xopt = cache fopt, xopt, history = cache
results.setdefault(obj_name, []).append((fopt, opt_name)) results.setdefault(obj_name, []).append((fopt, opt_name, history))
note = (lambda s: None) if quieter else m36 note = (lambda s: None) if quieter else m36
@ -377,7 +384,8 @@ if __name__ == "__main__":
) )
_ = optimizer(wrapped, n_trials=n_trials, n_dim=n_dim, with_count=False) _ = optimizer(wrapped, n_trials=n_trials, n_dim=n_dim, with_count=False)
fopt, xopt = wrapped.finish() fopt, xopt = wrapped.finish()
results.setdefault(obj_name, []).append((fopt, opt_name)) result = (fopt, opt_name, wrapped.history)
results.setdefault(obj_name, []).append(result)
once = True once = True
run += 1 run += 1
@ -391,7 +399,7 @@ if __name__ == "__main__":
print() print()
m1(f"{obj_name}:") m1(f"{obj_name}:")
all_res = {} all_res = {}
for fopt, opt_name in obj_res: for fopt, opt_name, extra in obj_res:
all_res.setdefault(fopt, []).append(opt_name) all_res.setdefault(fopt, []).append(opt_name)
all_opt_names.add(opt_name) all_opt_names.add(opt_name)
scores.setdefault(opt_name, 0.0) scores.setdefault(opt_name, 0.0)

View File

@ -173,6 +173,16 @@ class AcquireForWriting:
def perform_another_experimental_scoring_method(results): def perform_another_experimental_scoring_method(results):
if len(results) and len(something := next(iter(results.values()))[0]) == 3:
history_length = len(something[2])
each = {}
for i in range(history_length):
# for k, v in results.items(): for vi in v: assert len(vi) == 3, vi
l = {k: [(res[2][i], res[1]) for res in v] for k, v in results.items()}
for k, v in perform_another_experimental_scoring_method(l).items():
each.setdefault(k, []).append(v)
return {k: sum(v) / len(v) for k, v in each.items()}
new_results = {} new_results = {}
all_opt_names = set() all_opt_names = set()
for obj_name, obj_res in results.items(): for obj_name, obj_res in results.items():
@ -203,7 +213,7 @@ def perform_another_experimental_scoring_method(results):
scores = {k: 0.0 for k in all_opt_names} scores = {k: 0.0 for k in all_opt_names}
for opt_name, (rank, count) in best_ranks_and_counts.items(): for opt_name, (rank, count) in best_ranks_and_counts.items():
points = 2**(1 - rank) points = 2 ** (1 - rank)
count = min(count, limited_by_floating_point_precision) count = min(count, limited_by_floating_point_precision)
scores[opt_name] = score = sum(points / 2**i for i in range(count)) scores[opt_name] = score = sum(points / 2**i for i in range(count))
@ -211,17 +221,18 @@ def perform_another_experimental_scoring_method(results):
def needs_rerun(key, value): def needs_rerun(key, value):
if value["duration"] < 0.0 or "history" not in value:
return True
if value["timestamp"] < 1683295630.0: # bugged history field
return True
if not value["history"]: # not sure what happened here
return True
n_dim = len(value["xopt"]) n_dim = len(value["xopt"])
ng = [] ng = []
if value["duration"] > -1683000000.0:
if n_dim == 3:
ng += "go_ackley01 go_alpine01 go_deflectedcorrugatedspring go_exponential go_griewank go_infinity go_mishra11 go_multimodal go_pinter go_qing go_rastrigin go_salomon go_schwefel01 go_schwefel20 go_schwefel21 go_schwefel22 go_sineenvelope go_sodp go_trigonometric02 go_wavy go_weierstrass go_xinsheyang01 go_xinsheyang02 go_xinsheyang03 go_yaoliu04 go_yaoliu09 go_zerosum".split()
ng += "go_amgm go_brown go_cigar go_deb01 go_deb03 go_deceptive go_needleeye go_penalty01 go_schwefel04 go_schwefel26 go_sphere go_stretchedv go_styblinskitang go_zacharov".split()
if n_dim == 4:
ng += "go_ackley01 go_alpine01 go_cigar go_exponential go_griewank go_infinity go_pinter go_qing go_schwefel01 go_schwefel02 go_schwefel20 go_schwefel21 go_schwefel22 go_sineenvelope go_sphere go_step2 go_step go_stretchedv go_trigonometric02 go_weierstrass go_whitley go_xinsheyang01 go_xinsheyang02 go_yaoliu04 go_yaoliu09 go_zerosum".split()
ng += "go_amgm go_brown go_colville go_deb03 go_penalty01 go_penalty02 go_powell go_rosenbrock go_schwefel04 go_shekel05 go_shekel07 go_shekel10 go_shubert03 go_shubert04 go_styblinskitang go_vincent".split()
kd = decode_key(key) kd = decode_key(key)
assert kd is not None, key assert kd is not None, key
if kd.obj in ng: if kd.obj in ng:

View File

@ -1,4 +1,5 @@
# i've separated numpy-dependent methods from the rest of the utils. # i've separated numpy-dependent methods from the rest of the utils.
from time import time
from utils import AcquireForWriting, merge_summaries, feps, m33, m34, m93 from utils import AcquireForWriting, merge_summaries, feps, m33, m34, m93
import numpy as np import numpy as np
@ -60,7 +61,14 @@ def do_bounding(x, method="clip"):
class OWrap: class OWrap:
def __init__(self, objective, n_trials, frugal_percent=1.0, greedy_percent=2.0): def __init__(
self,
objective,
n_trials,
frugal_percent=1.0,
greedy_percent=2.0,
history_frequency=10,
):
self.feval_count = 0 self.feval_count = 0
self.best_so_far = None self.best_so_far = None
self.warning = None self.warning = None
@ -69,6 +77,8 @@ class OWrap:
self.__name__ = objective.__name__ # for evolopy self.__name__ = objective.__name__ # for evolopy
self.frugal_percent = float(frugal_percent) self.frugal_percent = float(frugal_percent)
self.greedy_percent = float(greedy_percent) self.greedy_percent = float(greedy_percent)
self.history_frequency = history_frequency
self.history = []
def __str__(self): def __str__(self):
return ( return (
@ -106,6 +116,10 @@ class OWrap:
if self.best_so_far is None or fx < self.best_so_far[0]: if self.best_so_far is None or fx < self.best_so_far[0]:
self.best_so_far = (fx, x) self.best_so_far = (fx, x)
if self.history_frequency > 0:
if self.feval_count % self.history_frequency == 0:
self.history.append(self.best_so_far[0])
return float(fx) return float(fx)
def finish(self, optimizer_name): def finish(self, optimizer_name):
@ -137,6 +151,7 @@ class COWrap:
self.n_dim = n_dim self.n_dim = n_dim
self.kwargs = kwargs self.kwargs = kwargs
self._dirty = False self._dirty = False
self._history = None
from pathlib import Path from pathlib import Path
@ -157,6 +172,8 @@ class COWrap:
def __call__(self, x, *args, **kwargs): def __call__(self, x, *args, **kwargs):
assert not self._ran, "please run .finish() before continuing!" assert not self._ran, "please run .finish() before continuing!"
if not self._dirty:
self.start_time = time()
result = self.ow.__call__(x, *args, **kwargs) result = self.ow.__call__(x, *args, **kwargs)
self._dirty = True self._dirty = True
return result return result
@ -176,6 +193,12 @@ class COWrap:
opt_name = self.optimizer.__name__ opt_name = self.optimizer.__name__
return f"COWrap_d{self.n_dim:02}_n{self.n_trials:03}_{opt_name}" return f"COWrap_d{self.n_dim:02}_n{self.n_trials:03}_{opt_name}"
@property
def history(self):
assert not self._dirty
assert self._history
return self._history
@property @property
def cache_key(self): def cache_key(self):
opt_name = self.optimizer.__name__ opt_name = self.optimizer.__name__
@ -237,15 +260,16 @@ class COWrap:
return None return None
assert "fopt" in summary, summary assert "fopt" in summary, summary
assert "xopt" in summary, summary assert "xopt" in summary, summary
assert "duration" in summary, summary assert "timestamp" in summary, summary
assert "history" in summary, summary
fopt = float(summary["fopt"]) fopt = float(summary["fopt"])
xopt = np.array(summary["xopt"], np.float64) xopt = np.array(summary["xopt"], np.float64)
duration = float(summary["duration"]) history = [fval for fval in summary["history"]]
return fopt, xopt assert history, "history cannot be empty" # this should get filtered now
return fopt, xopt, history
def finish(self, opt_name=None): def finish(self, opt_name=None):
from json import dumps from json import dumps
from time import time
assert self._dirty assert self._dirty
self._ran = True self._ran = True
@ -255,12 +279,23 @@ class COWrap:
assert self.ow.best_so_far is not None assert self.ow.best_so_far is not None
# fopt, xopt = self.ow.best_so_far # fopt, xopt = self.ow.best_so_far
fopt, xopt = self.ow.finish(self.optimizer.__name__) fopt, xopt = self.ow.finish(self.optimizer.__name__)
expected_length = self.n_trials // self.ow.history_frequency
history = [float(fval) for fval in self.ow.history]
history += [fopt] * (expected_length - len(history))
finish_time = time()
summary = dict( summary = dict(
fopt=float(fopt), fopt=float(fopt),
xopt=[float(x) for x in xopt], xopt=[float(x) for x in xopt],
# duration=float(-1), # old, bad for uniqueness # timestamp=float(-1), # old, bad for uniqueness
duration=float(-time()), timestamp=finish_time,
# optional: (for now?)
history=history,
duration=finish_time - self.start_time,
) )
self._history = summary["history"]
assert self._history, "why"
with AcquireForWriting(self.cache_file) as fp: with AcquireForWriting(self.cache_file) as fp:
self._cached_summaries = None # force reload self._cached_summaries = None # force reload