MPPI¶
Bases: Module
Model Predictive Path Integral (MPPI) controller.
At each call: sample n_samples candidate control sequences of length
horizon_length as perturbations around a nominal sequence:
where \(\varepsilon\) is drawn from a noise distribution (by default a
Gaussian AR(1)). The nominal sequence \(\bar{u}\) is the control sequence
from the previous step (initially zero), shifted by one time step. It is
carried in the policy state s. Each control sequence is rolled out over
the horizon grid through the dynamics. The resulting trajectories are
scored with loss_fn and combined via the standard MPPI weighting
i.e. a softmax over the temperature-scaled negative losses. Only the first control of the resulting sequence is applied at each step. The remainder becomes the next step's nominal sequence.
By default all candidates are rolled out with the same PRNG key (common
random numbers), so they face the same process and observation noise. The n_simulations rollouts
of one candidate draw different noise. Set common_rollout_randomness=False to
give each candidate its own noise instead (increases variance).
Each rollout is run under the "previous_transition" observation/
control convention, so a candidate's \(u_k\) influences \(x_{k+1}\) and
\(y_{k+1}\).
Customizing. Subclass MPPI and override any of the hooks below;
plan_step calls them in this order, and the defaults implement the
standard MPPI above. Each hook takes its own inputs followed by the same
context (x_hat, t_now, s): the belief handed to the policy, the current
time, and the policy state s, an MPPIState (see there for carrying
more or different state).
rollout_initial_condition(x_hat, t_now, s): the distribution each rollout's \(x_0\) is drawn from. Default: aDeltaatx_hat.mean.sample_controls(key, x_hat, t_now, s): the candidate control sequences (the proposal). Default:s.nominal_sequenceplus draws fromnoise(scaled bynoise_std).- Rollouts and
loss_fn(not overridable). Non-finite losses are clamped to the largest finite value. combine_sequences(losses, candidates, x_hat, t_now, s): chooses the weights and returns the plan, the combined sequence. Default: the softmax weighting above.update_state(plan, info, s): returns the next policy state.infois anMPPIStepInfowith the rest of the step:x_hat,t_now,candidates,lossesandresults(the rollouts). Default:swithnominal_sequenceset to the plan shifted left by one (last entry repeated), other fields unchanged.
plan_step then applies plan[0] and advances the next state's key.
Hooks run inside jax.lax.scan (and possibly jax.grad), so they must be
pure and JAX-traceable and must not draw randomness from s.key
(sample_controls gets its own key). The state update_state returns
must keep the structure, shapes and dtypes of the one it received. New fields on an MPPI subclass need a default (or
eqx.field(kw_only=True)).
Attributes:
| Name | Type | Description |
|---|---|---|
dynamics |
DynamicalModel
|
a |
loss_fn |
MPPILossFn
|
|
horizon |
Real[Array, ' horizon_plus_one']
|
The planning grid relative to |
noise_std |
Real[Array, ''] | Real[Array, ' control_dim']
|
Scale applied to the perturbations drawn from |
noise |
Distribution | None
|
Any NumPyro distribution whose samples have shape
|
n_samples |
int
|
Number of sampled control sequences per call. Defaults to
|
n_simulations |
int
|
Number of rollouts per candidate control sequence
(forwarded to |
common_rollout_randomness |
bool
|
If |
temperature |
float
|
MPPI's \(\lambda \ge 0\); higher values flatten the weights
toward a uniform average, lower values concentrate weight on the
lowest-loss samples, and |
batched |
bool
|
Whether the |
rng_key |
PRNGKeyArray | None
|
MPPI's own PRNG key, put in the policy state by
|
horizon_length: int
property
¶
Number of planning steps H in the grid horizon.
initial_state() -> MPPIState
¶
Zero nominal control sequence plus MPPI's own PRNG key.
Must be initialized explicitly. Override it to return an MPPIState
subclass carrying more state.
The key is rng_key if given, otherwise one drawn from the
surrounding NumPyro seed handler.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
rollout_initial_condition(x_hat: Distribution, t_now: Real[Array, ''], s: MPPIState) -> Distribution
¶
Distribution each candidate rollout's \(x_0\) is drawn from.
Default: a Delta at x_hat.mean, i.e. plan from the point estimate.
Return x_hat itself to plan over the whole belief instead.
sample_controls(key: PRNGKeyArray, x_hat: Distribution, t_now: Real[Array, ''], s: MPPIState) -> Real[Array, 'n_samples horizon control_dim']
¶
Candidate control sequences to roll out and score (the proposal).
Default: s.nominal_sequence plus n_samples noise_std-scaled
draws from noise.
combine_sequences(losses: Real[Array, ' n_samples'], candidates: Real[Array, 'n_samples horizon control_dim'], x_hat: Distribution, t_now: Real[Array, ''], s: MPPIState) -> Real[Array, 'horizon control_dim']
¶
Weight the candidates and combine them into this step's plan, whose
first entry is applied. losses are always finite.
Default: the softmax weights softmax(-losses / temperature)
and the weighted mean of the candidates. With
temperature=0 all the weight goes to the lowest-loss candidate.
update_state(plan: Real[Array, 'horizon control_dim'], info: MPPIStepInfo, s: MPPIState) -> MPPIState
¶
Next policy state, from this step's plan and info (an
MPPIStepInfo: the belief, time, candidates, their finite losses and
rollouts). Must return the same fields as s.
Default: s with nominal_sequence set to the plan shifted left by
one with the last entry repeated (the receding-horizon warm start);
other fields unchanged.
plan_step(x_hat: Distribution, t_now: Real[Array, ''], s: MPPIState) -> tuple[Real[Array, ' control_dim'], MPPIState, MPPIStepInfo]
¶
Do MPPI's full planning step and also return what it computed, as
the MPPIStepInfo, useful for debugging.
__call__ (used by DiscreteControlLoopSimulator) is a
thin wrapper around this that drops the info.
Every field of info.results is shaped
(n_samples, n_simulations, horizon, ...).
MPPIState¶
Bases: Module
MPPI's internal policy state.
To add fields, subclass it and override MPPI.initial_state to return
the subclass.
To use them, override the MPPI hooks that need them.
A key field is always required: MPPI uses it for its own randomness.
Update fields with s.replace(nominal_sequence=...).
Attributes:
| Name | Type | Description |
|---|---|---|
nominal_sequence |
Real[Array, 'horizon control_dim']
|
The sequence the candidates are sampled around,
|
key |
PRNGKeyArray
|
MPPI's own PRNG key, advanced by |
replace(**changes) -> Self
¶
A copy with the given fields replaced, e.g.
s.replace(nominal_sequence=new_nominal). Works for subclasses too.
MPPIStepInfo¶
Bases: NamedTuple
What one MPPI planning step computed, handed to MPPI.update_state.
Attributes:
| Name | Type | Description |
|---|---|---|
x_hat |
Distribution
|
The belief handed to the policy. |
t_now |
Real[Array, '']
|
The current time. |
candidates |
Real[Array, 'n_samples horizon control_dim']
|
The candidate control sequences,
|
losses |
Real[Array, ' n_samples']
|
Their (always finite) losses, |
results |
SimulatedResult
|
Their rollouts, a |
Noise distributions¶
NumPyro distributions for the perturbations MPPI adds to its nominal control
sequence. Pass one as MPPI(noise=...), or any other NumPyro distribution
whose samples have shape (horizon_length, control_dim).
WhiteNoise¶
Bases: Distribution
i.i.d. standard Gaussian perturbations, uncorrelated across the horizon. Only the number of planning steps matters, not their times.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
times
|
Real[Array, ' horizon_plus_one']
|
The planning grid |
required |
control_dim
|
int
|
The control dimension. |
required |
AR1Noise¶
Bases: Distribution
Ornstein-Uhlenbeck perturbations observed at the planning times,
correlated as Cov(eps_h, eps_h') = rho ** |t_h - t_h'|, where t_h is
the time perturbation h starts. Smoother than WhiteNoise; rho=0 is
equivalent to WhiteNoise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
times
|
Real[Array, ' horizon_plus_one']
|
The planning grid |
required |
control_dim
|
int
|
The control dimension. |
required |
rho
|
float
|
Correlation between perturbations one time unit apart, in
|
0.5
|
ColoredNoise¶
Bases: Distribution
Power-law (1/f**beta) perturbations generated in the frequency
domain. Smoother, low-frequency-dominated perturbations for larger
beta. beta=0 = WhiteNoise.
The FFT assumes equally spaced planning times. On an uneven grid the spectrum is over the step index rather than time. A warning is raised for concrete uneven grids; the diagnostic is skipped when times are traced.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
times
|
Real[Array, ' horizon_plus_one']
|
The planning grid |
required |
control_dim
|
int
|
The control dimension. |
required |
beta
|
float
|
Power-law exponent. |
2.0
|