LQR (parallel)#

LQR solver using associative parallel scan [Särkkä & García-Fernández, 2023, arXiv:2104.03186].

The value functions are found with an associative scan over conditional value function elements, and the optimal trajectory with an associative scan over the closed-loop affine dynamics. The cross term S and the linear input cost r are removed first by the change of variables u = ũ - G x - g, with G = R⁻¹Sᵀ and g = R⁻¹r, which leaves an equivalent problem with S = 0, r = 0.

diffilqrax.plqr.remove_cross_term(lqr)[source]#

Change of input variables u = ũ - G x - g, with G = R⁻¹Sᵀ and g = R⁻¹r, which removes the cross term and the linear input cost. The value functions and the adjoints are unchanged.

Parameters:

lqr (LQR) – LQR parameters, with R invertible.

Returns:

Equivalent LQR with S = 0 and r = 0, the state gain G [Txmxn] and offset g [Txm].

Return type:

Tuple[LQR, Array, Array]

diffilqrax.plqr.build_associative_riccati_elements(model)[source]#

Conditional value function elements (A, b, C, η, J) for the associative Riccati scan, with the value function V_t(x) = ½ xᵀ J_t x - η_tᵀ x.

Parameters:

model (LQRParams) – LQR model parameters.

Returns:

Elements A, b, C, η, J for t = 0..T, the last of which is the final cost.

Return type:

Tuple[Array, Array, Array, Array, Array]

diffilqrax.plqr.associative_riccati_scan(model)[source]#

Obtain value function through associative riccati scan.

Parameters:

model (LQRParams) – LQR model parameters.

Returns:

Linear (η) and quadratic (J) value functions for t = 0..T, with V_t(x) = ½ xᵀ J_t x - η_tᵀ x.

Return type:

Tuple[Array, Array]

diffilqrax.plqr.optimal_gains(model, etas, Js)[source]#

Optimal feedback u_t = K_t x_t + k_t given the value functions, in the original input variables.

Parameters:
  • model (LQRParams) – LQR model parameters.

  • etas (Array) – Linear value functions for t = 0..T.

  • Js (Array) – Quadratic value functions for t = 0..T.

Returns:

Gains (K, k) and the input Hessians Huu = R + Bᵀ J_{t+1} B.

Return type:

Tuple[Gains, Array]

diffilqrax.plqr.get_dcosts(model, etas, Js, alpha=1.0)[source]#

Expected change in cost terms, as returned by the sequential backward pass: V = Σ ½ kᵀ Huu k and v = Σ kᵀ hu, with hu = -Huu k. Scale with alpha for a backtracking step.

Parameters:
  • model (LQRParams) – LQR model parameters.

  • etas (Array) – Linear value functions.

  • Js (Array) – Quadratic value functions.

  • alpha (float) – Linesearch alpha parameter, by default 1.0.

Returns:

Total change in cost-to-go.

Return type:

CostToGo

diffilqrax.plqr.regularise_lqr(lqr, mu)[source]#

Levenberg-Marquardt regularisation in input space, R -> R + μI, i.e. a proximal cost ½μ‖u‖² on the input step. Unlike a regulariser applied to Huu during the Riccati recursion, it does not depend on the value function, so the regularised problem is still an LQR and the associative scan solves it exactly. In the Riccati recursion it adds μI to every Huu.

Parameters:
  • lqr (LQR) – LQR parameters.

  • mu (float) – Regularisation strength.

Returns:

Regularised LQR parameters.

Return type:

LQR

diffilqrax.plqr.project_psd(mat, delta=0.0)[source]#

Project symmetric matrices […xnxn] onto the PSD cone, clipping eigenvalues at delta.

Return type:

Array

diffilqrax.plqr.project_psd_lqr(lqr, delta=1e-06, which='full')[source]#

Convexify the local LQR stage by stage. R is projected to eigenvalues ≥ δ and, if which == "full", the Schur complement Q - S R⁻¹Sᵀ and Qf too. The fully projected problem is a strictly convex LQR, so every element of the associative scan is valid and every Huu is positive definite without retries. Linear terms are untouched, so the gradient of the local problem is unchanged, but it is no longer a Newton model where the projection is active. With which == "R" only negative input curvature is removed: the projection is inactive wherever R ≻ δI, where the Newton step is kept.

Parameters:
  • lqr (LQR) – LQR parameters.

  • delta (float) – Minimum eigenvalue after projection.

  • which (str) – “R” to project R only, “full” to also project Q - S R⁻¹Sᵀ and Qf.

Returns:

Convexified LQR parameters.

Return type:

LQR

diffilqrax.plqr.plqr_backward_pass(model, mu=0.0, pd_thresh=1e-08, return_values=False)[source]#

