You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2956 lines
99 KiB
2956 lines
99 KiB
2 years ago
|
# -*- coding: future_fstrings -*-
|
||
|
#
|
||
|
# Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
|
||
|
# Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
|
||
|
# Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
|
||
|
# Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
|
||
|
#
|
||
|
# This file is part of acados.
|
||
|
#
|
||
|
# The 2-Clause BSD License
|
||
|
#
|
||
|
# Redistribution and use in source and binary forms, with or without
|
||
|
# modification, are permitted provided that the following conditions are met:
|
||
|
#
|
||
|
# 1. Redistributions of source code must retain the above copyright notice,
|
||
|
# this list of conditions and the following disclaimer.
|
||
|
#
|
||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||
|
# this list of conditions and the following disclaimer in the documentation
|
||
|
# and/or other materials provided with the distribution.
|
||
|
#
|
||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
# POSSIBILITY OF SUCH DAMAGE.;
|
||
|
#
|
||
|
|
||
|
import numpy as np
|
||
|
import os
|
||
|
from .acados_model import AcadosModel
|
||
|
from .utils import get_acados_path, J_to_idx, J_to_idx_slack
|
||
|
|
||
|
class AcadosOcpDims:
|
||
|
"""
|
||
|
Class containing the dimensions of the optimal control problem.
|
||
|
"""
|
||
|
def __init__(self):
|
||
|
self.__nx = None
|
||
|
self.__nu = None
|
||
|
self.__nz = 0
|
||
|
self.__np = 0
|
||
|
self.__ny = 0
|
||
|
self.__ny_e = 0
|
||
|
self.__ny_0 = 0
|
||
|
self.__nr = 0
|
||
|
self.__nr_e = 0
|
||
|
self.__nh = 0
|
||
|
self.__nh_e = 0
|
||
|
self.__nphi = 0
|
||
|
self.__nphi_e = 0
|
||
|
self.__nbx = 0
|
||
|
self.__nbx_0 = 0
|
||
|
self.__nbx_e = 0
|
||
|
self.__nbu = 0
|
||
|
self.__nsbx = 0
|
||
|
self.__nsbx_e = 0
|
||
|
self.__nsbu = 0
|
||
|
self.__nsh = 0
|
||
|
self.__nsh_e = 0
|
||
|
self.__nsphi = 0
|
||
|
self.__nsphi_e = 0
|
||
|
self.__ns = 0
|
||
|
self.__ns_e = 0
|
||
|
self.__ng = 0
|
||
|
self.__ng_e = 0
|
||
|
self.__nsg = 0
|
||
|
self.__nsg_e = 0
|
||
|
self.__nbxe_0 = None
|
||
|
self.__N = None
|
||
|
|
||
|
|
||
|
@property
|
||
|
def nx(self):
|
||
|
""":math:`n_x` - number of states.
|
||
|
Type: int; default: None"""
|
||
|
return self.__nx
|
||
|
|
||
|
@property
|
||
|
def nz(self):
|
||
|
""":math:`n_z` - number of algebraic variables.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nz
|
||
|
|
||
|
@property
|
||
|
def nu(self):
|
||
|
""":math:`n_u` - number of inputs.
|
||
|
Type: int; default: None"""
|
||
|
return self.__nu
|
||
|
|
||
|
@property
|
||
|
def np(self):
|
||
|
""":math:`n_p` - number of parameters.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__np
|
||
|
|
||
|
@property
|
||
|
def ny(self):
|
||
|
""":math:`n_y` - number of residuals in Lagrange term.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__ny
|
||
|
|
||
|
@property
|
||
|
def ny_0(self):
|
||
|
""":math:`n_{y}^0` - number of residuals in Mayer term.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__ny_0
|
||
|
|
||
|
@property
|
||
|
def ny_e(self):
|
||
|
""":math:`n_{y}^e` - number of residuals in Mayer term.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__ny_e
|
||
|
|
||
|
@property
|
||
|
def nr(self):
|
||
|
""":math:`n_{\pi}` - dimension of the image of the inner nonlinear function in positive definite constraints.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nr
|
||
|
|
||
|
@property
|
||
|
def nr_e(self):
|
||
|
""":math:`n_{\pi}^e` - dimension of the image of the inner nonlinear function in positive definite constraints.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nr_e
|
||
|
|
||
|
@property
|
||
|
def nh(self):
|
||
|
""":math:`n_h` - number of nonlinear constraints.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nh
|
||
|
|
||
|
@property
|
||
|
def nh_e(self):
|
||
|
""":math:`n_{h}^e` - number of nonlinear constraints at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nh_e
|
||
|
|
||
|
@property
|
||
|
def nphi(self):
|
||
|
""":math:`n_{\phi}` - number of convex-over-nonlinear constraints.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nphi
|
||
|
|
||
|
@property
|
||
|
def nphi_e(self):
|
||
|
""":math:`n_{\phi}^e` - number of convex-over-nonlinear constraints at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nphi_e
|
||
|
|
||
|
@property
|
||
|
def nbx(self):
|
||
|
""":math:`n_{b_x}` - number of state bounds.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nbx
|
||
|
|
||
|
@property
|
||
|
def nbxe_0(self):
|
||
|
""":math:`n_{be_{x0}}` - number of state bounds at initial shooting node that are equalities.
|
||
|
Type: int; default: None"""
|
||
|
return self.__nbxe_0
|
||
|
|
||
|
@property
|
||
|
def nbx_0(self):
|
||
|
""":math:`n_{b_{x0}}` - number of state bounds for initial state.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nbx_0
|
||
|
|
||
|
@property
|
||
|
def nbx_e(self):
|
||
|
""":math:`n_{b_x}` - number of state bounds at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nbx_e
|
||
|
|
||
|
@property
|
||
|
def nbu(self):
|
||
|
""":math:`n_{b_u}` - number of input bounds.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nbu
|
||
|
|
||
|
@property
|
||
|
def nsbx(self):
|
||
|
""":math:`n_{{sb}_x}` - number of soft state bounds.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsbx
|
||
|
|
||
|
@property
|
||
|
def nsbx_e(self):
|
||
|
""":math:`n_{{sb}^e_{x}}` - number of soft state bounds at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsbx_e
|
||
|
|
||
|
@property
|
||
|
def nsbu(self):
|
||
|
""":math:`n_{{sb}_u}` - number of soft input bounds.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsbu
|
||
|
|
||
|
@property
|
||
|
def nsg(self):
|
||
|
""":math:`n_{{sg}}` - number of soft general linear constraints.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsg
|
||
|
|
||
|
@property
|
||
|
def nsg_e(self):
|
||
|
""":math:`n_{{sg}^e}` - number of soft general linear constraints at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsg_e
|
||
|
|
||
|
@property
|
||
|
def nsh(self):
|
||
|
""":math:`n_{{sh}}` - number of soft nonlinear constraints.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsh
|
||
|
|
||
|
@property
|
||
|
def nsh_e(self):
|
||
|
""":math:`n_{{sh}}^e` - number of soft nonlinear constraints at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsh_e
|
||
|
|
||
|
@property
|
||
|
def nsphi(self):
|
||
|
""":math:`n_{{s\phi}}` - number of soft convex-over-nonlinear constraints.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsphi
|
||
|
|
||
|
@property
|
||
|
def nsphi_e(self):
|
||
|
""":math:`n_{{s\phi}^e}` - number of soft convex-over-nonlinear constraints at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__nsphi_e
|
||
|
|
||
|
@property
|
||
|
def ns(self):
|
||
|
""":math:`n_{s}` - total number of slacks.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__ns
|
||
|
|
||
|
@property
|
||
|
def ns_e(self):
|
||
|
""":math:`n_{s}^e` - total number of slacks at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__ns_e
|
||
|
|
||
|
@property
|
||
|
def ng(self):
|
||
|
""":math:`n_{g}` - number of general polytopic constraints.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__ng
|
||
|
|
||
|
@property
|
||
|
def ng_e(self):
|
||
|
""":math:`n_{g}^e` - number of general polytopic constraints at terminal shooting node N.
|
||
|
Type: int; default: 0"""
|
||
|
return self.__ng_e
|
||
|
|
||
|
@property
|
||
|
def N(self):
|
||
|
""":math:`N` - prediction horizon.
|
||
|
Type: int; default: None"""
|
||
|
return self.__N
|
||
|
|
||
|
@nx.setter
|
||
|
def nx(self, nx):
|
||
|
if isinstance(nx, int) and nx > 0:
|
||
|
self.__nx = nx
|
||
|
else:
|
||
|
raise Exception('Invalid nx value, expected positive integer. Exiting.')
|
||
|
|
||
|
@nz.setter
|
||
|
def nz(self, nz):
|
||
|
if isinstance(nz, int) and nz > -1:
|
||
|
self.__nz = nz
|
||
|
else:
|
||
|
raise Exception('Invalid nz value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nu.setter
|
||
|
def nu(self, nu):
|
||
|
if isinstance(nu, int) and nu > -1:
|
||
|
self.__nu = nu
|
||
|
else:
|
||
|
raise Exception('Invalid nu value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@np.setter
|
||
|
def np(self, np):
|
||
|
if isinstance(np, int) and np > -1:
|
||
|
self.__np = np
|
||
|
else:
|
||
|
raise Exception('Invalid np value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@ny_0.setter
|
||
|
def ny_0(self, ny_0):
|
||
|
if isinstance(ny_0, int) and ny_0 > -1:
|
||
|
self.__ny_0 = ny_0
|
||
|
else:
|
||
|
raise Exception('Invalid ny_0 value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@ny.setter
|
||
|
def ny(self, ny):
|
||
|
if isinstance(ny, int) and ny > -1:
|
||
|
self.__ny = ny
|
||
|
else:
|
||
|
raise Exception('Invalid ny value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@ny_e.setter
|
||
|
def ny_e(self, ny_e):
|
||
|
if isinstance(ny_e, int) and ny_e > -1:
|
||
|
self.__ny_e = ny_e
|
||
|
else:
|
||
|
raise Exception('Invalid ny_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nr.setter
|
||
|
def nr(self, nr):
|
||
|
if isinstance(nr, int) and nr > -1:
|
||
|
self.__nr = nr
|
||
|
else:
|
||
|
raise Exception('Invalid nr value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nr_e.setter
|
||
|
def nr_e(self, nr_e):
|
||
|
if isinstance(nr_e, int) and nr_e > -1:
|
||
|
self.__nr_e = nr_e
|
||
|
else:
|
||
|
raise Exception('Invalid nr_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nh.setter
|
||
|
def nh(self, nh):
|
||
|
if isinstance(nh, int) and nh > -1:
|
||
|
self.__nh = nh
|
||
|
else:
|
||
|
raise Exception('Invalid nh value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nh_e.setter
|
||
|
def nh_e(self, nh_e):
|
||
|
if isinstance(nh_e, int) and nh_e > -1:
|
||
|
self.__nh_e = nh_e
|
||
|
else:
|
||
|
raise Exception('Invalid nh_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nphi.setter
|
||
|
def nphi(self, nphi):
|
||
|
if isinstance(nphi, int) and nphi > -1:
|
||
|
self.__nphi = nphi
|
||
|
else:
|
||
|
raise Exception('Invalid nphi value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nphi_e.setter
|
||
|
def nphi_e(self, nphi_e):
|
||
|
if isinstance(nphi_e, int) and nphi_e > -1:
|
||
|
self.__nphi_e = nphi_e
|
||
|
else:
|
||
|
raise Exception('Invalid nphi_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nbx.setter
|
||
|
def nbx(self, nbx):
|
||
|
if isinstance(nbx, int) and nbx > -1:
|
||
|
self.__nbx = nbx
|
||
|
else:
|
||
|
raise Exception('Invalid nbx value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nbxe_0.setter
|
||
|
def nbxe_0(self, nbxe_0):
|
||
|
if isinstance(nbxe_0, int) and nbxe_0 > -1:
|
||
|
self.__nbxe_0 = nbxe_0
|
||
|
else:
|
||
|
raise Exception('Invalid nbxe_0 value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nbx_0.setter
|
||
|
def nbx_0(self, nbx_0):
|
||
|
if isinstance(nbx_0, int) and nbx_0 > -1:
|
||
|
self.__nbx_0 = nbx_0
|
||
|
else:
|
||
|
raise Exception('Invalid nbx_0 value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nbx_e.setter
|
||
|
def nbx_e(self, nbx_e):
|
||
|
if isinstance(nbx_e, int) and nbx_e > -1:
|
||
|
self.__nbx_e = nbx_e
|
||
|
else:
|
||
|
raise Exception('Invalid nbx_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nbu.setter
|
||
|
def nbu(self, nbu):
|
||
|
if isinstance(nbu, int) and nbu > -1:
|
||
|
self.__nbu = nbu
|
||
|
else:
|
||
|
raise Exception('Invalid nbu value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsbx.setter
|
||
|
def nsbx(self, nsbx):
|
||
|
if isinstance(nsbx, int) and nsbx > -1:
|
||
|
self.__nsbx = nsbx
|
||
|
else:
|
||
|
raise Exception('Invalid nsbx value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsbx_e.setter
|
||
|
def nsbx_e(self, nsbx_e):
|
||
|
if isinstance(nsbx_e, int) and nsbx_e > -1:
|
||
|
self.__nsbx_e = nsbx_e
|
||
|
else:
|
||
|
raise Exception('Invalid nsbx_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsbu.setter
|
||
|
def nsbu(self, nsbu):
|
||
|
if isinstance(nsbu, int) and nsbu > -1:
|
||
|
self.__nsbu = nsbu
|
||
|
else:
|
||
|
raise Exception('Invalid nsbu value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsg.setter
|
||
|
def nsg(self, nsg):
|
||
|
if isinstance(nsg, int) and nsg > -1:
|
||
|
self.__nsg = nsg
|
||
|
else:
|
||
|
raise Exception('Invalid nsg value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsg_e.setter
|
||
|
def nsg_e(self, nsg_e):
|
||
|
if isinstance(nsg_e, int) and nsg_e > -1:
|
||
|
self.__nsg_e = nsg_e
|
||
|
else:
|
||
|
raise Exception('Invalid nsg_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsh.setter
|
||
|
def nsh(self, nsh):
|
||
|
if isinstance(nsh, int) and nsh > -1:
|
||
|
self.__nsh = nsh
|
||
|
else:
|
||
|
raise Exception('Invalid nsh value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsh_e.setter
|
||
|
def nsh_e(self, nsh_e):
|
||
|
if isinstance(nsh_e, int) and nsh_e > -1:
|
||
|
self.__nsh_e = nsh_e
|
||
|
else:
|
||
|
raise Exception('Invalid nsh_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsphi.setter
|
||
|
def nsphi(self, nsphi):
|
||
|
if isinstance(nsphi, int) and nsphi > -1:
|
||
|
self.__nsphi = nsphi
|
||
|
else:
|
||
|
raise Exception('Invalid nsphi value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@nsphi_e.setter
|
||
|
def nsphi_e(self, nsphi_e):
|
||
|
if isinstance(nsphi_e, int) and nsphi_e > -1:
|
||
|
self.__nsphi_e = nsphi_e
|
||
|
else:
|
||
|
raise Exception('Invalid nsphi_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@ns.setter
|
||
|
def ns(self, ns):
|
||
|
if isinstance(ns, int) and ns > -1:
|
||
|
self.__ns = ns
|
||
|
else:
|
||
|
raise Exception('Invalid ns value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@ns_e.setter
|
||
|
def ns_e(self, ns_e):
|
||
|
if isinstance(ns_e, int) and ns_e > -1:
|
||
|
self.__ns_e = ns_e
|
||
|
else:
|
||
|
raise Exception('Invalid ns_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@ng.setter
|
||
|
def ng(self, ng):
|
||
|
if isinstance(ng, int) and ng > -1:
|
||
|
self.__ng = ng
|
||
|
else:
|
||
|
raise Exception('Invalid ng value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@ng_e.setter
|
||
|
def ng_e(self, ng_e):
|
||
|
if isinstance(ng_e, int) and ng_e > -1:
|
||
|
self.__ng_e = ng_e
|
||
|
else:
|
||
|
raise Exception('Invalid ng_e value, expected nonnegative integer. Exiting.')
|
||
|
|
||
|
@N.setter
|
||
|
def N(self, N):
|
||
|
if isinstance(N, int) and N > 0:
|
||
|
self.__N = N
|
||
|
else:
|
||
|
raise Exception('Invalid N value, expected positive integer. Exiting.')
|
||
|
|
||
|
def set(self, attr, value):
|
||
|
setattr(self, attr, value)
|
||
|
|
||
|
|
||
|
class AcadosOcpCost:
|
||
|
"""
|
||
|
Class containing the numerical data of the cost:
|
||
|
|
||
|
In case of LINEAR_LS:
|
||
|
stage cost is
|
||
|
:math:`l(x,u,z) = || V_x \, x + V_u \, u + V_z \, z - y_\\text{ref}||^2_W`,
|
||
|
terminal cost is
|
||
|
:math:`m(x) = || V^e_x \, x - y_\\text{ref}^e||^2_{W^e}`
|
||
|
|
||
|
In case of NONLINEAR_LS:
|
||
|
stage cost is
|
||
|
:math:`l(x,u,z) = || y(x,u,z) - y_\\text{ref}||^2_W`,
|
||
|
terminal cost is
|
||
|
:math:`m(x) = || y^e(x) - y_\\text{ref}^e||^2_{W^e}`
|
||
|
"""
|
||
|
def __init__(self):
|
||
|
# initial stage
|
||
|
self.__cost_type_0 = None
|
||
|
self.__W_0 = None
|
||
|
self.__Vx_0 = None
|
||
|
self.__Vu_0 = None
|
||
|
self.__Vz_0 = None
|
||
|
self.__yref_0 = None
|
||
|
self.__cost_ext_fun_type_0 = 'casadi'
|
||
|
# Lagrange term
|
||
|
self.__cost_type = 'LINEAR_LS' # cost type
|
||
|
self.__W = np.zeros((0,0))
|
||
|
self.__Vx = np.zeros((0,0))
|
||
|
self.__Vu = np.zeros((0,0))
|
||
|
self.__Vz = np.zeros((0,0))
|
||
|
self.__yref = np.array([])
|
||
|
self.__Zl = np.array([])
|
||
|
self.__Zu = np.array([])
|
||
|
self.__zl = np.array([])
|
||
|
self.__zu = np.array([])
|
||
|
self.__cost_ext_fun_type = 'casadi'
|
||
|
# Mayer term
|
||
|
self.__cost_type_e = 'LINEAR_LS'
|
||
|
self.__W_e = np.zeros((0,0))
|
||
|
self.__Vx_e = np.zeros((0,0))
|
||
|
self.__yref_e = np.array([])
|
||
|
self.__Zl_e = np.array([])
|
||
|
self.__Zu_e = np.array([])
|
||
|
self.__zl_e = np.array([])
|
||
|
self.__zu_e = np.array([])
|
||
|
self.__cost_ext_fun_type_e = 'casadi'
|
||
|
|
||
|
# initial stage
|
||
|
@property
|
||
|
def cost_type_0(self):
|
||
|
"""Cost type at initial shooting node (0)
|
||
|
-- string in {EXTERNAL, LINEAR_LS, NONLINEAR_LS} or :code:`None`.
|
||
|
Default: :code:`None`.
|
||
|
|
||
|
.. note:: Cost at initial stage is the same as for intermediate shooting nodes if not set differently explicitly.
|
||
|
|
||
|
.. note:: If :py:attr:`cost_type_0` is set to :code:`None` values in :py:attr:`W_0`, :py:attr:`Vx_0`, :py:attr:`Vu_0`, :py:attr:`Vz_0` and :py:attr:`yref_0` are ignored (set to :code:`None`).
|
||
|
"""
|
||
|
return self.__cost_type_0
|
||
|
|
||
|
@property
|
||
|
def W_0(self):
|
||
|
""":math:`W_0` - weight matrix at initial shooting node (0).
|
||
|
Default: :code:`None`.
|
||
|
"""
|
||
|
return self.__W_0
|
||
|
|
||
|
@property
|
||
|
def Vx_0(self):
|
||
|
""":math:`V_x^0` - x matrix coefficient at initial shooting node (0).
|
||
|
Default: :code:`None`.
|
||
|
"""
|
||
|
return self.__Vx_0
|
||
|
|
||
|
@property
|
||
|
def Vu_0(self):
|
||
|
""":math:`V_u^0` - u matrix coefficient at initial shooting node (0).
|
||
|
Default: :code:`None`.
|
||
|
"""
|
||
|
return self.__Vu_0
|
||
|
|
||
|
@property
|
||
|
def Vz_0(self):
|
||
|
""":math:`V_z^0` - z matrix coefficient at initial shooting node (0).
|
||
|
Default: :code:`None`.
|
||
|
"""
|
||
|
return self.__Vz_0
|
||
|
|
||
|
@property
|
||
|
def yref_0(self):
|
||
|
""":math:`y_\\text{ref}^0` - reference at initial shooting node (0).
|
||
|
Default: :code:`None`.
|
||
|
"""
|
||
|
return self.__yref_0
|
||
|
|
||
|
@property
|
||
|
def cost_ext_fun_type_0(self):
|
||
|
"""Type of external function for cost at initial shooting node (0)
|
||
|
-- string in {casadi, generic} or :code:`None`
|
||
|
Default: :code:'casadi'.
|
||
|
|
||
|
.. note:: Cost at initial stage is the same as for intermediate shooting nodes if not set differently explicitly.
|
||
|
"""
|
||
|
return self.__cost_ext_fun_type_0
|
||
|
|
||
|
@yref_0.setter
|
||
|
def yref_0(self, yref_0):
|
||
|
if isinstance(yref_0, np.ndarray):
|
||
|
self.__yref_0 = yref_0
|
||
|
else:
|
||
|
raise Exception('Invalid yref_0 value, expected numpy array. Exiting.')
|
||
|
|
||
|
@W_0.setter
|
||
|
def W_0(self, W_0):
|
||
|
if isinstance(W_0, np.ndarray) and len(W_0.shape) == 2:
|
||
|
self.__W_0 = W_0
|
||
|
else:
|
||
|
raise Exception('Invalid cost W_0 value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@Vx_0.setter
|
||
|
def Vx_0(self, Vx_0):
|
||
|
if isinstance(Vx_0, np.ndarray) and len(Vx_0.shape) == 2:
|
||
|
self.__Vx_0 = Vx_0
|
||
|
else:
|
||
|
raise Exception('Invalid cost Vx_0 value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@Vu_0.setter
|
||
|
def Vu_0(self, Vu_0):
|
||
|
if isinstance(Vu_0, np.ndarray) and len(Vu_0.shape) == 2:
|
||
|
self.__Vu_0 = Vu_0
|
||
|
else:
|
||
|
raise Exception('Invalid cost Vu_0 value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@Vz_0.setter
|
||
|
def Vz_0(self, Vz_0):
|
||
|
if isinstance(Vz_0, np.ndarray) and len(Vz_0.shape) == 2:
|
||
|
self.__Vz_0 = Vz_0
|
||
|
else:
|
||
|
raise Exception('Invalid cost Vz_0 value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@cost_ext_fun_type_0.setter
|
||
|
def cost_ext_fun_type_0(self, cost_ext_fun_type_0):
|
||
|
if cost_ext_fun_type_0 in ['casadi', 'generic']:
|
||
|
self.__cost_ext_fun_type_0 = cost_ext_fun_type_0
|
||
|
else:
|
||
|
raise Exception('Invalid cost_ext_fun_type_0 value, expected numpy array. Exiting.')
|
||
|
|
||
|
# Lagrange term
|
||
|
@property
|
||
|
def cost_type(self):
|
||
|
"""
|
||
|
Cost type at intermediate shooting nodes (1 to N-1)
|
||
|
-- string in {EXTERNAL, LINEAR_LS, NONLINEAR_LS}.
|
||
|
Default: 'LINEAR_LS'.
|
||
|
"""
|
||
|
return self.__cost_type
|
||
|
|
||
|
@property
|
||
|
def W(self):
|
||
|
""":math:`W` - weight matrix at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.zeros((0,0))`.
|
||
|
"""
|
||
|
return self.__W
|
||
|
|
||
|
@property
|
||
|
def Vx(self):
|
||
|
""":math:`V_x` - x matrix coefficient at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.zeros((0,0))`.
|
||
|
"""
|
||
|
return self.__Vx
|
||
|
|
||
|
@property
|
||
|
def Vu(self):
|
||
|
""":math:`V_u` - u matrix coefficient at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.zeros((0,0))`.
|
||
|
"""
|
||
|
return self.__Vu
|
||
|
|
||
|
@property
|
||
|
def Vz(self):
|
||
|
""":math:`V_z` - z matrix coefficient at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.zeros((0,0))`.
|
||
|
"""
|
||
|
return self.__Vz
|
||
|
|
||
|
@property
|
||
|
def yref(self):
|
||
|
""":math:`y_\\text{ref}` - reference at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__yref
|
||
|
|
||
|
@property
|
||
|
def Zl(self):
|
||
|
""":math:`Z_l` - diagonal of Hessian wrt lower slack at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__Zl
|
||
|
|
||
|
@property
|
||
|
def Zu(self):
|
||
|
""":math:`Z_u` - diagonal of Hessian wrt upper slack at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__Zu
|
||
|
|
||
|
@property
|
||
|
def zl(self):
|
||
|
""":math:`z_l` - gradient wrt lower slack at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__zl
|
||
|
|
||
|
@property
|
||
|
def zu(self):
|
||
|
""":math:`z_u` - gradient wrt upper slack at intermediate shooting nodes (1 to N-1).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__zu
|
||
|
|
||
|
@property
|
||
|
def cost_ext_fun_type(self):
|
||
|
"""Type of external function for cost at intermediate shooting nodes (1 to N-1).
|
||
|
-- string in {casadi, generic}
|
||
|
Default: :code:'casadi'.
|
||
|
"""
|
||
|
return self.__cost_ext_fun_type
|
||
|
|
||
|
@cost_type.setter
|
||
|
def cost_type(self, cost_type):
|
||
|
cost_types = ('LINEAR_LS', 'NONLINEAR_LS', 'EXTERNAL')
|
||
|
if cost_type in cost_types:
|
||
|
self.__cost_type = cost_type
|
||
|
else:
|
||
|
raise Exception('Invalid cost_type value. Exiting.')
|
||
|
|
||
|
@cost_type_0.setter
|
||
|
def cost_type_0(self, cost_type_0):
|
||
|
cost_types = ('LINEAR_LS', 'NONLINEAR_LS', 'EXTERNAL')
|
||
|
if cost_type_0 in cost_types:
|
||
|
self.__cost_type_0 = cost_type_0
|
||
|
else:
|
||
|
raise Exception('Invalid cost_type_0 value. Exiting.')
|
||
|
|
||
|
@W.setter
|
||
|
def W(self, W):
|
||
|
if isinstance(W, np.ndarray) and len(W.shape) == 2:
|
||
|
self.__W = W
|
||
|
else:
|
||
|
raise Exception('Invalid cost W value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
|
||
|
@Vx.setter
|
||
|
def Vx(self, Vx):
|
||
|
if isinstance(Vx, np.ndarray) and len(Vx.shape) == 2:
|
||
|
self.__Vx = Vx
|
||
|
else:
|
||
|
raise Exception('Invalid cost Vx value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@Vu.setter
|
||
|
def Vu(self, Vu):
|
||
|
if isinstance(Vu, np.ndarray) and len(Vu.shape) == 2:
|
||
|
self.__Vu = Vu
|
||
|
else:
|
||
|
raise Exception('Invalid cost Vu value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@Vz.setter
|
||
|
def Vz(self, Vz):
|
||
|
if isinstance(Vz, np.ndarray) and len(Vz.shape) == 2:
|
||
|
self.__Vz = Vz
|
||
|
else:
|
||
|
raise Exception('Invalid cost Vz value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@yref.setter
|
||
|
def yref(self, yref):
|
||
|
if isinstance(yref, np.ndarray):
|
||
|
self.__yref = yref
|
||
|
else:
|
||
|
raise Exception('Invalid yref value, expected numpy array. Exiting.')
|
||
|
|
||
|
@Zl.setter
|
||
|
def Zl(self, Zl):
|
||
|
if isinstance(Zl, np.ndarray):
|
||
|
self.__Zl = Zl
|
||
|
else:
|
||
|
raise Exception('Invalid Zl value, expected numpy array. Exiting.')
|
||
|
|
||
|
@Zu.setter
|
||
|
def Zu(self, Zu):
|
||
|
if isinstance(Zu, np.ndarray):
|
||
|
self.__Zu = Zu
|
||
|
else:
|
||
|
raise Exception('Invalid Zu value, expected numpy array. Exiting.')
|
||
|
|
||
|
@zl.setter
|
||
|
def zl(self, zl):
|
||
|
if isinstance(zl, np.ndarray):
|
||
|
self.__zl = zl
|
||
|
else:
|
||
|
raise Exception('Invalid zl value, expected numpy array. Exiting.')
|
||
|
|
||
|
@zu.setter
|
||
|
def zu(self, zu):
|
||
|
if isinstance(zu, np.ndarray):
|
||
|
self.__zu = zu
|
||
|
else:
|
||
|
raise Exception('Invalid zu value, expected numpy array. Exiting.')
|
||
|
|
||
|
@cost_ext_fun_type.setter
|
||
|
def cost_ext_fun_type(self, cost_ext_fun_type):
|
||
|
if cost_ext_fun_type in ['casadi', 'generic']:
|
||
|
self.__cost_ext_fun_type = cost_ext_fun_type
|
||
|
else:
|
||
|
raise Exception('Invalid cost_ext_fun_type value, expected numpy array. Exiting.')
|
||
|
|
||
|
# Mayer term
|
||
|
@property
|
||
|
def cost_type_e(self):
|
||
|
"""
|
||
|
Cost type at terminal shooting node (N)
|
||
|
-- string in {EXTERNAL, LINEAR_LS, NONLINEAR_LS}.
|
||
|
Default: 'LINEAR_LS'.
|
||
|
"""
|
||
|
return self.__cost_type_e
|
||
|
|
||
|
@property
|
||
|
def W_e(self):
|
||
|
""":math:`W_e` - weight matrix at terminal shooting node (N).
|
||
|
Default: :code:`np.zeros((0,0))`.
|
||
|
"""
|
||
|
return self.__W_e
|
||
|
|
||
|
@property
|
||
|
def Vx_e(self):
|
||
|
""":math:`V_x^e` - x matrix coefficient for cost at terminal shooting node (N).
|
||
|
Default: :code:`np.zeros((0,0))`.
|
||
|
"""
|
||
|
return self.__Vx_e
|
||
|
|
||
|
@property
|
||
|
def yref_e(self):
|
||
|
""":math:`y_\\text{ref}^e` - cost reference at terminal shooting node (N).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__yref_e
|
||
|
|
||
|
@property
|
||
|
def Zl_e(self):
|
||
|
""":math:`Z_l^e` - diagonal of Hessian wrt lower slack at terminal shooting node (N).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__Zl_e
|
||
|
|
||
|
@property
|
||
|
def Zu_e(self):
|
||
|
""":math:`Z_u^e` - diagonal of Hessian wrt upper slack at terminal shooting node (N).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__Zu_e
|
||
|
|
||
|
@property
|
||
|
def zl_e(self):
|
||
|
""":math:`z_l^e` - gradient wrt lower slack at terminal shooting node (N).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__zl_e
|
||
|
|
||
|
@property
|
||
|
def zu_e(self):
|
||
|
""":math:`z_u^e` - gradient wrt upper slack at terminal shooting node (N).
|
||
|
Default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__zu_e
|
||
|
|
||
|
@property
|
||
|
def cost_ext_fun_type_e(self):
|
||
|
"""Type of external function for cost at intermediate shooting nodes (1 to N-1).
|
||
|
-- string in {casadi, generic}
|
||
|
Default: :code:'casadi'.
|
||
|
"""
|
||
|
return self.__cost_ext_fun_type_e
|
||
|
|
||
|
@cost_type_e.setter
|
||
|
def cost_type_e(self, cost_type_e):
|
||
|
cost_types = ('LINEAR_LS', 'NONLINEAR_LS', 'EXTERNAL')
|
||
|
|
||
|
if cost_type_e in cost_types:
|
||
|
self.__cost_type_e = cost_type_e
|
||
|
else:
|
||
|
raise Exception('Invalid cost_type_e value. Exiting.')
|
||
|
|
||
|
@W_e.setter
|
||
|
def W_e(self, W_e):
|
||
|
if isinstance(W_e, np.ndarray) and len(W_e.shape) == 2:
|
||
|
self.__W_e = W_e
|
||
|
else:
|
||
|
raise Exception('Invalid cost W_e value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@Vx_e.setter
|
||
|
def Vx_e(self, Vx_e):
|
||
|
if isinstance(Vx_e, np.ndarray) and len(Vx_e.shape) == 2:
|
||
|
self.__Vx_e = Vx_e
|
||
|
else:
|
||
|
raise Exception('Invalid cost Vx_e value. ' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@yref_e.setter
|
||
|
def yref_e(self, yref_e):
|
||
|
if isinstance(yref_e, np.ndarray):
|
||
|
self.__yref_e = yref_e
|
||
|
else:
|
||
|
raise Exception('Invalid yref_e value, expected numpy array. Exiting.')
|
||
|
|
||
|
@Zl_e.setter
|
||
|
def Zl_e(self, Zl_e):
|
||
|
if isinstance(Zl_e, np.ndarray):
|
||
|
self.__Zl_e = Zl_e
|
||
|
else:
|
||
|
raise Exception('Invalid Zl_e value, expected numpy array. Exiting.')
|
||
|
|
||
|
@Zu_e.setter
|
||
|
def Zu_e(self, Zu_e):
|
||
|
if isinstance(Zu_e, np.ndarray):
|
||
|
self.__Zu_e = Zu_e
|
||
|
else:
|
||
|
raise Exception('Invalid Zu_e value, expected numpy array. Exiting.')
|
||
|
|
||
|
@zl_e.setter
|
||
|
def zl_e(self, zl_e):
|
||
|
if isinstance(zl_e, np.ndarray):
|
||
|
self.__zl_e = zl_e
|
||
|
else:
|
||
|
raise Exception('Invalid zl_e value, expected numpy array. Exiting.')
|
||
|
|
||
|
@zu_e.setter
|
||
|
def zu_e(self, zu_e):
|
||
|
if isinstance(zu_e, np.ndarray):
|
||
|
self.__zu_e = zu_e
|
||
|
else:
|
||
|
raise Exception('Invalid zu_e value, expected numpy array. Exiting.')
|
||
|
|
||
|
@cost_ext_fun_type_e.setter
|
||
|
def cost_ext_fun_type_e(self, cost_ext_fun_type_e):
|
||
|
if cost_ext_fun_type_e in ['casadi', 'generic']:
|
||
|
self.__cost_ext_fun_type_e = cost_ext_fun_type_e
|
||
|
else:
|
||
|
raise Exception('Invalid cost_ext_fun_type_e value, expected numpy array. Exiting.')
|
||
|
|
||
|
def set(self, attr, value):
|
||
|
setattr(self, attr, value)
|
||
|
|
||
|
|
||
|
def print_J_to_idx_note():
|
||
|
print("NOTE: J* matrix is converted to zero based vector idx* vector, which is returned here.")
|
||
|
|
||
|
|
||
|
class AcadosOcpConstraints:
|
||
|
"""
|
||
|
class containing the description of the constraints
|
||
|
"""
|
||
|
def __init__(self):
|
||
|
self.__constr_type = 'BGH'
|
||
|
self.__constr_type_e = 'BGH'
|
||
|
# initial x
|
||
|
self.__lbx_0 = np.array([])
|
||
|
self.__ubx_0 = np.array([])
|
||
|
self.__idxbx_0 = np.array([])
|
||
|
self.__idxbxe_0 = np.array([])
|
||
|
# state bounds
|
||
|
self.__lbx = np.array([])
|
||
|
self.__ubx = np.array([])
|
||
|
self.__idxbx = np.array([])
|
||
|
# bounds on x at shooting node N
|
||
|
self.__lbx_e = np.array([])
|
||
|
self.__ubx_e = np.array([])
|
||
|
self.__idxbx_e = np.array([])
|
||
|
# bounds on u
|
||
|
self.__lbu = np.array([])
|
||
|
self.__ubu = np.array([])
|
||
|
self.__idxbu = np.array([])
|
||
|
# polytopic constraints
|
||
|
self.__lg = np.array([])
|
||
|
self.__ug = np.array([])
|
||
|
self.__D = np.zeros((0,0))
|
||
|
self.__C = np.zeros((0,0))
|
||
|
# polytopic constraints at shooting node N
|
||
|
self.__C_e = np.zeros((0,0))
|
||
|
self.__lg_e = np.array([])
|
||
|
self.__ug_e = np.array([])
|
||
|
# nonlinear constraints
|
||
|
self.__lh = np.array([])
|
||
|
self.__uh = np.array([])
|
||
|
# nonlinear constraints at shooting node N
|
||
|
self.__uh_e = np.array([])
|
||
|
self.__lh_e = np.array([])
|
||
|
# convex-over-nonlinear constraints
|
||
|
self.__lphi = np.array([])
|
||
|
self.__uphi = np.array([])
|
||
|
# nonlinear constraints at shooting node N
|
||
|
self.__uphi_e = np.array([])
|
||
|
self.__lphi_e = np.array([])
|
||
|
# SLACK BOUNDS
|
||
|
# soft bounds on x
|
||
|
self.__lsbx = np.array([])
|
||
|
self.__usbx = np.array([])
|
||
|
self.__idxsbx = np.array([])
|
||
|
# soft bounds on u
|
||
|
self.__lsbu = np.array([])
|
||
|
self.__usbu = np.array([])
|
||
|
self.__idxsbu = np.array([])
|
||
|
# soft bounds on x at shooting node N
|
||
|
self.__lsbx_e = np.array([])
|
||
|
self.__usbx_e = np.array([])
|
||
|
self.__idxsbx_e= np.array([])
|
||
|
# soft bounds on general linear constraints
|
||
|
self.__lsg = np.array([])
|
||
|
self.__usg = np.array([])
|
||
|
self.__idxsg = np.array([])
|
||
|
# soft bounds on nonlinear constraints
|
||
|
self.__lsh = np.array([])
|
||
|
self.__ush = np.array([])
|
||
|
self.__idxsh = np.array([])
|
||
|
# soft bounds on nonlinear constraints
|
||
|
self.__lsphi = np.array([])
|
||
|
self.__usphi = np.array([])
|
||
|
self.__idxsphi = np.array([])
|
||
|
# soft bounds on general linear constraints at shooting node N
|
||
|
self.__lsg_e = np.array([])
|
||
|
self.__usg_e = np.array([])
|
||
|
self.__idxsg_e = np.array([])
|
||
|
# soft bounds on nonlinear constraints at shooting node N
|
||
|
self.__lsh_e = np.array([])
|
||
|
self.__ush_e = np.array([])
|
||
|
self.__idxsh_e = np.array([])
|
||
|
# soft bounds on nonlinear constraints at shooting node N
|
||
|
self.__lsphi_e = np.array([])
|
||
|
self.__usphi_e = np.array([])
|
||
|
self.__idxsphi_e = np.array([])
|
||
|
|
||
|
|
||
|
# types
|
||
|
@property
|
||
|
def constr_type(self):
|
||
|
"""Constraints type for shooting nodes (0 to N-1). string in {BGH, BGP}.
|
||
|
Default: BGH; BGP is for convex over nonlinear."""
|
||
|
return self.__constr_type
|
||
|
|
||
|
@property
|
||
|
def constr_type_e(self):
|
||
|
"""Constraints type for terminal shooting node N. string in {BGH, BGP}.
|
||
|
Default: BGH; BGP is for convex over nonlinear."""
|
||
|
return self.__constr_type_e
|
||
|
|
||
|
# initial bounds on x
|
||
|
@property
|
||
|
def lbx_0(self):
|
||
|
""":math:`\\underline{x_0}` - lower bounds on x at initial stage 0.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`."""
|
||
|
return self.__lbx_0
|
||
|
|
||
|
@property
|
||
|
def ubx_0(self):
|
||
|
""":math:`\\bar{x_0}` - upper bounds on x at initial stage 0.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__ubx_0
|
||
|
|
||
|
@property
|
||
|
def Jbx_0(self):
|
||
|
""":math:`J_{bx,0}` - matrix coefficient for bounds on x at initial stage 0.
|
||
|
Translated internally to :py:attr:`idxbx_0`"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxbx_0
|
||
|
|
||
|
@property
|
||
|
def idxbx_0(self):
|
||
|
"""Indices of bounds on x at initial stage 0
|
||
|
-- can be set automatically via x0.
|
||
|
Can be set by using :py:attr:`Jbx_0`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxbx_0
|
||
|
|
||
|
@property
|
||
|
def idxbxe_0(self):
|
||
|
"""Indices of bounds on x0 that are equalities -- can be set automatically via :py:attr:`x0`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxbxe_0
|
||
|
|
||
|
# bounds on x
|
||
|
@property
|
||
|
def lbx(self):
|
||
|
""":math:`\\underline{x}` - lower bounds on x at intermediate shooting nodes (1 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__lbx
|
||
|
|
||
|
@property
|
||
|
def ubx(self):
|
||
|
""":math:`\\bar{x}` - upper bounds on x at intermediate shooting nodes (1 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__ubx
|
||
|
|
||
|
@property
|
||
|
def idxbx(self):
|
||
|
"""indices of bounds on x (defines :math:`J_{bx}`) at intermediate shooting nodes (1 to N-1).
|
||
|
Can be set by using :py:attr:`Jbx`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxbx
|
||
|
|
||
|
@property
|
||
|
def Jbx(self):
|
||
|
""":math:`J_{bx}` - matrix coefficient for bounds on x
|
||
|
at intermediate shooting nodes (1 to N-1).
|
||
|
Translated internally into :py:attr:`idxbx`."""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxbx
|
||
|
|
||
|
# bounds on x at shooting node N
|
||
|
@property
|
||
|
def lbx_e(self):
|
||
|
""":math:`\\underline{x}^e` - lower bounds on x at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__lbx_e
|
||
|
|
||
|
@property
|
||
|
def ubx_e(self):
|
||
|
""":math:`\\bar{x}^e` - upper bounds on x at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__ubx_e
|
||
|
|
||
|
@property
|
||
|
def idxbx_e(self):
|
||
|
"""Indices for bounds on x at terminal shooting node N (defines :math:`J_{bx}^e`).
|
||
|
Can be set by using :py:attr:`Jbx_e`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxbx_e
|
||
|
|
||
|
@property
|
||
|
def Jbx_e(self):
|
||
|
""":math:`J_{bx}^e` matrix coefficient for bounds on x at terminal shooting node N.
|
||
|
Translated internally into :py:attr:`idxbx_e`."""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxbx_e
|
||
|
|
||
|
# bounds on u
|
||
|
@property
|
||
|
def lbu(self):
|
||
|
""":math:`\\underline{u}` - lower bounds on u at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`
|
||
|
"""
|
||
|
return self.__lbu
|
||
|
|
||
|
@property
|
||
|
def ubu(self):
|
||
|
""":math:`\\bar{u}` - upper bounds on u at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`
|
||
|
"""
|
||
|
return self.__ubu
|
||
|
|
||
|
@property
|
||
|
def idxbu(self):
|
||
|
"""Indices of bounds on u (defines :math:`J_{bu}`) at shooting nodes (0 to N-1).
|
||
|
Can be set by using :py:attr:`Jbu`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`
|
||
|
"""
|
||
|
return self.__idxbu
|
||
|
|
||
|
@property
|
||
|
def Jbu(self):
|
||
|
""":math:`J_{bu}` - matrix coefficient for bounds on u at shooting nodes (0 to N-1).
|
||
|
Translated internally to :py:attr:`idxbu`.
|
||
|
"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxbu
|
||
|
|
||
|
# polytopic constraints
|
||
|
@property
|
||
|
def C(self):
|
||
|
""":math:`C` - C matrix in :math:`\\underline{g} \\leq D \, u + C \, x \\leq \\bar{g}`
|
||
|
at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array((0,0))`.
|
||
|
"""
|
||
|
return self.__C
|
||
|
|
||
|
@property
|
||
|
def D(self):
|
||
|
""":math:`D` - D matrix in :math:`\\underline{g} \\leq D \, u + C \, x \\leq \\bar{g}`
|
||
|
at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array((0,0))`
|
||
|
"""
|
||
|
return self.__D
|
||
|
|
||
|
@property
|
||
|
def lg(self):
|
||
|
""":math:`\\underline{g}` - lower bound for general polytopic inequalities
|
||
|
at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`
|
||
|
"""
|
||
|
return self.__lg
|
||
|
|
||
|
@property
|
||
|
def ug(self):
|
||
|
""":math:`\\bar{g}` - upper bound for general polytopic inequalities
|
||
|
at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__ug
|
||
|
|
||
|
# polytopic constraints at shooting node N
|
||
|
@property
|
||
|
def C_e(self):
|
||
|
""":math:`C^e` - C matrix at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array((0,0))`.
|
||
|
"""
|
||
|
return self.__C_e
|
||
|
|
||
|
@property
|
||
|
def lg_e(self):
|
||
|
""":math:`\\underline{g}^e` - lower bound on general polytopic inequalities
|
||
|
at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__lg_e
|
||
|
|
||
|
@property
|
||
|
def ug_e(self):
|
||
|
""":math:`\\bar{g}^e` - upper bound on general polytopic inequalities
|
||
|
at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__ug_e
|
||
|
|
||
|
|
||
|
# nonlinear constraints
|
||
|
@property
|
||
|
def lh(self):
|
||
|
""":math:`\\underline{h}` - lower bound for nonlinear inequalities
|
||
|
at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__lh
|
||
|
|
||
|
@property
|
||
|
def uh(self):
|
||
|
""":math:`\\bar{h}` - upper bound for nonlinear inequalities
|
||
|
at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__uh
|
||
|
|
||
|
# nonlinear constraints at shooting node N
|
||
|
@property
|
||
|
def lh_e(self):
|
||
|
""":math:`\\underline{h}^e` - lower bound on nonlinear inequalities
|
||
|
at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__lh_e
|
||
|
|
||
|
@property
|
||
|
def uh_e(self):
|
||
|
""":math:`\\bar{h}^e` - upper bound on nonlinear inequalities
|
||
|
at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__uh_e
|
||
|
|
||
|
# convex-over-nonlinear constraints
|
||
|
@property
|
||
|
def lphi(self):
|
||
|
""":math:`\\underline{\phi}` - lower bound for convex-over-nonlinear inequalities
|
||
|
at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__lphi
|
||
|
|
||
|
@property
|
||
|
def uphi(self):
|
||
|
""":math:`\\bar{\phi}` - upper bound for convex-over-nonlinear inequalities
|
||
|
at shooting nodes (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__uphi
|
||
|
|
||
|
# convex-over-nonlinear constraints at shooting node N
|
||
|
@property
|
||
|
def lphi_e(self):
|
||
|
""":math:`\\underline{\phi}^e` - lower bound on convex-over-nonlinear inequalities
|
||
|
at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__lphi_e
|
||
|
|
||
|
@property
|
||
|
def uphi_e(self):
|
||
|
""":math:`\\bar{\phi}^e` - upper bound on convex-over-nonlinear inequalities
|
||
|
at terminal shooting node N.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`.
|
||
|
"""
|
||
|
return self.__uphi_e
|
||
|
|
||
|
|
||
|
# SLACK bounds
|
||
|
# soft bounds on x
|
||
|
@property
|
||
|
def lsbx(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds on x
|
||
|
at stages (1 to N-1);
|
||
|
not required - zeros by default"""
|
||
|
return self.__lsbx
|
||
|
|
||
|
@property
|
||
|
def usbx(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds on x
|
||
|
at stages (1 to N-1);
|
||
|
not required - zeros by default"""
|
||
|
return self.__usbx
|
||
|
|
||
|
@property
|
||
|
def idxsbx(self):
|
||
|
"""Indices of soft bounds on x within the indices of bounds on x
|
||
|
at stages (1 to N-1).
|
||
|
Can be set by using :py:attr:`Jsbx`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxsbx
|
||
|
|
||
|
@property
|
||
|
def Jsbx(self):
|
||
|
""":math:`J_{sbx}` - matrix coefficient for soft bounds on x
|
||
|
at stages (1 to N-1);
|
||
|
Translated internally into :py:attr:`idxsbx`."""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsbx
|
||
|
|
||
|
# soft bounds on u
|
||
|
@property
|
||
|
def lsbu(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds on u
|
||
|
at stages (0 to N-1).
|
||
|
Not required - zeros by default."""
|
||
|
return self.__lsbu
|
||
|
|
||
|
@property
|
||
|
def usbu(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds on u
|
||
|
at stages (0 to N-1);
|
||
|
not required - zeros by default"""
|
||
|
return self.__usbu
|
||
|
|
||
|
@property
|
||
|
def idxsbu(self):
|
||
|
"""Indices of soft bounds on u within the indices of bounds on u
|
||
|
at stages (0 to N-1).
|
||
|
Can be set by using :py:attr:`Jsbu`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxsbu
|
||
|
|
||
|
@property
|
||
|
def Jsbu(self):
|
||
|
""":math:`J_{sbu}` - matrix coefficient for soft bounds on u
|
||
|
at stages (0 to N-1);
|
||
|
internally translated into :py:attr:`idxsbu`"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsbu
|
||
|
|
||
|
# soft bounds on x at shooting node N
|
||
|
@property
|
||
|
def lsbx_e(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds on x at shooting node N.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__lsbx_e
|
||
|
|
||
|
@property
|
||
|
def usbx_e(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds on x at shooting node N.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__usbx_e
|
||
|
|
||
|
@property
|
||
|
def idxsbx_e(self):
|
||
|
"""Indices of soft bounds on x at shooting node N, within the indices of bounds on x at terminal shooting node N.
|
||
|
Can be set by using :py:attr:`Jsbx_e`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxsbx_e
|
||
|
|
||
|
@property
|
||
|
def Jsbx_e(self):
|
||
|
""":math:`J_{sbx}^e` - matrix coefficient for soft bounds on x at terminal shooting node N.
|
||
|
Translated internally to :py:attr:`idxsbx_e`"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsbx_e
|
||
|
|
||
|
# soft general linear constraints
|
||
|
@property
|
||
|
def lsg(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds for general linear constraints
|
||
|
at stages (0 to N-1).
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`
|
||
|
"""
|
||
|
return self.__lsg
|
||
|
|
||
|
@property
|
||
|
def usg(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds for general linear constraints.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__usg
|
||
|
|
||
|
@property
|
||
|
def idxsg(self):
|
||
|
"""Indices of soft general linear constraints within the indices of general linear constraints.
|
||
|
Can be set by using :py:attr:`Jsg`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxsg
|
||
|
|
||
|
@property
|
||
|
def Jsg(self):
|
||
|
""":math:`J_{sg}` - matrix coefficient for soft bounds on general linear constraints.
|
||
|
Translated internally to :py:attr:`idxsg`"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsg
|
||
|
|
||
|
# soft nonlinear constraints
|
||
|
@property
|
||
|
def lsh(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds for nonlinear constraints.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__lsh
|
||
|
|
||
|
@property
|
||
|
def ush(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds for nonlinear constraints.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__ush
|
||
|
|
||
|
@property
|
||
|
def idxsh(self):
|
||
|
"""Indices of soft nonlinear constraints within the indices of nonlinear constraints.
|
||
|
Can be set by using :py:attr:`Jbx`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxsh
|
||
|
|
||
|
@property
|
||
|
def Jsh(self):
|
||
|
""":math:`J_{sh}` - matrix coefficient for soft bounds on nonlinear constraints.
|
||
|
Translated internally to :py:attr:`idxsh`"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsh
|
||
|
|
||
|
# soft bounds on convex-over-nonlinear constraints
|
||
|
@property
|
||
|
def lsphi(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds for convex-over-nonlinear constraints.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__lsphi
|
||
|
|
||
|
@property
|
||
|
def usphi(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds for convex-over-nonlinear constraints.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__usphi
|
||
|
|
||
|
@property
|
||
|
def idxsphi(self):
|
||
|
"""Indices of soft convex-over-nonlinear constraints within the indices of nonlinear constraints.
|
||
|
Can be set by using :py:attr:`Jsphi`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxsphi
|
||
|
|
||
|
@property
|
||
|
def Jsphi(self):
|
||
|
""":math:`J_{s, \phi}` - matrix coefficient for soft bounds on convex-over-nonlinear constraints.
|
||
|
Translated internally into :py:attr:`idxsphi`."""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsphi
|
||
|
|
||
|
|
||
|
# soft bounds on general linear constraints at shooting node N
|
||
|
@property
|
||
|
def lsg_e(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds for general linear constraints at shooting node N.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__lsg_e
|
||
|
|
||
|
@property
|
||
|
def usg_e(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds for general linear constraints at shooting node N.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__usg_e
|
||
|
|
||
|
@property
|
||
|
def idxsg_e(self):
|
||
|
"""Indices of soft general linear constraints at shooting node N within the indices of general linear constraints at shooting node N.
|
||
|
Can be set by using :py:attr:`Jsg_e`."""
|
||
|
return self.__idxsg_e
|
||
|
|
||
|
@property
|
||
|
def Jsg_e(self):
|
||
|
""":math:`J_{s,h}^e` - matrix coefficient for soft bounds on general linear constraints at terminal shooting node N.
|
||
|
Translated internally to :py:attr:`idxsg_e`"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsg_e
|
||
|
|
||
|
|
||
|
# soft bounds on nonlinear constraints at shooting node N
|
||
|
@property
|
||
|
def lsh_e(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds for nonlinear constraints at terminal shooting node N.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__lsh_e
|
||
|
|
||
|
@property
|
||
|
def ush_e(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds for nonlinear constraints at terminal shooting node N.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__ush_e
|
||
|
|
||
|
@property
|
||
|
def idxsh_e(self):
|
||
|
"""Indices of soft nonlinear constraints at shooting node N within the indices of nonlinear constraints at terminal shooting node N.
|
||
|
Can be set by using :py:attr:`Jsh_e`."""
|
||
|
return self.__idxsh_e
|
||
|
|
||
|
@property
|
||
|
def Jsh_e(self):
|
||
|
""":math:`J_{s,h}^e` - matrix coefficient for soft bounds on nonlinear constraints at terminal shooting node N; fills :py:attr:`idxsh_e`"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsh_e
|
||
|
|
||
|
# soft bounds on convex-over-nonlinear constraints at shooting node N
|
||
|
@property
|
||
|
def lsphi_e(self):
|
||
|
"""Lower bounds on slacks corresponding to soft lower bounds for convex-over-nonlinear constraints at terminal shooting node N.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__lsphi_e
|
||
|
|
||
|
@property
|
||
|
def usphi_e(self):
|
||
|
"""Lower bounds on slacks corresponding to soft upper bounds for convex-over-nonlinear constraints at terminal shooting node N.
|
||
|
Not required - zeros by default"""
|
||
|
return self.__usphi_e
|
||
|
|
||
|
@property
|
||
|
def idxsphi_e(self):
|
||
|
"""Indices of soft nonlinear constraints at shooting node N within the indices of nonlinear constraints at terminal shooting node N.
|
||
|
Can be set by using :py:attr:`Jsphi_e`.
|
||
|
Type: :code:`np.ndarray`; default: :code:`np.array([])`"""
|
||
|
return self.__idxsphi_e
|
||
|
|
||
|
@property
|
||
|
def Jsphi_e(self):
|
||
|
""":math:`J_{sh}^e` - matrix coefficient for soft bounds on convex-over-nonlinear constraints at shooting node N.
|
||
|
Translated internally to :py:attr:`idxsphi_e`"""
|
||
|
print_J_to_idx_note()
|
||
|
return self.__idxsphi_e
|
||
|
|
||
|
@property
|
||
|
def x0(self):
|
||
|
""":math:`x_0 \\in \mathbb{R}^{n_x}` - initial state --
|
||
|
Translated internally to :py:attr:`idxbx_0`, :py:attr:`lbx_0`, :py:attr:`ubx_0`, :py:attr:`idxbxe_0` """
|
||
|
print("x0 is converted to lbx_0, ubx_0, idxbx_0")
|
||
|
print("idxbx_0: ", self.__idxbx_0)
|
||
|
print("lbx_0: ", self.__lbx_0)
|
||
|
print("ubx_0: ", self.__ubx_0)
|
||
|
print("idxbxe_0: ", self.__idxbxe_0)
|
||
|
return None
|
||
|
|
||
|
# SETTERS
|
||
|
@constr_type.setter
|
||
|
def constr_type(self, constr_type):
|
||
|
constr_types = ('BGH', 'BGP')
|
||
|
if constr_type in constr_types:
|
||
|
self.__constr_type = constr_type
|
||
|
else:
|
||
|
raise Exception('Invalid constr_type value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(constr_types) + '.\n\nYou have: ' + constr_type + '.\n\nExiting.')
|
||
|
|
||
|
@constr_type_e.setter
|
||
|
def constr_type_e(self, constr_type_e):
|
||
|
constr_types = ('BGH', 'BGP')
|
||
|
if constr_type_e in constr_types:
|
||
|
self.__constr_type_e = constr_type_e
|
||
|
else:
|
||
|
raise Exception('Invalid constr_type_e value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(constr_types) + '.\n\nYou have: ' + constr_type_e + '.\n\nExiting.')
|
||
|
|
||
|
# initial x
|
||
|
@lbx_0.setter
|
||
|
def lbx_0(self, lbx_0):
|
||
|
if isinstance(lbx_0, np.ndarray):
|
||
|
self.__lbx_0 = lbx_0
|
||
|
else:
|
||
|
raise Exception('Invalid lbx_0 value. Exiting.')
|
||
|
|
||
|
@ubx_0.setter
|
||
|
def ubx_0(self, ubx_0):
|
||
|
if isinstance(ubx_0, np.ndarray):
|
||
|
self.__ubx_0 = ubx_0
|
||
|
else:
|
||
|
raise Exception('Invalid ubx_0 value. Exiting.')
|
||
|
|
||
|
@idxbx_0.setter
|
||
|
def idxbx_0(self, idxbx_0):
|
||
|
if isinstance(idxbx_0, np.ndarray):
|
||
|
self.__idxbx_0 = idxbx_0
|
||
|
else:
|
||
|
raise Exception('Invalid idxbx_0 value. Exiting.')
|
||
|
|
||
|
@Jbx_0.setter
|
||
|
def Jbx_0(self, Jbx_0):
|
||
|
if isinstance(Jbx_0, np.ndarray):
|
||
|
self.__idxbx_0 = J_to_idx(Jbx_0)
|
||
|
else:
|
||
|
raise Exception('Invalid Jbx_0 value. Exiting.')
|
||
|
|
||
|
@idxbxe_0.setter
|
||
|
def idxbxe_0(self, idxbxe_0):
|
||
|
if isinstance(idxbxe_0, np.ndarray):
|
||
|
self.__idxbxe_0 = idxbxe_0
|
||
|
else:
|
||
|
raise Exception('Invalid idxbxe_0 value. Exiting.')
|
||
|
|
||
|
|
||
|
@x0.setter
|
||
|
def x0(self, x0):
|
||
|
if isinstance(x0, np.ndarray):
|
||
|
self.__lbx_0 = x0
|
||
|
self.__ubx_0 = x0
|
||
|
self.__idxbx_0 = np.arange(x0.size)
|
||
|
self.__idxbxe_0 = np.arange(x0.size)
|
||
|
else:
|
||
|
raise Exception('Invalid x0 value. Exiting.')
|
||
|
|
||
|
# bounds on x
|
||
|
@lbx.setter
|
||
|
def lbx(self, lbx):
|
||
|
if isinstance(lbx, np.ndarray):
|
||
|
self.__lbx = lbx
|
||
|
else:
|
||
|
raise Exception('Invalid lbx value. Exiting.')
|
||
|
|
||
|
@ubx.setter
|
||
|
def ubx(self, ubx):
|
||
|
if isinstance(ubx, np.ndarray):
|
||
|
self.__ubx = ubx
|
||
|
else:
|
||
|
raise Exception('Invalid ubx value. Exiting.')
|
||
|
|
||
|
@idxbx.setter
|
||
|
def idxbx(self, idxbx):
|
||
|
if isinstance(idxbx, np.ndarray):
|
||
|
self.__idxbx = idxbx
|
||
|
else:
|
||
|
raise Exception('Invalid idxbx value. Exiting.')
|
||
|
|
||
|
@Jbx.setter
|
||
|
def Jbx(self, Jbx):
|
||
|
if isinstance(Jbx, np.ndarray):
|
||
|
self.__idxbx = J_to_idx(Jbx)
|
||
|
else:
|
||
|
raise Exception('Invalid Jbx value. Exiting.')
|
||
|
|
||
|
# bounds on u
|
||
|
@lbu.setter
|
||
|
def lbu(self, lbu):
|
||
|
if isinstance(lbu, np.ndarray):
|
||
|
self.__lbu = lbu
|
||
|
else:
|
||
|
raise Exception('Invalid lbu value. Exiting.')
|
||
|
|
||
|
@ubu.setter
|
||
|
def ubu(self, ubu):
|
||
|
if isinstance(ubu, np.ndarray):
|
||
|
self.__ubu = ubu
|
||
|
else:
|
||
|
raise Exception('Invalid ubu value. Exiting.')
|
||
|
|
||
|
@idxbu.setter
|
||
|
def idxbu(self, idxbu):
|
||
|
if isinstance(idxbu, np.ndarray):
|
||
|
self.__idxbu = idxbu
|
||
|
else:
|
||
|
raise Exception('Invalid idxbu value. Exiting.')
|
||
|
|
||
|
@Jbu.setter
|
||
|
def Jbu(self, Jbu):
|
||
|
if isinstance(Jbu, np.ndarray):
|
||
|
self.__idxbu = J_to_idx(Jbu)
|
||
|
else:
|
||
|
raise Exception('Invalid Jbu value. Exiting.')
|
||
|
|
||
|
# bounds on x at shooting node N
|
||
|
@lbx_e.setter
|
||
|
def lbx_e(self, lbx_e):
|
||
|
if isinstance(lbx_e, np.ndarray):
|
||
|
self.__lbx_e = lbx_e
|
||
|
else:
|
||
|
raise Exception('Invalid lbx_e value. Exiting.')
|
||
|
|
||
|
@ubx_e.setter
|
||
|
def ubx_e(self, ubx_e):
|
||
|
if isinstance(ubx_e, np.ndarray):
|
||
|
self.__ubx_e = ubx_e
|
||
|
else:
|
||
|
raise Exception('Invalid ubx_e value. Exiting.')
|
||
|
|
||
|
@idxbx_e.setter
|
||
|
def idxbx_e(self, idxbx_e):
|
||
|
if isinstance(idxbx_e, np.ndarray):
|
||
|
self.__idxbx_e = idxbx_e
|
||
|
else:
|
||
|
raise Exception('Invalid idxbx_e value. Exiting.')
|
||
|
|
||
|
@Jbx_e.setter
|
||
|
def Jbx_e(self, Jbx_e):
|
||
|
if isinstance(Jbx_e, np.ndarray):
|
||
|
self.__idxbx_e = J_to_idx(Jbx_e)
|
||
|
else:
|
||
|
raise Exception('Invalid Jbx_e value. Exiting.')
|
||
|
|
||
|
# polytopic constraints
|
||
|
@D.setter
|
||
|
def D(self, D):
|
||
|
if isinstance(D, np.ndarray) and len(D.shape) == 2:
|
||
|
self.__D = D
|
||
|
else:
|
||
|
raise Exception('Invalid constraint D value.' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@C.setter
|
||
|
def C(self, C):
|
||
|
if isinstance(C, np.ndarray) and len(C.shape) == 2:
|
||
|
self.__C = C
|
||
|
else:
|
||
|
raise Exception('Invalid constraint C value.' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@lg.setter
|
||
|
def lg(self, lg):
|
||
|
if isinstance(lg, np.ndarray):
|
||
|
self.__lg = lg
|
||
|
else:
|
||
|
raise Exception('Invalid lg value. Exiting.')
|
||
|
|
||
|
@ug.setter
|
||
|
def ug(self, ug):
|
||
|
if isinstance(ug, np.ndarray):
|
||
|
self.__ug = ug
|
||
|
else:
|
||
|
raise Exception('Invalid ug value. Exiting.')
|
||
|
|
||
|
# polytopic constraints at shooting node N
|
||
|
@C_e.setter
|
||
|
def C_e(self, C_e):
|
||
|
if isinstance(C_e, np.ndarray) and len(C_e.shape) == 2:
|
||
|
self.__C_e = C_e
|
||
|
else:
|
||
|
raise Exception('Invalid constraint C_e value.' \
|
||
|
+ 'Should be 2 dimensional numpy array. Exiting.')
|
||
|
|
||
|
@lg_e.setter
|
||
|
def lg_e(self, lg_e):
|
||
|
if isinstance(lg_e, np.ndarray):
|
||
|
self.__lg_e = lg_e
|
||
|
else:
|
||
|
raise Exception('Invalid lg_e value. Exiting.')
|
||
|
|
||
|
@ug_e.setter
|
||
|
def ug_e(self, ug_e):
|
||
|
if isinstance(ug_e, np.ndarray):
|
||
|
self.__ug_e = ug_e
|
||
|
else:
|
||
|
raise Exception('Invalid ug_e value. Exiting.')
|
||
|
|
||
|
# nonlinear constraints
|
||
|
@lh.setter
|
||
|
def lh(self, lh):
|
||
|
if isinstance(lh, np.ndarray):
|
||
|
self.__lh = lh
|
||
|
else:
|
||
|
raise Exception('Invalid lh value. Exiting.')
|
||
|
|
||
|
@uh.setter
|
||
|
def uh(self, uh):
|
||
|
if isinstance(uh, np.ndarray):
|
||
|
self.__uh = uh
|
||
|
else:
|
||
|
raise Exception('Invalid uh value. Exiting.')
|
||
|
|
||
|
# convex-over-nonlinear constraints
|
||
|
@lphi.setter
|
||
|
def lphi(self, lphi):
|
||
|
if isinstance(lphi, np.ndarray):
|
||
|
self.__lphi = lphi
|
||
|
else:
|
||
|
raise Exception('Invalid lphi value. Exiting.')
|
||
|
|
||
|
@uphi.setter
|
||
|
def uphi(self, uphi):
|
||
|
if isinstance(uphi, np.ndarray):
|
||
|
self.__uphi = uphi
|
||
|
else:
|
||
|
raise Exception('Invalid uphi value. Exiting.')
|
||
|
|
||
|
# nonlinear constraints at shooting node N
|
||
|
@lh_e.setter
|
||
|
def lh_e(self, lh_e):
|
||
|
if isinstance(lh_e, np.ndarray):
|
||
|
self.__lh_e = lh_e
|
||
|
else:
|
||
|
raise Exception('Invalid lh_e value. Exiting.')
|
||
|
|
||
|
@uh_e.setter
|
||
|
def uh_e(self, uh_e):
|
||
|
if isinstance(uh_e, np.ndarray):
|
||
|
self.__uh_e = uh_e
|
||
|
else:
|
||
|
raise Exception('Invalid uh_e value. Exiting.')
|
||
|
|
||
|
# convex-over-nonlinear constraints at shooting node N
|
||
|
@lphi_e.setter
|
||
|
def lphi_e(self, lphi_e):
|
||
|
if isinstance(lphi_e, np.ndarray):
|
||
|
self.__lphi_e = lphi_e
|
||
|
else:
|
||
|
raise Exception('Invalid lphi_e value. Exiting.')
|
||
|
|
||
|
@uphi_e.setter
|
||
|
def uphi_e(self, uphi_e):
|
||
|
if isinstance(uphi_e, np.ndarray):
|
||
|
self.__uphi_e = uphi_e
|
||
|
else:
|
||
|
raise Exception('Invalid uphi_e value. Exiting.')
|
||
|
|
||
|
# SLACK bounds
|
||
|
# soft bounds on x
|
||
|
@lsbx.setter
|
||
|
def lsbx(self, lsbx):
|
||
|
if isinstance(lsbx, np.ndarray):
|
||
|
self.__lsbx = lsbx
|
||
|
else:
|
||
|
raise Exception('Invalid lsbx value. Exiting.')
|
||
|
|
||
|
@usbx.setter
|
||
|
def usbx(self, usbx):
|
||
|
if isinstance(usbx, np.ndarray):
|
||
|
self.__usbx = usbx
|
||
|
else:
|
||
|
raise Exception('Invalid usbx value. Exiting.')
|
||
|
|
||
|
@idxsbx.setter
|
||
|
def idxsbx(self, idxsbx):
|
||
|
if isinstance(idxsbx, np.ndarray):
|
||
|
self.__idxsbx = idxsbx
|
||
|
else:
|
||
|
raise Exception('Invalid idxsbx value. Exiting.')
|
||
|
|
||
|
@Jsbx.setter
|
||
|
def Jsbx(self, Jsbx):
|
||
|
if isinstance(Jsbx, np.ndarray):
|
||
|
self.__idxsbx = J_to_idx_slack(Jsbx)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsbx value, expected numpy array. Exiting.')
|
||
|
|
||
|
# soft bounds on u
|
||
|
@lsbu.setter
|
||
|
def lsbu(self, lsbu):
|
||
|
if isinstance(lsbu, np.ndarray):
|
||
|
self.__lsbu = lsbu
|
||
|
else:
|
||
|
raise Exception('Invalid lsbu value. Exiting.')
|
||
|
|
||
|
@usbu.setter
|
||
|
def usbu(self, usbu):
|
||
|
if isinstance(usbu, np.ndarray):
|
||
|
self.__usbu = usbu
|
||
|
else:
|
||
|
raise Exception('Invalid usbu value. Exiting.')
|
||
|
|
||
|
@idxsbu.setter
|
||
|
def idxsbu(self, idxsbu):
|
||
|
if isinstance(idxsbu, np.ndarray):
|
||
|
self.__idxsbu = idxsbu
|
||
|
else:
|
||
|
raise Exception('Invalid idxsbu value. Exiting.')
|
||
|
|
||
|
@Jsbu.setter
|
||
|
def Jsbu(self, Jsbu):
|
||
|
if isinstance(Jsbu, np.ndarray):
|
||
|
self.__idxsbu = J_to_idx_slack(Jsbu)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsbu value. Exiting.')
|
||
|
|
||
|
# soft bounds on x at shooting node N
|
||
|
@lsbx_e.setter
|
||
|
def lsbx_e(self, lsbx_e):
|
||
|
if isinstance(lsbx_e, np.ndarray):
|
||
|
self.__lsbx_e = lsbx_e
|
||
|
else:
|
||
|
raise Exception('Invalid lsbx_e value. Exiting.')
|
||
|
|
||
|
@usbx_e.setter
|
||
|
def usbx_e(self, usbx_e):
|
||
|
if isinstance(usbx_e, np.ndarray):
|
||
|
self.__usbx_e = usbx_e
|
||
|
else:
|
||
|
raise Exception('Invalid usbx_e value. Exiting.')
|
||
|
|
||
|
@idxsbx_e.setter
|
||
|
def idxsbx_e(self, idxsbx_e):
|
||
|
if isinstance(idxsbx_e, np.ndarray):
|
||
|
self.__idxsbx_e = idxsbx_e
|
||
|
else:
|
||
|
raise Exception('Invalid idxsbx_e value. Exiting.')
|
||
|
|
||
|
@Jsbx_e.setter
|
||
|
def Jsbx_e(self, Jsbx_e):
|
||
|
if isinstance(Jsbx_e, np.ndarray):
|
||
|
self.__idxsbx_e = J_to_idx_slack(Jsbx_e)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsbx_e value. Exiting.')
|
||
|
|
||
|
|
||
|
# soft bounds on general linear constraints
|
||
|
@lsg.setter
|
||
|
def lsg(self, lsg):
|
||
|
if isinstance(lsg, np.ndarray):
|
||
|
self.__lsg = lsg
|
||
|
else:
|
||
|
raise Exception('Invalid lsg value. Exiting.')
|
||
|
|
||
|
@usg.setter
|
||
|
def usg(self, usg):
|
||
|
if isinstance(usg, np.ndarray):
|
||
|
self.__usg = usg
|
||
|
else:
|
||
|
raise Exception('Invalid usg value. Exiting.')
|
||
|
|
||
|
@idxsg.setter
|
||
|
def idxsg(self, idxsg):
|
||
|
if isinstance(idxsg, np.ndarray):
|
||
|
self.__idxsg = idxsg
|
||
|
else:
|
||
|
raise Exception('Invalid idxsg value. Exiting.')
|
||
|
|
||
|
@Jsg.setter
|
||
|
def Jsg(self, Jsg):
|
||
|
if isinstance(Jsg, np.ndarray):
|
||
|
self.__idxsg = J_to_idx_slack(Jsg)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsg value, expected numpy array. Exiting.')
|
||
|
|
||
|
|
||
|
# soft bounds on nonlinear constraints
|
||
|
@lsh.setter
|
||
|
def lsh(self, lsh):
|
||
|
if isinstance(lsh, np.ndarray):
|
||
|
self.__lsh = lsh
|
||
|
else:
|
||
|
raise Exception('Invalid lsh value. Exiting.')
|
||
|
|
||
|
@ush.setter
|
||
|
def ush(self, ush):
|
||
|
if isinstance(ush, np.ndarray):
|
||
|
self.__ush = ush
|
||
|
else:
|
||
|
raise Exception('Invalid ush value. Exiting.')
|
||
|
|
||
|
@idxsh.setter
|
||
|
def idxsh(self, idxsh):
|
||
|
if isinstance(idxsh, np.ndarray):
|
||
|
self.__idxsh = idxsh
|
||
|
else:
|
||
|
raise Exception('Invalid idxsh value. Exiting.')
|
||
|
|
||
|
|
||
|
@Jsh.setter
|
||
|
def Jsh(self, Jsh):
|
||
|
if isinstance(Jsh, np.ndarray):
|
||
|
self.__idxsh = J_to_idx_slack(Jsh)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsh value, expected numpy array. Exiting.')
|
||
|
|
||
|
# soft bounds on convex-over-nonlinear constraints
|
||
|
@lsphi.setter
|
||
|
def lsphi(self, lsphi):
|
||
|
if isinstance(lsphi, np.ndarray):
|
||
|
self.__lsphi = lsphi
|
||
|
else:
|
||
|
raise Exception('Invalid lsphi value. Exiting.')
|
||
|
|
||
|
@usphi.setter
|
||
|
def usphi(self, usphi):
|
||
|
if isinstance(usphi, np.ndarray):
|
||
|
self.__usphi = usphi
|
||
|
else:
|
||
|
raise Exception('Invalid usphi value. Exiting.')
|
||
|
|
||
|
@idxsphi.setter
|
||
|
def idxsphi(self, idxsphi):
|
||
|
if isinstance(idxsphi, np.ndarray):
|
||
|
self.__idxsphi = idxsphi
|
||
|
else:
|
||
|
raise Exception('Invalid idxsphi value. Exiting.')
|
||
|
|
||
|
@Jsphi.setter
|
||
|
def Jsphi(self, Jsphi):
|
||
|
if isinstance(Jsphi, np.ndarray):
|
||
|
self.__idxsphi = J_to_idx_slack(Jsphi)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsphi value, expected numpy array. Exiting.')
|
||
|
|
||
|
# soft bounds on general linear constraints at shooting node N
|
||
|
@lsg_e.setter
|
||
|
def lsg_e(self, lsg_e):
|
||
|
if isinstance(lsg_e, np.ndarray):
|
||
|
self.__lsg_e = lsg_e
|
||
|
else:
|
||
|
raise Exception('Invalid lsg_e value. Exiting.')
|
||
|
|
||
|
@usg_e.setter
|
||
|
def usg_e(self, usg_e):
|
||
|
if isinstance(usg_e, np.ndarray):
|
||
|
self.__usg_e = usg_e
|
||
|
else:
|
||
|
raise Exception('Invalid usg_e value. Exiting.')
|
||
|
|
||
|
@idxsg_e.setter
|
||
|
def idxsg_e(self, idxsg_e):
|
||
|
if isinstance(idxsg_e, np.ndarray):
|
||
|
self.__idxsg_e = idxsg_e
|
||
|
else:
|
||
|
raise Exception('Invalid idxsg_e value. Exiting.')
|
||
|
|
||
|
@Jsg_e.setter
|
||
|
def Jsg_e(self, Jsg_e):
|
||
|
if isinstance(Jsg_e, np.ndarray):
|
||
|
self.__idxsg_e = J_to_idx_slack(Jsg_e)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsg_e value, expected numpy array. Exiting.')
|
||
|
|
||
|
# soft bounds on nonlinear constraints at shooting node N
|
||
|
@lsh_e.setter
|
||
|
def lsh_e(self, lsh_e):
|
||
|
if isinstance(lsh_e, np.ndarray):
|
||
|
self.__lsh_e = lsh_e
|
||
|
else:
|
||
|
raise Exception('Invalid lsh_e value. Exiting.')
|
||
|
|
||
|
@ush_e.setter
|
||
|
def ush_e(self, ush_e):
|
||
|
if isinstance(ush_e, np.ndarray):
|
||
|
self.__ush_e = ush_e
|
||
|
else:
|
||
|
raise Exception('Invalid ush_e value. Exiting.')
|
||
|
|
||
|
@idxsh_e.setter
|
||
|
def idxsh_e(self, idxsh_e):
|
||
|
if isinstance(idxsh_e, np.ndarray):
|
||
|
self.__idxsh_e = idxsh_e
|
||
|
else:
|
||
|
raise Exception('Invalid idxsh_e value. Exiting.')
|
||
|
|
||
|
@Jsh_e.setter
|
||
|
def Jsh_e(self, Jsh_e):
|
||
|
if isinstance(Jsh_e, np.ndarray):
|
||
|
self.__idxsh_e = J_to_idx_slack(Jsh_e)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsh_e value, expected numpy array. Exiting.')
|
||
|
|
||
|
|
||
|
# soft bounds on convex-over-nonlinear constraints at shooting node N
|
||
|
@lsphi_e.setter
|
||
|
def lsphi_e(self, lsphi_e):
|
||
|
if isinstance(lsphi_e, np.ndarray):
|
||
|
self.__lsphi_e = lsphi_e
|
||
|
else:
|
||
|
raise Exception('Invalid lsphi_e value. Exiting.')
|
||
|
|
||
|
@usphi_e.setter
|
||
|
def usphi_e(self, usphi_e):
|
||
|
if isinstance(usphi_e, np.ndarray):
|
||
|
self.__usphi_e = usphi_e
|
||
|
else:
|
||
|
raise Exception('Invalid usphi_e value. Exiting.')
|
||
|
|
||
|
@idxsphi_e.setter
|
||
|
def idxsphi_e(self, idxsphi_e):
|
||
|
if isinstance(idxsphi_e, np.ndarray):
|
||
|
self.__idxsphi_e = idxsphi_e
|
||
|
else:
|
||
|
raise Exception('Invalid idxsphi_e value. Exiting.')
|
||
|
|
||
|
@Jsphi_e.setter
|
||
|
def Jsphi_e(self, Jsphi_e):
|
||
|
if isinstance(Jsphi_e, np.ndarray):
|
||
|
self.__idxsphi_e = J_to_idx_slack(Jsphi_e)
|
||
|
else:
|
||
|
raise Exception('Invalid Jsphi_e value. Exiting.')
|
||
|
|
||
|
def set(self, attr, value):
|
||
|
setattr(self, attr, value)
|
||
|
|
||
|
|
||
|
class AcadosOcpOptions:
|
||
|
"""
|
||
|
class containing the description of the solver options
|
||
|
"""
|
||
|
def __init__(self):
|
||
|
self.__qp_solver = 'PARTIAL_CONDENSING_HPIPM' # qp solver to be used in the NLP solver
|
||
|
self.__hessian_approx = 'GAUSS_NEWTON' # hessian approximation
|
||
|
self.__integrator_type = 'ERK' # integrator type
|
||
|
self.__tf = None # prediction horizon
|
||
|
self.__nlp_solver_type = 'SQP_RTI' # NLP solver
|
||
|
self.__globalization = 'FIXED_STEP'
|
||
|
self.__nlp_solver_step_length = 1.0 # fixed Newton step length
|
||
|
self.__levenberg_marquardt = 0.0
|
||
|
self.__collocation_type = 'GAUSS_LEGENDRE'
|
||
|
self.__sim_method_num_stages = 4 # number of stages in the integrator
|
||
|
self.__sim_method_num_steps = 1 # number of steps in the integrator
|
||
|
self.__sim_method_newton_iter = 3 # number of Newton iterations in simulation method
|
||
|
self.__sim_method_jac_reuse = 0
|
||
|
self.__qp_solver_tol_stat = None # QP solver stationarity tolerance
|
||
|
self.__qp_solver_tol_eq = None # QP solver equality tolerance
|
||
|
self.__qp_solver_tol_ineq = None # QP solver inequality
|
||
|
self.__qp_solver_tol_comp = None # QP solver complementarity
|
||
|
self.__qp_solver_iter_max = 50 # QP solver max iter
|
||
|
self.__qp_solver_cond_N = None # QP solver: new horizon after partial condensing
|
||
|
self.__qp_solver_warm_start = 0
|
||
|
self.__nlp_solver_tol_stat = 1e-6 # NLP solver stationarity tolerance
|
||
|
self.__nlp_solver_tol_eq = 1e-6 # NLP solver equality tolerance
|
||
|
self.__nlp_solver_tol_ineq = 1e-6 # NLP solver inequality
|
||
|
self.__nlp_solver_tol_comp = 1e-6 # NLP solver complementarity
|
||
|
self.__nlp_solver_max_iter = 100 # NLP solver maximum number of iterations
|
||
|
self.__Tsim = None # automatically calculated as tf/N
|
||
|
self.__print_level = 0 # print level
|
||
|
self.__initialize_t_slacks = 0 # possible values: 0, 1
|
||
|
self.__model_external_shared_lib_dir = None # path to the the .so lib
|
||
|
self.__model_external_shared_lib_name = None # name of the the .so lib
|
||
|
self.__regularize_method = None
|
||
|
self.__time_steps = None
|
||
|
self.__shooting_nodes = None
|
||
|
self.__exact_hess_cost = 1
|
||
|
self.__exact_hess_dyn = 1
|
||
|
self.__exact_hess_constr = 1
|
||
|
self.__ext_cost_num_hess = 0
|
||
|
self.__alpha_min = 0.05
|
||
|
self.__alpha_reduction = 0.7
|
||
|
self.__line_search_use_sufficient_descent = 0
|
||
|
self.__globalization_use_SOC = 0
|
||
|
self.__full_step_dual = 0
|
||
|
self.__eps_sufficient_descent = 1e-4
|
||
|
self.__hpipm_mode = 'BALANCE'
|
||
|
|
||
|
|
||
|
@property
|
||
|
def qp_solver(self):
|
||
|
"""QP solver to be used in the NLP solver.
|
||
|
String in ('PARTIAL_CONDENSING_HPIPM', 'FULL_CONDENSING_QPOASES', 'FULL_CONDENSING_HPIPM', 'PARTIAL_CONDENSING_QPDUNES', 'PARTIAL_CONDENSING_OSQP').
|
||
|
Default: 'PARTIAL_CONDENSING_HPIPM'.
|
||
|
"""
|
||
|
return self.__qp_solver
|
||
|
|
||
|
@property
|
||
|
def hpipm_mode(self):
|
||
|
"""
|
||
|
Mode of HPIPM to be used,
|
||
|
|
||
|
String in ('BALANCE', 'SPEED_ABS', 'SPEED', 'ROBUST').
|
||
|
|
||
|
Default: 'BALANCE'.
|
||
|
|
||
|
see https://cdn.syscop.de/publications/Frison2020a.pdf
|
||
|
and the HPIPM code:
|
||
|
https://github.com/giaf/hpipm/blob/master/ocp_qp/x_ocp_qp_ipm.c#L69
|
||
|
"""
|
||
|
return self.__hpipm_mode
|
||
|
|
||
|
@property
|
||
|
def hessian_approx(self):
|
||
|
"""Hessian approximation.
|
||
|
String in ('GAUSS_NEWTON', 'EXACT').
|
||
|
Default: 'GAUSS_NEWTON'.
|
||
|
"""
|
||
|
return self.__hessian_approx
|
||
|
|
||
|
@property
|
||
|
def integrator_type(self):
|
||
|
"""
|
||
|
Integrator type.
|
||
|
String in ('ERK', 'IRK', 'GNSF', 'DISCRETE', 'LIFTED_IRK').
|
||
|
Default: 'ERK'.
|
||
|
"""
|
||
|
return self.__integrator_type
|
||
|
|
||
|
@property
|
||
|
def nlp_solver_type(self):
|
||
|
"""NLP solver.
|
||
|
String in ('SQP', 'SQP_RTI').
|
||
|
Default: 'SQP_RTI'.
|
||
|
"""
|
||
|
return self.__nlp_solver_type
|
||
|
|
||
|
@property
|
||
|
def globalization(self):
|
||
|
"""Globalization type.
|
||
|
String in ('FIXED_STEP', 'MERIT_BACKTRACKING').
|
||
|
Default: 'FIXED_STEP'.
|
||
|
|
||
|
.. note:: preliminary implementation.
|
||
|
"""
|
||
|
return self.__globalization
|
||
|
|
||
|
@property
|
||
|
def collocation_type(self):
|
||
|
"""Collocation type: relevant for implicit integrators
|
||
|
-- string in {GAUSS_RADAU_IIA, GAUSS_LEGENDRE}.
|
||
|
|
||
|
Default: GAUSS_LEGENDRE
|
||
|
"""
|
||
|
return self.__collocation_type
|
||
|
|
||
|
@property
|
||
|
def regularize_method(self):
|
||
|
"""Regularization method for the Hessian.
|
||
|
String in ('NO_REGULARIZE', 'MIRROR', 'PROJECT', 'PROJECT_REDUC_HESS', 'CONVEXIFY') or :code:`None`.
|
||
|
|
||
|
Default: :code:`None`.
|
||
|
"""
|
||
|
return self.__regularize_method
|
||
|
|
||
|
@property
|
||
|
def nlp_solver_step_length(self):
|
||
|
"""
|
||
|
Fixed Newton step length.
|
||
|
Type: float > 0.
|
||
|
Default: 1.0.
|
||
|
"""
|
||
|
return self.__nlp_solver_step_length
|
||
|
|
||
|
@property
|
||
|
def levenberg_marquardt(self):
|
||
|
"""
|
||
|
Factor for LM regularization.
|
||
|
Type: float >= 0
|
||
|
Default: 0.0.
|
||
|
"""
|
||
|
return self.__levenberg_marquardt
|
||
|
|
||
|
@property
|
||
|
def sim_method_num_stages(self):
|
||
|
"""
|
||
|
Number of stages in the integrator.
|
||
|
Type: int > 0 or ndarray of ints > 0 of shape (N,).
|
||
|
Default: 4
|
||
|
"""
|
||
|
return self.__sim_method_num_stages
|
||
|
|
||
|
@property
|
||
|
def sim_method_num_steps(self):
|
||
|
"""
|
||
|
Number of steps in the integrator.
|
||
|
Type: int > 0 or ndarray of ints > 0 of shape (N,).
|
||
|
Default: 1
|
||
|
"""
|
||
|
return self.__sim_method_num_steps
|
||
|
|
||
|
@property
|
||
|
def sim_method_newton_iter(self):
|
||
|
"""
|
||
|
Number of Newton iterations in simulation method.
|
||
|
Type: int > 0
|
||
|
Default: 3
|
||
|
"""
|
||
|
return self.__sim_method_newton_iter
|
||
|
|
||
|
@property
|
||
|
def sim_method_jac_reuse(self):
|
||
|
"""
|
||
|
Integer determining if jacobians are reused within integrator or ndarray of ints > 0 of shape (N,).
|
||
|
0: False (no reuse); 1: True (reuse)
|
||
|
Default: 0
|
||
|
"""
|
||
|
return self.__sim_method_jac_reuse
|
||
|
|
||
|
@property
|
||
|
def qp_solver_tol_stat(self):
|
||
|
"""
|
||
|
QP solver stationarity tolerance.
|
||
|
Default: :code:`None`
|
||
|
"""
|
||
|
return self.__qp_solver_tol_stat
|
||
|
|
||
|
@property
|
||
|
def qp_solver_tol_eq(self):
|
||
|
"""
|
||
|
QP solver equality tolerance.
|
||
|
Default: :code:`None`
|
||
|
"""
|
||
|
return self.__qp_solver_tol_eq
|
||
|
|
||
|
@property
|
||
|
def qp_solver_tol_ineq(self):
|
||
|
"""
|
||
|
QP solver inequality.
|
||
|
Default: :code:`None`
|
||
|
"""
|
||
|
return self.__qp_solver_tol_ineq
|
||
|
|
||
|
@property
|
||
|
def qp_solver_tol_comp(self):
|
||
|
"""
|
||
|
QP solver complementarity.
|
||
|
Default: :code:`None`
|
||
|
"""
|
||
|
return self.__qp_solver_tol_comp
|
||
|
|
||
|
@property
|
||
|
def qp_solver_cond_N(self):
|
||
|
"""QP solver: New horizon after partial condensing.
|
||
|
Set to N by default -> no condensing."""
|
||
|
return self.__qp_solver_cond_N
|
||
|
|
||
|
@property
|
||
|
def qp_solver_warm_start(self):
|
||
|
"""QP solver: Warm starting.
|
||
|
0: no warm start; 1: warm start; 2: hot start."""
|
||
|
return self.__qp_solver_warm_start
|
||
|
|
||
|
@property
|
||
|
def qp_solver_iter_max(self):
|
||
|
"""
|
||
|
QP solver: maximum number of iterations.
|
||
|
Type: int > 0
|
||
|
Default: 50
|
||
|
"""
|
||
|
return self.__qp_solver_iter_max
|
||
|
|
||
|
@property
|
||
|
def tol(self):
|
||
|
"""
|
||
|
NLP solver tolerance. Sets or gets the max of :py:attr:`nlp_solver_tol_eq`,
|
||
|
:py:attr:`nlp_solver_tol_ineq`, :py:attr:`nlp_solver_tol_comp`
|
||
|
and :py:attr:`nlp_solver_tol_stat`.
|
||
|
"""
|
||
|
return max([self.__nlp_solver_tol_eq, self.__nlp_solver_tol_ineq,\
|
||
|
self.__nlp_solver_tol_comp, self.__nlp_solver_tol_stat])
|
||
|
|
||
|
@property
|
||
|
def qp_tol(self):
|
||
|
"""
|
||
|
QP solver tolerance.
|
||
|
Sets all of the following at once or gets the max of
|
||
|
:py:attr:`qp_solver_tol_eq`, :py:attr:`qp_solver_tol_ineq`,
|
||
|
:py:attr:`qp_solver_tol_comp` and
|
||
|
:py:attr:`qp_solver_tol_stat`.
|
||
|
"""
|
||
|
return max([self.__qp_solver_tol_eq, self.__qp_solver_tol_ineq,\
|
||
|
self.__qp_solver_tol_comp, self.__qp_solver_tol_stat])
|
||
|
|
||
|
@property
|
||
|
def nlp_solver_tol_stat(self):
|
||
|
"""
|
||
|
NLP solver stationarity tolerance.
|
||
|
Type: float > 0
|
||
|
Default: 1e-6
|
||
|
"""
|
||
|
return self.__nlp_solver_tol_stat
|
||
|
|
||
|
@property
|
||
|
def nlp_solver_tol_eq(self):
|
||
|
"""NLP solver equality tolerance"""
|
||
|
return self.__nlp_solver_tol_eq
|
||
|
|
||
|
@property
|
||
|
def alpha_min(self):
|
||
|
"""Minimal step size for globalization MERIT_BACKTRACKING, default: 0.05."""
|
||
|
return self.__alpha_min
|
||
|
|
||
|
@property
|
||
|
def alpha_reduction(self):
|
||
|
"""Step size reduction factor for globalization MERIT_BACKTRACKING, default: 0.7."""
|
||
|
return self.__alpha_reduction
|
||
|
|
||
|
@property
|
||
|
def line_search_use_sufficient_descent(self):
|
||
|
"""
|
||
|
Determines if sufficient descent (Armijo) condition is used in line search.
|
||
|
Type: int; 0 or 1;
|
||
|
default: 0.
|
||
|
"""
|
||
|
return self.__line_search_use_sufficient_descent
|
||
|
|
||
|
@property
|
||
|
def eps_sufficient_descent(self):
|
||
|
"""
|
||
|
Factor for sufficient descent (Armijo) conditon, see line_search_use_sufficient_descent.
|
||
|
Type: float,
|
||
|
default: 1e-4.
|
||
|
"""
|
||
|
return self.__eps_sufficient_descent
|
||
|
|
||
|
@property
|
||
|
def globalization_use_SOC(self):
|
||
|
"""
|
||
|
Determines if second order correction (SOC) is done when using MERIT_BACKTRACKING.
|
||
|
SOC is done if preliminary line search does not return full step.
|
||
|
Type: int; 0 or 1;
|
||
|
default: 0.
|
||
|
"""
|
||
|
return self.__globalization_use_SOC
|
||
|
|
||
|
@property
|
||
|
def full_step_dual(self):
|
||
|
"""
|
||
|
Determines if dual variables are updated with full steps (alpha=1.0) when primal variables are updated with smaller step.
|
||
|
Type: int; 0 or 1;
|
||
|
default: 0.
|
||
|
"""
|
||
|
return self.__full_step_dual
|
||
|
|
||
|
@property
|
||
|
def nlp_solver_tol_ineq(self):
|
||
|
"""NLP solver inequality tolerance"""
|
||
|
return self.__nlp_solver_tol_ineq
|
||
|
|
||
|
@property
|
||
|
def nlp_solver_tol_comp(self):
|
||
|
"""NLP solver complementarity tolerance"""
|
||
|
return self.__nlp_solver_tol_comp
|
||
|
|
||
|
@property
|
||
|
def nlp_solver_max_iter(self):
|
||
|
"""
|
||
|
NLP solver maximum number of iterations.
|
||
|
Type: int > 0
|
||
|
Default: 100
|
||
|
"""
|
||
|
return self.__nlp_solver_max_iter
|
||
|
|
||
|
@property
|
||
|
def time_steps(self):
|
||
|
"""
|
||
|
Vector with time steps between the shooting nodes. Set automatically to uniform discretization if :py:attr:`N` and :py:attr:`tf` are provided.
|
||
|
Default: :code:`None`
|
||
|
"""
|
||
|
return self.__time_steps
|
||
|
|
||
|
@property
|
||
|
def shooting_nodes(self):
|
||
|
"""
|
||
|
Vector with the shooting nodes, time_steps will be computed from it automatically.
|
||
|
Default: :code:`None`
|
||
|
"""
|
||
|
return self.__shooting_nodes
|
||
|
|
||
|
@property
|
||
|
def tf(self):
|
||
|
"""
|
||
|
Prediction horizon
|
||
|
Type: float > 0
|
||
|
Default: :code:`None`
|
||
|
"""
|
||
|
return self.__tf
|
||
|
|
||
|
@property
|
||
|
def Tsim(self):
|
||
|
"""
|
||
|
Time horizon for one integrator step. Automatically calculated as :py:attr:`tf`/:py:attr:`N`.
|
||
|
Default: :code:`None`
|
||
|
"""
|
||
|
return self.__Tsim
|
||
|
|
||
|
@property
|
||
|
def print_level(self):
|
||
|
"""
|
||
|
Verbosity of printing.
|
||
|
Type: int >= 0
|
||
|
Default: 0
|
||
|
"""
|
||
|
return self.__print_level
|
||
|
|
||
|
@property
|
||
|
def model_external_shared_lib_dir(self):
|
||
|
"""Path to the .so lib"""
|
||
|
return self.__model_external_shared_lib_dir
|
||
|
|
||
|
@property
|
||
|
def model_external_shared_lib_name(self):
|
||
|
"""Name of the .so lib"""
|
||
|
return self.__model_external_shared_lib_name
|
||
|
|
||
|
@property
|
||
|
def exact_hess_constr(self):
|
||
|
"""
|
||
|
Used in case of hessian_approx == 'EXACT'.\n
|
||
|
Can be used to turn off exact hessian contributions from the constraints module.
|
||
|
"""
|
||
|
return self.__exact_hess_constr
|
||
|
|
||
|
@property
|
||
|
def exact_hess_cost(self):
|
||
|
"""
|
||
|
Used in case of hessian_approx == 'EXACT'.\n
|
||
|
Can be used to turn off exact hessian contributions from the cost module.
|
||
|
"""
|
||
|
return self.__exact_hess_cost
|
||
|
|
||
|
@property
|
||
|
def exact_hess_dyn(self):
|
||
|
"""
|
||
|
Used in case of hessian_approx == 'EXACT'.\n
|
||
|
Can be used to turn off exact hessian contributions from the dynamics module.
|
||
|
"""
|
||
|
return self.__exact_hess_dyn
|
||
|
|
||
|
@property
|
||
|
def ext_cost_num_hess(self):
|
||
|
"""
|
||
|
Determines if custom hessian approximation for cost contribution is used (> 0).\n
|
||
|
Or if hessian contribution is evaluated exactly using CasADi external function (=0 - default).
|
||
|
"""
|
||
|
return self.__ext_cost_num_hess
|
||
|
|
||
|
@qp_solver.setter
|
||
|
def qp_solver(self, qp_solver):
|
||
|
qp_solvers = ('PARTIAL_CONDENSING_HPIPM', \
|
||
|
'FULL_CONDENSING_QPOASES', 'FULL_CONDENSING_HPIPM', \
|
||
|
'PARTIAL_CONDENSING_QPDUNES', 'PARTIAL_CONDENSING_OSQP')
|
||
|
if qp_solver in qp_solvers:
|
||
|
self.__qp_solver = qp_solver
|
||
|
else:
|
||
|
raise Exception('Invalid qp_solver value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(qp_solvers) + '.\n\nYou have: ' + qp_solver + '.\n\nExiting.')
|
||
|
|
||
|
@regularize_method.setter
|
||
|
def regularize_method(self, regularize_method):
|
||
|
regularize_methods = ('NO_REGULARIZE', 'MIRROR', 'PROJECT', \
|
||
|
'PROJECT_REDUC_HESS', 'CONVEXIFY')
|
||
|
if regularize_method in regularize_methods:
|
||
|
self.__regularize_method = regularize_method
|
||
|
else:
|
||
|
raise Exception('Invalid regularize_method value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(regularize_methods) + '.\n\nYou have: ' + regularize_method + '.\n\nExiting.')
|
||
|
|
||
|
@collocation_type.setter
|
||
|
def collocation_type(self, collocation_type):
|
||
|
collocation_types = ('GAUSS_RADAU_IIA', 'GAUSS_LEGENDRE')
|
||
|
if collocation_type in collocation_types:
|
||
|
self.__collocation_type = collocation_type
|
||
|
else:
|
||
|
raise Exception('Invalid collocation_type value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(collocation_types) + '.\n\nYou have: ' + collocation_type + '.\n\nExiting.')
|
||
|
|
||
|
@hpipm_mode.setter
|
||
|
def hpipm_mode(self, hpipm_mode):
|
||
|
hpipm_modes = ('BALANCE', 'SPEED_ABS', 'SPEED', 'ROBUST')
|
||
|
if hpipm_mode in hpipm_modes:
|
||
|
self.__hpipm_mode = hpipm_mode
|
||
|
else:
|
||
|
raise Exception('Invalid hpipm_mode value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(hpipm_modes) + '.\n\nYou have: ' + hpipm_mode + '.\n\nExiting.')
|
||
|
|
||
|
@hessian_approx.setter
|
||
|
def hessian_approx(self, hessian_approx):
|
||
|
hessian_approxs = ('GAUSS_NEWTON', 'EXACT')
|
||
|
if hessian_approx in hessian_approxs:
|
||
|
self.__hessian_approx = hessian_approx
|
||
|
else:
|
||
|
raise Exception('Invalid hessian_approx value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(hessian_approxs) + '.\n\nYou have: ' + hessian_approx + '.\n\nExiting.')
|
||
|
|
||
|
@integrator_type.setter
|
||
|
def integrator_type(self, integrator_type):
|
||
|
integrator_types = ('ERK', 'IRK', 'GNSF', 'DISCRETE', 'LIFTED_IRK')
|
||
|
if integrator_type in integrator_types:
|
||
|
self.__integrator_type = integrator_type
|
||
|
else:
|
||
|
raise Exception('Invalid integrator_type value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(integrator_types) + '.\n\nYou have: ' + integrator_type + '.\n\nExiting.')
|
||
|
|
||
|
@tf.setter
|
||
|
def tf(self, tf):
|
||
|
self.__tf = tf
|
||
|
|
||
|
@time_steps.setter
|
||
|
def time_steps(self, time_steps):
|
||
|
if isinstance(time_steps, np.ndarray):
|
||
|
if len(time_steps.shape) == 1:
|
||
|
self.__time_steps = time_steps
|
||
|
else:
|
||
|
raise Exception('Invalid time_steps, expected np.ndarray of shape (N,).')
|
||
|
else:
|
||
|
raise Exception('Invalid time_steps, expected np.ndarray.')
|
||
|
|
||
|
@shooting_nodes.setter
|
||
|
def shooting_nodes(self, shooting_nodes):
|
||
|
if isinstance(shooting_nodes, np.ndarray):
|
||
|
if len(shooting_nodes.shape) == 1:
|
||
|
self.__shooting_nodes = shooting_nodes
|
||
|
else:
|
||
|
raise Exception('Invalid shooting_nodes, expected np.ndarray of shape (N+1,).')
|
||
|
else:
|
||
|
raise Exception('Invalid shooting_nodes, expected np.ndarray.')
|
||
|
|
||
|
@Tsim.setter
|
||
|
def Tsim(self, Tsim):
|
||
|
self.__Tsim = Tsim
|
||
|
|
||
|
@globalization.setter
|
||
|
def globalization(self, globalization):
|
||
|
globalization_types = ('MERIT_BACKTRACKING', 'FIXED_STEP')
|
||
|
if globalization in globalization_types:
|
||
|
self.__globalization = globalization
|
||
|
else:
|
||
|
raise Exception('Invalid globalization value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(globalization_types) + '.\n\nYou have: ' + globalization + '.\n\nExiting.')
|
||
|
|
||
|
@alpha_min.setter
|
||
|
def alpha_min(self, alpha_min):
|
||
|
self.__alpha_min = alpha_min
|
||
|
|
||
|
@alpha_reduction.setter
|
||
|
def alpha_reduction(self, alpha_reduction):
|
||
|
self.__alpha_reduction = alpha_reduction
|
||
|
|
||
|
@line_search_use_sufficient_descent.setter
|
||
|
def line_search_use_sufficient_descent(self, line_search_use_sufficient_descent):
|
||
|
if line_search_use_sufficient_descent in [0, 1]:
|
||
|
self.__line_search_use_sufficient_descent = line_search_use_sufficient_descent
|
||
|
else:
|
||
|
raise Exception(f'Invalid value for line_search_use_sufficient_descent. Possible values are 0, 1, got {line_search_use_sufficient_descent}')
|
||
|
|
||
|
@globalization_use_SOC.setter
|
||
|
def globalization_use_SOC(self, globalization_use_SOC):
|
||
|
if globalization_use_SOC in [0, 1]:
|
||
|
self.__globalization_use_SOC = globalization_use_SOC
|
||
|
else:
|
||
|
raise Exception(f'Invalid value for globalization_use_SOC. Possible values are 0, 1, got {globalization_use_SOC}')
|
||
|
|
||
|
@full_step_dual.setter
|
||
|
def full_step_dual(self, full_step_dual):
|
||
|
if full_step_dual in [0, 1]:
|
||
|
self.__full_step_dual = full_step_dual
|
||
|
else:
|
||
|
raise Exception(f'Invalid value for full_step_dual. Possible values are 0, 1, got {full_step_dual}')
|
||
|
|
||
|
@eps_sufficient_descent.setter
|
||
|
def eps_sufficient_descent(self, eps_sufficient_descent):
|
||
|
if isinstance(eps_sufficient_descent, float) and eps_sufficient_descent > 0:
|
||
|
self.__eps_sufficient_descent = eps_sufficient_descent
|
||
|
else:
|
||
|
raise Exception('Invalid eps_sufficient_descent value. eps_sufficient_descent must be a positive float. Exiting')
|
||
|
|
||
|
@sim_method_num_stages.setter
|
||
|
def sim_method_num_stages(self, sim_method_num_stages):
|
||
|
|
||
|
# if isinstance(sim_method_num_stages, int):
|
||
|
# self.__sim_method_num_stages = sim_method_num_stages
|
||
|
# else:
|
||
|
# raise Exception('Invalid sim_method_num_stages value. sim_method_num_stages must be an integer. Exiting.')
|
||
|
|
||
|
self.__sim_method_num_stages = sim_method_num_stages
|
||
|
|
||
|
@sim_method_num_steps.setter
|
||
|
def sim_method_num_steps(self, sim_method_num_steps):
|
||
|
|
||
|
# if isinstance(sim_method_num_steps, int):
|
||
|
# self.__sim_method_num_steps = sim_method_num_steps
|
||
|
# else:
|
||
|
# raise Exception('Invalid sim_method_num_steps value. sim_method_num_steps must be an integer. Exiting.')
|
||
|
self.__sim_method_num_steps = sim_method_num_steps
|
||
|
|
||
|
|
||
|
@sim_method_newton_iter.setter
|
||
|
def sim_method_newton_iter(self, sim_method_newton_iter):
|
||
|
|
||
|
if isinstance(sim_method_newton_iter, int):
|
||
|
self.__sim_method_newton_iter = sim_method_newton_iter
|
||
|
else:
|
||
|
raise Exception('Invalid sim_method_newton_iter value. sim_method_newton_iter must be an integer. Exiting.')
|
||
|
|
||
|
@sim_method_jac_reuse.setter
|
||
|
def sim_method_jac_reuse(self, sim_method_jac_reuse):
|
||
|
# if sim_method_jac_reuse in (True, False):
|
||
|
self.__sim_method_jac_reuse = sim_method_jac_reuse
|
||
|
# else:
|
||
|
# raise Exception('Invalid sim_method_jac_reuse value. sim_method_jac_reuse must be a Boolean.')
|
||
|
|
||
|
@nlp_solver_type.setter
|
||
|
def nlp_solver_type(self, nlp_solver_type):
|
||
|
nlp_solver_types = ('SQP', 'SQP_RTI')
|
||
|
if nlp_solver_type in nlp_solver_types:
|
||
|
self.__nlp_solver_type = nlp_solver_type
|
||
|
else:
|
||
|
raise Exception('Invalid nlp_solver_type value. Possible values are:\n\n' \
|
||
|
+ ',\n'.join(nlp_solver_types) + '.\n\nYou have: ' + nlp_solver_type + '.\n\nExiting.')
|
||
|
|
||
|
@nlp_solver_step_length.setter
|
||
|
def nlp_solver_step_length(self, nlp_solver_step_length):
|
||
|
if isinstance(nlp_solver_step_length, float) and nlp_solver_step_length > 0:
|
||
|
self.__nlp_solver_step_length = nlp_solver_step_length
|
||
|
else:
|
||
|
raise Exception('Invalid nlp_solver_step_length value. nlp_solver_step_length must be a positive float. Exiting')
|
||
|
|
||
|
@levenberg_marquardt.setter
|
||
|
def levenberg_marquardt(self, levenberg_marquardt):
|
||
|
if isinstance(levenberg_marquardt, float) and levenberg_marquardt >= 0:
|
||
|
self.__levenberg_marquardt = levenberg_marquardt
|
||
|
else:
|
||
|
raise Exception('Invalid levenberg_marquardt value. levenberg_marquardt must be a positive float. Exiting')
|
||
|
|
||
|
@qp_solver_iter_max.setter
|
||
|
def qp_solver_iter_max(self, qp_solver_iter_max):
|
||
|
if isinstance(qp_solver_iter_max, int) and qp_solver_iter_max > 0:
|
||
|
self.__qp_solver_iter_max = qp_solver_iter_max
|
||
|
else:
|
||
|
raise Exception('Invalid qp_solver_iter_max value. qp_solver_iter_max must be a positive int. Exiting')
|
||
|
|
||
|
@qp_solver_cond_N.setter
|
||
|
def qp_solver_cond_N(self, qp_solver_cond_N):
|
||
|
if isinstance(qp_solver_cond_N, int) and qp_solver_cond_N >= 0:
|
||
|
self.__qp_solver_cond_N = qp_solver_cond_N
|
||
|
else:
|
||
|
raise Exception('Invalid qp_solver_cond_N value. qp_solver_cond_N must be a positive int. Exiting')
|
||
|
|
||
|
@qp_solver_warm_start.setter
|
||
|
def qp_solver_warm_start(self, qp_solver_warm_start):
|
||
|
if qp_solver_warm_start in [0, 1, 2]:
|
||
|
self.__qp_solver_warm_start = qp_solver_warm_start
|
||
|
else:
|
||
|
raise Exception('Invalid qp_solver_warm_start value. qp_solver_warm_start must be 0 or 1 or 2. Exiting')
|
||
|
|
||
|
@qp_tol.setter
|
||
|
def qp_tol(self, qp_tol):
|
||
|
if isinstance(qp_tol, float) and qp_tol > 0:
|
||
|
self.__qp_solver_tol_eq = qp_tol
|
||
|
self.__qp_solver_tol_ineq = qp_tol
|
||
|
self.__qp_solver_tol_stat = qp_tol
|
||
|
self.__qp_solver_tol_comp = qp_tol
|
||
|
else:
|
||
|
raise Exception('Invalid qp_tol value. qp_tol must be a positive float. Exiting')
|
||
|
|
||
|
@qp_solver_tol_stat.setter
|
||
|
def qp_solver_tol_stat(self, qp_solver_tol_stat):
|
||
|
if isinstance(qp_solver_tol_stat, float) and qp_solver_tol_stat > 0:
|
||
|
self.__qp_solver_tol_stat = qp_solver_tol_stat
|
||
|
else:
|
||
|
raise Exception('Invalid qp_solver_tol_stat value. qp_solver_tol_stat must be a positive float. Exiting')
|
||
|
|
||
|
@qp_solver_tol_eq.setter
|
||
|
def qp_solver_tol_eq(self, qp_solver_tol_eq):
|
||
|
if isinstance(qp_solver_tol_eq, float) and qp_solver_tol_eq > 0:
|
||
|
self.__qp_solver_tol_eq = qp_solver_tol_eq
|
||
|
else:
|
||
|
raise Exception('Invalid qp_solver_tol_eq value. qp_solver_tol_eq must be a positive float. Exiting')
|
||
|
|
||
|
@qp_solver_tol_ineq.setter
|
||
|
def qp_solver_tol_ineq(self, qp_solver_tol_ineq):
|
||
|
if isinstance(qp_solver_tol_ineq, float) and qp_solver_tol_ineq > 0:
|
||
|
self.__qp_solver_tol_ineq = qp_solver_tol_ineq
|
||
|
else:
|
||
|
raise Exception('Invalid qp_solver_tol_ineq value. qp_solver_tol_ineq must be a positive float. Exiting')
|
||
|
|
||
|
@qp_solver_tol_comp.setter
|
||
|
def qp_solver_tol_comp(self, qp_solver_tol_comp):
|
||
|
if isinstance(qp_solver_tol_comp, float) and qp_solver_tol_comp > 0:
|
||
|
self.__qp_solver_tol_comp = qp_solver_tol_comp
|
||
|
else:
|
||
|
raise Exception('Invalid qp_solver_tol_comp value. qp_solver_tol_comp must be a positive float. Exiting')
|
||
|
|
||
|
@tol.setter
|
||
|
def tol(self, tol):
|
||
|
if isinstance(tol, float) and tol > 0:
|
||
|
self.__nlp_solver_tol_eq = tol
|
||
|
self.__nlp_solver_tol_ineq = tol
|
||
|
self.__nlp_solver_tol_stat = tol
|
||
|
self.__nlp_solver_tol_comp = tol
|
||
|
else:
|
||
|
raise Exception('Invalid tol value. tol must be a positive float. Exiting')
|
||
|
|
||
|
@nlp_solver_tol_stat.setter
|
||
|
def nlp_solver_tol_stat(self, nlp_solver_tol_stat):
|
||
|
if isinstance(nlp_solver_tol_stat, float) and nlp_solver_tol_stat > 0:
|
||
|
self.__nlp_solver_tol_stat = nlp_solver_tol_stat
|
||
|
else:
|
||
|
raise Exception('Invalid nlp_solver_tol_stat value. nlp_solver_tol_stat must be a positive float. Exiting')
|
||
|
|
||
|
@nlp_solver_tol_eq.setter
|
||
|
def nlp_solver_tol_eq(self, nlp_solver_tol_eq):
|
||
|
if isinstance(nlp_solver_tol_eq, float) and nlp_solver_tol_eq > 0:
|
||
|
self.__nlp_solver_tol_eq = nlp_solver_tol_eq
|
||
|
else:
|
||
|
raise Exception('Invalid nlp_solver_tol_eq value. nlp_solver_tol_eq must be a positive float. Exiting')
|
||
|
|
||
|
@nlp_solver_tol_ineq.setter
|
||
|
def nlp_solver_tol_ineq(self, nlp_solver_tol_ineq):
|
||
|
if isinstance(nlp_solver_tol_ineq, float) and nlp_solver_tol_ineq > 0:
|
||
|
self.__nlp_solver_tol_ineq = nlp_solver_tol_ineq
|
||
|
else:
|
||
|
raise Exception('Invalid nlp_solver_tol_ineq value. nlp_solver_tol_ineq must be a positive float. Exiting')
|
||
|
|
||
|
@nlp_solver_tol_comp.setter
|
||
|
def nlp_solver_tol_comp(self, nlp_solver_tol_comp):
|
||
|
if isinstance(nlp_solver_tol_comp, float) and nlp_solver_tol_comp > 0:
|
||
|
self.__nlp_solver_tol_comp = nlp_solver_tol_comp
|
||
|
else:
|
||
|
raise Exception('Invalid nlp_solver_tol_comp value. nlp_solver_tol_comp must be a positive float. Exiting')
|
||
|
|
||
|
@nlp_solver_max_iter.setter
|
||
|
def nlp_solver_max_iter(self, nlp_solver_max_iter):
|
||
|
|
||
|
if isinstance(nlp_solver_max_iter, int) and nlp_solver_max_iter > 0:
|
||
|
self.__nlp_solver_max_iter = nlp_solver_max_iter
|
||
|
else:
|
||
|
raise Exception('Invalid nlp_solver_max_iter value. nlp_solver_max_iter must be a positive int. Exiting')
|
||
|
|
||
|
@print_level.setter
|
||
|
def print_level(self, print_level):
|
||
|
if isinstance(print_level, int) and print_level >= 0:
|
||
|
self.__print_level = print_level
|
||
|
else:
|
||
|
raise Exception('Invalid print_level value. print_level takes one of the values >=0. Exiting')
|
||
|
|
||
|
@model_external_shared_lib_dir.setter
|
||
|
def model_external_shared_lib_dir(self, model_external_shared_lib_dir):
|
||
|
if isinstance(model_external_shared_lib_dir, str) :
|
||
|
self.__model_external_shared_lib_dir = model_external_shared_lib_dir
|
||
|
else:
|
||
|
raise Exception('Invalid model_external_shared_lib_dir value. Str expected.' \
|
||
|
+ '.\n\nYou have: ' + type(model_external_shared_lib_dir) + '.\n\nExiting.')
|
||
|
|
||
|
@model_external_shared_lib_name.setter
|
||
|
def model_external_shared_lib_name(self, model_external_shared_lib_name):
|
||
|
if isinstance(model_external_shared_lib_name, str) :
|
||
|
if model_external_shared_lib_name[-3:] == '.so' :
|
||
|
raise Exception('Invalid model_external_shared_lib_name value. Remove the .so extension.' \
|
||
|
+ '.\n\nYou have: ' + type(model_external_shared_lib_name) + '.\n\nExiting.')
|
||
|
else :
|
||
|
self.__model_external_shared_lib_name = model_external_shared_lib_name
|
||
|
else:
|
||
|
raise Exception('Invalid model_external_shared_lib_name value. Str expected.' \
|
||
|
+ '.\n\nYou have: ' + type(model_external_shared_lib_name) + '.\n\nExiting.')
|
||
|
|
||
|
@exact_hess_constr.setter
|
||
|
def exact_hess_constr(self, exact_hess_constr):
|
||
|
if exact_hess_constr in [0, 1]:
|
||
|
self.__exact_hess_constr = exact_hess_constr
|
||
|
else:
|
||
|
raise Exception('Invalid exact_hess_constr value. exact_hess_constr takes one of the values 0, 1. Exiting')
|
||
|
|
||
|
@exact_hess_cost.setter
|
||
|
def exact_hess_cost(self, exact_hess_cost):
|
||
|
if exact_hess_cost in [0, 1]:
|
||
|
self.__exact_hess_cost = exact_hess_cost
|
||
|
else:
|
||
|
raise Exception('Invalid exact_hess_cost value. exact_hess_cost takes one of the values 0, 1. Exiting')
|
||
|
|
||
|
@exact_hess_dyn.setter
|
||
|
def exact_hess_dyn(self, exact_hess_dyn):
|
||
|
if exact_hess_dyn in [0, 1]:
|
||
|
self.__exact_hess_dyn = exact_hess_dyn
|
||
|
else:
|
||
|
raise Exception('Invalid exact_hess_dyn value. exact_hess_dyn takes one of the values 0, 1. Exiting')
|
||
|
|
||
|
@ext_cost_num_hess.setter
|
||
|
def ext_cost_num_hess(self, ext_cost_num_hess):
|
||
|
if ext_cost_num_hess in [0, 1]:
|
||
|
self.__ext_cost_num_hess = ext_cost_num_hess
|
||
|
else:
|
||
|
raise Exception('Invalid ext_cost_num_hess value. ext_cost_num_hess takes one of the values 0, 1. Exiting')
|
||
|
|
||
|
def set(self, attr, value):
|
||
|
setattr(self, attr, value)
|
||
|
|
||
|
|
||
|
class AcadosOcp:
|
||
|
"""
|
||
|
Class containing the full description of the optimal control problem.
|
||
|
This object can be used to create an :py:class:`acados_template.acados_ocp_solver.AcadosOcpSolver`.
|
||
|
|
||
|
The class has the following properties that can be modified to formulate a specific OCP, see below:
|
||
|
|
||
|
- :py:attr:`dims` of type :py:class:`acados_template.acados_ocp.AcadosOcpDims`
|
||
|
- :py:attr:`model` of type :py:class:`acados_template.acados_model.AcadosModel`
|
||
|
- :py:attr:`cost` of type :py:class:`acados_template.acados_ocp.AcadosOcpCost`
|
||
|
- :py:attr:`constraints` of type :py:class:`acados_template.acados_ocp.AcadosOcpConstraints`
|
||
|
- :py:attr:`solver_options` of type :py:class:`acados_template.acados_ocp.AcadosOcpOptions`
|
||
|
|
||
|
- :py:attr:`acados_include_path` (set automatically)
|
||
|
- :py:attr:`acados_lib_path` (set automatically)
|
||
|
- :py:attr:`parameter_values` - used to initialize the parameters (can be changed)
|
||
|
"""
|
||
|
def __init__(self, acados_path=''):
|
||
|
"""
|
||
|
Keyword arguments:
|
||
|
acados_path -- path of your acados installation
|
||
|
"""
|
||
|
if acados_path == '':
|
||
|
acados_path = get_acados_path()
|
||
|
|
||
|
self.dims = AcadosOcpDims()
|
||
|
"""Dimension definitions, type :py:class:`acados_template.acados_ocp.AcadosOcpDims`"""
|
||
|
self.model = AcadosModel()
|
||
|
"""Model definitions, type :py:class:`acados_template.acados_model.AcadosModel`"""
|
||
|
self.cost = AcadosOcpCost()
|
||
|
"""Cost definitions, type :py:class:`acados_template.acados_ocp.AcadosOcpCost`"""
|
||
|
self.constraints = AcadosOcpConstraints()
|
||
|
"""Constraints definitions, type :py:class:`acados_template.acados_ocp.AcadosOcpConstraints`"""
|
||
|
self.solver_options = AcadosOcpOptions()
|
||
|
"""Solver Options, type :py:class:`acados_template.acados_ocp.AcadosOcpOptions`"""
|
||
|
|
||
|
self.acados_include_path = os.path.join(acados_path, 'include').replace(os.sep, '/') # the replace part is important on Windows for CMake
|
||
|
"""Path to acados include directory (set automatically), type: `string`"""
|
||
|
self.acados_lib_path = os.path.join(acados_path, 'lib').replace(os.sep, '/') # the replace part is important on Windows for CMake
|
||
|
"""Path to where acados library is located, type: `string`"""
|
||
|
|
||
|
import numpy
|
||
|
self.cython_include_dirs = numpy.get_include()
|
||
|
|
||
|
self.__parameter_values = np.array([])
|
||
|
self.__problem_class = 'OCP'
|
||
|
|
||
|
self.code_export_directory = 'c_generated_code'
|
||
|
"""Path to where code will be exported. Default: `c_generated_code`."""
|
||
|
|
||
|
@property
|
||
|
def parameter_values(self):
|
||
|
""":math:`p` - initial values for parameter - can be updated stagewise"""
|
||
|
return self.__parameter_values
|
||
|
|
||
|
@parameter_values.setter
|
||
|
def parameter_values(self, parameter_values):
|
||
|
if isinstance(parameter_values, np.ndarray):
|
||
|
self.__parameter_values = parameter_values
|
||
|
else:
|
||
|
raise Exception('Invalid parameter_values value. ' +
|
||
|
f'Expected numpy array, got {type(parameter_values)}.')
|
||
|
|
||
|
def set(self, attr, value):
|
||
|
# tokenize string
|
||
|
tokens = attr.split('_', 1)
|
||
|
if len(tokens) > 1:
|
||
|
setter_to_call = getattr(getattr(self, tokens[0]), 'set')
|
||
|
else:
|
||
|
setter_to_call = getattr(self, 'set')
|
||
|
|
||
|
setter_to_call(tokens[1], value)
|
||
|
|
||
|
return
|