Source code for symforce.opt.objectives.min_max_barrier_objective
# ----------------------------------------------------------------------------
# SymForce - Copyright 2022, Skydio, Inc.
# This source code is under the Apache 2.0 license found in the LICENSE file.
# ----------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import dataclass
import symforce.symbolic as sf
from symforce.opt import barrier_functions
from symforce.opt import noise_models
from symforce.opt import objective
from symforce.opt.residual_block import ResidualBlock
[docs]class MinMaxBarrierObjective(objective.TimestepObjective):
[docs] @dataclass
class Params:
"""
Fields are the same as :func:`symforce.opt.barrier_functions.min_max_power_barrier`
Attributes:
x_nominal_lower: x-value of the point at which the error is equal to error_nominal on
the left-hand side of the barrier function.
x_nominal_upper: x-value of the point at which the error is equal to error_nominal on
the right-hand side of the barrier function.
error_nominal: Error returned when x equals x_nominal_lower or x_nominal_upper.
dist_zero_to_nominal: The distance from either of the x_nominal points to the region of
zero error. Must be less than half the distance between x_nominal_lower and
x_nominal_upper, and must be greater than zero.
"""
x_nominal_lower: sf.Scalar
x_nominal_upper: sf.Scalar
error_nominal: sf.Scalar
dist_zero_to_nominal: sf.Scalar
[docs] @dataclass
class ExtraValues:
"""
Attributes:
unwhitened_residual: The value of each element of the vector after applying the barrier
function but before applying the cost scaling.
"""
unwhitened_residual: sf.Matrix
[docs] @staticmethod
def residual_at_timestep(
vector: sf.Matrix,
params: MinMaxBarrierObjective.Params,
power: sf.Scalar = 1,
cost_scaling: sf.Scalar = 1,
epsilon: sf.Scalar = sf.epsilon(),
) -> ResidualBlock:
"""
Returns the residual block for the given timestep, where the residual is computed by
applying a barrier function to each element of ``vector``, and then optionally scaling the
corresponding cost in the overall optimization problem by ``cost_scaling``.
Args:
vector: Each element of the given vector has a barrier function and scaling applied to
it.
params: Parameters defining the barrier function
power: Power of the barrier function. Defaults to 1, producing a linear barrier function
in the residual, which corresponds to a quadratic cost in the overall optimization
problem.
cost_scaling: Optional scaling parameter. Corresponds to multiplying the cost in the
overall optimization problem by a constant.
"""
# Apply min/max barrier to each element of the vector
barrier = lambda x: barrier_functions.min_max_power_barrier(
x=x,
x_nominal_lower=params.x_nominal_lower,
x_nominal_upper=params.x_nominal_upper,
error_nominal=params.error_nominal,
dist_zero_to_nominal=params.dist_zero_to_nominal,
power=power,
epsilon=epsilon,
)
unwhitened_residual = vector.applyfunc(barrier)
noise_model = noise_models.IsotropicNoiseModel(scalar_information=cost_scaling)
whitened_residual = noise_model.whiten(unwhitened_residual)
return ResidualBlock(
residual=whitened_residual,
extra_values=MinMaxBarrierObjective.ExtraValues(
unwhitened_residual=unwhitened_residual
),
)