Parallel counterpart of diffilqrax.lqr.regularised_backward_pass(): associative Riccati scan of the problem regularised with regularise_lqr(), and its optimal gains.

Parameters:
  • model (LQRParams) – LQR model parameters.

  • mu (float) – Regularisation strength, by default 0.0 (exact LQR solution).

  • pd_thresh (float) – Minimum eigenvalue of the regularised Huu for it to count as positive definite, by default 1e-8.

  • return_values (bool) – Also return the value functions (η, J) of the regularised problem, by default False.

Returns:

Expected change in cost terms (V: Σ ½ kᵀ Huu k with the unregularised Huu, v: Σ kᵀ hu), the gains (u = Kx + k), and a flag that is True if the regularised Huu is positive definite at every time step and the gains are finite. With return_values, also (η, J) [(T+1)xn], [(T+1)xnxn], whose costates λ_t = J_t x_t - η_t are the multipliers of the regularised problem.

Return type:

Tuple

diffilqrax.plqr.build_associative_lin_dyn_elements(model, gains, alpha=1.0)[source]#

Closed-loop affine dynamics elements x_{t+1} = F_t x_t + c_t under u_t = K_t x_t + α k_t. The first element absorbs the initial state.

Parameters:
  • model (LQRParams) – LQR model parameters (only the dynamics and x0 are used).

  • gains (Gains) – Feedback gains (K, k).

  • alpha (float) – Linesearch step on the feedforward term, by default 1.0.

Returns:

Elements (F, c).

Return type:

Tuple[Array, Array]

diffilqrax.plqr.closed_loop_scan(model, gains, alpha=1.0)[source]#

States x_1..x_T of the linear dynamics under u_t = K_t x_t + α k_t, by an associative scan.

Parameters:
  • model (LQRParams) – LQR model parameters (only the dynamics and x0 are used).

  • gains (Gains) – Feedback gains (K, k).

  • alpha (float) – Linesearch step on the feedforward term, by default 1.0.

Returns:

States x_1..x_T.

Return type:

Array

diffilqrax.plqr.associative_opt_traj_scan(model, etas, Js, alpha=1.0)[source]#

Obtain the optimal state trajectory through an associative scan of the closed-loop dynamics.

Parameters:
  • model (LQRParams) – LQR problem (initial state, LQR parameters).

  • etas (Array) – Linear value functions.

  • Js (Array) – Quadratic value functions.

  • alpha (float) – Linesearch step on the feedforward term, by default 1.0.

Returns:

States x_1..x_T, and the gains with u_t = K_t x_t + α k_t.

Return type:

Tuple[Array, Gains]

diffilqrax.plqr.solve_plqr(model)[source]#

Run backward forward sweep to find optimal control.

Parameters:

model (LQRParams) – LQR model parameters.

Returns:

State trajectory, control inputs, and adjoint variables.

Return type:

Tuple[Array, Array, Array]

diffilqrax.plqr.solve_plqr_swap_x0(model)[source]#

Run backward forward sweep to find optimal control freeze x0 to zero.

Parameters:

model (LQRParams) – LQR model parameters.

Returns:

State trajectory, control inputs, and adjoint variables.

Return type:

Tuple[Array, Array, Array]

diffilqrax.plqr.build_fwd_lin_dyn_elements(lqr_params, Us_init, a_term=None)[source]#

Generate sequence of elements {c} for forward integration.

Parameters:
  • lqr_params (LQRParams) – LQR parameters and initial state.

  • Us_init (Array) – Input sequence.

  • a_term (Array) – Offset term, by default None.

Returns:

Set of elements {c} for associative scan.

Return type:

Tuple[Array, Array]

diffilqrax.plqr.parallel_forward_lin_integration(lqr_params, Us_init, a_term)[source]#

Associative scan for forward linear dynamics.

Parameters:
  • lqr_params (LQRParams) – LQR parameters and initial state.

  • Us_init (Array) – Input sequence.

  • a_term (Array) – Offset term.

Returns:

State trajectory.

Return type:

Array

diffilqrax.plqr.build_rev_lin_dyn_elements(lqr_params, xs_traj, us_traj)[source]#

Generate sequence of elements {c} for reverse integration of adjoints.

Parameters:
  • lqr_params (LQRParams) – LQR parameters and initial state.

  • xs_traj (Array) – State trajectory.

  • us_traj (Array) – Control inputs.

Returns:

Set of elements {c} for associative scan.

Return type:

Tuple[Array, Array]

diffilqrax.plqr.parallel_reverse_lin_integration(lqr_params, xs_traj, us_traj)[source]#

Associative scan for reverse linear dynamics.

Parameters:
  • lqr_params (LQRParams) – LQR parameters and initial state.

  • xs_traj (Array) – State trajectory.

  • us_traj (Array) – Control inputs.

Returns:

Adjoint variables.

Return type:

Array