pub struct LqRegulator<const N: usize, const M: usize> {
pub a: Vec<f64>,
pub b: Vec<f64>,
pub c: Vec<f64>,
pub q: Vec<f64>,
pub q_terminal: Vec<f64>,
pub r: Vec<f64>,
pub horizon: f64,
/* private fields */
}Expand description
Finite-horizon linear-quadratic regulator with constant coefficients.
Matrices are stored row-major as Vec<f64>. The control dimension M is
part of the type so the Control associated type can be a fixed-length
array.
See the module-level documentation for the formulation and exact solution.
Fields§
§a: Vec<f64>State-drift coupling matrix A (row-major, n x n).
b: Vec<f64>Control-input matrix B (row-major, n x m).
c: Vec<f64>Diffusion matrix C (row-major, n x n).
q: Vec<f64>Running state cost Q (row-major, n x n).
q_terminal: Vec<f64>Terminal state cost Q_T (row-major, n x n).
r: Vec<f64>Running control cost R (row-major, m x m).
horizon: f64Remaining horizon T.
Implementations§
Source§impl<const N: usize, const M: usize> LqRegulator<N, M>
impl<const N: usize, const M: usize> LqRegulator<N, M>
Sourcepub fn new(
a: &[f64],
b: &[f64],
c: &[f64],
q: &[f64],
q_terminal: &[f64],
r: &[f64],
horizon: f64,
) -> Self
pub fn new( a: &[f64], b: &[f64], c: &[f64], q: &[f64], q_terminal: &[f64], r: &[f64], horizon: f64, ) -> Self
Creates an LQ regulator.
Matrices are row-major. All matrix sizes are asserted to match N and
M.
§Panics
Panics if horizon is not positive or any matrix has the wrong length.
§Examples
use solver::models::lq_regulator::LqRegulator;
let lq = LqRegulator::<2, 1>::new(
&[0.0, 1.0, 0.0, 0.0],
&[0.0, 1.0],
&[0.0, 0.0, 0.0, 0.0],
&[1.0, 0.0, 0.0, 0.0],
&[1.0, 0.0, 0.0, 0.0],
&[1.0],
1.0,
);
assert_eq!(lq.horizon, 1.0);Sourcepub fn riccati_solution(&self) -> (Vec<f64>, f64)
pub fn riccati_solution(&self) -> (Vec<f64>, f64)
Solves the backward Riccati ODE with an implicit Euler scheme.
Returns (p, q) where p is the flat row-major solution of P(t)
at t = 0 and q is the scalar noise-correction term q(0).
The number of time steps is fixed by Self::riccati_steps.
§Examples
use solver::models::lq_regulator::LqRegulator;
let lq = LqRegulator::<1, 1>::new(
&[0.0], &[1.0], &[0.0], &[1.0], &[1.0], &[1.0], 1.0,
);
let (p, q) = lq.riccati_solution();
assert!(p[0] > 0.0);
assert!(q >= 0.0);Sourcepub fn riccati_solution_with_steps(&self, steps: usize) -> (Vec<f64>, f64)
pub fn riccati_solution_with_steps(&self, steps: usize) -> (Vec<f64>, f64)
Solves the backward Riccati ODE for the first steps fixed-size
backward steps from the terminal condition.
Each step has size horizon / riccati_steps, so steps selects the
remaining horizon steps * horizon / riccati_steps at which P and q
are evaluated. steps = 0 returns the terminal condition (Q_T, 0);
steps = riccati_steps() returns the solution at the start of the
horizon.
Sourcepub fn riccati_steps(&self) -> usize
pub fn riccati_steps(&self) -> usize
Number of Riccati backward steps.
The Riccati ODE is independent of the spatial grid and, for constant
coefficients, its solution is essentially independent of the step size
once dt is small. A fixed modest step count keeps the reference cheap
and deterministic.
Sourcepub fn feedback_gain(&self, t: f64) -> Vec<f64>
pub fn feedback_gain(&self, t: f64) -> Vec<f64>
Optimal feedback gain K = -R^{-1} B' P(t) at forward time t.
Returns a row-major m x n matrix K so that u = K x.
Trait Implementations§
Source§impl<const N: usize, const M: usize> Clone for LqRegulator<N, M>
impl<const N: usize, const M: usize> Clone for LqRegulator<N, M>
Source§fn clone(&self) -> LqRegulator<N, M>
fn clone(&self) -> LqRegulator<N, M>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<const N: usize, const M: usize> ControlProblem<N> for LqRegulator<N, M>
impl<const N: usize, const M: usize> ControlProblem<N> for LqRegulator<N, M>
Source§type Control = [f64; M]
type Control = [f64; M]
Source§fn optimize(
&self,
t: f64,
state: &[f64; N],
_derivs: &StateDerivatives<N>,
) -> Self::Control
fn optimize( &self, t: f64, state: &[f64; N], _derivs: &StateDerivatives<N>, ) -> Self::Control
(t, state).Source§fn running_reward(
&self,
_t: f64,
state: &[f64; N],
control: &Self::Control,
) -> f64
fn running_reward( &self, _t: f64, state: &[f64; N], control: &Self::Control, ) -> f64
f(t,x,u).Source§fn generator(
&self,
_t: f64,
state: &[f64; N],
control: &Self::Control,
derivs: &StateDerivatives<N>,
) -> f64
fn generator( &self, _t: f64, state: &[f64; N], control: &Self::Control, derivs: &StateDerivatives<N>, ) -> f64
L^u V for the given control and
derivative bundle.Source§fn next_step(
&self,
t: f64,
state: &[f64; N],
dt: f64,
noise: &[f64; N],
) -> [f64; N]
fn next_step( &self, t: f64, state: &[f64; N], dt: f64, noise: &[f64; N], ) -> [f64; N]
t.Source§fn is_diffusion_dimension(&self, _dim: usize) -> bool
fn is_diffusion_dimension(&self, _dim: usize) -> bool
Source§fn driver(
&self,
t: f64,
state: &[f64; N],
control: &Self::Control,
derivs: &StateDerivatives<N>,
) -> f64
fn driver( &self, t: f64, state: &[f64; N], control: &Self::Control, derivs: &StateDerivatives<N>, ) -> f64
f(t,x,u) + L^u V. Read moreSource§fn bsde_driver(
&self,
t: f64,
state: &[f64; N],
control: &Self::Control,
_derivs: &StateDerivatives<N>,
_dt: f64,
) -> f64
fn bsde_driver( &self, t: f64, state: &[f64; N], control: &Self::Control, _derivs: &StateDerivatives<N>, _dt: f64, ) -> f64
Source§fn apply_constraint(&self, _state: &[f64; N], value: f64) -> f64
fn apply_constraint(&self, _state: &[f64; N], value: f64) -> f64
V >= payoff for an American option. Read moreSource§fn constant_discount_rate(&self) -> Option<f64>
fn constant_discount_rate(&self) -> Option<f64>
None (state dependent).Source§fn next_step_controlled(
&self,
t: f64,
state: &[f64; N],
_control: &Self::Control,
dt: f64,
noise: &[f64; N],
) -> [f64; N]
fn next_step_controlled( &self, t: f64, state: &[f64; N], _control: &Self::Control, dt: f64, noise: &[f64; N], ) -> [f64; N]
Source§fn is_reduced_value(&self) -> bool
fn is_reduced_value(&self) -> bool
Source§fn gradient_step(&self, _dim: usize) -> f64
fn gradient_step(&self, _dim: usize) -> f64
Auto Trait Implementations§
impl<const N: usize, const M: usize> !Freeze for LqRegulator<N, M>
impl<const N: usize, const M: usize> RefUnwindSafe for LqRegulator<N, M>where
OnceLock<RiccatiCache<N, M>>: RefUnwindSafe,
impl<const N: usize, const M: usize> Send for LqRegulator<N, M>
impl<const N: usize, const M: usize> Sync for LqRegulator<N, M>
impl<const N: usize, const M: usize> Unpin for LqRegulator<N, M>
impl<const N: usize, const M: usize> UnsafeUnpin for LqRegulator<N, M>where
OnceLock<RiccatiCache<N, M>>: UnsafeUnpin,
impl<const N: usize, const M: usize> UnwindSafe for LqRegulator<N, M>where
OnceLock<RiccatiCache<N, M>>: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more