From 258c42d963c503828a54778160e9fd724d313927 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sun, 7 May 2023 06:52:41 -0700 Subject: [PATCH] move objective wrapper into its own file --- thursday/utilities/__init__.py | 1 + thursday/utilities/closures.py | 38 ++++++++++++++++++++++++++++++++++ thursday/utilities/utils.py | 35 ------------------------------- thursday/utilities/utils_np.py | 3 ++- 4 files changed, 41 insertions(+), 36 deletions(-) create mode 100644 thursday/utilities/closures.py diff --git a/thursday/utilities/__init__.py b/thursday/utilities/__init__.py index e85f74d..6dbac33 100644 --- a/thursday/utilities/__init__.py +++ b/thursday/utilities/__init__.py @@ -1,3 +1,4 @@ +from .closures import * from .colors import * from .prog80 import prog from .scoring import * diff --git a/thursday/utilities/closures.py b/thursday/utilities/closures.py new file mode 100644 index 0000000..b7918ff --- /dev/null +++ b/thursday/utilities/closures.py @@ -0,0 +1,38 @@ +from .utils import scalar_softplus +from .utils_np import do_bounding + +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 + + +class ExhaustedTrialsError(Exception): + pass + + +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 diff --git a/thursday/utilities/utils.py b/thursday/utilities/utils.py index d9f7e2e..d6da0c2 100644 --- a/thursday/utilities/utils.py +++ b/thursday/utilities/utils.py @@ -3,12 +3,6 @@ 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 - - -class ExhaustedTrialsError(Exception): - pass def scalar_softplus(x): @@ -30,35 +24,6 @@ def phi(d): 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 diff --git a/thursday/utilities/utils_np.py b/thursday/utilities/utils_np.py index e8d7a70..80eb8e2 100644 --- a/thursday/utilities/utils_np.py +++ b/thursday/utilities/utils_np.py @@ -1,5 +1,6 @@ # i've separated numpy-dependent methods from the rest of the utils. -from . import AcquireForWriting, merge_summaries, feps, m33, m34, m93 +from .colors import m33, m34, m93 +from .utils import AcquireForWriting, merge_summaries, feps from time import time import numpy as np