Source code for astrophot.fit.func.slalom
import numpy as np
from ...errors import OptimizeStopFail, OptimizeStopSuccess
from ...backend_obj import backend
[docs]
def slalom_step(f, g, x0, m, S, N=10, up=1.3, down=0.5):
l = [f(x0).item()]
d = [0.0]
grad = g(x0)
if backend.allclose(grad, backend.zeros_like(grad)):
raise OptimizeStopSuccess("success: Gradient is zero, optimization converged.")
D = grad + m
D = D / backend.linalg.norm(D)
seeking = False
for _ in range(N):
l.append(f(x0 - S * D).item())
d.append(S)
# Check if the last value is finite
if not np.isfinite(l[-1]):
l.pop()
d.pop()
S *= down
continue
if seeking and np.argmin(l) == len(l) - 1:
# If we are seeking a minimum and the last value is the minimum, we can stop
break
if len(l) < 3:
# Seek better step size based on loss improvement
if l[-1] < l[-2]:
S *= up
else:
S *= down
else:
O = np.polyfit(d[-3:], l[-3:], 2)
if O[0] > 0:
S = -O[1] / (2 * O[0])
seeking = True
else:
S *= down
seeking = False
if np.argmin(l) == 0:
raise OptimizeStopFail("fail: cannot find step to improve.")
return d[np.argmin(l)], l[np.argmin(l)], grad