L-BFGS is a memory-efficient quasi-Newton optimizer that approximates the inverse Hessian using a limited history of past parameter and gradient differences. The two-loop recursion is its core algorithm for computing the search direction without ever forming the full matrix.
Given the current gradient and a history of m past step differences (s_list) and gradient differences (y_list), compute the L-BFGS search direction.
For each history pair i:
si=xi+1−xiyi=gi+1−giρi=yiTsi1First loop (backward, i = m-1 down to 0):
Initial scaling using the most recent pair:
γ=ym−1Tym−1sm−1Tym−1r=γ⋅qSecond loop (forward, i = 0 up to m-1):
For each i from oldest to newest: compute beta = rho_i * dot(y_i, r), then update r = r + s_i * (alpha_i - beta).
Return the negated result: direction = -r (descent direction).
Input:
grad = [2.0], s_list = [[1.0]], y_list = [[2.0]]
Output:
[-1.0]
With one history pair in 1D: rho = 0.5, alpha = 1.0, q becomes 0. gamma = 0.5, r = 0. After forward loop r = 1.0. Negated: [-1.0].
Input:
grad = [6.0, 4.0, 2.0], s_list = [[1,0,0],[0,1,0],[0,0,1]], y_list = [[2,0,0],[0,2,0],[0,0,2]]
Output:
[-3.0, -2.0, -1.0]
With an identity-like history, the inverse Hessian approximation is 0.5 * I, so the direction is -0.5 * gradient.
The backward loop goes from the most recent history pair (index m-1) to the oldest (index 0). Store each alpha_i for use in the forward loop.
The dot product of two vectors a and b is sum(a_i * b_i). You need it for rho, alpha, beta, and gamma computations.
Sign in to take notes on this problem
Accepts: array
Accepts: array
Accepts: array
L-BFGS is a memory-efficient quasi-Newton optimizer that approximates the inverse Hessian using a limited history of past parameter and gradient differences. The two-loop recursion is its core algorithm for computing the search direction without ever forming the full matrix.
Given the current gradient and a history of m past step differences (s_list) and gradient differences (y_list), compute the L-BFGS search direction.
For each history pair i:
si=xi+1−xiyi=gi+1−giρi=yiTsi1First loop (backward, i = m-1 down to 0):
Initial scaling using the most recent pair:
γ=ym−1Tym−1sm−1Tym−1r=γ⋅qSecond loop (forward, i = 0 up to m-1):
For each i from oldest to newest: compute beta = rho_i * dot(y_i, r), then update r = r + s_i * (alpha_i - beta).
Return the negated result: direction = -r (descent direction).
Input:
grad = [2.0], s_list = [[1.0]], y_list = [[2.0]]
Output:
[-1.0]
With one history pair in 1D: rho = 0.5, alpha = 1.0, q becomes 0. gamma = 0.5, r = 0. After forward loop r = 1.0. Negated: [-1.0].
Input:
grad = [6.0, 4.0, 2.0], s_list = [[1,0,0],[0,1,0],[0,0,1]], y_list = [[2,0,0],[0,2,0],[0,0,2]]
Output:
[-3.0, -2.0, -1.0]
With an identity-like history, the inverse Hessian approximation is 0.5 * I, so the direction is -0.5 * gradient.
The backward loop goes from the most recent history pair (index m-1) to the oldest (index 0). Store each alpha_i for use in the forward loop.
The dot product of two vectors a and b is sum(a_i * b_i). You need it for rho, alpha, beta, and gamma computations.
Sign in to take notes on this problem
Accepts: array
Accepts: array
Accepts: array