Source code for agentlib_mpc.optimization_backends.casadi_.minlp

import casadi as ca
import numpy as np

from agentlib_mpc.data_structures.casadi_utils import DiscretizationMethod
from agentlib_mpc.data_structures.mpc_datamodels import MINLPVariableReference
from agentlib_mpc.models.casadi_model import CasadiModel
from agentlib_mpc.optimization_backends.casadi_.core.VariableGroup import (
    OptimizationVariable,
)

from agentlib_mpc.optimization_backends.casadi_ import basic
from agentlib_mpc.optimization_backends.casadi_.core.casadi_backend import CasADiBackend

# todo: All the names are minlp, but this is actually minlp capable


[docs]class CasadiMINLPSystem(basic.BaseSystem): binary_controls: OptimizationVariable def __init__(self): super().__init__() self.is_linear = False
[docs] def initialize(self, model: CasadiModel, var_ref: MINLPVariableReference): self.binary_controls = OptimizationVariable.declare( denotation="w", variables=model.get_inputs(var_ref.binary_controls), ref_list=var_ref.binary_controls, assert_complete=True, binary=True, ) super().initialize(model=model, var_ref=var_ref) self.is_linear = self._is_minlp()
def _is_minlp(self) -> bool: inputs = ca.vertcat(*(v.full_symbolic for v in self.variables)) parameters = ca.vertcat( *(v.full_symbolic for v in self.parameters if v.use_in_stage_function) ) test_params = [1] * ca.vertcat( *( v.add_default_values()[v.name] for v in self.parameters if v.use_in_stage_function ) ) ode = self.ode constraints = self.model_constraints.function outputs = ca.vertcat(ode, constraints) jac = ca.jacobian(outputs, inputs) print(jac) test_input = [0] * inputs.shape[0] jac_func = ca.Function( "jac_func", [inputs, parameters], [jac], ["inputs", "parameters"], ["jacobian"], ) test2 = np.array(test_input) + 0.5 return jac_func(test_input, test_params) == jac_func(test2, test_params)
[docs]class DirectCollocation(basic.DirectCollocation): def _discretize(self, sys: CasadiMINLPSystem): """ Defines a direct collocation discretization. # pylint: disable=invalid-name """ # setup the polynomial base collocation_matrices = self._collocation_polynomial() # shorthands n = self.options.prediction_horizon ts = self.options.time_step # Initial State x0 = self.add_opt_par(sys.initial_state) xk = self.add_opt_var(sys.states, lb=x0, ub=x0, guess=x0) # Parameters that are constant over the horizon const_par = self.add_opt_par(sys.model_parameters) # Formulate the NLP # loop over prediction horizon while self.k < n: # New NLP variable for the control uk = self.add_opt_var(sys.controls) wk = self.add_opt_var(sys.binary_controls) # New parameter for inputs dk = self.add_opt_par(sys.non_controlled_inputs) # perform inner collocation loop opt_vars_inside_inner = [sys.algebraics, sys.outputs] opt_pars_inside_inner = [] constant_over_inner = { sys.controls: uk, sys.non_controlled_inputs: dk, sys.model_parameters: const_par, sys.binary_controls: wk, } xk_end, constraints = self._collocation_inner_loop( collocation=collocation_matrices, state_at_beginning=xk, states=sys.states, opt_vars=opt_vars_inside_inner, opt_pars=opt_pars_inside_inner, const=constant_over_inner, ) # increment loop counter and time self.k += 1 self.pred_time = ts * self.k # New NLP variable for differential state at end of interval xk = self.add_opt_var(sys.states) # Add continuity constraint self.add_constraint(xk - xk_end, gap_closing=True) # add collocation constraints later for fatrop for constraint in constraints: self.add_constraint(*constraint)
[docs]class CasADiMINLPBackend(CasADiBackend): """ Class doing optimization of ADMM subproblems with CasADi. """ system_type = CasadiMINLPSystem discretization_types = {DiscretizationMethod.collocation: DirectCollocation} system: CasadiMINLPSystem