From 4829cbb0af9269abbe8de947c0aa2863af79c15d Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Thu, 4 May 2023 08:22:54 -0700 Subject: [PATCH] add the bare-ish minimum to get things going --- .gitignore | 2 + generate_lists.py | 69 ++++++ go_benchmark_it.py | 497 ++++++++++++++++++++++++++++++++++++++++ go_benchmark_lists.py | 371 ++++++++++++++++++++++++++++++ go_benchmarks.py | 49 ++++ nloptcube2.py | 218 ++++++++++++++++++ notwacube.py | 12 + prog80.py | 442 +++++++++++++++++++++++++++++++++++ project.py | 41 ++++ randomcube2.py | 35 +++ solutions_1680721604.py | 485 +++++++++++++++++++++++++++++++++++++++ solutions_1680730206.py | 242 +++++++++++++++++++ solutions_1680975848.py | 251 ++++++++++++++++++++ utils.py | 263 +++++++++++++++++++++ utils_np.py | 257 +++++++++++++++++++++ 15 files changed, 3234 insertions(+) create mode 100755 generate_lists.py create mode 100644 go_benchmark_it.py create mode 100644 go_benchmark_lists.py create mode 100644 go_benchmarks.py create mode 100644 nloptcube2.py create mode 100644 notwacube.py create mode 100755 prog80.py create mode 100644 project.py create mode 100644 randomcube2.py create mode 100644 solutions_1680721604.py create mode 100644 solutions_1680730206.py create mode 100644 solutions_1680975848.py create mode 100644 utils.py create mode 100644 utils_np.py diff --git a/.gitignore b/.gitignore index 96403d3..9f27c88 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ __pycache__/* +*.old +*.bak diff --git a/generate_lists.py b/generate_lists.py new file mode 100755 index 0000000..d82e046 --- /dev/null +++ b/generate_lists.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +from types import ModuleType +import solutions_1680721604 +import solutions_1680730206 +import solutions_1680730206 +import solutions_1680975848 + +solutions = {} +loaded = [] +for local_k in tuple(locals().keys()): + local_v = locals()[local_k] + if local_k.startswith("solutions_") and isinstance(local_v, ModuleType): + loaded.append(local_k) + for k, v in local_v.solutions.items(): + solutions.setdefault(k, {}) + solutions[k] |= v + +dims_seen = set() +totally_fine = {} +too_variable = {} +too_centered = {} +too_far_away = {} +too_positive = {} +for k, v in solutions.items(): + fopt = sorted(v)[0] + xopt = v[fopt] + dims = len(xopt) + dims_seen.add(dims) + alpha = [0, 256, 200, 100, 64][dims] + name = k.removeprefix("go_").removesuffix(str(dims)).removesuffix("_on_cube__") + is_too_centered = all(round(x * alpha) == alpha // 2 for x in xopt) + is_too_positive = sum(abs(x - sum(xopt) / dims) for x in xopt) / dims <= 1e-3 + is_too_far_away = any(abs(0.5 - x) > 0.49 for x in xopt) + is_inconsistent = name in ("stochastic", "xinsheyang01") + if name == "csendes": + pass # skip; this is basically equivalent to "infinite" + elif is_inconsistent: + too_variable.setdefault(dims, []).append(name) + elif is_too_centered: + too_centered.setdefault(dims, []).append(name) + elif is_too_far_away: + too_far_away.setdefault(dims, []).append(name) + elif is_too_positive: + too_positive.setdefault(dims, []).append(name) + else: + totally_fine.setdefault(dims, []).append(name) + + +def dump_list(name, rows): + print() + print(f"{name} = [") + for row in rows: + print(f" {repr(row)},") + print("]") + + +print("# this file was automatically generated by generate_lists.py,") +print("# any changes may be overwritten!") +for name in loaded: + print(f"# loaded {name}.py") +for dims in sorted(dims_seen): + dump_list(f"too_variable_{dims}", too_variable.get(dims, [])) + dump_list(f"too_centered_{dims}", too_centered.get(dims, [])) + dump_list(f"too_far_away_{dims}", too_far_away.get(dims, [])) + dump_list(f"too_positive_{dims}", too_positive.get(dims, [])) + dump_list(f"totally_fine_{dims}", totally_fine.get(dims, [])) + + # print(len(totally_fine)) + # print(len(totally_fine) + len(too_centered) + len(too_positive)) diff --git a/go_benchmark_it.py b/go_benchmark_it.py new file mode 100644 index 0000000..52f8bfc --- /dev/null +++ b/go_benchmark_it.py @@ -0,0 +1,497 @@ +from go_benchmark_lists import * +from go_benchmarks import problems_2d, problems_3d, problems_4d +from notwacube import book_of_optimizers +from prog80 import prog +from utils import OWrap, COWrap, m1, m33, m36 +from utils import perform_another_experimental_scoring_method +import numpy as np + +all_problems = { + 2: problems_2d, + 3: problems_3d, + 4: problems_4d, +} + +tiny_offset = 1.1102230246251565e-16 + + +def make_transform(lo, hi): + mul = max(lo, hi) - min(lo, hi) + add = min(lo, hi) + return mul, add + + +def flipit(transformations, flippy): + flip_dim = flippy - 1 + mul, add = transformations[flip_dim] + desired_mul, desired_add = -1, 1 # f(g(x)) = f(1 - x) + mul, add = mul * desired_mul, mul * desired_add + add + transformations[flip_dim] = (mul, add) + + +def make_objective(problem, n_dim, *, fix_stuff=0): + obj = problem(n_dim) + name = problem.__name__ + flippy = 0 # when positive, helps removes positive correlations in solutions + trippy = None # when not None, moves solution away from center: (dim, dir) + + if fix_stuff >= 0: + if name == "Deb03": + # this problem has the wrong bounds for some reason, so we have to patch it. + obj._bounds = list(zip([0.0] * obj.N, [1.0] * obj.N)) + elif name == "Csendes" or name == "Infinity": + # this problem is weird... let's avoid division by zero, okay? + # these problems are duplicates of each other. weird. + replacement = n_dim * (2 + np.sin(1)) + _fun = obj.fun + obj.fun = lambda x: replacement if np.any(x == 0.0) else _fun(x) + elif name == "Keane": + # another problem that may attempt to divide by zero. + _fun = obj.fun + obj.fun = lambda x: 0.0 if np.all(x**2 == 0.0) else _fun(x) + elif name == "Kowalik": + # this divide by zero actually approaches infinity when not clipped. + # TODO: there seems to be some confusion about which is `a` + # and which is `b` between the equations and the code. + # hmm it seems like the code is right, judging by this: + # https://www.itl.nist.gov/div898/strd/nls/data/LINKS/DATA/MGH09.dat + helper = lambda x: np.where(x < 0, -1, 1) * ( + np.abs(x) + tiny_offset + ) + # 1.0 - 1e-16 == 0.9999999999999999 + # 1.0 + 1e-16 == 1.0 + # 1.0 + 2e-16 == 1.0000000000000002 + # 1 / 1.1102230246251565e-16**2 == 8.112963841460668e+31 + a, b = obj.a, obj.b + obj.fun = ( + lambda x: sum( + b - (x[0] * (a**2 + a * x[1]) / helper(a**2 + a * x[2] + x[3])) + ) + ** 2 + ) + elif name == "Gulf": + # just another division by zero. + adjust = np.array([tiny_offset, 0.0, 0.0]) + _fun = obj.fun + obj.fun = lambda x: _fun(x + adjust) + + if fix_stuff >= 1: + stuff = {2: too_positive_2, 3: too_positive_3, 4: too_positive_4}[n_dim] + if name.lower() in stuff: + # too positively correlated, do some evil. + ind = stuff.index(name.lower()) + flippy = ind % n_dim + 1 # uniformly select a dimension to "flip" + + if fix_stuff >= 2: + stuff = {2: too_centered_2, 3: too_centered_3, 4: too_centered_4}[n_dim] + if name.lower() in stuff: + # uniformly select offsets to "trip". + ind = stuff.index(name.lower()) + trippy = (ind % n_dim, ind // n_dim % n_dim) # (dim, dir) + + transformations = [make_transform(lo, hi) for lo, hi in obj.bounds] + + if flippy: + flipit(transformations, flippy) + + def objective(x): + # assert all(xi >= 0.0 for xi in x), list(float(xi) for xi in x) + # assert all(xi <= 1.0 for xi in x), list(float(xi) for xi in x) + if trippy: + x = list(x) # mostly to create a copy + ind = trippy[0] + x[ind] = 1 - (1 - x[ind]) ** 0.5 if trippy[1] else x[ind] ** 0.5 + x = [xi * mul + add for xi, (mul, add) in zip(x, transformations)] + # if problem.__name__.startswith("Deb"): print(x) + return obj.fun(np.array(x, copy=False)) + + objective.__name__ = f"go_{problem.__name__.lower()}_on_cube" + objective.__realname__ = problem.__name__ + # objective.__qualname__ = problem.__name__ + return objective + + +def make_objectives(n_dim, n_trials=None, fix_stuff=0): + problems = all_problems[n_dim] + return [make_objective(problem, n_dim, fix_stuff=fix_stuff) for problem in problems] + + +def find_objective(query, n_dim=None): + results = [] + for p_dim, problems in all_problems.items(): + if n_dim is not None and p_dim != n_dim: + continue + for problem in problems: + if problem.__name__.lower() == query.lower(): + results.append(problem) + assert results, "no results found for name " + repr(query) + return results[0] + + +λ = lambda q: make_objective(find_objective(q, 2), 2, fix_stuff=2) +GO_BENCHMARK_2D_PROBLEMS = list( + map(λ, totally_fine_2 + too_positive_2 + too_centered_2) +) + +λ = lambda q: make_objective(find_objective(q, 3), 3, fix_stuff=2) +GO_BENCHMARK_3D_PROBLEMS = list( + map(λ, totally_fine_3 + too_positive_3 + too_centered_3) +) + +λ = lambda q: make_objective(find_objective(q, 4), 4, fix_stuff=2) +GO_BENCHMARK_4D_PROBLEMS = list( + map(λ, totally_fine_4 + too_positive_4 + too_centered_4) +) + +GO_BENCHMARKS = { + 2: GO_BENCHMARK_2D_PROBLEMS, + 3: GO_BENCHMARK_3D_PROBLEMS, + 4: GO_BENCHMARK_4D_PROBLEMS, +} + +for problem_list in GO_BENCHMARKS.values(): + for problem in problem_list: + # print(problem.__realname__) + assert ( + problem.__realname__ != "Csendes" + ), "please use Infinity instead; it's basically equivalent" + + +if __name__ == "__main__": + from tqdm import tqdm + import sys + + def fib(n): + return pow(2 << n, n + 1, (4 << 2 * n) - (2 << n) - 1) % (2 << n) + + def optimizer_filter(name): + # worst scoring optimizers: (awards=(5, 3, 2, 1)) (obj=146, opt=389) (dims=2, evals=80) + # evosax_pbt with (score: 0, price: 593) -593 + # worst scoring optimizers: (awards=(5, 3, 2, 1)) (obj=70, opt=389) (dims=3, evals=1440) + # evosax_pbt with (score: 0, price: 315) -315 + return not ( + False + # or name.startswith("freelunch_krillherd_") # too buggy + or name == "ng_fcma_cube" # WTF HOW ARE YOU NAN'ING ON HYPERSPHERE + or name == "ngx_fcmas03_cube" # same thing but quintic + or name == "ngx_zero_cube" # 0 score, high price + # or name == "ngx_microcma_cube" # 0 score, high price + # or name == "ng_multiscalecma_cube" # 0 score, high price + or name == "evosax_pbt_cube" # 0 score, high price + or name == "evosax_guidedes_cube" # does get *a little* score... + or name == "freelunch_sa_ps04_cube" + or name == "ngx_microcma_cube" + ) + + def stfu(please_be_quiet=None): + if please_be_quiet is None: + please_be_quiet = ( + "ng_ascmadethird_cube", + "ng_cmabounded_cube", + "ng_cmatuning_cube", + "ng_chaincmapowell_cube", + "ng_chainnaivetbpsacmapowell_cube", + "ng_paraportfolio_cube", + "ng_rescaledcma_cube", + ) + + for optimizer in optimizers: + name = optimizer.__name__ + if any(obnoxious in name for obnoxious in please_be_quiet): + import warnings + from cma.evolution_strategy import InjectionWarning + + warnings.simplefilter("ignore", InjectionWarning) # not our fault + break + + def mark(opt_name): + return ( + "\033[95m@" + if opt_name in ("another_random_cube", "quasirandom_cube") + else "\033[96m!" + if "nelder" in opt_name + else " " + ) + + def fancy_output(opt_name, score, price): + name = opt_name.removesuffix("_cube") + 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)) + stats = f"(score:{score * unweight:4.0f}, price:{price * unweight:4.0f})" + else: + stats = f"(score:{score:4}, price:{price:4})" + color = 0 + reset = "\033[m" + # this will need adjusting depending on your terminal colors: + gradient = (32, 92, 93, 33, 91) # good to bad + + if score == 0 and price == 0: + pass # wat? + elif score < 0 and price < 0: + color = 35 # wat?! + elif score > 0 and price == 0: + color = gradient[0] # good + elif score == 0 and price > 0: + color = gradient[4] # awful + elif score > price: + color = gradient[1] # ok + elif score == price: + color = gradient[2] # meh + elif score < price: + color = gradient[3] # bad + color = f"\033[{color}m" + + s = f"{mark(opt_name)} {name:<32}{reset} with {color}{stats}{reset}" + + delta = score - price + if type(score) is float: + delta *= unweight + color = 0 + if delta > 6: + color = gradient[0] + elif delta < -6: + color = gradient[4] + elif delta > 1: + color = gradient[1] + elif delta < -1: + color = gradient[3] + else: + color = gradient[2] + color = f"\033[{color}m" + s += f" {color}{float(delta):+.0f}{reset}" + # s += f" {color}{delta:+}{reset}" + + return s + + def prune_results(results, multiple): + # if there are more than `multiple` results for one optimizer+objective pair, + # then trim the bottom and top until there are only `multiple` left. + new_results = {} + for obj_name, obj_res in results.items(): + new_res = {} + for fopt, opt_name in sorted(obj_res): + new_res.setdefault(opt_name, []).append(fopt) + for opt_name, fopts in new_res.items(): + # 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). + down = (len(fopts) - multiple) // 2 + up = len(fopts) - (len(fopts) - multiple + 1) // 2 + # print("asdf", len(fopts), down, up) + new_res[opt_name] = fopts[down:up] + for opt_name, fopts in new_res.items(): + if not no_summary: + assert len(fopts) == multiple, (len(fopts), multiple) + if len(fopts) == multiple: + for fopt in fopts: + new_results.setdefault(obj_name, []).append((fopt, opt_name)) + return results + + reset = "\033[m" + + quieter = True + please_stop_the_spam = True + no_summary = True + + if 1: + multiple = 2 + run_anyway = 3 # run_anyway = 7 + always_run_anyway = True + else: + multiple = 1 + run_anyway = 3 + always_run_anyway = False + + #percents = dict(frugal_percent=0.1, greedy_percent=1.5) + percents = dict(frugal_percent=1.0, greedy_percent=2.0) + + book = book_of_optimizers + which = book[sys.argv[1]] if len(sys.argv) > 1 else book["standard"] + n_dim = int(sys.argv[2]) if len(sys.argv) > 2 else -2 + n_trials = int(sys.argv[3]) if len(sys.argv) > 3 else fib(abs(n_dim) + 4) * 10 + + place_names = ("1st", "2nd", "3rd", "4th") + assert n_dim < 0, "unsupported in this version" + n_dim = abs(n_dim) + place_scores = (5, 3, 2, 1) + objectives = GO_BENCHMARKS[n_dim] # * multiple + + optimizers = list(which) # copy + before = len(optimizers) + # if which is not book["everything"]: + optimizers = [opt for opt in optimizers if optimizer_filter(opt.__name__)] + after = len(optimizers) + s = "s" if before - after != 1 else "" + print(f"Pruned {before - after} unwanted optimizer{s}.") + + ms = f" ({multiple} times)" if multiple != 1 else "" + n_obj = len(objectives) + n_opt = len(optimizers) + print(f"Optimizing {n_obj} objectives{ms} with {n_opt} optimizers...") + + stfu() + + pseudo_shuffled = lambda stuff: sorted(stuff, key=lambda obj: hash(repr(obj))) + + 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, + n_trials=n_trials, + n_dim=n_dim, + **percents, + ) + else: + wrapped.objective = objective # 10+ times faster + + run = 1 + while (cache := wrapped.cached(run)) is not None: + run += 1 + fopt, xopt = cache + results.setdefault(obj_name, []).append((fopt, opt_name)) + + note = (lambda s: None) if quieter else m36 + + 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, n_trials=n_trials, n_dim=n_dim, with_count=False) + fopt, xopt = wrapped.finish() + results.setdefault(obj_name, []).append((fopt, opt_name)) + once = True + run += 1 + + all_results = results + results = prune_results(results, multiple) + + scores, prices = {}, {} + all_opt_names = set() + for obj_name, obj_res in results.items(): + if not please_stop_the_spam: + print() + m1(f"{obj_name}:") + all_res = {} + for fopt, opt_name in obj_res: + all_res.setdefault(fopt, []).append(opt_name) + all_opt_names.add(opt_name) + scores.setdefault(opt_name, 0.0) + prices.setdefault(opt_name, 0.0) + sorted_res = sorted(all_res) + score_insignificance = sum( + len(all_res[fopt]) + for _, fopt in zip(range(len(place_scores)), sorted_res) + ) + price_insignificance = sum( + len(all_res[fopt]) + for _, fopt in zip(range(len(place_scores)), reversed(sorted_res)) + ) + # print("score 1/x:", obj_name, score_insignificance) + # print("price 1/x:", obj_name, price_insignificance) + for i, fopt in enumerate(sorted_res): + # if i >= len(place_scores): # TODO: just make this part of the loop. + # break + mi = len(all_res) - i - 1 + if i < len(place_scores): + for opt_name in all_res[fopt]: + scores[opt_name] = ( + scores[opt_name] + place_scores[i] / score_insignificance + ) + if mi < len(place_scores): + for opt_name in all_res[fopt]: + prices[opt_name] = ( + prices[opt_name] + place_scores[mi] / price_insignificance + ) + + more_scores = perform_another_experimental_scoring_method(results) + + for blah, points in zip(("best", "worst"), (scores, prices)): + if not no_summary: + print( + f"\n\033[1m{blah} scoring optimizers:\033[m" + f" (awards={place_scores})" + f" (obj={len(objectives)}, opt={len(optimizers)})" + f" (dims={n_dim}, evals={n_trials})" + ) + for opt_name, opt_point in sorted(points.items(), key=lambda t: -t[1]): + # place = place_names[i] if i < len(place_names) else " " + # delta = scores.get(opt_name, 0) - prices.get(opt_name, 0) + if not no_summary: + print( + fancy_output( + opt_name, scores.get(opt_name, 0), prices.get(opt_name, 0) + ) + ) + + positive, negative = [], [] + for opt_name in sorted(all_opt_names): + delta = scores.get(opt_name, 0) - prices.get(opt_name, 0) + # note: this intentionally includes delta == 0 in both positive and negative. + if delta >= 0: + if opt_name not in positive: + positive.append(opt_name) + if delta <= 0: + if opt_name not in negative: + negative.append(opt_name) + + if no_summary: + print( + f"\n\033[1malternatively scored optimizers:\033[m" + f" (awards={place_scores})" + f" (obj={len(objectives)}, opt={len(optimizers)})" + f" (dims={n_dim}, evals={n_trials})" + ) + for opt_name, opt_score in sorted(more_scores.items(), key=lambda t: -t[1]): + # if opt_score < 1: continue + stats = f"{opt_score:18.16f}" + name = opt_name.removesuffix("_cube") + color = "\033[1m" if opt_score > 1.0 else "\033[33m" if opt_score < 1.0 else "" + s = f"{mark(opt_name)} {name:<32}{reset} with {color}{stats}{reset}" + # s += f" {color}{float(delta):+.0f}{reset}" + print(s) + + text = "# this file was automatically generated by go_benchmark_it.py,\n" + text += "# any changes may be overwritten!\n" + + text += "PREVIOUSLY_POSITIVE = [\n" + text += "".join(f' "{opt_name}",\n' for opt_name in positive) + text += "]\n" + + text += "PREVIOUSLY_NEGATIVE = [\n" + text += "".join(f' "{opt_name}",\n' for opt_name in negative) + text += "]\n" + + if positive or negative: + try: + __import__("pathlib").Path("previous.py").write_text(text) + except PermissionError: + print("# failed to write previous.py, ignoring...") + + if len(sys.argv) > 1 and sys.argv[1] in ("positive", "negative"): + all_old_opt_names = set(opt.__name__ for opt in optimizers) + C = set(("quasirandom_cube", "another_random_cube")) + if sys.argv[1] == "positive" and set(positive) - C == all_old_opt_names - C: + exit(2) # no changes + if sys.argv[1] == "negative" and set(negative) - C == all_old_opt_names - C: + exit(2) # no changes diff --git a/go_benchmark_lists.py b/go_benchmark_lists.py new file mode 100644 index 0000000..63aea32 --- /dev/null +++ b/go_benchmark_lists.py @@ -0,0 +1,371 @@ +# this file was automatically generated by generate_lists.py, +# any changes may be overwritten! +# loaded solutions_1680721604.py +# loaded solutions_1680730206.py +# loaded solutions_1680975848.py + +too_variable_2 = [ + 'stochastic', + 'xinsheyang01', +] + +too_centered_2 = [ + 'ackley01', + 'ackley02', + 'bartelsconn', + 'bohachevsky2', + 'bukin04', + 'bukin06', + 'cigar', + 'deflectedcorrugatedspring', + 'dropwave', + 'exponential', + 'griewank', + 'infinity', + 'matyas', + 'needleeye', + 'pathological', + 'pinter', + 'price02', + 'price04', + 'qing', + 'rotatedellipse01', + 'rotatedellipse02', + 'salomon', + 'sargan', + 'schaffer01', + 'schaffer02', + 'schwefel01', + 'schwefel02', + 'sphere', + 'threehumpcamel', + 'treccani', + 'trigonometric02', + 'ursem04', + 'ventersobiezcczanskisobieski', + 'wayburnseader02', + 'xinsheyang02', + 'xinsheyang03', + 'xinsheyang04', + 'yaoliu04', + 'yaoliu09', +] + +too_far_away_2 = [ + 'adjiman', + 'brent', + 'crosslegtable', + 'eggholder', + 'katsuura', + 'mishra01', + 'mishra02', + 'mishra03', + 'mishra05', + 'newfunction01', + 'newfunction02', + 'rana', + 'trigonometric01', + 'ursemwaves', +] + +too_positive_2 = [ + 'amgm', + 'brown', + 'cosinemixture', + 'crossintray', + 'cube', + 'deb01', + 'deb03', + 'decanomial', + 'easom', + 'eggcrate', + 'giunta', + 'jennrichsampson', + 'keane', + 'levy03', + 'mishra04', + 'penalty01', + 'penalty02', + 'penholder', + 'price03', + 'quintic', + 'schwefel04', + 'schwefel20', + 'schwefel26', + 'shubert03', + 'step2', + 'styblinskitang', + 'testtubeholder', + 'vincent', + 'weierstrass', + 'zacharov', + 'zettl', +] + +totally_fine_2 = [ + 'ackley03', + 'alpine01', + 'alpine02', + 'beale', + 'biggsexp02', + 'bird', + 'bohachevsky1', + 'bohachevsky3', + 'branin01', + 'branin02', + 'bukin02', + 'carromtable', + 'chichinadze', + 'crownedcross', + 'damavandi', + 'deceptive', + 'deckkersaarts', + 'dixonprice', + 'elattarvidyasagardutta', + 'exp2', + 'freudensteinroth', + 'goldsteinprice', + 'hansen', + 'himmelblau', + 'holdertable', + 'hosaki', + 'judge', + 'langermann', + 'leon', + 'levy05', + 'levy13', + 'mccormick', + 'michalewicz', + 'mishra06', + 'mishra07', + 'mishra08', + 'mishra10', + 'mishra11', + 'multimodal', + 'oddsquare', + 'parsopoulos', + 'permfunction01', + 'permfunction02', + 'plateau', + 'price01', + 'quadratic', + 'rastrigin', + 'ripple01', + 'ripple25', + 'rosenbrock', + 'rosenbrockmodified', + 'schaffer03', + 'schaffer04', + 'schwefel06', + 'schwefel21', + 'schwefel22', + 'schwefel36', + 'shubert01', + 'shubert04', + 'sineenvelope', + 'sixhumpcamel', + 'sodp', + 'step', + 'stretchedv', + 'trefethen', + 'tripod', + 'ursem01', + 'ursem03', + 'wavy', + 'wayburnseader01', + 'whitley', + 'zerosum', + 'zimmerman', + 'zirilli', +] + +too_variable_3 = [ + 'stochastic', + 'xinsheyang01', +] + +too_centered_3 = [ + 'ackley01', + 'alpine01', + 'deflectedcorrugatedspring', + 'exponential', + 'griewank', + 'infinity', + 'mishra11', + 'multimodal', + 'pinter', + 'qing', + 'rastrigin', + 'salomon', + 'schwefel01', + 'schwefel20', + 'schwefel21', + 'schwefel22', + 'sineenvelope', + 'sodp', + 'trigonometric02', + 'wavy', + 'weierstrass', + 'xinsheyang02', + 'xinsheyang03', + 'yaoliu04', + 'yaoliu09', + 'zerosum', +] + +too_far_away_3 = [ + 'cosinemixture', + 'katsuura', + 'meyer', + 'mishra01', + 'mishra02', + 'rana', + 'trigonometric01', + 'whitley', + 'wolfe', +] + +too_positive_3 = [ + 'amgm', + 'brown', + 'cigar', + 'deb01', + 'deb03', + 'deceptive', + 'needleeye', + 'penalty01', + 'schwefel04', + 'schwefel26', + 'sphere', + 'stretchedv', + 'styblinskitang', + 'zacharov', +] + +totally_fine_3 = [ + 'alpine02', + 'biggsexp03', + 'boxbetts', + 'dixonprice', + 'eckerle4', + 'eggholder', + 'gulf', + 'hartmann3', + 'helicalvalley', + 'mishra07', + 'mishra09', + 'penalty02', + 'permfunction01', + 'permfunction02', + 'plateau', + 'quadratic', + 'quintic', + 'ratkowsky02', + 'rosenbrock', + 'sargan', + 'schwefel02', + 'shubert01', + 'shubert03', + 'shubert04', + 'step2', + 'step', + 'vincent', + 'xinsheyang04', +] + +too_variable_4 = [ + 'stochastic', + 'xinsheyang01', +] + +too_centered_4 = [ + 'ackley01', + 'alpine01', + 'cigar', + 'exponential', + 'griewank', + 'infinity', + 'pinter', + 'qing', + 'schwefel01', + 'schwefel02', + 'schwefel20', + 'schwefel21', + 'schwefel22', + 'sineenvelope', + 'sphere', + 'step2', + 'step', + 'stretchedv', + 'trigonometric02', + 'weierstrass', + 'whitley', + 'xinsheyang02', + 'yaoliu04', + 'yaoliu09', + 'zerosum', +] + +too_far_away_4 = [ + 'corana', + 'cosinemixture', + 'devilliersglasser01', + 'katsuura', + 'mielecantrell', + 'mishra01', + 'mishra02', + 'rana', + 'sargan', + 'trigonometric01', + 'xinsheyang03', +] + +too_positive_4 = [ + 'amgm', + 'brown', + 'colville', + 'deb03', + 'penalty01', + 'penalty02', + 'powell', + 'rosenbrock', + 'schwefel04', + 'shekel05', + 'shekel07', + 'shekel10', + 'shubert03', + 'shubert04', + 'styblinskitang', + 'vincent', +] + +totally_fine_4 = [ + 'alpine02', + 'biggsexp04', + 'deb01', + 'deceptive', + 'deflectedcorrugatedspring', + 'dixonprice', + 'eggholder', + 'gear', + 'kowalik', + 'mishra07', + 'mishra11', + 'multimodal', + 'needleeye', + 'permfunction01', + 'permfunction02', + 'plateau', + 'powersum', + 'quadratic', + 'quintic', + 'rastrigin', + 'ratkowsky01', + 'salomon', + 'schwefel26', + 'shubert01', + 'sodp', + 'wavy', + 'xinsheyang04', + 'zacharov', +] diff --git a/go_benchmarks.py b/go_benchmarks.py new file mode 100644 index 0000000..6a34a6f --- /dev/null +++ b/go_benchmarks.py @@ -0,0 +1,49 @@ +from go_benchmark_functions import * +from inspect import getmro, isclass + +_looky_here = False + +problems = [] +for k in list(locals().keys()): + smth = locals()[k] + if isclass(smth) and Benchmark in getmro(smth)[1:]: + problems.append(smth) + +counts = {} +vcount = 0 +problems_by_dimensions = {} + +for cls in problems: + name = cls.__name__ + obj = cls() + n = obj.N + if _looky_here: + print(n, name, "(variable)" if obj.change_dimensionality else "(fixed)") + counts[n] = counts.get(n, 0) + 1 + if obj.change_dimensionality: + vcount += 1 + dimkey = f"{n}+" + else: + dimkey = f"{n}" + problems_by_dimensions.setdefault(dimkey, []).append(cls) + del obj + +counts["variable"] = vcount + +if _looky_here: + print(sorted(counts.items(), key=lambda x: f"{x[0]:09}" if isinstance(x[0], int) else str(x[0]))) + +p_by_d = problems_by_dimensions + +if _looky_here: + for dims in range(2, 6 + 1): + dimp = f"{dims}+" + print(dims, len(p_by_d.get(str(dims), [])), sep="\t") + print(dimp, len(p_by_d.get(dimp, [])), sep="\t") + +at_least_2d = p_by_d.get("2+", []) +at_least_3d = p_by_d.get("3+", []) + at_least_2d +at_least_4d = p_by_d.get("4+", []) + at_least_3d +problems_2d = p_by_d.get("2", []) + at_least_2d +problems_3d = p_by_d.get("3", []) + at_least_3d +problems_4d = p_by_d.get("4", []) + at_least_4d diff --git a/nloptcube2.py b/nloptcube2.py new file mode 100644 index 0000000..79956ec --- /dev/null +++ b/nloptcube2.py @@ -0,0 +1,218 @@ +import nlopt +import numpy as np + +NLOPTIMIZERS = { + # "gd_mlsl": nlopt.GD_MLSL, + # "gd_mlsl_lds": nlopt.GD_MLSL_LDS, + # "gd_stogo": nlopt.GD_STOGO, + # "gd_stogo_rand": nlopt.GD_STOGO_RAND, + "gn_ags": nlopt.GN_AGS, + "gn_crs2_lm": nlopt.GN_CRS2_LM, + "gn_direct": nlopt.GN_DIRECT, + "gn_direct_l": nlopt.GN_DIRECT_L, + "gn_direct_l_noscal": nlopt.GN_DIRECT_L_NOSCAL, + "gn_direct_l_rand": nlopt.GN_DIRECT_L_RAND, + "gn_direct_l_rand_noscal": nlopt.GN_DIRECT_L_RAND_NOSCAL, + "gn_direct_noscal": nlopt.GN_DIRECT_NOSCAL, + "gn_esch": nlopt.GN_ESCH, + "gn_isres": nlopt.GN_ISRES, + "gn_mlsl": nlopt.GN_MLSL, + "gn_mlsl_lds": nlopt.GN_MLSL_LDS, + "gn_orig_direct": nlopt.GN_ORIG_DIRECT, + "gn_orig_direct_l": nlopt.GN_ORIG_DIRECT_L, + "g_mlsl": nlopt.G_MLSL, + "g_mlsl_lds": nlopt.G_MLSL_LDS, + # "ld_auglag": nlopt.LD_AUGLAG, + # "ld_auglag_eq": nlopt.LD_AUGLAG_EQ, + # "ld_ccsaq": nlopt.LD_CCSAQ, + # "ld_lbfgs": nlopt.LD_LBFGS, + # "ld_lbfgs_nocedal": nlopt.LD_LBFGS_NOCEDAL, + # "ld_mma": nlopt.LD_MMA, + # "ld_slsqp": nlopt.LD_SLSQP, + # "ld_tnewton": nlopt.LD_TNEWTON, + # "ld_tnewton_precond": nlopt.LD_TNEWTON_PRECOND, + # "ld_tnewton_precond_restart": nlopt.LD_TNEWTON_PRECOND_RESTART, + # "ld_tnewton_restart": nlopt.LD_TNEWTON_RESTART, + # "ld_var1": nlopt.LD_VAR1, + # "ld_var2": nlopt.LD_VAR2, + "ln_auglag": nlopt.LN_AUGLAG, + "ln_auglag_eq": nlopt.LN_AUGLAG_EQ, + "ln_bobyqa": nlopt.LN_BOBYQA, + "ln_cobyla": nlopt.LN_COBYLA, + "ln_neldermead": nlopt.LN_NELDERMEAD, + "ln_newuoa": nlopt.LN_NEWUOA, + "ln_newuoa_bound": nlopt.LN_NEWUOA_BOUND, + "ln_praxis": nlopt.LN_PRAXIS, + "ln_sbplx": nlopt.LN_SBPLX, +} + + +def nlopt_cube_factory(objective, n_trials, n_dim, with_count, method): + optim = NLOPTIMIZERS[method] + + feval_count = 0 + best_so_far = None + + def _objective(x, grad): + nonlocal feval_count, best_so_far + fx = objective(x) + feval_count += 1 + if feval_count <= n_trials: + if best_so_far is None or fx < best_so_far[0]: + best_so_far = (fx, x) + return fx + + opt = nlopt.opt(optim, n_dim) + opt.set_lower_bounds([0.0] * n_dim) + opt.set_upper_bounds([1.0] * n_dim) + opt.set_min_objective(_objective) + opt.set_maxeval(n_trials) + + try: + opt.optimize([0.5] * n_dim) + except nlopt.RoundoffLimited as e: + print( # FIXME: de-uglify this! + "\033[33m", + "nlopt_" + method, + " exited early (", + type(e).__name__, + ")", + "\033[0m", + sep="", + ) + + assert best_so_far is not None, optimizer.__name__ + fopt, xopt = best_so_far + + return (fopt, xopt, feval_count) if with_count else (fopt, xopt) + + +def nlopt_ags_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_ags") + + +def nlopt_crs2_lm_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_crs2_lm") + + +def nlopt_direct_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_direct") + + +def nlopt_direct_l_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_direct_l") + + +def nlopt_direct_l_noscal_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory( + objective, n_trials, n_dim, with_count, "gn_direct_l_noscal" + ) + + +def nlopt_direct_lr_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory( + objective, n_trials, n_dim, with_count, "gn_direct_l_rand" + ) + + +def nlopt_direct_lr_noscal_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory( + objective, n_trials, n_dim, with_count, "gn_direct_l_rand_noscal" + ) + + +def nlopt_direct_noscal_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory( + objective, n_trials, n_dim, with_count, "gn_direct_noscal" + ) + + +def nlopt_esch_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_esch") + + +def nlopt_isres_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_isres") + + +def nlopt_mlsl_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_mlsl") + + +def nlopt_mlsl_lds_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_mlsl_lds") + + +def nlopt_orig_direct_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "gn_orig_direct") + + +def nlopt_orig_direct_l_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory( + objective, n_trials, n_dim, with_count, "gn_orig_direct_l" + ) + + +def nlopt_auglag_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_auglag") + + +def nlopt_auglag_eq_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_auglag_eq") + + +def nlopt_bobyqa_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_bobyqa") + + +def nlopt_cobyla_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_cobyla") + + +def nlopt_neldermead_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_neldermead") + + +def nlopt_newuoa_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_newuoa") + + +def nlopt_newuoa_bound_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_newuoa_bound") + + +def nlopt_praxis_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_praxis") + + +def nlopt_sbplx_cube(objective, n_trials, n_dim, with_count): + return nlopt_cube_factory(objective, n_trials, n_dim, with_count, "ln_sbplx") + + +NLOPT_OPTIMIZERS = [ + # global + # nlopt_ags_cube, # ValueError: nlopt invalid argument + nlopt_crs2_lm_cube, + nlopt_direct_cube, + nlopt_direct_l_cube, + nlopt_direct_l_noscal_cube, + nlopt_direct_lr_cube, + nlopt_direct_lr_noscal_cube, + nlopt_direct_noscal_cube, + nlopt_esch_cube, + nlopt_isres_cube, + # nlopt_mlsl_cube, # FIXME: Segmentation fault + # nlopt_mlsl_lds_cube # FIXME: Segmentation fault, + nlopt_orig_direct_cube, + nlopt_orig_direct_l_cube, + # local + # nlopt_auglag_cube, # FIXME: Segmentation fault + # nlopt_auglag_eq_cube, # FIXME: Segmentation fault + nlopt_bobyqa_cube, + nlopt_cobyla_cube, + nlopt_neldermead_cube, + nlopt_newuoa_cube, + # nlopt_newuoa_bound_cube, # sadly this times out on shekel. however it wins in nlopt_classic_d21_n550_armor + # nlopt_praxis_cube, # AssertionError: x is not finite (NaN or Inf or -Inf) + nlopt_sbplx_cube, +] diff --git a/notwacube.py b/notwacube.py new file mode 100644 index 0000000..0ad8544 --- /dev/null +++ b/notwacube.py @@ -0,0 +1,12 @@ +from nloptcube2 import nlopt_neldermead_cube +from randomcube2 import another_random_cube, quasirandom_cube + +BASELINE_OPTIMIZERS = [ + another_random_cube, + nlopt_neldermead_cube, + quasirandom_cube, +] + +book_of_optimizers = dict( + baseline=BASELINE_OPTIMIZERS, +) diff --git a/prog80.py b/prog80.py new file mode 100755 index 0000000..c2f0e46 --- /dev/null +++ b/prog80.py @@ -0,0 +1,442 @@ +import atexit +import sys +import time + +# TODO: make this a namedtuple? or one of those newfangles dataclasses. +options = dict( + ascii=False, # TODO + color=True, + flush=True, + patient=True, # TODO: better name? +) + +active = [] +allocated = 0 + +DEBUG = False + + +def get_terminal_size(file=sys.stderr): + from os import get_terminal_size as os_gts + + cols, rows = 0, 0 + try: + cols, rows = os_gts(file.fileno()) + except OSError: + pass + if cols <= 0 or rows <= 0: + from shutil import get_terminal_size as shutil_gts + + # NOTE: this uses sys.stdout instead of our file! + cols, rows = shutil_gts() + return cols, rows + + +def extend72(s, mode=""): + if "t" in mode or "d" in mode or "a" in mode: + s = s[:-1] + return ((s[0] + s[1:-1]) * 72)[:71] + s[-1] + + +@atexit.register # in the absence of a try-except for KeyboardInterrupt... +def reset(*, file=sys.stderr): + # TODO: flesh this out? + # TODO: fancy backspace "\b" stuff to hide potentially unsupported escape sequences. + s = "\0337\033[J\033[r\0338" + if file is not None: + print(end=s, file=file, flush=True) + else: + return s + + +def alloc(lines): + # first, perform a reset of whatever scrolling region may already be set. + # the cursor is (almost) always reset after performing a reset command, + # so wrap the command in a cursor-save and cursor-restore. + s = "\0337\033[r\0338" + + # now, do some magic to ensure there's enough empty lines for the progress bars + # *without* forcing the screen to scroll if there already is. + # TODO: clear these lines too? hmm, that would overwrite bars though, wouldn't it? + s += "\n" * lines # this part is simple enough; just print some newlines. + s += "\0338" # however, that resets the cursor's column, so restore its position. + # the position might not be on the same row as the line of text it was on before, + s += f"\033[{lines}B\033[{lines}A" # so move it down (clamped) and back up again. + # s += "\0337" # that should be everything, so store the adjusted cursor for later. + + return s + + +class Prog80: + # TODO: use different(-ly placed) delimiters when length < 72? + styles = dict( + # TODO: maybe use namedtuples for these? + # TODO: maybe use a separate field for the "cursor" characters? + # this ought to eliminate the need for "d", "t" and "P" modes. + bar=dict(A=" ", B="█▌", mode="r"), + bar2=dict(A=" ▌", B="██", mode="dp"), # TODO: what's the non-'p' version? + bracketed=dict(A="[" + " " * 70 + "]", B="[" + "=" * 70 + "]", mode="P"), + circumslider=dict(A="o", B="oô", mode="pr"), + crossslider=dict(A="†", B="†‡", mode="pr"), + dotslider=dict(A="-", B="-÷", mode="pr"), + dotted=dict(A=".", B="!?", mode="r"), + equally=dict(A=".", B="="), + fractional=dict( + A="·····¬·····¬·····¼·····¬·····¬·····½·····¬·····¬·····¾·····¬·····¬·····!", + B="xƒ", + mode="ir", + ), + longdotslider=dict(A="—", B="—÷", mode="pr"), + meme=dict( # slightly modified + A="According to all known laws of aviation, there is no way a bee should be", + B="able to fly. Its wings are too small to get its fat body off the ground.", + mode="P", + ), + middledots=dict(A="•", B="◘"), + money=dict(A="¢", B="$"), + # pacman=dict(A="-", B="#"), + # bracketedpacman=dict(A="[" + "-" * 70 + "]", B="[" + "#" * 70 + "]", mode="P"), + pacman=dict(A="[" + "-" * 70 + "]", B="[" + "#" * 70 + "]", mode="P"), + piping=dict(A="=", B="=|", mode="pr"), + ruler=dict(A="90123456780", B="90123456780", mode="P"), + slider=dict(A="_", B="_⌂", mode="pr"), + smile=dict(A="☺", B="☻"), + song=dict( + A=" - ♪ - ♪ - ♪ - ♪", + B=" ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫ ♫", + ), + sticks=dict(A="/", B="\\|", mode="p"), + virus=dict(A=".▀", B=" TECHNO ▄", mode="ap"), # »Don't touch the keyboard« + ) + + bands = [ # TODO: come up with a better name for this variable. + ("*", -4.94065645841246544177e-324, lambda x: "Waiting"), + ("*", 0.0, lambda x: "Running"), + ("*", 1.3888888888888887e-08, lambda x: "TooSlow"), + ("*", 0.00027776388888888886, lambda x: f"{x * 60 * 60:6.4f}/h"[1:]), + ("*", 0.001666583333333333, lambda x: f"{x * 60 * 60:5.3f}/h"), + ("s", 0.01666583333333333, lambda x: f"{x * 60:6.4f}/m"[1:]), + ("m", 0.01666583333333333, lambda x: f"{x * 60:6.4f}/m"[1:]), + ("s", 0.09995, lambda x: f"{x * 60:5.3f}/m"), + ("s", 0.9999499999999999, lambda x: f"{x:6.4f}/s"[1:]), + ("m", 0.16665833333333332, lambda x: f"{x * 60:5.3f}/m"), + ("m", 1.666583333333333, lambda x: f"{x * 60:5.2f}/m"), + ("s", 9.999499999999998, lambda x: f"{x:5.3f}/s"), + ("s", 12.000833333333333, lambda x: f"{x:5.2f}/s"), + ("m", 16.66583333333333, lambda x: f"{x * 60:5.1f}/m"), + ("m", 166.6583333333333, lambda x: f"{x * 60:4.0f}./m"), + ("*", 0.002777638888888889, lambda x: f"{x * 60 * 60:5.3f}/h"), + ("*", 0.027776388888888885, lambda x: f"{x * 60 * 60:5.2f}/h"), + ("*", 0.20001388888888888, lambda x: f"{x * 60 * 60:5.1f}/h"), + ("h", 0.2777638888888888, lambda x: f"{x * 60 * 60:5.1f}/h"), + ("h", 2.7776388888888883, lambda x: f"{x * 60 * 60:4.0f}./h"), + ("*", 1.666583333333333, lambda x: f"{x * 60:5.2f}/m"), + ("*", 12.000833333333333, lambda x: f"{x * 60:5.1f}/m"), + ("*", 99.99499999999999, lambda x: f"{x:5.2f}/s"), + ("*", 999.9499999999999, lambda x: f"{x:5.1f}/s"), + ("*", 9999.499999999998, lambda x: f"{x:4.0f}./s"), + ("*", 1.7976931348623157e308, lambda x: f"TooFast"), + ] + + # TODO: default to sys.stderr as well! + def __init__( + self, + it, + length, + *, + printer=print, + style=None, + display="elapsed", + preference="*", + ): + self.i = 0 + self.it = iter(it) + self.length = length + self.printer = printer + self.depth = 0 + self.start, self.end = 0, 0 + self.cols, self.rows = 0, 0 + self.preference = preference + self.previous_update = 0.0 + self._state = None + self.state = "initialized" + self.style = style if style in self.styles else "fractional" # TODO: warning + # self.style = style if style in self.styles else "slider" # TODO: warning + # self.style = style if style in self.styles else list(self.styles)[-1] + self.display = display + assert self.display in ("elapsed", "eta", "rate") + + @property + def state(self): + return self._state + + @state.setter + def state(self, new_state): + if self._state is not None and new_state == self._state: + return # just ignore this + valid = { + "initialized": {None}, + "prepared": {"initialized"}, + "began": {"prepared", "progressing"}, + "progressing": {"began"}, + "finished": {"began"}, + } + assert new_state in valid, f"unknown state {new_state}" + assert ( + self._state in valid[new_state] + ), f"invalid state transition from {self._state} to {new_state}" + self._state = new_state + + def __len__(self): + return self.length + + @property + def unfilled(self): + return extend72(self.styles[self.style]["A"], self.styling) + + @property + def filled(self): + return extend72(self.styles[self.style]["B"], self.styling) + + @property + def styling(self): + return self.styles[self.style].get("mode", "") + + @property + def full(self): + return self.i * 72 // self.length if self.length > 0 else 72 + + @property + def needs_update(self): + if self.length <= 0: + return True + w = 72 * 3 if "t" in self.styling else 72 * 2 if "d" in self.styling else 72 + return self.i * w // self.length != (self.i - 1) * w // self.length + + @property + def elapsed(self): + now = self.end if self.state == "finished" else time.time() + return now - self.start + + @property + def rate(self): + assert self.state in ( + "began", + "progressing", + "finished", + ), "invalid state for this" + elapsed = self.elasped + if elapsed == 0.0: + return self.bands[-1][1] # closest thing to infinity + return self.i / elapsed + + @property + def eta(self): + raise NotImplementedError("TODO") + + @classmethod + def format_rate(cls, rate, preference="*"): + for pref, threshold, formater in cls.bands: + if (pref == "*" or pref == preference) and rate <= threshold: + return formater(rate) + " " + return "????????" # normally unreachable (unless perhaps rate is Inf or NaN?) + + @classmethod + def format_time(cls, duration, preference="*"): + o = "-" if duration < 0.0 else "+" + duration = abs(duration) + if duration < 60.0: + o += f"{max(0.0, duration - 0.005):5.2f}s " + elif duration < 3600.0: + x = int(duration) + o += f"{x // 60:2d}m{x % 60:02d}s " + elif duration < 86400.0: + x = int(duration) + o += f"{x // 3600:2d}h{x // 60 % 60:02d}m " + elif duration < 8640000.0: + x = int(duration) + o += f"{x // 86400:2d}d{x // 3600 % 24:02d}h " + else: + o += "TooLong" + return o + + @property + def blurb(self): # only the first 8 characters that don't constitute the bar at all + if self.display == "rate": + return self.format_rate(self.rate, self.preference) + elif self.display == "elapsed": + return self.format_time(self.elapsed, self.preference) + elif self.display == "eta": + return self.format_time(-self.eta, self.preference) + + @property + def bar(self): # the full 80 characters available in any state + if options["color"]: + color1 = "\033[7m" + color2 = "\033[m\033[1m" + color_reset = "\033[m" + else: + color1 = "" + color2 = "" + color_reset = "" + + if self.state in ("began", "finished", "progressing"): + s = self.blurb + if options["color"] and "i" in self.styling: + left = self.unfilled[: self.full] + right = self.unfilled[self.full :] + if self.state == "progressing" or "p" in self.styling: + s += color1 + left + color2 + right[0] + s += color_reset + right[1:] + else: + s += color1 + left + s += color_reset + right + + else: + filled = self.filled + style = self.styles[self.style] + progressing = self.state == "progressing" or "p" in self.styling + t = (filled[-1], style["A"][-1], style["B"][-1]) + if "t" in self.styling and self.length > 0: + triple = self.i * 72 * 3 // self.length + filled = filled[:-1] + t[triple % 3] + elif "d" in self.styling and self.length > 0: + double = self.i * 72 * 2 // self.length + filled = filled[:-1] + t[double % 2 + 1] + elif "a" in self.styling and self.length > 0: + filled = filled[:-1] + t[self.full % 2 + 1] + + s += color2 + if progressing: + if "r" in self.styling: + s += filled[-self.full - 1 :] + elif "P" in self.styling: + s += filled[: self.full + 1] + else: + s += filled[: self.full] + filled[-1] + s += color_reset + self.unfilled[self.full + 1 :] + else: + if "r" in self.styling and self.full > 0: + s += filled[-self.full :] + else: + s += filled[: self.full] + s += color_reset + self.unfilled[self.full :] + elif self.state == "prepared": + s = "Ready..." + " " * 72 + else: + s = "watdafuk" + "?" * 72 + # assert len(s) == 80 + len(color2) + len(color_reset), (self.full, self.state, repr(s)) + return s + + @property + def row(self): + assert self.state in ("began", "progressing"), "invalid state for this" + return self.rows - allocated + self.depth + + def __iter__(self): + # TODO: check env-var override for disabling and colors! + if self.length == 0: + return self.it + if self.i == 0: + self.begin() + for x in self.it: + self.progress(False) + yield x + self.progress(True) + self.progressing = False + self.finish() + + # TODO: is there a case where i actually need this? + # def __next__(self): + # pass + + def prepare(self): + self.state = "prepared" + return self + + def begin(self): + global allocated + self.start = time.time() + assert self not in active, "what" + active.append(self) + self.depth = len(active) + + (_cols, _rows) = get_terminal_size() + # propagate terminal size to parents (and self) in case it has since changed: + for pb in active: + pb.cols, pb.rows = _cols, _rows + + # TODO: this should be handleable in most cases; hide the top bars for a while. + # need at least 1 blank line for regular output (or just for the cursor to sit) + # i guess just act as though only a subset of `active` are active for a while? + assert self.rows - 1 > self.depth, "ran out of space for progress bars" + + s = alloc(self.depth) # TODO: only do this as necessary? (based on allocated) + + # keep track of how many lines are available for progress bars. + newly = len(active) - allocated if len(active) > allocated else 0 + # TODO: allow the user to allocate many at once. + allocated += newly + self.state = "began" + + s += "\0337" + if 1: + for pb in active: + # TODO: respect 30 fps timers? + s += f"\033[{pb.row};1H\033[K{pb.bar}" + else: # this isn't as flexible, but it works...? + # FIXME: progress() is still broken! + for pb in active: + s += f"\n\033[K{pb.bar}" + # prevent the user from accidentally printing over the progress bars. + s += f"\033[1;{self.rows - allocated}r" + s += "\0338" # finally, return to the user's (properly adjusted) line and column. + self.printer(end=s) + # time.sleep(2); exit() + + if DEBUG: + print(repr(s).replace("\\x1b", "\\033")) + time.sleep(0.5) + + def progress(self, finishing=False): + if finishing: + self.i += 1 + self.state = "began" + else: + self.state = "progressing" + + if not options["patient"] or self.needs_update: + now = time.time() + if now >= self.previous_update + 0.03333333333333333: # limit to 30 fps + self.previous_update = now + s = f"\0337\033[{self.row};1H\033[K{self.bar}\0338" + self.printer(end=s) + + def finish(self): + global allocated + self.end = time.time() + row = self.row # we need this before we transition states + assert self.depth == len(active) and active[-1] is self, "what" + active.pop() + self.state = "finished" + s = "" + if len(active) == 0: + s += "\0337\033[J\033[r\0338" + allocated = 0 + else: + s += f"\0337\033[{row};1H\033[K\0338" + self.printer(end=s) + + +def prog(it, *, file=sys.stderr, pref="*"): + def printy(*args, **kwargs): + # print(repr(kwargs.get("end", "?").replace("\\x1b", "\\033"))) + # time.sleep(2.5) + print(*args, **kwargs, file=file, flush=options["flush"]) + # time.sleep(2.5) + + try: + l = len(it) + except TypeError: + raise TypeError("prog(iterator) only works with iterators with a known length") + return Prog80(it, l, printer=printy, preference=pref).prepare() diff --git a/project.py b/project.py new file mode 100644 index 0000000..6dd9fdf --- /dev/null +++ b/project.py @@ -0,0 +1,41 @@ +import numpy as np + + +#def project(a, b): # projects b onto the unit cube, using a as an offset origin +# a = np.asanyarray(a) +# b = np.asanyarray(b) +# d = b - a +# if all(np.abs(d) <= 1e-8): +# return a +# inner = -1 / np.where(np.abs(d) > 1e-8, d, np.where(d >= 0, 1e-8, -1e-8)) +# small = np.minimum(1 - a, a - 1) +# large = np.maximum(0 - a, a - 0) +# rescale = np.min(np.maximum(inner * small, inner * large)) +# assert np.isfinite(rescale), rescale +# if rescale < 1: +# return a + (rescale - 1e-6) * d +# else: +# return b + + +def project(p, a, eps=1e-8): + # https://www.desmos.com/calculator/gdcu0ivk0i + p = np.asanyarray(p) + a = np.asanyarray(a) + d = p - a + if all(np.abs(d) <= eps): + # we might still be inching out of bounds, so just to be sure: + a[a <= 0] = 0 + a[a >= 1] = 1 + return a + + inner = 1 / np.where(np.abs(d) > eps, d, np.where(d >= 0, eps, -eps)) + small = -np.abs(p - 1) # np.minimum(1 - p, p - 1) + large = np.abs(p) # np.maximum(0 - p, p - 0) + rescale = np.min(np.maximum(inner * small, inner * large)) + + if rescale <= 1: + b = p - max(0, rescale - 1e-8) * d + return b + else: + return a diff --git a/randomcube2.py b/randomcube2.py new file mode 100644 index 0000000..c194d72 --- /dev/null +++ b/randomcube2.py @@ -0,0 +1,35 @@ +from utils import phi +import numpy as np + + +def another_random_cube(objective, n_trials, n_dim, with_count, seed=None): + prng = np.random.default_rng(seed) + fopt = None + xopt = None + for i in range(n_trials): + x = prng.uniform(size=n_dim) + fx = objective(x) + if fopt is None or xopt is None or fx < fopt: + fopt = fx + xopt = x + return (fopt, xopt, n_trials) if with_count else (fopt, xopt) + + +def quasirandom_cube(objective, n_trials, n_dim, with_count): + # http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/ + magic = phi(n_dim) + alpha = np.zeros(n_dim) + for i in range(n_dim): + alpha[i] = pow(1 / magic, i + 1) % 1 + xs = np.zeros((n_trials, n_dim)) + xs[0, :] = 0.5 # first point is always dead center + for i in range(1, n_trials): + xs[i] = (xs[i - 1] + alpha) % 1 + + best_so_far = None + for i, x in zip(range(n_trials), xs): + fx = objective(x) + if best_so_far is None or fx < best_so_far[0]: + best_so_far = (fx, x) + fopt, xopt = best_so_far + return (fopt, xopt, n_trials) if with_count else (fopt, xopt) diff --git a/solutions_1680721604.py b/solutions_1680721604.py new file mode 100644 index 0000000..c4a4673 --- /dev/null +++ b/solutions_1680721604.py @@ -0,0 +1,485 @@ +solutions = { + "go_ackley01_on_cube__2": { + 4.440892098500626e-16: [0.5000000000012516, 0.5000000000009395], + }, + "go_ackley02_on_cube__2": { + -200.0: [0.5, 0.5], + }, + "go_ackley03_on_cube__2": { + -195.62902826227938: [0.4893347317380225, 0.4943640332293448], + }, + "go_adjiman_on_cube__2": { + -2.0218067833597875: [0.9999999999999714, 0.5528917033764795], + }, + "go_alpine01_on_cube__2": { + 0.0: [0.5, 0.9762267885778328], + }, + "go_alpine02_on_cube__2": { + -6.129503891130689: [0.4815842302257306, 0.7917052693161503], + }, + "go_amgm_on_cube__2": { + 0.0: [0.14528557476989837, 0.14528557476989837], + }, + "go_bartelsconn_on_cube__2": { + 1.0: [0.5, 0.5], + }, + "go_beale_on_cube__2": { + 0.0: [0.8333333333333334, 0.5555555555555556], + }, + "go_biggsexp02_on_cube__2": { + 0.0: [0.05017234270730255, 0.5018173197656695], + }, + "go_bird_on_cube__2": { + -106.76453674926478: [0.3739033841634505, 0.2508203315071311], + }, + "go_bohachevsky1_on_cube__2": { + 0.0: [0.440593060336285, 0.5625000000000355], + }, + "go_bohachevsky2_on_cube__2": { + 0.0: [0.5, 0.5], + }, + "go_bohachevsky3_on_cube__2": { + 0.0: [0.5, 0.0371852048138242], + }, + "go_branin01_on_cube__2": { + 0.39788735772973816: [0.12094130784112306, 0.8309013410017676], + }, + "go_branin02_on_cube__2": { + 5.558914403893816: [0.09015057853516895, 0.8763128943301511], + }, + "go_brent_on_cube__2": { + 1.3838965267367376e-87: [0.00014895223910016858, 0.00021530390524300317], + }, + "go_brown_on_cube__2": { + 0.0: [0.20000000000000023, 0.20000000000000012], + }, + "go_bukin02_on_cube__2": { + -124.75: [0.14238611093033351, 0.5000000018001576], + }, + "go_bukin04_on_cube__2": { + 0.0: [0.5, 0.5], + }, + "go_bukin06_on_cube__2": { + 5.865983528536844e-06: [0.5, 0.5], + }, + "go_carromtable_on_cube__2": { + -24.156815547391254: [0.017691616522249504, 0.9823083834798857], + }, + "go_chichinadze_on_cube__2": { + -42.94438701899099: [0.6035311135612936, 0.5097635900809587], + }, + "go_cigar_on_cube__2": { + 0.0: [0.5000000000000002, 0.5], + }, + "go_cosinemixture_on_cube__2": { + -1.8: [0.75, 0.75], + }, + "go_crossintray_on_cube__2": { + -2.0626118708227397: [0.4325296712598773, 0.43252966716129265], + }, + "go_crosslegtable_on_cube__2": { + -1.0: [0.0019232616287467377, 0.501953125], + }, + "go_crownedcross_on_cube__2": { + 0.0001: [0.3218787362308007, 0.308124995755209], + }, + "go_csendes_on_cube__2": { + 1.0670199460593143e-95: [0.49999999999999994, 0.49999999999999994], + }, + "go_cube_on_cube__2": { + 0.0: [0.5499999821185895, 0.5499999821185895], + }, + "go_damavandi_on_cube__2": { + -8.548717318273045e-14: [0.14285714236851058, 0.5], + }, + "go_deb01_on_cube__2": { + -1.0: [0.7499990498894216, 0.7499999657093407], + }, + "go_deb03_on_cube__2": { + -1.0: [0.07969939247253323, 0.07969939211843553], + }, + "go_decanomial_on_cube__2": { + 0.0: [0.5999969620477643, 0.5999969620477643], + }, + "go_deceptive_on_cube__2": { + -1.0: [0.3333395662049635, 0.6666666666666666], + }, + "go_deckkersaarts_on_cube__2": { + -24776.518342317697: [0.49999422157482337, 0.8633377885933347], + }, + "go_deflectedcorrugatedspring_on_cube__2": { + -1.0: [0.5000000000382508, 0.5000000001114326], + }, + "go_dixonprice_on_cube__2": { + 2.465190328815662e-30: [0.5500000000000005, 0.5353553390593274], + }, + "go_dropwave_on_cube__2": { + -1.0: [0.4999999999807786, 0.50000000007422], + }, + "go_easom_on_cube__2": { + -1.0: [0.5157064122321219, 0.5157064122321219], + }, + "go_eggcrate_on_cube__2": { + 0.0: [0.18428181626851456, 0.18428181626851456], + }, + "go_eggholder_on_cube__2": { + -959.6406627208506: [1.0, 0.894767898730016], + }, + "go_elattarvidyasagardutta_on_cube__2": { + 1.7127803548621996: [0.5170459341098588, 0.48914283482200543], + }, + "go_exp2_on_cube__2": { + 3.918816046997309e-33: [0.050000088297583685, 0.5000007180480729], + }, + "go_exponential_on_cube__2": { + -1.0: [0.5000000013789645, 0.500000001379979], + }, + "go_freudensteinroth_on_cube__2": { + 0.0: [0.75, 0.7], + }, + "go_giunta_on_cube__2": { + 0.06447042053690555: [0.2164719678737906, 0.2164719678737906], + }, + "go_goldsteinprice_on_cube__2": { + 2.999999999999936: [0.5000000000134474, 0.25000000003431383], + }, + "go_griewank_on_cube__2": { + 0.0: [0.4999999959578959, 0.4999999959578959], + }, + "go_hansen_on_cube__2": { + -176.54179313674572: [0.4346646143793226, 0.1760714471446315], + }, + "go_himmelblau_on_cube__2": { + 0.0: [0.8000000005441553, 0.699999998930247], + }, + "go_holdertable_on_cube__2": { + -19.208502567886757: [0.9027539594713605, 0.9832285117561048], + }, + "go_hosaki_on_cube__2": { + -2.3458115761013154: [0.8000000052198215, 0.33333333377951074], + }, + "go_infinity_on_cube__2": { + 1.0670199460593143e-95: [0.500000000000078, 0.5000000000000799], + }, + "go_jennrichsampson_on_cube__2": { + 124.36218235561478: [0.628912606360244, 0.628912607266392], + }, + "go_judge_on_cube__2": { + 16.08173013296038: [0.5432393693433495, 0.5617874256124593], + }, + "go_katsuura_on_cube__2": { + 1.0: [1.0465968369732792e-12, 5.32695415556006e-13], + }, + "go_keane_on_cube__2": { + 0.0: [0.37101044225030444, 0.37101044225030444], + }, + "go_langermann_on_cube__2": { + -5.162126159963984: [0.4247007879960495, 0.5243904060958999], + }, + "go_leon_on_cube__2": { + 4.979684464207637e-30: [0.5142395223724617, 0.5003219683645784], + }, + "go_levy03_on_cube__2": { + 1.4997597826618576e-32: [0.55, 0.55], + }, + "go_levy05_on_cube__2": { + -176.1375780016295: [0.43465734957884006, 0.42875774788733895], + }, + "go_levy13_on_cube__2": { + 1.3497838043956716e-31: [0.5500150851792615, 0.5588857050847033], + }, + "go_matyas_on_cube__2": { + 0.0: [0.5, 0.5], + }, + "go_mccormick_on_cube__2": { + -1.9132229549810367: [0.18464510306427817, 0.2463861846869465], + }, + "go_michalewicz_on_cube__2": { + -1.8013034100985537: [0.9442092427714985, 0.137930239782405], + }, + "go_mishra01_on_cube__2": { + 1.9999999976137055: [1.0, 0.45651381229089155], + }, + "go_mishra02_on_cube__2": { + 1.9999999976137055: [0.9999998753782375, 0.9999999999988338], + }, + "go_mishra03_on_cube__2": { + -0.19992970874179772: [0.00017566064782963478, 0.00017567826653813387], + }, + "go_mishra04_on_cube__2": { + -0.17771527939061962: [0.055900292323033035, 0.0555232000601078], + }, + "go_mishra05_on_cube__2": { + -1.0198295199309433: [0.4496859216030812, 5.052677111002609e-14], + }, + "go_mishra06_on_cube__2": { + -2.283949838474759: [0.6443153606209077, 0.5911630166051212], + }, + "go_mishra07_on_cube__2": { + 0.0: [0.34609320629638907, 0.491495756043251], + }, + "go_mishra08_on_cube__2": { + 0.0: [0.6, 0.4999999999999505], + }, + "go_mishra10_on_cube__2": { + 0.0: [0.5624973533886062, 0.4448689469647824], + }, + "go_mishra11_on_cube__2": { + 0.0: [0.3864490164718726, 0.6606615057516221], + }, + "go_multimodal_on_cube__2": { + 0.0: [0.2580651476136024, 0.5], + }, + "go_needleeye_on_cube__2": { + 1.0: [0.5000029697574638, 0.4999988242523547], + }, + "go_newfunction01_on_cube__2": { + -0.18466699349665727: [0.0766649450293288, 3.8163916471489756e-17], + }, + "go_newfunction02_on_cube__2": { + -0.19941146890593808: [0.0029425599479900697, 6.269061894428091e-09], + }, + "go_oddsquare_on_cube__2": { + -1.0084672811394724: [0.5293830040843023, 0.54382826973797], + }, + "go_parsopoulos_on_cube__2": { + 3.374459510989179e-32: [0.9712388980384691, 0.5], + }, + "go_pathological_on_cube__2": { + 0.0: [0.49999999999760364, 0.5000000000214441], + }, + "go_penalty01_on_cube__2": { + 1.570544771786639e-32: [0.48999999999999994, 0.49], + }, + "go_penalty02_on_cube__2": { + 1.3497838043956716e-31: [0.51, 0.51], + }, + "go_penholder_on_cube__2": { + -0.9635348327265058: [0.9401864564627503, 0.9386821449166709], + }, + "go_permfunction01_on_cube__2": { + 0.0: [0.7519531250381614, 0.6152343749994894], + }, + "go_permfunction02_on_cube__2": { + 7.099748146989106e-30: [0.578293852394686, 0.5282223006004134], + }, + "go_pinter_on_cube__2": { + 0.0: [0.49958445065499896, 0.49910744487758496], + }, + "go_plateau_on_cube__2": { + 30.0: [0.572454495541009, 0.56229500763676], + }, + "go_price01_on_cube__2": { + 0.0: [0.25499999999999995, 0.745], + }, + "go_price02_on_cube__2": { + 0.9: [0.4999999996935737, 0.5000000001302558], + }, + "go_price03_on_cube__2": { + 1.232595164407831e-32: [0.6, 0.5999999999999999], + }, + "go_price04_on_cube__2": { + 0.0: [0.5000799946500851, 0.49956191788571896], + }, + "go_qing_on_cube__2": { + 1.050959940980693e-27: [0.499, 0.4985857864376269], + }, + "go_quadratic_on_cube__2": { + -3873.7241821862717: [0.5095015478153164, 0.5241747012576643], + }, + "go_quintic_on_cube__2": { + 0.0: [0.47986860294069383, 0.4798679708433461], + }, + "go_rana_on_cube__2": { + -500.80216100356625: [1.0, 0.7236207232318757], + }, + "go_rastrigin_on_cube__2": { + 0.0: [0.5715218344919186, 0.5511489887028654], + }, + "go_ripple01_on_cube__2": { + -2.2: [0.09922161610301354, 0.10142343315723641], + }, + "go_ripple25_on_cube__2": { + -2.0: [0.08254001808623358, 0.08702649220076682], + }, + "go_rosenbrock_on_cube__2": { + 1.135959703518257e-28: [0.5166666666666668, 0.4947701574224009], + }, + "go_rosenbrockmodified_on_cube__2": { + 34.0402431066405: [0.2726115657051843, 0.26235707188727275], + }, + "go_rotatedellipse01_on_cube__2": { + 0.0: [0.498801015711877, 0.498801015711877], + }, + "go_rotatedellipse02_on_cube__2": { + 0.0: [0.5, 0.5], + }, + "go_salomon_on_cube__2": { + 0.0: [0.5, 0.500000000003638], + }, + "go_sargan_on_cube__2": { + 0.0: [0.49999999999999994, 0.5], + }, + "go_schaffer01_on_cube__2": { + 0.0: [0.49999999999999634, 0.49999999999999634], + }, + "go_schaffer02_on_cube__2": { + 0.0: [0.4999999981621386, 0.4999999986347427], + }, + "go_schaffer03_on_cube__2": { + 0.001566854526003969: [0.5000000000002823, 0.5035528201669792], + }, + "go_schaffer04_on_cube__2": { + 0.29257863203598033: [0.5000013136163499, 0.4937343165448773], + }, + "go_schwefel01_on_cube__2": { + 0.0: [0.5, 0.4999999998835847], + }, + "go_schwefel02_on_cube__2": { + 0.0: [0.5, 0.5], + }, + "go_schwefel04_on_cube__2": { + 0.0: [0.1020808914860876, 0.1020808914860876], + }, + "go_schwefel06_on_cube__2": { + 0.0: [0.505, 0.5150000000000001], + }, + "go_schwefel20_on_cube__2": { + 0.0: [0.12205247389109272, 0.12205247389109272], + }, + "go_schwefel21_on_cube__2": { + 0.0: [0.6166298780113924, 0.7130508226020703], + }, + "go_schwefel22_on_cube__2": { + 0.0: [0.5, 0.49609363079071045], + }, + "go_schwefel26_on_cube__2": { + -5.448675892694155e-07: [0.9209687462455439, 0.9209687459329059], + }, + "go_schwefel36_on_cube__2": { + -3456.000000000001: [0.024000000147307608, 0.49162499998238574], + }, + "go_shubert01_on_cube__2": { + -186.73090883102398: [0.7429028439177817, 0.1458246796260435], + }, + "go_shubert03_on_cube__2": { + -24.062498884334293: [0.7895897235076741, 0.7895897236028214], + }, + "go_shubert04_on_cube__2": { + -29.016015854390076: [0.14821760462818873, 0.22311218016348278], + }, + "go_sineenvelope_on_cube__2": { + 0.0: [0.4596149239853102, 0.5030264073322085], + }, + "go_sixhumpcamel_on_cube__2": { + -1.0316284534898774: [0.8412902456484702, 0.3984249755872633], + }, + "go_sodp_on_cube__2": { + 0.0: [0.4999999298520932, 0.4949623459343995], + }, + "go_sphere_on_cube__2": { + 0.0: [0.5, 0.5], + }, + "go_step2_on_cube__2": { + 0.5: [0.4962750387667936, 0.4979955154520701], + }, + "go_step_on_cube__2": { + 0.0: [0.49741917962545434, 0.49952460080066174], + }, + "go_stochastic_on_cube__2": { + 0.0: [0.5999973641998414, 0.5000000044703483], + }, + "go_stretchedv_on_cube__2": { + 0.0: [0.23227978992486353, 0.5003909127586422], + }, + "go_styblinskitang_on_cube__2": { + -78.33233140754285: [0.2096465967930618, 0.20964659707425057], + }, + "go_testtubeholder_on_cube__2": { + -10.872300105622747: [0.4050972481936185, 0.4050972481936185], + }, + "go_threehumpcamel_on_cube__2": { + 0.0: [0.4999999884956858, 0.500000025238776], + }, + "go_treccani_on_cube__2": { + 0.0: [0.5000000005096527, 0.49999998234850795], + }, + "go_trefethen_on_cube__2": { + -3.3068686474752407: [0.4987798460133582, 0.5105306213572468], + }, + "go_trigonometric01_on_cube__2": { + 0.0: [0.0, 3.469446951953614e-18], + }, + "go_trigonometric02_on_cube__2": { + 1.0: [0.5002303123236185, 0.5008999999854868], + }, + "go_tripod_on_cube__2": { + 0.0: [0.5, 0.25], + }, + "go_ursem01_on_cube__2": { + -4.816814063734823: [0.7631157194886242, 0.4999999991819998], + }, + "go_ursem03_on_cube__2": { + -3.0: [0.49999999999894734, 0.5064942023957556], + }, + "go_ursem04_on_cube__2": { + -1.5: [0.49999999999999994, 0.49999999999999994], + }, + "go_ursemwaves_on_cube__2": { + -8.553600000000005: [1.0, 1.0], + }, + "go_ventersobiezcczanskisobieski_on_cube__2": { + -400.0: [0.4999999999691136, 0.5000000000649738], + }, + "go_vincent_on_cube__2": { + -2.0: [0.7647463840583177, 0.7647463860955502], + }, + "go_wavy_on_cube__2": { + 0.0: [0.5990111627305801, 0.7166822395492828], + }, + "go_wayburnseader01_on_cube__2": { + 3.865418435582958e-29: [0.5931930653112957, 0.701088291102508], + }, + "go_wayburnseader02_on_cube__2": { + 1.1093356479670479e-27: [0.5002001389746917, 0.5009999999999929], + }, + "go_weierstrass_on_cube__2": { + 0.0: [0.48388671875000094, 0.4838867187500006], + }, + "go_whitley_on_cube__2": { + 0.0: [0.5004834467831857, 0.39297526505649716], + }, + "go_xinsheyang01_on_cube__2": { + 0.0: [0.49919291830153395, 0.49919291830153395], + }, + "go_xinsheyang02_on_cube__2": { + 0.0: [0.5000000000002875, 0.4999999999999388], + }, + "go_xinsheyang03_on_cube__2": { + -1.0: [0.4999999986162714, 0.5000000059276509], + }, + "go_xinsheyang04_on_cube__2": { + -1.0: [0.49999999999999967, 0.4999999892774735], + }, + "go_yaoliu04_on_cube__2": { + 0.0: [0.5000000035524891, 0.5000000035524891], + }, + "go_yaoliu09_on_cube__2": { + 0.0: [0.4999999999409883, 0.4999999999993396], + }, + "go_zacharov_on_cube__2": { + 0.0: [0.3333333333333333, 0.3333333333333333], + }, + "go_zerosum_on_cube__2": { + 0.0: [0.24019956025564648, 0.7597811926967968], + }, + "go_zettl_on_cube__2": { + -0.0037912372204688986: [0.3313423297689443, 0.3329125985152123], + }, + "go_zimmerman_on_cube__2": { + 8.881784197001252e-16: [0.024979873370145907, 0.05681725730945934], + }, + "go_zirilli_on_cube__2": { + -0.3523860738000365: [0.44782232329859883, 0.5004437701361232], + }, +} diff --git a/solutions_1680730206.py b/solutions_1680730206.py new file mode 100644 index 0000000..ea7b15a --- /dev/null +++ b/solutions_1680730206.py @@ -0,0 +1,242 @@ +solutions = { + "go_ackley01_on_cube__3": { + 4.440892098500626e-16: [0.5, 0.5, 0.5], + }, + "go_alpine01_on_cube__3": { + 0.0: [0.49999999999999956, 0.5000000000000002, 0.5000000000000012], + }, + "go_alpine02_on_cube__3": { + -17.212450994658354: [0.7917052684142234, 0.7917052676939672, 0.4815842307193425], + }, + "go_amgm_on_cube__3": { + 0.0: [0.8245598718496522, 0.8245598800645785, 0.8245598774911281], + }, + "go_biggsexp03_on_cube__3": { + 0.0: [0.05, 0.5, 0.24999999999999997], + }, + "go_boxbetts_on_cube__3": { + 0.0: [0.3333333333333335, 0.454545454545454, 0.3333333333333334], + }, + "go_brown_on_cube__3": { + 0.0: [0.20000001930221908, 0.19999995251347022, 0.19999929921954904], + }, + "go_cigar_on_cube__3": { + 0.0: [0.5950381095427524, 0.5950381095427524, 0.5950381095427524], + }, + "go_cosinemixture_on_cube__3": { + -2.7: [3.659195132255668e-06, 1.5076273613395665e-11, 9.543896963247637e-16], + }, + "go_csendes_on_cube__3": { + 1.6005299190889717e-95: [0.5000002614943283, 0.49999979737945727, 0.4999991373845789], + }, + "go_deb01_on_cube__3": { + -1.0: [0.049649550146846286, 0.05000289851470013, 0.05006420897463226], + }, + "go_deb03_on_cube__3": { + -1.0: [0.8488416211971612, 0.8488416208778257, 0.8488416211316454], + }, + "go_deceptive_on_cube__3": { + -1.0: [0.7499999999714193, 0.7499999999714193, 0.7499999999714193], + }, + "go_deflectedcorrugatedspring_on_cube__3": { + -1.0: [0.5000000007403892, 0.5000000012200565, 0.49999999741084855], + }, + "go_dixonprice_on_cube__3": { + 1.1931521191467804e-29: [0.55, 0.5353553390593274, 0.470269822124932], + }, + "go_eckerle4_on_cube__3": { + 0.0014635887487274677: [0.08717603638237367, 0.22786082165419722, 0.7482996827664747], + }, + "go_eggholder_on_cube__3": { + -1888.321390893595: [0.970181519670115, 0.9266961632465174, 0.9411871032839637], + }, + "go_exponential_on_cube__3": { + -1.0: [0.5003591836784682, 0.500348485292889, 0.5001780115493856], + }, + "go_griewank_on_cube__3": { + 0.0: [0.5000000000113756, 0.5000000000565452, 0.4999999999274707], + }, + "go_gulf_on_cube__3": { + 5.915132712320822e-31: [0.1348208391857785, 0.5, 0.03], + }, + "go_hartmann3_on_cube__3": { + -3.862782147820756: [0.11461434502192798, 0.5556488498282574, 0.8525469537098168], + }, + "go_helicalvalley_on_cube__3": { + 0.0: [0.5497725561310041, 0.5048351824540244, 0.5076838383564906], + }, + "go_infinity_on_cube__3": { + 1.6005299190889717e-95: [0.4999999715839852, 0.5000000247025426, 0.5000000016223345], + }, + "go_katsuura_on_cube__3": { + 1.0: [5.679137715652871e-14, 6.262039498050598e-13, 5.512708345367656e-13], + }, + "go_meyer_on_cube__3": { + 3718453685.016923: [0.9999999999999996, 0.9999999999999999, 3.122502256758253e-17], + }, + "go_mishra01_on_cube__3": { + 1.9999999952274108: [1.0, 0.9999999999999999, 0.009829734043015896], + }, + "go_mishra02_on_cube__3": { + 1.9999999952274108: [0.9999999999999993, 1.0, 0.9999999999999998], + }, + "go_mishra07_on_cube__3": { + 0.0: [0.5240408900442571, 0.5079805506782411, 0.6569953605954606], + }, + "go_mishra09_on_cube__3": { + 0.0: [0.5537573946909716, 0.6002010732109465, 0.6409128191691206], + }, + "go_mishra11_on_cube__3": { + 0.0: [0.5, 0.5, 0.5], + }, + "go_multimodal_on_cube__3": { + 0.0: [0.5022237648504779, 0.49970052009979826, 0.5005325922218133], + }, + "go_needleeye_on_cube__3": { + 1.0: [0.39961640034876017, 0.39961640034876017, 0.39961640034875184], + }, + "go_penalty01_on_cube__3": { + 1.570544771786639e-32: [0.49, 0.49, 0.49000000000000005], + }, + "go_penalty02_on_cube__3": { + 1.3497838043956716e-31: [0.5133271718479692, 0.5062564318780072, 0.5146267812010901], + }, + "go_permfunction01_on_cube__3": { + 9.860761315262648e-31: [0.640860903825709, 0.01929983613560043, 0.6044294128164022], + }, + "go_permfunction02_on_cube__3": { + 2.2186712959340957e-30: [0.5714578794300258, 0.47532015480578127, 0.49894707267621674], + }, + "go_pinter_on_cube__3": { + 0.0: [0.5, 0.5, 0.5], + }, + "go_plateau_on_cube__3": { + 30.0: [0.4046704030611626, 0.4976189802302213, 0.3543757372858257], + }, + "go_qing_on_cube__3": { + 5.3707622579709536e-27: [0.501, 0.4985857864376269, 0.5017320508075689], + }, + "go_quadratic_on_cube__3": { + -3873.7241821862717: [0.5096940087870239, 0.5242566945952262, 0.29760349466562863], + }, + "go_quintic_on_cube__3": { + 0.0: [0.44999999999999996, 0.60941162109375, 0.45], + }, + "go_rana_on_cube__3": { + -998.9595261322422: [4.150441195255471e-09, 0.0009301076431260141, 0.0019640025818469242], + }, + "go_rastrigin_on_cube__3": { + 0.0: [0.4999999997679357, 0.49999999993791394, 0.4999999999832573], + }, + "go_ratkowsky02_on_cube__3": { + 8.056522933811229: [0.3289191890500581, 0.4706837418911737, 0.1170595919922324], + }, + "go_rosenbrock_on_cube__3": { + 5.679798517591285e-28: [0.4991978266453091, 0.5000882128754777, 0.4938730426361304], + }, + "go_salomon_on_cube__3": { + 0.0: [0.49999999999999994, 0.5000000000000001, 0.5], + }, + "go_sargan_on_cube__3": { + 0.0: [0.4890611845448031, 0.5152469505181654, 0.4890831221795244], + }, + "go_schwefel01_on_cube__3": { + 0.0: [0.5000000000000001, 0.5, 0.5], + }, + "go_schwefel02_on_cube__3": { + 0.0: [0.515625, 0.12989525470348404, 0.5], + }, + "go_schwefel04_on_cube__3": { + 0.0: [0.3928252864281473, 0.3928252864281473, 0.39282528642814735], + }, + "go_schwefel20_on_cube__3": { + 0.0: [0.5, 0.5, 0.5], + }, + "go_schwefel21_on_cube__3": { + 0.0: [0.5, 0.49999999999999994, 0.5], + }, + "go_schwefel22_on_cube__3": { + 0.0: [0.49999998835820214, 0.49999999999999994, 0.49999999999999956], + }, + "go_schwefel26_on_cube__3": { + -8.173014975909609e-07: [0.9204820116767811, 0.9204820113041389, 0.9204820116767811], + }, + "go_shubert01_on_cube__3": { + -2709.093505572829: [0.44022055084214423, 0.7741432103584681, 0.7429028439073201], + }, + "go_shubert03_on_cube__3": { + -36.09374832650144: [0.7895348359272809, 0.9397543606957739, 0.7896478307580592], + }, + "go_shubert04_on_cube__3": { + -43.524023781585115: [0.6640013808576284, 0.14582468028277795, 0.7741432091030084], + }, + "go_sineenvelope_on_cube__3": { + 0.0: [0.5000009025942251, 0.500000893069357, 0.5000003811955986], + }, + "go_sodp_on_cube__3": { + 0.0: [0.5, 0.5, 0.5], + }, + "go_sphere_on_cube__3": { + 0.0: [0.4833130709800822, 0.4833130709800822, 0.4833130709800822], + }, + "go_step2_on_cube__3": { + 0.75: [0.5016868928445066, 0.5061703854573943, 0.5026760176613241], + }, + "go_step_on_cube__3": { + 0.0: [0.5081581595102049, 0.49675129077493513, 0.5079476141696376], + }, + "go_stochastic_on_cube__3": { + 1.5938474175637294e-22: [0.5333327585272383, 0.5333327585272383, 0.5499994072312144], + }, + "go_stretchedv_on_cube__3": { + 0.0: [0.2500000000000284, 0.24999999999997158, 0.2500000000000284], + }, + "go_styblinskitang_on_cube__3": { + -117.49849711131428: [0.2096465969993631, 0.2096465972561869, 0.20964659614351272], + }, + "go_trigonometric01_on_cube__3": { + 0.0: [1.3877787807814457e-17, 6.938893903907228e-18, 0.0], + }, + "go_trigonometric02_on_cube__3": { + 1.0: [0.5008999999918231, 0.5008999999997376, 0.5008999999924959], + }, + "go_vincent_on_cube__3": { + -3.0: [0.6708629450200313, 0.7647463865513029, 0.7647158663337039], + }, + "go_wavy_on_cube__3": { + 0.0: [0.499999999997531, 0.5000000000621029, 0.5000000003640678], + }, + "go_weierstrass_on_cube__3": { + 0.0: [0.4999961853027344, 0.49999999999999967, 0.49999999999999967], + }, + "go_whitley_on_cube__3": { + 0.0: [0.0057694254008727915, 0.9614112930973773, 0.13985557238051557], + }, + "go_wolfe_on_cube__3": { + 0.0: [0.0, 0.0, 0.0], + }, + "go_xinsheyang01_on_cube__3": { + 0.0: [0.5, 0.5, 0.5], + }, + "go_xinsheyang02_on_cube__3": { + 0.0: [0.5, 0.5, 0.5], + }, + "go_xinsheyang03_on_cube__3": { + -1.0: [0.49999999997731115, 0.5000000000034495, 0.49999999998913747], + }, + "go_xinsheyang04_on_cube__3": { + -1.0: [0.3429203670388802, 0.6570796326524454, 0.3429203673085393], + }, + "go_yaoliu04_on_cube__3": { + 0.0: [0.5, 0.5, 0.5], + }, + "go_yaoliu09_on_cube__3": { + 0.0: [0.5000000000269273, 0.4999999999491878, 0.49999999989083205], + }, + "go_zacharov_on_cube__3": { + 0.0: [0.3333333333333333, 0.3333333333333333, 0.3333333333333333], + }, + "go_zerosum_on_cube__3": { + 0.0: [0.4999999775192155, 0.5, 0.5], + }, +} diff --git a/solutions_1680975848.py b/solutions_1680975848.py new file mode 100644 index 0000000..4592f01 --- /dev/null +++ b/solutions_1680975848.py @@ -0,0 +1,251 @@ +solutions = { + "go_ackley01_on_cube__4": { + 4.440892098500626e-16: [0.5, 0.5, 0.5, 0.5], + }, + "go_alpine01_on_cube__4": { + 0.0: [0.4952297200093428, 0.4952297200093428, 0.4952297200093428, 0.4952297200093428], + }, + "go_alpine02_on_cube__4": { + -48.33482032244272: [0.7917052678377633, 0.7917052674957755, 0.48158423270992656, 0.7917052673588358], + }, + "go_amgm_on_cube__4": { + 0.0: [0.012306988086844196, 0.012306988086844196, 0.012306988086844196, 0.012306988086844196], + }, + "go_biggsexp04_on_cube__4": { + 0.0: [0.04996029633691984, 0.04996029633691984, 0.24980148168459912, 0.24980148168459912], + }, + "go_brown_on_cube__4": { + 0.0: [0.19999999999999812, 0.2000000000000008, 0.20000000000000118, 0.20000000000000062], + }, + "go_cigar_on_cube__4": { + 0.0: [0.5, 0.5, 0.5, 0.5], + }, + "go_colville_on_cube__4": { + 0.0: [0.5499999999999998, 0.5500000000000002, 0.5500000000000005, 0.5500000000000003], + }, + "go_corana_on_cube__4": { + 0.0: [0.16514354301841233, 0.5037790090306642, 0.5812655986635484, 0.9965260213661287], + }, + "go_cosinemixture_on_cube__4": { + -3.6: [1.0, 1.0, 1.0, 1.0], + }, + "go_csendes_on_cube__4": { + 2.1340398921186287e-95: [0.49999999999999994, 0.49999999999999994, 0.49999999999999994, 0.49999999999999994], + }, + "go_deb01_on_cube__4": { + -1.0: [0.24998474166810553, 0.2842827054985171, 0.250000000494007, 0.24517076362726262], + }, + "go_deb03_on_cube__4": { + -1.0: [0.6814202220739899, 0.6814202214962974, 0.6814202217045495, 0.6814202224584512], + }, + "go_deceptive_on_cube__4": { + -1.0: [0.12504729371493664, 0.4, 0.6, 0.8], + }, + "go_deflectedcorrugatedspring_on_cube__4": { + -1.0: [0.5293413782227367, 0.4718024985689048, 0.434224546444892, 0.4705267221389782], + }, + "go_devilliersglasser01_on_cube__4": { + 1.1781353629549932e-24: [0.643599554903393, 0.003164412438938837, 0.021191388101335643, 0.7694639665621702], + }, + "go_dixonprice_on_cube__4": { + 2.0362472116017367e-29: [0.55, 0.5353553390593274, 0.529730177875068, 0.5272626933166314], + }, + "go_eggholder_on_cube__4": { + -2808.1847921823232: [0.9711233598527298, 0.9228135061716958, 0.936490209590872, 0.9652220933524724], + }, + "go_exponential_on_cube__4": { + -1.0: [0.5000000247218881, 0.49999998767538123, 0.49999998303134136, 0.5000000097075422], + }, + "go_gear_on_cube__4": { + 2.7008571488865134e-12: [0.09051675206121865, 0.15129928153389963, 0.6492028326465633, 0.7748019437203442], + }, + "go_griewank_on_cube__4": { + 0.0: [0.499999999976616, 0.4999999999392863, 0.49999999996604166, 0.4999999988626738], + }, + "go_infinity_on_cube__4": { + 2.1340398921186287e-95: [0.49804687500000006, 0.49804687500000006, 0.5019531249999999, 0.49804687500000006], + }, + "go_katsuura_on_cube__4": { + 1.0: [2.646355357072139e-13, 3.995866137973536e-13, 8.982398158607907e-14, 5.381459167175251e-14], + }, + "go_kowalik_on_cube__4": { + 0.00030748598780560557: [0.5308380971332559, 0.6379070854704445, 0.7895950761936558, 0.5868729032688482], + }, + "go_mielecantrell_on_cube__4": { + 0.0: [0.5, 1.0, 1.0, 1.0], + }, + "go_mishra01_on_cube__4": { + 1.9999999928411163: [0.9999999999999993, 0.9999999999999992, 0.9999999999999999, 0.12006013934268739], + }, + "go_mishra02_on_cube__4": { + 1.9999999928411163: [0.9907412835351275, 0.9172213539800724, 0.9999999999999996, 0.8792695446455677], + }, + "go_mishra07_on_cube__4": { + 0.0: [0.8727569465722927, 0.9226986283327735, 0.09557227422564515, 0.1391780495360423], + }, + "go_mishra11_on_cube__4": { + 0.0: [0.49262618729194974, 0.31782158010515016, 0.5494294194887934, 0.43243988862988303], + }, + "go_multimodal_on_cube__4": { + 0.0: [0.5000000000004408, 0.5000000000000095, 0.6555568806051131, 0.5000000000005456], + }, + "go_needleeye_on_cube__4": { + 1.0: [0.4999999988366891, 0.4999999979965216, 0.4999999988366891, 0.6747993599890604], + }, + "go_penalty01_on_cube__4": { + 1.570544771786639e-32: [0.49000000000000216, 0.4900000000045488, 0.49000000000434424, 0.49000000000259214], + }, + "go_penalty02_on_cube__4": { + 1.3497838043956716e-31: [0.51, 0.51, 0.51, 0.51], + }, + "go_permfunction01_on_cube__4": { + 0.022942589411403945: [0.5076571662271249, 0.8575457353508119, 0.5843426595258812, 0.8361085666110741], + }, + "go_permfunction02_on_cube__4": { + 4.525357590326688e-30: [0.5555598137337187, 0.4719642376742956, 0.49939744649300466, 0.4796132767078549], + }, + "go_pinter_on_cube__4": { + 0.0: [0.5, 0.5, 0.5, 0.5], + }, + "go_plateau_on_cube__4": { + 30.0: [0.4932734474316645, 0.4932734474316645, 0.4932734474316645, 0.5508581326238648], + }, + "go_powell_on_cube__4": { + 0.0: [0.44444509150710204, 0.4444437719243386, 0.4444482661673988, 0.4444482661564514], + }, + "go_powersum_on_cube__4": { + 0.0: [0.6844559265801914, 0.30950792678221917, 0.3343492057195142, 0.6719797392682317], + }, + "go_qing_on_cube__4": { + 5.3707622579709536e-27: [0.49900000000000005, 0.4985857864376269, 0.49826794919243106, 0.498], + }, + "go_quadratic_on_cube__4": { + -3873.7241821862717: [0.5096874319451075, 0.5242667998367262, 0.8136976152333063, 0.18518089676316943], + }, + "go_quintic_on_cube__4": { + 0.0: [0.5354949699058432, 0.3458348614376502, 0.389003675938885, 0.5867971950589506], + }, + "go_rana_on_cube__4": { + -1495.900483081144: [0.19966236719231722, 1.0, 0.001954518905221303, 0.0030862541309490607], + }, + "go_rastrigin_on_cube__4": { + 0.0: [0.49999999999969436, 0.5000002447154946, 0.549866189132194, 0.5000000000019278], + }, + "go_ratkowsky01_on_cube__4": { + 8786.404907963095: [0.6996415124695768, 0.22511186067152653, 0.253209795946327, 0.19987261064121364], + }, + "go_rosenbrock_on_cube__4": { + 1.8427790745962836e-27: [0.5166666666666667, 0.5166666666666668, 0.5166666666666672, 0.5166666666666674], + }, + "go_salomon_on_cube__4": { + 0.0: [0.4990867028725108, 0.49824612382646793, 0.20357400849962232, 0.5035731475872616], + }, + "go_sargan_on_cube__4": { + -35200.00000000005: [0.8999999985946622, 3.469446951953614e-17, 1.0, 0.10000000181447662], + }, + "go_schwefel01_on_cube__4": { + 0.0: [0.50048828125, 0.5, 0.5, 0.5], + }, + "go_schwefel02_on_cube__4": { + 0.0: [0.5000005284691311, 0.4999980379339887, 0.50000312482585, 0.4999975956916072], + }, + "go_schwefel04_on_cube__4": { + 0.0: [0.1, 0.1, 0.1, 0.1], + }, + "go_schwefel20_on_cube__4": { + 0.0: [0.49999999999999983, 0.5000000000000002, 0.5, 0.49999999995473077], + }, + "go_schwefel21_on_cube__4": { + 0.0: [0.4999999997893743, 0.49999999985716703, 0.5000000002106256, 0.49999999978937426], + }, + "go_schwefel22_on_cube__4": { + 0.0: [0.5, 0.5000000000000001, 0.5, 0.5], + }, + "go_schwefel26_on_cube__4": { + -1.089735178538831e-06: [0.9305937532533836, 0.9209687464160179, 0.19747734132307387, 0.9209687456292082], + }, + "go_shekel05_on_cube__4": { + -10.15319967905823: [0.4000037689925856, 0.4000130672256758, 0.40000279482137596, 0.4000143020086375], + }, + "go_shekel07_on_cube__4": { + -10.402940566818666: [0.40005211433664734, 0.4000732914719807, 0.3999500655069954, 0.3999652204984656], + }, + "go_shekel10_on_cube__4": { + -10.536409816692046: [0.4000746531076067, 0.400059293286648, 0.39996633980382557, 0.3999509799996026], + }, + "go_shubert01_on_cube__4": { + -39303.550054363215: [0.7741440434102077, 0.7741556333290653, 0.7429083697053124, 0.7741396753978015], + }, + "go_shubert03_on_cube__4": { + -48.12499776866859: [0.7895897234617342, 0.7895897234965026, 0.7895897234965026, 0.7895897234965026], + }, + "go_shubert04_on_cube__4": { + -58.03203170878015: [0.1458246797794856, 0.14582467977948557, 0.14582467959087073, 0.1458246797794856], + }, + "go_sineenvelope_on_cube__4": { + 0.0: [0.5000000000049838, 0.5000000000180229, 0.4999999999815214, 0.5000000000104797], + }, + "go_sodp_on_cube__4": { + 0.0: [0.5000003501207233, 0.49934332155107486, 0.5009018689609204, 0.5232120945186667], + }, + "go_sphere_on_cube__4": { + 0.0: [0.5, 0.5000000000000009, 0.5, 0.5], + }, + "go_step2_on_cube__4": { + 1.0: [0.5012432021330329, 0.4951491010577182, 0.5059914251045634, 0.502325162192821], + }, + "go_step_on_cube__4": { + 0.0: [0.4996842002116297, 0.49694494375720955, 0.503280368273251, 0.4951664506412295], + }, + "go_stochastic_on_cube__4": { + 9.300834900727792e-22: [0.6, 0.3, 0.33684113309205904, 0.5249999995343387], + }, + "go_stretchedv_on_cube__4": { + 0.0: [0.5, 0.5, 0.5, 0.5], + }, + "go_styblinskitang_on_cube__4": { + -156.6646628150857: [0.022117851576171424, 0.022117851595805146, 0.022117851595805146, 0.022117851576171424], + }, + "go_trigonometric01_on_cube__4": { + 0.0: [0.0, 0.0, 6.938893903907228e-18, 1.734723475976807e-17], + }, + "go_trigonometric02_on_cube__4": { + 1.0: [0.5009000000000405, 0.5009000000002075, 0.5009000000004369, 0.5008998066497936], + }, + "go_vincent_on_cube__4": { + -4.0: [0.3960212450924436, 0.39602124595914034, 0.39602124518164733, 0.39602124530774435], + }, + "go_wavy_on_cube__4": { + 0.0: [0.49999999994282107, 0.4894464797508772, 0.49999999985754334, 0.5000000001497444], + }, + "go_weierstrass_on_cube__4": { + 0.0: [0.5000152588472697, 0.5000000000000009, 0.5, 0.5], + }, + "go_whitley_on_cube__4": { + 0.0: [0.5000697309500134, 0.5000697309500134, 0.5000697309500134, 0.5000697309500134], + }, + "go_xinsheyang01_on_cube__4": { + 0.0: [0.5000638843834544, 0.499956010089577, 0.5008984704522029, 0.5048778232729327], + }, + "go_xinsheyang02_on_cube__4": { + 0.0: [0.5, 0.5, 0.5, 0.49999999999999994], + }, + "go_xinsheyang03_on_cube__4": { + -1.0: [0.3750000212082758, 1.8722817393679314e-10, 0.9999999995579297, 1.1439725125517164e-08], + }, + "go_xinsheyang04_on_cube__4": { + -1.0: [0.344534632972428, 0.3417994205644585, 0.35607999521170186, 0.34602083862333655], + }, + "go_yaoliu04_on_cube__4": { + 0.0: [0.5, 0.5, 0.5, 0.5], + }, + "go_yaoliu09_on_cube__4": { + 0.0: [0.5000000008566511, 0.5000000000634754, 0.500000000363694, 0.49999999975360193], + }, + "go_zacharov_on_cube__4": { + 0.0: [0.4316875852820895, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333], + }, + "go_zerosum_on_cube__4": { + 0.0: [0.5, 0.5, 0.5, 0.5], + }, +} diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..caff946 --- /dev/null +++ b/utils.py @@ -0,0 +1,263 @@ +from dataclasses import dataclass +import math + +feps = 2.0**-23.0 +tiniest = 2.0**-1022.0 +check = object() # secret "key" to pass to wrap_untrustworthy to extract feval_count +final = object() # secret "key" to pass to wrap_untrustworthy to extract results + +color_factory = lambda color: lambda s: print(f"\033[{color}m{s}\033[m") +m1 = color_factory(1) +m30 = color_factory(30) +m31 = color_factory(31) +m32 = color_factory(32) +m33 = color_factory(33) +m34 = color_factory(34) +m35 = color_factory(35) +m36 = color_factory(36) +m37 = color_factory(37) +m90 = color_factory(90) +m91 = color_factory(91) +m92 = color_factory(92) +m93 = color_factory(93) +m94 = color_factory(94) +m95 = color_factory(95) +m96 = color_factory(96) +m97 = color_factory(97) + + +class ExhaustedTrialsError(Exception): + pass + + +def scalar_softplus(x): + if x >= 33.276435657655455: + return float(x) + elif x <= -745.13330078125: + return 0.0 + else: + return math.log1p(math.exp(x)) + + +def phi(d): + # phi(1) = golden ratio + # phi(2) = plastic constant + # phi(3) = the positive real root of x**4-x-1 + x = 2.0 + for i in range(30 if d == 1 else max(10, 28 - d)): + x = pow(1 + x, 1 / (d + 1)) + return x + + +def wrap_untrustworthy( + objective, n_trials, *, raising=False, bounding=None, softplus=False, eps=0.0 +): + # also handles bounding now, so it may be used for other purposes as well. whoops. + feval_count = 0 + best_so_far = None + + def _objective(x): + nonlocal feval_count, best_so_far + if x is check: + return feval_count + if x is final: + assert best_so_far is not None + fopt, xopt = best_so_far + return fopt, xopt, feval_count + if raising and feval_count >= n_trials: + raise ExhaustedTrialsError() + if bounding is not None: + x = do_bounding(x, bounding) + fx = objective(x) + feval_count += 1 + if n_trials is None or feval_count <= n_trials: + if best_so_far is None or fx < best_so_far[0]: + best_so_far = (fx, x.copy()) + return scalar_softplus(fx) + eps if softplus else fx + + return _objective + + +@dataclass +class KeyData: + key: str + d: int + n: int + opt: str + obj: str + run: int + + +def decode_key(key, _filtering=False): + # example key: + # COWrap_d03_n130_freelunch_qpso_ps16_cube_go_amgm_on_cube + k, _, run = key.partition("[") + run, _, _ = run.partition("]") + k = k.removeprefix("COWrap_") + d, _, k = k.partition("_") + n, _, k = k.partition("_") + opt, _, k = k.partition("_cube_") + obj, _, k = k.partition("_on_cube") + if not obj: + if opt.endswith("_on_cube"): + return # fcmaes_biteopt was missing the _cube in its name for a while + if _filtering and obj in ("go_stochastic", "go_xinsheyang01"): + return # these are random + assert not k, k + d = int(d.removeprefix("d"), 10) + n = int(n.removeprefix("n"), 10) + run = int(run, 10) + return KeyData(key=key, d=d, n=n, opt=opt, obj=obj, run=run) + + +class AcquireForWriting: + """ + A context manager that allows for very crude file-locking-like + functionality when the FileLock module is missing. + """ + + def __init__(self, filepath, usingfilelock=None): + from pathlib import Path + + self.filepath = Path(filepath) + if usingfilelock is None: + try: + from filelock import FileLock + except ModuleNotFoundError: + self._locking = False + self.lock = None + else: + self._locking = True + self.lock = FileLock(self._altpath) + elif usingfilelock: + from filelock import FileLock + + self._locking = True + self.lock = FileLock(self._altpath) + else: + self._locking = False + self.lock = None + + @property + def _altpath(self): + suffix = ".lock" if self._locking else "~" + return self.filepath.with_suffix(self.filepath.suffix + suffix) + + def __enter__(self): + if self._locking: + self.lock.__enter__() + else: + from time import sleep + + for _ in range(3): + if self._altpath.exists(): + sleep(1) + assert not self._altpath.exists(), f"file is locked: {self.filepath}" + if not self._locking: + self._altpath.write_bytes(b"") + return self.filepath if self._locking else self._altpath + + def __exit__(self, *exc): + if self._locking: + self.lock.__exit__(*exc) + elif exc == (None, None, None): + assert self._altpath.exists(), f"file went missing: {self.filepath}" + try: + data = self._altpath.read_bytes() + if data: + self.filepath.write_bytes(data) + finally: + self._altpath.unlink() + # from shutil import move + # move(self._altpath, self.filepath) # assumes os.rename overwrites files + + +def perform_another_experimental_scoring_method(results): + new_results = {} + all_opt_names = set() + for obj_name, obj_res in results.items(): + all_res = {} + for fopt, opt_name in obj_res: + all_res.setdefault(fopt, []).append(opt_name) + all_opt_names.add(opt_name) + new_results[obj_name] = dict(sorted(all_res.items())) + + limited_by_floating_point_precision = 53 + + best_ranks_and_counts = {} + for outer_rank in range(1, limited_by_floating_point_precision + 1): + for obj_name, all_res in new_results.items(): + for fopt, opt_names in all_res.items(): + dirty = False + for opt_name in set(opt_names): + if opt_name in best_ranks_and_counts: + rank, count = best_ranks_and_counts[opt_name] + if rank == outer_rank: + best_ranks_and_counts[opt_name] = (rank, count + 1) + dirty = True + else: + best_ranks_and_counts[opt_name] = (outer_rank, 1) + dirty = True + if dirty: + break + + scores = {k: 0.0 for k in all_opt_names} + for opt_name, (rank, count) in best_ranks_and_counts.items(): + points = 2**(1 - rank) + count = min(count, limited_by_floating_point_precision) + scores[opt_name] = score = sum(points / 2**i for i in range(count)) + + return scores + + +def needs_rerun(key, value): + n_dim = len(value["xopt"]) + 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) + assert kd is not None, key + if kd.obj in ng: + # print("filtered", key, file=__import__("sys").stderr) + return True + + return False + + +def merge_summaries(all_summaries): + # i only needed to write this because i effed up my filenames at one point. oh well. + if len(all_summaries) == 0: + return {} + elif len(all_summaries) == 1: + return {k: v for k, v in all_summaries[0].items() if not needs_rerun(k, v)} + new_summaries = {} + for s in all_summaries: + for key, value in s.items(): + if needs_rerun(key, value): + continue + k, _, run = key.partition("[") + run, _, _ = run.partition("]") + for i in range(1, 100): + new_key = f"{k}[{i}]" + if new_key in new_summaries: + if new_summaries[new_key] == value: # this works 'cause it's POD + break # already exists (probably; duration is fucked) + continue + new_summaries[new_key] = value + break + return new_summaries + + +try: + import numpy +except ModuleNotFoundError: + pass +else: + from utils_np import * diff --git a/utils_np.py b/utils_np.py new file mode 100644 index 0000000..a77f5d6 --- /dev/null +++ b/utils_np.py @@ -0,0 +1,257 @@ +# i've separated numpy-dependent methods from the rest of the utils. +from project import project +from utils import AcquireForWriting, merge_summaries, feps, m33, m34, m93 +import numpy as np + + +def do_bounding(x, method="clip"): + if method == "clip": + x = np.clip(x, 0, 1) + elif method == "proj": + # projects x back into the unit hypercube, poorly. + if any(x < 0) or any(x > 1): + x = 2 * x - 1 + x /= np.max(np.abs(x)) + feps + x = (x + 1) / 2 + assert all(x >= 0) and all(x <= 1), x + elif method == "pro2": + # a little more logical. + # FIXME: we need a way to determine the previous (or center) x somehow? + if any(x < 0) or any(x > 1): + x = project(best_so_far[1], x, eps=feps) + elif method == "prcl": + # over-engineered clipping with projection-sliding. (yeah don't ask) + # FIXME: we need a way to determine the previous (or center) x somehow? + from bitten_snes import _project_with + + x = _project_with(x, old, np.array([[0.0, 1.0] * n_dim]), clipping=0.5) + elif method == "tria": + hp = np.pi / 2 + x = np.abs(np.arcsin(np.sin(x * hp)) / hp) + elif method == "sine": + x = np.square(np.sin(0.5 * np.pi * x)) + elif method == "ssin": + x = np.square(np.sin(0.5 * np.pi * (np.arcsinh(x - 0.5) + 0.5))) + elif method == "pycma": + raise Exception("TODO: workaround this like pycma does.") # old ver or new ver? + return x + + +class OWrap: + def __init__(self, objective, n_trials, frugal_percent=1.0, greedy_percent=2.0): + self.feval_count = 0 + self.best_so_far = None + self.warning = None + self.objective = objective + self.n_trials = n_trials + self.__name__ = objective.__name__ # for evolopy + self.frugal_percent = float(frugal_percent) + self.greedy_percent = float(greedy_percent) + + def __str__(self): + return ( + "" + ) + + def __call__(self, x, *args, **kwargs): + if getattr(x, "get_x", None): # zoopt + x = x.get_x() + if type(x) is list: # opytimizer + x = np.array(x) + + if x.ndim == 2: # flatten column vectors + assert x.shape[1] == 1, x.shape + x = x.T[0] + + if not self.warning and (any(x < 0) or any(x > 1.00000001)): + self.warning = "bounds" + # assert False, x + + if not all(np.isfinite(x)): + if not self.warning: + m33("x is not finite (NaN or Inf or -Inf)") + self.warning = "finite" + x[~np.isfinite(x)] = 0.5 + x = np.clip(x, 0, 1) + # assert all(np.isfinite(x)), "x is not finite (NaN or Inf or -Inf)" + fx = self.objective(x) + assert np.isfinite(fx), "f(x) is not finite (NaN or Inf or -Inf)" + self.feval_count += 1 + + if self.feval_count <= self.n_trials: + if self.best_so_far is None or fx < self.best_so_far[0]: + self.best_so_far = (fx, x) + + return float(fx) + + def finish(self, optimizer_name): + if self.warning == "bounds": + m33(f"{optimizer_name} did not abide to bounds") + if self.warning == "finite": + m33(f"{optimizer_name} passed a non-finite value") + if self.feval_count >= self.n_trials * self.greedy_percent: + m33(f"{optimizer_name} got greedy ({self.feval_count}>{self.n_trials})") + # if self.feval_count <= self.n_trials * 0.95: + if self.feval_count < self.n_trials * self.frugal_percent: + m34(f"{optimizer_name} was frugal ({self.feval_count}<{self.n_trials})") + return self.best_so_far + + @property + def fopt(self): + return None if self.best_so_far is None else self.best_so_far[0] + + @property + def xopt(self): + return None if self.best_so_far is None else self.best_so_far[1] + + +class COWrap: + def __init__(self, objective, *, optimizer, n_trials, n_dim, **kwargs): + self._objective = objective + self.optimizer = optimizer + self.n_trials = n_trials + self.n_dim = n_dim + self.kwargs = kwargs + self._dirty = False + + from pathlib import Path + + # self.cache_dir = Path("./cache") + self.cache_dir = Path("~/thursday-cache").expanduser() + self._cached_summaries = None + self.reset_objective() + + def __str__(self): + return ( + "" + ) + + def __name__(self): + return str(getattr(self.ow.objective, "__name__", str(self.ow.objective))) + + def __call__(self, x, *args, **kwargs): + assert not self._ran, "please run .finish() before continuing!" + result = self.ow.__call__(x, *args, **kwargs) + self._dirty = True + return result + + @property + def objective(self): + return self._objective + + @objective.setter + def objective(self, new_objective): + # don't do this or it defeats the purpose: self._cached_summaries = None + self._objective = new_objective + self.reset_objective() + + @property + def cache_name(self): + opt_name = self.optimizer.__name__ + return f"COWrap_d{self.n_dim:02}_n{self.n_trials:03}_{opt_name}" + + @property + def cache_key(self): + opt_name = self.optimizer.__name__ + obj_name = self._objective.__name__ + return f"{self.cache_name}_{obj_name}[{self._run}]" + + @property + def cache_file(self): + opt_name = self.optimizer.__name__ + return self.cache_dir / f"{self.cache_name}.json" + + @property + def cache_file_fucked(self): + opt_name = self.optimizer.__name__ + return self.cache_dir / f"{self.cache_name}_{opt_name}.json" + + @property # TODO: write a setter as well? + def cached_summaries(self): + if self._cached_summaries is not None: + return self._cached_summaries + from json import loads + + if not self.cache_dir.exists() or not ( + self.cache_file.exists() or self.cache_file_fucked.exists() + ): + return {} + # text = self.cache_file.read_text() + # if not text: + # return {} + # summaries = loads(text) + # self._cached_summaries = summaries + all_summaries = [] + for cf in (self.cache_file, self.cache_file_fucked): + if cf.exists(): # at least one exists at this point... + if text := cf.read_text(): # ...but not every file contains anything + all_summaries.append(loads(text)) + self._cached_summaries = merge_summaries(all_summaries) + return self._cached_summaries + + def reset_objective(self): + self._dirty = False + self.ow = OWrap(self._objective, self.n_trials, **self.kwargs) + self._check_cache() + + def _check_cache(self): + # assert not self._dirty # useless for a private method + self._run = 1 + self._ran = False + while self.cache_key in self.cached_summaries: + self._run += 1 + + def cached(self, run): + assert not self._dirty + old_run = self._run + self._run = run + summary = self.cached_summaries.get(self.cache_key, None) + self._run = old_run + if summary is None: + return None + assert "fopt" in summary, summary + assert "xopt" in summary, summary + assert "duration" in summary, summary + fopt = float(summary["fopt"]) + xopt = np.array(summary["xopt"], np.float64) + duration = float(summary["duration"]) + return fopt, xopt + + def finish(self, opt_name=None): + from json import dumps + from time import time + + assert self._dirty + self._ran = True + if opt_name is not None and opt_name != self.optimizer.__name__: + m93("Warning: opt_name mistmatch") + + assert self.ow.best_so_far is not None + # fopt, xopt = self.ow.best_so_far + fopt, xopt = self.ow.finish(self.optimizer.__name__) + summary = dict( + fopt=float(fopt), + xopt=[float(x) for x in xopt], + # duration=float(-1), # old, bad for uniqueness + duration=float(-time()), + ) + + with AcquireForWriting(self.cache_file) as fp: + self._cached_summaries = None # force reload + self._check_cache() # refresh ._run and thereby .cache_key + summaries = self.cached_summaries + summaries[self.cache_key] = summary + text = dumps(summaries, separators=(",", ":")) + fp.write_text(text) + + if self.cache_file_fucked.exists(): + # safe to delete now that i've written and tested merge_summaries. + self.cache_file_fucked.unlink() + + self._cached_summaries = None # force reload in case of other writes + self.reset_objective() + return fopt, xopt