thursday/thursday/utilities/closures.py

39 lines
1.2 KiB
Python

from .math 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, budget, *, 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 >= budget:
raise ExhaustedTrialsError()
if bounding is not None:
x = do_bounding(x, bounding)
fx = objective(x)
feval_count += 1
if budget is None or feval_count <= budget:
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